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, &current_pc, &exc_recnum_,
1159                                                 &target_pc, &exc_bb_num_,
1160                                                 &exc_time_, &exc_num_insns_);
1161    }
1162
1163    // If an exception occurred in this basic block, then use the
1164    // number of instructions specified in the exception record.
1165    if (!exc_end_ && exc_recnum_ == bb_recnum_) {
1166        num_insns = exc_num_insns_;
1167    } else {
1168        // Otherwise, use the number of instructions specified in the
1169        // static basic block.
1170        num_insns = blocks_[bb_num].rec.num_insns;
1171    }
1172    return num_insns;
1173}
1174
1175// Finds the current pid for the given time.  This routine reads the pid
1176// trace file and assumes that the "time" parameter is monotonically
1177// increasing.
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