// 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 */