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