blob: b4d14d31cc7792c245218a84aea18e1d36f9cee1 [file] [log] [blame]
Jack Veenstraf55a4d12009-05-09 11:56:59 -07001// 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
13typedef TraceReader<> TraceReaderType;
14
15#include "parse_options-inl.h"
16#include "callstack.h"
17
18typedef CallStack<StackFrame<symbol_type> > CallStackType;
19
20void compareStacks(uint64_t time, int pid);
21void dumpStacks(int pid);
22
23static uint64_t debugTime;
24static const int kNumStackFrames = 500;
25static const int kMaxThreads = (32 * 1024);
26CallStackType *eStacks[kMaxThreads];
27
28int numErrors;
29static const int kMaxErrors = 3;
30
31struct frame {
32 uint64_t time;
33 uint32_t addr;
34 const char *name;
Jack Veenstraa476e452009-05-19 16:47:04 -070035 bool isNative;
Jack Veenstraf55a4d12009-05-09 11:56:59 -070036
Jack Veenstraa476e452009-05-19 16:47:04 -070037 frame(uint64_t time, uint32_t addr, const char *name, bool isNative) {
Jack Veenstraf55a4d12009-05-09 11:56:59 -070038 this->time = time;
39 this->addr = addr;
40 this->name = name;
Jack Veenstraa476e452009-05-19 16:47:04 -070041 this->isNative = isNative;
Jack Veenstraf55a4d12009-05-09 11:56:59 -070042 }
43};
44
45class Stack {
46public:
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
60void 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
69frame *Stack::pop() {
70 if (top <= 0)
71 return NULL;
72 top -= 1;
73 return frames[top];
74}
75
76Stack *mStacks[kMaxThreads];
77
78void Usage(const char *program)
79{
80 fprintf(stderr, "Usage: %s [options] trace_name elf_file\n",
81 program);
82 OptionsUsage();
83}
84
85int 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
Jack Veenstraa476e452009-05-19 16:47:04 -0700130 int flags = method_record.flags;
131 if (flags == kMethodEnter || flags == kNativeEnter) {
Jack Veenstraf55a4d12009-05-09 11:56:59 -0700132 pframe = new frame(method_record.time, method_record.addr,
Jack Veenstraa476e452009-05-19 16:47:04 -0700133 sym == NULL ? NULL: sym->name,
134 method_record.flags == kNativeEnter);
Jack Veenstraf55a4d12009-05-09 11:56:59 -0700135 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
175void compareStacks(uint64_t time, int pid) {
176 CallStackType *eStack = eStacks[pid];
177 Stack *mStack = mStacks[pid];
Jack Veenstraa476e452009-05-19 16:47:04 -0700178 frame **mFrames = mStack->frames;
Jack Veenstraf55a4d12009-05-09 11:56:59 -0700179 frame *mframe;
180
181 int mTop = mStack->top;
182 int eTop = eStack->mTop;
183 CallStackType::frame_type *eFrames = eStack->mFrames;
184
Jack Veenstraa476e452009-05-19 16:47:04 -0700185 // 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
Jack Veenstraf55a4d12009-05-09 11:56:59 -0700194 // 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.
Jack Veenstraa476e452009-05-19 16:47:04 -0700205 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);
Jack Veenstraf55a4d12009-05-09 11:56:59 -0700208 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;
Jack Veenstraa476e452009-05-19 16:47:04 -0700223 while (mIndex < mTop && mFrames[mIndex]->isNative) {
224 mIndex += 1;
225 }
226 if (mIndex >= mTop)
227 break;
228 if (addr != mFrames[mIndex]->addr) {
Jack Veenstraf55a4d12009-05-09 11:56:59 -0700229 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
237void 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];
Jack Veenstraa476e452009-05-19 16:47:04 -0700246 const char *native = mframe->isNative ? "n" : " ";
247 printf(" %s %d: %llu 0x%x %s\n",
248 native, ii, mframe->time, mframe->addr,
Jack Veenstraf55a4d12009-05-09 11:56:59 -0700249 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}