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