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