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