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 LLDB_LOGF(log, 406 "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 LLDB_LOGF(log, "UnwindPlan::GetLastRow() when rows are empty"); 417 return UnwindPlan::RowSP(); 418 } 419 return m_row_list.back(); 420 } 421 422 int UnwindPlan::GetRowCount() const { return m_row_list.size(); } 423 424 void UnwindPlan::SetPlanValidAddressRange(const AddressRange &range) { 425 if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0) 426 m_plan_valid_address_range = range; 427 } 428 429 bool UnwindPlan::PlanValidAtAddress(Address addr) { 430 // If this UnwindPlan has no rows, it is an invalid UnwindPlan. 431 if (GetRowCount() == 0) { 432 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); 433 if (log) { 434 StreamString s; 435 if (addr.Dump(&s, nullptr, Address::DumpStyleSectionNameOffset)) { 436 LLDB_LOGF(log, 437 "UnwindPlan is invalid -- no unwind rows for UnwindPlan " 438 "'%s' at address %s", 439 m_source_name.GetCString(), s.GetData()); 440 } else { 441 LLDB_LOGF(log, 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 LLDB_LOGF(log, 460 "UnwindPlan is invalid -- no CFA register defined in row 0 " 461 "for UnwindPlan '%s' at address %s", 462 m_source_name.GetCString(), s.GetData()); 463 } else { 464 LLDB_LOGF(log, 465 "UnwindPlan is invalid -- no CFA register defined in row 0 " 466 "for UnwindPlan '%s'", 467 m_source_name.GetCString()); 468 } 469 } 470 return false; 471 } 472 473 if (!m_plan_valid_address_range.GetBaseAddress().IsValid() || 474 m_plan_valid_address_range.GetByteSize() == 0) 475 return true; 476 477 if (!addr.IsValid()) 478 return true; 479 480 if (m_plan_valid_address_range.ContainsFileAddress(addr)) 481 return true; 482 483 return false; 484 } 485 486 void UnwindPlan::Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const { 487 if (!m_source_name.IsEmpty()) { 488 s.Printf("This UnwindPlan originally sourced from %s\n", 489 m_source_name.GetCString()); 490 } 491 if (m_lsda_address.IsValid() && m_personality_func_addr.IsValid()) { 492 TargetSP target_sp(thread->CalculateTarget()); 493 addr_t lsda_load_addr = m_lsda_address.GetLoadAddress(target_sp.get()); 494 addr_t personality_func_load_addr = 495 m_personality_func_addr.GetLoadAddress(target_sp.get()); 496 497 if (lsda_load_addr != LLDB_INVALID_ADDRESS && 498 personality_func_load_addr != LLDB_INVALID_ADDRESS) { 499 s.Printf("LSDA address 0x%" PRIx64 500 ", personality routine is at address 0x%" PRIx64 "\n", 501 lsda_load_addr, personality_func_load_addr); 502 } 503 } 504 s.Printf("This UnwindPlan is sourced from the compiler: "); 505 switch (m_plan_is_sourced_from_compiler) { 506 case eLazyBoolYes: 507 s.Printf("yes.\n"); 508 break; 509 case eLazyBoolNo: 510 s.Printf("no.\n"); 511 break; 512 case eLazyBoolCalculate: 513 s.Printf("not specified.\n"); 514 break; 515 } 516 s.Printf("This UnwindPlan is valid at all instruction locations: "); 517 switch (m_plan_is_valid_at_all_instruction_locations) { 518 case eLazyBoolYes: 519 s.Printf("yes.\n"); 520 break; 521 case eLazyBoolNo: 522 s.Printf("no.\n"); 523 break; 524 case eLazyBoolCalculate: 525 s.Printf("not specified.\n"); 526 break; 527 } 528 if (m_plan_valid_address_range.GetBaseAddress().IsValid() && 529 m_plan_valid_address_range.GetByteSize() > 0) { 530 s.PutCString("Address range of this UnwindPlan: "); 531 TargetSP target_sp(thread->CalculateTarget()); 532 m_plan_valid_address_range.Dump(&s, target_sp.get(), 533 Address::DumpStyleSectionNameOffset); 534 s.EOL(); 535 } 536 collection::const_iterator pos, begin = m_row_list.begin(), 537 end = m_row_list.end(); 538 for (pos = begin; pos != end; ++pos) { 539 s.Printf("row[%u]: ", (uint32_t)std::distance(begin, pos)); 540 (*pos)->Dump(s, this, thread, base_addr); 541 } 542 } 543 544 void UnwindPlan::SetSourceName(const char *source) { 545 m_source_name = ConstString(source); 546 } 547 548 ConstString UnwindPlan::GetSourceName() const { return m_source_name; } 549 550 const RegisterInfo *UnwindPlan::GetRegisterInfo(Thread *thread, 551 uint32_t unwind_reg) const { 552 if (thread) { 553 RegisterContext *reg_ctx = thread->GetRegisterContext().get(); 554 if (reg_ctx) { 555 uint32_t reg; 556 if (m_register_kind == eRegisterKindLLDB) 557 reg = unwind_reg; 558 else 559 reg = reg_ctx->ConvertRegisterKindToRegisterNumber(m_register_kind, 560 unwind_reg); 561 if (reg != LLDB_INVALID_REGNUM) 562 return reg_ctx->GetRegisterInfoAtIndex(reg); 563 } 564 } 565 return nullptr; 566 } 567