• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
CreateTracePath(const char * filename,const char * ext)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 
AllocFuture()74 inline BBReader::Future *BBReader::AllocFuture()
75 {
76     Future *future = free_;
77     free_ = free_->next;
78     return future;
79 }
80 
FreeFuture(Future * future)81 inline void BBReader::FreeFuture(Future *future)
82 {
83     future->next = free_;
84     free_ = future;
85 }
86 
InsertFuture(Future * future)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.
DecodeNextRec()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 
BBReader(TraceReaderBase * trace)123 BBReader::BBReader(TraceReaderBase *trace)
124 {
125     trace_ = trace;
126     decoder_ = new Decoder;
127 }
128 
~BBReader()129 BBReader::~BBReader()
130 {
131     delete decoder_;
132 }
133 
Open(const char * filename)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 
Close()155 void BBReader::Close()
156 {
157     decoder_->Close();
158 }
159 
160 // Returns true at end of file.
ReadBB(BBEvent * event)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 
InsnReader()261 InsnReader::InsnReader()
262 {
263     decoder_ = new Decoder;
264 }
265 
~InsnReader()266 InsnReader::~InsnReader()
267 {
268     delete decoder_;
269 }
270 
Open(const char * filename)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 
Close()283 void InsnReader::Close()
284 {
285     decoder_->Close();
286 }
287 
ReadInsnTime(uint64_t min_time)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 
AddrReader()301 AddrReader::AddrReader()
302 {
303     decoder_ = new Decoder;
304     opened_ = false;
305 }
306 
~AddrReader()307 AddrReader::~AddrReader()
308 {
309     delete decoder_;
310 }
311 
312 // Returns true if there is an error opening the file
Open(const char * filename,const char * suffix)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 
Close()334 void AddrReader::Close()
335 {
336     decoder_->Close();
337 }
338 
339 // Returns true at end of file.
ReadAddr(uint64_t * time,uint32_t * addr)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 
ExcReader()360 ExcReader::ExcReader()
361 {
362     decoder_ = new Decoder;
363 }
364 
~ExcReader()365 ExcReader::~ExcReader()
366 {
367     delete decoder_;
368 }
369 
Open(const char * filename)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 
Close()381 void ExcReader::Close()
382 {
383     decoder_->Close();
384 }
385 
386 // Returns true at end of file.
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)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 
PidReader()414 PidReader::PidReader()
415 {
416     decoder_ = new Decoder;
417 }
418 
~PidReader()419 PidReader::~PidReader()
420 {
421     delete decoder_;
422 }
423 
Open(const char * filename)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 
Close()434 void PidReader::Close()
435 {
436     decoder_->Close();
437 }
438 
439 // Returns true at end of file.
ReadPidEvent(PidEvent * event)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.
Dispose(PidEvent * 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 
MethodReader()553 MethodReader::MethodReader()
554 {
555     decoder_ = new Decoder;
556     opened_ = false;
557 }
558 
~MethodReader()559 MethodReader::~MethodReader()
560 {
561     delete decoder_;
562 }
563 
Open(const char * filename)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 
Close()586 void MethodReader::Close()
587 {
588     decoder_->Close();
589 }
590 
591 // Returns true at end of file.
ReadMethod(MethodRec * method_record)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 
TraceReaderBase()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 
~TraceReaderBase()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 
ReadTraceHeader(FILE * fstream,const char * filename,const char * tracename,TraceHeader * header)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 
Open(const char * filename)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.
FindMmapDexFileEvent()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 
CopyDexSymbolsToArray(DexFileList * dexfile,DexSymList * head,int num_symbols)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 
ParseDexList(const char * filename)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@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.
ExtractDexPathFromMmap(const char * mmap_path)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 
Close()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 
WriteHeader(TraceHeader * header)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.
ReadStatic(StaticRec * rec)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.
ReadStaticInsns(int num,uint32_t * insns)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 
TruncateLastBlock(uint32_t num_insns)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 
FindNumInsns(uint64_t bb_num,uint64_t bb_start_time)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.
FindCurrentPid(uint64_t time)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