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/Core/SourceManager.h"
18 #include "lldb/Symbol/Block.h"
19 #include "lldb/Symbol/Function.h"
20 #include "lldb/Symbol/Symbol.h"
21 #include "lldb/Target/Process.h"
22 #include "lldb/Target/RegisterContext.h"
23 #include "lldb/Target/StackFrame.h"
24 #include "lldb/Target/Target.h"
25 #include "lldb/Target/Thread.h"
26 #include "lldb/Target/Unwind.h"
27 
28 //#define DEBUG_STACK_FRAMES 1
29 
30 using namespace lldb;
31 using namespace lldb_private;
32 
33 //----------------------------------------------------------------------
34 // StackFrameList constructor
35 //----------------------------------------------------------------------
36 StackFrameList::StackFrameList
37 (
38     Thread &thread,
39     const lldb::StackFrameListSP &prev_frames_sp,
40     bool show_inline_frames
41 ) :
42     m_thread (thread),
43     m_prev_frames_sp (prev_frames_sp),
44     m_mutex (Mutex::eMutexTypeRecursive),
45     m_frames (),
46     m_selected_frame_idx (0),
47     m_show_inlined_frames (show_inline_frames)
48 {
49 }
50 
51 //----------------------------------------------------------------------
52 // Destructor
53 //----------------------------------------------------------------------
54 StackFrameList::~StackFrameList()
55 {
56 }
57 
58 
59 uint32_t
60 StackFrameList::GetNumFrames (bool can_create)
61 {
62     Mutex::Locker locker (m_mutex);
63 
64     if (can_create && m_frames.size() <= 1)
65     {
66         if (m_show_inlined_frames)
67         {
68 #if defined (DEBUG_STACK_FRAMES)
69             StreamFile s(stdout, false);
70 #endif
71             Unwind *unwinder = m_thread.GetUnwinder ();
72             addr_t pc = LLDB_INVALID_ADDRESS;
73             addr_t cfa = LLDB_INVALID_ADDRESS;
74 
75             // If we are going to show inlined stack frames as actual frames,
76             // we need to calculate all concrete frames first, then iterate
77             // through all of them and count up how many inlined functions are
78             // in each frame.
79             const uint32_t unwind_frame_count = unwinder->GetFrameCount();
80 
81             StackFrameSP unwind_frame_sp;
82             for (uint32_t idx=0; idx<unwind_frame_count; ++idx)
83             {
84                 if (idx == 0)
85                 {
86                     // We might have already created frame zero, only create it
87                     // if we need to
88                     if (m_frames.empty())
89                     {
90                         cfa = m_thread.m_reg_context_sp->GetSP();
91                         m_thread.GetRegisterContext();
92                         unwind_frame_sp.reset (new StackFrame (m_frames.size(),
93                                                                idx,
94                                                                m_thread,
95                                                                m_thread.m_reg_context_sp,
96                                                                cfa,
97                                                                m_thread.m_reg_context_sp->GetPC(),
98                                                                NULL));
99                         m_frames.push_back (unwind_frame_sp);
100                     }
101                     else
102                     {
103                         unwind_frame_sp = m_frames.front();
104                         cfa = unwind_frame_sp->m_id.GetCallFrameAddress();
105                     }
106                 }
107                 else
108                 {
109                     const bool success = unwinder->GetFrameInfoAtIndex(idx, cfa, pc);
110                     assert (success);
111                     unwind_frame_sp.reset (new StackFrame (m_frames.size(), idx, m_thread, cfa, pc, NULL));
112                     m_frames.push_back (unwind_frame_sp);
113                 }
114 
115                 SymbolContext unwind_sc = unwind_frame_sp->GetSymbolContext (eSymbolContextBlock | eSymbolContextFunction);
116                 Block *unwind_block = unwind_sc.block;
117                 if (unwind_block)
118                 {
119                     Address curr_frame_address (unwind_frame_sp->GetFrameCodeAddress());
120                     // Be sure to adjust the frame address to match the address
121                     // that was used to lookup the symbol context above. If we are
122                     // in the first concrete frame, then we lookup using the current
123                     // address, else we decrement the address by one to get the correct
124                     // location.
125                     if (idx > 0)
126                         curr_frame_address.Slide(-1);
127 
128                     SymbolContext next_frame_sc;
129                     Address next_frame_address;
130 
131                     while (unwind_sc.GetParentOfInlinedScope(curr_frame_address, next_frame_sc, next_frame_address))
132                     {
133                             StackFrameSP frame_sp(new StackFrame (m_frames.size(),
134                                                                   idx,
135                                                                   m_thread,
136                                                                   unwind_frame_sp->GetRegisterContextSP (),
137                                                                   cfa,
138                                                                   next_frame_address,
139                                                                   &next_frame_sc));
140 
141                             m_frames.push_back (frame_sp);
142                             unwind_sc = next_frame_sc;
143                             curr_frame_address = next_frame_address;
144 
145                     }
146                 }
147             }
148 
149             if (m_prev_frames_sp)
150             {
151                 StackFrameList *prev_frames = m_prev_frames_sp.get();
152                 StackFrameList *curr_frames = this;
153 
154 #if defined (DEBUG_STACK_FRAMES)
155                 s.PutCString("\nprev_frames:\n");
156                 prev_frames->Dump (&s);
157                 s.PutCString("\ncurr_frames:\n");
158                 curr_frames->Dump (&s);
159                 s.EOL();
160 #endif
161                 size_t curr_frame_num, prev_frame_num;
162 
163                 for (curr_frame_num = curr_frames->m_frames.size(), prev_frame_num = prev_frames->m_frames.size();
164                      curr_frame_num > 0 && prev_frame_num > 0;
165                      --curr_frame_num, --prev_frame_num)
166                 {
167                     const size_t curr_frame_idx = curr_frame_num-1;
168                     const size_t prev_frame_idx = prev_frame_num-1;
169                     StackFrameSP curr_frame_sp (curr_frames->m_frames[curr_frame_idx]);
170                     StackFrameSP prev_frame_sp (prev_frames->m_frames[prev_frame_idx]);
171 
172 #if defined (DEBUG_STACK_FRAMES)
173                     s.Printf("\n\nCurr frame #%u ", curr_frame_idx);
174                     if (curr_frame_sp)
175                         curr_frame_sp->Dump (&s, true, false);
176                     else
177                         s.PutCString("NULL");
178                     s.Printf("\nPrev frame #%u ", prev_frame_idx);
179                     if (prev_frame_sp)
180                         prev_frame_sp->Dump (&s, true, false);
181                     else
182                         s.PutCString("NULL");
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                     // Check the stack ID to make sure they are equal
192                     if (curr_frame->GetStackID() != prev_frame->GetStackID())
193                         break;
194 
195                     prev_frame->UpdatePreviousFrameFromCurrentFrame (*curr_frame);
196                     // Now copy the fixed up previous frame into the current frames
197                     // so the pointer doesn't change
198                     m_frames[curr_frame_idx] = prev_frame_sp;
199                     //curr_frame->UpdateCurrentFrameFromPreviousFrame (*prev_frame);
200 
201 #if defined (DEBUG_STACK_FRAMES)
202                     s.Printf("\n    Copying previous frame to current frame");
203 #endif
204                 }
205                 // We are done with the old stack frame list, we can release it now
206                 m_prev_frames_sp.reset();
207             }
208 
209 #if defined (DEBUG_STACK_FRAMES)
210                 s.PutCString("\n\nNew frames:\n");
211                 Dump (&s);
212                 s.EOL();
213 #endif
214         }
215         else
216         {
217             m_frames.resize(m_thread.GetUnwinder()->GetFrameCount());
218         }
219     }
220     return m_frames.size();
221 }
222 
223 void
224 StackFrameList::Dump (Stream *s)
225 {
226     if (s == NULL)
227         return;
228     Mutex::Locker locker (m_mutex);
229 
230     const_iterator pos, begin = m_frames.begin(), end = m_frames.end();
231     for (pos = begin; pos != end; ++pos)
232     {
233         StackFrame *frame = (*pos).get();
234         s->Printf("%p: ", frame);
235         if (frame)
236         {
237             frame->GetStackID().Dump (s);
238             frame->DumpUsingSettingsFormat (s);
239         }
240         else
241             s->Printf("frame #%ld", std::distance (begin, pos));
242         s->EOL();
243     }
244     s->EOL();
245 }
246 
247 StackFrameSP
248 StackFrameList::GetFrameAtIndex (uint32_t idx)
249 {
250     StackFrameSP frame_sp;
251     Mutex::Locker locker (m_mutex);
252     if (idx < m_frames.size())
253         frame_sp = m_frames[idx];
254 
255     if (frame_sp)
256         return frame_sp;
257 
258     // Special case the first frame (idx == 0) so that we don't need to
259     // know how many stack frames there are to get it. If we need any other
260     // frames, then we do need to know if "idx" is a valid index.
261     if (idx == 0)
262     {
263         // If this is the first frame, we want to share the thread register
264         // context with the stack frame at index zero.
265         m_thread.GetRegisterContext();
266         assert (m_thread.m_reg_context_sp.get());
267         frame_sp.reset (new StackFrame (0,
268                                         0,
269                                         m_thread,
270                                         m_thread.m_reg_context_sp,
271                                         m_thread.m_reg_context_sp->GetSP(),
272                                         m_thread.m_reg_context_sp->GetPC(),
273                                         NULL));
274 
275         SetFrameAtIndex(idx, frame_sp);
276     }
277     else if (idx < GetNumFrames())
278     {
279         if (m_show_inlined_frames)
280         {
281             // When inline frames are enabled we cache up all frames in GetNumFrames()
282             frame_sp = m_frames[idx];
283         }
284         else
285         {
286             Unwind *unwinder = m_thread.GetUnwinder ();
287             if (unwinder)
288             {
289                 addr_t pc, cfa;
290                 if (unwinder->GetFrameInfoAtIndex(idx, cfa, pc))
291                 {
292                     frame_sp.reset (new StackFrame (idx, idx, m_thread, cfa, pc, NULL));
293 
294                     Function *function = frame_sp->GetSymbolContext (eSymbolContextFunction).function;
295                     if (function)
296                     {
297                         // When we aren't showing inline functions we always use
298                         // the top most function block as the scope.
299                         frame_sp->SetSymbolContextScope (&function->GetBlock(false));
300                     }
301                     else
302                     {
303                         // Set the symbol scope from the symbol regardless if it is NULL or valid.
304                         frame_sp->SetSymbolContextScope (frame_sp->GetSymbolContext (eSymbolContextSymbol).symbol);
305                     }
306                     SetFrameAtIndex(idx, frame_sp);
307                 }
308             }
309         }
310     }
311     return frame_sp;
312 }
313 
314 StackFrameSP
315 StackFrameList::GetFrameWithConcreteFrameIndex (uint32_t unwind_idx)
316 {
317     // First try assuming the unwind index is the same as the frame index. The
318     // unwind index is always greater than or equal to the frame index, so it
319     // is a good place to start. If we have inlined frames we might have 5
320     // concrete frames (frame unwind indexes go from 0-4), but we might have 15
321     // frames after we make all the inlined frames. Most of the time the unwind
322     // frame index (or the concrete frame index) is the same as the frame index.
323     uint32_t frame_idx = unwind_idx;
324     StackFrameSP frame_sp (GetFrameAtIndex (frame_idx));
325     while (frame_sp)
326     {
327         if (frame_sp->GetFrameIndex() == unwind_idx)
328             break;
329         frame_sp = GetFrameAtIndex (++frame_idx);
330     }
331     return frame_sp;
332 }
333 
334 StackFrameSP
335 StackFrameList::GetFrameWithStackID (StackID &stack_id)
336 {
337     uint32_t frame_idx = 0;
338     StackFrameSP frame_sp;
339     do
340     {
341         frame_sp = GetFrameAtIndex (frame_idx);
342         if (frame_sp && frame_sp->GetStackID() == stack_id)
343             break;
344         frame_idx++;
345     }
346     while (frame_sp);
347     return frame_sp;
348 }
349 
350 bool
351 StackFrameList::SetFrameAtIndex (uint32_t idx, StackFrameSP &frame_sp)
352 {
353     if (idx >= m_frames.size())
354         m_frames.resize(idx + 1);
355     // Make sure allocation succeeded by checking bounds again
356     if (idx < m_frames.size())
357     {
358         m_frames[idx] = frame_sp;
359         return true;
360     }
361     return false;   // resize failed, out of memory?
362 }
363 
364 uint32_t
365 StackFrameList::GetSelectedFrameIndex () const
366 {
367     Mutex::Locker locker (m_mutex);
368     return m_selected_frame_idx;
369 }
370 
371 
372 uint32_t
373 StackFrameList::SetSelectedFrame (lldb_private::StackFrame *frame)
374 {
375     Mutex::Locker locker (m_mutex);
376     const_iterator pos;
377     const_iterator begin = m_frames.begin();
378     const_iterator end = m_frames.end();
379     m_selected_frame_idx = 0;
380     for (pos = begin; pos != end; ++pos)
381     {
382         if (pos->get() == frame)
383         {
384             m_selected_frame_idx = std::distance (begin, pos);
385             break;
386         }
387     }
388     SetDefaultFileAndLineToSelectedFrame();
389     return m_selected_frame_idx;
390 }
391 
392 // Mark a stack frame as the current frame using the frame index
393 void
394 StackFrameList::SetSelectedFrameByIndex (uint32_t idx)
395 {
396     Mutex::Locker locker (m_mutex);
397     m_selected_frame_idx = idx;
398     SetDefaultFileAndLineToSelectedFrame();
399 }
400 
401 void
402 StackFrameList::SetDefaultFileAndLineToSelectedFrame()
403 {
404     if (m_thread.GetID() == m_thread.GetProcess().GetThreadList().GetSelectedThread()->GetID())
405     {
406         StackFrameSP frame_sp (GetFrameAtIndex (GetSelectedFrameIndex()));
407         if (frame_sp)
408         {
409             SymbolContext sc = frame_sp->GetSymbolContext(eSymbolContextLineEntry);
410             if (sc.line_entry.file)
411                 m_thread.GetProcess().GetTarget().GetSourceManager().SetDefaultFileAndLine (sc.line_entry.file,
412                                                                                             sc.line_entry.line);
413         }
414     }
415 }
416 
417 // The thread has been run, reset the number stack frames to zero so we can
418 // determine how many frames we have lazily.
419 void
420 StackFrameList::Clear ()
421 {
422     Mutex::Locker locker (m_mutex);
423     m_frames.clear();
424 }
425 
426 void
427 StackFrameList::InvalidateFrames (uint32_t start_idx)
428 {
429     Mutex::Locker locker (m_mutex);
430     if (m_show_inlined_frames)
431     {
432         Clear();
433     }
434     else
435     {
436         const size_t num_frames = m_frames.size();
437         while (start_idx < num_frames)
438         {
439             m_frames[start_idx].reset();
440             ++start_idx;
441         }
442     }
443 }
444 
445 void
446 StackFrameList::Merge (std::auto_ptr<StackFrameList>& curr_ap, lldb::StackFrameListSP& prev_sp)
447 {
448     Mutex::Locker curr_locker (curr_ap.get() ? curr_ap->m_mutex.GetMutex() : NULL);
449     Mutex::Locker prev_locker (prev_sp.get() ? prev_sp->m_mutex.GetMutex() : NULL);
450 
451 #if defined (DEBUG_STACK_FRAMES)
452     StreamFile s(stdout, false);
453     s.PutCString("\n\nStackFrameList::Merge():\nPrev:\n");
454     if (prev_sp.get())
455         prev_sp->Dump (&s);
456     else
457         s.PutCString ("NULL");
458     s.PutCString("\nCurr:\n");
459     if (curr_ap.get())
460         curr_ap->Dump (&s);
461     else
462         s.PutCString ("NULL");
463     s.EOL();
464 #endif
465 
466     if (curr_ap.get() == NULL || curr_ap->GetNumFrames (false) == 0)
467     {
468 #if defined (DEBUG_STACK_FRAMES)
469         s.PutCString("No current frames, leave previous frames alone...\n");
470 #endif
471         curr_ap.release();
472         return;
473     }
474 
475     if (prev_sp.get() == NULL || prev_sp->GetNumFrames (false) == 0)
476     {
477 #if defined (DEBUG_STACK_FRAMES)
478         s.PutCString("No previous frames, so use current frames...\n");
479 #endif
480         // We either don't have any previous frames, or since we have more than
481         // one current frames it means we have all the frames and can safely
482         // replace our previous frames.
483         prev_sp.reset (curr_ap.release());
484         return;
485     }
486 
487     const uint32_t num_curr_frames = curr_ap->GetNumFrames (false);
488 
489     if (num_curr_frames > 1)
490     {
491 #if defined (DEBUG_STACK_FRAMES)
492         s.PutCString("We have more than one current frame, so use current frames...\n");
493 #endif
494         // We have more than one current frames it means we have all the frames
495         // and can safely replace our previous frames.
496         prev_sp.reset (curr_ap.release());
497 
498 #if defined (DEBUG_STACK_FRAMES)
499         s.PutCString("\nMerged:\n");
500         prev_sp->Dump (&s);
501 #endif
502         return;
503     }
504 
505     StackFrameSP prev_frame_zero_sp(prev_sp->GetFrameAtIndex (0));
506     StackFrameSP curr_frame_zero_sp(curr_ap->GetFrameAtIndex (0));
507     StackID curr_stack_id (curr_frame_zero_sp->GetStackID());
508     StackID prev_stack_id (prev_frame_zero_sp->GetStackID());
509 
510 #if defined (DEBUG_STACK_FRAMES)
511     const uint32_t num_prev_frames = prev_sp->GetNumFrames (false);
512     s.Printf("\n%u previous frames with one current frame\n", num_prev_frames);
513 #endif
514 
515     // We have only a single current frame
516     // Our previous stack frames only had a single frame as well...
517     if (curr_stack_id == prev_stack_id)
518     {
519 #if defined (DEBUG_STACK_FRAMES)
520         s.Printf("\nPrevious frame #0 is same as current frame #0, merge the cached data\n");
521 #endif
522 
523         curr_frame_zero_sp->UpdateCurrentFrameFromPreviousFrame (*prev_frame_zero_sp);
524 //        prev_frame_zero_sp->UpdatePreviousFrameFromCurrentFrame (*curr_frame_zero_sp);
525 //        prev_sp->SetFrameAtIndex (0, prev_frame_zero_sp);
526     }
527     else if (curr_stack_id < prev_stack_id)
528     {
529 #if defined (DEBUG_STACK_FRAMES)
530         s.Printf("\nCurrent frame #0 has a stack ID that is less than the previous frame #0, insert current frame zero in front of previous\n");
531 #endif
532         prev_sp->m_frames.insert (prev_sp->m_frames.begin(), curr_frame_zero_sp);
533     }
534 
535     curr_ap.release();
536 
537 #if defined (DEBUG_STACK_FRAMES)
538     s.PutCString("\nMerged:\n");
539     prev_sp->Dump (&s);
540 #endif
541 
542 
543 }
544 
545 lldb::StackFrameSP
546 StackFrameList::GetStackFrameSPForStackFramePtr (StackFrame *stack_frame_ptr)
547 {
548     const_iterator pos;
549     const_iterator begin = m_frames.begin();
550     const_iterator end = m_frames.end();
551     lldb::StackFrameSP ret_sp;
552 
553     for (pos = begin; pos != end; ++pos)
554     {
555         if (pos->get() == stack_frame_ptr)
556         {
557             ret_sp = (*pos);
558             break;
559         }
560     }
561     return ret_sp;
562 }
563 
564 size_t
565 StackFrameList::GetStatus (Stream& strm,
566                            uint32_t first_frame,
567                            uint32_t num_frames,
568                            bool show_frame_info,
569                            uint32_t num_frames_with_source,
570                            uint32_t source_lines_before,
571                            uint32_t source_lines_after)
572 {
573     size_t num_frames_displayed = 0;
574 
575     if (num_frames == 0)
576         return 0;
577 
578     StackFrameSP frame_sp;
579     uint32_t frame_idx = 0;
580     uint32_t last_frame;
581 
582     // Don't let the last frame wrap around...
583     if (num_frames == UINT32_MAX)
584         last_frame = UINT32_MAX;
585     else
586         last_frame = first_frame + num_frames;
587 
588     for (frame_idx = first_frame; frame_idx < last_frame; ++frame_idx)
589     {
590         frame_sp = GetFrameAtIndex(frame_idx);
591         if (frame_sp.get() == NULL)
592             break;
593 
594         if (!frame_sp->GetStatus (strm,
595                                   show_frame_info,
596                                   num_frames_with_source > first_frame - frame_idx,
597                                   source_lines_before,
598                                   source_lines_after))
599             break;
600         ++num_frames_displayed;
601     }
602 
603     strm.IndentLess();
604     return num_frames_displayed;
605 }
606 
607