1 //===-- UnwindPlan.cpp ----------------------------------*- C++ -*-===// 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 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 DataExtractor extractor(expr.data(), expr.size(), order_and_width->first, 83 order_and_width->second); 84 if (!DWARFExpression::PrintDWARFExpression(s, extractor, 85 order_and_width->second, 86 /*dwarf_ref_size*/ 4, 87 /*location_expression*/ false)) 88 s.PutCString("invalid-dwarf-expr"); 89 } else 90 s.PutCString("dwarf-expr"); 91 } 92 93 void UnwindPlan::Row::RegisterLocation::Dump(Stream &s, 94 const UnwindPlan *unwind_plan, 95 const UnwindPlan::Row *row, 96 Thread *thread, 97 bool verbose) const { 98 switch (m_type) { 99 case unspecified: 100 if (verbose) 101 s.PutCString("=<unspec>"); 102 else 103 s.PutCString("=!"); 104 break; 105 case undefined: 106 if (verbose) 107 s.PutCString("=<undef>"); 108 else 109 s.PutCString("=?"); 110 break; 111 case same: 112 s.PutCString("= <same>"); 113 break; 114 115 case atCFAPlusOffset: 116 case isCFAPlusOffset: { 117 s.PutChar('='); 118 if (m_type == atCFAPlusOffset) 119 s.PutChar('['); 120 s.Printf("CFA%+d", m_location.offset); 121 if (m_type == atCFAPlusOffset) 122 s.PutChar(']'); 123 } break; 124 125 case atAFAPlusOffset: 126 case isAFAPlusOffset: { 127 s.PutChar('='); 128 if (m_type == atAFAPlusOffset) 129 s.PutChar('['); 130 s.Printf("AFA%+d", m_location.offset); 131 if (m_type == atAFAPlusOffset) 132 s.PutChar(']'); 133 } break; 134 135 case inOtherRegister: { 136 const RegisterInfo *other_reg_info = nullptr; 137 if (unwind_plan) 138 other_reg_info = unwind_plan->GetRegisterInfo(thread, m_location.reg_num); 139 if (other_reg_info) 140 s.Printf("=%s", other_reg_info->name); 141 else 142 s.Printf("=reg(%u)", m_location.reg_num); 143 } break; 144 145 case atDWARFExpression: 146 case isDWARFExpression: { 147 s.PutChar('='); 148 if (m_type == atDWARFExpression) 149 s.PutChar('['); 150 DumpDWARFExpr( 151 s, llvm::makeArrayRef(m_location.expr.opcodes, m_location.expr.length), 152 thread); 153 if (m_type == atDWARFExpression) 154 s.PutChar(']'); 155 } break; 156 } 157 } 158 159 static void DumpRegisterName(Stream &s, const UnwindPlan *unwind_plan, 160 Thread *thread, uint32_t reg_num) { 161 const RegisterInfo *reg_info = unwind_plan->GetRegisterInfo(thread, reg_num); 162 if (reg_info) 163 s.PutCString(reg_info->name); 164 else 165 s.Printf("reg(%u)", reg_num); 166 } 167 168 bool UnwindPlan::Row::FAValue:: 169 operator==(const UnwindPlan::Row::FAValue &rhs) const { 170 if (m_type == rhs.m_type) { 171 switch (m_type) { 172 case unspecified: 173 return true; 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 default: 209 s.PutCString("unspecified"); 210 break; 211 } 212 } 213 214 void UnwindPlan::Row::Clear() { 215 m_cfa_value.SetUnspecified(); 216 m_afa_value.SetUnspecified(); 217 m_offset = 0; 218 m_register_locations.clear(); 219 } 220 221 void UnwindPlan::Row::Dump(Stream &s, const UnwindPlan *unwind_plan, 222 Thread *thread, addr_t base_addr) const { 223 if (base_addr != LLDB_INVALID_ADDRESS) 224 s.Printf("0x%16.16" PRIx64 ": CFA=", base_addr + GetOffset()); 225 else 226 s.Printf("%4" PRId64 ": CFA=", GetOffset()); 227 228 m_cfa_value.Dump(s, unwind_plan, thread); 229 230 if (!m_afa_value.IsUnspecified()) { 231 s.Printf(" AFA="); 232 m_afa_value.Dump(s, unwind_plan, thread); 233 } 234 235 s.Printf(" => "); 236 for (collection::const_iterator idx = m_register_locations.begin(); 237 idx != m_register_locations.end(); ++idx) { 238 DumpRegisterName(s, unwind_plan, thread, idx->first); 239 const bool verbose = false; 240 idx->second.Dump(s, unwind_plan, this, thread, verbose); 241 s.PutChar(' '); 242 } 243 s.EOL(); 244 } 245 246 UnwindPlan::Row::Row() 247 : m_offset(0), 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 return false; 258 } 259 260 void UnwindPlan::Row::RemoveRegisterInfo(uint32_t reg_num) { 261 collection::const_iterator pos = m_register_locations.find(reg_num); 262 if (pos != m_register_locations.end()) { 263 m_register_locations.erase(pos); 264 } 265 } 266 267 void UnwindPlan::Row::SetRegisterInfo( 268 uint32_t reg_num, 269 const UnwindPlan::Row::RegisterLocation register_location) { 270 m_register_locations[reg_num] = register_location; 271 } 272 273 bool UnwindPlan::Row::SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num, 274 int32_t offset, 275 bool can_replace) { 276 if (!can_replace && 277 m_register_locations.find(reg_num) != m_register_locations.end()) 278 return false; 279 RegisterLocation reg_loc; 280 reg_loc.SetAtCFAPlusOffset(offset); 281 m_register_locations[reg_num] = reg_loc; 282 return true; 283 } 284 285 bool UnwindPlan::Row::SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num, 286 int32_t offset, 287 bool can_replace) { 288 if (!can_replace && 289 m_register_locations.find(reg_num) != m_register_locations.end()) 290 return false; 291 RegisterLocation reg_loc; 292 reg_loc.SetIsCFAPlusOffset(offset); 293 m_register_locations[reg_num] = reg_loc; 294 return true; 295 } 296 297 bool UnwindPlan::Row::SetRegisterLocationToUndefined( 298 uint32_t reg_num, bool can_replace, bool can_replace_only_if_unspecified) { 299 collection::iterator pos = m_register_locations.find(reg_num); 300 collection::iterator end = m_register_locations.end(); 301 302 if (pos != end) { 303 if (!can_replace) 304 return false; 305 if (can_replace_only_if_unspecified && !pos->second.IsUnspecified()) 306 return false; 307 } 308 RegisterLocation reg_loc; 309 reg_loc.SetUndefined(); 310 m_register_locations[reg_num] = reg_loc; 311 return true; 312 } 313 314 bool UnwindPlan::Row::SetRegisterLocationToUnspecified(uint32_t reg_num, 315 bool can_replace) { 316 if (!can_replace && 317 m_register_locations.find(reg_num) != m_register_locations.end()) 318 return false; 319 RegisterLocation reg_loc; 320 reg_loc.SetUnspecified(); 321 m_register_locations[reg_num] = reg_loc; 322 return true; 323 } 324 325 bool UnwindPlan::Row::SetRegisterLocationToRegister(uint32_t reg_num, 326 uint32_t other_reg_num, 327 bool can_replace) { 328 if (!can_replace && 329 m_register_locations.find(reg_num) != m_register_locations.end()) 330 return false; 331 RegisterLocation reg_loc; 332 reg_loc.SetInRegister(other_reg_num); 333 m_register_locations[reg_num] = reg_loc; 334 return true; 335 } 336 337 bool UnwindPlan::Row::SetRegisterLocationToSame(uint32_t reg_num, 338 bool must_replace) { 339 if (must_replace && 340 m_register_locations.find(reg_num) == m_register_locations.end()) 341 return false; 342 RegisterLocation reg_loc; 343 reg_loc.SetSame(); 344 m_register_locations[reg_num] = reg_loc; 345 return true; 346 } 347 348 bool UnwindPlan::Row::operator==(const UnwindPlan::Row &rhs) const { 349 return m_offset == rhs.m_offset && 350 m_cfa_value == rhs.m_cfa_value && 351 m_afa_value == rhs.m_afa_value && 352 m_register_locations == rhs.m_register_locations; 353 } 354 355 void UnwindPlan::AppendRow(const UnwindPlan::RowSP &row_sp) { 356 if (m_row_list.empty() || 357 m_row_list.back()->GetOffset() != row_sp->GetOffset()) 358 m_row_list.push_back(row_sp); 359 else 360 m_row_list.back() = row_sp; 361 } 362 363 void UnwindPlan::InsertRow(const UnwindPlan::RowSP &row_sp, 364 bool replace_existing) { 365 collection::iterator it = m_row_list.begin(); 366 while (it != m_row_list.end()) { 367 RowSP row = *it; 368 if (row->GetOffset() >= row_sp->GetOffset()) 369 break; 370 it++; 371 } 372 if (it == m_row_list.end() || (*it)->GetOffset() != row_sp->GetOffset()) 373 m_row_list.insert(it, row_sp); 374 else if (replace_existing) 375 *it = row_sp; 376 } 377 378 UnwindPlan::RowSP UnwindPlan::GetRowForFunctionOffset(int offset) const { 379 RowSP row; 380 if (!m_row_list.empty()) { 381 if (offset == -1) 382 row = m_row_list.back(); 383 else { 384 collection::const_iterator pos, end = m_row_list.end(); 385 for (pos = m_row_list.begin(); pos != end; ++pos) { 386 if ((*pos)->GetOffset() <= static_cast<lldb::offset_t>(offset)) 387 row = *pos; 388 else 389 break; 390 } 391 } 392 } 393 return row; 394 } 395 396 bool UnwindPlan::IsValidRowIndex(uint32_t idx) const { 397 return idx < m_row_list.size(); 398 } 399 400 const UnwindPlan::RowSP UnwindPlan::GetRowAtIndex(uint32_t idx) const { 401 if (idx < m_row_list.size()) 402 return m_row_list[idx]; 403 else { 404 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); 405 if (log) 406 log->Printf("error: UnwindPlan::GetRowAtIndex(idx = %u) invalid index " 407 "(number rows is %u)", 408 idx, (uint32_t)m_row_list.size()); 409 return UnwindPlan::RowSP(); 410 } 411 } 412 413 const UnwindPlan::RowSP UnwindPlan::GetLastRow() const { 414 if (m_row_list.empty()) { 415 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); 416 if (log) 417 log->Printf("UnwindPlan::GetLastRow() when rows are empty"); 418 return UnwindPlan::RowSP(); 419 } 420 return m_row_list.back(); 421 } 422 423 int UnwindPlan::GetRowCount() const { return m_row_list.size(); } 424 425 void UnwindPlan::SetPlanValidAddressRange(const AddressRange &range) { 426 if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0) 427 m_plan_valid_address_range = range; 428 } 429 430 bool UnwindPlan::PlanValidAtAddress(Address addr) { 431 // If this UnwindPlan has no rows, it is an invalid UnwindPlan. 432 if (GetRowCount() == 0) { 433 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); 434 if (log) { 435 StreamString s; 436 if (addr.Dump(&s, nullptr, Address::DumpStyleSectionNameOffset)) { 437 log->Printf("UnwindPlan is invalid -- no unwind rows for UnwindPlan " 438 "'%s' at address %s", 439 m_source_name.GetCString(), s.GetData()); 440 } else { 441 log->Printf( 442 "UnwindPlan is invalid -- no unwind rows for UnwindPlan '%s'", 443 m_source_name.GetCString()); 444 } 445 } 446 return false; 447 } 448 449 // If the 0th Row of unwind instructions is missing, or if it doesn't provide 450 // a register to use to find the Canonical Frame Address, this is not a valid 451 // UnwindPlan. 452 if (GetRowAtIndex(0).get() == nullptr || 453 GetRowAtIndex(0)->GetCFAValue().GetValueType() == 454 Row::FAValue::unspecified) { 455 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); 456 if (log) { 457 StreamString s; 458 if (addr.Dump(&s, nullptr, Address::DumpStyleSectionNameOffset)) { 459 log->Printf("UnwindPlan is invalid -- no CFA register defined in row 0 " 460 "for UnwindPlan '%s' at address %s", 461 m_source_name.GetCString(), s.GetData()); 462 } else { 463 log->Printf("UnwindPlan is invalid -- no CFA register defined in row 0 " 464 "for UnwindPlan '%s'", 465 m_source_name.GetCString()); 466 } 467 } 468 return false; 469 } 470 471 if (!m_plan_valid_address_range.GetBaseAddress().IsValid() || 472 m_plan_valid_address_range.GetByteSize() == 0) 473 return true; 474 475 if (!addr.IsValid()) 476 return true; 477 478 if (m_plan_valid_address_range.ContainsFileAddress(addr)) 479 return true; 480 481 return false; 482 } 483 484 void UnwindPlan::Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const { 485 if (!m_source_name.IsEmpty()) { 486 s.Printf("This UnwindPlan originally sourced from %s\n", 487 m_source_name.GetCString()); 488 } 489 if (m_lsda_address.IsValid() && m_personality_func_addr.IsValid()) { 490 TargetSP target_sp(thread->CalculateTarget()); 491 addr_t lsda_load_addr = m_lsda_address.GetLoadAddress(target_sp.get()); 492 addr_t personality_func_load_addr = 493 m_personality_func_addr.GetLoadAddress(target_sp.get()); 494 495 if (lsda_load_addr != LLDB_INVALID_ADDRESS && 496 personality_func_load_addr != LLDB_INVALID_ADDRESS) { 497 s.Printf("LSDA address 0x%" PRIx64 498 ", personality routine is at address 0x%" PRIx64 "\n", 499 lsda_load_addr, personality_func_load_addr); 500 } 501 } 502 s.Printf("This UnwindPlan is sourced from the compiler: "); 503 switch (m_plan_is_sourced_from_compiler) { 504 case eLazyBoolYes: 505 s.Printf("yes.\n"); 506 break; 507 case eLazyBoolNo: 508 s.Printf("no.\n"); 509 break; 510 case eLazyBoolCalculate: 511 s.Printf("not specified.\n"); 512 break; 513 } 514 s.Printf("This UnwindPlan is valid at all instruction locations: "); 515 switch (m_plan_is_valid_at_all_instruction_locations) { 516 case eLazyBoolYes: 517 s.Printf("yes.\n"); 518 break; 519 case eLazyBoolNo: 520 s.Printf("no.\n"); 521 break; 522 case eLazyBoolCalculate: 523 s.Printf("not specified.\n"); 524 break; 525 } 526 if (m_plan_valid_address_range.GetBaseAddress().IsValid() && 527 m_plan_valid_address_range.GetByteSize() > 0) { 528 s.PutCString("Address range of this UnwindPlan: "); 529 TargetSP target_sp(thread->CalculateTarget()); 530 m_plan_valid_address_range.Dump(&s, target_sp.get(), 531 Address::DumpStyleSectionNameOffset); 532 s.EOL(); 533 } 534 collection::const_iterator pos, begin = m_row_list.begin(), 535 end = m_row_list.end(); 536 for (pos = begin; pos != end; ++pos) { 537 s.Printf("row[%u]: ", (uint32_t)std::distance(begin, pos)); 538 (*pos)->Dump(s, this, thread, base_addr); 539 } 540 } 541 542 void UnwindPlan::SetSourceName(const char *source) { 543 m_source_name = ConstString(source); 544 } 545 546 ConstString UnwindPlan::GetSourceName() const { return m_source_name; } 547 548 const RegisterInfo *UnwindPlan::GetRegisterInfo(Thread *thread, 549 uint32_t unwind_reg) const { 550 if (thread) { 551 RegisterContext *reg_ctx = thread->GetRegisterContext().get(); 552 if (reg_ctx) { 553 uint32_t reg; 554 if (m_register_kind == eRegisterKindLLDB) 555 reg = unwind_reg; 556 else 557 reg = reg_ctx->ConvertRegisterKindToRegisterNumber(m_register_kind, 558 unwind_reg); 559 if (reg != LLDB_INVALID_REGNUM) 560 return reg_ctx->GetRegisterInfoAtIndex(reg); 561 } 562 } 563 return nullptr; 564 } 565