1 //===-- StackFrameList.cpp --------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "lldb/Target/StackFrameList.h" 11 12 // C Includes 13 // C++ Includes 14 // Other libraries and framework includes 15 // Project includes 16 #include "lldb/Core/StreamFile.h" 17 #include "lldb/Core/SourceManager.h" 18 #include "lldb/Symbol/Block.h" 19 #include "lldb/Symbol/Function.h" 20 #include "lldb/Symbol/Symbol.h" 21 #include "lldb/Target/Process.h" 22 #include "lldb/Target/RegisterContext.h" 23 #include "lldb/Target/StackFrame.h" 24 #include "lldb/Target/StopInfo.h" 25 #include "lldb/Target/Target.h" 26 #include "lldb/Target/Thread.h" 27 #include "lldb/Target/Unwind.h" 28 29 //#define DEBUG_STACK_FRAMES 1 30 31 using namespace lldb; 32 using namespace lldb_private; 33 34 //---------------------------------------------------------------------- 35 // StackFrameList constructor 36 //---------------------------------------------------------------------- 37 StackFrameList::StackFrameList 38 ( 39 Thread &thread, 40 const lldb::StackFrameListSP &prev_frames_sp, 41 bool show_inline_frames 42 ) : 43 m_thread (thread), 44 m_prev_frames_sp (prev_frames_sp), 45 m_mutex (Mutex::eMutexTypeRecursive), 46 m_frames (), 47 m_selected_frame_idx (0), 48 m_concrete_frames_fetched (0), 49 m_current_inlined_depth (UINT32_MAX), 50 m_current_inlined_pc (LLDB_INVALID_ADDRESS), 51 m_show_inlined_frames (show_inline_frames) 52 { 53 if (prev_frames_sp) 54 { 55 m_current_inlined_depth = prev_frames_sp->m_current_inlined_depth; 56 m_current_inlined_pc = prev_frames_sp->m_current_inlined_pc; 57 } 58 } 59 60 //---------------------------------------------------------------------- 61 // Destructor 62 //---------------------------------------------------------------------- 63 StackFrameList::~StackFrameList() 64 { 65 } 66 67 void 68 StackFrameList::CalculateCurrentInlinedDepth() 69 { 70 uint32_t cur_inlined_depth = GetCurrentInlinedDepth(); 71 if (cur_inlined_depth == UINT32_MAX) 72 { 73 ResetCurrentInlinedDepth(); 74 } 75 } 76 77 uint32_t 78 StackFrameList::GetCurrentInlinedDepth () 79 { 80 if (m_show_inlined_frames) 81 { 82 lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC(); 83 if (cur_pc != m_current_inlined_pc) 84 { 85 m_current_inlined_pc = LLDB_INVALID_ADDRESS; 86 m_current_inlined_depth = UINT32_MAX; 87 } 88 return m_current_inlined_depth; 89 } 90 else 91 { 92 return UINT32_MAX; 93 } 94 } 95 96 void 97 StackFrameList::ResetCurrentInlinedDepth () 98 { 99 if (m_show_inlined_frames) 100 { 101 GetFramesUpTo(0); 102 if (!m_frames[0]->IsInlined()) 103 { 104 m_current_inlined_depth = UINT32_MAX; 105 m_current_inlined_pc = LLDB_INVALID_ADDRESS; 106 } 107 else 108 { 109 // We only need to do something special about inlined blocks when we 110 // are at the beginning of an inlined function: 111 // FIXME: We probably also have to do something special if the PC is at the END 112 // of an inlined function, which coincides with the end of either its containing 113 // function or another inlined function. 114 115 lldb::addr_t curr_pc = m_thread.GetRegisterContext()->GetPC(); 116 Block *block_ptr = m_frames[0]->GetFrameBlock(); 117 if (block_ptr) 118 { 119 Address pc_as_address; 120 pc_as_address.SetLoadAddress(curr_pc, &(m_thread.GetProcess()->GetTarget())); 121 AddressRange containing_range; 122 if (block_ptr->GetRangeContainingAddress(pc_as_address, containing_range)) 123 { 124 if (pc_as_address == containing_range.GetBaseAddress()) 125 { 126 // If we got here because of a breakpoint hit, then set the inlined depth depending on where 127 // the breakpoint was set. 128 // If we got here because of a crash, then set the inlined depth to the deepest most block. 129 // Otherwise, we stopped here naturally as the result of a step, so set ourselves in the 130 // containing frame of the whole set of nested inlines, so the user can then "virtually" 131 // step into the frames one by one, or next over the whole mess. 132 // Note: We don't have to handle being somewhere in the middle of the stack here, since 133 // ResetCurrentInlinedDepth doesn't get called if there is a valid inlined depth set. 134 StopInfoSP stop_info_sp = m_thread.GetStopInfo(); 135 if (stop_info_sp) 136 { 137 switch (stop_info_sp->GetStopReason()) 138 { 139 case eStopReasonWatchpoint: 140 case eStopReasonException: 141 case eStopReasonSignal: 142 // In all these cases we want to stop in the deepest most frame. 143 m_current_inlined_pc = curr_pc; 144 m_current_inlined_depth = 0; 145 break; 146 case eStopReasonBreakpoint: 147 { 148 // FIXME: Figure out what this break point is doing, and set the inline depth 149 // appropriately. Be careful to take into account breakpoints that implement 150 // step over prologue, since that should do the default calculation. 151 } 152 default: 153 { 154 // Otherwise, we should set ourselves at the container of the inlining, so that the 155 // user can descend into them. 156 // So first we check whether we have more than one inlined block sharing this PC: 157 int num_inlined_functions = 0; 158 159 for (Block *container_ptr = block_ptr->GetInlinedParent(); 160 container_ptr != NULL; 161 container_ptr = container_ptr->GetInlinedParent()) 162 { 163 if (!container_ptr->GetRangeContainingAddress(pc_as_address, containing_range)) 164 break; 165 if (pc_as_address != containing_range.GetBaseAddress()) 166 break; 167 168 num_inlined_functions++; 169 } 170 m_current_inlined_pc = curr_pc; 171 m_current_inlined_depth = num_inlined_functions + 1; 172 173 } 174 break; 175 } 176 } 177 } 178 } 179 } 180 } 181 } 182 } 183 184 bool 185 StackFrameList::DecrementCurrentInlinedDepth () 186 { 187 if (m_show_inlined_frames) 188 { 189 uint32_t current_inlined_depth = GetCurrentInlinedDepth(); 190 if (current_inlined_depth != UINT32_MAX) 191 { 192 if (current_inlined_depth > 0) 193 { 194 m_current_inlined_depth--; 195 return true; 196 } 197 } 198 } 199 return false; 200 } 201 202 void 203 StackFrameList::GetFramesUpTo(uint32_t end_idx) 204 { 205 // We've already gotten more frames than asked for, or we've already finished unwinding, return. 206 if (m_frames.size() > end_idx || GetAllFramesFetched()) 207 return; 208 209 Unwind *unwinder = m_thread.GetUnwinder (); 210 211 if (m_show_inlined_frames) 212 { 213 #if defined (DEBUG_STACK_FRAMES) 214 StreamFile s(stdout, false); 215 #endif 216 // If we are hiding some frames from the outside world, we need to add those onto the total count of 217 // frames to fetch. However, we don't need ot do that if end_idx is 0 since in that case we always 218 // get the first concrete frame and all the inlined frames below it... 219 220 uint32_t inlined_depth = 0; 221 if (end_idx > 0) 222 { 223 inlined_depth = GetCurrentInlinedDepth(); 224 if (inlined_depth != UINT32_MAX) 225 { 226 if (end_idx > 0) 227 end_idx += inlined_depth; 228 } 229 else 230 inlined_depth = 0; 231 } 232 233 StackFrameSP unwind_frame_sp; 234 do 235 { 236 uint32_t idx = m_concrete_frames_fetched++; 237 lldb::addr_t pc; 238 lldb::addr_t cfa; 239 if (idx == 0) 240 { 241 // We might have already created frame zero, only create it 242 // if we need to 243 if (m_frames.empty()) 244 { 245 m_thread.GetRegisterContext(); 246 assert (m_thread.m_reg_context_sp.get()); 247 248 const bool success = unwinder->GetFrameInfoAtIndex(idx, cfa, pc); 249 // There shouldn't be any way not to get the frame info for frame 0. 250 // But if the unwinder can't make one, lets make one by hand with the 251 // SP as the CFA and see if that gets any further. 252 if (!success) 253 { 254 cfa = m_thread.GetRegisterContext()->GetSP(); 255 pc = m_thread.GetRegisterContext()->GetPC(); 256 } 257 258 unwind_frame_sp.reset (new StackFrame (m_thread.shared_from_this(), 259 m_frames.size(), 260 idx, 261 m_thread.m_reg_context_sp, 262 cfa, 263 pc, 264 NULL)); 265 m_frames.push_back (unwind_frame_sp); 266 } 267 else 268 { 269 unwind_frame_sp = m_frames.front(); 270 cfa = unwind_frame_sp->m_id.GetCallFrameAddress(); 271 } 272 } 273 else 274 { 275 const bool success = unwinder->GetFrameInfoAtIndex(idx, cfa, pc); 276 if (!success) 277 { 278 // We've gotten to the end of the stack. 279 SetAllFramesFetched(); 280 break; 281 } 282 unwind_frame_sp.reset (new StackFrame (m_thread.shared_from_this(), m_frames.size(), idx, cfa, pc, NULL)); 283 m_frames.push_back (unwind_frame_sp); 284 } 285 286 SymbolContext unwind_sc = unwind_frame_sp->GetSymbolContext (eSymbolContextBlock | eSymbolContextFunction); 287 Block *unwind_block = unwind_sc.block; 288 if (unwind_block) 289 { 290 Address curr_frame_address (unwind_frame_sp->GetFrameCodeAddress()); 291 // Be sure to adjust the frame address to match the address 292 // that was used to lookup the symbol context above. If we are 293 // in the first concrete frame, then we lookup using the current 294 // address, else we decrement the address by one to get the correct 295 // location. 296 if (idx > 0) 297 curr_frame_address.Slide(-1); 298 299 SymbolContext next_frame_sc; 300 Address next_frame_address; 301 302 while (unwind_sc.GetParentOfInlinedScope(curr_frame_address, next_frame_sc, next_frame_address)) 303 { 304 StackFrameSP frame_sp(new StackFrame (m_thread.shared_from_this(), 305 m_frames.size(), 306 idx, 307 unwind_frame_sp->GetRegisterContextSP (), 308 cfa, 309 next_frame_address, 310 &next_frame_sc)); 311 312 m_frames.push_back (frame_sp); 313 unwind_sc = next_frame_sc; 314 curr_frame_address = next_frame_address; 315 } 316 } 317 } while (m_frames.size() - 1 < end_idx); 318 319 // Don't try to merge till you've calculated all the frames in this stack. 320 if (GetAllFramesFetched() && m_prev_frames_sp) 321 { 322 StackFrameList *prev_frames = m_prev_frames_sp.get(); 323 StackFrameList *curr_frames = this; 324 325 curr_frames->m_current_inlined_depth = prev_frames->m_current_inlined_depth; 326 curr_frames->m_current_inlined_pc = prev_frames->m_current_inlined_pc; 327 328 #if defined (DEBUG_STACK_FRAMES) 329 s.PutCString("\nprev_frames:\n"); 330 prev_frames->Dump (&s); 331 s.PutCString("\ncurr_frames:\n"); 332 curr_frames->Dump (&s); 333 s.EOL(); 334 #endif 335 size_t curr_frame_num, prev_frame_num; 336 337 for (curr_frame_num = curr_frames->m_frames.size(), prev_frame_num = prev_frames->m_frames.size(); 338 curr_frame_num > 0 && prev_frame_num > 0; 339 --curr_frame_num, --prev_frame_num) 340 { 341 const size_t curr_frame_idx = curr_frame_num-1; 342 const size_t prev_frame_idx = prev_frame_num-1; 343 StackFrameSP curr_frame_sp (curr_frames->m_frames[curr_frame_idx]); 344 StackFrameSP prev_frame_sp (prev_frames->m_frames[prev_frame_idx]); 345 346 #if defined (DEBUG_STACK_FRAMES) 347 s.Printf("\n\nCurr frame #%u ", curr_frame_idx); 348 if (curr_frame_sp) 349 curr_frame_sp->Dump (&s, true, false); 350 else 351 s.PutCString("NULL"); 352 s.Printf("\nPrev frame #%u ", prev_frame_idx); 353 if (prev_frame_sp) 354 prev_frame_sp->Dump (&s, true, false); 355 else 356 s.PutCString("NULL"); 357 #endif 358 359 StackFrame *curr_frame = curr_frame_sp.get(); 360 StackFrame *prev_frame = prev_frame_sp.get(); 361 362 if (curr_frame == NULL || prev_frame == NULL) 363 break; 364 365 // Check the stack ID to make sure they are equal 366 if (curr_frame->GetStackID() != prev_frame->GetStackID()) 367 break; 368 369 prev_frame->UpdatePreviousFrameFromCurrentFrame (*curr_frame); 370 // Now copy the fixed up previous frame into the current frames 371 // so the pointer doesn't change 372 m_frames[curr_frame_idx] = prev_frame_sp; 373 //curr_frame->UpdateCurrentFrameFromPreviousFrame (*prev_frame); 374 375 #if defined (DEBUG_STACK_FRAMES) 376 s.Printf("\n Copying previous frame to current frame"); 377 #endif 378 } 379 // We are done with the old stack frame list, we can release it now 380 m_prev_frames_sp.reset(); 381 } 382 383 #if defined (DEBUG_STACK_FRAMES) 384 s.PutCString("\n\nNew frames:\n"); 385 Dump (&s); 386 s.EOL(); 387 #endif 388 } 389 else 390 { 391 if (end_idx < m_concrete_frames_fetched) 392 return; 393 394 uint32_t num_frames = unwinder->GetFramesUpTo(end_idx); 395 if (num_frames <= end_idx + 1) 396 { 397 //Done unwinding. 398 m_concrete_frames_fetched = UINT32_MAX; 399 } 400 m_frames.resize(num_frames); 401 } 402 } 403 404 uint32_t 405 StackFrameList::GetNumFrames (bool can_create) 406 { 407 Mutex::Locker locker (m_mutex); 408 409 if (can_create) 410 GetFramesUpTo (UINT32_MAX); 411 412 uint32_t inlined_depth = GetCurrentInlinedDepth(); 413 if (inlined_depth == UINT32_MAX) 414 return m_frames.size(); 415 else 416 return m_frames.size() - inlined_depth; 417 } 418 419 void 420 StackFrameList::Dump (Stream *s) 421 { 422 if (s == NULL) 423 return; 424 Mutex::Locker locker (m_mutex); 425 426 const_iterator pos, begin = m_frames.begin(), end = m_frames.end(); 427 for (pos = begin; pos != end; ++pos) 428 { 429 StackFrame *frame = (*pos).get(); 430 s->Printf("%p: ", frame); 431 if (frame) 432 { 433 frame->GetStackID().Dump (s); 434 frame->DumpUsingSettingsFormat (s); 435 } 436 else 437 s->Printf("frame #%u", (uint32_t)std::distance (begin, pos)); 438 s->EOL(); 439 } 440 s->EOL(); 441 } 442 443 StackFrameSP 444 StackFrameList::GetFrameAtIndex (uint32_t idx) 445 { 446 StackFrameSP frame_sp; 447 Mutex::Locker locker (m_mutex); 448 uint32_t inlined_depth = GetCurrentInlinedDepth(); 449 if (inlined_depth != UINT32_MAX) 450 idx += inlined_depth; 451 452 if (idx < m_frames.size()) 453 frame_sp = m_frames[idx]; 454 455 if (frame_sp) 456 return frame_sp; 457 458 // GetFramesUpTo will fill m_frames with as many frames as you asked for, 459 // if there are that many. If there weren't then you asked for too many 460 // frames. 461 GetFramesUpTo (idx); 462 if (idx < m_frames.size()) 463 { 464 if (m_show_inlined_frames) 465 { 466 // When inline frames are enabled we actually create all the frames in GetFramesUpTo. 467 frame_sp = m_frames[idx]; 468 } 469 else 470 { 471 Unwind *unwinder = m_thread.GetUnwinder (); 472 if (unwinder) 473 { 474 addr_t pc, cfa; 475 if (unwinder->GetFrameInfoAtIndex(idx, cfa, pc)) 476 { 477 frame_sp.reset (new StackFrame (m_thread.shared_from_this(), idx, idx, cfa, pc, NULL)); 478 479 Function *function = frame_sp->GetSymbolContext (eSymbolContextFunction).function; 480 if (function) 481 { 482 // When we aren't showing inline functions we always use 483 // the top most function block as the scope. 484 frame_sp->SetSymbolContextScope (&function->GetBlock(false)); 485 } 486 else 487 { 488 // Set the symbol scope from the symbol regardless if it is NULL or valid. 489 frame_sp->SetSymbolContextScope (frame_sp->GetSymbolContext (eSymbolContextSymbol).symbol); 490 } 491 SetFrameAtIndex(idx, frame_sp); 492 } 493 } 494 } 495 } 496 return frame_sp; 497 } 498 499 StackFrameSP 500 StackFrameList::GetFrameWithConcreteFrameIndex (uint32_t unwind_idx) 501 { 502 // First try assuming the unwind index is the same as the frame index. The 503 // unwind index is always greater than or equal to the frame index, so it 504 // is a good place to start. If we have inlined frames we might have 5 505 // concrete frames (frame unwind indexes go from 0-4), but we might have 15 506 // frames after we make all the inlined frames. Most of the time the unwind 507 // frame index (or the concrete frame index) is the same as the frame index. 508 uint32_t frame_idx = unwind_idx; 509 StackFrameSP frame_sp (GetFrameAtIndex (frame_idx)); 510 while (frame_sp) 511 { 512 if (frame_sp->GetFrameIndex() == unwind_idx) 513 break; 514 frame_sp = GetFrameAtIndex (++frame_idx); 515 } 516 return frame_sp; 517 } 518 519 StackFrameSP 520 StackFrameList::GetFrameWithStackID (const StackID &stack_id) 521 { 522 uint32_t frame_idx = 0; 523 StackFrameSP frame_sp; 524 do 525 { 526 frame_sp = GetFrameAtIndex (frame_idx); 527 if (frame_sp && frame_sp->GetStackID() == stack_id) 528 break; 529 frame_idx++; 530 } 531 while (frame_sp); 532 return frame_sp; 533 } 534 535 bool 536 StackFrameList::SetFrameAtIndex (uint32_t idx, StackFrameSP &frame_sp) 537 { 538 if (idx >= m_frames.size()) 539 m_frames.resize(idx + 1); 540 // Make sure allocation succeeded by checking bounds again 541 if (idx < m_frames.size()) 542 { 543 m_frames[idx] = frame_sp; 544 return true; 545 } 546 return false; // resize failed, out of memory? 547 } 548 549 uint32_t 550 StackFrameList::GetSelectedFrameIndex () const 551 { 552 Mutex::Locker locker (m_mutex); 553 return m_selected_frame_idx; 554 } 555 556 557 uint32_t 558 StackFrameList::SetSelectedFrame (lldb_private::StackFrame *frame) 559 { 560 Mutex::Locker locker (m_mutex); 561 const_iterator pos; 562 const_iterator begin = m_frames.begin(); 563 const_iterator end = m_frames.end(); 564 m_selected_frame_idx = 0; 565 for (pos = begin; pos != end; ++pos) 566 { 567 if (pos->get() == frame) 568 { 569 m_selected_frame_idx = std::distance (begin, pos); 570 uint32_t inlined_depth = GetCurrentInlinedDepth(); 571 if (inlined_depth != UINT32_MAX) 572 m_selected_frame_idx -= inlined_depth; 573 break; 574 } 575 } 576 SetDefaultFileAndLineToSelectedFrame(); 577 return m_selected_frame_idx; 578 } 579 580 // Mark a stack frame as the current frame using the frame index 581 bool 582 StackFrameList::SetSelectedFrameByIndex (uint32_t idx) 583 { 584 Mutex::Locker locker (m_mutex); 585 StackFrameSP frame_sp (GetFrameAtIndex (idx)); 586 if (frame_sp) 587 { 588 SetSelectedFrame(frame_sp.get()); 589 return true; 590 } 591 else 592 return false; 593 } 594 595 void 596 StackFrameList::SetDefaultFileAndLineToSelectedFrame() 597 { 598 if (m_thread.GetID() == m_thread.GetProcess()->GetThreadList().GetSelectedThread()->GetID()) 599 { 600 StackFrameSP frame_sp (GetFrameAtIndex (GetSelectedFrameIndex())); 601 if (frame_sp) 602 { 603 SymbolContext sc = frame_sp->GetSymbolContext(eSymbolContextLineEntry); 604 if (sc.line_entry.file) 605 m_thread.CalculateTarget()->GetSourceManager().SetDefaultFileAndLine (sc.line_entry.file, 606 sc.line_entry.line); 607 } 608 } 609 } 610 611 // The thread has been run, reset the number stack frames to zero so we can 612 // determine how many frames we have lazily. 613 void 614 StackFrameList::Clear () 615 { 616 Mutex::Locker locker (m_mutex); 617 m_frames.clear(); 618 m_concrete_frames_fetched = 0; 619 } 620 621 void 622 StackFrameList::InvalidateFrames (uint32_t start_idx) 623 { 624 Mutex::Locker locker (m_mutex); 625 if (m_show_inlined_frames) 626 { 627 Clear(); 628 } 629 else 630 { 631 const size_t num_frames = m_frames.size(); 632 while (start_idx < num_frames) 633 { 634 m_frames[start_idx].reset(); 635 ++start_idx; 636 } 637 } 638 } 639 640 void 641 StackFrameList::Merge (std::auto_ptr<StackFrameList>& curr_ap, lldb::StackFrameListSP& prev_sp) 642 { 643 Mutex::Locker curr_locker (curr_ap.get() ? &curr_ap->m_mutex : NULL); 644 Mutex::Locker prev_locker (prev_sp.get() ? &prev_sp->m_mutex : NULL); 645 646 #if defined (DEBUG_STACK_FRAMES) 647 StreamFile s(stdout, false); 648 s.PutCString("\n\nStackFrameList::Merge():\nPrev:\n"); 649 if (prev_sp.get()) 650 prev_sp->Dump (&s); 651 else 652 s.PutCString ("NULL"); 653 s.PutCString("\nCurr:\n"); 654 if (curr_ap.get()) 655 curr_ap->Dump (&s); 656 else 657 s.PutCString ("NULL"); 658 s.EOL(); 659 #endif 660 661 if (curr_ap.get() == NULL || curr_ap->GetNumFrames (false) == 0) 662 { 663 #if defined (DEBUG_STACK_FRAMES) 664 s.PutCString("No current frames, leave previous frames alone...\n"); 665 #endif 666 curr_ap.release(); 667 return; 668 } 669 670 if (prev_sp.get() == NULL || prev_sp->GetNumFrames (false) == 0) 671 { 672 #if defined (DEBUG_STACK_FRAMES) 673 s.PutCString("No previous frames, so use current frames...\n"); 674 #endif 675 // We either don't have any previous frames, or since we have more than 676 // one current frames it means we have all the frames and can safely 677 // replace our previous frames. 678 prev_sp.reset (curr_ap.release()); 679 return; 680 } 681 682 const uint32_t num_curr_frames = curr_ap->GetNumFrames (false); 683 684 if (num_curr_frames > 1) 685 { 686 #if defined (DEBUG_STACK_FRAMES) 687 s.PutCString("We have more than one current frame, so use current frames...\n"); 688 #endif 689 // We have more than one current frames it means we have all the frames 690 // and can safely replace our previous frames. 691 prev_sp.reset (curr_ap.release()); 692 693 #if defined (DEBUG_STACK_FRAMES) 694 s.PutCString("\nMerged:\n"); 695 prev_sp->Dump (&s); 696 #endif 697 return; 698 } 699 700 StackFrameSP prev_frame_zero_sp(prev_sp->GetFrameAtIndex (0)); 701 StackFrameSP curr_frame_zero_sp(curr_ap->GetFrameAtIndex (0)); 702 StackID curr_stack_id (curr_frame_zero_sp->GetStackID()); 703 StackID prev_stack_id (prev_frame_zero_sp->GetStackID()); 704 705 #if defined (DEBUG_STACK_FRAMES) 706 const uint32_t num_prev_frames = prev_sp->GetNumFrames (false); 707 s.Printf("\n%u previous frames with one current frame\n", num_prev_frames); 708 #endif 709 710 // We have only a single current frame 711 // Our previous stack frames only had a single frame as well... 712 if (curr_stack_id == prev_stack_id) 713 { 714 #if defined (DEBUG_STACK_FRAMES) 715 s.Printf("\nPrevious frame #0 is same as current frame #0, merge the cached data\n"); 716 #endif 717 718 curr_frame_zero_sp->UpdateCurrentFrameFromPreviousFrame (*prev_frame_zero_sp); 719 // prev_frame_zero_sp->UpdatePreviousFrameFromCurrentFrame (*curr_frame_zero_sp); 720 // prev_sp->SetFrameAtIndex (0, prev_frame_zero_sp); 721 } 722 else if (curr_stack_id < prev_stack_id) 723 { 724 #if defined (DEBUG_STACK_FRAMES) 725 s.Printf("\nCurrent frame #0 has a stack ID that is less than the previous frame #0, insert current frame zero in front of previous\n"); 726 #endif 727 prev_sp->m_frames.insert (prev_sp->m_frames.begin(), curr_frame_zero_sp); 728 } 729 730 curr_ap.release(); 731 732 #if defined (DEBUG_STACK_FRAMES) 733 s.PutCString("\nMerged:\n"); 734 prev_sp->Dump (&s); 735 #endif 736 737 738 } 739 740 lldb::StackFrameSP 741 StackFrameList::GetStackFrameSPForStackFramePtr (StackFrame *stack_frame_ptr) 742 { 743 const_iterator pos; 744 const_iterator begin = m_frames.begin(); 745 const_iterator end = m_frames.end(); 746 lldb::StackFrameSP ret_sp; 747 748 for (pos = begin; pos != end; ++pos) 749 { 750 if (pos->get() == stack_frame_ptr) 751 { 752 ret_sp = (*pos); 753 break; 754 } 755 } 756 return ret_sp; 757 } 758 759 size_t 760 StackFrameList::GetStatus (Stream& strm, 761 uint32_t first_frame, 762 uint32_t num_frames, 763 bool show_frame_info, 764 uint32_t num_frames_with_source) 765 { 766 size_t num_frames_displayed = 0; 767 768 if (num_frames == 0) 769 return 0; 770 771 StackFrameSP frame_sp; 772 uint32_t frame_idx = 0; 773 uint32_t last_frame; 774 775 // Don't let the last frame wrap around... 776 if (num_frames == UINT32_MAX) 777 last_frame = UINT32_MAX; 778 else 779 last_frame = first_frame + num_frames; 780 781 for (frame_idx = first_frame; frame_idx < last_frame; ++frame_idx) 782 { 783 frame_sp = GetFrameAtIndex(frame_idx); 784 if (frame_sp.get() == NULL) 785 break; 786 787 if (!frame_sp->GetStatus (strm, 788 show_frame_info, 789 num_frames_with_source > (first_frame - frame_idx))) 790 break; 791 ++num_frames_displayed; 792 } 793 794 strm.IndentLess(); 795 return num_frames_displayed; 796 } 797 798