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/Symbol/Block.h"
17 #include "lldb/Symbol/Function.h"
18 #include "lldb/Target/RegisterContext.h"
19 #include "lldb/Target/StackFrame.h"
20 #include "lldb/Target/Thread.h"
21 #include "lldb/Target/Unwind.h"
22 
23 using namespace lldb;
24 using namespace lldb_private;
25 
26 //----------------------------------------------------------------------
27 // StackFrameList constructor
28 //----------------------------------------------------------------------
29 StackFrameList::StackFrameList(Thread &thread, bool show_inline_frames) :
30     m_thread (thread),
31     m_show_inlined_frames (show_inline_frames),
32     m_mutex (Mutex::eMutexTypeRecursive),
33     m_actual_frames (),
34     m_inline_frames (),
35     m_current_frame_idx (0)
36 {
37 }
38 
39 //----------------------------------------------------------------------
40 // Destructor
41 //----------------------------------------------------------------------
42 StackFrameList::~StackFrameList()
43 {
44 }
45 
46 
47 uint32_t
48 StackFrameList::GetNumFrames()
49 {
50     Mutex::Locker locker (m_mutex);
51 
52     if (m_show_inlined_frames)
53     {
54         if (m_inlined_frame_info.empty())
55         {
56             Unwind *unwinder = m_thread.GetUnwinder ();
57             // If we are going to show inlined stack frames as actual frames,
58             // we need to calculate all concrete frames first, then iterate
59             // through all of them and count up how many inlined functions are
60             // in each frame. We can then fill in m_inlined_frame_info with
61             // the concrete frame index and inlined depth
62             const uint32_t concrete_frame_count = unwinder->GetFrameCount();
63 
64             addr_t pc, cfa;
65             InlinedFrameInfo inlined_frame_info;
66 
67             StackFrameSP frame_sp;
68             for (uint32_t idx=0; idx<concrete_frame_count; ++idx)
69             {
70                 if (idx == 0)
71                 {
72                     m_thread.GetRegisterContext();
73                     frame_sp.reset (new StackFrame (0,
74                                                     0,
75                                                     m_thread,
76                                                     m_thread.m_reg_context_sp,
77                                                     m_thread.m_reg_context_sp->GetSP(),
78                                                     0,
79                                                     m_thread.m_reg_context_sp->GetPC(),
80                                                     NULL));
81                 }
82                 else
83                 {
84                     const bool success = unwinder->GetFrameInfoAtIndex(idx, cfa, pc);
85                     assert (success);
86                     frame_sp.reset (new StackFrame (m_inlined_frame_info.size(), idx, m_thread, cfa, 0, pc, NULL));
87                 }
88                 SetActualFrameAtIndex (idx, frame_sp);
89                 Block *block = frame_sp->GetSymbolContext (eSymbolContextBlock).block;
90 
91                 inlined_frame_info.concrete_frame_index = idx;
92                 inlined_frame_info.inline_height = 0;
93                 inlined_frame_info.block = block;
94                 m_inlined_frame_info.push_back (inlined_frame_info);
95 
96                 if (block)
97                 {
98                     Block *inlined_block;
99                     if (block->InlinedFunctionInfo())
100                         inlined_block = block;
101                     else
102                         inlined_block = block->GetInlinedParent ();
103 
104                     while (inlined_block)
105                     {
106                         inlined_frame_info.block = inlined_block;
107                         inlined_frame_info.inline_height++;
108                         m_inlined_frame_info.push_back (inlined_frame_info);
109                         inlined_block = inlined_block->GetInlinedParent ();
110                     }
111                 }
112             }
113         }
114         return m_inlined_frame_info.size();
115     }
116     else
117     {
118         if (m_actual_frames.empty())
119             m_actual_frames.resize(m_thread.GetUnwinder()->GetFrameCount());
120 
121         return m_actual_frames.size();
122     }
123     return 0;
124 }
125 
126 lldb::StackFrameSP
127 StackFrameList::GetActualFrameAtIndex (uint32_t idx) const
128 {
129     StackFrameSP frame_sp;
130         if (idx < m_actual_frames.size())
131             frame_sp = m_actual_frames[idx];
132     return frame_sp;
133 }
134 
135 lldb::StackFrameSP
136 StackFrameList::GetInlineFrameAtIndex (uint32_t idx) const
137 {
138     StackFrameSP frame_sp;
139     if (idx < m_inline_frames.size())
140         frame_sp = m_inline_frames[idx];
141     return frame_sp;
142 }
143 
144 
145 StackFrameSP
146 StackFrameList::GetFrameAtIndex (uint32_t idx)
147 {
148     StackFrameSP frame_sp;
149     {
150         Mutex::Locker locker (m_mutex);
151 
152         if (m_show_inlined_frames)
153         {
154             frame_sp = GetInlineFrameAtIndex (idx);
155         }
156         else
157         {
158             frame_sp = GetActualFrameAtIndex (idx);
159         }
160 
161         if (frame_sp.get())
162         return frame_sp;
163 
164     // Special case the first frame (idx == 0) so that we don't need to
165     // know how many stack frames there are to get it. If we need any other
166     // frames, then we do need to know if "idx" is a valid index.
167     if (idx == 0)
168     {
169         // If this is the first frame, we want to share the thread register
170         // context with the stack frame at index zero.
171         m_thread.GetRegisterContext();
172         assert (m_thread.m_reg_context_sp.get());
173         frame_sp.reset (new StackFrame (0,
174                                         0,
175                                         m_thread,
176                                         m_thread.m_reg_context_sp,
177                                         m_thread.m_reg_context_sp->GetSP(),
178                                         0,
179                                         m_thread.m_reg_context_sp->GetPC(),
180                                         NULL));
181     }
182     else if (idx < GetNumFrames())
183     {
184         if (m_show_inlined_frames)
185         {
186             if (m_inlined_frame_info[idx].inline_height == 0)
187             {
188                 // Same as the concrete stack frame if block is NULL
189                 assert (m_inlined_frame_info[idx].concrete_frame_index < m_actual_frames.size());
190                 frame_sp = GetActualFrameAtIndex (m_inlined_frame_info[idx].concrete_frame_index);
191             }
192             else
193             {
194                 // We have blocks that were above an inlined function. Inlined
195                 // functions are represented as blocks with non-NULL inline
196                 // function info. Here we must reconstruct a frame by looking
197                 // at the block
198                 StackFrameSP previous_frame_sp (m_thread.GetStackFrameAtIndex (idx-1));
199 
200                 SymbolContext inline_sc;
201 
202                 Block *inlined_parent_block = m_inlined_frame_info[idx].block->GetInlinedParent();
203 
204                 if (inlined_parent_block)
205                     inlined_parent_block->CalculateSymbolContext (&inline_sc);
206                 else
207                 {
208                     Block *parent_block = m_inlined_frame_info[idx].block->GetParent();
209                     parent_block->CalculateSymbolContext(&inline_sc);
210                 }
211 
212                 Address previous_frame_lookup_addr (previous_frame_sp->GetFrameCodeAddress());
213                 if (previous_frame_sp->IsConcrete () && previous_frame_sp->GetFrameIndex() > 0)
214                     previous_frame_lookup_addr.Slide (-1);
215 
216                 AddressRange range;
217                 m_inlined_frame_info[idx].block->GetRangeContainingAddress (previous_frame_lookup_addr, range);
218 
219                 const InlineFunctionInfo* inline_info = m_inlined_frame_info[idx].block->InlinedFunctionInfo();
220                 assert (inline_info);
221                 inline_sc.line_entry.range.GetBaseAddress() = previous_frame_sp->GetFrameCodeAddress();
222                 inline_sc.line_entry.file = inline_info->GetCallSite().GetFile();
223                 inline_sc.line_entry.line = inline_info->GetCallSite().GetLine();
224                 inline_sc.line_entry.column = inline_info->GetCallSite().GetColumn();
225 
226                 StackFrameSP concrete_frame_sp (GetActualFrameAtIndex (m_inlined_frame_info[idx].concrete_frame_index));
227                 assert (previous_frame_sp.get());
228 
229                 frame_sp.reset (new StackFrame (idx,
230                                                 m_inlined_frame_info[idx].concrete_frame_index,
231                                                 m_thread,
232                                                 concrete_frame_sp->GetRegisterContextSP (),
233                                                 concrete_frame_sp->GetStackID().GetCallFrameAddress(),  // CFA
234                                                 m_inlined_frame_info[idx].inline_height,                // Inline height
235                                                 range.GetBaseAddress(),
236                                                 &inline_sc));                                           // The symbol context for this inline frame
237 
238             }
239         }
240         else
241         {
242             Unwind *unwinder = m_thread.GetUnwinder ();
243             if (unwinder)
244             {
245                 addr_t pc, cfa;
246                 if (unwinder->GetFrameInfoAtIndex(idx, cfa, pc))
247                     frame_sp.reset (new StackFrame (idx, idx, m_thread, cfa, 0, pc, NULL));
248             }
249         }
250     }
251     if (m_show_inlined_frames)
252         SetInlineFrameAtIndex(idx, frame_sp);
253     else
254         SetActualFrameAtIndex(idx, frame_sp);
255     return frame_sp;
256 
257     }
258     return frame_sp;
259 }
260 
261 bool
262 StackFrameList::SetActualFrameAtIndex (uint32_t idx, StackFrameSP &frame_sp)
263 {
264     if (idx >= m_actual_frames.size())
265         m_actual_frames.resize(idx + 1);
266     // Make sure allocation succeeded by checking bounds again
267     if (idx < m_actual_frames.size())
268     {
269         m_actual_frames[idx] = frame_sp;
270         return true;
271     }
272     return false;   // resize failed, out of memory?
273 }
274 
275 bool
276 StackFrameList::SetInlineFrameAtIndex (uint32_t idx, StackFrameSP &frame_sp)
277 {
278     if (idx >= m_inline_frames.size())
279         m_inline_frames.resize(idx + 1);
280     // Make sure allocation succeeded by checking bounds again
281     if (idx < m_inline_frames.size())
282     {
283         m_inline_frames[idx] = frame_sp;
284         return true;
285     }
286     return false;   // resize failed, out of memory?
287 }
288 
289 uint32_t
290 StackFrameList::GetCurrentFrameIndex () const
291 {
292     Mutex::Locker locker (m_mutex);
293     return m_current_frame_idx;
294 }
295 
296 
297 uint32_t
298 StackFrameList::SetCurrentFrame (lldb_private::StackFrame *frame)
299 {
300     Mutex::Locker locker (m_mutex);
301     const_iterator pos;
302     const_iterator begin = m_show_inlined_frames ? m_inline_frames.begin() : m_actual_frames.begin();
303     const_iterator end   = m_show_inlined_frames ? m_inline_frames.end()   : m_actual_frames.end();
304     for (pos = begin; pos != end; ++pos)
305     {
306         if (pos->get() == frame)
307         {
308             m_current_frame_idx = std::distance (begin, pos);
309             return m_current_frame_idx;
310         }
311     }
312     m_current_frame_idx = 0;
313     return m_current_frame_idx;
314 }
315 
316 // Mark a stack frame as the current frame using the frame index
317 void
318 StackFrameList::SetCurrentFrameByIndex (uint32_t idx)
319 {
320     Mutex::Locker locker (m_mutex);
321     m_current_frame_idx = idx;
322 }
323 
324 // The thread has been run, reset the number stack frames to zero so we can
325 // determine how many frames we have lazily.
326 void
327 StackFrameList::Clear ()
328 {
329     Mutex::Locker locker (m_mutex);
330     m_actual_frames.clear();
331     m_inline_frames.clear();
332     m_inlined_frame_info.clear();
333 }
334 
335 void
336 StackFrameList::InvalidateFrames (uint32_t start_idx)
337 {
338     Mutex::Locker locker (m_mutex);
339     if (m_show_inlined_frames)
340     {
341         Clear();
342     }
343     else
344     {
345         const size_t num_frames = m_actual_frames.size();
346         while (start_idx < num_frames)
347         {
348             m_actual_frames[start_idx].reset();
349             ++start_idx;
350         }
351     }
352 }
353