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 */ 776