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 // You must call IsValidRowIndex(idx) first before calling this!!! 389 assert (idx < m_row_list.size()); 390 return m_row_list[idx]; 391 } 392 393 const UnwindPlan::RowSP 394 UnwindPlan::GetLastRow () const 395 { 396 // You must call GetRowCount() first to make sure there is at least one row 397 assert (!m_row_list.empty()); 398 return m_row_list.back(); 399 } 400 401 int 402 UnwindPlan::GetRowCount () const 403 { 404 return m_row_list.size (); 405 } 406 407 void 408 UnwindPlan::SetPlanValidAddressRange (const AddressRange& range) 409 { 410 if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0) 411 m_plan_valid_address_range = range; 412 } 413 414 bool 415 UnwindPlan::PlanValidAtAddress (Address addr) 416 { 417 // If this UnwindPlan has no rows, it is an invalid UnwindPlan. 418 if (GetRowCount() == 0) 419 { 420 Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); 421 if (log) 422 { 423 StreamString s; 424 if (addr.Dump (&s, nullptr, Address::DumpStyleSectionNameOffset)) 425 { 426 log->Printf ("UnwindPlan is invalid -- no unwind rows for UnwindPlan '%s' at address %s", 427 m_source_name.GetCString(), s.GetData()); 428 } 429 else 430 { 431 log->Printf ("UnwindPlan is invalid -- no unwind rows for UnwindPlan '%s'", 432 m_source_name.GetCString()); 433 } 434 } 435 return false; 436 } 437 438 // If the 0th Row of unwind instructions is missing, or if it doesn't provide 439 // a register to use to find the Canonical Frame Address, this is not a valid UnwindPlan. 440 if (GetRowAtIndex(0).get() == nullptr || 441 GetRowAtIndex(0)->GetCFAValue().GetValueType() == Row::CFAValue::unspecified) 442 { 443 Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); 444 if (log) 445 { 446 StreamString s; 447 if (addr.Dump (&s, nullptr, Address::DumpStyleSectionNameOffset)) 448 { 449 log->Printf ("UnwindPlan is invalid -- no CFA register defined in row 0 for UnwindPlan '%s' at address %s", 450 m_source_name.GetCString(), s.GetData()); 451 } 452 else 453 { 454 log->Printf ("UnwindPlan is invalid -- no CFA register defined in row 0 for UnwindPlan '%s'", 455 m_source_name.GetCString()); 456 } 457 } 458 return false; 459 } 460 461 if (!m_plan_valid_address_range.GetBaseAddress().IsValid() || m_plan_valid_address_range.GetByteSize() == 0) 462 return true; 463 464 if (!addr.IsValid()) 465 return true; 466 467 if (m_plan_valid_address_range.ContainsFileAddress (addr)) 468 return true; 469 470 return false; 471 } 472 473 void 474 UnwindPlan::Dump (Stream& s, Thread *thread, lldb::addr_t base_addr) const 475 { 476 if (!m_source_name.IsEmpty()) 477 { 478 s.Printf ("This UnwindPlan originally sourced from %s\n", m_source_name.GetCString()); 479 } 480 if (m_lsda_address.IsValid() && m_personality_func_addr.IsValid()) 481 { 482 TargetSP target_sp(thread->CalculateTarget()); 483 addr_t lsda_load_addr = m_lsda_address.GetLoadAddress (target_sp.get()); 484 addr_t personality_func_load_addr = m_personality_func_addr.GetLoadAddress (target_sp.get()); 485 486 if (lsda_load_addr != LLDB_INVALID_ADDRESS && personality_func_load_addr != LLDB_INVALID_ADDRESS) 487 { 488 s.Printf("LSDA address 0x%" PRIx64 ", personality routine is at address 0x%" PRIx64 "\n", 489 lsda_load_addr, personality_func_load_addr); 490 } 491 } 492 s.Printf ("This UnwindPlan is sourced from the compiler: "); 493 switch (m_plan_is_sourced_from_compiler) 494 { 495 case eLazyBoolYes: 496 s.Printf ("yes.\n"); 497 break; 498 case eLazyBoolNo: 499 s.Printf ("no.\n"); 500 break; 501 case eLazyBoolCalculate: 502 s.Printf ("not specified.\n"); 503 break; 504 } 505 s.Printf ("This UnwindPlan is valid at all instruction locations: "); 506 switch (m_plan_is_valid_at_all_instruction_locations) 507 { 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 if (m_plan_valid_address_range.GetBaseAddress().IsValid() && m_plan_valid_address_range.GetByteSize() > 0) 519 { 520 s.PutCString ("Address range of this UnwindPlan: "); 521 TargetSP target_sp(thread->CalculateTarget()); 522 m_plan_valid_address_range.Dump (&s, target_sp.get(), Address::DumpStyleSectionNameOffset); 523 s.EOL(); 524 } 525 collection::const_iterator pos, begin = m_row_list.begin(), end = m_row_list.end(); 526 for (pos = begin; pos != end; ++pos) 527 { 528 s.Printf ("row[%u]: ", (uint32_t)std::distance (begin, pos)); 529 (*pos)->Dump(s, this, thread, base_addr); 530 } 531 } 532 533 void 534 UnwindPlan::SetSourceName (const char *source) 535 { 536 m_source_name = ConstString (source); 537 } 538 539 ConstString 540 UnwindPlan::GetSourceName () const 541 { 542 return m_source_name; 543 } 544 545 const RegisterInfo * 546 UnwindPlan::GetRegisterInfo (Thread* thread, uint32_t unwind_reg) const 547 { 548 if (thread) 549 { 550 RegisterContext *reg_ctx = thread->GetRegisterContext().get(); 551 if (reg_ctx) 552 { 553 uint32_t reg; 554 if (m_register_kind == eRegisterKindLLDB) 555 reg = unwind_reg; 556 else 557 reg = reg_ctx->ConvertRegisterKindToRegisterNumber (m_register_kind, unwind_reg); 558 if (reg != LLDB_INVALID_REGNUM) 559 return reg_ctx->GetRegisterInfoAtIndex (reg); 560 } 561 } 562 return nullptr; 563 } 564 565