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