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/Symbol/Block.h" 17 #include "lldb/Symbol/Function.h" 18 #include "lldb/Target/RegisterContext.h" 19 #include "lldb/Target/StackFrame.h" 20 #include "lldb/Target/Thread.h" 21 #include "lldb/Target/Unwind.h" 22 23 using namespace lldb; 24 using namespace lldb_private; 25 26 //---------------------------------------------------------------------- 27 // StackFrameList constructor 28 //---------------------------------------------------------------------- 29 StackFrameList::StackFrameList(Thread &thread, StackFrameList *prev_frames, bool show_inline_frames) : 30 m_thread (thread), 31 m_prev_frames_ap (prev_frames), 32 m_show_inlined_frames (show_inline_frames), 33 m_mutex (Mutex::eMutexTypeRecursive), 34 m_unwind_frames (), 35 m_inline_frames (), 36 m_current_frame_idx (0) 37 { 38 } 39 40 //---------------------------------------------------------------------- 41 // Destructor 42 //---------------------------------------------------------------------- 43 StackFrameList::~StackFrameList() 44 { 45 } 46 47 48 uint32_t 49 StackFrameList::GetNumFrames() 50 { 51 Mutex::Locker locker (m_mutex); 52 53 if (m_show_inlined_frames) 54 { 55 if (m_inlined_info.empty()) 56 { 57 Unwind *unwinder = m_thread.GetUnwinder (); 58 // If we are going to show inlined stack frames as actual frames, 59 // we need to calculate all concrete frames first, then iterate 60 // through all of them and count up how many inlined functions are 61 // in each frame. We can then fill in m_inlined_info with 62 // the concrete frame index and inlined depth 63 const uint32_t concrete_frame_count = unwinder->GetFrameCount(); 64 65 addr_t pc, cfa; 66 InlinedFrameInfo inlined_frame_info; 67 68 StackFrameSP frame_sp; 69 for (uint32_t idx=0; idx<concrete_frame_count; ++idx) 70 { 71 if (idx == 0) 72 { 73 m_thread.GetRegisterContext(); 74 frame_sp.reset (new StackFrame (0, 75 0, 76 m_thread, 77 m_thread.m_reg_context_sp, 78 m_thread.m_reg_context_sp->GetSP(), 79 m_thread.m_reg_context_sp->GetPC(), 80 NULL)); 81 } 82 else 83 { 84 const bool success = unwinder->GetFrameInfoAtIndex(idx, cfa, pc); 85 assert (success); 86 frame_sp.reset (new StackFrame (m_inlined_info.size(), idx, m_thread, cfa, pc, NULL)); 87 } 88 SetUnwindFrameAtIndex (idx, frame_sp); 89 Block *block = frame_sp->GetSymbolContext (eSymbolContextBlock).block; 90 91 inlined_frame_info.unwind_frame_index = idx; 92 inlined_frame_info.block = NULL; 93 m_inlined_info.push_back (inlined_frame_info); 94 95 if (block) 96 { 97 Block *inlined_block = block->GetContainingInlinedBlock(); 98 99 if (inlined_block) 100 { 101 frame_sp->SetInlineBlockID (inlined_block->GetID()); 102 103 while (inlined_block) 104 { 105 inlined_frame_info.block = inlined_block; 106 m_inlined_info.push_back (inlined_frame_info); 107 inlined_block = inlined_block->GetInlinedParent (); 108 } 109 } 110 } 111 } 112 } 113 return m_inlined_info.size(); 114 } 115 else 116 { 117 if (m_unwind_frames.empty()) 118 m_unwind_frames.resize(m_thread.GetUnwinder()->GetFrameCount()); 119 120 return m_unwind_frames.size(); 121 } 122 return 0; 123 } 124 125 lldb::StackFrameSP 126 StackFrameList::GetUnwindFrameAtIndex (uint32_t idx) const 127 { 128 StackFrameSP frame_sp; 129 if (idx < m_unwind_frames.size()) 130 frame_sp = m_unwind_frames[idx]; 131 return frame_sp; 132 } 133 134 lldb::StackFrameSP 135 StackFrameList::GetInlineFrameAtIndex (uint32_t idx) const 136 { 137 StackFrameSP frame_sp; 138 if (idx < m_inline_frames.size()) 139 frame_sp = m_inline_frames[idx]; 140 return frame_sp; 141 } 142 143 144 StackFrameSP 145 StackFrameList::GetFrameAtIndex (uint32_t idx) 146 { 147 StackFrameSP frame_sp; 148 { 149 Mutex::Locker locker (m_mutex); 150 151 if (m_show_inlined_frames) 152 { 153 frame_sp = GetInlineFrameAtIndex (idx); 154 } 155 else 156 { 157 frame_sp = GetUnwindFrameAtIndex (idx); 158 } 159 160 if (frame_sp.get()) 161 return frame_sp; 162 163 // Special case the first frame (idx == 0) so that we don't need to 164 // know how many stack frames there are to get it. If we need any other 165 // frames, then we do need to know if "idx" is a valid index. 166 if (idx == 0) 167 { 168 // If this is the first frame, we want to share the thread register 169 // context with the stack frame at index zero. 170 m_thread.GetRegisterContext(); 171 assert (m_thread.m_reg_context_sp.get()); 172 frame_sp.reset (new StackFrame (0, 173 0, 174 m_thread, 175 m_thread.m_reg_context_sp, 176 m_thread.m_reg_context_sp->GetSP(), 177 m_thread.m_reg_context_sp->GetPC(), 178 NULL)); 179 180 if (m_show_inlined_frames && idx + 1 < m_inlined_info.size()) 181 { 182 if (m_inlined_info[idx].unwind_frame_index == m_inlined_info[idx+1].unwind_frame_index) 183 frame_sp->SetInlineBlockID (frame_sp->GetSymbolContext (eSymbolContextBlock).block->GetID()); 184 } 185 186 } 187 else if (idx < GetNumFrames()) 188 { 189 if (m_show_inlined_frames) 190 { 191 if (m_inlined_info[idx].block == NULL) 192 { 193 // Same as the concrete stack frame if block is NULL 194 assert (m_inlined_info[idx].unwind_frame_index < m_unwind_frames.size()); 195 frame_sp = GetUnwindFrameAtIndex (m_inlined_info[idx].unwind_frame_index); 196 if (idx + 1 < m_inlined_info.size()) 197 { 198 if (m_inlined_info[idx].unwind_frame_index == m_inlined_info[idx+1].unwind_frame_index) 199 frame_sp->SetInlineBlockID (frame_sp->GetSymbolContext (eSymbolContextBlock).block->GetID()); 200 } 201 } 202 else 203 { 204 // We have blocks that were above an inlined function. Inlined 205 // functions are represented as blocks with non-NULL inline 206 // function info. Here we must reconstruct a frame by looking 207 // at the block 208 StackFrameSP previous_frame_sp (m_thread.GetStackFrameAtIndex (idx-1)); 209 210 SymbolContext inline_sc; 211 212 Block *inlined_parent_block = m_inlined_info[idx].block->GetInlinedParent(); 213 214 if (inlined_parent_block) 215 inlined_parent_block->CalculateSymbolContext (&inline_sc); 216 else 217 { 218 Block *parent_block = m_inlined_info[idx].block->GetParent(); 219 parent_block->CalculateSymbolContext(&inline_sc); 220 } 221 222 Address previous_frame_lookup_addr (previous_frame_sp->GetFrameCodeAddress()); 223 if (previous_frame_sp->GetFrameIndex() > 0 && m_inlined_info[idx-1].block == NULL) 224 previous_frame_lookup_addr.Slide (-1); 225 226 AddressRange range; 227 m_inlined_info[idx].block->GetRangeContainingAddress (previous_frame_lookup_addr, range); 228 229 const InlineFunctionInfo* inline_info = m_inlined_info[idx].block->InlinedFunctionInfo(); 230 assert (inline_info); 231 inline_sc.line_entry.range.GetBaseAddress() = previous_frame_sp->GetFrameCodeAddress(); 232 inline_sc.line_entry.file = inline_info->GetCallSite().GetFile(); 233 inline_sc.line_entry.line = inline_info->GetCallSite().GetLine(); 234 inline_sc.line_entry.column = inline_info->GetCallSite().GetColumn(); 235 236 StackFrameSP concrete_frame_sp (GetUnwindFrameAtIndex (m_inlined_info[idx].unwind_frame_index)); 237 assert (previous_frame_sp.get()); 238 239 frame_sp.reset (new StackFrame (idx, 240 m_inlined_info[idx].unwind_frame_index, 241 m_thread, 242 concrete_frame_sp->GetRegisterContextSP (), 243 concrete_frame_sp->GetStackID().GetCallFrameAddress(), // CFA 244 range.GetBaseAddress(), 245 &inline_sc)); // The symbol context for this inline frame 246 247 if (idx + 1 < m_inlined_info.size()) 248 { 249 if (m_inlined_info[idx].unwind_frame_index == m_inlined_info[idx+1].unwind_frame_index) 250 frame_sp->SetInlineBlockID (m_inlined_info[idx].block->GetID()); 251 } 252 } 253 } 254 else 255 { 256 Unwind *unwinder = m_thread.GetUnwinder (); 257 if (unwinder) 258 { 259 addr_t pc, cfa; 260 if (unwinder->GetFrameInfoAtIndex(idx, cfa, pc)) 261 frame_sp.reset (new StackFrame (idx, idx, m_thread, cfa, pc, NULL)); 262 } 263 } 264 } 265 266 if (m_show_inlined_frames) 267 { 268 SetInlineFrameAtIndex(idx, frame_sp); 269 } 270 else 271 { 272 SetUnwindFrameAtIndex(idx, frame_sp); 273 } 274 return frame_sp; 275 276 } 277 return frame_sp; 278 } 279 280 bool 281 StackFrameList::SetUnwindFrameAtIndex (uint32_t idx, StackFrameSP &frame_sp) 282 { 283 if (idx >= m_unwind_frames.size()) 284 m_unwind_frames.resize(idx + 1); 285 // Make sure allocation succeeded by checking bounds again 286 if (idx < m_unwind_frames.size()) 287 { 288 m_unwind_frames[idx] = frame_sp; 289 return true; 290 } 291 return false; // resize failed, out of memory? 292 } 293 294 bool 295 StackFrameList::SetInlineFrameAtIndex (uint32_t idx, StackFrameSP &frame_sp) 296 { 297 if (idx >= m_inline_frames.size()) 298 m_inline_frames.resize(idx + 1); 299 // Make sure allocation succeeded by checking bounds again 300 if (idx < m_inline_frames.size()) 301 { 302 m_inline_frames[idx] = frame_sp; 303 return true; 304 } 305 return false; // resize failed, out of memory? 306 } 307 308 uint32_t 309 StackFrameList::GetCurrentFrameIndex () const 310 { 311 Mutex::Locker locker (m_mutex); 312 return m_current_frame_idx; 313 } 314 315 316 uint32_t 317 StackFrameList::SetCurrentFrame (lldb_private::StackFrame *frame) 318 { 319 Mutex::Locker locker (m_mutex); 320 const_iterator pos; 321 const_iterator begin = m_show_inlined_frames ? m_inline_frames.begin() : m_unwind_frames.begin(); 322 const_iterator end = m_show_inlined_frames ? m_inline_frames.end() : m_unwind_frames.end(); 323 for (pos = begin; pos != end; ++pos) 324 { 325 if (pos->get() == frame) 326 { 327 m_current_frame_idx = std::distance (begin, pos); 328 return m_current_frame_idx; 329 } 330 } 331 m_current_frame_idx = 0; 332 return m_current_frame_idx; 333 } 334 335 // Mark a stack frame as the current frame using the frame index 336 void 337 StackFrameList::SetCurrentFrameByIndex (uint32_t idx) 338 { 339 Mutex::Locker locker (m_mutex); 340 m_current_frame_idx = idx; 341 } 342 343 // The thread has been run, reset the number stack frames to zero so we can 344 // determine how many frames we have lazily. 345 void 346 StackFrameList::Clear () 347 { 348 Mutex::Locker locker (m_mutex); 349 m_unwind_frames.clear(); 350 m_inline_frames.clear(); 351 m_inlined_info.clear(); 352 } 353 354 void 355 StackFrameList::InvalidateFrames (uint32_t start_idx) 356 { 357 Mutex::Locker locker (m_mutex); 358 if (m_show_inlined_frames) 359 { 360 Clear(); 361 } 362 else 363 { 364 const size_t num_frames = m_unwind_frames.size(); 365 while (start_idx < num_frames) 366 { 367 m_unwind_frames[start_idx].reset(); 368 ++start_idx; 369 } 370 } 371 } 372