OSDN Git Service

android-2.1_r1 snapshot
[android-x86/sdk.git] / emulator / qtools / callstack.h
1 // 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
9 class 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.
23 template <class SYM>
24 class 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;
35     static const uint32_t kStartNative     = 0x04;
36     static const uint32_t kPopBarrier      = (kCausedException | kInterpreted
37         | kStartNative);
38
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
46 template <class FRAME, class BASE = CallStackBase>
47 class CallStack : public BASE {
48 public:
49     typedef FRAME frame_type;
50     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
62     // Set to true if you don't want to see any Java methods ever
63     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; }
70     void        showStack(FILE *stream);
71
72     int         mNumFrames;
73     FRAME       *mFrames;
74     int         mTop;           // index of the next stack frame to write
75
76 private:
77     enum Action { NONE, PUSH, POP, NATIVE_PUSH };
78
79     Action      getAction(BBEvent *event, symbol_type *function);
80     void        doMethodAction(BBEvent *event, symbol_type *function);
81     void        doMethodPop(BBEvent *event, uint32_t addr, const uint32_t flags);
82     void        doSimplePush(symbol_type *function, uint32_t addr,
83                              uint64_t time, int flags);
84     void        doSimplePop(uint64_t time);
85     void        doPush(BBEvent *event, symbol_type *function);
86     void        doPop(BBEvent *event, symbol_type *function, Action methodAction);
87
88     TraceReaderType *mTrace;
89
90     // This is a global switch that disables Java methods from appearing
91     // on the stack.
92     bool        mNativeOnly;
93   
94     // This keeps track of whether native frames are currently allowed on the
95     // stack.
96     bool        mAllowNativeFrames;
97
98     symbol_type mDummyFunction;
99     region_type mDummyRegion;
100
101     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
114 template<class FRAME, class BASE>
115 MethodRec CallStack<FRAME, BASE>::sCurrentMethod;
116 template<class FRAME, class BASE>
117 MethodRec CallStack<FRAME, BASE>::sNextMethod;
118
119 template<class FRAME, class BASE>
120 CallStack<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;
128     mAllowNativeFrames = true;
129
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;
139
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
153 template<class FRAME, class BASE>
154 CallStack<FRAME, BASE>::~CallStack()
155 {
156     delete mFrames;
157 }
158
159 template<class FRAME, class BASE>
160 void
161 CallStack<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;
168     } else {
169         doMethodAction(event, function);
170     }
171
172     Action action = getAction(event, function);
173
174     // 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
191     // 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     }
215 #endif
216
217     // If the stack is now empty, then push the current function.
218     if (mTop == 0) {
219         uint64_t time = event->time - mSkippedTime;
220         int flags = 0;
221         if (function->vm_sym != NULL) {
222             flags = FRAME::kInterpreted;
223         }
224         doSimplePush(function, 0, time, 0);
225     }
226
227     mPrevFunction = function;
228     mPrevEvent = *event;
229 }
230
231 template<class FRAME, class BASE>
232 void
233 CallStack<FRAME, BASE>::threadStart(uint64_t time)
234 {
235     mSkippedTime += time - mLastRunTime;
236 }
237
238 template<class FRAME, class BASE>
239 void
240 CallStack<FRAME, BASE>::threadStop(uint64_t time)
241 {
242     mLastRunTime = time;
243 }
244
245 template<class FRAME, class BASE>
246 typename CallStack<FRAME, BASE>::Action
247 CallStack<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
382 template<class FRAME, class BASE>
383 void 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) {
389         // 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.
392 #if 0
393         showStack(stderr);
394 #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
417     // For debugging only.  Show the stack before entering the kernel
418     // exception-handling code.
419     if (function->flags & symbol_type::kIsVectorStart) {
420         printf("stack before entering exception\n");
421         showStack(stderr);
422     }
423 #endif
424
425     // If the top of stack is a vector table, then pop it
426     // 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.
429     if (mTop > 0
430         && (mFrames[mTop - 1].function->flags & symbol_type::kIsVectorTable)) {
431         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
455         // For debugging.
456         printf("  doPush(): popping to user mode, bb_addr: 0x%08x\n",
457                event->bb_addr);
458         showStack(stderr);
459 #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
475         // For debugging
476         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
487     // 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);
495 }
496
497 template<class FRAME, class BASE>
498 void CallStack<FRAME, BASE>::doSimplePush(symbol_type *function, uint32_t addr,
499                                           uint64_t time, int flags)
500 {
501     // Check for stack overflow
502     if (mTop >= mNumFrames) {
503         showStack(stderr);
504         fprintf(stderr, "too many stack frames (%d)\n", mTop);
505         exit(1);
506     }
507
508     mFrames[mTop].addr = addr;
509     mFrames[mTop].function = function;
510     mFrames[mTop].flags = flags;
511     mFrames[mTop].time = time;
512     mFrames[mTop].global_time = time + mSkippedTime;
513
514     mFrames[mTop].push(mTop, time, this);
515     mTop += 1;
516 }
517
518 template<class FRAME, class BASE>
519 void 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
528     if (mNativeOnly)
529         return;
530
531     // 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;
547         }
548     }
549 }
550
551 template<class FRAME, class BASE>
552 void 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
593                 // 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
600                 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
638     // If we are popping off a large number of stack frames, then
639     // we might have a bug.
640     if (mTop - stackLevel > 7) {
641         printf("popping thru level %d\n", stackLevel);
642         showStack(stderr);
643     }
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
680 template<class FRAME, class BASE>
681 void CallStack<FRAME, BASE>::popAll(uint64_t time)
682 {
683     time -= mSkippedTime;
684     while (mTop != 0) {
685         doSimplePop(time);
686     }
687 }
688
689 template<class FRAME, class BASE>
690 void CallStack<FRAME, BASE>::doMethodPop(BBEvent *event, uint32_t addr,
691                                          const uint32_t flags)
692 {
693     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         }
710     }
711
712     // 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 }
720
721 template<class FRAME, class BASE>
722 void CallStack<FRAME, BASE>::doMethodAction(BBEvent *event, symbol_type *function)
723 {
724     // 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
726     // 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.
729     while (event->time >= sNextMethod.time) {
730         sCurrentMethod = sNextMethod;
731         if (mTrace->ReadMethod(&sNextMethod)) {
732             sNextMethod.time = ~0ull;
733         }
734     }
735
736     if (event->time >= sCurrentMethod.time && event->pid == sCurrentMethod.pid) {
737         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);
749         }
750
751         // 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;
756         }
757     }
758 }
759
760 template<class FRAME, class BASE>
761 void CallStack<FRAME, BASE>::showStack(FILE *stream)
762 {
763     fprintf(stream, "mTop: %d skippedTime: %llu\n", mTop, mSkippedTime);
764     for (int ii = 0; ii < mTop; ++ii) {
765         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",
768                 ii, mFrames[ii].time, mFrames[ii].global_time,
769                 mFrames[ii].flags,
770                 mFrames[ii].addr, addr,
771                 mFrames[ii].function->name);
772     }
773 }
774
775 #endif /* CALL_STACK_H */