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