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