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("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 } 241 } 242 else 243 { 244 m_frames.resize(m_thread.GetUnwinder()->GetFrameCount()); 245 } 246 } 247 return m_frames.size(); 248 } 249 250 void 251 StackFrameList::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) 259 { 260 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(); 267 } 268 s->EOL(); 269 } 270 271 StackFrameSP 272 StackFrameList::GetFrameAtIndex (uint32_t idx) 273 { 274 StackFrameSP frame_sp; 275 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) 286 { 287 // 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)); 298 299 if (m_show_inlined_frames) 300 { 301 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]; 318 } 319 else 320 { 321 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 } 331 } 332 333 } 334 return frame_sp; 335 } 336 337 338 bool 339 StackFrameList::SetFrameAtIndex (uint32_t idx, StackFrameSP &frame_sp) 340 { 341 if (idx >= m_frames.size()) 342 m_frames.resize(idx + 1); 343 // Make sure allocation succeeded by checking bounds again 344 if (idx < m_frames.size()) 345 { 346 m_frames[idx] = frame_sp; 347 return true; 348 } 349 return false; // resize failed, out of memory? 350 } 351 352 uint32_t 353 StackFrameList::GetSelectedFrameIndex () const 354 { 355 Mutex::Locker locker (m_mutex); 356 return m_selected_frame_idx; 357 } 358 359 360 uint32_t 361 StackFrameList::SetSelectedFrame (lldb_private::StackFrame *frame) 362 { 363 Mutex::Locker locker (m_mutex); 364 const_iterator pos; 365 const_iterator begin = m_frames.begin(); 366 const_iterator end = m_frames.end(); 367 for (pos = begin; pos != end; ++pos) 368 { 369 if (pos->get() == frame) 370 { 371 m_selected_frame_idx = std::distance (begin, pos); 372 return m_selected_frame_idx; 373 } 374 } 375 m_selected_frame_idx = 0; 376 return m_selected_frame_idx; 377 } 378 379 // Mark a stack frame as the current frame using the frame index 380 void 381 StackFrameList::SetSelectedFrameByIndex (uint32_t idx) 382 { 383 Mutex::Locker locker (m_mutex); 384 m_selected_frame_idx = idx; 385 } 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. 389 void 390 StackFrameList::Clear () 391 { 392 Mutex::Locker locker (m_mutex); 393 m_frames.clear(); 394 } 395 396 void 397 StackFrameList::InvalidateFrames (uint32_t start_idx) 398 { 399 Mutex::Locker locker (m_mutex); 400 if (m_show_inlined_frames) 401 { 402 Clear(); 403 } 404 else 405 { 406 const size_t num_frames = m_frames.size(); 407 while (start_idx < num_frames) 408 { 409 m_frames[start_idx].reset(); 410 ++start_idx; 411 } 412 } 413 } 414