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() : m_cfa_value(), m_afa_value(), m_register_locations() {} 249 250 bool UnwindPlan::Row::GetRegisterInfo( 251 uint32_t reg_num, 252 UnwindPlan::Row::RegisterLocation ®ister_location) const { 253 collection::const_iterator pos = m_register_locations.find(reg_num); 254 if (pos != m_register_locations.end()) { 255 register_location = pos->second; 256 return true; 257 } 258 if (m_unspecified_registers_are_undefined) { 259 register_location.SetUndefined(); 260 return true; 261 } 262 return false; 263 } 264 265 void UnwindPlan::Row::RemoveRegisterInfo(uint32_t reg_num) { 266 collection::const_iterator pos = m_register_locations.find(reg_num); 267 if (pos != m_register_locations.end()) { 268 m_register_locations.erase(pos); 269 } 270 } 271 272 void UnwindPlan::Row::SetRegisterInfo( 273 uint32_t reg_num, 274 const UnwindPlan::Row::RegisterLocation register_location) { 275 m_register_locations[reg_num] = register_location; 276 } 277 278 bool UnwindPlan::Row::SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num, 279 int32_t offset, 280 bool can_replace) { 281 if (!can_replace && 282 m_register_locations.find(reg_num) != m_register_locations.end()) 283 return false; 284 RegisterLocation reg_loc; 285 reg_loc.SetAtCFAPlusOffset(offset); 286 m_register_locations[reg_num] = reg_loc; 287 return true; 288 } 289 290 bool UnwindPlan::Row::SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num, 291 int32_t offset, 292 bool can_replace) { 293 if (!can_replace && 294 m_register_locations.find(reg_num) != m_register_locations.end()) 295 return false; 296 RegisterLocation reg_loc; 297 reg_loc.SetIsCFAPlusOffset(offset); 298 m_register_locations[reg_num] = reg_loc; 299 return true; 300 } 301 302 bool UnwindPlan::Row::SetRegisterLocationToUndefined( 303 uint32_t reg_num, bool can_replace, bool can_replace_only_if_unspecified) { 304 collection::iterator pos = m_register_locations.find(reg_num); 305 collection::iterator end = m_register_locations.end(); 306 307 if (pos != end) { 308 if (!can_replace) 309 return false; 310 if (can_replace_only_if_unspecified && !pos->second.IsUnspecified()) 311 return false; 312 } 313 RegisterLocation reg_loc; 314 reg_loc.SetUndefined(); 315 m_register_locations[reg_num] = reg_loc; 316 return true; 317 } 318 319 bool UnwindPlan::Row::SetRegisterLocationToUnspecified(uint32_t reg_num, 320 bool can_replace) { 321 if (!can_replace && 322 m_register_locations.find(reg_num) != m_register_locations.end()) 323 return false; 324 RegisterLocation reg_loc; 325 reg_loc.SetUnspecified(); 326 m_register_locations[reg_num] = reg_loc; 327 return true; 328 } 329 330 bool UnwindPlan::Row::SetRegisterLocationToRegister(uint32_t reg_num, 331 uint32_t other_reg_num, 332 bool can_replace) { 333 if (!can_replace && 334 m_register_locations.find(reg_num) != m_register_locations.end()) 335 return false; 336 RegisterLocation reg_loc; 337 reg_loc.SetInRegister(other_reg_num); 338 m_register_locations[reg_num] = reg_loc; 339 return true; 340 } 341 342 bool UnwindPlan::Row::SetRegisterLocationToSame(uint32_t reg_num, 343 bool must_replace) { 344 if (must_replace && 345 m_register_locations.find(reg_num) == m_register_locations.end()) 346 return false; 347 RegisterLocation reg_loc; 348 reg_loc.SetSame(); 349 m_register_locations[reg_num] = reg_loc; 350 return true; 351 } 352 353 bool UnwindPlan::Row::operator==(const UnwindPlan::Row &rhs) const { 354 return m_offset == rhs.m_offset && m_cfa_value == rhs.m_cfa_value && 355 m_afa_value == rhs.m_afa_value && 356 m_unspecified_registers_are_undefined == 357 rhs.m_unspecified_registers_are_undefined && 358 m_register_locations == rhs.m_register_locations; 359 } 360 361 void UnwindPlan::AppendRow(const UnwindPlan::RowSP &row_sp) { 362 if (m_row_list.empty() || 363 m_row_list.back()->GetOffset() != row_sp->GetOffset()) 364 m_row_list.push_back(row_sp); 365 else 366 m_row_list.back() = row_sp; 367 } 368 369 void UnwindPlan::InsertRow(const UnwindPlan::RowSP &row_sp, 370 bool replace_existing) { 371 collection::iterator it = m_row_list.begin(); 372 while (it != m_row_list.end()) { 373 RowSP row = *it; 374 if (row->GetOffset() >= row_sp->GetOffset()) 375 break; 376 it++; 377 } 378 if (it == m_row_list.end() || (*it)->GetOffset() != row_sp->GetOffset()) 379 m_row_list.insert(it, row_sp); 380 else if (replace_existing) 381 *it = row_sp; 382 } 383 384 UnwindPlan::RowSP UnwindPlan::GetRowForFunctionOffset(int offset) const { 385 RowSP row; 386 if (!m_row_list.empty()) { 387 if (offset == -1) 388 row = m_row_list.back(); 389 else { 390 collection::const_iterator pos, end = m_row_list.end(); 391 for (pos = m_row_list.begin(); pos != end; ++pos) { 392 if ((*pos)->GetOffset() <= static_cast<lldb::offset_t>(offset)) 393 row = *pos; 394 else 395 break; 396 } 397 } 398 } 399 return row; 400 } 401 402 bool UnwindPlan::IsValidRowIndex(uint32_t idx) const { 403 return idx < m_row_list.size(); 404 } 405 406 const UnwindPlan::RowSP UnwindPlan::GetRowAtIndex(uint32_t idx) const { 407 if (idx < m_row_list.size()) 408 return m_row_list[idx]; 409 else { 410 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); 411 LLDB_LOGF(log, 412 "error: UnwindPlan::GetRowAtIndex(idx = %u) invalid index " 413 "(number rows is %u)", 414 idx, (uint32_t)m_row_list.size()); 415 return UnwindPlan::RowSP(); 416 } 417 } 418 419 const UnwindPlan::RowSP UnwindPlan::GetLastRow() const { 420 if (m_row_list.empty()) { 421 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); 422 LLDB_LOGF(log, "UnwindPlan::GetLastRow() when rows are empty"); 423 return UnwindPlan::RowSP(); 424 } 425 return m_row_list.back(); 426 } 427 428 int UnwindPlan::GetRowCount() const { return m_row_list.size(); } 429 430 void UnwindPlan::SetPlanValidAddressRange(const AddressRange &range) { 431 if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0) 432 m_plan_valid_address_range = range; 433 } 434 435 bool UnwindPlan::PlanValidAtAddress(Address addr) { 436 // If this UnwindPlan has no rows, it is an invalid UnwindPlan. 437 if (GetRowCount() == 0) { 438 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); 439 if (log) { 440 StreamString s; 441 if (addr.Dump(&s, nullptr, Address::DumpStyleSectionNameOffset)) { 442 LLDB_LOGF(log, 443 "UnwindPlan is invalid -- no unwind rows for UnwindPlan " 444 "'%s' at address %s", 445 m_source_name.GetCString(), s.GetData()); 446 } else { 447 LLDB_LOGF(log, 448 "UnwindPlan is invalid -- no unwind rows for UnwindPlan '%s'", 449 m_source_name.GetCString()); 450 } 451 } 452 return false; 453 } 454 455 // If the 0th Row of unwind instructions is missing, or if it doesn't provide 456 // a register to use to find the Canonical Frame Address, this is not a valid 457 // UnwindPlan. 458 if (GetRowAtIndex(0).get() == nullptr || 459 GetRowAtIndex(0)->GetCFAValue().GetValueType() == 460 Row::FAValue::unspecified) { 461 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); 462 if (log) { 463 StreamString s; 464 if (addr.Dump(&s, nullptr, Address::DumpStyleSectionNameOffset)) { 465 LLDB_LOGF(log, 466 "UnwindPlan is invalid -- no CFA register defined in row 0 " 467 "for UnwindPlan '%s' at address %s", 468 m_source_name.GetCString(), s.GetData()); 469 } else { 470 LLDB_LOGF(log, 471 "UnwindPlan is invalid -- no CFA register defined in row 0 " 472 "for UnwindPlan '%s'", 473 m_source_name.GetCString()); 474 } 475 } 476 return false; 477 } 478 479 if (!m_plan_valid_address_range.GetBaseAddress().IsValid() || 480 m_plan_valid_address_range.GetByteSize() == 0) 481 return true; 482 483 if (!addr.IsValid()) 484 return true; 485 486 if (m_plan_valid_address_range.ContainsFileAddress(addr)) 487 return true; 488 489 return false; 490 } 491 492 void UnwindPlan::Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const { 493 if (!m_source_name.IsEmpty()) { 494 s.Printf("This UnwindPlan originally sourced from %s\n", 495 m_source_name.GetCString()); 496 } 497 if (m_lsda_address.IsValid() && m_personality_func_addr.IsValid()) { 498 TargetSP target_sp(thread->CalculateTarget()); 499 addr_t lsda_load_addr = m_lsda_address.GetLoadAddress(target_sp.get()); 500 addr_t personality_func_load_addr = 501 m_personality_func_addr.GetLoadAddress(target_sp.get()); 502 503 if (lsda_load_addr != LLDB_INVALID_ADDRESS && 504 personality_func_load_addr != LLDB_INVALID_ADDRESS) { 505 s.Printf("LSDA address 0x%" PRIx64 506 ", personality routine is at address 0x%" PRIx64 "\n", 507 lsda_load_addr, personality_func_load_addr); 508 } 509 } 510 s.Printf("This UnwindPlan is sourced from the compiler: "); 511 switch (m_plan_is_sourced_from_compiler) { 512 case eLazyBoolYes: 513 s.Printf("yes.\n"); 514 break; 515 case eLazyBoolNo: 516 s.Printf("no.\n"); 517 break; 518 case eLazyBoolCalculate: 519 s.Printf("not specified.\n"); 520 break; 521 } 522 s.Printf("This UnwindPlan is valid at all instruction locations: "); 523 switch (m_plan_is_valid_at_all_instruction_locations) { 524 case eLazyBoolYes: 525 s.Printf("yes.\n"); 526 break; 527 case eLazyBoolNo: 528 s.Printf("no.\n"); 529 break; 530 case eLazyBoolCalculate: 531 s.Printf("not specified.\n"); 532 break; 533 } 534 s.Printf("This UnwindPlan is for a trap handler function: "); 535 switch (m_plan_is_for_signal_trap) { 536 case eLazyBoolYes: 537 s.Printf("yes.\n"); 538 break; 539 case eLazyBoolNo: 540 s.Printf("no.\n"); 541 break; 542 case eLazyBoolCalculate: 543 s.Printf("not specified.\n"); 544 break; 545 } 546 if (m_plan_valid_address_range.GetBaseAddress().IsValid() && 547 m_plan_valid_address_range.GetByteSize() > 0) { 548 s.PutCString("Address range of this UnwindPlan: "); 549 TargetSP target_sp(thread->CalculateTarget()); 550 m_plan_valid_address_range.Dump(&s, target_sp.get(), 551 Address::DumpStyleSectionNameOffset); 552 s.EOL(); 553 } 554 collection::const_iterator pos, begin = m_row_list.begin(), 555 end = m_row_list.end(); 556 for (pos = begin; pos != end; ++pos) { 557 s.Printf("row[%u]: ", (uint32_t)std::distance(begin, pos)); 558 (*pos)->Dump(s, this, thread, base_addr); 559 s.Printf("\n"); 560 } 561 } 562 563 void UnwindPlan::SetSourceName(const char *source) { 564 m_source_name = ConstString(source); 565 } 566 567 ConstString UnwindPlan::GetSourceName() const { return m_source_name; } 568 569 const RegisterInfo *UnwindPlan::GetRegisterInfo(Thread *thread, 570 uint32_t unwind_reg) const { 571 if (thread) { 572 RegisterContext *reg_ctx = thread->GetRegisterContext().get(); 573 if (reg_ctx) { 574 uint32_t reg; 575 if (m_register_kind == eRegisterKindLLDB) 576 reg = unwind_reg; 577 else 578 reg = reg_ctx->ConvertRegisterKindToRegisterNumber(m_register_kind, 579 unwind_reg); 580 if (reg != LLDB_INVALID_REGNUM) 581 return reg_ctx->GetRegisterInfoAtIndex(reg); 582 } 583 } 584 return nullptr; 585 } 586