• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
getId()11      int    getId()          { return mId; }
setId(int id)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  
~StackFrame()27      virtual ~StackFrame() {};
28  
push(int stackLevel,uint64_t time,CallStackBase * base)29      virtual void push(int stackLevel, uint64_t time, CallStackBase *base) {};
pop(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
setNativeOnly(bool nativeOnly)63      void    setNativeOnly(bool nativeOnly) {
64          mNativeOnly = nativeOnly;
65      }
66  
getStackLevel()67      int         getStackLevel() { return mTop; }
68  
getGlobalTime(uint64_t time)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>
CallStack(int id,int numFrames,TraceReaderType * trace)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>
~CallStack()154  CallStack<FRAME, BASE>::~CallStack()
155  {
156      delete mFrames;
157  }
158  
159  template<class FRAME, class BASE>
160  void
updateStack(BBEvent * event,symbol_type * function)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
threadStart(uint64_t time)233  CallStack<FRAME, BASE>::threadStart(uint64_t time)
234  {
235      mSkippedTime += time - mLastRunTime;
236  }
237  
238  template<class FRAME, class BASE>
239  void
threadStop(uint64_t time)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
getAction(BBEvent * event,symbol_type * function)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>
doPush(BBEvent * event,symbol_type * function)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>
doSimplePush(symbol_type * function,uint32_t addr,uint64_t time,int flags)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>
doSimplePop(uint64_t time)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>
doPop(BBEvent * event,symbol_type * function,Action methodAction)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>
popAll(uint64_t time)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>
doMethodPop(BBEvent * event,uint32_t addr,const uint32_t flags)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>
doMethodAction(BBEvent * event,symbol_type * function)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>
showStack(FILE * stream)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 */
776