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