Home | History | Annotate | Download | only in qtools
      1 // Copyright 2006 The Android Open Source Project
      2 
      3 #include <stdio.h>
      4 #include <stdlib.h>
      5 #include <string.h>
      6 #include <limits.h>
      7 #include <inttypes.h>
      8 #include <assert.h>
      9 #include <unistd.h>
     10 #include <sys/types.h>
     11 #include <sys/stat.h>
     12 #include <elf.h>
     13 #include "trace_reader.h"
     14 #include "decoder.h"
     15 
     16 // A struct for creating temporary linked-lists of DexSym structs
     17 struct DexSymList {
     18     DexSymList  *next;
     19     DexSym      sym;
     20 };
     21 
     22 // Declare static functions used in this file
     23 static char *ExtractDexPathFromMmap(const char *mmap_path);
     24 static void CopyDexSymbolsToArray(DexFileList *dexfile,
     25                                   DexSymList *head, int num_symbols);
     26 
     27 // This function creates the pathname to the a specific trace file.  The
     28 // string space is allocated in this routine and must be freed by the
     29 // caller.
     30 static char *CreateTracePath(const char *filename, const char *ext)
     31 {
     32     char *fname;
     33     const char *base_start, *base_end;
     34     int ii, len, base_len, dir_len, path_len, qtrace_len;
     35 
     36     // Handle error cases
     37     if (filename == NULL || *filename == 0 || strcmp(filename, "/") == 0)
     38         return NULL;
     39 
     40     // Ignore a trailing slash, if any
     41     len = strlen(filename);
     42     if (filename[len - 1] == '/')
     43         len -= 1;
     44 
     45     // Find the basename.  We don't use basename(3) because there are
     46     // different behaviors for GNU and Posix in the case where the
     47     // last character is a slash.
     48     base_start = base_end = &filename[len];
     49     for (ii = 0; ii < len; ++ii) {
     50         base_start -= 1;
     51         if (*base_start == '/') {
     52             base_start += 1;
     53             break;
     54         }
     55     }
     56     base_len = base_end - base_start;
     57     dir_len = len - base_len;
     58     qtrace_len = strlen("/qtrace");
     59 
     60     // Create space for the pathname: "/dir/basename/qtrace.ext"
     61     // The "ext" string already contains the dot, so just add a byte
     62     // for the terminating zero.
     63     path_len = dir_len + base_len + qtrace_len + strlen(ext) + 1;
     64     fname = new char[path_len];
     65     if (dir_len > 0)
     66         strncpy(fname, filename, dir_len);
     67     fname[dir_len] = 0;
     68     strncat(fname, base_start, base_len);
     69     strcat(fname, "/qtrace");
     70     strcat(fname, ext);
     71     return fname;
     72 }
     73 
     74 inline BBReader::Future *BBReader::AllocFuture()
     75 {
     76     Future *future = free_;
     77     free_ = free_->next;
     78     return future;
     79 }
     80 
     81 inline void BBReader::FreeFuture(Future *future)
     82 {
     83     future->next = free_;
     84     free_ = future;
     85 }
     86 
     87 inline void BBReader::InsertFuture(Future *future)
     88 {
     89     uint64_t future_time = future->bb.next_time;
     90     Future *prev = NULL;
     91     Future *ptr;
     92     for (ptr = head_; ptr; prev = ptr, ptr = ptr->next) {
     93         if (future_time <= ptr->bb.next_time)
     94             break;
     95     }
     96     if (prev == NULL) {
     97         // link it at the front
     98         future->next = head_;
     99         head_ = future;
    100     } else {
    101         // link it after "prev"
    102         future->next = prev->next;
    103         prev->next = future;
    104     }
    105 }
    106 
    107 // Decodes the next basic block record from the file.  Returns 1
    108 // at end-of-file, otherwise returns 0.
    109 inline int BBReader::DecodeNextRec()
    110 {
    111     int64_t bb_diff = decoder_->Decode(true);
    112     uint64_t time_diff = decoder_->Decode(false);
    113     nextrec_.bb_rec.repeat = decoder_->Decode(false);
    114     if (time_diff == 0)
    115         return 1;
    116     if (nextrec_.bb_rec.repeat)
    117         nextrec_.bb_rec.time_diff = decoder_->Decode(false);
    118     nextrec_.bb_rec.bb_num += bb_diff;
    119     nextrec_.bb_rec.start_time += time_diff;
    120     return 0;
    121 }
    122 
    123 BBReader::BBReader(TraceReaderBase *trace)
    124 {
    125     trace_ = trace;
    126     decoder_ = new Decoder;
    127 }
    128 
    129 BBReader::~BBReader()
    130 {
    131     delete decoder_;
    132 }
    133 
    134 void BBReader::Open(const char *filename)
    135 {
    136     // Initialize the class variables
    137     memset(&nextrec_, 0, sizeof(TimeRec));
    138     memset(futures_, 0, sizeof(Future) * kMaxNumBasicBlocks);
    139     head_ = NULL;
    140 
    141     // Link all of the futures_[] array elements on the free list.
    142     for (int ii = 0; ii < kMaxNumBasicBlocks - 1; ++ii) {
    143         futures_[ii].next = &futures_[ii + 1];
    144     }
    145     futures_[kMaxNumBasicBlocks - 1].next = 0;
    146     free_ = &futures_[0];
    147 
    148     // Open the trace.bb file
    149     char *fname = CreateTracePath(filename, ".bb");
    150     decoder_->Open(fname);
    151     is_eof_ = DecodeNextRec();
    152     delete[] fname;
    153 }
    154 
    155 void BBReader::Close()
    156 {
    157     decoder_->Close();
    158 }
    159 
    160 // Returns true at end of file.
    161 bool BBReader::ReadBB(BBEvent *event)
    162 {
    163     if (is_eof_ && head_ == NULL) {
    164         return true;
    165     }
    166 
    167 #if 0
    168     if (nextrec_) {
    169         printf("nextrec: buffer[%d], bb_num: %lld start: %d diff %d repeat %d next %u\n",
    170                nextrec_ - &buffer_[0],
    171                nextrec_->bb_rec.bb_num, nextrec_->bb_rec.start_time,
    172                nextrec_->bb_rec.time_diff, nextrec_->bb_rec.repeat,
    173                nextrec_->next_time);
    174     }
    175     if (head_) {
    176         printf("head: 0x%x, bb_num: %lld start: %d diff %d repeat %d next %u\n",
    177                head_,
    178                head_->bb->bb_rec.bb_num, head_->bb->bb_rec.start_time,
    179                head_->bb->bb_rec.time_diff, head_->bb->bb_rec.repeat,
    180                head_->bb->next_time);
    181     }
    182 #endif
    183     if (!is_eof_) {
    184         if (head_) {
    185             TimeRec *bb = &head_->bb;
    186             if (bb->next_time < nextrec_.bb_rec.start_time) {
    187                 // The head is earlier.
    188                 event->time = bb->next_time;
    189                 event->bb_num = bb->bb_rec.bb_num;
    190                 event->bb_addr = trace_->GetBBAddr(event->bb_num);
    191                 event->insns = trace_->GetInsns(event->bb_num);
    192                 event->num_insns = trace_->FindNumInsns(event->bb_num, event->time);
    193                 event->pid = trace_->FindCurrentPid(event->time);
    194                 event->is_thumb = trace_->GetIsThumb(event->bb_num);
    195 
    196                 // Remove the head element from the list
    197                 Future *future = head_;
    198                 head_ = head_->next;
    199                 if (bb->bb_rec.repeat > 0) {
    200                     // there are more repetitions of this bb
    201                     bb->bb_rec.repeat -= 1;
    202                     bb->next_time += bb->bb_rec.time_diff;
    203 
    204                     // Insert this future into the sorted list
    205                     InsertFuture(future);
    206                 } else {
    207                     // Add this future to the free list
    208                     FreeFuture(future);
    209                 }
    210                 return false;
    211             }
    212         }
    213         // The nextrec is earlier (or there was no head)
    214         event->time = nextrec_.bb_rec.start_time;
    215         event->bb_num = nextrec_.bb_rec.bb_num;
    216         event->bb_addr = trace_->GetBBAddr(event->bb_num);
    217         event->insns = trace_->GetInsns(event->bb_num);
    218         event->num_insns = trace_->FindNumInsns(event->bb_num, event->time);
    219         event->pid = trace_->FindCurrentPid(event->time);
    220         event->is_thumb = trace_->GetIsThumb(event->bb_num);
    221         if (nextrec_.bb_rec.repeat > 0) {
    222             Future *future = AllocFuture();
    223             future->bb.bb_rec = nextrec_.bb_rec;
    224             future->bb.bb_rec.repeat -= 1;
    225             future->bb.next_time = nextrec_.bb_rec.start_time + nextrec_.bb_rec.time_diff;
    226             InsertFuture(future);
    227         }
    228 
    229         is_eof_ = DecodeNextRec();
    230         return false;
    231     }
    232 
    233     //printf("using head_ 0x%x\n", head_);
    234     assert(head_);
    235     TimeRec *bb = &head_->bb;
    236     event->time = bb->next_time;
    237     event->bb_num = bb->bb_rec.bb_num;
    238     event->bb_addr = trace_->GetBBAddr(event->bb_num);
    239     event->insns = trace_->GetInsns(event->bb_num);
    240     event->num_insns = trace_->FindNumInsns(event->bb_num, event->time);
    241     event->pid = trace_->FindCurrentPid(event->time);
    242     event->is_thumb = trace_->GetIsThumb(event->bb_num);
    243 
    244     // Remove the head element from the list
    245     Future *future = head_;
    246     head_ = head_->next;
    247     if (bb->bb_rec.repeat > 0) {
    248         // there are more repetitions of this bb
    249         bb->bb_rec.repeat -= 1;
    250         bb->next_time += bb->bb_rec.time_diff;
    251 
    252         // Insert this future into the sorted list
    253         InsertFuture(future);
    254     } else {
    255         // Add this future to the free list
    256         FreeFuture(future);
    257     }
    258     return false;
    259 }
    260 
    261 InsnReader::InsnReader()
    262 {
    263     decoder_ = new Decoder;
    264 }
    265 
    266 InsnReader::~InsnReader()
    267 {
    268     delete decoder_;
    269 }
    270 
    271 void InsnReader::Open(const char *filename)
    272 {
    273     prev_time_ = 0;
    274     time_diff_ = 0;
    275     repeat_ = -1;
    276 
    277     // Open the trace.insn file
    278     char *fname = CreateTracePath(filename, ".insn");
    279     decoder_->Open(fname);
    280     delete[] fname;
    281 }
    282 
    283 void InsnReader::Close()
    284 {
    285     decoder_->Close();
    286 }
    287 
    288 uint64_t InsnReader::ReadInsnTime(uint64_t min_time)
    289 {
    290     do {
    291         if (repeat_ == -1) {
    292             time_diff_ = decoder_->Decode(false);
    293             repeat_ = decoder_->Decode(false);
    294         }
    295         prev_time_ += time_diff_;
    296         repeat_ -= 1;
    297     } while (prev_time_ < min_time);
    298     return prev_time_;
    299 }
    300 
    301 AddrReader::AddrReader()
    302 {
    303     decoder_ = new Decoder;
    304     opened_ = false;
    305 }
    306 
    307 AddrReader::~AddrReader()
    308 {
    309     delete decoder_;
    310 }
    311 
    312 // Returns true if there is an error opening the file
    313 bool AddrReader::Open(const char *filename, const char *suffix)
    314 {
    315     struct stat stat_buf;
    316 
    317     prev_addr_ = 0;
    318     prev_time_ = 0;
    319 
    320     // Open the trace.addr file
    321     char *fname = CreateTracePath(filename, suffix);
    322     int rval = stat(fname, &stat_buf);
    323     if (rval == -1) {
    324         // The file does not exist
    325         delete[] fname;
    326         return true;
    327     }
    328     decoder_->Open(fname);
    329     opened_ = true;
    330     delete[] fname;
    331     return false;
    332 }
    333 
    334 void AddrReader::Close()
    335 {
    336     decoder_->Close();
    337 }
    338 
    339 // Returns true at end of file.
    340 bool AddrReader::ReadAddr(uint64_t *time, uint32_t *addr)
    341 {
    342     if (!opened_) {
    343         fprintf(stderr, "Cannot read address trace\n");
    344         exit(1);
    345     }
    346     uint32_t addr_diff = decoder_->Decode(true);
    347     uint64_t time_diff = decoder_->Decode(false);
    348     if (time_diff == 0 && addr_diff == 0) {
    349         *addr = 0;
    350         *time = 0;
    351         return true;
    352     }
    353     prev_addr_ += addr_diff;
    354     prev_time_ += time_diff;
    355     *addr = prev_addr_;
    356     *time = prev_time_;
    357     return false;
    358 }
    359 
    360 ExcReader::ExcReader()
    361 {
    362     decoder_ = new Decoder;
    363 }
    364 
    365 ExcReader::~ExcReader()
    366 {
    367     delete decoder_;
    368 }
    369 
    370 void ExcReader::Open(const char *filename)
    371 {
    372     prev_time_ = 0;
    373     prev_recnum_ = 0;
    374 
    375     // Open the trace.exc file
    376     char *fname = CreateTracePath(filename, ".exc");
    377     decoder_->Open(fname);
    378     delete[] fname;
    379 }
    380 
    381 void ExcReader::Close()
    382 {
    383     decoder_->Close();
    384 }
    385 
    386 // Returns true at end of file.
    387 bool ExcReader::ReadExc(uint64_t *time, uint32_t *current_pc, uint64_t *recnum,
    388                         uint32_t *target_pc, uint64_t *bb_num,
    389                         uint64_t *bb_start_time, int *num_insns)
    390 {
    391     uint64_t time_diff = decoder_->Decode(false);
    392     uint32_t pc = decoder_->Decode(false);
    393     if ((time_diff | pc) == 0) {
    394         decoder_->Decode(false);
    395         decoder_->Decode(false);
    396         decoder_->Decode(false);
    397         decoder_->Decode(false);
    398         decoder_->Decode(false);
    399         return true;
    400     }
    401     uint64_t recnum_diff = decoder_->Decode(false);
    402     prev_time_ += time_diff;
    403     prev_recnum_ += recnum_diff;
    404     *time = prev_time_;
    405     *current_pc = pc;
    406     *recnum = prev_recnum_;
    407     *target_pc = decoder_->Decode(false);
    408     *bb_num = decoder_->Decode(false);
    409     *bb_start_time = decoder_->Decode(false);
    410     *num_insns = decoder_->Decode(false);
    411     return false;
    412 }
    413 
    414 PidReader::PidReader()
    415 {
    416     decoder_ = new Decoder;
    417 }
    418 
    419 PidReader::~PidReader()
    420 {
    421     delete decoder_;
    422 }
    423 
    424 void PidReader::Open(const char *filename)
    425 {
    426     prev_time_ = 0;
    427 
    428     // Open the trace.pid file
    429     char *fname = CreateTracePath(filename, ".pid");
    430     decoder_->Open(fname);
    431     delete[] fname;
    432 }
    433 
    434 void PidReader::Close()
    435 {
    436     decoder_->Close();
    437 }
    438 
    439 // Returns true at end of file.
    440 bool PidReader::ReadPidEvent(PidEvent *event)
    441 {
    442     uint64_t time_diff = decoder_->Decode(false);
    443     int rec_type = decoder_->Decode(false);
    444     prev_time_ += time_diff;
    445     event->time = prev_time_;
    446     event->rec_type = rec_type;
    447     switch(rec_type) {
    448         case kPidEndOfFile:
    449             return true;
    450         case kPidSwitch:
    451         case kPidExit:
    452             event->pid = decoder_->Decode(false);
    453             break;
    454         case kPidFork:
    455         case kPidClone:
    456             event->tgid = decoder_->Decode(false);
    457             event->pid = decoder_->Decode(false);
    458             break;
    459         case kPidMmap:
    460             {
    461                 event->vstart = decoder_->Decode(false);
    462                 event->vend = decoder_->Decode(false);
    463                 event->offset = decoder_->Decode(false);
    464                 int len = decoder_->Decode(false);
    465                 char *path = new char[len + 1];
    466                 decoder_->Read(path, len);
    467                 path[len] = 0;
    468                 event->path = path;
    469                 event->mmap_path = path;
    470                 char *dexfile = ExtractDexPathFromMmap(path);
    471                 if (dexfile != NULL) {
    472                     delete[] event->path;
    473                     event->path = dexfile;
    474                 }
    475             }
    476             break;
    477         case kPidMunmap:
    478             {
    479                 event->vstart = decoder_->Decode(false);
    480                 event->vend = decoder_->Decode(false);
    481             }
    482             break;
    483         case kPidSymbolAdd:
    484             {
    485                 event->vstart = decoder_->Decode(false);
    486                 int len = decoder_->Decode(false);
    487                 char *path = new char[len + 1];
    488                 decoder_->Read(path, len);
    489                 path[len] = 0;
    490                 event->path = path;
    491             }
    492             break;
    493         case kPidSymbolRemove:
    494             event->vstart = decoder_->Decode(false);
    495             break;
    496         case kPidExec:
    497             {
    498                 int argc = decoder_->Decode(false);
    499                 event->argc = argc;
    500                 char **argv = new char*[argc];
    501                 event->argv = argv;
    502                 for (int ii = 0; ii < argc; ++ii) {
    503                     int alen = decoder_->Decode(false);
    504                     argv[ii] = new char[alen + 1];
    505                     decoder_->Read(argv[ii], alen);
    506                     argv[ii][alen] = 0;
    507                 }
    508             }
    509             break;
    510         case kPidName:
    511         case kPidKthreadName:
    512             {
    513                 if (rec_type == kPidKthreadName) {
    514                     event->tgid = decoder_->Decode(false);
    515                 }
    516                 event->pid = decoder_->Decode(false);
    517                 int len = decoder_->Decode(false);
    518                 char *path = new char[len + 1];
    519                 decoder_->Read(path, len);
    520                 path[len] = 0;
    521                 event->path = path;
    522             }
    523             break;
    524     }
    525     return false;
    526 }
    527 
    528 // Frees the memory that might have been allocated for the given event.
    529 void PidReader::Dispose(PidEvent *event)
    530 {
    531     switch(event->rec_type) {
    532         case kPidMmap:
    533         case kPidSymbolAdd:
    534         case kPidName:
    535         case kPidKthreadName:
    536             delete[] event->path;
    537             event->path = NULL;
    538             event->mmap_path = NULL;
    539             break;
    540 
    541         case kPidExec:
    542             for (int ii = 0; ii < event->argc; ++ii) {
    543                 delete[] event->argv[ii];
    544             }
    545             delete[] event->argv;
    546             event->argv = NULL;
    547             event->argc = 0;
    548             break;
    549     }
    550 }
    551 
    552 
    553 MethodReader::MethodReader()
    554 {
    555     decoder_ = new Decoder;
    556     opened_ = false;
    557 }
    558 
    559 MethodReader::~MethodReader()
    560 {
    561     delete decoder_;
    562 }
    563 
    564 bool MethodReader::Open(const char *filename)
    565 {
    566     struct stat stat_buf;
    567 
    568     prev_time_ = 0;
    569     prev_addr_ = 0;
    570     prev_pid_ = 0;
    571 
    572     // Open the trace.method file
    573     char *fname = CreateTracePath(filename, ".method");
    574     int rval = stat(fname, &stat_buf);
    575     if (rval == -1) {
    576         // The file does not exist
    577         delete[] fname;
    578         return true;
    579     }
    580     decoder_->Open(fname);
    581     delete[] fname;
    582     opened_ = true;
    583     return false;
    584 }
    585 
    586 void MethodReader::Close()
    587 {
    588     decoder_->Close();
    589 }
    590 
    591 // Returns true at end of file.
    592 bool MethodReader::ReadMethod(MethodRec *method_record)
    593 {
    594     if (!opened_)
    595         return true;
    596     uint64_t time_diff = decoder_->Decode(false);
    597     int32_t addr_diff = decoder_->Decode(true);
    598     if (time_diff == 0) {
    599         method_record->time = 0;
    600         method_record->addr = 0;
    601         method_record->flags = 0;
    602         return true;
    603     }
    604     int32_t pid_diff = decoder_->Decode(true);
    605     prev_time_ += time_diff;
    606     prev_addr_ += addr_diff;
    607     prev_pid_ += pid_diff;
    608     method_record->time = prev_time_;
    609     method_record->addr = prev_addr_;
    610     method_record->pid = prev_pid_;
    611     method_record->flags = decoder_->Decode(false);
    612     return false;
    613 }
    614 
    615 TraceReaderBase::TraceReaderBase()
    616 {
    617     static_filename_ = NULL;
    618     static_fstream_ = NULL;
    619     header_ = new TraceHeader;
    620     bb_reader_ = new BBReader(this);
    621     insn_reader_ = new InsnReader;
    622     load_addr_reader_ = new AddrReader;
    623     store_addr_reader_ = new AddrReader;
    624     exc_reader_ = new ExcReader;
    625     pid_reader_ = new PidReader;
    626     method_reader_ = new MethodReader;
    627     internal_exc_reader_ = new ExcReader;
    628     internal_pid_reader_ = new PidReader;
    629     internal_method_reader_ = new MethodReader;
    630     blocks_ = NULL;
    631     bb_recnum_ = 0;
    632     exc_recnum_ = 0;
    633     exc_end_ = false;
    634     exc_bb_num_ = 0;
    635     exc_time_ = 0;
    636     exc_num_insns_ = 0;
    637     current_pid_ = 0;
    638     next_pid_ = 0;
    639     next_pid_switch_time_ = 0;
    640     post_processing_ = false;
    641     dex_hash_ = NULL;
    642     load_eof_ = false;
    643     load_time_ = 0;
    644     load_addr_ = 0;
    645     store_eof_ = false;
    646     store_time_ = 0;
    647     store_addr_ = 0;
    648 }
    649 
    650 TraceReaderBase::~TraceReaderBase()
    651 {
    652     Close();
    653     delete bb_reader_;
    654     delete insn_reader_;
    655     delete load_addr_reader_;
    656     delete store_addr_reader_;
    657     delete exc_reader_;
    658     delete pid_reader_;
    659     delete method_reader_;
    660     delete internal_exc_reader_;
    661     delete internal_pid_reader_;
    662     delete internal_method_reader_;
    663     if (blocks_) {
    664         int num_static_bb = header_->num_static_bb;
    665         for (int ii = 0; ii < num_static_bb; ++ii) {
    666             delete[] blocks_[ii].insns;
    667         }
    668         delete[] blocks_;
    669     }
    670     delete header_;
    671     if (dex_hash_ != NULL) {
    672         HashTable<DexFileList*>::entry_type *ptr;
    673         for (ptr = dex_hash_->GetFirst(); ptr; ptr = dex_hash_->GetNext()) {
    674             DexFileList *dexfile = ptr->value;
    675             delete[] dexfile->path;
    676             int nsymbols = dexfile->nsymbols;
    677             DexSym *symbols = dexfile->symbols;
    678             for (int ii = 0; ii < nsymbols; ii++) {
    679                 delete[] symbols[ii].name;
    680             }
    681             delete[] dexfile->symbols;
    682             delete dexfile;
    683         }
    684     }
    685     delete dex_hash_;
    686     delete[] static_filename_;
    687 }
    688 
    689 void TraceReaderBase::ReadTraceHeader(FILE *fstream, const char *filename,
    690                                       const char *tracename, TraceHeader *header)
    691 {
    692     int rval = fread(header, sizeof(TraceHeader), 1, fstream);
    693     if (rval != 1) {
    694         perror(filename);
    695         exit(1);
    696     }
    697 
    698     if (!post_processing_ && strcmp(header->ident, TRACE_IDENT) != 0) {
    699         fprintf(stderr, "%s: missing trace header; run 'post_trace %s' first\n",
    700                 filename, tracename);
    701         exit(1);
    702     }
    703 
    704     if (header->version != TRACE_VERSION) {
    705         fprintf(stderr,
    706                 "%s: trace header version (%d) does not match compiled tools version (%d)\n",
    707                 tracename, header->version, TRACE_VERSION);
    708         exit(1);
    709     }
    710 
    711     convert32(header->version);
    712     convert32(header->start_sec);
    713     convert32(header->start_usec);
    714     convert32(header->pdate);
    715     convert32(header->ptime);
    716     convert64(header->num_static_bb);
    717     convert64(header->num_static_insn);
    718     convert64(header->num_dynamic_bb);
    719     convert64(header->num_dynamic_insn);
    720     convert64(header->elapsed_usecs);
    721 }
    722 
    723 
    724 void TraceReaderBase::Open(const char *filename)
    725 {
    726     char *fname;
    727     FILE *fstream;
    728 
    729     // Open the qtrace.bb file
    730     bb_reader_->Open(filename);
    731 
    732     // Open the qtrace.insn file
    733     insn_reader_->Open(filename);
    734 
    735     // Open the qtrace.load file and read the first line
    736     load_eof_ = load_addr_reader_->Open(filename, ".load");
    737     if (!load_eof_)
    738         load_eof_ = load_addr_reader_->ReadAddr(&load_time_, &load_addr_);
    739 
    740     // Open the qtrace.store file and read the first line
    741     store_eof_ = store_addr_reader_->Open(filename, ".store");
    742     if (!store_eof_)
    743         store_eof_ = store_addr_reader_->ReadAddr(&store_time_, &store_addr_);
    744 
    745     // Open the qtrace.exc file
    746     exc_reader_->Open(filename);
    747 
    748     // Open another file stream to the qtrace.exc file for internal reads.
    749     // This allows the caller to also read from the qtrace.exc file.
    750     internal_exc_reader_->Open(filename);
    751 
    752     // Open the qtrace.pid file
    753     pid_reader_->Open(filename);
    754     internal_pid_reader_->Open(filename);
    755 
    756     // Open the qtrace.method file
    757     method_reader_->Open(filename);
    758     internal_method_reader_->Open(filename);
    759 
    760     // Open the qtrace.static file
    761     fname = CreateTracePath(filename, ".static");
    762     static_filename_ = fname;
    763 
    764     fstream = fopen(fname, "r");
    765     if (fstream == NULL) {
    766         perror(fname);
    767         exit(1);
    768     }
    769     static_fstream_ = fstream;
    770 
    771     // Read the header
    772     ReadTraceHeader(fstream, fname, filename, header_);
    773 
    774     // Allocate space for all of the static blocks
    775     int num_static_bb = header_->num_static_bb;
    776     if (num_static_bb) {
    777         blocks_ = new StaticBlock[num_static_bb];
    778 
    779         // Read in all the static blocks
    780         for (int ii = 0; ii < num_static_bb; ++ii) {
    781             ReadStatic(&blocks_[ii].rec);
    782             int num_insns = blocks_[ii].rec.num_insns;
    783             if (num_insns > 0) {
    784                 blocks_[ii].insns = new uint32_t[num_insns];
    785                 ReadStaticInsns(num_insns, blocks_[ii].insns);
    786             } else {
    787                 blocks_[ii].insns = NULL;
    788             }
    789         }
    790         fseek(static_fstream_, sizeof(TraceHeader), SEEK_SET);
    791     }
    792 
    793     ParseDexList(filename);
    794 
    795     // If the dex_hash_ is NULL, then assign it a small hash table
    796     // so that we can simply do a Find() operation without having
    797     // to check for NULL first.
    798     if (dex_hash_ == NULL) {
    799         dex_hash_ = new HashTable<DexFileList*>(1, NULL);
    800     }
    801 }
    802 
    803 // Reads the list of pid events looking for an mmap of a dex file.
    804 PidEvent * TraceReaderBase::FindMmapDexFileEvent()
    805 {
    806     static PidEvent event;
    807 
    808     while (!pid_reader_->ReadPidEvent(&event)) {
    809         if (event.rec_type == kPidMmap && event.path != event.mmap_path) {
    810             return &event;
    811         }
    812         pid_reader_->Dispose(&event);
    813     }
    814     return NULL;
    815 }
    816 
    817 static void CopyDexSymbolsToArray(DexFileList *dexfile,
    818                                   DexSymList *head, int num_symbols)
    819 {
    820     if (dexfile == NULL)
    821         return;
    822 
    823     DexSym *symbols = NULL;
    824     if (num_symbols > 0) {
    825         symbols = new DexSym[num_symbols];
    826     }
    827     dexfile->nsymbols = num_symbols;
    828     dexfile->symbols = symbols;
    829 
    830     // Copy the linked-list to the array.
    831     DexSymList *next_sym = NULL;
    832     int next_index = 0;
    833     for (DexSymList *sym = head; sym; sym = next_sym) {
    834         next_sym = sym->next;
    835         symbols[next_index].addr = sym->sym.addr;
    836         symbols[next_index].len = sym->sym.len;
    837         symbols[next_index].name = sym->sym.name;
    838         next_index += 1;
    839         delete sym;
    840     }
    841 }
    842 
    843 void TraceReaderBase::ParseDexList(const char *filename)
    844 {
    845     struct stat stat_buf;
    846     static const int kBufSize = 4096;
    847     char buf[kBufSize];
    848     char current_file[kBufSize];
    849 
    850     // Find an example dex file in the list of mmaps
    851     PidEvent *event = FindMmapDexFileEvent();
    852 
    853     // Reset the pid_reader to the beginning of the file.
    854     pid_reader_->Close();
    855     pid_reader_->Open(filename);
    856 
    857     // If there were no mmapped dex files, then there is no need to parse
    858     // the dexlist.
    859     if (event == NULL)
    860         return;
    861     char *mmap_dexfile = event->path;
    862 
    863     // Check if the dexlist file exists.  It should have the name
    864     // "qtrace.dexlist"
    865     char *fname = CreateTracePath(filename, ".dexlist");
    866     int rval = stat(fname, &stat_buf);
    867     if (rval == -1) {
    868         // The file does not exist
    869         delete[] fname;
    870         return;
    871     }
    872 
    873     // Open the qtrace.dexlist file
    874     FILE *fstream = fopen(fname, "r");
    875     if (fstream == NULL) {
    876         perror(fname);
    877         exit(1);
    878     }
    879 
    880     // First pass: read all the filenames, looking for a match for the
    881     // example mmap dex filename.  Also count the files so that we
    882     // know how big to make the hash table.
    883     char *match = NULL;
    884     int num_files = 0;
    885     while (fgets(buf, kBufSize, fstream)) {
    886         if (buf[0] != '#')
    887             continue;
    888         num_files += 1;
    889         match = strstr(buf + 1, mmap_dexfile);
    890 
    891         // Check that the dexlist file ends with the string mmap_dexfile.
    892         // We add one to the length of the mmap_dexfile because buf[]
    893         // ends with a newline.  The strlen(mmap_dexfile) computation
    894         // could be moved above the loop but it should only ever be
    895         // executed once.
    896         if (match != NULL && strlen(match) == strlen(mmap_dexfile) + 1)
    897             break;
    898     }
    899 
    900     // Count the rest of the files
    901     while (fgets(buf, kBufSize, fstream)) {
    902         if (buf[0] == '#')
    903             num_files += 1;
    904     }
    905 
    906     if (match == NULL) {
    907         fprintf(stderr,
    908                 "Cannot find the mmapped dex file '%s' in the dexlist\n",
    909                 mmap_dexfile);
    910         exit(1);
    911     }
    912     delete[] mmap_dexfile;
    913 
    914     // The prefix length includes the leading '#'.
    915     int prefix_len = match - buf;
    916 
    917     // Allocate a hash table
    918     dex_hash_ = new HashTable<DexFileList*>(4 * num_files, NULL);
    919 
    920     // Reset the file stream to the beginning
    921     rewind(fstream);
    922 
    923     // Second pass: read the filenames, stripping off the common prefix.
    924     // And read all the (address, method) mappings.  When we read a new
    925     // filename, create a new DexFileList and add it to the hash table.
    926     // Add new symbol mappings to a linked list until we have the whole
    927     // list and then create an array for them so that we can use binary
    928     // search on the address to find the symbol name quickly.
    929 
    930     // Use a linked list for storing the symbols
    931     DexSymList *head = NULL;
    932     DexSymList *prev = NULL;
    933     int num_symbols = 0;
    934 
    935     DexFileList *dexfile = NULL;
    936     int linenum = 0;
    937     while (fgets(buf, kBufSize, fstream)) {
    938         linenum += 1;
    939         if (buf[0] == '#') {
    940             // Everything after the '#' is a filename.
    941             // Ignore the common prefix.
    942 
    943             // First, save all the symbols from the previous file (if any).
    944             CopyDexSymbolsToArray(dexfile, head, num_symbols);
    945 
    946             dexfile = new DexFileList;
    947             // Subtract one because buf[] contains a trailing newline
    948             int pathlen = strlen(buf) - prefix_len - 1;
    949             char *path = new char[pathlen + 1];
    950             strncpy(path, buf + prefix_len, pathlen);
    951             path[pathlen] = 0;
    952             dexfile->path = path;
    953             dexfile->nsymbols = 0;
    954             dexfile->symbols = NULL;
    955             dex_hash_->Update(path, dexfile);
    956             num_symbols = 0;
    957             head = NULL;
    958             prev = NULL;
    959             continue;
    960         }
    961 
    962         uint32_t addr;
    963         int len, line;
    964         char clazz[kBufSize], method[kBufSize], sig[kBufSize], file[kBufSize];
    965         if (sscanf(buf, "0x%x %d %s %s %s %s %d",
    966                    &addr, &len, clazz, method, sig, file, &line) != 7) {
    967             fprintf(stderr, "Cannot parse line %d of file %s:\n%s",
    968                     linenum, fname, buf);
    969             exit(1);
    970         }
    971 
    972         // Concatenate the class name, method name, and signature
    973         // plus one for the period separating the class and method.
    974         int nchars = strlen(clazz) + strlen(method) + strlen(sig) + 1;
    975         char *name = new char[nchars + 1];
    976         strcpy(name, clazz);
    977         strcat(name, ".");
    978         strcat(name, method);
    979         strcat(name, sig);
    980 
    981         DexSymList *symbol = new DexSymList;
    982         symbol->sym.addr = addr;
    983         symbol->sym.len = len;
    984         symbol->sym.name = name;
    985         symbol->next = NULL;
    986 
    987         // Keep the list in the same order as the file
    988         if (head == NULL)
    989             head = symbol;
    990         if (prev != NULL)
    991             prev->next = symbol;
    992         prev = symbol;
    993         num_symbols += 1;
    994     }
    995     fclose(fstream);
    996 
    997     // Copy the symbols from the last file.
    998     CopyDexSymbolsToArray(dexfile, head, num_symbols);
    999     delete[] fname;
   1000 }
   1001 
   1002 // Extracts the pathname to a jar file (or .apk file) from the mmap pathname.
   1003 // An example mmap pathname looks something like this:
   1004 //   /data/dalvik-cache/system@app (at) TestHarness.apk@classes.dex
   1005 // We want to convert that to this:
   1006 //   /system/app/TestHarness.apk
   1007 // If the pathname is not of the expected form, then NULL is returned.
   1008 // The space for the extracted path is allocated in this routine and should
   1009 // be freed by the caller after it is no longer needed.
   1010 static char *ExtractDexPathFromMmap(const char *mmap_path)
   1011 {
   1012     const char *end = rindex(mmap_path, '@');
   1013     if (end == NULL)
   1014         return NULL;
   1015     const char *start = rindex(mmap_path, '/');
   1016     if (start == NULL)
   1017         return NULL;
   1018     int len = end - start;
   1019     char *path = new char[len + 1];
   1020     strncpy(path, start, len);
   1021     path[len] = 0;
   1022 
   1023     // Replace all the occurrences of '@' with '/'
   1024     for (int ii = 0; ii < len; ii++) {
   1025         if (path[ii] == '@')
   1026             path[ii] = '/';
   1027     }
   1028     return path;
   1029 }
   1030 
   1031 void TraceReaderBase::Close()
   1032 {
   1033     bb_reader_->Close();
   1034     insn_reader_->Close();
   1035     load_addr_reader_->Close();
   1036     store_addr_reader_->Close();
   1037     exc_reader_->Close();
   1038     pid_reader_->Close();
   1039     method_reader_->Close();
   1040     internal_exc_reader_->Close();
   1041     internal_pid_reader_->Close();
   1042     internal_method_reader_->Close();
   1043     fclose(static_fstream_);
   1044     static_fstream_ = NULL;
   1045 }
   1046 
   1047 void TraceReaderBase::WriteHeader(TraceHeader *header)
   1048 {
   1049     TraceHeader swappedHeader;
   1050 
   1051     freopen(static_filename_, "r+", static_fstream_);
   1052     fseek(static_fstream_, 0, SEEK_SET);
   1053 
   1054     memcpy(&swappedHeader, header, sizeof(TraceHeader));
   1055 
   1056     convert32(swappedHeader.version);
   1057     convert32(swappedHeader.start_sec);
   1058     convert32(swappedHeader.start_usec);
   1059     convert32(swappedHeader.pdate);
   1060     convert32(swappedHeader.ptime);
   1061     convert64(swappedHeader.num_static_bb);
   1062     convert64(swappedHeader.num_static_insn);
   1063     convert64(swappedHeader.num_dynamic_bb);
   1064     convert64(swappedHeader.num_dynamic_insn);
   1065     convert64(swappedHeader.elapsed_usecs);
   1066 
   1067     fwrite(&swappedHeader, sizeof(TraceHeader), 1, static_fstream_);
   1068 }
   1069 
   1070 // Reads the next StaticRec from the trace file (not including the list
   1071 // of instructions).  On end-of-file, this function returns true.
   1072 int TraceReaderBase::ReadStatic(StaticRec *rec)
   1073 {
   1074     int rval = fread(rec, sizeof(StaticRec), 1, static_fstream_);
   1075     if (rval != 1) {
   1076         if (feof(static_fstream_)) {
   1077             return true;
   1078         }
   1079         perror(static_filename_);
   1080         exit(1);
   1081     }
   1082     convert64(rec->bb_num);
   1083     convert32(rec->bb_addr);
   1084     convert32(rec->num_insns);
   1085     return false;
   1086 }
   1087 
   1088 // Reads "num" instructions into the array "insns" which must be large
   1089 // enough to hold the "num" instructions.
   1090 // Returns the actual number of instructions read.  This will usually
   1091 // be "num" but may be less if end-of-file occurred.
   1092 int TraceReaderBase::ReadStaticInsns(int num, uint32_t *insns)
   1093 {
   1094     if (num == 0)
   1095         return 0;
   1096     int rval = fread(insns, sizeof(uint32_t), num, static_fstream_);
   1097 
   1098     // Convert from little-endian, if necessary
   1099     for (int ii = 0; ii < num; ++ii)
   1100         convert32(insns[ii]);
   1101 
   1102     if (rval != num) {
   1103         if (feof(static_fstream_)) {
   1104             return rval;
   1105         }
   1106         perror(static_filename_);
   1107         exit(1);
   1108     }
   1109     return rval;
   1110 }
   1111 
   1112 void TraceReaderBase::TruncateLastBlock(uint32_t num_insns)
   1113 {
   1114     uint32_t insns[kMaxInsnPerBB];
   1115     StaticRec static_rec;
   1116     long loc = 0, prev_loc = 0;
   1117 
   1118     freopen(static_filename_, "r+", static_fstream_);
   1119     fseek(static_fstream_, sizeof(TraceHeader), SEEK_SET);
   1120 
   1121     // Find the last record
   1122     while (1) {
   1123         prev_loc = loc;
   1124         loc = ftell(static_fstream_);
   1125 
   1126         // We don't need to byte-swap static_rec here because we are just
   1127         // reading the records until we get to the last one.
   1128         int rval = fread(&static_rec, sizeof(StaticRec), 1, static_fstream_);
   1129         if (rval != 1)
   1130             break;
   1131         ReadStaticInsns(static_rec.num_insns, insns);
   1132     }
   1133     if (prev_loc != 0) {
   1134         fseek(static_fstream_, prev_loc, SEEK_SET);
   1135         static_rec.num_insns = num_insns;
   1136 
   1137         // Now we need to byte-swap, but just the field that we changed.
   1138         convert32(static_rec.num_insns);
   1139         fwrite(&static_rec, sizeof(StaticRec), 1, static_fstream_);
   1140         int fd = fileno(static_fstream_);
   1141         long len = ftell(static_fstream_);
   1142         len += num_insns * sizeof(uint32_t);
   1143         ftruncate(fd, len);
   1144     }
   1145 }
   1146 
   1147 int TraceReaderBase::FindNumInsns(uint64_t bb_num, uint64_t bb_start_time)
   1148 {
   1149     int num_insns;
   1150 
   1151     // Read the exception trace file.  "bb_recnum_" is the number of
   1152     // basic block records that have been read so far, and "exc_recnum_"
   1153     // is the record number from the exception trace.
   1154     while (!exc_end_ && exc_recnum_ < bb_recnum_) {
   1155         uint32_t current_pc, target_pc;
   1156         uint64_t time;
   1157 
   1158         exc_end_ = internal_exc_reader_->ReadExc(&time, &current_pc, &exc_recnum_,
   1159                                                  &target_pc, &exc_bb_num_,
   1160                                                  &exc_time_, &exc_num_insns_);
   1161     }
   1162 
   1163     // If an exception occurred in this basic block, then use the
   1164     // number of instructions specified in the exception record.
   1165     if (!exc_end_ && exc_recnum_ == bb_recnum_) {
   1166         num_insns = exc_num_insns_;
   1167     } else {
   1168         // Otherwise, use the number of instructions specified in the
   1169         // static basic block.
   1170         num_insns = blocks_[bb_num].rec.num_insns;
   1171     }
   1172     return num_insns;
   1173 }
   1174 
   1175 // Finds the current pid for the given time.  This routine reads the pid
   1176 // trace file and assumes that the "time" parameter is monotonically
   1177 // increasing.
   1178 int TraceReaderBase::FindCurrentPid(uint64_t time)
   1179 {
   1180     PidEvent event;
   1181 
   1182     if (time < next_pid_switch_time_)
   1183         return current_pid_;
   1184 
   1185     current_pid_ = next_pid_;
   1186     while (1) {
   1187         if (internal_pid_reader_->ReadPidEvent(&event)) {
   1188             next_pid_switch_time_ = ~0ull;
   1189             break;
   1190         }
   1191         if (event.rec_type != kPidSwitch)
   1192             continue;
   1193         if (event.time > time) {
   1194             next_pid_ = event.pid;
   1195             next_pid_switch_time_ = event.time;
   1196             break;
   1197         }
   1198         current_pid_ = event.pid;
   1199     }
   1200     return current_pid_;
   1201 }
   1202