1 //===-- UnwindPlan.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/Symbol/UnwindPlan.h" 11 12 #include "lldb/Core/ConstString.h" 13 #include "lldb/Target/Process.h" 14 #include "lldb/Target/RegisterContext.h" 15 #include "lldb/Target/Thread.h" 16 17 using namespace lldb; 18 using namespace lldb_private; 19 20 bool 21 UnwindPlan::Row::RegisterLocation::operator == (const UnwindPlan::Row::RegisterLocation& rhs) const 22 { 23 if (m_type == rhs.m_type) 24 { 25 switch (m_type) 26 { 27 case unspecified: 28 case undefined: 29 case same: 30 return true; 31 32 case atCFAPlusOffset: 33 case isCFAPlusOffset: 34 return m_location.offset == rhs.m_location.offset; 35 36 case inOtherRegister: 37 return m_location.reg_num == rhs.m_location.reg_num; 38 39 case atDWARFExpression: 40 case isDWARFExpression: 41 if (m_location.expr.length == rhs.m_location.expr.length) 42 return !memcmp (m_location.expr.opcodes, rhs.m_location.expr.opcodes, m_location.expr.length); 43 break; 44 } 45 } 46 return false; 47 } 48 49 // This function doesn't copy the dwarf expression bytes; they must remain in allocated 50 // memory for the lifespan of this UnwindPlan object. 51 void 52 UnwindPlan::Row::RegisterLocation::SetAtDWARFExpression (const uint8_t *opcodes, uint32_t len) 53 { 54 m_type = atDWARFExpression; 55 m_location.expr.opcodes = opcodes; 56 m_location.expr.length = len; 57 } 58 59 // This function doesn't copy the dwarf expression bytes; they must remain in allocated 60 // memory for the lifespan of this UnwindPlan object. 61 void 62 UnwindPlan::Row::RegisterLocation::SetIsDWARFExpression (const uint8_t *opcodes, uint32_t len) 63 { 64 m_type = isDWARFExpression; 65 m_location.expr.opcodes = opcodes; 66 m_location.expr.length = len; 67 } 68 69 void 70 UnwindPlan::Row::RegisterLocation::Dump (Stream &s, const UnwindPlan* unwind_plan, const UnwindPlan::Row* row, Thread* thread, bool verbose) const 71 { 72 switch (m_type) 73 { 74 case unspecified: 75 if (verbose) 76 s.PutCString ("=<unspec>"); 77 else 78 s.PutCString ("=!"); 79 break; 80 case undefined: 81 if (verbose) 82 s.PutCString ("=<undef>"); 83 else 84 s.PutCString ("=?"); 85 break; 86 case same: 87 s.PutCString ("= <same>"); 88 break; 89 90 case atCFAPlusOffset: 91 case isCFAPlusOffset: 92 { 93 s.PutChar('='); 94 if (m_type == atCFAPlusOffset) 95 s.PutChar('['); 96 if (verbose) 97 s.Printf ("CFA%+d", m_location.offset); 98 99 if (unwind_plan && row) 100 { 101 const uint32_t cfa_reg = row->GetCFARegister(); 102 const RegisterInfo *cfa_reg_info = unwind_plan->GetRegisterInfo (thread, cfa_reg); 103 const int32_t offset = row->GetCFAOffset() + m_location.offset; 104 if (verbose) 105 { 106 if (cfa_reg_info) 107 s.Printf (" (%s%+d)", cfa_reg_info->name, offset); 108 else 109 s.Printf (" (reg(%u)%+d)", cfa_reg, offset); 110 } 111 else 112 { 113 if (cfa_reg_info) 114 s.Printf ("%s", cfa_reg_info->name); 115 else 116 s.Printf ("reg(%u)", cfa_reg); 117 if (offset != 0) 118 s.Printf ("%+d", offset); 119 } 120 } 121 if (m_type == atCFAPlusOffset) 122 s.PutChar(']'); 123 } 124 break; 125 126 case inOtherRegister: 127 { 128 const RegisterInfo *other_reg_info = NULL; 129 if (unwind_plan) 130 other_reg_info = unwind_plan->GetRegisterInfo (thread, m_location.reg_num); 131 if (other_reg_info) 132 s.Printf ("=%s", other_reg_info->name); 133 else 134 s.Printf ("=reg(%u)", m_location.reg_num); 135 } 136 break; 137 138 case atDWARFExpression: 139 case isDWARFExpression: 140 { 141 s.PutChar('='); 142 if (m_type == atDWARFExpression) 143 s.PutCString("[dwarf-expr]"); 144 else 145 s.PutCString("dwarf-expr"); 146 } 147 break; 148 149 } 150 } 151 152 void 153 UnwindPlan::Row::Clear () 154 { 155 m_offset = 0; 156 m_cfa_reg_num = 0; 157 m_cfa_offset = 0; 158 m_register_locations.clear(); 159 } 160 161 void 162 UnwindPlan::Row::Dump (Stream& s, const UnwindPlan* unwind_plan, Thread* thread, addr_t base_addr) const 163 { 164 const RegisterInfo *reg_info = unwind_plan->GetRegisterInfo (thread, GetCFARegister()); 165 166 if (base_addr != LLDB_INVALID_ADDRESS) 167 s.Printf ("0x%16.16llx: CFA=", base_addr + GetOffset()); 168 else 169 s.Printf ("0x%8.8llx: CFA=", GetOffset()); 170 171 if (reg_info) 172 s.Printf ("%s", reg_info->name); 173 else 174 s.Printf ("reg(%u)", GetCFARegister()); 175 s.Printf ("%+3d =>", GetCFAOffset ()); 176 for (collection::const_iterator idx = m_register_locations.begin (); idx != m_register_locations.end (); ++idx) 177 { 178 reg_info = unwind_plan->GetRegisterInfo (thread, idx->first); 179 if (reg_info) 180 s.Printf ("%s", reg_info->name); 181 else 182 s.Printf ("reg(%u)", idx->first); 183 const bool verbose = false; 184 idx->second.Dump(s, unwind_plan, this, thread, verbose); 185 s.PutChar (' '); 186 } 187 s.EOL(); 188 } 189 190 UnwindPlan::Row::Row() : 191 m_offset(0), 192 m_cfa_reg_num(0), 193 m_cfa_offset(0), 194 m_register_locations() 195 { 196 } 197 198 bool 199 UnwindPlan::Row::GetRegisterInfo (uint32_t reg_num, UnwindPlan::Row::RegisterLocation& register_location) const 200 { 201 collection::const_iterator pos = m_register_locations.find(reg_num); 202 if (pos != m_register_locations.end()) 203 { 204 register_location = pos->second; 205 return true; 206 } 207 return false; 208 } 209 210 void 211 UnwindPlan::Row::SetRegisterInfo (uint32_t reg_num, const UnwindPlan::Row::RegisterLocation register_location) 212 { 213 m_register_locations[reg_num] = register_location; 214 } 215 216 bool 217 UnwindPlan::Row::SetRegisterLocationToAtCFAPlusOffset (uint32_t reg_num, int32_t offset, bool can_replace) 218 { 219 if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end()) 220 return false; 221 RegisterLocation reg_loc; 222 reg_loc.SetAtCFAPlusOffset(offset); 223 m_register_locations[reg_num] = reg_loc; 224 return true; 225 } 226 227 bool 228 UnwindPlan::Row::SetRegisterLocationToIsCFAPlusOffset (uint32_t reg_num, int32_t offset, bool can_replace) 229 { 230 if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end()) 231 return false; 232 RegisterLocation reg_loc; 233 reg_loc.SetIsCFAPlusOffset(offset); 234 m_register_locations[reg_num] = reg_loc; 235 return true; 236 } 237 238 bool 239 UnwindPlan::Row::SetRegisterLocationToUndefined (uint32_t reg_num, bool can_replace, bool can_replace_only_if_unspecified) 240 { 241 collection::iterator pos = m_register_locations.find(reg_num); 242 collection::iterator end = m_register_locations.end(); 243 244 if (pos != end) 245 { 246 if (!can_replace) 247 return false; 248 if (can_replace_only_if_unspecified && !pos->second.IsUnspecified()) 249 return false; 250 } 251 RegisterLocation reg_loc; 252 reg_loc.SetUndefined(); 253 m_register_locations[reg_num] = reg_loc; 254 return true; 255 } 256 257 bool 258 UnwindPlan::Row::SetRegisterLocationToUnspecified (uint32_t reg_num, bool can_replace) 259 { 260 if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end()) 261 return false; 262 RegisterLocation reg_loc; 263 reg_loc.SetUnspecified(); 264 m_register_locations[reg_num] = reg_loc; 265 return true; 266 } 267 268 bool 269 UnwindPlan::Row::SetRegisterLocationToRegister (uint32_t reg_num, 270 uint32_t other_reg_num, 271 bool can_replace) 272 { 273 if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end()) 274 return false; 275 RegisterLocation reg_loc; 276 reg_loc.SetInRegister(other_reg_num); 277 m_register_locations[reg_num] = reg_loc; 278 return true; 279 } 280 281 bool 282 UnwindPlan::Row::SetRegisterLocationToSame (uint32_t reg_num, bool must_replace) 283 { 284 if (must_replace && m_register_locations.find(reg_num) == m_register_locations.end()) 285 return false; 286 RegisterLocation reg_loc; 287 reg_loc.SetSame(); 288 m_register_locations[reg_num] = reg_loc; 289 return true; 290 } 291 292 void 293 UnwindPlan::Row::SetCFARegister (uint32_t reg_num) 294 { 295 m_cfa_reg_num = reg_num; 296 } 297 298 void 299 UnwindPlan::AppendRow (const UnwindPlan::Row &row) 300 { 301 if (m_row_list.empty() || m_row_list.back().GetOffset() != row.GetOffset()) 302 m_row_list.push_back(row); 303 else 304 m_row_list.back() = row; 305 } 306 307 const UnwindPlan::Row * 308 UnwindPlan::GetRowForFunctionOffset (int offset) const 309 { 310 const UnwindPlan::Row *row_ptr = NULL; 311 if (!m_row_list.empty()) 312 { 313 if (offset == -1) 314 row_ptr = &m_row_list.back(); 315 else 316 { 317 collection::const_iterator pos, end = m_row_list.end(); 318 for (pos = m_row_list.begin(); pos != end; ++pos) 319 { 320 if (pos->GetOffset() <= offset) 321 row_ptr = &*pos; 322 else 323 break; 324 } 325 } 326 } 327 return row_ptr; 328 } 329 330 bool 331 UnwindPlan::IsValidRowIndex (uint32_t idx) const 332 { 333 return idx < m_row_list.size(); 334 } 335 336 const UnwindPlan::Row& 337 UnwindPlan::GetRowAtIndex (uint32_t idx) const 338 { 339 // You must call IsValidRowIndex(idx) first before calling this!!! 340 assert (idx < m_row_list.size()); 341 return m_row_list[idx]; 342 } 343 344 const UnwindPlan::Row& 345 UnwindPlan::GetLastRow () const 346 { 347 // You must call GetRowCount() first to make sure there is at least one row 348 assert (!m_row_list.empty()); 349 return m_row_list.back(); 350 } 351 352 int 353 UnwindPlan::GetRowCount () const 354 { 355 return m_row_list.size (); 356 } 357 358 void 359 UnwindPlan::SetPlanValidAddressRange (const AddressRange& range) 360 { 361 if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0) 362 m_plan_valid_address_range = range; 363 } 364 365 bool 366 UnwindPlan::PlanValidAtAddress (Address addr) 367 { 368 if (!m_plan_valid_address_range.GetBaseAddress().IsValid() || m_plan_valid_address_range.GetByteSize() == 0) 369 return true; 370 371 if (!addr.IsValid()) 372 return true; 373 374 if (m_plan_valid_address_range.ContainsFileAddress (addr)) 375 return true; 376 377 return false; 378 } 379 380 void 381 UnwindPlan::Dump (Stream& s, Thread *thread, lldb::addr_t base_addr) const 382 { 383 if (!m_source_name.IsEmpty()) 384 { 385 s.Printf ("This UnwindPlan originally sourced from %s\n", m_source_name.GetCString()); 386 } 387 if (m_plan_valid_address_range.GetBaseAddress().IsValid() && m_plan_valid_address_range.GetByteSize() > 0) 388 { 389 s.PutCString ("Address range of this UnwindPlan: "); 390 m_plan_valid_address_range.Dump (&s, &thread->GetProcess().GetTarget(), Address::DumpStyleSectionNameOffset); 391 s.EOL(); 392 } 393 else 394 { 395 s.PutCString ("No valid address range recorded for this UnwindPlan.\n"); 396 } 397 s.Printf ("UnwindPlan register kind %d", m_register_kind); 398 switch (m_register_kind) 399 { 400 case eRegisterKindGCC: s.PutCString (" [eRegisterKindGCC]"); break; 401 case eRegisterKindDWARF: s.PutCString (" [eRegisterKindDWARF]"); break; 402 case eRegisterKindGeneric: s.PutCString (" [eRegisterKindGeneric]"); break; 403 case eRegisterKindGDB: s.PutCString (" [eRegisterKindGDB]"); break; 404 case eRegisterKindLLDB: s.PutCString (" [eRegisterKindLLDB]"); break; 405 default: s.PutCString (" [eRegisterKind???]"); break; 406 } 407 s.EOL(); 408 collection::const_iterator pos, begin = m_row_list.begin(), end = m_row_list.end(); 409 for (pos = begin; pos != end; ++pos) 410 { 411 s.Printf ("row[%u]: ", (uint32_t)std::distance (begin, pos)); 412 pos->Dump(s, this, thread, base_addr); 413 } 414 } 415 416 void 417 UnwindPlan::SetSourceName (const char *source) 418 { 419 m_source_name = ConstString (source); 420 } 421 422 ConstString 423 UnwindPlan::GetSourceName () const 424 { 425 return m_source_name; 426 } 427 428 const RegisterInfo * 429 UnwindPlan::GetRegisterInfo (Thread* thread, uint32_t unwind_reg) const 430 { 431 if (thread) 432 { 433 RegisterContext *reg_ctx = thread->GetRegisterContext().get(); 434 if (reg_ctx) 435 { 436 uint32_t reg; 437 if (m_register_kind == eRegisterKindLLDB) 438 reg = unwind_reg; 439 else 440 reg = reg_ctx->ConvertRegisterKindToRegisterNumber (m_register_kind, unwind_reg); 441 if (reg != LLDB_INVALID_REGNUM) 442 return reg_ctx->GetRegisterInfoAtIndex (reg); 443 } 444 } 445 return NULL; 446 } 447 448