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 17struct DexSymList { 18 DexSymList *next; 19 DexSym sym; 20}; 21 22// Declare static functions used in this file 23static char *ExtractDexPathFromMmap(const char *mmap_path); 24static 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. 30static 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 74inline BBReader::Future *BBReader::AllocFuture() 75{ 76 Future *future = free_; 77 free_ = free_->next; 78 return future; 79} 80 81inline void BBReader::FreeFuture(Future *future) 82{ 83 future->next = free_; 84 free_ = future; 85} 86 87inline 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. 109inline 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 123BBReader::BBReader(TraceReaderBase *trace) 124{ 125 trace_ = trace; 126 decoder_ = new Decoder; 127} 128 129BBReader::~BBReader() 130{ 131 delete decoder_; 132} 133 134void 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 155void BBReader::Close() 156{ 157 decoder_->Close(); 158} 159 160// Returns true at end of file. 161bool 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 261InsnReader::InsnReader() 262{ 263 decoder_ = new Decoder; 264} 265 266InsnReader::~InsnReader() 267{ 268 delete decoder_; 269} 270 271void 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 283void InsnReader::Close() 284{ 285 decoder_->Close(); 286} 287 288uint64_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 301AddrReader::AddrReader() 302{ 303 decoder_ = new Decoder; 304 opened_ = false; 305} 306 307AddrReader::~AddrReader() 308{ 309 delete decoder_; 310} 311 312// Returns true if there is an error opening the file 313bool 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 334void AddrReader::Close() 335{ 336 decoder_->Close(); 337} 338 339// Returns true at end of file. 340bool 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 360ExcReader::ExcReader() 361{ 362 decoder_ = new Decoder; 363} 364 365ExcReader::~ExcReader() 366{ 367 delete decoder_; 368} 369 370void 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 381void ExcReader::Close() 382{ 383 decoder_->Close(); 384} 385 386// Returns true at end of file. 387bool 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 414PidReader::PidReader() 415{ 416 decoder_ = new Decoder; 417} 418 419PidReader::~PidReader() 420{ 421 delete decoder_; 422} 423 424void 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 434void PidReader::Close() 435{ 436 decoder_->Close(); 437} 438 439// Returns true at end of file. 440bool 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. 529void 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 553MethodReader::MethodReader() 554{ 555 decoder_ = new Decoder; 556 opened_ = false; 557} 558 559MethodReader::~MethodReader() 560{ 561 delete decoder_; 562} 563 564bool 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 586void MethodReader::Close() 587{ 588 decoder_->Close(); 589} 590 591// Returns true at end of file. 592bool 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 615TraceReaderBase::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 650TraceReaderBase::~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 689void 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 724void 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. 804PidEvent * 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 817static 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 843void 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. 1010static 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 1031void 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 1047void 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. 1072int 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. 1092int 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 1112void 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 1147int 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. 1178int 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