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