blob: 249100ab2ff7017b534bcfa6720a18eb70a47b18 [file] [log] [blame]
Chris Lattner24943d22010-06-08 16:52:24 +00001//===-- 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
Greg Clayton782b9cc2010-08-25 00:35:26 +000010#include "lldb/Target/StackFrameList.h"
11
Chris Lattner24943d22010-06-08 16:52:24 +000012// C Includes
13// C++ Includes
14// Other libraries and framework includes
15// Project includes
Greg Clayton1d66ef52010-08-27 18:24:16 +000016#include "lldb/Core/StreamFile.h"
Greg Clayton782b9cc2010-08-25 00:35:26 +000017#include "lldb/Symbol/Block.h"
18#include "lldb/Symbol/Function.h"
19#include "lldb/Target/RegisterContext.h"
Chris Lattner24943d22010-06-08 16:52:24 +000020#include "lldb/Target/StackFrame.h"
Greg Clayton782b9cc2010-08-25 00:35:26 +000021#include "lldb/Target/Thread.h"
22#include "lldb/Target/Unwind.h"
Chris Lattner24943d22010-06-08 16:52:24 +000023
Greg Clayton1d66ef52010-08-27 18:24:16 +000024//#define DEBUG_STACK_FRAMES 1
25
Chris Lattner24943d22010-06-08 16:52:24 +000026using namespace lldb;
27using namespace lldb_private;
28
29//----------------------------------------------------------------------
30// StackFrameList constructor
31//----------------------------------------------------------------------
Greg Claytonf40e3082010-08-26 02:28:22 +000032StackFrameList::StackFrameList(Thread &thread, StackFrameList *prev_frames, bool show_inline_frames) :
Greg Clayton782b9cc2010-08-25 00:35:26 +000033 m_thread (thread),
Greg Claytonf40e3082010-08-26 02:28:22 +000034 m_prev_frames_ap (prev_frames),
Greg Clayton782b9cc2010-08-25 00:35:26 +000035 m_show_inlined_frames (show_inline_frames),
Chris Lattner24943d22010-06-08 16:52:24 +000036 m_mutex (Mutex::eMutexTypeRecursive),
Greg Clayton1d66ef52010-08-27 18:24:16 +000037 m_frames (),
Jim Inghamc8332952010-08-26 21:32:51 +000038 m_selected_frame_idx (0)
Chris Lattner24943d22010-06-08 16:52:24 +000039{
40}
41
42//----------------------------------------------------------------------
43// Destructor
44//----------------------------------------------------------------------
45StackFrameList::~StackFrameList()
46{
47}
48
49
50uint32_t
Greg Clayton782b9cc2010-08-25 00:35:26 +000051StackFrameList::GetNumFrames()
Chris Lattner24943d22010-06-08 16:52:24 +000052{
53 Mutex::Locker locker (m_mutex);
Greg Clayton782b9cc2010-08-25 00:35:26 +000054
Greg Clayton1d66ef52010-08-27 18:24:16 +000055 if (m_frames.size() <= 1)
Greg Clayton782b9cc2010-08-25 00:35:26 +000056 {
Greg Clayton1d66ef52010-08-27 18:24:16 +000057 if (m_show_inlined_frames)
Greg Clayton782b9cc2010-08-25 00:35:26 +000058 {
Greg Clayton1d66ef52010-08-27 18:24:16 +000059#if defined (DEBUG_STACK_FRAMES)
60 StreamFile s(stdout);
61#endif
Greg Clayton782b9cc2010-08-25 00:35:26 +000062 Unwind *unwinder = m_thread.GetUnwinder ();
Greg Clayton1d66ef52010-08-27 18:24:16 +000063 addr_t pc, cfa;
64
Greg Clayton782b9cc2010-08-25 00:35:26 +000065 // If we are going to show inlined stack frames as actual frames,
66 // we need to calculate all concrete frames first, then iterate
67 // through all of them and count up how many inlined functions are
Greg Clayton1d66ef52010-08-27 18:24:16 +000068 // in each frame.
69 const uint32_t unwind_frame_count = unwinder->GetFrameCount();
Greg Clayton782b9cc2010-08-25 00:35:26 +000070
Greg Clayton1d66ef52010-08-27 18:24:16 +000071 StackFrameSP unwind_frame_sp;
72 for (uint32_t idx=0; idx<unwind_frame_count; ++idx)
Greg Clayton782b9cc2010-08-25 00:35:26 +000073 {
74 if (idx == 0)
75 {
Greg Clayton1d66ef52010-08-27 18:24:16 +000076 // We might have already created frame zero, only create it
77 // if we need to
78 if (m_frames.empty())
79 {
80 m_thread.GetRegisterContext();
81 unwind_frame_sp.reset (new StackFrame (m_frames.size(),
82 idx,
83 m_thread,
84 m_thread.m_reg_context_sp,
85 m_thread.m_reg_context_sp->GetSP(),
86 m_thread.m_reg_context_sp->GetPC(),
87 NULL));
88 m_frames.push_back (unwind_frame_sp);
89 }
90 else
91 {
92 unwind_frame_sp = m_frames.front();
93 }
Greg Clayton782b9cc2010-08-25 00:35:26 +000094 }
95 else
96 {
97 const bool success = unwinder->GetFrameInfoAtIndex(idx, cfa, pc);
98 assert (success);
Greg Clayton1d66ef52010-08-27 18:24:16 +000099 unwind_frame_sp.reset (new StackFrame (m_frames.size(), idx, m_thread, cfa, pc, NULL));
100 m_frames.push_back (unwind_frame_sp);
Greg Clayton782b9cc2010-08-25 00:35:26 +0000101 }
Greg Clayton782b9cc2010-08-25 00:35:26 +0000102
Greg Clayton1d66ef52010-08-27 18:24:16 +0000103 Block *block = unwind_frame_sp->GetSymbolContext (eSymbolContextBlock).block;
104
Greg Clayton782b9cc2010-08-25 00:35:26 +0000105 if (block)
106 {
Greg Clayton1d66ef52010-08-27 18:24:16 +0000107 for (block = block->GetContainingInlinedBlock(); block != NULL; block = block->GetInlinedParent ())
Greg Clayton782b9cc2010-08-25 00:35:26 +0000108 {
Greg Clayton1d66ef52010-08-27 18:24:16 +0000109 SymbolContext inline_sc;
110 Block *parent_block = block->GetInlinedParent();
Greg Claytonf40e3082010-08-26 02:28:22 +0000111
Greg Clayton1d66ef52010-08-27 18:24:16 +0000112 const bool is_inlined_frame = parent_block != NULL;
113
114 if (parent_block == NULL)
115 parent_block = block->GetParent();
116
117 parent_block->CalculateSymbolContext (&inline_sc);
118
119 Address previous_frame_lookup_addr (m_frames.back()->GetFrameCodeAddress());
120 if (unwind_frame_sp->GetFrameIndex() > 0 && m_frames.back().get() == unwind_frame_sp.get())
121 previous_frame_lookup_addr.Slide (-1);
122
123 AddressRange range;
124 block->GetRangeContainingAddress (previous_frame_lookup_addr, range);
125
126 const InlineFunctionInfo* inline_info = block->InlinedFunctionInfo();
127 assert (inline_info);
128 inline_sc.line_entry.range.GetBaseAddress() = m_frames.back()->GetFrameCodeAddress();
129 inline_sc.line_entry.file = inline_info->GetCallSite().GetFile();
130 inline_sc.line_entry.line = inline_info->GetCallSite().GetLine();
131 inline_sc.line_entry.column = inline_info->GetCallSite().GetColumn();
132
133 StackFrameSP frame_sp(new StackFrame (m_frames.size(),
134 idx,
135 m_thread,
136 unwind_frame_sp->GetRegisterContextSP (),
137 unwind_frame_sp->GetStackID().GetCallFrameAddress(), // CFA
138 range.GetBaseAddress(),
139 &inline_sc)); // The symbol context for this inline frame
140
141 if (is_inlined_frame)
142 frame_sp->SetInlineBlockID (block->GetID());
143
144 m_frames.push_back (frame_sp);
Greg Clayton782b9cc2010-08-25 00:35:26 +0000145 }
146 }
147 }
Greg Clayton1d66ef52010-08-27 18:24:16 +0000148 StackFrameList *prev_frames = m_prev_frames_ap.get();
149 if (prev_frames)
150 {
151 StackFrameList *curr_frames = this;
152
153#if defined (DEBUG_STACK_FRAMES)
154 s.PutCString("prev_frames:\n");
155 prev_frames->Dump (&s);
156 s.PutCString("curr_frames:\n");
157 curr_frames->Dump (&s);
158 s.EOL();
159#endif
160 size_t curr_frame_num, prev_frame_num;
161
162 for (curr_frame_num = curr_frames->m_frames.size(), prev_frame_num = prev_frames->m_frames.size();
163 curr_frame_num > 0 && prev_frame_num > 0;
164 --curr_frame_num, --prev_frame_num)
165 {
166 const size_t curr_frame_idx = curr_frame_num-1;
167 const size_t prev_frame_idx = prev_frame_num-1;
168 StackFrameSP curr_frame_sp (curr_frames->m_frames[curr_frame_idx]);
169 StackFrameSP prev_frame_sp (prev_frames->m_frames[prev_frame_idx]);
170
171#if defined (DEBUG_STACK_FRAMES)
172 s.Printf("\nCurrent frame #%u ", curr_frame_idx);
173 if (curr_frame_sp)
174 curr_frame_sp->Dump (&s, true);
175 else
176 s.PutCString("NULL");
177 s.Printf("\nPrevious frame #%u ", prev_frame_idx);
178 if (prev_frame_sp)
179 prev_frame_sp->Dump (&s, true);
180 else
181 s.PutCString("NULL");
182 s.EOL();
183#endif
184
185 StackFrame *curr_frame = curr_frame_sp.get();
186 StackFrame *prev_frame = prev_frame_sp.get();
187
188 if (curr_frame == NULL || prev_frame == NULL)
189 break;
190
191 // Do a quick sanity check to see if the CFA values are the same.
192 if (curr_frame->m_id.GetCallFrameAddress() != prev_frame->m_id.GetCallFrameAddress())
193 break;
194
195 // Now check our function or symbol
196 SymbolContext curr_sc (curr_frame->GetSymbolContext (eSymbolContextFunction | eSymbolContextBlock | eSymbolContextSymbol));
197 SymbolContext prev_sc (prev_frame->GetSymbolContext (eSymbolContextFunction | eSymbolContextBlock | eSymbolContextSymbol));
198 if (curr_sc.function && curr_sc.function == prev_sc.function)
199 {
200 // Same function
201 if (curr_sc.block != prev_sc.block)
202 {
203 // Same function different block
204 if (m_show_inlined_frames)
205 break;
206 else
207 prev_frame->SetSymbolContext (curr_frame->m_sc);
208 }
209 }
210 else if (curr_sc.symbol && curr_sc.symbol == prev_sc.symbol)
211 {
212 // Same symbol
213 }
214 else if (curr_frame->GetFrameCodeAddress() != prev_frame->GetFrameCodeAddress())
215 {
216 // No symbols for this frame and the PC was different
217 break;
218 }
219
220 if (curr_frame->GetFrameCodeAddress() != prev_frame->GetFrameCodeAddress())
221 {
222#if defined (DEBUG_STACK_FRAMES)
223 s.Printf("\nUpdating frame code address and symbol context in previous frame #%u to current frame #%u", prev_frame_idx, curr_frame_idx);
224#endif
225 // We have a different code frame address, we might need to copy
226 // some stuff in prev_frame, yet update the code address...
227 prev_frame->SetFrameCodeAddress (curr_frame->GetFrameCodeAddress());
228 prev_frame->SetSymbolContext (curr_frame->m_sc);
229 }
230
231 curr_frames->m_frames[curr_frame_idx] = prev_frames->m_frames[prev_frame_idx];
232
233#if defined (DEBUG_STACK_FRAMES)
234 s.Printf("\nCopying previous frame #%u to current frame #%u", prev_frame_idx, curr_frame_idx);
235#endif
236 }
237 // We are done with the old stack frame list, we can release it now
238 m_prev_frames_ap.release();
239 prev_frames = NULL;
240 }
Greg Clayton782b9cc2010-08-25 00:35:26 +0000241 }
Greg Clayton1d66ef52010-08-27 18:24:16 +0000242 else
243 {
244 m_frames.resize(m_thread.GetUnwinder()->GetFrameCount());
245 }
Greg Clayton782b9cc2010-08-25 00:35:26 +0000246 }
Greg Clayton1d66ef52010-08-27 18:24:16 +0000247 return m_frames.size();
248}
249
250void
251StackFrameList::Dump (Stream *s)
252{
253 if (s == NULL)
254 return;
255 Mutex::Locker locker (m_mutex);
256
257 const_iterator pos, begin = m_frames.begin(), end = m_frames.end();
258 for (pos = begin; pos != end; ++pos)
Greg Clayton782b9cc2010-08-25 00:35:26 +0000259 {
Greg Clayton1d66ef52010-08-27 18:24:16 +0000260 StackFrame *frame = (*pos).get();
261 s->Printf("%p: ", frame);
262 if (frame)
263 frame->Dump(s, true);
264 else
265 s->Printf("frame #%u", std::distance (begin, pos));
266 s->EOL();
Greg Clayton782b9cc2010-08-25 00:35:26 +0000267 }
Greg Clayton1d66ef52010-08-27 18:24:16 +0000268 s->EOL();
Chris Lattner24943d22010-06-08 16:52:24 +0000269}
270
Chris Lattner24943d22010-06-08 16:52:24 +0000271StackFrameSP
Greg Clayton782b9cc2010-08-25 00:35:26 +0000272StackFrameList::GetFrameAtIndex (uint32_t idx)
Chris Lattner24943d22010-06-08 16:52:24 +0000273{
274 StackFrameSP frame_sp;
Greg Clayton1d66ef52010-08-27 18:24:16 +0000275 Mutex::Locker locker (m_mutex);
276 if (idx < m_frames.size())
277 frame_sp = m_frames[idx];
278
279 if (frame_sp)
280 return frame_sp;
281
282 // Special case the first frame (idx == 0) so that we don't need to
283 // know how many stack frames there are to get it. If we need any other
284 // frames, then we do need to know if "idx" is a valid index.
285 if (idx == 0)
Chris Lattner24943d22010-06-08 16:52:24 +0000286 {
Greg Clayton1d66ef52010-08-27 18:24:16 +0000287 // If this is the first frame, we want to share the thread register
288 // context with the stack frame at index zero.
289 m_thread.GetRegisterContext();
290 assert (m_thread.m_reg_context_sp.get());
291 frame_sp.reset (new StackFrame (0,
292 0,
293 m_thread,
294 m_thread.m_reg_context_sp,
295 m_thread.m_reg_context_sp->GetSP(),
296 m_thread.m_reg_context_sp->GetPC(),
297 NULL));
Greg Claytonf40e3082010-08-26 02:28:22 +0000298
Greg Clayton782b9cc2010-08-25 00:35:26 +0000299 if (m_show_inlined_frames)
300 {
Greg Clayton1d66ef52010-08-27 18:24:16 +0000301 Block *block = frame_sp->GetSymbolContext (eSymbolContextBlock).block;
302
303 if (block)
304 {
305 Block *inline_block = block->GetContainingInlinedBlock();
306 if (inline_block)
307 frame_sp->SetInlineBlockID (inline_block->GetID());
308 }
309 }
310 SetFrameAtIndex(idx, frame_sp);
311 }
312 else if (idx < GetNumFrames())
313 {
314 if (m_show_inlined_frames)
315 {
316 // When inline frames are enabled we cache up all frames in GetNumFrames()
317 frame_sp = m_frames[idx];
Greg Clayton782b9cc2010-08-25 00:35:26 +0000318 }
319 else
320 {
Greg Clayton1d66ef52010-08-27 18:24:16 +0000321 Unwind *unwinder = m_thread.GetUnwinder ();
322 if (unwinder)
323 {
324 addr_t pc, cfa;
325 if (unwinder->GetFrameInfoAtIndex(idx, cfa, pc))
326 {
327 frame_sp.reset (new StackFrame (idx, idx, m_thread, cfa, pc, NULL));
328 SetFrameAtIndex(idx, frame_sp);
329 }
330 }
Greg Clayton782b9cc2010-08-25 00:35:26 +0000331 }
Greg Claytonf40e3082010-08-26 02:28:22 +0000332
Chris Lattner24943d22010-06-08 16:52:24 +0000333 }
334 return frame_sp;
335}
336
Greg Clayton782b9cc2010-08-25 00:35:26 +0000337
338bool
Greg Clayton1d66ef52010-08-27 18:24:16 +0000339StackFrameList::SetFrameAtIndex (uint32_t idx, StackFrameSP &frame_sp)
Greg Clayton782b9cc2010-08-25 00:35:26 +0000340{
Greg Clayton1d66ef52010-08-27 18:24:16 +0000341 if (idx >= m_frames.size())
342 m_frames.resize(idx + 1);
Greg Clayton782b9cc2010-08-25 00:35:26 +0000343 // Make sure allocation succeeded by checking bounds again
Greg Clayton1d66ef52010-08-27 18:24:16 +0000344 if (idx < m_frames.size())
Greg Clayton782b9cc2010-08-25 00:35:26 +0000345 {
Greg Clayton1d66ef52010-08-27 18:24:16 +0000346 m_frames[idx] = frame_sp;
Chris Lattner24943d22010-06-08 16:52:24 +0000347 return true;
348 }
349 return false; // resize failed, out of memory?
350}
351
352uint32_t
Jim Inghamc8332952010-08-26 21:32:51 +0000353StackFrameList::GetSelectedFrameIndex () const
Chris Lattner24943d22010-06-08 16:52:24 +0000354{
355 Mutex::Locker locker (m_mutex);
Jim Inghamc8332952010-08-26 21:32:51 +0000356 return m_selected_frame_idx;
Chris Lattner24943d22010-06-08 16:52:24 +0000357}
358
359
360uint32_t
Jim Inghamc8332952010-08-26 21:32:51 +0000361StackFrameList::SetSelectedFrame (lldb_private::StackFrame *frame)
Chris Lattner24943d22010-06-08 16:52:24 +0000362{
363 Mutex::Locker locker (m_mutex);
Greg Clayton782b9cc2010-08-25 00:35:26 +0000364 const_iterator pos;
Greg Clayton1d66ef52010-08-27 18:24:16 +0000365 const_iterator begin = m_frames.begin();
366 const_iterator end = m_frames.end();
Chris Lattner24943d22010-06-08 16:52:24 +0000367 for (pos = begin; pos != end; ++pos)
368 {
369 if (pos->get() == frame)
370 {
Jim Inghamc8332952010-08-26 21:32:51 +0000371 m_selected_frame_idx = std::distance (begin, pos);
372 return m_selected_frame_idx;
Chris Lattner24943d22010-06-08 16:52:24 +0000373 }
374 }
Jim Inghamc8332952010-08-26 21:32:51 +0000375 m_selected_frame_idx = 0;
376 return m_selected_frame_idx;
Chris Lattner24943d22010-06-08 16:52:24 +0000377}
378
379// Mark a stack frame as the current frame using the frame index
380void
Jim Inghamc8332952010-08-26 21:32:51 +0000381StackFrameList::SetSelectedFrameByIndex (uint32_t idx)
Chris Lattner24943d22010-06-08 16:52:24 +0000382{
383 Mutex::Locker locker (m_mutex);
Jim Inghamc8332952010-08-26 21:32:51 +0000384 m_selected_frame_idx = idx;
Chris Lattner24943d22010-06-08 16:52:24 +0000385}
386
387// The thread has been run, reset the number stack frames to zero so we can
388// determine how many frames we have lazily.
389void
390StackFrameList::Clear ()
391{
392 Mutex::Locker locker (m_mutex);
Greg Clayton1d66ef52010-08-27 18:24:16 +0000393 m_frames.clear();
Chris Lattner24943d22010-06-08 16:52:24 +0000394}
395
396void
397StackFrameList::InvalidateFrames (uint32_t start_idx)
398{
399 Mutex::Locker locker (m_mutex);
Greg Clayton782b9cc2010-08-25 00:35:26 +0000400 if (m_show_inlined_frames)
Chris Lattner24943d22010-06-08 16:52:24 +0000401 {
Greg Clayton782b9cc2010-08-25 00:35:26 +0000402 Clear();
403 }
404 else
405 {
Greg Clayton1d66ef52010-08-27 18:24:16 +0000406 const size_t num_frames = m_frames.size();
Greg Clayton782b9cc2010-08-25 00:35:26 +0000407 while (start_idx < num_frames)
408 {
Greg Clayton1d66ef52010-08-27 18:24:16 +0000409 m_frames[start_idx].reset();
Greg Clayton782b9cc2010-08-25 00:35:26 +0000410 ++start_idx;
411 }
Chris Lattner24943d22010-06-08 16:52:24 +0000412 }
413}