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/Symbol/Block.h" 18 #include "lldb/Symbol/Function.h" 19 #include "lldb/Target/RegisterContext.h" 20 #include "lldb/Target/StackFrame.h" 21 #include "lldb/Target/Thread.h" 22 #include "lldb/Target/Unwind.h" 23 24 //#define DEBUG_STACK_FRAMES 1 25 26 using namespace lldb; 27 using namespace lldb_private; 28 29 //---------------------------------------------------------------------- 30 // StackFrameList constructor 31 //---------------------------------------------------------------------- 32 StackFrameList::StackFrameList(Thread &thread, StackFrameList *prev_frames, bool show_inline_frames) : 33 m_thread (thread), 34 m_prev_frames_ap (prev_frames), 35 m_show_inlined_frames (show_inline_frames), 36 m_mutex (Mutex::eMutexTypeRecursive), 37 m_frames (), 38 m_selected_frame_idx (0) 39 { 40 } 41 42 //---------------------------------------------------------------------- 43 // Destructor 44 //---------------------------------------------------------------------- 45 StackFrameList::~StackFrameList() 46 { 47 } 48 49 50 uint32_t 51 StackFrameList::GetNumFrames() 52 { 53 Mutex::Locker locker (m_mutex); 54 55 if (m_frames.size() <= 1) 56 { 57 if (m_show_inlined_frames) 58 { 59 #if defined (DEBUG_STACK_FRAMES) 60 StreamFile s(stdout); 61 #endif 62 Unwind *unwinder = m_thread.GetUnwinder (); 63 addr_t pc, cfa; 64 65 // 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 68 // in each frame. 69 const uint32_t unwind_frame_count = unwinder->GetFrameCount(); 70 71 StackFrameSP unwind_frame_sp; 72 for (uint32_t idx=0; idx<unwind_frame_count; ++idx) 73 { 74 if (idx == 0) 75 { 76 // 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 } 94 } 95 else 96 { 97 const bool success = unwinder->GetFrameInfoAtIndex(idx, cfa, pc); 98 assert (success); 99 unwind_frame_sp.reset (new StackFrame (m_frames.size(), idx, m_thread, cfa, pc, NULL)); 100 m_frames.push_back (unwind_frame_sp); 101 } 102 103 Block *block = unwind_frame_sp->GetSymbolContext (eSymbolContextBlock).block; 104 105 if (block) 106 { 107 for (block = block->GetContainingInlinedBlock(); block != NULL; block = block->GetInlinedParent ()) 108 { 109 SymbolContext inline_sc; 110 Block *parent_block = block->GetInlinedParent(); 111 112 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); 145 } 146 } 147 } 148 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("\nprev_frames:\n"); 155 prev_frames->Dump (&s); 156 s.PutCString("\ncurr_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 } 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 218 curr_frame->UpdateCurrentFrameFromPreviousFrame (*prev_frame); 219 220 #if defined (DEBUG_STACK_FRAMES) 221 s.Printf("\n Copying previous frame to current frame"); 222 #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 } 228 229 #if defined (DEBUG_STACK_FRAMES) 230 s.PutCString("\n\nNew frames:\n"); 231 Dump (&s); 232 s.EOL(); 233 #endif 234 } 235 else 236 { 237 m_frames.resize(m_thread.GetUnwinder()->GetFrameCount()); 238 } 239 } 240 return m_frames.size(); 241 } 242 243 void 244 StackFrameList::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) 252 { 253 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(); 260 } 261 s->EOL(); 262 } 263 264 StackFrameSP 265 StackFrameList::GetFrameAtIndex (uint32_t idx) 266 { 267 StackFrameSP frame_sp; 268 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) 279 { 280 // 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)); 291 292 if (m_show_inlined_frames) 293 { 294 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]; 311 } 312 else 313 { 314 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 } 324 } 325 326 } 327 return frame_sp; 328 } 329 330 331 bool 332 StackFrameList::SetFrameAtIndex (uint32_t idx, StackFrameSP &frame_sp) 333 { 334 if (idx >= m_frames.size()) 335 m_frames.resize(idx + 1); 336 // Make sure allocation succeeded by checking bounds again 337 if (idx < m_frames.size()) 338 { 339 m_frames[idx] = frame_sp; 340 return true; 341 } 342 return false; // resize failed, out of memory? 343 } 344 345 uint32_t 346 StackFrameList::GetSelectedFrameIndex () const 347 { 348 Mutex::Locker locker (m_mutex); 349 return m_selected_frame_idx; 350 } 351 352 353 uint32_t 354 StackFrameList::SetSelectedFrame (lldb_private::StackFrame *frame) 355 { 356 Mutex::Locker locker (m_mutex); 357 const_iterator pos; 358 const_iterator begin = m_frames.begin(); 359 const_iterator end = m_frames.end(); 360 for (pos = begin; pos != end; ++pos) 361 { 362 if (pos->get() == frame) 363 { 364 m_selected_frame_idx = std::distance (begin, pos); 365 return m_selected_frame_idx; 366 } 367 } 368 m_selected_frame_idx = 0; 369 return m_selected_frame_idx; 370 } 371 372 // Mark a stack frame as the current frame using the frame index 373 void 374 StackFrameList::SetSelectedFrameByIndex (uint32_t idx) 375 { 376 Mutex::Locker locker (m_mutex); 377 m_selected_frame_idx = idx; 378 } 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. 382 void 383 StackFrameList::Clear () 384 { 385 Mutex::Locker locker (m_mutex); 386 m_frames.clear(); 387 } 388 389 void 390 StackFrameList::InvalidateFrames (uint32_t start_idx) 391 { 392 Mutex::Locker locker (m_mutex); 393 if (m_show_inlined_frames) 394 { 395 Clear(); 396 } 397 else 398 { 399 const size_t num_frames = m_frames.size(); 400 while (start_idx < num_frames) 401 { 402 m_frames[start_idx].reset(); 403 ++start_idx; 404 } 405 } 406 } 407