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