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/Core/Log.h" 14 #include "lldb/Target/Process.h" 15 #include "lldb/Target/RegisterContext.h" 16 #include "lldb/Target/Thread.h" 17 18 using namespace lldb; 19 using namespace lldb_private; 20 21 bool 22 UnwindPlan::Row::RegisterLocation::operator == (const UnwindPlan::Row::RegisterLocation& rhs) const 23 { 24 if (m_type == rhs.m_type) 25 { 26 switch (m_type) 27 { 28 case unspecified: 29 case undefined: 30 case same: 31 return true; 32 33 case atCFAPlusOffset: 34 case isCFAPlusOffset: 35 return m_location.offset == rhs.m_location.offset; 36 37 case inOtherRegister: 38 return m_location.reg_num == rhs.m_location.reg_num; 39 40 case atDWARFExpression: 41 case isDWARFExpression: 42 if (m_location.expr.length == rhs.m_location.expr.length) 43 return !memcmp (m_location.expr.opcodes, rhs.m_location.expr.opcodes, m_location.expr.length); 44 break; 45 } 46 } 47 return false; 48 } 49 50 // This function doesn't copy the dwarf expression bytes; they must remain in allocated 51 // memory for the lifespan of this UnwindPlan object. 52 void 53 UnwindPlan::Row::RegisterLocation::SetAtDWARFExpression (const uint8_t *opcodes, uint32_t len) 54 { 55 m_type = atDWARFExpression; 56 m_location.expr.opcodes = opcodes; 57 m_location.expr.length = len; 58 } 59 60 // This function doesn't copy the dwarf expression bytes; they must remain in allocated 61 // memory for the lifespan of this UnwindPlan object. 62 void 63 UnwindPlan::Row::RegisterLocation::SetIsDWARFExpression (const uint8_t *opcodes, uint32_t len) 64 { 65 m_type = isDWARFExpression; 66 m_location.expr.opcodes = opcodes; 67 m_location.expr.length = len; 68 } 69 70 void 71 UnwindPlan::Row::RegisterLocation::Dump (Stream &s, const UnwindPlan* unwind_plan, const UnwindPlan::Row* row, Thread* thread, bool verbose) const 72 { 73 switch (m_type) 74 { 75 case unspecified: 76 if (verbose) 77 s.PutCString ("=<unspec>"); 78 else 79 s.PutCString ("=!"); 80 break; 81 case undefined: 82 if (verbose) 83 s.PutCString ("=<undef>"); 84 else 85 s.PutCString ("=?"); 86 break; 87 case same: 88 s.PutCString ("= <same>"); 89 break; 90 91 case atCFAPlusOffset: 92 case isCFAPlusOffset: 93 { 94 s.PutChar('='); 95 if (m_type == atCFAPlusOffset) 96 s.PutChar('['); 97 if (verbose) 98 s.Printf ("CFA%+d", m_location.offset); 99 100 if (unwind_plan && row) 101 { 102 const uint32_t cfa_reg = row->GetCFARegister(); 103 const RegisterInfo *cfa_reg_info = unwind_plan->GetRegisterInfo (thread, cfa_reg); 104 const int32_t offset = row->GetCFAOffset() + m_location.offset; 105 if (verbose) 106 { 107 if (cfa_reg_info) 108 s.Printf (" (%s%+d)", cfa_reg_info->name, offset); 109 else 110 s.Printf (" (reg(%u)%+d)", cfa_reg, offset); 111 } 112 else 113 { 114 if (cfa_reg_info) 115 s.Printf ("%s", cfa_reg_info->name); 116 else 117 s.Printf ("reg(%u)", cfa_reg); 118 if (offset != 0) 119 s.Printf ("%+d", offset); 120 } 121 } 122 if (m_type == atCFAPlusOffset) 123 s.PutChar(']'); 124 } 125 break; 126 127 case inOtherRegister: 128 { 129 const RegisterInfo *other_reg_info = nullptr; 130 if (unwind_plan) 131 other_reg_info = unwind_plan->GetRegisterInfo (thread, m_location.reg_num); 132 if (other_reg_info) 133 s.Printf ("=%s", other_reg_info->name); 134 else 135 s.Printf ("=reg(%u)", m_location.reg_num); 136 } 137 break; 138 139 case atDWARFExpression: 140 case isDWARFExpression: 141 { 142 s.PutChar('='); 143 if (m_type == atDWARFExpression) 144 s.PutCString("[dwarf-expr]"); 145 else 146 s.PutCString("dwarf-expr"); 147 } 148 break; 149 150 } 151 } 152 153 void 154 UnwindPlan::Row::Clear () 155 { 156 m_cfa_type = CFAIsRegisterPlusOffset; 157 m_offset = 0; 158 m_cfa_reg_num = LLDB_INVALID_REGNUM; 159 m_cfa_offset = 0; 160 m_register_locations.clear(); 161 } 162 163 void 164 UnwindPlan::Row::Dump (Stream& s, const UnwindPlan* unwind_plan, Thread* thread, addr_t base_addr) const 165 { 166 const RegisterInfo *reg_info = unwind_plan->GetRegisterInfo (thread, GetCFARegister()); 167 168 if (base_addr != LLDB_INVALID_ADDRESS) 169 s.Printf ("0x%16.16" PRIx64 ": CFA=", base_addr + GetOffset()); 170 else 171 s.Printf ("0x%8.8" PRIx64 ": CFA=", GetOffset()); 172 173 if (reg_info) 174 s.Printf ("%s", reg_info->name); 175 else 176 s.Printf ("reg(%u)", GetCFARegister()); 177 s.Printf ("%+3d => ", GetCFAOffset ()); 178 for (collection::const_iterator idx = m_register_locations.begin (); idx != m_register_locations.end (); ++idx) 179 { 180 reg_info = unwind_plan->GetRegisterInfo (thread, idx->first); 181 if (reg_info) 182 s.Printf ("%s", reg_info->name); 183 else 184 s.Printf ("reg(%u)", idx->first); 185 const bool verbose = false; 186 idx->second.Dump(s, unwind_plan, this, thread, verbose); 187 s.PutChar (' '); 188 } 189 s.EOL(); 190 } 191 192 UnwindPlan::Row::Row() : 193 m_offset (0), 194 m_cfa_type (CFAIsRegisterPlusOffset), 195 m_cfa_reg_num (LLDB_INVALID_REGNUM), 196 m_cfa_offset (0), 197 m_register_locations () 198 { 199 } 200 201 bool 202 UnwindPlan::Row::GetRegisterInfo (uint32_t reg_num, UnwindPlan::Row::RegisterLocation& register_location) const 203 { 204 collection::const_iterator pos = m_register_locations.find(reg_num); 205 if (pos != m_register_locations.end()) 206 { 207 register_location = pos->second; 208 return true; 209 } 210 return false; 211 } 212 213 void 214 UnwindPlan::Row::SetRegisterInfo (uint32_t reg_num, const UnwindPlan::Row::RegisterLocation register_location) 215 { 216 m_register_locations[reg_num] = register_location; 217 } 218 219 bool 220 UnwindPlan::Row::SetRegisterLocationToAtCFAPlusOffset (uint32_t reg_num, int32_t offset, bool can_replace) 221 { 222 if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end()) 223 return false; 224 RegisterLocation reg_loc; 225 reg_loc.SetAtCFAPlusOffset(offset); 226 m_register_locations[reg_num] = reg_loc; 227 return true; 228 } 229 230 bool 231 UnwindPlan::Row::SetRegisterLocationToIsCFAPlusOffset (uint32_t reg_num, int32_t offset, bool can_replace) 232 { 233 if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end()) 234 return false; 235 RegisterLocation reg_loc; 236 reg_loc.SetIsCFAPlusOffset(offset); 237 m_register_locations[reg_num] = reg_loc; 238 return true; 239 } 240 241 bool 242 UnwindPlan::Row::SetRegisterLocationToUndefined (uint32_t reg_num, bool can_replace, bool can_replace_only_if_unspecified) 243 { 244 collection::iterator pos = m_register_locations.find(reg_num); 245 collection::iterator end = m_register_locations.end(); 246 247 if (pos != end) 248 { 249 if (!can_replace) 250 return false; 251 if (can_replace_only_if_unspecified && !pos->second.IsUnspecified()) 252 return false; 253 } 254 RegisterLocation reg_loc; 255 reg_loc.SetUndefined(); 256 m_register_locations[reg_num] = reg_loc; 257 return true; 258 } 259 260 bool 261 UnwindPlan::Row::SetRegisterLocationToUnspecified (uint32_t reg_num, bool can_replace) 262 { 263 if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end()) 264 return false; 265 RegisterLocation reg_loc; 266 reg_loc.SetUnspecified(); 267 m_register_locations[reg_num] = reg_loc; 268 return true; 269 } 270 271 bool 272 UnwindPlan::Row::SetRegisterLocationToRegister (uint32_t reg_num, 273 uint32_t other_reg_num, 274 bool can_replace) 275 { 276 if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end()) 277 return false; 278 RegisterLocation reg_loc; 279 reg_loc.SetInRegister(other_reg_num); 280 m_register_locations[reg_num] = reg_loc; 281 return true; 282 } 283 284 bool 285 UnwindPlan::Row::SetRegisterLocationToSame (uint32_t reg_num, bool must_replace) 286 { 287 if (must_replace && m_register_locations.find(reg_num) == m_register_locations.end()) 288 return false; 289 RegisterLocation reg_loc; 290 reg_loc.SetSame(); 291 m_register_locations[reg_num] = reg_loc; 292 return true; 293 } 294 295 void 296 UnwindPlan::Row::SetCFARegister (uint32_t reg_num) 297 { 298 m_cfa_reg_num = reg_num; 299 } 300 301 bool 302 UnwindPlan::Row::operator == (const UnwindPlan::Row& rhs) const 303 { 304 if (m_offset != rhs.m_offset || m_cfa_reg_num != rhs.m_cfa_reg_num || m_cfa_offset != rhs.m_cfa_offset) 305 return false; 306 307 if (m_cfa_type != rhs.m_cfa_type) 308 return false; 309 310 if (m_cfa_type == CFAIsRegisterPlusOffset) 311 { 312 if (m_cfa_reg_num != rhs.m_cfa_reg_num) 313 return false; 314 if (m_cfa_offset != rhs.m_cfa_offset) 315 return false; 316 } 317 if (m_cfa_type == CFAIsRegisterDereferenced) 318 { 319 if (m_cfa_reg_num != rhs.m_cfa_reg_num) 320 return false; 321 } 322 323 return m_register_locations == rhs.m_register_locations; 324 } 325 326 void 327 UnwindPlan::AppendRow (const UnwindPlan::RowSP &row_sp) 328 { 329 if (m_row_list.empty() || m_row_list.back()->GetOffset() != row_sp->GetOffset()) 330 m_row_list.push_back(row_sp); 331 else 332 m_row_list.back() = row_sp; 333 } 334 335 void 336 UnwindPlan::InsertRow (const UnwindPlan::RowSP &row_sp) 337 { 338 collection::iterator it = m_row_list.begin(); 339 while (it != m_row_list.end()) { 340 RowSP row = *it; 341 if (row->GetOffset() > row_sp->GetOffset()) 342 break; 343 it++; 344 } 345 m_row_list.insert(it, row_sp); 346 } 347 348 UnwindPlan::RowSP 349 UnwindPlan::GetRowForFunctionOffset (int offset) const 350 { 351 RowSP row; 352 if (!m_row_list.empty()) 353 { 354 if (offset == -1) 355 row = m_row_list.back(); 356 else 357 { 358 collection::const_iterator pos, end = m_row_list.end(); 359 for (pos = m_row_list.begin(); pos != end; ++pos) 360 { 361 if ((*pos)->GetOffset() <= static_cast<lldb::offset_t>(offset)) 362 row = *pos; 363 else 364 break; 365 } 366 } 367 } 368 return row; 369 } 370 371 bool 372 UnwindPlan::IsValidRowIndex (uint32_t idx) const 373 { 374 return idx < m_row_list.size(); 375 } 376 377 const UnwindPlan::RowSP 378 UnwindPlan::GetRowAtIndex (uint32_t idx) const 379 { 380 // You must call IsValidRowIndex(idx) first before calling this!!! 381 assert (idx < m_row_list.size()); 382 return m_row_list[idx]; 383 } 384 385 const UnwindPlan::RowSP 386 UnwindPlan::GetLastRow () const 387 { 388 // You must call GetRowCount() first to make sure there is at least one row 389 assert (!m_row_list.empty()); 390 return m_row_list.back(); 391 } 392 393 int 394 UnwindPlan::GetRowCount () const 395 { 396 return m_row_list.size (); 397 } 398 399 void 400 UnwindPlan::SetPlanValidAddressRange (const AddressRange& range) 401 { 402 if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0) 403 m_plan_valid_address_range = range; 404 } 405 406 bool 407 UnwindPlan::PlanValidAtAddress (Address addr) 408 { 409 // If this UnwindPlan has no rows, it is an invalid UnwindPlan. 410 if (GetRowCount() == 0) 411 { 412 Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); 413 if (log) 414 { 415 StreamString s; 416 if (addr.Dump (&s, nullptr, Address::DumpStyleSectionNameOffset)) 417 { 418 log->Printf ("UnwindPlan is invalid -- no unwind rows for UnwindPlan '%s' at address %s", 419 m_source_name.GetCString(), s.GetData()); 420 } 421 else 422 { 423 log->Printf ("UnwindPlan is invalid -- no unwind rows for UnwindPlan '%s'", 424 m_source_name.GetCString()); 425 } 426 } 427 return false; 428 } 429 430 // If the 0th Row of unwind instructions is missing, or if it doesn't provide 431 // a register to use to find the Canonical Frame Address, this is not a valid UnwindPlan. 432 if (GetRowAtIndex(0).get() == nullptr || GetRowAtIndex(0)->GetCFARegister() == LLDB_INVALID_REGNUM) 433 { 434 Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); 435 if (log) 436 { 437 StreamString s; 438 if (addr.Dump (&s, nullptr, Address::DumpStyleSectionNameOffset)) 439 { 440 log->Printf ("UnwindPlan is invalid -- no CFA register defined in row 0 for UnwindPlan '%s' at address %s", 441 m_source_name.GetCString(), s.GetData()); 442 } 443 else 444 { 445 log->Printf ("UnwindPlan is invalid -- no CFA register defined in row 0 for UnwindPlan '%s'", 446 m_source_name.GetCString()); 447 } 448 } 449 return false; 450 } 451 452 if (!m_plan_valid_address_range.GetBaseAddress().IsValid() || m_plan_valid_address_range.GetByteSize() == 0) 453 return true; 454 455 if (!addr.IsValid()) 456 return true; 457 458 if (m_plan_valid_address_range.ContainsFileAddress (addr)) 459 return true; 460 461 return false; 462 } 463 464 void 465 UnwindPlan::Dump (Stream& s, Thread *thread, lldb::addr_t base_addr) const 466 { 467 if (!m_source_name.IsEmpty()) 468 { 469 s.Printf ("This UnwindPlan originally sourced from %s\n", m_source_name.GetCString()); 470 } 471 if (m_lsda_address.IsValid() && m_personality_func_addr.IsValid()) 472 { 473 TargetSP target_sp(thread->CalculateTarget()); 474 addr_t lsda_load_addr = m_lsda_address.GetLoadAddress (target_sp.get()); 475 addr_t personality_func_load_addr = m_personality_func_addr.GetLoadAddress (target_sp.get()); 476 477 if (lsda_load_addr != LLDB_INVALID_ADDRESS && personality_func_load_addr != LLDB_INVALID_ADDRESS) 478 { 479 s.Printf("LSDA address 0x%" PRIx64 ", personality routine is at address 0x%" PRIx64 "\n", 480 lsda_load_addr, personality_func_load_addr); 481 } 482 } 483 s.Printf ("This UnwindPlan is sourced from the compiler: "); 484 switch (m_plan_is_sourced_from_compiler) 485 { 486 case eLazyBoolYes: 487 s.Printf ("yes.\n"); 488 break; 489 case eLazyBoolNo: 490 s.Printf ("no.\n"); 491 break; 492 case eLazyBoolCalculate: 493 s.Printf ("not specified.\n"); 494 break; 495 } 496 s.Printf ("This UnwindPlan is valid at all instruction locations: "); 497 switch (m_plan_is_valid_at_all_instruction_locations) 498 { 499 case eLazyBoolYes: 500 s.Printf ("yes.\n"); 501 break; 502 case eLazyBoolNo: 503 s.Printf ("no.\n"); 504 break; 505 case eLazyBoolCalculate: 506 s.Printf ("not specified.\n"); 507 break; 508 } 509 if (m_plan_valid_address_range.GetBaseAddress().IsValid() && m_plan_valid_address_range.GetByteSize() > 0) 510 { 511 s.PutCString ("Address range of this UnwindPlan: "); 512 TargetSP target_sp(thread->CalculateTarget()); 513 m_plan_valid_address_range.Dump (&s, target_sp.get(), Address::DumpStyleSectionNameOffset); 514 s.EOL(); 515 } 516 collection::const_iterator pos, begin = m_row_list.begin(), end = m_row_list.end(); 517 for (pos = begin; pos != end; ++pos) 518 { 519 s.Printf ("row[%u]: ", (uint32_t)std::distance (begin, pos)); 520 (*pos)->Dump(s, this, thread, base_addr); 521 } 522 } 523 524 void 525 UnwindPlan::SetSourceName (const char *source) 526 { 527 m_source_name = ConstString (source); 528 } 529 530 ConstString 531 UnwindPlan::GetSourceName () const 532 { 533 return m_source_name; 534 } 535 536 const RegisterInfo * 537 UnwindPlan::GetRegisterInfo (Thread* thread, uint32_t unwind_reg) const 538 { 539 if (thread) 540 { 541 RegisterContext *reg_ctx = thread->GetRegisterContext().get(); 542 if (reg_ctx) 543 { 544 uint32_t reg; 545 if (m_register_kind == eRegisterKindLLDB) 546 reg = unwind_reg; 547 else 548 reg = reg_ctx->ConvertRegisterKindToRegisterNumber (m_register_kind, unwind_reg); 549 if (reg != LLDB_INVALID_REGNUM) 550 return reg_ctx->GetRegisterInfoAtIndex (reg); 551 } 552 } 553 return nullptr; 554 } 555 556