blob: be4e6e46da2da582e3a0d6f018321def75833779 [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)
Greg Clayton870a1cd2010-08-27 21:47:54 +0000154 s.PutCString("\nprev_frames:\n");
Greg Clayton1d66ef52010-08-27 18:24:16 +0000155 prev_frames->Dump (&s);
Greg Clayton870a1cd2010-08-27 21:47:54 +0000156 s.PutCString("\ncurr_frames:\n");
Greg Clayton1d66ef52010-08-27 18:24:16 +0000157 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;
Greg Clayton1d66ef52010-08-27 18:24:16 +0000206 }
207 }
208 else if (curr_sc.symbol && curr_sc.symbol == prev_sc.symbol)
209 {
210 // Same symbol
211 }
212 else if (curr_frame->GetFrameCodeAddress() != prev_frame->GetFrameCodeAddress())
213 {
214 // No symbols for this frame and the PC was different
215 break;
216 }
217
Greg Clayton870a1cd2010-08-27 21:47:54 +0000218 curr_frame->UpdateCurrentFrameFromPreviousFrame (*prev_frame);
Greg Clayton1d66ef52010-08-27 18:24:16 +0000219
220#if defined (DEBUG_STACK_FRAMES)
Greg Clayton870a1cd2010-08-27 21:47:54 +0000221 s.Printf("\n Copying previous frame to current frame");
Greg Clayton1d66ef52010-08-27 18:24:16 +0000222#endif
223 }
224 // We are done with the old stack frame list, we can release it now
225 m_prev_frames_ap.release();
226 prev_frames = NULL;
227 }
Greg Clayton870a1cd2010-08-27 21:47:54 +0000228
229#if defined (DEBUG_STACK_FRAMES)
230 s.PutCString("\n\nNew frames:\n");
231 Dump (&s);
232 s.EOL();
233#endif
Greg Clayton782b9cc2010-08-25 00:35:26 +0000234 }
Greg Clayton1d66ef52010-08-27 18:24:16 +0000235 else
236 {
237 m_frames.resize(m_thread.GetUnwinder()->GetFrameCount());
238 }
Greg Clayton782b9cc2010-08-25 00:35:26 +0000239 }
Greg Clayton1d66ef52010-08-27 18:24:16 +0000240 return m_frames.size();
241}
242
243void
244StackFrameList::Dump (Stream *s)
245{
246 if (s == NULL)
247 return;
248 Mutex::Locker locker (m_mutex);
249
250 const_iterator pos, begin = m_frames.begin(), end = m_frames.end();
251 for (pos = begin; pos != end; ++pos)
Greg Clayton782b9cc2010-08-25 00:35:26 +0000252 {
Greg Clayton1d66ef52010-08-27 18:24:16 +0000253 StackFrame *frame = (*pos).get();
254 s->Printf("%p: ", frame);
255 if (frame)
256 frame->Dump(s, true);
257 else
258 s->Printf("frame #%u", std::distance (begin, pos));
259 s->EOL();
Greg Clayton782b9cc2010-08-25 00:35:26 +0000260 }
Greg Clayton1d66ef52010-08-27 18:24:16 +0000261 s->EOL();
Chris Lattner24943d22010-06-08 16:52:24 +0000262}
263
Chris Lattner24943d22010-06-08 16:52:24 +0000264StackFrameSP
Greg Clayton782b9cc2010-08-25 00:35:26 +0000265StackFrameList::GetFrameAtIndex (uint32_t idx)
Chris Lattner24943d22010-06-08 16:52:24 +0000266{
267 StackFrameSP frame_sp;
Greg Clayton1d66ef52010-08-27 18:24:16 +0000268 Mutex::Locker locker (m_mutex);
269 if (idx < m_frames.size())
270 frame_sp = m_frames[idx];
271
272 if (frame_sp)
273 return frame_sp;
274
275 // Special case the first frame (idx == 0) so that we don't need to
276 // know how many stack frames there are to get it. If we need any other
277 // frames, then we do need to know if "idx" is a valid index.
278 if (idx == 0)
Chris Lattner24943d22010-06-08 16:52:24 +0000279 {
Greg Clayton1d66ef52010-08-27 18:24:16 +0000280 // If this is the first frame, we want to share the thread register
281 // context with the stack frame at index zero.
282 m_thread.GetRegisterContext();
283 assert (m_thread.m_reg_context_sp.get());
284 frame_sp.reset (new StackFrame (0,
285 0,
286 m_thread,
287 m_thread.m_reg_context_sp,
288 m_thread.m_reg_context_sp->GetSP(),
289 m_thread.m_reg_context_sp->GetPC(),
290 NULL));
Greg Claytonf40e3082010-08-26 02:28:22 +0000291
Greg Clayton782b9cc2010-08-25 00:35:26 +0000292 if (m_show_inlined_frames)
293 {
Greg Clayton1d66ef52010-08-27 18:24:16 +0000294 Block *block = frame_sp->GetSymbolContext (eSymbolContextBlock).block;
295
296 if (block)
297 {
298 Block *inline_block = block->GetContainingInlinedBlock();
299 if (inline_block)
300 frame_sp->SetInlineBlockID (inline_block->GetID());
301 }
302 }
303 SetFrameAtIndex(idx, frame_sp);
304 }
305 else if (idx < GetNumFrames())
306 {
307 if (m_show_inlined_frames)
308 {
309 // When inline frames are enabled we cache up all frames in GetNumFrames()
310 frame_sp = m_frames[idx];
Greg Clayton782b9cc2010-08-25 00:35:26 +0000311 }
312 else
313 {
Greg Clayton1d66ef52010-08-27 18:24:16 +0000314 Unwind *unwinder = m_thread.GetUnwinder ();
315 if (unwinder)
316 {
317 addr_t pc, cfa;
318 if (unwinder->GetFrameInfoAtIndex(idx, cfa, pc))
319 {
320 frame_sp.reset (new StackFrame (idx, idx, m_thread, cfa, pc, NULL));
321 SetFrameAtIndex(idx, frame_sp);
322 }
323 }
Greg Clayton782b9cc2010-08-25 00:35:26 +0000324 }
Greg Claytonf40e3082010-08-26 02:28:22 +0000325
Chris Lattner24943d22010-06-08 16:52:24 +0000326 }
327 return frame_sp;
328}
329
Greg Clayton782b9cc2010-08-25 00:35:26 +0000330
331bool
Greg Clayton1d66ef52010-08-27 18:24:16 +0000332StackFrameList::SetFrameAtIndex (uint32_t idx, StackFrameSP &frame_sp)
Greg Clayton782b9cc2010-08-25 00:35:26 +0000333{
Greg Clayton1d66ef52010-08-27 18:24:16 +0000334 if (idx >= m_frames.size())
335 m_frames.resize(idx + 1);
Greg Clayton782b9cc2010-08-25 00:35:26 +0000336 // Make sure allocation succeeded by checking bounds again
Greg Clayton1d66ef52010-08-27 18:24:16 +0000337 if (idx < m_frames.size())
Greg Clayton782b9cc2010-08-25 00:35:26 +0000338 {
Greg Clayton1d66ef52010-08-27 18:24:16 +0000339 m_frames[idx] = frame_sp;
Chris Lattner24943d22010-06-08 16:52:24 +0000340 return true;
341 }
342 return false; // resize failed, out of memory?
343}
344
345uint32_t
Jim Inghamc8332952010-08-26 21:32:51 +0000346StackFrameList::GetSelectedFrameIndex () const
Chris Lattner24943d22010-06-08 16:52:24 +0000347{
348 Mutex::Locker locker (m_mutex);
Jim Inghamc8332952010-08-26 21:32:51 +0000349 return m_selected_frame_idx;
Chris Lattner24943d22010-06-08 16:52:24 +0000350}
351
352
353uint32_t
Jim Inghamc8332952010-08-26 21:32:51 +0000354StackFrameList::SetSelectedFrame (lldb_private::StackFrame *frame)
Chris Lattner24943d22010-06-08 16:52:24 +0000355{
356 Mutex::Locker locker (m_mutex);
Greg Clayton782b9cc2010-08-25 00:35:26 +0000357 const_iterator pos;
Greg Clayton1d66ef52010-08-27 18:24:16 +0000358 const_iterator begin = m_frames.begin();
359 const_iterator end = m_frames.end();
Chris Lattner24943d22010-06-08 16:52:24 +0000360 for (pos = begin; pos != end; ++pos)
361 {
362 if (pos->get() == frame)
363 {
Jim Inghamc8332952010-08-26 21:32:51 +0000364 m_selected_frame_idx = std::distance (begin, pos);
365 return m_selected_frame_idx;
Chris Lattner24943d22010-06-08 16:52:24 +0000366 }
367 }
Jim Inghamc8332952010-08-26 21:32:51 +0000368 m_selected_frame_idx = 0;
369 return m_selected_frame_idx;
Chris Lattner24943d22010-06-08 16:52:24 +0000370}
371
372// Mark a stack frame as the current frame using the frame index
373void
Jim Inghamc8332952010-08-26 21:32:51 +0000374StackFrameList::SetSelectedFrameByIndex (uint32_t idx)
Chris Lattner24943d22010-06-08 16:52:24 +0000375{
376 Mutex::Locker locker (m_mutex);
Jim Inghamc8332952010-08-26 21:32:51 +0000377 m_selected_frame_idx = idx;
Chris Lattner24943d22010-06-08 16:52:24 +0000378}
379
380// The thread has been run, reset the number stack frames to zero so we can
381// determine how many frames we have lazily.
382void
383StackFrameList::Clear ()
384{
385 Mutex::Locker locker (m_mutex);
Greg Clayton1d66ef52010-08-27 18:24:16 +0000386 m_frames.clear();
Chris Lattner24943d22010-06-08 16:52:24 +0000387}
388
389void
390StackFrameList::InvalidateFrames (uint32_t start_idx)
391{
392 Mutex::Locker locker (m_mutex);
Greg Clayton782b9cc2010-08-25 00:35:26 +0000393 if (m_show_inlined_frames)
Chris Lattner24943d22010-06-08 16:52:24 +0000394 {
Greg Clayton782b9cc2010-08-25 00:35:26 +0000395 Clear();
396 }
397 else
398 {
Greg Clayton1d66ef52010-08-27 18:24:16 +0000399 const size_t num_frames = m_frames.size();
Greg Clayton782b9cc2010-08-25 00:35:26 +0000400 while (start_idx < num_frames)
401 {
Greg Clayton1d66ef52010-08-27 18:24:16 +0000402 m_frames[start_idx].reset();
Greg Clayton782b9cc2010-08-25 00:35:26 +0000403 ++start_idx;
404 }
Chris Lattner24943d22010-06-08 16:52:24 +0000405 }
406}