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