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