// Copyright 2006 The Android Open Source Project
#ifndef TRACE_READER_BASE_H
#define TRACE_READER_BASE_H
#include <inttypes.h>
#include "trace_common.h"
#include "hash_table.h"
class BBReader;
class InsnReader;
class AddrReader;
class ExcReader;
class PidReader;
class MethodReader;
struct StaticRec {
uint64_t bb_num;
uint32_t bb_addr;
uint32_t num_insns;
};
struct StaticBlock {
StaticRec rec;
uint32_t *insns;
};
struct BBEvent {
uint64_t time;
uint64_t bb_num;
uint32_t bb_addr;
uint32_t *insns;
int num_insns;
int pid;
int is_thumb;
};
struct PidEvent {
uint64_t time;
int rec_type; // record type: fork, context switch, exit ...
int tgid; // thread group id
int pid; // for fork: child pid; for switch: next pid;
// for exit: exit value
uint32_t vstart; // virtual start address (only used with mmap)
uint32_t vend; // virtual end address (only used with mmap)
uint32_t offset; // virtual file offset (only used with mmap)
// Dynamically allocated path to executable (or lib). In the case of
// an mmapped dex file, the path is modified to be more useful for
// comparing against the output of dexlist. For example, instead of this:
// /data/dalvik-cache/system@app@TestHarness.apk@classes.dex
// We convert to this:
// /system/app/TestHarness.apk
char *path;
char *mmap_path; // unmodified mmap path
int argc; // number of args
char **argv; // dynamically allocated array of args
};
struct MethodRec {
uint64_t time;
uint32_t addr;
int pid;
int flags;
};
struct DexSym {
uint32_t addr;
int len;
char *name;
};
struct DexFileList {
char *path;
int nsymbols;
DexSym *symbols;
};
class TraceReaderBase {
public:
TraceReaderBase();
virtual ~TraceReaderBase();
friend class BBReader;
void Open(const char *filename);
void Close();
void WriteHeader(TraceHeader *header);
inline bool ReadBB(BBEvent *event);
int ReadStatic(StaticRec *rec);
int ReadStaticInsns(int num, uint32_t *insns);
TraceHeader *GetHeader() { return header_; }
inline uint64_t ReadInsnTime(uint64_t min_time);
void TruncateLastBlock(uint32_t num_insns);
inline bool ReadAddr(uint64_t *time, uint32_t *addr, int *flags);
inline bool ReadExc(uint64_t *time, uint32_t *current_pc,
uint64_t *recnum, uint32_t *target_pc,
uint64_t *bb_num, uint64_t *bb_start_time,
int *num_insns);
inline bool ReadPidEvent(PidEvent *event);
inline bool ReadMethod(MethodRec *method_record);
StaticBlock *GetStaticBlock(uint64_t bb_num) { return &blocks_[bb_num]; }
uint32_t *GetInsns(uint64_t bb_num) { return blocks_[bb_num].insns; }
uint32_t GetBBAddr(uint64_t bb_num) {
return blocks_[bb_num].rec.bb_addr & ~1;
}
int GetIsThumb(uint64_t bb_num) {
return blocks_[bb_num].rec.bb_addr & 1;
}
void SetPostProcessing(bool val) { post_processing_ = val; }
protected:
virtual int FindCurrentPid(uint64_t time);
int current_pid_;
int next_pid_;
uint64_t next_pid_switch_time_;
PidReader *internal_pid_reader_;
MethodReader *internal_method_reader_;
HashTable<DexFileList*> *dex_hash_;
private:
int FindNumInsns(uint64_t bb_num, uint64_t bb_start_time);
void ReadTraceHeader(FILE *fstream, const char *filename,
const char *tracename, TraceHeader *header);
PidEvent *FindMmapDexFileEvent();
void ParseDexList(const char *filename);
char *static_filename_;
FILE *static_fstream_;
TraceHeader *header_;
BBReader *bb_reader_;
InsnReader *insn_reader_;
AddrReader *load_addr_reader_;
AddrReader *store_addr_reader_;
ExcReader *exc_reader_;
PidReader *pid_reader_;
MethodReader *method_reader_;
ExcReader *internal_exc_reader_;
StaticBlock *blocks_;
bool exc_end_;
uint64_t bb_recnum_;
uint64_t exc_recnum_;
uint64_t exc_bb_num_;
uint64_t exc_time_;
int exc_num_insns_;
bool post_processing_;
bool load_eof_;
uint64_t load_time_;
uint32_t load_addr_;
bool store_eof_;
uint64_t store_time_;
uint32_t store_addr_;
};
class Decoder;
class BBReader {
public:
explicit BBReader(TraceReaderBase *trace);
~BBReader();
void Open(const char *filename);
void Close();
bool ReadBB(BBEvent *event);
private:
struct TimeRec {
BBRec bb_rec;
uint64_t next_time;
};
struct Future {
Future *next;
TimeRec bb;
};
inline Future *AllocFuture();
inline void FreeFuture(Future *future);
inline void InsertFuture(Future *future);
inline int DecodeNextRec();
TimeRec nextrec_;
Future futures_[kMaxNumBasicBlocks];
Future *head_;
Future *free_;
Decoder *decoder_;
bool is_eof_;
TraceReaderBase *trace_;
};
class InsnReader {
public:
InsnReader();
~InsnReader();
void Open(const char *filename);
void Close();
uint64_t ReadInsnTime(uint64_t min_time);
private:
Decoder *decoder_;
uint64_t prev_time_;
uint64_t time_diff_;
int repeat_;
};
class AddrReader {
public:
AddrReader();
~AddrReader();
bool Open(const char *filename, const char *suffix);
void Close();
bool ReadAddr(uint64_t *time, uint32_t *addr);
private:
Decoder *decoder_;
uint32_t prev_addr_;
uint64_t prev_time_;
bool opened_; // true after file is opened
};
class ExcReader {
public:
ExcReader();
~ExcReader();
void Open(const char *filename);
void Close();
bool ReadExc(uint64_t *time, uint32_t *current_pc,
uint64_t *recnum, uint32_t *target_pc,
uint64_t *bb_num, uint64_t *bb_start_time,
int *num_insns);
private:
Decoder *decoder_;
uint64_t prev_time_;
uint64_t prev_recnum_;
};
class PidReader {
public:
PidReader();
~PidReader();
void Open(const char *filename);
void Close();
bool ReadPidEvent(struct PidEvent *event);
void Dispose(struct PidEvent *event);
private:
Decoder *decoder_;
uint64_t prev_time_;
};
class MethodReader {
public:
MethodReader();
~MethodReader();
bool Open(const char *filename);
void Close();
bool ReadMethod(MethodRec *method_record);
private:
Decoder *decoder_;
uint64_t prev_time_;
uint32_t prev_addr_;
int32_t prev_pid_;
bool opened_; // true after file is opened
};
// Reads the next dynamic basic block from the trace.
// Returns true on end-of-file.
inline bool TraceReaderBase::ReadBB(BBEvent *event)
{
bb_recnum_ += 1;
return bb_reader_->ReadBB(event);
}
inline uint64_t TraceReaderBase::ReadInsnTime(uint64_t min_time)
{
return insn_reader_->ReadInsnTime(min_time);
}
inline bool TraceReaderBase::ReadAddr(uint64_t *time, uint32_t *addr, int *flags)
{
if (load_eof_ && store_eof_)
return true;
if (store_eof_ || (!load_eof_ && load_time_ <= store_time_)) {
*time = load_time_;
*addr = load_addr_;
*flags = 0;
load_eof_ = load_addr_reader_->ReadAddr(&load_time_, &load_addr_);
} else {
*time = store_time_;
*addr = store_addr_;
*flags = 1;
store_eof_ = store_addr_reader_->ReadAddr(&store_time_, &store_addr_);
}
return false;
}
inline bool TraceReaderBase::ReadExc(uint64_t *time, uint32_t *current_pc,
uint64_t *recnum, uint32_t *target_pc,
uint64_t *bb_num, uint64_t *bb_start_time,
int *num_insns)
{
return exc_reader_->ReadExc(time, current_pc, recnum, target_pc, bb_num,
bb_start_time, num_insns);
}
inline bool TraceReaderBase::ReadPidEvent(PidEvent *event)
{
return pid_reader_->ReadPidEvent(event);
}
inline bool TraceReaderBase::ReadMethod(MethodRec *method_record)
{
return method_reader_->ReadMethod(method_record);
}
// Duplicates a string, allocating space using new[].
inline char * Strdup(const char *src) {
int len = strlen(src);
char *copy = new char[len + 1];
strcpy(copy, src);
return copy;
}
#endif /* TRACE_READER_BASE_H */