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