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