UnwindPlan.cpp revision 263369
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 18using namespace lldb; 19using namespace lldb_private; 20 21bool 22UnwindPlan::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. 52void 53UnwindPlan::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. 62void 63UnwindPlan::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 70void 71UnwindPlan::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 = NULL; 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 153void 154UnwindPlan::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 162void 163UnwindPlan::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 191UnwindPlan::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 199bool 200UnwindPlan::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 211void 212UnwindPlan::Row::SetRegisterInfo (uint32_t reg_num, const UnwindPlan::Row::RegisterLocation register_location) 213{ 214 m_register_locations[reg_num] = register_location; 215} 216 217bool 218UnwindPlan::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 228bool 229UnwindPlan::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 239bool 240UnwindPlan::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 258bool 259UnwindPlan::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 269bool 270UnwindPlan::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 282bool 283UnwindPlan::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 293void 294UnwindPlan::Row::SetCFARegister (uint32_t reg_num) 295{ 296 m_cfa_reg_num = reg_num; 297} 298 299bool 300UnwindPlan::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 307void 308UnwindPlan::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 316UnwindPlan::RowSP 317UnwindPlan::GetRowForFunctionOffset (int offset) const 318{ 319 RowSP row; 320 if (!m_row_list.empty()) 321 { 322 if (offset == -1) 323 row = m_row_list.back(); 324 else 325 { 326 collection::const_iterator pos, end = m_row_list.end(); 327 for (pos = m_row_list.begin(); pos != end; ++pos) 328 { 329 if ((*pos)->GetOffset() <= offset) 330 row = *pos; 331 else 332 break; 333 } 334 } 335 } 336 return row; 337} 338 339bool 340UnwindPlan::IsValidRowIndex (uint32_t idx) const 341{ 342 return idx < m_row_list.size(); 343} 344 345const UnwindPlan::RowSP 346UnwindPlan::GetRowAtIndex (uint32_t idx) const 347{ 348 // You must call IsValidRowIndex(idx) first before calling this!!! 349 assert (idx < m_row_list.size()); 350 return m_row_list[idx]; 351} 352 353const UnwindPlan::RowSP 354UnwindPlan::GetLastRow () const 355{ 356 // You must call GetRowCount() first to make sure there is at least one row 357 assert (!m_row_list.empty()); 358 return m_row_list.back(); 359} 360 361int 362UnwindPlan::GetRowCount () const 363{ 364 return m_row_list.size (); 365} 366 367void 368UnwindPlan::SetPlanValidAddressRange (const AddressRange& range) 369{ 370 if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0) 371 m_plan_valid_address_range = range; 372} 373 374bool 375UnwindPlan::PlanValidAtAddress (Address addr) 376{ 377 // If this UnwindPlan has no rows, it is an invalid UnwindPlan. 378 if (GetRowCount() == 0) 379 { 380 Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); 381 if (log) 382 { 383 StreamString s; 384 if (addr.Dump (&s, NULL, Address::DumpStyleSectionNameOffset)) 385 { 386 log->Printf ("UnwindPlan is invalid -- no unwind rows for UnwindPlan '%s' at address %s", 387 m_source_name.GetCString(), s.GetData()); 388 } 389 else 390 { 391 log->Printf ("UnwindPlan is invalid -- no unwind rows for UnwindPlan '%s'", 392 m_source_name.GetCString()); 393 } 394 } 395 return false; 396 } 397 398 // If the 0th Row of unwind instructions is missing, or if it doesn't provide 399 // a register to use to find the Canonical Frame Address, this is not a valid UnwindPlan. 400 if (GetRowAtIndex(0).get() == NULL || GetRowAtIndex(0)->GetCFARegister() == LLDB_INVALID_REGNUM) 401 { 402 Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); 403 if (log) 404 { 405 StreamString s; 406 if (addr.Dump (&s, NULL, Address::DumpStyleSectionNameOffset)) 407 { 408 log->Printf ("UnwindPlan is invalid -- no CFA register defined in row 0 for UnwindPlan '%s' at address %s", 409 m_source_name.GetCString(), s.GetData()); 410 } 411 else 412 { 413 log->Printf ("UnwindPlan is invalid -- no CFA register defined in row 0 for UnwindPlan '%s'", 414 m_source_name.GetCString()); 415 } 416 } 417 return false; 418 } 419 420 if (!m_plan_valid_address_range.GetBaseAddress().IsValid() || 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 432void 433UnwindPlan::Dump (Stream& s, Thread *thread, lldb::addr_t base_addr) const 434{ 435 if (!m_source_name.IsEmpty()) 436 { 437 s.Printf ("This UnwindPlan originally sourced from %s\n", m_source_name.GetCString()); 438 } 439 if (m_plan_valid_address_range.GetBaseAddress().IsValid() && m_plan_valid_address_range.GetByteSize() > 0) 440 { 441 s.PutCString ("Address range of this UnwindPlan: "); 442 TargetSP target_sp(thread->CalculateTarget()); 443 m_plan_valid_address_range.Dump (&s, target_sp.get(), Address::DumpStyleSectionNameOffset); 444 s.EOL(); 445 } 446 collection::const_iterator pos, begin = m_row_list.begin(), end = m_row_list.end(); 447 for (pos = begin; pos != end; ++pos) 448 { 449 s.Printf ("row[%u]: ", (uint32_t)std::distance (begin, pos)); 450 (*pos)->Dump(s, this, thread, base_addr); 451 } 452} 453 454void 455UnwindPlan::SetSourceName (const char *source) 456{ 457 m_source_name = ConstString (source); 458} 459 460ConstString 461UnwindPlan::GetSourceName () const 462{ 463 return m_source_name; 464} 465 466const RegisterInfo * 467UnwindPlan::GetRegisterInfo (Thread* thread, uint32_t unwind_reg) const 468{ 469 if (thread) 470 { 471 RegisterContext *reg_ctx = thread->GetRegisterContext().get(); 472 if (reg_ctx) 473 { 474 uint32_t reg; 475 if (m_register_kind == eRegisterKindLLDB) 476 reg = unwind_reg; 477 else 478 reg = reg_ctx->ConvertRegisterKindToRegisterNumber (m_register_kind, unwind_reg); 479 if (reg != LLDB_INVALID_REGNUM) 480 return reg_ctx->GetRegisterInfoAtIndex (reg); 481 } 482 } 483 return NULL; 484} 485 486