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