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