StackFrameList.cpp revision 263367
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 && 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 && 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                const bool cfa_is_valid = true;
340                const bool stop_id_is_valid = false;
341                const bool is_history_frame = false;
342                unwind_frame_sp.reset (new StackFrame (m_thread.shared_from_this(), m_frames.size(), idx, cfa, cfa_is_valid, pc, 0, stop_id_is_valid, is_history_frame, NULL));
343                m_frames.push_back (unwind_frame_sp);
344            }
345
346            SymbolContext unwind_sc = unwind_frame_sp->GetSymbolContext (eSymbolContextBlock | eSymbolContextFunction);
347            Block *unwind_block = unwind_sc.block;
348            if (unwind_block)
349            {
350                Address curr_frame_address (unwind_frame_sp->GetFrameCodeAddress());
351                // Be sure to adjust the frame address to match the address
352                // that was used to lookup the symbol context above. If we are
353                // in the first concrete frame, then we lookup using the current
354                // address, else we decrement the address by one to get the correct
355                // location.
356                if (idx > 0)
357                    curr_frame_address.Slide(-1);
358
359                SymbolContext next_frame_sc;
360                Address next_frame_address;
361
362                while (unwind_sc.GetParentOfInlinedScope(curr_frame_address, next_frame_sc, next_frame_address))
363                {
364                        StackFrameSP frame_sp(new StackFrame (m_thread.shared_from_this(),
365                                                              m_frames.size(),
366                                                              idx,
367                                                              unwind_frame_sp->GetRegisterContextSP (),
368                                                              cfa,
369                                                              next_frame_address,
370                                                              &next_frame_sc));
371
372                        m_frames.push_back (frame_sp);
373                        unwind_sc = next_frame_sc;
374                        curr_frame_address = next_frame_address;
375                }
376            }
377        } while (m_frames.size() - 1 < end_idx);
378
379        // Don't try to merge till you've calculated all the frames in this stack.
380        if (GetAllFramesFetched() && m_prev_frames_sp)
381        {
382            StackFrameList *prev_frames = m_prev_frames_sp.get();
383            StackFrameList *curr_frames = this;
384
385            //curr_frames->m_current_inlined_depth = prev_frames->m_current_inlined_depth;
386            //curr_frames->m_current_inlined_pc = prev_frames->m_current_inlined_pc;
387            //printf ("GetFramesUpTo: Copying current inlined depth: %d 0x%" PRIx64 ".\n", curr_frames->m_current_inlined_depth, curr_frames->m_current_inlined_pc);
388
389#if defined (DEBUG_STACK_FRAMES)
390            s.PutCString("\nprev_frames:\n");
391            prev_frames->Dump (&s);
392            s.PutCString("\ncurr_frames:\n");
393            curr_frames->Dump (&s);
394            s.EOL();
395#endif
396            size_t curr_frame_num, prev_frame_num;
397
398            for (curr_frame_num = curr_frames->m_frames.size(), prev_frame_num = prev_frames->m_frames.size();
399                 curr_frame_num > 0 && prev_frame_num > 0;
400                 --curr_frame_num, --prev_frame_num)
401            {
402                const size_t curr_frame_idx = curr_frame_num-1;
403                const size_t prev_frame_idx = prev_frame_num-1;
404                StackFrameSP curr_frame_sp (curr_frames->m_frames[curr_frame_idx]);
405                StackFrameSP prev_frame_sp (prev_frames->m_frames[prev_frame_idx]);
406
407#if defined (DEBUG_STACK_FRAMES)
408                s.Printf("\n\nCurr frame #%u ", curr_frame_idx);
409                if (curr_frame_sp)
410                    curr_frame_sp->Dump (&s, true, false);
411                else
412                    s.PutCString("NULL");
413                s.Printf("\nPrev frame #%u ", prev_frame_idx);
414                if (prev_frame_sp)
415                    prev_frame_sp->Dump (&s, true, false);
416                else
417                    s.PutCString("NULL");
418#endif
419
420                StackFrame *curr_frame = curr_frame_sp.get();
421                StackFrame *prev_frame = prev_frame_sp.get();
422
423                if (curr_frame == NULL || prev_frame == NULL)
424                    break;
425
426                // Check the stack ID to make sure they are equal
427                if (curr_frame->GetStackID() != prev_frame->GetStackID())
428                    break;
429
430                prev_frame->UpdatePreviousFrameFromCurrentFrame (*curr_frame);
431                // Now copy the fixed up previous frame into the current frames
432                // so the pointer doesn't change
433                m_frames[curr_frame_idx] = prev_frame_sp;
434                //curr_frame->UpdateCurrentFrameFromPreviousFrame (*prev_frame);
435
436#if defined (DEBUG_STACK_FRAMES)
437                s.Printf("\n    Copying previous frame to current frame");
438#endif
439            }
440            // We are done with the old stack frame list, we can release it now
441            m_prev_frames_sp.reset();
442        }
443
444#if defined (DEBUG_STACK_FRAMES)
445            s.PutCString("\n\nNew frames:\n");
446            Dump (&s);
447            s.EOL();
448#endif
449    }
450    else
451    {
452        if (end_idx < m_concrete_frames_fetched)
453            return;
454
455        if (unwinder)
456        {
457            uint32_t num_frames = unwinder->GetFramesUpTo(end_idx);
458            if (num_frames <= end_idx + 1)
459            {
460                //Done unwinding.
461                m_concrete_frames_fetched = UINT32_MAX;
462            }
463            m_frames.resize(num_frames);
464        }
465    }
466}
467
468uint32_t
469StackFrameList::GetNumFrames (bool can_create)
470{
471    Mutex::Locker locker (m_mutex);
472
473    if (can_create)
474        GetFramesUpTo (UINT32_MAX);
475
476    uint32_t inlined_depth = GetCurrentInlinedDepth();
477    if (inlined_depth == UINT32_MAX)
478        return m_frames.size();
479    else
480        return m_frames.size() - inlined_depth;
481}
482
483void
484StackFrameList::Dump (Stream *s)
485{
486    if (s == NULL)
487        return;
488    Mutex::Locker locker (m_mutex);
489
490    const_iterator pos, begin = m_frames.begin(), end = m_frames.end();
491    for (pos = begin; pos != end; ++pos)
492    {
493        StackFrame *frame = (*pos).get();
494        s->Printf("%p: ", frame);
495        if (frame)
496        {
497            frame->GetStackID().Dump (s);
498            frame->DumpUsingSettingsFormat (s);
499        }
500        else
501            s->Printf("frame #%u", (uint32_t)std::distance (begin, pos));
502        s->EOL();
503    }
504    s->EOL();
505}
506
507StackFrameSP
508StackFrameList::GetFrameAtIndex (uint32_t idx)
509{
510    StackFrameSP frame_sp;
511    Mutex::Locker locker (m_mutex);
512    uint32_t original_idx = idx;
513
514    uint32_t inlined_depth = GetCurrentInlinedDepth();
515    if (inlined_depth != UINT32_MAX)
516        idx += inlined_depth;
517
518    if (idx < m_frames.size())
519        frame_sp = m_frames[idx];
520
521    if (frame_sp)
522        return frame_sp;
523
524    // GetFramesUpTo will fill m_frames with as many frames as you asked for,
525    // if there are that many.  If there weren't then you asked for too many
526    // frames.
527    GetFramesUpTo (idx);
528    if (idx < m_frames.size())
529    {
530        if (m_show_inlined_frames)
531        {
532            // When inline frames are enabled we actually create all the frames in GetFramesUpTo.
533            frame_sp = m_frames[idx];
534        }
535        else
536        {
537            Unwind *unwinder = m_thread.GetUnwinder ();
538            if (unwinder)
539            {
540                addr_t pc, cfa;
541                if (unwinder->GetFrameInfoAtIndex(idx, cfa, pc))
542                {
543                    const bool cfa_is_valid = true;
544                    const bool stop_id_is_valid = false;
545                    const bool is_history_frame = false;
546                    frame_sp.reset (new StackFrame (m_thread.shared_from_this(), idx, idx, cfa, cfa_is_valid, pc, 0, stop_id_is_valid, is_history_frame, NULL));
547
548                    Function *function = frame_sp->GetSymbolContext (eSymbolContextFunction).function;
549                    if (function)
550                    {
551                        // When we aren't showing inline functions we always use
552                        // the top most function block as the scope.
553                        frame_sp->SetSymbolContextScope (&function->GetBlock(false));
554                    }
555                    else
556                    {
557                        // Set the symbol scope from the symbol regardless if it is NULL or valid.
558                        frame_sp->SetSymbolContextScope (frame_sp->GetSymbolContext (eSymbolContextSymbol).symbol);
559                    }
560                    SetFrameAtIndex(idx, frame_sp);
561                }
562            }
563        }
564    }
565    else if (original_idx == 0)
566    {
567        // There should ALWAYS be a frame at index 0.  If something went wrong with the CurrentInlinedDepth such that
568        // there weren't as many frames as we thought taking that into account, then reset the current inlined depth
569        // and return the real zeroth frame.
570        if (m_frames.size() > 0)
571        {
572            ResetCurrentInlinedDepth();
573            frame_sp = m_frames[original_idx];
574        }
575        else
576        {
577            // Why do we have a thread with zero frames, that should not ever happen...
578            if (m_thread.IsValid())
579                assert ("A valid thread has no frames.");
580
581        }
582    }
583
584    return frame_sp;
585}
586
587StackFrameSP
588StackFrameList::GetFrameWithConcreteFrameIndex (uint32_t unwind_idx)
589{
590    // First try assuming the unwind index is the same as the frame index. The
591    // unwind index is always greater than or equal to the frame index, so it
592    // is a good place to start. If we have inlined frames we might have 5
593    // concrete frames (frame unwind indexes go from 0-4), but we might have 15
594    // frames after we make all the inlined frames. Most of the time the unwind
595    // frame index (or the concrete frame index) is the same as the frame index.
596    uint32_t frame_idx = unwind_idx;
597    StackFrameSP frame_sp (GetFrameAtIndex (frame_idx));
598    while (frame_sp)
599    {
600        if (frame_sp->GetFrameIndex() == unwind_idx)
601            break;
602        frame_sp = GetFrameAtIndex (++frame_idx);
603    }
604    return frame_sp;
605}
606
607static bool
608CompareStackID (const StackFrameSP &stack_sp, const StackID &stack_id)
609{
610    return stack_sp->GetStackID() < stack_id;
611}
612
613StackFrameSP
614StackFrameList::GetFrameWithStackID (const StackID &stack_id)
615{
616    StackFrameSP frame_sp;
617
618    if (stack_id.IsValid())
619    {
620        Mutex::Locker locker (m_mutex);
621        uint32_t frame_idx = 0;
622        // Do a binary search in case the stack frame is already in our cache
623        collection::const_iterator begin = m_frames.begin();
624        collection::const_iterator end = m_frames.end();
625        if (begin != end)
626        {
627            collection::const_iterator pos = std::lower_bound (begin, end, stack_id, CompareStackID);
628            if (pos != end && (*pos)->GetStackID() == stack_id)
629                return *pos;
630
631            if (m_frames.back()->GetStackID() < stack_id)
632                frame_idx = m_frames.size();
633        }
634        do
635        {
636            frame_sp = GetFrameAtIndex (frame_idx);
637            if (frame_sp && frame_sp->GetStackID() == stack_id)
638                break;
639            frame_idx++;
640        }
641        while (frame_sp);
642    }
643    return frame_sp;
644}
645
646bool
647StackFrameList::SetFrameAtIndex (uint32_t idx, StackFrameSP &frame_sp)
648{
649    if (idx >= m_frames.size())
650        m_frames.resize(idx + 1);
651    // Make sure allocation succeeded by checking bounds again
652    if (idx < m_frames.size())
653    {
654        m_frames[idx] = frame_sp;
655        return true;
656    }
657    return false;   // resize failed, out of memory?
658}
659
660uint32_t
661StackFrameList::GetSelectedFrameIndex () const
662{
663    Mutex::Locker locker (m_mutex);
664    return m_selected_frame_idx;
665}
666
667
668uint32_t
669StackFrameList::SetSelectedFrame (lldb_private::StackFrame *frame)
670{
671    Mutex::Locker locker (m_mutex);
672    const_iterator pos;
673    const_iterator begin = m_frames.begin();
674    const_iterator end = m_frames.end();
675    m_selected_frame_idx = 0;
676    for (pos = begin; pos != end; ++pos)
677    {
678        if (pos->get() == frame)
679        {
680            m_selected_frame_idx = std::distance (begin, pos);
681            uint32_t inlined_depth = GetCurrentInlinedDepth();
682            if (inlined_depth != UINT32_MAX)
683                m_selected_frame_idx -= inlined_depth;
684            break;
685        }
686    }
687    SetDefaultFileAndLineToSelectedFrame();
688    return m_selected_frame_idx;
689}
690
691// Mark a stack frame as the current frame using the frame index
692bool
693StackFrameList::SetSelectedFrameByIndex (uint32_t idx)
694{
695    Mutex::Locker locker (m_mutex);
696    StackFrameSP frame_sp (GetFrameAtIndex (idx));
697    if (frame_sp)
698    {
699        SetSelectedFrame(frame_sp.get());
700        return true;
701    }
702    else
703        return false;
704}
705
706void
707StackFrameList::SetDefaultFileAndLineToSelectedFrame()
708{
709    if (m_thread.GetID() == m_thread.GetProcess()->GetThreadList().GetSelectedThread()->GetID())
710    {
711        StackFrameSP frame_sp (GetFrameAtIndex (GetSelectedFrameIndex()));
712        if (frame_sp)
713        {
714            SymbolContext sc = frame_sp->GetSymbolContext(eSymbolContextLineEntry);
715            if (sc.line_entry.file)
716                m_thread.CalculateTarget()->GetSourceManager().SetDefaultFileAndLine (sc.line_entry.file,
717                                                                                            sc.line_entry.line);
718        }
719    }
720}
721
722// The thread has been run, reset the number stack frames to zero so we can
723// determine how many frames we have lazily.
724void
725StackFrameList::Clear ()
726{
727    Mutex::Locker locker (m_mutex);
728    m_frames.clear();
729    m_concrete_frames_fetched = 0;
730}
731
732void
733StackFrameList::InvalidateFrames (uint32_t start_idx)
734{
735    Mutex::Locker locker (m_mutex);
736    if (m_show_inlined_frames)
737    {
738        Clear();
739    }
740    else
741    {
742        const size_t num_frames = m_frames.size();
743        while (start_idx < num_frames)
744        {
745            m_frames[start_idx].reset();
746            ++start_idx;
747        }
748    }
749}
750
751void
752StackFrameList::Merge (std::unique_ptr<StackFrameList>& curr_ap, lldb::StackFrameListSP& prev_sp)
753{
754    Mutex::Locker curr_locker (curr_ap.get() ? &curr_ap->m_mutex : NULL);
755    Mutex::Locker prev_locker (prev_sp.get() ? &prev_sp->m_mutex : NULL);
756
757#if defined (DEBUG_STACK_FRAMES)
758    StreamFile s(stdout, false);
759    s.PutCString("\n\nStackFrameList::Merge():\nPrev:\n");
760    if (prev_sp.get())
761        prev_sp->Dump (&s);
762    else
763        s.PutCString ("NULL");
764    s.PutCString("\nCurr:\n");
765    if (curr_ap.get())
766        curr_ap->Dump (&s);
767    else
768        s.PutCString ("NULL");
769    s.EOL();
770#endif
771
772    if (curr_ap.get() == NULL || curr_ap->GetNumFrames (false) == 0)
773    {
774#if defined (DEBUG_STACK_FRAMES)
775        s.PutCString("No current frames, leave previous frames alone...\n");
776#endif
777        curr_ap.release();
778        return;
779    }
780
781    if (prev_sp.get() == NULL || prev_sp->GetNumFrames (false) == 0)
782    {
783#if defined (DEBUG_STACK_FRAMES)
784        s.PutCString("No previous frames, so use current frames...\n");
785#endif
786        // We either don't have any previous frames, or since we have more than
787        // one current frames it means we have all the frames and can safely
788        // replace our previous frames.
789        prev_sp.reset (curr_ap.release());
790        return;
791    }
792
793    const uint32_t num_curr_frames = curr_ap->GetNumFrames (false);
794
795    if (num_curr_frames > 1)
796    {
797#if defined (DEBUG_STACK_FRAMES)
798        s.PutCString("We have more than one current frame, so use current frames...\n");
799#endif
800        // We have more than one current frames it means we have all the frames
801        // and can safely replace our previous frames.
802        prev_sp.reset (curr_ap.release());
803
804#if defined (DEBUG_STACK_FRAMES)
805        s.PutCString("\nMerged:\n");
806        prev_sp->Dump (&s);
807#endif
808        return;
809    }
810
811    StackFrameSP prev_frame_zero_sp(prev_sp->GetFrameAtIndex (0));
812    StackFrameSP curr_frame_zero_sp(curr_ap->GetFrameAtIndex (0));
813    StackID curr_stack_id (curr_frame_zero_sp->GetStackID());
814    StackID prev_stack_id (prev_frame_zero_sp->GetStackID());
815
816#if defined (DEBUG_STACK_FRAMES)
817    const uint32_t num_prev_frames = prev_sp->GetNumFrames (false);
818    s.Printf("\n%u previous frames with one current frame\n", num_prev_frames);
819#endif
820
821    // We have only a single current frame
822    // Our previous stack frames only had a single frame as well...
823    if (curr_stack_id == prev_stack_id)
824    {
825#if defined (DEBUG_STACK_FRAMES)
826        s.Printf("\nPrevious frame #0 is same as current frame #0, merge the cached data\n");
827#endif
828
829        curr_frame_zero_sp->UpdateCurrentFrameFromPreviousFrame (*prev_frame_zero_sp);
830//        prev_frame_zero_sp->UpdatePreviousFrameFromCurrentFrame (*curr_frame_zero_sp);
831//        prev_sp->SetFrameAtIndex (0, prev_frame_zero_sp);
832    }
833    else if (curr_stack_id < prev_stack_id)
834    {
835#if defined (DEBUG_STACK_FRAMES)
836        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");
837#endif
838        prev_sp->m_frames.insert (prev_sp->m_frames.begin(), curr_frame_zero_sp);
839    }
840
841    curr_ap.release();
842
843#if defined (DEBUG_STACK_FRAMES)
844    s.PutCString("\nMerged:\n");
845    prev_sp->Dump (&s);
846#endif
847
848
849}
850
851lldb::StackFrameSP
852StackFrameList::GetStackFrameSPForStackFramePtr (StackFrame *stack_frame_ptr)
853{
854    const_iterator pos;
855    const_iterator begin = m_frames.begin();
856    const_iterator end = m_frames.end();
857    lldb::StackFrameSP ret_sp;
858
859    for (pos = begin; pos != end; ++pos)
860    {
861        if (pos->get() == stack_frame_ptr)
862        {
863            ret_sp = (*pos);
864            break;
865        }
866    }
867    return ret_sp;
868}
869
870size_t
871StackFrameList::GetStatus (Stream& strm,
872                           uint32_t first_frame,
873                           uint32_t num_frames,
874                           bool show_frame_info,
875                           uint32_t num_frames_with_source,
876                           const char *selected_frame_marker)
877{
878    size_t num_frames_displayed = 0;
879
880    if (num_frames == 0)
881        return 0;
882
883    StackFrameSP frame_sp;
884    uint32_t frame_idx = 0;
885    uint32_t last_frame;
886
887    // Don't let the last frame wrap around...
888    if (num_frames == UINT32_MAX)
889        last_frame = UINT32_MAX;
890    else
891        last_frame = first_frame + num_frames;
892
893    StackFrameSP selected_frame_sp = m_thread.GetSelectedFrame();
894    const char *unselected_marker = NULL;
895    std::string buffer;
896    if (selected_frame_marker)
897    {
898        size_t len = strlen(selected_frame_marker);
899        buffer.insert(buffer.begin(), len, ' ');
900        unselected_marker = buffer.c_str();
901    }
902    const char *marker = NULL;
903
904    for (frame_idx = first_frame; frame_idx < last_frame; ++frame_idx)
905    {
906        frame_sp = GetFrameAtIndex(frame_idx);
907        if (frame_sp.get() == NULL)
908            break;
909
910        if (selected_frame_marker != NULL)
911        {
912            if (frame_sp == selected_frame_sp)
913                marker = selected_frame_marker;
914            else
915                marker = unselected_marker;
916        }
917
918        if (!frame_sp->GetStatus (strm,
919                                  show_frame_info,
920                                  num_frames_with_source > (first_frame - frame_idx), marker))
921            break;
922        ++num_frames_displayed;
923    }
924
925    strm.IndentLess();
926    return num_frames_displayed;
927}
928
929