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, ¤t_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