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