• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
frameframe37     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 
Stack()51     Stack() {
52         top = 0;
53     }
54 
55     void        push(frame *pframe);
56     frame*      pop();
57     void        dump();
58 };
59 
push(frame * pframe)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 
pop()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 
Usage(const char * program)78 void Usage(const char *program)
79 {
80     fprintf(stderr, "Usage: %s [options] trace_name elf_file\n",
81             program);
82     OptionsUsage();
83 }
84 
main(int argc,char ** argv)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 
compareStacks(uint64_t time,int pid)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 
dumpStacks(int pid)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