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