1 //===-- StackFrameList.cpp --------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "lldb/Target/StackFrameList.h"
11 
12 // C Includes
13 // C++ Includes
14 // Other libraries and framework includes
15 // Project includes
16 #include "lldb/Core/StreamFile.h"
17 #include "lldb/Symbol/Block.h"
18 #include "lldb/Symbol/Function.h"
19 #include "lldb/Symbol/Symbol.h"
20 #include "lldb/Target/RegisterContext.h"
21 #include "lldb/Target/StackFrame.h"
22 #include "lldb/Target/Thread.h"
23 #include "lldb/Target/Unwind.h"
24 
25 //#define DEBUG_STACK_FRAMES 1
26 
27 using namespace lldb;
28 using namespace lldb_private;
29 
30 //----------------------------------------------------------------------
31 // StackFrameList constructor
32 //----------------------------------------------------------------------
33 StackFrameList::StackFrameList(Thread &thread, StackFrameList *prev_frames, bool show_inline_frames) :
34     m_thread (thread),
35     m_prev_frames_ap (prev_frames),
36     m_show_inlined_frames (show_inline_frames),
37     m_mutex (Mutex::eMutexTypeRecursive),
38     m_frames (),
39     m_selected_frame_idx (0)
40 {
41 }
42 
43 //----------------------------------------------------------------------
44 // Destructor
45 //----------------------------------------------------------------------
46 StackFrameList::~StackFrameList()
47 {
48 }
49 
50 
51 uint32_t
52 StackFrameList::GetNumFrames()
53 {
54     Mutex::Locker locker (m_mutex);
55 
56     if (m_frames.size() <= 1)
57     {
58         if (m_show_inlined_frames)
59         {
60 #if defined (DEBUG_STACK_FRAMES)
61             StreamFile s(stdout);
62 #endif
63             Unwind *unwinder = m_thread.GetUnwinder ();
64             addr_t pc = LLDB_INVALID_ADDRESS;
65             addr_t cfa = LLDB_INVALID_ADDRESS;
66 
67             // If we are going to show inlined stack frames as actual frames,
68             // we need to calculate all concrete frames first, then iterate
69             // through all of them and count up how many inlined functions are
70             // in each frame.
71             const uint32_t unwind_frame_count = unwinder->GetFrameCount();
72 
73             StackFrameSP unwind_frame_sp;
74             for (uint32_t idx=0; idx<unwind_frame_count; ++idx)
75             {
76                 if (idx == 0)
77                 {
78                     // We might have already created frame zero, only create it
79                     // if we need to
80                     if (m_frames.empty())
81                     {
82                         cfa = m_thread.m_reg_context_sp->GetSP();
83                         m_thread.GetRegisterContext();
84                         unwind_frame_sp.reset (new StackFrame (m_frames.size(),
85                                                                idx,
86                                                                m_thread,
87                                                                m_thread.m_reg_context_sp,
88                                                                cfa,
89                                                                m_thread.m_reg_context_sp->GetPC(),
90                                                                NULL));
91                         m_frames.push_back (unwind_frame_sp);
92                     }
93                     else
94                     {
95                         unwind_frame_sp = m_frames.front();
96                         cfa = unwind_frame_sp->m_id.GetCallFrameAddress();
97                     }
98                 }
99                 else
100                 {
101                     const bool success = unwinder->GetFrameInfoAtIndex(idx, cfa, pc);
102                     assert (success);
103                     unwind_frame_sp.reset (new StackFrame (m_frames.size(), idx, m_thread, cfa, pc, NULL));
104                     m_frames.push_back (unwind_frame_sp);
105                 }
106 
107                 Block *unwind_block = unwind_frame_sp->GetSymbolContext (eSymbolContextBlock).block;
108 
109                 if (unwind_block)
110                 {
111                     Block *inlined_block = unwind_block->GetContainingInlinedBlock();
112                     if (inlined_block)
113                     {
114                         for (; inlined_block != NULL; inlined_block = inlined_block->GetInlinedParent ())
115                         {
116                             SymbolContext inline_sc;
117                             Block *parent_block = inlined_block->GetInlinedParent();
118 
119                             const bool is_inlined_frame = parent_block != NULL;
120 
121                             if (parent_block == NULL)
122                                 parent_block = inlined_block->GetParent();
123 
124                             parent_block->CalculateSymbolContext (&inline_sc);
125 
126                             Address previous_frame_lookup_addr (m_frames.back()->GetFrameCodeAddress());
127                             if (unwind_frame_sp->GetFrameIndex() > 0 && m_frames.back().get() == unwind_frame_sp.get())
128                                 previous_frame_lookup_addr.Slide (-1);
129 
130                             AddressRange range;
131                             inlined_block->GetRangeContainingAddress (previous_frame_lookup_addr, range);
132 
133                             const InlineFunctionInfo* inline_info = inlined_block->InlinedFunctionInfo();
134                             assert (inline_info);
135                             inline_sc.line_entry.range.GetBaseAddress() = m_frames.back()->GetFrameCodeAddress();
136                             inline_sc.line_entry.file = inline_info->GetCallSite().GetFile();
137                             inline_sc.line_entry.line = inline_info->GetCallSite().GetLine();
138                             inline_sc.line_entry.column = inline_info->GetCallSite().GetColumn();
139 
140                             StackFrameSP frame_sp(new StackFrame (m_frames.size(),
141                                                                   idx,
142                                                                   m_thread,
143                                                                   unwind_frame_sp->GetRegisterContextSP (),
144                                                                   cfa,
145                                                                   range.GetBaseAddress(),
146                                                                   &inline_sc));                                           // The symbol context for this inline frame
147 
148                             if (is_inlined_frame)
149                             {
150                                 // Use the block with the inlined function info
151                                 // as the symbol context since we want this frame
152                                 // to have only the variables for the inlined function
153                                 frame_sp->SetSymbolContextScope (parent_block);
154                             }
155                             else
156                             {
157                                 // This block is not inlined with means it has no
158                                 // inlined parents either, so we want to use the top
159                                 // most function block.
160                                 frame_sp->SetSymbolContextScope (&unwind_frame_sp->GetSymbolContext (eSymbolContextFunction).function->GetBlock(false));
161                             }
162 
163                             m_frames.push_back (frame_sp);
164                         }
165                     }
166                 }
167             }
168             StackFrameList *prev_frames = m_prev_frames_ap.get();
169             if (prev_frames)
170             {
171                 StackFrameList *curr_frames = this;
172 
173 #if defined (DEBUG_STACK_FRAMES)
174                 s.PutCString("\nprev_frames:\n");
175                 prev_frames->Dump (&s);
176                 s.PutCString("\ncurr_frames:\n");
177                 curr_frames->Dump (&s);
178                 s.EOL();
179 #endif
180                 size_t curr_frame_num, prev_frame_num;
181 
182                 for (curr_frame_num = curr_frames->m_frames.size(), prev_frame_num = prev_frames->m_frames.size();
183                      curr_frame_num > 0 && prev_frame_num > 0;
184                      --curr_frame_num, --prev_frame_num)
185                 {
186                     const size_t curr_frame_idx = curr_frame_num-1;
187                     const size_t prev_frame_idx = prev_frame_num-1;
188                     StackFrameSP curr_frame_sp (curr_frames->m_frames[curr_frame_idx]);
189                     StackFrameSP prev_frame_sp (prev_frames->m_frames[prev_frame_idx]);
190 
191 #if defined (DEBUG_STACK_FRAMES)
192                     s.Printf("\nCurrent frame #%u ", curr_frame_idx);
193                     if (curr_frame_sp)
194                         curr_frame_sp->Dump (&s, true);
195                     else
196                         s.PutCString("NULL");
197                     s.Printf("\nPrevious frame #%u ", prev_frame_idx);
198                     if (prev_frame_sp)
199                         prev_frame_sp->Dump (&s, true);
200                     else
201                         s.PutCString("NULL");
202                     s.EOL();
203 #endif
204 
205                     StackFrame *curr_frame = curr_frame_sp.get();
206                     StackFrame *prev_frame = prev_frame_sp.get();
207 
208                     if (curr_frame == NULL || prev_frame == NULL)
209                         break;
210 
211                     // Check the stack ID to make sure they are equal
212                     if (curr_frame->GetStackID() != prev_frame->GetStackID())
213                         break;
214 
215                     prev_frame->UpdatePreviousFrameFromCurrentFrame (*curr_frame);
216                     // Now copy the fixed up previous frame into the current frames
217                     // so the pointer doesn't change
218                     m_frames[curr_frame_idx] = prev_frame_sp;
219                     //curr_frame->UpdateCurrentFrameFromPreviousFrame (*prev_frame);
220 
221 #if defined (DEBUG_STACK_FRAMES)
222                     s.Printf("\n    Copying previous frame to current frame");
223 #endif
224                 }
225                 // We are done with the old stack frame list, we can release it now
226                 m_prev_frames_ap.release();
227                 prev_frames = NULL;
228             }
229 
230 #if defined (DEBUG_STACK_FRAMES)
231                 s.PutCString("\n\nNew frames:\n");
232                 Dump (&s);
233                 s.EOL();
234 #endif
235         }
236         else
237         {
238             m_frames.resize(m_thread.GetUnwinder()->GetFrameCount());
239         }
240     }
241     return m_frames.size();
242 }
243 
244 void
245 StackFrameList::Dump (Stream *s)
246 {
247     if (s == NULL)
248         return;
249     Mutex::Locker locker (m_mutex);
250 
251     const_iterator pos, begin = m_frames.begin(), end = m_frames.end();
252     for (pos = begin; pos != end; ++pos)
253     {
254         StackFrame *frame = (*pos).get();
255         s->Printf("%p: ", frame);
256         if (frame)
257         {
258             frame->GetStackID().Dump (s);
259             frame->Dump(s, true);
260         }
261         else
262             s->Printf("frame #%u", std::distance (begin, pos));
263         s->EOL();
264     }
265     s->EOL();
266 }
267 
268 StackFrameSP
269 StackFrameList::GetFrameAtIndex (uint32_t idx)
270 {
271     StackFrameSP frame_sp;
272     Mutex::Locker locker (m_mutex);
273     if (idx < m_frames.size())
274         frame_sp = m_frames[idx];
275 
276     if (frame_sp)
277         return frame_sp;
278 
279     // Special case the first frame (idx == 0) so that we don't need to
280     // know how many stack frames there are to get it. If we need any other
281     // frames, then we do need to know if "idx" is a valid index.
282     if (idx == 0)
283     {
284         // If this is the first frame, we want to share the thread register
285         // context with the stack frame at index zero.
286         m_thread.GetRegisterContext();
287         assert (m_thread.m_reg_context_sp.get());
288         frame_sp.reset (new StackFrame (0,
289                                         0,
290                                         m_thread,
291                                         m_thread.m_reg_context_sp,
292                                         m_thread.m_reg_context_sp->GetSP(),
293                                         m_thread.m_reg_context_sp->GetPC(),
294                                         NULL));
295 
296         SetFrameAtIndex(idx, frame_sp);
297     }
298     else if (idx < GetNumFrames())
299     {
300         if (m_show_inlined_frames)
301         {
302             // When inline frames are enabled we cache up all frames in GetNumFrames()
303             frame_sp = m_frames[idx];
304         }
305         else
306         {
307             Unwind *unwinder = m_thread.GetUnwinder ();
308             if (unwinder)
309             {
310                 addr_t pc, cfa;
311                 if (unwinder->GetFrameInfoAtIndex(idx, cfa, pc))
312                 {
313                     frame_sp.reset (new StackFrame (idx, idx, m_thread, cfa, pc, NULL));
314 
315                     Function *function = frame_sp->GetSymbolContext (eSymbolContextFunction).function;
316                     if (function)
317                     {
318                         // When we aren't showing inline functions we always use
319                         // the top most function block as the scope.
320                         frame_sp->SetSymbolContextScope (&function->GetBlock(false));
321                     }
322                     else
323                     {
324                         // Set the symbol scope from the symbol regardless if it is NULL or valid.
325                         frame_sp->SetSymbolContextScope (frame_sp->GetSymbolContext (eSymbolContextSymbol).symbol);
326                     }
327                     SetFrameAtIndex(idx, frame_sp);
328                 }
329             }
330         }
331     }
332     return frame_sp;
333 }
334 
335 
336 bool
337 StackFrameList::SetFrameAtIndex (uint32_t idx, StackFrameSP &frame_sp)
338 {
339     if (idx >= m_frames.size())
340         m_frames.resize(idx + 1);
341     // Make sure allocation succeeded by checking bounds again
342     if (idx < m_frames.size())
343     {
344         m_frames[idx] = frame_sp;
345         return true;
346     }
347     return false;   // resize failed, out of memory?
348 }
349 
350 uint32_t
351 StackFrameList::GetSelectedFrameIndex () const
352 {
353     Mutex::Locker locker (m_mutex);
354     return m_selected_frame_idx;
355 }
356 
357 
358 uint32_t
359 StackFrameList::SetSelectedFrame (lldb_private::StackFrame *frame)
360 {
361     Mutex::Locker locker (m_mutex);
362     const_iterator pos;
363     const_iterator begin = m_frames.begin();
364     const_iterator end = m_frames.end();
365     for (pos = begin; pos != end; ++pos)
366     {
367         if (pos->get() == frame)
368         {
369             m_selected_frame_idx = std::distance (begin, pos);
370             return m_selected_frame_idx;
371         }
372     }
373     m_selected_frame_idx = 0;
374     return m_selected_frame_idx;
375 }
376 
377 // Mark a stack frame as the current frame using the frame index
378 void
379 StackFrameList::SetSelectedFrameByIndex (uint32_t idx)
380 {
381     Mutex::Locker locker (m_mutex);
382     m_selected_frame_idx = idx;
383 }
384 
385 // The thread has been run, reset the number stack frames to zero so we can
386 // determine how many frames we have lazily.
387 void
388 StackFrameList::Clear ()
389 {
390     Mutex::Locker locker (m_mutex);
391     m_frames.clear();
392 }
393 
394 void
395 StackFrameList::InvalidateFrames (uint32_t start_idx)
396 {
397     Mutex::Locker locker (m_mutex);
398     if (m_show_inlined_frames)
399     {
400         Clear();
401     }
402     else
403     {
404         const size_t num_frames = m_frames.size();
405         while (start_idx < num_frames)
406         {
407             m_frames[start_idx].reset();
408             ++start_idx;
409         }
410     }
411 }
412