blob: b869956f85732c7d32640a7345acf9824c3f7a4e [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;
35 static const uint32_t kPopBarrier = (kCausedException | kInterpreted);
36
37 symbol_type *function; // the symbol for the function we entered
38 uint32_t addr; // return address when this function returns
39 uint32_t flags;
40 uint32_t time; // for debugging when a problem occurred
41 uint32_t global_time; // for debugging when a problem occurred
42};
43
44template <class FRAME, class BASE = CallStackBase>
45class CallStack : public BASE {
46 public:
47 typedef typename FRAME::symbol_type symbol_type;
48 typedef typename FRAME::symbol_type::region_type region_type;
49 typedef BASE base_type;
50
51 CallStack(int id, int numFrames, TraceReaderType *trace);
52 ~CallStack();
53
54 void updateStack(BBEvent *event, symbol_type *function);
55 void popAll(uint64_t time);
56 void threadStart(uint64_t time);
57 void threadStop(uint64_t time);
58
59 // Set to true if you don't want to see any Java methods
60 void setNativeOnly(bool nativeOnly) {
61 mNativeOnly = nativeOnly;
62 }
63
64 int getStackLevel() { return mTop; }
65
66 uint64_t getGlobalTime(uint64_t time) { return time + mSkippedTime; }
67 void showStack();
68 void showSnapshotStack();
69
70 private:
71 enum Action { NONE, PUSH, POP };
72
73 Action getAction(BBEvent *event, symbol_type *function);
74 Action getMethodAction(BBEvent *event, symbol_type *function);
75 void doSimplePush(symbol_type *function, uint32_t addr,
76 uint64_t time);
77 void doSimplePop(uint64_t time);
78 void doPush(BBEvent *event, symbol_type *function);
79 void doPop(BBEvent *event, symbol_type *function, Action methodAction);
80
81 void transitionToJava();
82 void transitionFromJava(uint64_t time);
83
84 TraceReaderType *mTrace;
85 bool mNativeOnly;
86
87 symbol_type mDummyFunction;
88 region_type mDummyRegion;
89
90 int mNumFrames;
91 FRAME *mFrames;
92 int mTop; // index of the next stack frame to write
93
94 int mJavaTop;
95
96 int mSnapshotNumFrames;
97 FRAME *mSnapshotFrames;
98 int mSnapshotTop; // index of the next stack frame to write
99
100 symbol_type *mPrevFunction;
101 BBEvent mPrevEvent;
102
103 symbol_type *mUserFunction;
104 BBEvent mUserEvent; // the previous user-mode event
105
106 uint64_t mSkippedTime;
107 uint64_t mLastRunTime;
108
109 static MethodRec sCurrentMethod;
110 static MethodRec sNextMethod;
111};
112
113template<class FRAME, class BASE>
114MethodRec CallStack<FRAME, BASE>::sCurrentMethod;
115template<class FRAME, class BASE>
116MethodRec CallStack<FRAME, BASE>::sNextMethod;
117
118template<class FRAME, class BASE>
119CallStack<FRAME, BASE>::CallStack(int id, int numFrames, TraceReaderType *trace)
120{
121 mNativeOnly = false;
122 mTrace = trace;
123 BASE::setId(id);
124 mNumFrames = numFrames;
125 mFrames = new FRAME[mNumFrames];
126 mTop = 0;
127
128 mSnapshotNumFrames = numFrames;
129 mSnapshotFrames = new FRAME[mSnapshotNumFrames];
130 mSnapshotTop = 0;
131
132 memset(&mDummyFunction, 0, sizeof(symbol_type));
133 memset(&mDummyRegion, 0, sizeof(region_type));
134 mDummyFunction.region = &mDummyRegion;
135 mPrevFunction = &mDummyFunction;
136 memset(&mPrevEvent, 0, sizeof(BBEvent));
137 mUserFunction = &mDummyFunction;
138 memset(&mUserEvent, 0, sizeof(BBEvent));
139 mSkippedTime = 0;
140 mLastRunTime = 0;
141 mJavaTop = 0;
142
143 // Read the first two methods from the trace if we haven't already read
144 // from the method trace yet.
145 if (sCurrentMethod.time == 0) {
146 if (mTrace->ReadMethod(&sCurrentMethod)) {
147 sCurrentMethod.time = ~0ull;
148 sNextMethod.time = ~0ull;
149 }
150 if (sNextMethod.time != ~0ull && mTrace->ReadMethod(&sNextMethod)) {
151 sNextMethod.time = ~0ull;
152 }
153 }
154}
155
156template<class FRAME, class BASE>
157CallStack<FRAME, BASE>::~CallStack()
158{
159 delete mFrames;
160}
161
162template<class FRAME, class BASE>
163void
164CallStack<FRAME, BASE>::updateStack(BBEvent *event, symbol_type *function)
165{
166 if (mNativeOnly) {
167 // If this is an interpreted function, then use the native VM function
168 // instead.
169 if (function->vm_sym != NULL)
170 function = function->vm_sym;
171 }
172
173 Action action = getAction(event, function);
174 Action methodAction = getMethodAction(event, function);
175
176 // Pop off native functions before pushing or popping Java methods.
177 if (action == POP && mPrevFunction->vm_sym == NULL) {
178 // Pop off the previous function first.
179 doPop(event, function, NONE);
180 if (methodAction == POP) {
181 doPop(event, function, POP);
182 } else if (methodAction == PUSH) {
183 doPush(event, function);
184 }
185 } else {
186 if (methodAction != NONE) {
187 // If the method trace has a push or pop, then do it.
188 action = methodAction;
189 } else if (function->vm_sym != NULL) {
190 // This function is a Java method. Don't push or pop the
191 // Java method without a corresponding method trace record.
192 action = NONE;
193 }
194 if (action == POP) {
195 doPop(event, function, methodAction);
196 } else if (action == PUSH) {
197 doPush(event, function);
198 }
199 }
200
201 // If the stack is now empty, then push the current function.
202 if (mTop == 0) {
203 uint64_t time = event->time - mSkippedTime;
204 doSimplePush(function, 0, time);
205 }
206
207 mPrevFunction = function;
208 mPrevEvent = *event;
209}
210
211template<class FRAME, class BASE>
212void
213CallStack<FRAME, BASE>::threadStart(uint64_t time)
214{
215 mSkippedTime += time - mLastRunTime;
216}
217
218template<class FRAME, class BASE>
219void
220CallStack<FRAME, BASE>::threadStop(uint64_t time)
221{
222 mLastRunTime = time;
223}
224
225template<class FRAME, class BASE>
226typename CallStack<FRAME, BASE>::Action
227CallStack<FRAME, BASE>::getAction(BBEvent *event, symbol_type *function)
228{
229 Action action;
230 uint32_t offset;
231
232 // Compute the offset from the start of the function to this basic
233 // block address.
234 offset = event->bb_addr - function->addr - function->region->base_addr;
235
236 // Get the previously executed instruction
237 Opcode op = OP_INVALID;
238 int numInsns = mPrevEvent.num_insns;
239 uint32_t insn = 0;
240 if (numInsns > 0) {
241 insn = mPrevEvent.insns[numInsns - 1];
242 if (mPrevEvent.is_thumb) {
243 insn = insn_unwrap_thumb(insn);
244 op = decode_insn_thumb(insn);
245 } else {
246 op = Arm::decode(insn);
247 }
248 }
249
250 // The number of bytes in the previous basic block depends on
251 // whether the basic block was ARM or THUMB instructions.
252 int numBytes;
253 if (mPrevEvent.is_thumb) {
254 numBytes = numInsns << 1;
255 } else {
256 numBytes = numInsns << 2;
257 }
258
259 // If this basic block follows the previous one, then return NONE.
260 // If we don't do this, then we may be fooled into thinking this
261 // is a POP if the previous block ended with a conditional
262 // (non-executed) ldmia instruction. We do this check before
263 // checking if we are in a different function because we otherwise
264 // we might be fooled into thinking this is a PUSH to a new function
265 // when it is really just a fall-thru into a local kernel symbol
266 // that just looks like a new function.
267 uint32_t prev_end_addr = mPrevEvent.bb_addr + numBytes;
268 if (prev_end_addr == event->bb_addr) {
269 return NONE;
270 }
271
272 // If this basic block is in the same function as the last basic block,
273 // then just return NONE (but see the exceptions below).
274 // Exception 1: if the function calls itself (offset == 0) then we
275 // want to push this function.
276 // Exception 2: if the function returns to itself, then we want
277 // to pop this function. We detect this case by checking if the last
278 // instruction in the previous basic block was a load-multiple (ldm)
279 // and included r15 as one of the loaded registers.
280 if (function == mPrevFunction) {
281 if (numInsns > 0) {
282 // If this is the beginning of the function and the previous
283 // instruction was not a branch, then it's a PUSH.
284 if (offset == 0 && op != OP_B && op != OP_THUMB_B)
285 return PUSH;
286
287 // If the previous instruction was an ldm that loaded r15,
288 // then it's a POP.
289 if (offset != 0 && ((op == OP_LDM && (insn & 0x8000))
290 || (op == OP_THUMB_POP && (insn & 0x100)))) {
291 return POP;
292 }
293 }
294
295 return NONE;
296 }
297
298 // We have to figure out if this new function is a call or a
299 // return. We don't necessarily have a complete call stack (since
300 // we could have started tracing at any point), so we have to use
301 // heuristics. If the address we are jumping to is the beginning
302 // of a function, or if the instruction that took us there was
303 // either "bl" or "blx" then this is a PUSH. Also, if the
304 // function offset is non-zero and the previous instruction is a
305 // branch instruction, we will call it a PUSH. This happens in
306 // the kernel a lot when there is a branch to an offset from a
307 // label. A couple more special cases:
308 //
309 // - entering a .plt section ("procedure linkage table") is a PUSH,
310 // - an exception that jumps into the kernel vector entry point
311 // is also a push.
312 //
313 // If the function offset is non-zero and the previous instruction
314 // is a bx or some non-branch instruction, then it's a POP.
315 //
316 // There's another special case that comes up. The user code
317 // might execute an instruction that returns but before the pc
318 // starts executing in the caller, a kernel interrupt occurs.
319 // But it may be hard to tell if this is a return until after
320 // the kernel interrupt code is done and returns to user space.
321 // So we save the last user basic block and look at it when
322 // we come back into user space.
323
324 const uint32_t kIsKernelRegion = region_type::kIsKernelRegion;
325
326 if (((mPrevFunction->region->flags & kIsKernelRegion) == 0)
327 && (function->region->flags & kIsKernelRegion)) {
328 // We just switched into the kernel. Save the previous
329 // user-mode basic block and function.
330 mUserEvent = mPrevEvent;
331 mUserFunction = mPrevFunction;
332 } else if ((mPrevFunction->region->flags & kIsKernelRegion)
333 && ((function->region->flags & kIsKernelRegion) == 0)) {
334 // We just switched from kernel to user mode.
335 return POP;
336 }
337
338 action = PUSH;
339 if (offset != 0 && mPrevFunction != &mDummyFunction) {
340 // We are jumping into the middle of a function, so this is
341 // probably a return, not a function call. But look at the
342 // previous instruction first to see if it was a branch-and-link.
343
344 // If the previous instruction was not a branch (and not a
345 // branch-and-link) then POP; or if it is a "bx" instruction
346 // then POP because that is used to return from functions.
347 if (!isBranch(op) || op == OP_BX || op == OP_THUMB_BX) {
348 action = POP;
349 } else if (isBranch(op) && !isBranchLink(op)) {
350 // If the previous instruction was a normal branch to a
351 // local symbol then don't count it as a push or a pop.
352 action = NONE;
353 }
354
355 if (function->flags & symbol_type::kIsVectorTable)
356 action = PUSH;
357 }
358 return action;
359}
360
361
362template<class FRAME, class BASE>
363void CallStack<FRAME, BASE>::doPush(BBEvent *event, symbol_type *function)
364{
365 uint64_t time = event->time - mSkippedTime;
366
367 // Check for stack overflow
368 if (mTop >= mNumFrames) {
369#if 0
370 showStack();
371#endif
372 fprintf(stderr, "Error: stack overflow (%d frames)\n", mTop);
373 exit(1);
374 }
375
376 // Compute the return address here because we may need to change
377 // it if we are popping off a frame for a vector table.
378 int numBytes;
379 if (mPrevEvent.is_thumb) {
380 numBytes = mPrevEvent.num_insns << 1;
381 } else {
382 numBytes = mPrevEvent.num_insns << 2;
383 }
384 uint32_t retAddr = mPrevEvent.bb_addr + numBytes;
385
386 // If this is a Java method then set the return address to zero.
387 // We won't be using it for popping the method and it may lead
388 // to false matches when searching the stack.
389 if (function->vm_sym != NULL) {
390 retAddr = 0;
391 }
392
393#if 0
394 if (function->flags & symbol_type::kIsVectorStart) {
395 printf("stack before entering exception\n");
396 showStack();
397 }
398#endif
399
400 // If the previous function was a vector table, then pop it
401 // off before pushing on the new function. Also, change the
402 // return address for the new function to the return address
403 // from the vector table.
404 if ((mPrevFunction->flags & symbol_type::kIsVectorTable) && mTop > 0) {
405 retAddr = mFrames[mTop - 1].addr;
406 doSimplePop(time);
407 }
408
409 const uint32_t kIsKernelRegion = region_type::kIsKernelRegion;
410
411 // The following code handles the case where one function, F1,
412 // calls another function, F2, but the before F2 can start
413 // executing, it takes a page fault (on the first instruction
414 // in F2). The kernel is entered, handles the page fault, and
415 // then returns to the called function. The problem is that
416 // this looks like a new function call to F2 from the kernel.
417 // The following code cleans up the stack by popping the
418 // kernel frames back to F1 (but not including F1). The
419 // return address for F2 also has to be fixed up to point to
420 // F1 instead of the kernel.
421 //
422 // We detect this case by checking if the previous basic block
423 // was in the kernel and the current basic block is not.
424 if ((mPrevFunction->region->flags & kIsKernelRegion)
425 && ((function->region->flags & kIsKernelRegion) == 0)
426 && mTop > 0) {
427 // We are switching from kernel mode to user mode.
428#if 0
429 printf(" doPush(): popping to user mode, bb_addr: 0x%08x\n",
430 event->bb_addr);
431 showStack();
432#endif
433 do {
434 // Pop off the kernel frames until we reach the one that
435 // caused the exception.
436 doSimplePop(time);
437
438 // If the next stack frame is the one that caused an
439 // exception then stop popping frames.
440 if (mTop > 0
441 && (mFrames[mTop - 1].flags & FRAME::kCausedException)) {
442 mFrames[mTop - 1].flags &= ~FRAME::kCausedException;
443 retAddr = mFrames[mTop].addr;
444 break;
445 }
446 } while (mTop > 0);
447#if 0
448 printf(" doPush() popping to level %d, using retAddr 0x%08x\n",
449 mTop, retAddr);
450#endif
451 }
452
453 // If we are starting an exception handler, then mark the previous
454 // stack frame so that we know where to return when the exception
455 // handler finishes.
456 if ((function->flags & symbol_type::kIsVectorStart) && mTop > 0)
457 mFrames[mTop - 1].flags |= FRAME::kCausedException;
458
459 doSimplePush(function, retAddr, time);
460}
461
462template<class FRAME, class BASE>
463void CallStack<FRAME, BASE>::doSimplePush(symbol_type *function,
464 uint32_t addr, uint64_t time)
465{
466 // Check for stack overflow
467 if (mTop >= mNumFrames) {
468 showStack();
469 fprintf(stderr, "too many stack frames (%d)\n", mTop);
470 exit(1);
471 }
472
473 // Keep track of the number of Java methods we push on the stack.
474 if (!mNativeOnly && function->vm_sym != NULL) {
475 // If we are pushing the first Java method on the stack, then
476 // save a snapshot of the stack so that we can clean things up
477 // later when we pop off the last Java stack frame.
478 if (mJavaTop == 0) {
479 transitionToJava();
480 }
481 mJavaTop += 1;
482 }
483
484 mFrames[mTop].addr = addr;
485 mFrames[mTop].function = function;
486 mFrames[mTop].flags = 0;
487 mFrames[mTop].time = time;
488 mFrames[mTop].global_time = time + mSkippedTime;
489
490 // If the function being pushed is a Java method, then mark it on
491 // the stack so that we don't pop it off until we get a matching
492 // trace record from the method trace file.
493 if (function->vm_sym != NULL) {
494 mFrames[mTop].flags = FRAME::kInterpreted;
495 }
496
497 mFrames[mTop].push(mTop, time, this);
498 mTop += 1;
499}
500
501template<class FRAME, class BASE>
502void CallStack<FRAME, BASE>::doSimplePop(uint64_t time)
503{
504 if (mTop <= 0) {
505 return;
506 }
507
508 mTop -= 1;
509 mFrames[mTop].pop(mTop, time, this);
510
511 // Keep track of the number of Java methods we have on the stack.
512 symbol_type *function = mFrames[mTop].function;
513 if (!mNativeOnly && function->vm_sym != NULL) {
514 mJavaTop -= 1;
515
516 // When there are no more Java stack frames, then clean up
517 // the client's stack. We need to do this because the client
518 // doesn't see the changes to the native stack underlying the
519 // fake Java stack until the last Java method is popped off.
520 if (mJavaTop == 0) {
521 transitionFromJava(time);
522 }
523 }
524}
525
526template<class FRAME, class BASE>
527void CallStack<FRAME, BASE>::doPop(BBEvent *event, symbol_type *function,
528 Action methodAction)
529{
530 uint64_t time = event->time - mSkippedTime;
531
532 // Search backward on the stack for a matching return address.
533 // The most common case is that we pop one stack frame, but
534 // sometimes we pop more than one.
535 int stackLevel;
536 bool allowMethodPop = (methodAction == POP);
537 for (stackLevel = mTop - 1; stackLevel >= 0; --stackLevel) {
538 if (event->bb_addr == mFrames[stackLevel].addr) {
539 // We found a matching return address on the stack.
540 break;
541 }
542
543 // If this stack frame caused an exception, then do not pop
544 // this stack frame.
545 if (mFrames[stackLevel].flags & FRAME::kPopBarrier) {
546 // If this is a Java method, then allow a pop only if we
547 // have a matching trace record.
548 if (mFrames[stackLevel].flags & FRAME::kInterpreted) {
549 if (allowMethodPop) {
550 // Allow at most one method pop
551 allowMethodPop = false;
552 continue;
553 }
554 }
555 stackLevel += 1;
556 break;
557 }
558 }
559
560 // If we didn't find a matching return address then search the stack
561 // again for a matching function.
562 if (stackLevel < 0 || event->bb_addr != mFrames[stackLevel].addr) {
563 bool allowMethodPop = (methodAction == POP);
564 for (stackLevel = mTop - 1; stackLevel >= 0; --stackLevel) {
565 // Compare the function with the one in the stack frame.
566 if (function == mFrames[stackLevel].function) {
567 // We found a matching function. We want to pop up to but not
568 // including this frame.
569 stackLevel += 1;
570 break;
571 }
572
573 // If this stack frame caused an exception, then do not pop
574 // this stack frame.
575 if (mFrames[stackLevel].flags & FRAME::kPopBarrier) {
576 // If this is a Java method, then allow a pop only if we
577 // have a matching trace record.
578 if (mFrames[stackLevel].flags & FRAME::kInterpreted) {
579 if (allowMethodPop) {
580 // Allow at most one method pop
581 allowMethodPop = false;
582 continue;
583 }
584 }
585 stackLevel += 1;
586 break;
587 }
588 }
589 if (stackLevel < 0)
590 stackLevel = 0;
591 }
592
593 // Note that if we didn't find a matching stack frame, we will pop
594 // the whole stack (unless there is a Java method or exception
595 // frame on the stack). This is intentional because we may have
596 // started the trace in the middle of an executing program that is
597 // returning up the stack and we do not know the whole stack. So
598 // the right thing to do is to empty the stack.
599
600 // If we are emptying the stack, then add the current function
601 // on top. If the current function is the same as the top of
602 // stack, then avoid an extraneous pop and push.
603 if (stackLevel == 0 && mFrames[0].function == function)
604 stackLevel = 1;
605
606#if 0
607 if (mTop - stackLevel > 7) {
608 printf("popping thru level %d\n", stackLevel);
609 showStack();
610 }
611#endif
612
613 // Pop the stack frames
614 for (int ii = mTop - 1; ii >= stackLevel; --ii)
615 doSimplePop(time);
616
617 // Clear the "caused exception" bit on the current stack frame
618 if (mTop > 0) {
619 mFrames[mTop - 1].flags &= ~FRAME::kCausedException;
620 }
621
622 // Also handle the case where F1 calls F2 and F2 returns to
623 // F1, but before we can execute any instructions in F1, we
624 // switch to the kernel. Then when we return from the kernel
625 // we want to pop off F2 from the stack instead of pushing F1
626 // on top of F2. To handle this case, we saved the last
627 // user-mode basic block when we entered the kernel (in
628 // the getAction() function) and now we can check to see if
629 // that was a return to F1 instead of a call. We use the
630 // getAction() function to determine this.
631 const uint32_t kIsKernelRegion = region_type::kIsKernelRegion;
632 if ((mPrevFunction->region->flags & kIsKernelRegion)
633 && ((function->region->flags & kIsKernelRegion) == 0)) {
634 mPrevEvent = mUserEvent;
635 mPrevFunction = mUserFunction;
636 if (getAction(event, function) == POP) {
637 // We may need to pop more than one frame, so just
638 // call doPop() again. This won't be an infinite loop
639 // here because we changed mPrevEvent to the last
640 // user-mode event.
641 doPop(event, function, methodAction);
642 return;
643 }
644 }
645}
646
647template<class FRAME, class BASE>
648void CallStack<FRAME, BASE>::popAll(uint64_t time)
649{
650 time -= mSkippedTime;
651 while (mTop != 0) {
652 doSimplePop(time);
653 }
654}
655
656template<class FRAME, class BASE>
657typename CallStack<FRAME, BASE>::Action
658CallStack<FRAME, BASE>::getMethodAction(BBEvent *event, symbol_type *function)
659{
660 if (function->vm_sym == NULL && mPrevFunction->vm_sym == NULL) {
661 return NONE;
662 }
663
664 Action action = NONE;
665 uint32_t prevAddr = mPrevFunction->addr + mPrevFunction->region->base_addr;
666 uint32_t addr = function->addr + function->region->base_addr;
667
668 // If the events get ahead of the method trace, then read ahead until we
669 // sync up again. This can happen if there is a pop of a method in the
670 // method trace for which we don't have a previous push.
671 while (event->time >= sNextMethod.time) {
672 sCurrentMethod = sNextMethod;
673 if (mTrace->ReadMethod(&sNextMethod)) {
674 sNextMethod.time = ~0ull;
675 }
676 }
677
678 if (event->time >= sCurrentMethod.time) {
679 if (addr == sCurrentMethod.addr || prevAddr == sCurrentMethod.addr) {
680 action = (sCurrentMethod.flags == 0) ? PUSH : POP;
681 // We found a match, so read the next record.
682 sCurrentMethod = sNextMethod;
683 if (sNextMethod.time != ~0ull && mTrace->ReadMethod(&sNextMethod)) {
684 sNextMethod.time = ~0ull;
685 }
686 }
687 }
688 return action;
689}
690
691// When the first Java method is pushed on the stack, this method is
692// called to save a snapshot of the current native stack so that the
693// client's view of the native stack can be patched up later when the
694// Java stack is empty.
695template<class FRAME, class BASE>
696void CallStack<FRAME, BASE>::transitionToJava()
697{
698 mSnapshotTop = mTop;
699 for (int ii = 0; ii < mTop; ++ii) {
700 mSnapshotFrames[ii] = mFrames[ii];
701 }
702}
703
704// When the Java stack becomes empty, the native stack becomes
705// visible. This method is called when the Java stack becomes empty
706// to patch up the client's view of the native stack, which may have
707// changed underneath the Java stack. The stack snapshot is used to
708// create a sequence of pops and pushes to make the client's view of
709// the native stack match the current native stack.
710template<class FRAME, class BASE>
711void CallStack<FRAME, BASE>::transitionFromJava(uint64_t time)
712{
713 int top = mTop;
714 if (top > mSnapshotTop) {
715 top = mSnapshotTop;
716 }
717 for (int ii = 0; ii < top; ++ii) {
718 if (mSnapshotFrames[ii].function->addr == mFrames[ii].function->addr) {
719 continue;
720 }
721
722 // Pop off all the rest of the frames from the snapshot
723 for (int jj = top - 1; jj >= ii; --jj) {
724 mSnapshotFrames[jj].pop(jj, time, this);
725 }
726
727 // Push the new frames from the native stack
728 for (int jj = ii; jj < mTop; ++jj) {
729 mFrames[jj].push(jj, time, this);
730 }
731 break;
732 }
733}
734
735template<class FRAME, class BASE>
736void CallStack<FRAME, BASE>::showStack()
737{
738 fprintf(stderr, "mTop: %d skippedTime: %llu\n", mTop, mSkippedTime);
739 for (int ii = 0; ii < mTop; ++ii) {
740 fprintf(stderr, " %d: t %d gt %d f %x 0x%08x 0x%08x %s\n",
741 ii, mFrames[ii].time, mFrames[ii].global_time,
742 mFrames[ii].flags,
743 mFrames[ii].addr, mFrames[ii].function->addr,
744 mFrames[ii].function->name);
745 }
746}
747
748template<class FRAME, class BASE>
749void CallStack<FRAME, BASE>::showSnapshotStack()
750{
751 fprintf(stderr, "mSnapshotTop: %d\n", mSnapshotTop);
752 for (int ii = 0; ii < mSnapshotTop; ++ii) {
753 fprintf(stderr, " %d: t %d f %x 0x%08x 0x%08x %s\n",
754 ii, mSnapshotFrames[ii].time, mSnapshotFrames[ii].flags,
755 mSnapshotFrames[ii].addr, mSnapshotFrames[ii].function->addr,
756 mSnapshotFrames[ii].function->name);
757 }
758}
759
760#endif /* CALL_STACK_H */