Home | History | Annotate | Download | only in qtools
      1 // Copyright 2009 The Android Open Source Project
      2 
      3 #include <stdio.h>
      4 #include <unistd.h>
      5 #include <stdlib.h>
      6 #include <inttypes.h>
      7 #include <assert.h>
      8 #include "trace_reader.h"
      9 #include "bitvector.h"
     10 #include "parse_options.h"
     11 #include "armdis.h"
     12 
     13 typedef TraceReader<> TraceReaderType;
     14 
     15 #include "parse_options-inl.h"
     16 #include "callstack.h"
     17 
     18 typedef CallStack<StackFrame<symbol_type> > CallStackType;
     19 
     20 void compareStacks(uint64_t time, int pid);
     21 void dumpStacks(int pid);
     22 
     23 static uint64_t debugTime;
     24 static const int kNumStackFrames = 500;
     25 static const int kMaxThreads = (32 * 1024);
     26 CallStackType *eStacks[kMaxThreads];
     27 
     28 int numErrors;
     29 static const int kMaxErrors = 3;
     30 
     31 struct frame {
     32     uint64_t    time;
     33     uint32_t    addr;
     34     const char  *name;
     35     bool        isNative;
     36 
     37     frame(uint64_t time, uint32_t addr, const char *name, bool isNative) {
     38         this->time = time;
     39         this->addr = addr;
     40         this->name = name;
     41         this->isNative = isNative;
     42     }
     43 };
     44 
     45 class Stack {
     46 public:
     47     static const int kMaxFrames = 1000;
     48     int top;
     49     frame *frames[kMaxFrames];
     50 
     51     Stack() {
     52         top = 0;
     53     }
     54 
     55     void        push(frame *pframe);
     56     frame*      pop();
     57     void        dump();
     58 };
     59 
     60 void Stack::push(frame *pframe) {
     61     if (top == kMaxFrames) {
     62         fprintf(stderr, "Error: stack overflow\n");
     63         exit(1);
     64     }
     65     frames[top] = pframe;
     66     top += 1;
     67 }
     68 
     69 frame *Stack::pop() {
     70     if (top <= 0)
     71         return NULL;
     72     top -= 1;
     73     return frames[top];
     74 }
     75 
     76 Stack *mStacks[kMaxThreads];
     77 
     78 void Usage(const char *program)
     79 {
     80     fprintf(stderr, "Usage: %s [options] trace_name elf_file\n",
     81             program);
     82     OptionsUsage();
     83 }
     84 
     85 int main(int argc, char **argv)
     86 {
     87     ParseOptions(argc, argv);
     88     if (argc - optind != 2) {
     89         Usage(argv[0]);
     90         exit(1);
     91     }
     92 
     93     char *qemu_trace_file = argv[optind++];
     94     char *elf_file = argv[optind++];
     95 
     96     TraceReaderType *etrace = new TraceReaderType;
     97     etrace->Open(qemu_trace_file);
     98     etrace->ReadKernelSymbols(elf_file);
     99     etrace->SetRoot(root);
    100 
    101     TraceReaderType *mtrace = new TraceReaderType;
    102     mtrace->Open(qemu_trace_file);
    103     mtrace->ReadKernelSymbols(elf_file);
    104     mtrace->SetRoot(root);
    105 
    106     BBEvent event;
    107     while (1) {
    108         BBEvent ignored;
    109         symbol_type *function;
    110         MethodRec method_record;
    111         symbol_type *sym;
    112         TraceReaderType::ProcessState *proc;
    113         frame *pframe;
    114 
    115         if (mtrace->ReadMethodSymbol(&method_record, &sym, &proc))
    116             break;
    117 
    118         if (!IsValidPid(proc->pid))
    119             continue;
    120 
    121         // Get the stack for the current thread
    122         Stack *mStack = mStacks[proc->pid];
    123 
    124         // If the stack does not exist, then allocate a new one.
    125         if (mStack == NULL) {
    126             mStack = new Stack();
    127             mStacks[proc->pid] = mStack;
    128         }
    129 
    130         int flags = method_record.flags;
    131         if (flags == kMethodEnter || flags == kNativeEnter) {
    132             pframe = new frame(method_record.time, method_record.addr,
    133                                sym == NULL ? NULL: sym->name,
    134                                method_record.flags == kNativeEnter);
    135             mStack->push(pframe);
    136         } else {
    137             pframe = mStack->pop();
    138             delete pframe;
    139         }
    140 
    141         do {
    142             if (GetNextValidEvent(etrace, &event, &ignored, &function))
    143                 break;
    144             if (event.bb_num == 0)
    145                 break;
    146 
    147             // Get the stack for the current thread
    148             CallStackType *eStack = eStacks[event.pid];
    149 
    150             // If the stack does not exist, then allocate a new one.
    151             if (eStack == NULL) {
    152                 eStack = new CallStackType(event.pid, kNumStackFrames, etrace);
    153                 eStacks[event.pid] = eStack;
    154             }
    155             if (debugTime != 0 && event.time >= debugTime)
    156                 printf("time: %llu debug time: %lld\n", event.time, debugTime);
    157 
    158             // Update the stack
    159             eStack->updateStack(&event, function);
    160         } while (event.time < method_record.time);
    161 
    162         compareStacks(event.time, event.pid);
    163     }
    164 
    165     for (int ii = 0; ii < kMaxThreads; ++ii) {
    166         if (eStacks[ii])
    167             eStacks[ii]->popAll(event.time);
    168     }
    169 
    170     delete etrace;
    171     delete mtrace;
    172     return 0;
    173 }
    174 
    175 void compareStacks(uint64_t time, int pid) {
    176     CallStackType *eStack = eStacks[pid];
    177     Stack *mStack = mStacks[pid];
    178     frame **mFrames = mStack->frames;
    179     frame *mframe;
    180 
    181     int mTop = mStack->top;
    182     int eTop = eStack->mTop;
    183     CallStackType::frame_type *eFrames = eStack->mFrames;
    184 
    185     // Count the number of non-native methods (ie, Java methods) on the
    186     // Java method stack
    187     int numNonNativeMethods = 0;
    188     for (int ii = 0; ii < mTop; ++ii) {
    189         if (!mFrames[ii]->isNative) {
    190             numNonNativeMethods += 1;
    191         }
    192     }
    193 
    194     // Count the number of Java methods on the native stack
    195     int numMethods = 0;
    196     for (int ii = 0; ii < eTop; ++ii) {
    197         if (eFrames[ii].flags & CallStackType::frame_type::kInterpreted) {
    198             numMethods += 1;
    199         }
    200     }
    201 
    202     // Verify that the number of Java methods on both stacks are the same.
    203     // Allow the native stack to have one less Java method because the
    204     // native stack might be pushing a native function first.
    205     if (numNonNativeMethods != numMethods && numNonNativeMethods != numMethods + 1) {
    206         printf("\nDiff at time %llu pid %d: non-native %d numMethods %d\n",
    207                time, pid, numNonNativeMethods, numMethods);
    208         dumpStacks(pid);
    209         numErrors += 1;
    210         if (numErrors >= kMaxErrors)
    211             exit(1);
    212     }
    213 
    214     // Verify that the Java methods on the method stack are the same
    215     // as the Java methods on the native stack.
    216     int mIndex = 0;
    217     for (int ii = 0; ii < eTop; ++ii) {
    218         // Ignore native functions on the native stack.
    219         if ((eFrames[ii].flags & CallStackType::frame_type::kInterpreted) == 0)
    220             continue;
    221         uint32_t addr = eFrames[ii].function->addr;
    222         addr += eFrames[ii].function->region->vstart;
    223         while (mIndex < mTop && mFrames[mIndex]->isNative) {
    224             mIndex += 1;
    225         }
    226         if (mIndex >= mTop)
    227             break;
    228         if (addr != mFrames[mIndex]->addr) {
    229             printf("\nDiff at time %llu pid %d: frame %d\n", time, pid, ii);
    230             dumpStacks(pid);
    231             exit(1);
    232         }
    233         mIndex += 1;
    234     }
    235 }
    236 
    237 void dumpStacks(int pid) {
    238     CallStackType *eStack = eStacks[pid];
    239     Stack *mStack = mStacks[pid];
    240     frame *mframe;
    241 
    242     int mTop = mStack->top;
    243     printf("\nJava method stack\n");
    244     for (int ii = 0; ii < mTop; ii++) {
    245         mframe = mStack->frames[ii];
    246         const char *native = mframe->isNative ? "n" : " ";
    247         printf("  %s %d: %llu 0x%x %s\n",
    248                native, ii, mframe->time, mframe->addr,
    249                mframe->name == NULL ? "" : mframe->name);
    250     }
    251 
    252     int eTop = eStack->mTop;
    253     CallStackType::frame_type *eFrames = eStack->mFrames;
    254     int mIndex = 0;
    255     printf("\nNative stack\n");
    256     for (int ii = 0; ii < eTop; ++ii) {
    257         uint32_t addr = eFrames[ii].function->addr;
    258         addr += eFrames[ii].function->region->vstart;
    259         const char *marker = " ";
    260         if (eFrames[ii].flags & CallStackType::frame_type::kInterpreted) {
    261             if (mIndex >= mTop || addr != mStack->frames[mIndex]->addr) {
    262                 marker = "*";
    263             }
    264             mIndex += 1;
    265         }
    266         printf(" %s %d: %d f %d 0x%08x %s\n",
    267                marker, ii, eFrames[ii].time, eFrames[ii].flags, addr,
    268                eFrames[ii].function->name);
    269     }
    270 }
    271