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