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