blob: 89823301f8944b59823f383c97082fce6fa2e995 [file] [log] [blame]
The Android Open Source Project52d4c302009-03-03 19:29:09 -08001// Copyright 2006 The Android Open Source Project
2
3#ifndef CALL_STACK_H
4#define CALL_STACK_H
5
6#include "opcode.h"
7#include "armdis.h"
8
9class CallStackBase {
10 public:
11 int getId() { return mId; }
12 void setId(int id) { mId = id; }
13
14 private:
15 int mId;
16};
17
18// Define a template class for the stack frame. The template parameter
19// SYM is the symbol_type from the TraceReader<> template class. To
20// use the CallStack class, the user derives a subclass of StackFrame
21// and defines push() and pop() methods. This derived class is then
22// passed as a template parameter to CallStack.
23template <class SYM>
24class StackFrame {
25 public:
26
27 virtual ~StackFrame() {};
28
29 virtual void push(int stackLevel, uint64_t time, CallStackBase *base) {};
30 virtual void pop(int stackLevel, uint64_t time, CallStackBase *base) {};
31
32 typedef SYM symbol_type;
33 static const uint32_t kCausedException = 0x01;
34 static const uint32_t kInterpreted = 0x02;
Jack Veenstra2bb9bb42009-05-19 15:07:29 -070035 static const uint32_t kStartNative = 0x04;
36 static const uint32_t kPopBarrier = (kCausedException | kInterpreted
37 | kStartNative);
The Android Open Source Project52d4c302009-03-03 19:29:09 -080038
39 symbol_type *function; // the symbol for the function we entered
40 uint32_t addr; // return address when this function returns
41 uint32_t flags;
42 uint32_t time; // for debugging when a problem occurred
43 uint32_t global_time; // for debugging when a problem occurred
44};
45
46template <class FRAME, class BASE = CallStackBase>
47class CallStack : public BASE {
Jack Veenstra2bb9bb42009-05-19 15:07:29 -070048public:
Jack Veenstra12985702009-05-09 11:50:34 -070049 typedef FRAME frame_type;
The Android Open Source Project52d4c302009-03-03 19:29:09 -080050 typedef typename FRAME::symbol_type symbol_type;
51 typedef typename FRAME::symbol_type::region_type region_type;
52 typedef BASE base_type;
53
54 CallStack(int id, int numFrames, TraceReaderType *trace);
55 ~CallStack();
56
57 void updateStack(BBEvent *event, symbol_type *function);
58 void popAll(uint64_t time);
59 void threadStart(uint64_t time);
60 void threadStop(uint64_t time);
61
Jack Veenstra2bb9bb42009-05-19 15:07:29 -070062 // Set to true if you don't want to see any Java methods ever
The Android Open Source Project52d4c302009-03-03 19:29:09 -080063 void setNativeOnly(bool nativeOnly) {
64 mNativeOnly = nativeOnly;
65 }
66
67 int getStackLevel() { return mTop; }
68
69 uint64_t getGlobalTime(uint64_t time) { return time + mSkippedTime; }
Jack Veenstra12985702009-05-09 11:50:34 -070070 void showStack(FILE *stream);
Jack Veenstra12985702009-05-09 11:50:34 -070071
72 int mNumFrames;
73 FRAME *mFrames;
74 int mTop; // index of the next stack frame to write
The Android Open Source Project52d4c302009-03-03 19:29:09 -080075
Jack Veenstra2bb9bb42009-05-19 15:07:29 -070076private:
77 enum Action { NONE, PUSH, POP, NATIVE_PUSH };
The Android Open Source Project52d4c302009-03-03 19:29:09 -080078
79 Action getAction(BBEvent *event, symbol_type *function);
Jack Veenstra2bb9bb42009-05-19 15:07:29 -070080 void doMethodAction(BBEvent *event, symbol_type *function);
81 void doMethodPop(BBEvent *event, uint32_t addr, const uint32_t flags);
The Android Open Source Project52d4c302009-03-03 19:29:09 -080082 void doSimplePush(symbol_type *function, uint32_t addr,
Jack Veenstra2bb9bb42009-05-19 15:07:29 -070083 uint64_t time, int flags);
The Android Open Source Project52d4c302009-03-03 19:29:09 -080084 void doSimplePop(uint64_t time);
85 void doPush(BBEvent *event, symbol_type *function);
86 void doPop(BBEvent *event, symbol_type *function, Action methodAction);
87
The Android Open Source Project52d4c302009-03-03 19:29:09 -080088 TraceReaderType *mTrace;
Jack Veenstra2bb9bb42009-05-19 15:07:29 -070089
90 // This is a global switch that disables Java methods from appearing
91 // on the stack.
The Android Open Source Project52d4c302009-03-03 19:29:09 -080092 bool mNativeOnly;
Jack Veenstra2bb9bb42009-05-19 15:07:29 -070093
94 // This keeps track of whether native frames are currently allowed on the
95 // stack.
96 bool mAllowNativeFrames;
The Android Open Source Project52d4c302009-03-03 19:29:09 -080097
98 symbol_type mDummyFunction;
99 region_type mDummyRegion;
100
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800101 symbol_type *mPrevFunction;
102 BBEvent mPrevEvent;
103
104 symbol_type *mUserFunction;
105 BBEvent mUserEvent; // the previous user-mode event
106
107 uint64_t mSkippedTime;
108 uint64_t mLastRunTime;
109
110 static MethodRec sCurrentMethod;
111 static MethodRec sNextMethod;
112};
113
114template<class FRAME, class BASE>
115MethodRec CallStack<FRAME, BASE>::sCurrentMethod;
116template<class FRAME, class BASE>
117MethodRec CallStack<FRAME, BASE>::sNextMethod;
118
119template<class FRAME, class BASE>
120CallStack<FRAME, BASE>::CallStack(int id, int numFrames, TraceReaderType *trace)
121{
122 mNativeOnly = false;
123 mTrace = trace;
124 BASE::setId(id);
125 mNumFrames = numFrames;
126 mFrames = new FRAME[mNumFrames];
127 mTop = 0;
Jack Veenstra2bb9bb42009-05-19 15:07:29 -0700128 mAllowNativeFrames = true;
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800129
130 memset(&mDummyFunction, 0, sizeof(symbol_type));
131 memset(&mDummyRegion, 0, sizeof(region_type));
132 mDummyFunction.region = &mDummyRegion;
133 mPrevFunction = &mDummyFunction;
134 memset(&mPrevEvent, 0, sizeof(BBEvent));
135 mUserFunction = &mDummyFunction;
136 memset(&mUserEvent, 0, sizeof(BBEvent));
137 mSkippedTime = 0;
138 mLastRunTime = 0;
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800139
140 // Read the first two methods from the trace if we haven't already read
141 // from the method trace yet.
142 if (sCurrentMethod.time == 0) {
143 if (mTrace->ReadMethod(&sCurrentMethod)) {
144 sCurrentMethod.time = ~0ull;
145 sNextMethod.time = ~0ull;
146 }
147 if (sNextMethod.time != ~0ull && mTrace->ReadMethod(&sNextMethod)) {
148 sNextMethod.time = ~0ull;
149 }
150 }
151}
152
153template<class FRAME, class BASE>
154CallStack<FRAME, BASE>::~CallStack()
155{
156 delete mFrames;
157}
158
159template<class FRAME, class BASE>
160void
161CallStack<FRAME, BASE>::updateStack(BBEvent *event, symbol_type *function)
162{
163 if (mNativeOnly) {
164 // If this is an interpreted function, then use the native VM function
165 // instead.
166 if (function->vm_sym != NULL)
167 function = function->vm_sym;
Jack Veenstra2bb9bb42009-05-19 15:07:29 -0700168 } else {
169 doMethodAction(event, function);
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800170 }
171
172 Action action = getAction(event, function);
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800173
Jack Veenstra2bb9bb42009-05-19 15:07:29 -0700174 // Allow native frames if we are executing in the kernel.
175 if (!mAllowNativeFrames
176 && (function->region->flags & region_type::kIsKernelRegion) == 0) {
177 action = NONE;
178 }
179
180 if (function->vm_sym != NULL) {
181 function = function->vm_sym;
182 function->vm_sym = NULL;
183 }
184 if (action == PUSH) {
185 doPush(event, function);
186 } else if (action == POP) {
187 doPop(event, function, NONE);
188 }
189
190#if 0
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800191 // Pop off native functions before pushing or popping Java methods.
192 if (action == POP && mPrevFunction->vm_sym == NULL) {
193 // Pop off the previous function first.
194 doPop(event, function, NONE);
195 if (methodAction == POP) {
196 doPop(event, function, POP);
197 } else if (methodAction == PUSH) {
198 doPush(event, function);
199 }
200 } else {
201 if (methodAction != NONE) {
202 // If the method trace has a push or pop, then do it.
203 action = methodAction;
204 } else if (function->vm_sym != NULL) {
205 // This function is a Java method. Don't push or pop the
206 // Java method without a corresponding method trace record.
207 action = NONE;
208 }
209 if (action == POP) {
210 doPop(event, function, methodAction);
211 } else if (action == PUSH) {
212 doPush(event, function);
213 }
214 }
Jack Veenstra2bb9bb42009-05-19 15:07:29 -0700215#endif
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800216
217 // If the stack is now empty, then push the current function.
218 if (mTop == 0) {
219 uint64_t time = event->time - mSkippedTime;
Jack Veenstra2bb9bb42009-05-19 15:07:29 -0700220 int flags = 0;
221 if (function->vm_sym != NULL) {
222 flags = FRAME::kInterpreted;
223 }
224 doSimplePush(function, 0, time, 0);
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800225 }
226
227 mPrevFunction = function;
228 mPrevEvent = *event;
229}
230
231template<class FRAME, class BASE>
232void
233CallStack<FRAME, BASE>::threadStart(uint64_t time)
234{
235 mSkippedTime += time - mLastRunTime;
236}
237
238template<class FRAME, class BASE>
239void
240CallStack<FRAME, BASE>::threadStop(uint64_t time)
241{
242 mLastRunTime = time;
243}
244
245template<class FRAME, class BASE>
246typename CallStack<FRAME, BASE>::Action
247CallStack<FRAME, BASE>::getAction(BBEvent *event, symbol_type *function)
248{
249 Action action;
250 uint32_t offset;
251
252 // Compute the offset from the start of the function to this basic
253 // block address.
254 offset = event->bb_addr - function->addr - function->region->base_addr;
255
256 // Get the previously executed instruction
257 Opcode op = OP_INVALID;
258 int numInsns = mPrevEvent.num_insns;
259 uint32_t insn = 0;
260 if (numInsns > 0) {
261 insn = mPrevEvent.insns[numInsns - 1];
262 if (mPrevEvent.is_thumb) {
263 insn = insn_unwrap_thumb(insn);
264 op = decode_insn_thumb(insn);
265 } else {
266 op = Arm::decode(insn);
267 }
268 }
269
270 // The number of bytes in the previous basic block depends on
271 // whether the basic block was ARM or THUMB instructions.
272 int numBytes;
273 if (mPrevEvent.is_thumb) {
274 numBytes = numInsns << 1;
275 } else {
276 numBytes = numInsns << 2;
277 }
278
279 // If this basic block follows the previous one, then return NONE.
280 // If we don't do this, then we may be fooled into thinking this
281 // is a POP if the previous block ended with a conditional
282 // (non-executed) ldmia instruction. We do this check before
283 // checking if we are in a different function because we otherwise
284 // we might be fooled into thinking this is a PUSH to a new function
285 // when it is really just a fall-thru into a local kernel symbol
286 // that just looks like a new function.
287 uint32_t prev_end_addr = mPrevEvent.bb_addr + numBytes;
288 if (prev_end_addr == event->bb_addr) {
289 return NONE;
290 }
291
292 // If this basic block is in the same function as the last basic block,
293 // then just return NONE (but see the exceptions below).
294 // Exception 1: if the function calls itself (offset == 0) then we
295 // want to push this function.
296 // Exception 2: if the function returns to itself, then we want
297 // to pop this function. We detect this case by checking if the last
298 // instruction in the previous basic block was a load-multiple (ldm)
299 // and included r15 as one of the loaded registers.
300 if (function == mPrevFunction) {
301 if (numInsns > 0) {
302 // If this is the beginning of the function and the previous
303 // instruction was not a branch, then it's a PUSH.
304 if (offset == 0 && op != OP_B && op != OP_THUMB_B)
305 return PUSH;
306
307 // If the previous instruction was an ldm that loaded r15,
308 // then it's a POP.
309 if (offset != 0 && ((op == OP_LDM && (insn & 0x8000))
310 || (op == OP_THUMB_POP && (insn & 0x100)))) {
311 return POP;
312 }
313 }
314
315 return NONE;
316 }
317
318 // We have to figure out if this new function is a call or a
319 // return. We don't necessarily have a complete call stack (since
320 // we could have started tracing at any point), so we have to use
321 // heuristics. If the address we are jumping to is the beginning
322 // of a function, or if the instruction that took us there was
323 // either "bl" or "blx" then this is a PUSH. Also, if the
324 // function offset is non-zero and the previous instruction is a
325 // branch instruction, we will call it a PUSH. This happens in
326 // the kernel a lot when there is a branch to an offset from a
327 // label. A couple more special cases:
328 //
329 // - entering a .plt section ("procedure linkage table") is a PUSH,
330 // - an exception that jumps into the kernel vector entry point
331 // is also a push.
332 //
333 // If the function offset is non-zero and the previous instruction
334 // is a bx or some non-branch instruction, then it's a POP.
335 //
336 // There's another special case that comes up. The user code
337 // might execute an instruction that returns but before the pc
338 // starts executing in the caller, a kernel interrupt occurs.
339 // But it may be hard to tell if this is a return until after
340 // the kernel interrupt code is done and returns to user space.
341 // So we save the last user basic block and look at it when
342 // we come back into user space.
343
344 const uint32_t kIsKernelRegion = region_type::kIsKernelRegion;
345
346 if (((mPrevFunction->region->flags & kIsKernelRegion) == 0)
347 && (function->region->flags & kIsKernelRegion)) {
348 // We just switched into the kernel. Save the previous
349 // user-mode basic block and function.
350 mUserEvent = mPrevEvent;
351 mUserFunction = mPrevFunction;
352 } else if ((mPrevFunction->region->flags & kIsKernelRegion)
353 && ((function->region->flags & kIsKernelRegion) == 0)) {
354 // We just switched from kernel to user mode.
355 return POP;
356 }
357
358 action = PUSH;
359 if (offset != 0 && mPrevFunction != &mDummyFunction) {
360 // We are jumping into the middle of a function, so this is
361 // probably a return, not a function call. But look at the
362 // previous instruction first to see if it was a branch-and-link.
363
364 // If the previous instruction was not a branch (and not a
365 // branch-and-link) then POP; or if it is a "bx" instruction
366 // then POP because that is used to return from functions.
367 if (!isBranch(op) || op == OP_BX || op == OP_THUMB_BX) {
368 action = POP;
369 } else if (isBranch(op) && !isBranchLink(op)) {
370 // If the previous instruction was a normal branch to a
371 // local symbol then don't count it as a push or a pop.
372 action = NONE;
373 }
374
375 if (function->flags & symbol_type::kIsVectorTable)
376 action = PUSH;
377 }
378 return action;
379}
380
381
382template<class FRAME, class BASE>
383void CallStack<FRAME, BASE>::doPush(BBEvent *event, symbol_type *function)
384{
385 uint64_t time = event->time - mSkippedTime;
386
387 // Check for stack overflow
388 if (mTop >= mNumFrames) {
Jack Veenstra12985702009-05-09 11:50:34 -0700389 // Don't show the stack by default because this generates a lot
390 // of output and this is seen by users if there is an error when
391 // post-processing the trace. But this is useful for debugging.
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800392#if 0
Jack Veenstra12985702009-05-09 11:50:34 -0700393 showStack(stderr);
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800394#endif
395 fprintf(stderr, "Error: stack overflow (%d frames)\n", mTop);
396 exit(1);
397 }
398
399 // Compute the return address here because we may need to change
400 // it if we are popping off a frame for a vector table.
401 int numBytes;
402 if (mPrevEvent.is_thumb) {
403 numBytes = mPrevEvent.num_insns << 1;
404 } else {
405 numBytes = mPrevEvent.num_insns << 2;
406 }
407 uint32_t retAddr = mPrevEvent.bb_addr + numBytes;
408
409 // If this is a Java method then set the return address to zero.
410 // We won't be using it for popping the method and it may lead
411 // to false matches when searching the stack.
412 if (function->vm_sym != NULL) {
413 retAddr = 0;
414 }
415
416#if 0
Jack Veenstra12985702009-05-09 11:50:34 -0700417 // For debugging only. Show the stack before entering the kernel
418 // exception-handling code.
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800419 if (function->flags & symbol_type::kIsVectorStart) {
420 printf("stack before entering exception\n");
Jack Veenstra12985702009-05-09 11:50:34 -0700421 showStack(stderr);
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800422 }
423#endif
424
Jack Veenstra12985702009-05-09 11:50:34 -0700425 // If the top of stack is a vector table, then pop it
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800426 // off before pushing on the new function. Also, change the
427 // return address for the new function to the return address
428 // from the vector table.
Jack Veenstra12985702009-05-09 11:50:34 -0700429 if (mTop > 0
430 && (mFrames[mTop - 1].function->flags & symbol_type::kIsVectorTable)) {
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800431 retAddr = mFrames[mTop - 1].addr;
432 doSimplePop(time);
433 }
434
435 const uint32_t kIsKernelRegion = region_type::kIsKernelRegion;
436
437 // The following code handles the case where one function, F1,
438 // calls another function, F2, but the before F2 can start
439 // executing, it takes a page fault (on the first instruction
440 // in F2). The kernel is entered, handles the page fault, and
441 // then returns to the called function. The problem is that
442 // this looks like a new function call to F2 from the kernel.
443 // The following code cleans up the stack by popping the
444 // kernel frames back to F1 (but not including F1). The
445 // return address for F2 also has to be fixed up to point to
446 // F1 instead of the kernel.
447 //
448 // We detect this case by checking if the previous basic block
449 // was in the kernel and the current basic block is not.
450 if ((mPrevFunction->region->flags & kIsKernelRegion)
451 && ((function->region->flags & kIsKernelRegion) == 0)
452 && mTop > 0) {
453 // We are switching from kernel mode to user mode.
454#if 0
Jack Veenstra12985702009-05-09 11:50:34 -0700455 // For debugging.
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800456 printf(" doPush(): popping to user mode, bb_addr: 0x%08x\n",
457 event->bb_addr);
Jack Veenstra12985702009-05-09 11:50:34 -0700458 showStack(stderr);
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800459#endif
460 do {
461 // Pop off the kernel frames until we reach the one that
462 // caused the exception.
463 doSimplePop(time);
464
465 // If the next stack frame is the one that caused an
466 // exception then stop popping frames.
467 if (mTop > 0
468 && (mFrames[mTop - 1].flags & FRAME::kCausedException)) {
469 mFrames[mTop - 1].flags &= ~FRAME::kCausedException;
470 retAddr = mFrames[mTop].addr;
471 break;
472 }
473 } while (mTop > 0);
474#if 0
Jack Veenstra12985702009-05-09 11:50:34 -0700475 // For debugging
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800476 printf(" doPush() popping to level %d, using retAddr 0x%08x\n",
477 mTop, retAddr);
478#endif
479 }
480
481 // If we are starting an exception handler, then mark the previous
482 // stack frame so that we know where to return when the exception
483 // handler finishes.
484 if ((function->flags & symbol_type::kIsVectorStart) && mTop > 0)
485 mFrames[mTop - 1].flags |= FRAME::kCausedException;
486
Jack Veenstra2bb9bb42009-05-19 15:07:29 -0700487 // If the function being pushed is a Java method, then mark it on
488 // the stack so that we don't pop it off until we get a matching
489 // trace record from the method trace file.
490 int flags = 0;
491 if (function->vm_sym != NULL) {
492 flags = FRAME::kInterpreted;
493 }
494 doSimplePush(function, retAddr, time, flags);
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800495}
496
497template<class FRAME, class BASE>
Jack Veenstra2bb9bb42009-05-19 15:07:29 -0700498void CallStack<FRAME, BASE>::doSimplePush(symbol_type *function, uint32_t addr,
499 uint64_t time, int flags)
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800500{
501 // Check for stack overflow
502 if (mTop >= mNumFrames) {
Jack Veenstra12985702009-05-09 11:50:34 -0700503 showStack(stderr);
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800504 fprintf(stderr, "too many stack frames (%d)\n", mTop);
505 exit(1);
506 }
507
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800508 mFrames[mTop].addr = addr;
509 mFrames[mTop].function = function;
Jack Veenstra2bb9bb42009-05-19 15:07:29 -0700510 mFrames[mTop].flags = flags;
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800511 mFrames[mTop].time = time;
512 mFrames[mTop].global_time = time + mSkippedTime;
513
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800514 mFrames[mTop].push(mTop, time, this);
515 mTop += 1;
516}
517
518template<class FRAME, class BASE>
519void CallStack<FRAME, BASE>::doSimplePop(uint64_t time)
520{
521 if (mTop <= 0) {
522 return;
523 }
524
525 mTop -= 1;
526 mFrames[mTop].pop(mTop, time, this);
527
Jack Veenstra2bb9bb42009-05-19 15:07:29 -0700528 if (mNativeOnly)
529 return;
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800530
Jack Veenstra2bb9bb42009-05-19 15:07:29 -0700531 // If the stack is empty, then allow more native frames.
532 // Otherwise, if we are transitioning from Java to native, then allow
533 // more native frames.
534 // Otherwise, if we are transitioning from native to Java, then disallow
535 // more native frames.
536 if (mTop == 0) {
537 mAllowNativeFrames = true;
538 } else {
539 bool newerIsJava = (mFrames[mTop].flags & FRAME::kInterpreted) != 0;
540 bool olderIsJava = (mFrames[mTop - 1].flags & FRAME::kInterpreted) != 0;
541 if (newerIsJava && !olderIsJava) {
542 // We are transitioning from Java to native
543 mAllowNativeFrames = true;
544 } else if (!newerIsJava && olderIsJava) {
545 // We are transitioning from native to Java
546 mAllowNativeFrames = false;
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800547 }
548 }
549}
550
551template<class FRAME, class BASE>
552void CallStack<FRAME, BASE>::doPop(BBEvent *event, symbol_type *function,
553 Action methodAction)
554{
555 uint64_t time = event->time - mSkippedTime;
556
557 // Search backward on the stack for a matching return address.
558 // The most common case is that we pop one stack frame, but
559 // sometimes we pop more than one.
560 int stackLevel;
561 bool allowMethodPop = (methodAction == POP);
562 for (stackLevel = mTop - 1; stackLevel >= 0; --stackLevel) {
563 if (event->bb_addr == mFrames[stackLevel].addr) {
564 // We found a matching return address on the stack.
565 break;
566 }
567
568 // If this stack frame caused an exception, then do not pop
569 // this stack frame.
570 if (mFrames[stackLevel].flags & FRAME::kPopBarrier) {
571 // If this is a Java method, then allow a pop only if we
572 // have a matching trace record.
573 if (mFrames[stackLevel].flags & FRAME::kInterpreted) {
574 if (allowMethodPop) {
575 // Allow at most one method pop
576 allowMethodPop = false;
577 continue;
578 }
579 }
580 stackLevel += 1;
581 break;
582 }
583 }
584
585 // If we didn't find a matching return address then search the stack
586 // again for a matching function.
587 if (stackLevel < 0 || event->bb_addr != mFrames[stackLevel].addr) {
588 bool allowMethodPop = (methodAction == POP);
589 for (stackLevel = mTop - 1; stackLevel >= 0; --stackLevel) {
590 // Compare the function with the one in the stack frame.
591 if (function == mFrames[stackLevel].function) {
592 // We found a matching function. We want to pop up to but not
Jack Veenstra12985702009-05-09 11:50:34 -0700593 // including this frame. But allow popping this frame if this
594 // method called itself and we have a method pop.
595 if (allowMethodPop && function == mPrevFunction) {
596 // pop this frame
597 break;
598 }
599 // do not pop this frame
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800600 stackLevel += 1;
601 break;
602 }
603
604 // If this stack frame caused an exception, then do not pop
605 // this stack frame.
606 if (mFrames[stackLevel].flags & FRAME::kPopBarrier) {
607 // If this is a Java method, then allow a pop only if we
608 // have a matching trace record.
609 if (mFrames[stackLevel].flags & FRAME::kInterpreted) {
610 if (allowMethodPop) {
611 // Allow at most one method pop
612 allowMethodPop = false;
613 continue;
614 }
615 }
616 stackLevel += 1;
617 break;
618 }
619 }
620 if (stackLevel < 0)
621 stackLevel = 0;
622 }
623
624 // Note that if we didn't find a matching stack frame, we will pop
625 // the whole stack (unless there is a Java method or exception
626 // frame on the stack). This is intentional because we may have
627 // started the trace in the middle of an executing program that is
628 // returning up the stack and we do not know the whole stack. So
629 // the right thing to do is to empty the stack.
630
631 // If we are emptying the stack, then add the current function
632 // on top. If the current function is the same as the top of
633 // stack, then avoid an extraneous pop and push.
634 if (stackLevel == 0 && mFrames[0].function == function)
635 stackLevel = 1;
636
637#if 0
Jack Veenstra12985702009-05-09 11:50:34 -0700638 // If we are popping off a large number of stack frames, then
639 // we might have a bug.
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800640 if (mTop - stackLevel > 7) {
641 printf("popping thru level %d\n", stackLevel);
Jack Veenstra12985702009-05-09 11:50:34 -0700642 showStack(stderr);
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800643 }
644#endif
645
646 // Pop the stack frames
647 for (int ii = mTop - 1; ii >= stackLevel; --ii)
648 doSimplePop(time);
649
650 // Clear the "caused exception" bit on the current stack frame
651 if (mTop > 0) {
652 mFrames[mTop - 1].flags &= ~FRAME::kCausedException;
653 }
654
655 // Also handle the case where F1 calls F2 and F2 returns to
656 // F1, but before we can execute any instructions in F1, we
657 // switch to the kernel. Then when we return from the kernel
658 // we want to pop off F2 from the stack instead of pushing F1
659 // on top of F2. To handle this case, we saved the last
660 // user-mode basic block when we entered the kernel (in
661 // the getAction() function) and now we can check to see if
662 // that was a return to F1 instead of a call. We use the
663 // getAction() function to determine this.
664 const uint32_t kIsKernelRegion = region_type::kIsKernelRegion;
665 if ((mPrevFunction->region->flags & kIsKernelRegion)
666 && ((function->region->flags & kIsKernelRegion) == 0)) {
667 mPrevEvent = mUserEvent;
668 mPrevFunction = mUserFunction;
669 if (getAction(event, function) == POP) {
670 // We may need to pop more than one frame, so just
671 // call doPop() again. This won't be an infinite loop
672 // here because we changed mPrevEvent to the last
673 // user-mode event.
674 doPop(event, function, methodAction);
675 return;
676 }
677 }
678}
679
680template<class FRAME, class BASE>
681void CallStack<FRAME, BASE>::popAll(uint64_t time)
682{
683 time -= mSkippedTime;
684 while (mTop != 0) {
685 doSimplePop(time);
686 }
687}
688
689template<class FRAME, class BASE>
Jack Veenstra2bb9bb42009-05-19 15:07:29 -0700690void CallStack<FRAME, BASE>::doMethodPop(BBEvent *event, uint32_t addr,
691 const uint32_t flags)
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800692{
Jack Veenstra2bb9bb42009-05-19 15:07:29 -0700693 uint64_t time = event->time - mSkippedTime;
694
695 // Search the stack from the top down for a frame that contains a
696 // matching method.
697 int stackLevel;
698 for (stackLevel = mTop - 1; stackLevel >= 0; --stackLevel) {
699 if (mFrames[stackLevel].flags & flags) {
700 // If we are searching for a native method, then don't bother trying
701 // to match the address.
702 if (flags == FRAME::kStartNative)
703 break;
704 symbol_type *func = mFrames[stackLevel].function;
705 uint32_t methodAddr = func->region->base_addr + func->addr;
706 if (methodAddr == addr) {
707 break;
708 }
709 }
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800710 }
711
Jack Veenstra2bb9bb42009-05-19 15:07:29 -0700712 // If we found a matching frame then pop the stack up to and including
713 // that frame.
714 if (stackLevel >= 0) {
715 // Pop the stack frames
716 for (int ii = mTop - 1; ii >= stackLevel; --ii)
717 doSimplePop(time);
718 }
719}
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800720
Jack Veenstra2bb9bb42009-05-19 15:07:29 -0700721template<class FRAME, class BASE>
722void CallStack<FRAME, BASE>::doMethodAction(BBEvent *event, symbol_type *function)
723{
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800724 // If the events get ahead of the method trace, then read ahead until we
725 // sync up again. This can happen if there is a pop of a method in the
Jack Veenstra2bb9bb42009-05-19 15:07:29 -0700726 // method trace for which we don't have a previous push. Such an unmatched
727 // pop can happen because the user can start tracing at any time and so
728 // there might already be a stack when we start tracing.
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800729 while (event->time >= sNextMethod.time) {
730 sCurrentMethod = sNextMethod;
731 if (mTrace->ReadMethod(&sNextMethod)) {
732 sNextMethod.time = ~0ull;
733 }
734 }
735
Jack Veenstra12985702009-05-09 11:50:34 -0700736 if (event->time >= sCurrentMethod.time && event->pid == sCurrentMethod.pid) {
Jack Veenstra2bb9bb42009-05-19 15:07:29 -0700737 uint64_t time = event->time - mSkippedTime;
738 int flags = sCurrentMethod.flags;
739 if (flags == kMethodEnter) {
740 doSimplePush(function, 0, time, FRAME::kInterpreted);
741 mAllowNativeFrames = false;
742 } else if (flags == kNativeEnter) {
743 doSimplePush(function, 0, time, FRAME::kStartNative);
744 mAllowNativeFrames = true;
745 } else if (flags == kMethodExit || flags == kMethodException) {
746 doMethodPop(event, sCurrentMethod.addr, FRAME::kInterpreted);
747 } else if (flags == kNativeExit || flags == kNativeException) {
748 doMethodPop(event, sCurrentMethod.addr, FRAME::kStartNative);
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800749 }
750
Jack Veenstra2bb9bb42009-05-19 15:07:29 -0700751 // We found a match, so read the next record. When we get to the end
752 // of the trace, we set the time to the maximum value (~0).
753 sCurrentMethod = sNextMethod;
754 if (sNextMethod.time != ~0ull && mTrace->ReadMethod(&sNextMethod)) {
755 sNextMethod.time = ~0ull;
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800756 }
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800757 }
758}
759
760template<class FRAME, class BASE>
Jack Veenstra12985702009-05-09 11:50:34 -0700761void CallStack<FRAME, BASE>::showStack(FILE *stream)
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800762{
Jack Veenstra12985702009-05-09 11:50:34 -0700763 fprintf(stream, "mTop: %d skippedTime: %llu\n", mTop, mSkippedTime);
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800764 for (int ii = 0; ii < mTop; ++ii) {
Jack Veenstra12985702009-05-09 11:50:34 -0700765 uint32_t addr = mFrames[ii].function->addr;
766 addr += mFrames[ii].function->region->vstart;
767 fprintf(stream, " %d: t %d gt %d f %x 0x%08x 0x%08x %s\n",
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800768 ii, mFrames[ii].time, mFrames[ii].global_time,
769 mFrames[ii].flags,
Jack Veenstra12985702009-05-09 11:50:34 -0700770 mFrames[ii].addr, addr,
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800771 mFrames[ii].function->name);
772 }
773}
774
The Android Open Source Project52d4c302009-03-03 19:29:09 -0800775#endif /* CALL_STACK_H */