1 //===-- UnwindPlan.h --------------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLDB_SYMBOL_UNWINDPLAN_H 10 #define LLDB_SYMBOL_UNWINDPLAN_H 11 12 #include <map> 13 #include <memory> 14 #include <vector> 15 16 #include "lldb/Core/AddressRange.h" 17 #include "lldb/Utility/ConstString.h" 18 #include "lldb/Utility/Stream.h" 19 #include "lldb/lldb-private.h" 20 21 namespace lldb_private { 22 23 // The UnwindPlan object specifies how to unwind out of a function - where this 24 // function saves the caller's register values before modifying them (for non- 25 // volatile aka saved registers) and how to find this frame's Canonical Frame 26 // Address (CFA) or Aligned Frame Address (AFA). 27 28 // CFA is a DWARF's Canonical Frame Address. 29 // Most commonly, registers are saved on the stack, offset some bytes from the 30 // Canonical Frame Address, or CFA, which is the starting address of this 31 // function's stack frame (the CFA is same as the eh_frame's CFA, whatever that 32 // may be on a given architecture). The CFA address for the stack frame does 33 // not change during the lifetime of the function. 34 35 // AFA is an artificially introduced Aligned Frame Address. 36 // It is used only for stack frames with realignment (e.g. when some of the 37 // locals has an alignment requirement higher than the stack alignment right 38 // after the function call). It is used to access register values saved on the 39 // stack after the realignment (and so they are inaccessible through the CFA). 40 // AFA usually equals the stack pointer value right after the realignment. 41 42 // Internally, the UnwindPlan is structured as a vector of register locations 43 // organized by code address in the function, showing which registers have been 44 // saved at that point and where they are saved. It can be thought of as the 45 // expanded table form of the DWARF CFI encoded information. 46 47 // Other unwind information sources will be converted into UnwindPlans before 48 // being added to a FuncUnwinders object. The unwind source may be an eh_frame 49 // FDE, a DWARF debug_frame FDE, or assembly language based prologue analysis. 50 // The UnwindPlan is the canonical form of this information that the unwinder 51 // code will use when walking the stack. 52 53 class UnwindPlan { 54 public: 55 class Row { 56 public: 57 class RegisterLocation { 58 public: 59 enum RestoreType { 60 unspecified, // not specified, we may be able to assume this 61 // is the same register. gcc doesn't specify all 62 // initial values so we really don't know... 63 undefined, // reg is not available, e.g. volatile reg 64 same, // reg is unchanged 65 atCFAPlusOffset, // reg = deref(CFA + offset) 66 isCFAPlusOffset, // reg = CFA + offset 67 atAFAPlusOffset, // reg = deref(AFA + offset) 68 isAFAPlusOffset, // reg = AFA + offset 69 inOtherRegister, // reg = other reg 70 atDWARFExpression, // reg = deref(eval(dwarf_expr)) 71 isDWARFExpression // reg = eval(dwarf_expr) 72 }; 73 RegisterLocation()74 RegisterLocation() : m_location() {} 75 76 bool operator==(const RegisterLocation &rhs) const; 77 78 bool operator!=(const RegisterLocation &rhs) const { 79 return !(*this == rhs); 80 } 81 SetUnspecified()82 void SetUnspecified() { m_type = unspecified; } 83 SetUndefined()84 void SetUndefined() { m_type = undefined; } 85 SetSame()86 void SetSame() { m_type = same; } 87 IsSame()88 bool IsSame() const { return m_type == same; } 89 IsUnspecified()90 bool IsUnspecified() const { return m_type == unspecified; } 91 IsUndefined()92 bool IsUndefined() const { return m_type == undefined; } 93 IsCFAPlusOffset()94 bool IsCFAPlusOffset() const { return m_type == isCFAPlusOffset; } 95 IsAtCFAPlusOffset()96 bool IsAtCFAPlusOffset() const { return m_type == atCFAPlusOffset; } 97 IsAFAPlusOffset()98 bool IsAFAPlusOffset() const { return m_type == isAFAPlusOffset; } 99 IsAtAFAPlusOffset()100 bool IsAtAFAPlusOffset() const { return m_type == atAFAPlusOffset; } 101 IsInOtherRegister()102 bool IsInOtherRegister() const { return m_type == inOtherRegister; } 103 IsAtDWARFExpression()104 bool IsAtDWARFExpression() const { return m_type == atDWARFExpression; } 105 IsDWARFExpression()106 bool IsDWARFExpression() const { return m_type == isDWARFExpression; } 107 SetAtCFAPlusOffset(int32_t offset)108 void SetAtCFAPlusOffset(int32_t offset) { 109 m_type = atCFAPlusOffset; 110 m_location.offset = offset; 111 } 112 SetIsCFAPlusOffset(int32_t offset)113 void SetIsCFAPlusOffset(int32_t offset) { 114 m_type = isCFAPlusOffset; 115 m_location.offset = offset; 116 } 117 SetAtAFAPlusOffset(int32_t offset)118 void SetAtAFAPlusOffset(int32_t offset) { 119 m_type = atAFAPlusOffset; 120 m_location.offset = offset; 121 } 122 SetIsAFAPlusOffset(int32_t offset)123 void SetIsAFAPlusOffset(int32_t offset) { 124 m_type = isAFAPlusOffset; 125 m_location.offset = offset; 126 } 127 SetInRegister(uint32_t reg_num)128 void SetInRegister(uint32_t reg_num) { 129 m_type = inOtherRegister; 130 m_location.reg_num = reg_num; 131 } 132 GetRegisterNumber()133 uint32_t GetRegisterNumber() const { 134 if (m_type == inOtherRegister) 135 return m_location.reg_num; 136 return LLDB_INVALID_REGNUM; 137 } 138 GetLocationType()139 RestoreType GetLocationType() const { return m_type; } 140 GetOffset()141 int32_t GetOffset() const { 142 switch(m_type) 143 { 144 case atCFAPlusOffset: 145 case isCFAPlusOffset: 146 case atAFAPlusOffset: 147 case isAFAPlusOffset: 148 return m_location.offset; 149 default: 150 return 0; 151 } 152 } 153 GetDWARFExpr(const uint8_t ** opcodes,uint16_t & len)154 void GetDWARFExpr(const uint8_t **opcodes, uint16_t &len) const { 155 if (m_type == atDWARFExpression || m_type == isDWARFExpression) { 156 *opcodes = m_location.expr.opcodes; 157 len = m_location.expr.length; 158 } else { 159 *opcodes = nullptr; 160 len = 0; 161 } 162 } 163 164 void SetAtDWARFExpression(const uint8_t *opcodes, uint32_t len); 165 166 void SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len); 167 GetDWARFExpressionBytes()168 const uint8_t *GetDWARFExpressionBytes() { 169 if (m_type == atDWARFExpression || m_type == isDWARFExpression) 170 return m_location.expr.opcodes; 171 return nullptr; 172 } 173 GetDWARFExpressionLength()174 int GetDWARFExpressionLength() { 175 if (m_type == atDWARFExpression || m_type == isDWARFExpression) 176 return m_location.expr.length; 177 return 0; 178 } 179 180 void Dump(Stream &s, const UnwindPlan *unwind_plan, 181 const UnwindPlan::Row *row, Thread *thread, bool verbose) const; 182 183 private: 184 RestoreType m_type = unspecified; // How do we locate this register? 185 union { 186 // For m_type == atCFAPlusOffset or m_type == isCFAPlusOffset 187 int32_t offset; 188 // For m_type == inOtherRegister 189 uint32_t reg_num; // The register number 190 // For m_type == atDWARFExpression or m_type == isDWARFExpression 191 struct { 192 const uint8_t *opcodes; 193 uint16_t length; 194 } expr; 195 } m_location; 196 }; 197 198 class FAValue { 199 public: 200 enum ValueType { 201 unspecified, // not specified 202 isRegisterPlusOffset, // FA = register + offset 203 isRegisterDereferenced, // FA = [reg] 204 isDWARFExpression, // FA = eval(dwarf_expr) 205 isRaSearch, // FA = SP + offset + ??? 206 }; 207 FAValue()208 FAValue() : m_value() {} 209 210 bool operator==(const FAValue &rhs) const; 211 212 bool operator!=(const FAValue &rhs) const { return !(*this == rhs); } 213 SetUnspecified()214 void SetUnspecified() { m_type = unspecified; } 215 IsUnspecified()216 bool IsUnspecified() const { return m_type == unspecified; } 217 SetRaSearch(int32_t offset)218 void SetRaSearch(int32_t offset) { 219 m_type = isRaSearch; 220 m_value.ra_search_offset = offset; 221 } 222 IsRegisterPlusOffset()223 bool IsRegisterPlusOffset() const { 224 return m_type == isRegisterPlusOffset; 225 } 226 SetIsRegisterPlusOffset(uint32_t reg_num,int32_t offset)227 void SetIsRegisterPlusOffset(uint32_t reg_num, int32_t offset) { 228 m_type = isRegisterPlusOffset; 229 m_value.reg.reg_num = reg_num; 230 m_value.reg.offset = offset; 231 } 232 IsRegisterDereferenced()233 bool IsRegisterDereferenced() const { 234 return m_type == isRegisterDereferenced; 235 } 236 SetIsRegisterDereferenced(uint32_t reg_num)237 void SetIsRegisterDereferenced(uint32_t reg_num) { 238 m_type = isRegisterDereferenced; 239 m_value.reg.reg_num = reg_num; 240 } 241 IsDWARFExpression()242 bool IsDWARFExpression() const { return m_type == isDWARFExpression; } 243 SetIsDWARFExpression(const uint8_t * opcodes,uint32_t len)244 void SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len) { 245 m_type = isDWARFExpression; 246 m_value.expr.opcodes = opcodes; 247 m_value.expr.length = len; 248 } 249 GetRegisterNumber()250 uint32_t GetRegisterNumber() const { 251 if (m_type == isRegisterDereferenced || m_type == isRegisterPlusOffset) 252 return m_value.reg.reg_num; 253 return LLDB_INVALID_REGNUM; 254 } 255 GetValueType()256 ValueType GetValueType() const { return m_type; } 257 GetOffset()258 int32_t GetOffset() const { 259 switch (m_type) { 260 case isRegisterPlusOffset: 261 return m_value.reg.offset; 262 case isRaSearch: 263 return m_value.ra_search_offset; 264 default: 265 return 0; 266 } 267 } 268 IncOffset(int32_t delta)269 void IncOffset(int32_t delta) { 270 if (m_type == isRegisterPlusOffset) 271 m_value.reg.offset += delta; 272 } 273 SetOffset(int32_t offset)274 void SetOffset(int32_t offset) { 275 if (m_type == isRegisterPlusOffset) 276 m_value.reg.offset = offset; 277 } 278 GetDWARFExpr(const uint8_t ** opcodes,uint16_t & len)279 void GetDWARFExpr(const uint8_t **opcodes, uint16_t &len) const { 280 if (m_type == isDWARFExpression) { 281 *opcodes = m_value.expr.opcodes; 282 len = m_value.expr.length; 283 } else { 284 *opcodes = nullptr; 285 len = 0; 286 } 287 } 288 GetDWARFExpressionBytes()289 const uint8_t *GetDWARFExpressionBytes() { 290 if (m_type == isDWARFExpression) 291 return m_value.expr.opcodes; 292 return nullptr; 293 } 294 GetDWARFExpressionLength()295 int GetDWARFExpressionLength() { 296 if (m_type == isDWARFExpression) 297 return m_value.expr.length; 298 return 0; 299 } 300 301 void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread) const; 302 303 private: 304 ValueType m_type = unspecified; // How do we compute CFA value? 305 union { 306 struct { 307 // For m_type == isRegisterPlusOffset or m_type == 308 // isRegisterDereferenced 309 uint32_t reg_num; // The register number 310 // For m_type == isRegisterPlusOffset 311 int32_t offset; 312 } reg; 313 // For m_type == isDWARFExpression 314 struct { 315 const uint8_t *opcodes; 316 uint16_t length; 317 } expr; 318 // For m_type == isRaSearch 319 int32_t ra_search_offset; 320 } m_value; 321 }; // class FAValue 322 323 Row(); 324 325 bool operator==(const Row &rhs) const; 326 327 bool GetRegisterInfo(uint32_t reg_num, 328 RegisterLocation ®ister_location) const; 329 330 void SetRegisterInfo(uint32_t reg_num, 331 const RegisterLocation register_location); 332 333 void RemoveRegisterInfo(uint32_t reg_num); 334 GetOffset()335 lldb::addr_t GetOffset() const { return m_offset; } 336 SetOffset(lldb::addr_t offset)337 void SetOffset(lldb::addr_t offset) { m_offset = offset; } 338 SlideOffset(lldb::addr_t offset)339 void SlideOffset(lldb::addr_t offset) { m_offset += offset; } 340 GetCFAValue()341 FAValue &GetCFAValue() { return m_cfa_value; } 342 GetAFAValue()343 FAValue &GetAFAValue() { return m_afa_value; } 344 345 bool SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num, int32_t offset, 346 bool can_replace); 347 348 bool SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num, int32_t offset, 349 bool can_replace); 350 351 bool SetRegisterLocationToUndefined(uint32_t reg_num, bool can_replace, 352 bool can_replace_only_if_unspecified); 353 354 bool SetRegisterLocationToUnspecified(uint32_t reg_num, bool can_replace); 355 356 bool SetRegisterLocationToRegister(uint32_t reg_num, uint32_t other_reg_num, 357 bool can_replace); 358 359 bool SetRegisterLocationToSame(uint32_t reg_num, bool must_replace); 360 361 // When this UnspecifiedRegistersAreUndefined mode is 362 // set, any register that is not specified by this Row will 363 // be described as Undefined. 364 // This will prevent the unwinder from iterating down the 365 // stack looking for a spill location, or a live register value 366 // at frame 0. 367 // It would be used for an UnwindPlan row where we can't track 368 // spilled registers -- for instance a jitted stack frame where 369 // we have no unwind information or start address -- and registers 370 // MAY have been spilled and overwritten, so providing the 371 // spilled/live value from a newer frame may show an incorrect value. SetUnspecifiedRegistersAreUndefined(bool unspec_is_undef)372 void SetUnspecifiedRegistersAreUndefined(bool unspec_is_undef) { 373 m_unspecified_registers_are_undefined = unspec_is_undef; 374 } 375 GetUnspecifiedRegistersAreUndefined()376 bool GetUnspecifiedRegistersAreUndefined() { 377 return m_unspecified_registers_are_undefined; 378 } 379 380 void Clear(); 381 382 void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread, 383 lldb::addr_t base_addr) const; 384 385 protected: 386 typedef std::map<uint32_t, RegisterLocation> collection; 387 lldb::addr_t m_offset = 0; // Offset into the function for this row 388 389 FAValue m_cfa_value; 390 FAValue m_afa_value; 391 collection m_register_locations; 392 bool m_unspecified_registers_are_undefined = false; 393 }; // class Row 394 395 typedef std::shared_ptr<Row> RowSP; 396 UnwindPlan(lldb::RegisterKind reg_kind)397 UnwindPlan(lldb::RegisterKind reg_kind) 398 : m_register_kind(reg_kind), m_return_addr_register(LLDB_INVALID_REGNUM), 399 m_plan_is_sourced_from_compiler(eLazyBoolCalculate), 400 m_plan_is_valid_at_all_instruction_locations(eLazyBoolCalculate), 401 m_plan_is_for_signal_trap(eLazyBoolCalculate) {} 402 403 // Performs a deep copy of the plan, including all the rows (expensive). UnwindPlan(const UnwindPlan & rhs)404 UnwindPlan(const UnwindPlan &rhs) 405 : m_plan_valid_address_range(rhs.m_plan_valid_address_range), 406 m_register_kind(rhs.m_register_kind), 407 m_return_addr_register(rhs.m_return_addr_register), 408 m_source_name(rhs.m_source_name), 409 m_plan_is_sourced_from_compiler(rhs.m_plan_is_sourced_from_compiler), 410 m_plan_is_valid_at_all_instruction_locations( 411 rhs.m_plan_is_valid_at_all_instruction_locations), 412 m_plan_is_for_signal_trap(rhs.m_plan_is_for_signal_trap), 413 m_lsda_address(rhs.m_lsda_address), 414 m_personality_func_addr(rhs.m_personality_func_addr) { 415 m_row_list.reserve(rhs.m_row_list.size()); 416 for (const RowSP &row_sp : rhs.m_row_list) 417 m_row_list.emplace_back(new Row(*row_sp)); 418 } 419 420 ~UnwindPlan() = default; 421 422 void Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const; 423 424 void AppendRow(const RowSP &row_sp); 425 426 void InsertRow(const RowSP &row_sp, bool replace_existing = false); 427 428 // Returns a pointer to the best row for the given offset into the function's 429 // instructions. If offset is -1 it indicates that the function start is 430 // unknown - the final row in the UnwindPlan is returned. In practice, the 431 // UnwindPlan for a function with no known start address will be the 432 // architectural default UnwindPlan which will only have one row. 433 UnwindPlan::RowSP GetRowForFunctionOffset(int offset) const; 434 GetRegisterKind()435 lldb::RegisterKind GetRegisterKind() const { return m_register_kind; } 436 SetRegisterKind(lldb::RegisterKind kind)437 void SetRegisterKind(lldb::RegisterKind kind) { m_register_kind = kind; } 438 SetReturnAddressRegister(uint32_t regnum)439 void SetReturnAddressRegister(uint32_t regnum) { 440 m_return_addr_register = regnum; 441 } 442 GetReturnAddressRegister()443 uint32_t GetReturnAddressRegister() { return m_return_addr_register; } 444 GetInitialCFARegister()445 uint32_t GetInitialCFARegister() const { 446 if (m_row_list.empty()) 447 return LLDB_INVALID_REGNUM; 448 return m_row_list.front()->GetCFAValue().GetRegisterNumber(); 449 } 450 451 // This UnwindPlan may not be valid at every address of the function span. 452 // For instance, a FastUnwindPlan will not be valid at the prologue setup 453 // instructions - only in the body of the function. 454 void SetPlanValidAddressRange(const AddressRange &range); 455 GetAddressRange()456 const AddressRange &GetAddressRange() const { 457 return m_plan_valid_address_range; 458 } 459 460 bool PlanValidAtAddress(Address addr); 461 462 bool IsValidRowIndex(uint32_t idx) const; 463 464 const UnwindPlan::RowSP GetRowAtIndex(uint32_t idx) const; 465 466 const UnwindPlan::RowSP GetLastRow() const; 467 468 lldb_private::ConstString GetSourceName() const; 469 470 void SetSourceName(const char *); 471 472 // Was this UnwindPlan emitted by a compiler? GetSourcedFromCompiler()473 lldb_private::LazyBool GetSourcedFromCompiler() const { 474 return m_plan_is_sourced_from_compiler; 475 } 476 477 // Was this UnwindPlan emitted by a compiler? SetSourcedFromCompiler(lldb_private::LazyBool from_compiler)478 void SetSourcedFromCompiler(lldb_private::LazyBool from_compiler) { 479 m_plan_is_sourced_from_compiler = from_compiler; 480 } 481 482 // Is this UnwindPlan valid at all instructions? If not, then it is assumed 483 // valid at call sites, e.g. for exception handling. GetUnwindPlanValidAtAllInstructions()484 lldb_private::LazyBool GetUnwindPlanValidAtAllInstructions() const { 485 return m_plan_is_valid_at_all_instruction_locations; 486 } 487 488 // Is this UnwindPlan valid at all instructions? If not, then it is assumed 489 // valid at call sites, e.g. for exception handling. SetUnwindPlanValidAtAllInstructions(lldb_private::LazyBool valid_at_all_insn)490 void SetUnwindPlanValidAtAllInstructions( 491 lldb_private::LazyBool valid_at_all_insn) { 492 m_plan_is_valid_at_all_instruction_locations = valid_at_all_insn; 493 } 494 495 // Is this UnwindPlan for a signal trap frame? If so, then its saved pc 496 // may have been set manually by the signal dispatch code and therefore 497 // not follow a call to the child frame. GetUnwindPlanForSignalTrap()498 lldb_private::LazyBool GetUnwindPlanForSignalTrap() const { 499 return m_plan_is_for_signal_trap; 500 } 501 SetUnwindPlanForSignalTrap(lldb_private::LazyBool is_for_signal_trap)502 void SetUnwindPlanForSignalTrap(lldb_private::LazyBool is_for_signal_trap) { 503 m_plan_is_for_signal_trap = is_for_signal_trap; 504 } 505 506 int GetRowCount() const; 507 Clear()508 void Clear() { 509 m_row_list.clear(); 510 m_plan_valid_address_range.Clear(); 511 m_register_kind = lldb::eRegisterKindDWARF; 512 m_source_name.Clear(); 513 m_plan_is_sourced_from_compiler = eLazyBoolCalculate; 514 m_plan_is_valid_at_all_instruction_locations = eLazyBoolCalculate; 515 m_plan_is_for_signal_trap = eLazyBoolCalculate; 516 m_lsda_address.Clear(); 517 m_personality_func_addr.Clear(); 518 } 519 520 const RegisterInfo *GetRegisterInfo(Thread *thread, uint32_t reg_num) const; 521 GetLSDAAddress()522 Address GetLSDAAddress() const { return m_lsda_address; } 523 SetLSDAAddress(Address lsda_addr)524 void SetLSDAAddress(Address lsda_addr) { m_lsda_address = lsda_addr; } 525 GetPersonalityFunctionPtr()526 Address GetPersonalityFunctionPtr() const { return m_personality_func_addr; } 527 SetPersonalityFunctionPtr(Address presonality_func_ptr)528 void SetPersonalityFunctionPtr(Address presonality_func_ptr) { 529 m_personality_func_addr = presonality_func_ptr; 530 } 531 532 private: 533 typedef std::vector<RowSP> collection; 534 collection m_row_list; 535 AddressRange m_plan_valid_address_range; 536 lldb::RegisterKind m_register_kind; // The RegisterKind these register numbers 537 // are in terms of - will need to be 538 // translated to lldb native reg nums at unwind time 539 uint32_t m_return_addr_register; // The register that has the return address 540 // for the caller frame 541 // e.g. the lr on arm 542 lldb_private::ConstString 543 m_source_name; // for logging, where this UnwindPlan originated from 544 lldb_private::LazyBool m_plan_is_sourced_from_compiler; 545 lldb_private::LazyBool m_plan_is_valid_at_all_instruction_locations; 546 lldb_private::LazyBool m_plan_is_for_signal_trap; 547 548 Address m_lsda_address; // Where the language specific data area exists in the 549 // module - used 550 // in exception handling. 551 Address m_personality_func_addr; // The address of a pointer to the 552 // personality function - used in 553 // exception handling. 554 }; // class UnwindPlan 555 556 } // namespace lldb_private 557 558 #endif // LLDB_SYMBOL_UNWINDPLAN_H 559