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