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