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 AbstractRegisterLocation { 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 isConstant // reg = constant 73 }; 74 AbstractRegisterLocation()75 AbstractRegisterLocation() : m_location() {} 76 77 bool operator==(const AbstractRegisterLocation &rhs) const; 78 79 bool operator!=(const AbstractRegisterLocation &rhs) const { 80 return !(*this == rhs); 81 } 82 SetUnspecified()83 void SetUnspecified() { m_type = unspecified; } 84 SetUndefined()85 void SetUndefined() { m_type = undefined; } 86 SetSame()87 void SetSame() { m_type = same; } 88 IsSame()89 bool IsSame() const { return m_type == same; } 90 IsUnspecified()91 bool IsUnspecified() const { return m_type == unspecified; } 92 IsUndefined()93 bool IsUndefined() const { return m_type == undefined; } 94 IsCFAPlusOffset()95 bool IsCFAPlusOffset() const { return m_type == isCFAPlusOffset; } 96 IsAtCFAPlusOffset()97 bool IsAtCFAPlusOffset() const { return m_type == atCFAPlusOffset; } 98 IsAFAPlusOffset()99 bool IsAFAPlusOffset() const { return m_type == isAFAPlusOffset; } 100 IsAtAFAPlusOffset()101 bool IsAtAFAPlusOffset() const { return m_type == atAFAPlusOffset; } 102 IsInOtherRegister()103 bool IsInOtherRegister() const { return m_type == inOtherRegister; } 104 IsAtDWARFExpression()105 bool IsAtDWARFExpression() const { return m_type == atDWARFExpression; } 106 IsDWARFExpression()107 bool IsDWARFExpression() const { return m_type == isDWARFExpression; } 108 IsConstant()109 bool IsConstant() const { return m_type == isConstant; } 110 SetIsConstant(uint64_t value)111 void SetIsConstant(uint64_t value) { 112 m_type = isConstant; 113 m_location.constant_value = value; 114 } 115 GetConstant()116 uint64_t GetConstant() const { return m_location.constant_value; } 117 SetAtCFAPlusOffset(int32_t offset)118 void SetAtCFAPlusOffset(int32_t offset) { 119 m_type = atCFAPlusOffset; 120 m_location.offset = offset; 121 } 122 SetIsCFAPlusOffset(int32_t offset)123 void SetIsCFAPlusOffset(int32_t offset) { 124 m_type = isCFAPlusOffset; 125 m_location.offset = offset; 126 } 127 SetAtAFAPlusOffset(int32_t offset)128 void SetAtAFAPlusOffset(int32_t offset) { 129 m_type = atAFAPlusOffset; 130 m_location.offset = offset; 131 } 132 SetIsAFAPlusOffset(int32_t offset)133 void SetIsAFAPlusOffset(int32_t offset) { 134 m_type = isAFAPlusOffset; 135 m_location.offset = offset; 136 } 137 SetInRegister(uint32_t reg_num)138 void SetInRegister(uint32_t reg_num) { 139 m_type = inOtherRegister; 140 m_location.reg_num = reg_num; 141 } 142 GetRegisterNumber()143 uint32_t GetRegisterNumber() const { 144 if (m_type == inOtherRegister) 145 return m_location.reg_num; 146 return LLDB_INVALID_REGNUM; 147 } 148 GetLocationType()149 RestoreType GetLocationType() const { return m_type; } 150 GetOffset()151 int32_t GetOffset() const { 152 switch(m_type) 153 { 154 case atCFAPlusOffset: 155 case isCFAPlusOffset: 156 case atAFAPlusOffset: 157 case isAFAPlusOffset: 158 return m_location.offset; 159 default: 160 return 0; 161 } 162 } 163 GetDWARFExpr(const uint8_t ** opcodes,uint16_t & len)164 void GetDWARFExpr(const uint8_t **opcodes, uint16_t &len) const { 165 if (m_type == atDWARFExpression || m_type == isDWARFExpression) { 166 *opcodes = m_location.expr.opcodes; 167 len = m_location.expr.length; 168 } else { 169 *opcodes = nullptr; 170 len = 0; 171 } 172 } 173 174 void SetAtDWARFExpression(const uint8_t *opcodes, uint32_t len); 175 176 void SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len); 177 GetDWARFExpressionBytes()178 const uint8_t *GetDWARFExpressionBytes() const { 179 if (m_type == atDWARFExpression || m_type == isDWARFExpression) 180 return m_location.expr.opcodes; 181 return nullptr; 182 } 183 GetDWARFExpressionLength()184 int GetDWARFExpressionLength() const { 185 if (m_type == atDWARFExpression || m_type == isDWARFExpression) 186 return m_location.expr.length; 187 return 0; 188 } 189 190 void Dump(Stream &s, const UnwindPlan *unwind_plan, 191 const UnwindPlan::Row *row, Thread *thread, bool verbose) const; 192 193 private: 194 RestoreType m_type = unspecified; // How do we locate this register? 195 union { 196 // For m_type == atCFAPlusOffset or m_type == isCFAPlusOffset 197 int32_t offset; 198 // For m_type == inOtherRegister 199 uint32_t reg_num; // The register number 200 // For m_type == atDWARFExpression or m_type == isDWARFExpression 201 struct { 202 const uint8_t *opcodes; 203 uint16_t length; 204 } expr; 205 // For m_type == isConstant 206 uint64_t constant_value; 207 } m_location; 208 }; 209 210 class FAValue { 211 public: 212 enum ValueType { 213 unspecified, // not specified 214 isRegisterPlusOffset, // FA = register + offset 215 isRegisterDereferenced, // FA = [reg] 216 isDWARFExpression, // FA = eval(dwarf_expr) 217 isRaSearch, // FA = SP + offset + ??? 218 isConstant, // FA = constant 219 }; 220 FAValue()221 FAValue() : m_value() {} 222 223 bool operator==(const FAValue &rhs) const; 224 225 bool operator!=(const FAValue &rhs) const { return !(*this == rhs); } 226 SetUnspecified()227 void SetUnspecified() { m_type = unspecified; } 228 IsUnspecified()229 bool IsUnspecified() const { return m_type == unspecified; } 230 SetRaSearch(int32_t offset)231 void SetRaSearch(int32_t offset) { 232 m_type = isRaSearch; 233 m_value.ra_search_offset = offset; 234 } 235 IsRegisterPlusOffset()236 bool IsRegisterPlusOffset() const { 237 return m_type == isRegisterPlusOffset; 238 } 239 SetIsRegisterPlusOffset(uint32_t reg_num,int32_t offset)240 void SetIsRegisterPlusOffset(uint32_t reg_num, int32_t offset) { 241 m_type = isRegisterPlusOffset; 242 m_value.reg.reg_num = reg_num; 243 m_value.reg.offset = offset; 244 } 245 IsRegisterDereferenced()246 bool IsRegisterDereferenced() const { 247 return m_type == isRegisterDereferenced; 248 } 249 SetIsRegisterDereferenced(uint32_t reg_num)250 void SetIsRegisterDereferenced(uint32_t reg_num) { 251 m_type = isRegisterDereferenced; 252 m_value.reg.reg_num = reg_num; 253 } 254 IsDWARFExpression()255 bool IsDWARFExpression() const { return m_type == isDWARFExpression; } 256 SetIsDWARFExpression(const uint8_t * opcodes,uint32_t len)257 void SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len) { 258 m_type = isDWARFExpression; 259 m_value.expr.opcodes = opcodes; 260 m_value.expr.length = len; 261 } 262 IsConstant()263 bool IsConstant() const { return m_type == isConstant; } 264 SetIsConstant(uint64_t constant)265 void SetIsConstant(uint64_t constant) { 266 m_type = isConstant; 267 m_value.constant = constant; 268 } 269 GetConstant()270 uint64_t GetConstant() const { return m_value.constant; } 271 GetRegisterNumber()272 uint32_t GetRegisterNumber() const { 273 if (m_type == isRegisterDereferenced || m_type == isRegisterPlusOffset) 274 return m_value.reg.reg_num; 275 return LLDB_INVALID_REGNUM; 276 } 277 GetValueType()278 ValueType GetValueType() const { return m_type; } 279 GetOffset()280 int32_t GetOffset() const { 281 switch (m_type) { 282 case isRegisterPlusOffset: 283 return m_value.reg.offset; 284 case isRaSearch: 285 return m_value.ra_search_offset; 286 default: 287 return 0; 288 } 289 } 290 IncOffset(int32_t delta)291 void IncOffset(int32_t delta) { 292 if (m_type == isRegisterPlusOffset) 293 m_value.reg.offset += delta; 294 } 295 SetOffset(int32_t offset)296 void SetOffset(int32_t offset) { 297 if (m_type == isRegisterPlusOffset) 298 m_value.reg.offset = offset; 299 } 300 GetDWARFExpr(const uint8_t ** opcodes,uint16_t & len)301 void GetDWARFExpr(const uint8_t **opcodes, uint16_t &len) const { 302 if (m_type == isDWARFExpression) { 303 *opcodes = m_value.expr.opcodes; 304 len = m_value.expr.length; 305 } else { 306 *opcodes = nullptr; 307 len = 0; 308 } 309 } 310 GetDWARFExpressionBytes()311 const uint8_t *GetDWARFExpressionBytes() const { 312 if (m_type == isDWARFExpression) 313 return m_value.expr.opcodes; 314 return nullptr; 315 } 316 GetDWARFExpressionLength()317 int GetDWARFExpressionLength() const { 318 if (m_type == isDWARFExpression) 319 return m_value.expr.length; 320 return 0; 321 } 322 323 void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread) const; 324 325 private: 326 ValueType m_type = unspecified; // How do we compute CFA value? 327 union { 328 struct { 329 // For m_type == isRegisterPlusOffset or m_type == 330 // isRegisterDereferenced 331 uint32_t reg_num; // The register number 332 // For m_type == isRegisterPlusOffset 333 int32_t offset; 334 } reg; 335 // For m_type == isDWARFExpression 336 struct { 337 const uint8_t *opcodes; 338 uint16_t length; 339 } expr; 340 // For m_type == isRaSearch 341 int32_t ra_search_offset; 342 // For m_type = isConstant 343 uint64_t constant; 344 } m_value; 345 }; // class FAValue 346 347 Row(); 348 349 bool operator==(const Row &rhs) const; 350 351 bool GetRegisterInfo(uint32_t reg_num, 352 AbstractRegisterLocation ®ister_location) const; 353 354 void SetRegisterInfo(uint32_t reg_num, 355 const AbstractRegisterLocation register_location); 356 357 void RemoveRegisterInfo(uint32_t reg_num); 358 GetOffset()359 int64_t GetOffset() const { return m_offset; } 360 SetOffset(int64_t offset)361 void SetOffset(int64_t offset) { m_offset = offset; } 362 SlideOffset(int64_t offset)363 void SlideOffset(int64_t offset) { m_offset += offset; } 364 GetCFAValue()365 const FAValue &GetCFAValue() const { return m_cfa_value; } GetCFAValue()366 FAValue &GetCFAValue() { return m_cfa_value; } 367 GetAFAValue()368 const FAValue &GetAFAValue() const { return m_afa_value; } GetAFAValue()369 FAValue &GetAFAValue() { return m_afa_value; } 370 371 bool SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num, int32_t offset, 372 bool can_replace); 373 374 bool SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num, int32_t offset, 375 bool can_replace); 376 377 bool SetRegisterLocationToUndefined(uint32_t reg_num, bool can_replace, 378 bool can_replace_only_if_unspecified); 379 380 bool SetRegisterLocationToUnspecified(uint32_t reg_num, bool can_replace); 381 382 bool SetRegisterLocationToRegister(uint32_t reg_num, uint32_t other_reg_num, 383 bool can_replace); 384 385 bool SetRegisterLocationToSame(uint32_t reg_num, bool must_replace); 386 387 /// This method does not make a copy of the \a opcodes memory, it is 388 /// assumed to have the same lifetime as the Module this UnwindPlan will 389 /// be registered in. 390 bool SetRegisterLocationToIsDWARFExpression(uint32_t reg_num, 391 const uint8_t *opcodes, 392 uint32_t len, bool can_replace); 393 394 bool SetRegisterLocationToIsConstant(uint32_t reg_num, uint64_t constant, 395 bool can_replace); 396 397 // When this UnspecifiedRegistersAreUndefined mode is 398 // set, any register that is not specified by this Row will 399 // be described as Undefined. 400 // This will prevent the unwinder from iterating down the 401 // stack looking for a spill location, or a live register value 402 // at frame 0. 403 // It would be used for an UnwindPlan row where we can't track 404 // spilled registers -- for instance a jitted stack frame where 405 // we have no unwind information or start address -- and registers 406 // MAY have been spilled and overwritten, so providing the 407 // spilled/live value from a newer frame may show an incorrect value. SetUnspecifiedRegistersAreUndefined(bool unspec_is_undef)408 void SetUnspecifiedRegistersAreUndefined(bool unspec_is_undef) { 409 m_unspecified_registers_are_undefined = unspec_is_undef; 410 } 411 GetUnspecifiedRegistersAreUndefined()412 bool GetUnspecifiedRegistersAreUndefined() { 413 return m_unspecified_registers_are_undefined; 414 } 415 416 void Clear(); 417 418 void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread, 419 lldb::addr_t base_addr) const; 420 421 protected: 422 typedef std::map<uint32_t, AbstractRegisterLocation> collection; 423 int64_t m_offset = 0; // Offset into the function for this row 424 425 FAValue m_cfa_value; 426 FAValue m_afa_value; 427 collection m_register_locations; 428 bool m_unspecified_registers_are_undefined = false; 429 }; // class Row 430 UnwindPlan(lldb::RegisterKind reg_kind)431 UnwindPlan(lldb::RegisterKind reg_kind) 432 : m_register_kind(reg_kind), m_return_addr_register(LLDB_INVALID_REGNUM), 433 m_plan_is_sourced_from_compiler(eLazyBoolCalculate), 434 m_plan_is_valid_at_all_instruction_locations(eLazyBoolCalculate), 435 m_plan_is_for_signal_trap(eLazyBoolCalculate) {} 436 437 // Performs a deep copy of the plan, including all the rows (expensive). 438 UnwindPlan(const UnwindPlan &rhs) = default; 439 UnwindPlan &operator=(const UnwindPlan &rhs) = default; 440 441 UnwindPlan(UnwindPlan &&rhs) = default; 442 UnwindPlan &operator=(UnwindPlan &&) = default; 443 444 ~UnwindPlan() = default; 445 446 void Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const; 447 448 void AppendRow(Row row); 449 450 void InsertRow(Row row, bool replace_existing = false); 451 452 // Returns a pointer to the best row for the given offset into the function's 453 // instructions. If offset is std::nullopt it indicates that the function 454 // start is unknown - the final row in the UnwindPlan is returned. In 455 // practice, the UnwindPlan for a function with no known start address will be 456 // the architectural default UnwindPlan which will only have one row. 457 const UnwindPlan::Row * 458 GetRowForFunctionOffset(std::optional<int64_t> offset) const; 459 GetRegisterKind()460 lldb::RegisterKind GetRegisterKind() const { return m_register_kind; } 461 SetRegisterKind(lldb::RegisterKind kind)462 void SetRegisterKind(lldb::RegisterKind kind) { m_register_kind = kind; } 463 SetReturnAddressRegister(uint32_t regnum)464 void SetReturnAddressRegister(uint32_t regnum) { 465 m_return_addr_register = regnum; 466 } 467 GetReturnAddressRegister()468 uint32_t GetReturnAddressRegister() const { return m_return_addr_register; } 469 GetInitialCFARegister()470 uint32_t GetInitialCFARegister() const { 471 if (m_row_list.empty()) 472 return LLDB_INVALID_REGNUM; 473 return m_row_list.front().GetCFAValue().GetRegisterNumber(); 474 } 475 476 // This UnwindPlan may not be valid at every address of the function span. 477 // For instance, a FastUnwindPlan will not be valid at the prologue setup 478 // instructions - only in the body of the function. SetPlanValidAddressRanges(std::vector<AddressRange> ranges)479 void SetPlanValidAddressRanges(std::vector<AddressRange> ranges) { 480 m_plan_valid_ranges = std::move(ranges); 481 } 482 483 bool PlanValidAtAddress(Address addr) const; 484 485 bool IsValidRowIndex(uint32_t idx) const; 486 487 const UnwindPlan::Row *GetRowAtIndex(uint32_t idx) const; 488 489 const UnwindPlan::Row *GetLastRow() const; 490 491 lldb_private::ConstString GetSourceName() const; 492 493 void SetSourceName(const char *); 494 495 // Was this UnwindPlan emitted by a compiler? GetSourcedFromCompiler()496 lldb_private::LazyBool GetSourcedFromCompiler() const { 497 return m_plan_is_sourced_from_compiler; 498 } 499 500 // Was this UnwindPlan emitted by a compiler? SetSourcedFromCompiler(lldb_private::LazyBool from_compiler)501 void SetSourcedFromCompiler(lldb_private::LazyBool from_compiler) { 502 m_plan_is_sourced_from_compiler = from_compiler; 503 } 504 505 // Is this UnwindPlan valid at all instructions? If not, then it is assumed 506 // valid at call sites, e.g. for exception handling. GetUnwindPlanValidAtAllInstructions()507 lldb_private::LazyBool GetUnwindPlanValidAtAllInstructions() const { 508 return m_plan_is_valid_at_all_instruction_locations; 509 } 510 511 // Is this UnwindPlan valid at all instructions? If not, then it is assumed 512 // valid at call sites, e.g. for exception handling. SetUnwindPlanValidAtAllInstructions(lldb_private::LazyBool valid_at_all_insn)513 void SetUnwindPlanValidAtAllInstructions( 514 lldb_private::LazyBool valid_at_all_insn) { 515 m_plan_is_valid_at_all_instruction_locations = valid_at_all_insn; 516 } 517 518 // Is this UnwindPlan for a signal trap frame? If so, then its saved pc 519 // may have been set manually by the signal dispatch code and therefore 520 // not follow a call to the child frame. GetUnwindPlanForSignalTrap()521 lldb_private::LazyBool GetUnwindPlanForSignalTrap() const { 522 return m_plan_is_for_signal_trap; 523 } 524 SetUnwindPlanForSignalTrap(lldb_private::LazyBool is_for_signal_trap)525 void SetUnwindPlanForSignalTrap(lldb_private::LazyBool is_for_signal_trap) { 526 m_plan_is_for_signal_trap = is_for_signal_trap; 527 } 528 GetRowCount()529 int GetRowCount() const { return m_row_list.size(); } 530 Clear()531 void Clear() { 532 m_row_list.clear(); 533 m_plan_valid_ranges.clear(); 534 m_register_kind = lldb::eRegisterKindDWARF; 535 m_source_name.Clear(); 536 m_plan_is_sourced_from_compiler = eLazyBoolCalculate; 537 m_plan_is_valid_at_all_instruction_locations = eLazyBoolCalculate; 538 m_plan_is_for_signal_trap = eLazyBoolCalculate; 539 } 540 541 const RegisterInfo *GetRegisterInfo(Thread *thread, uint32_t reg_num) const; 542 543 private: 544 std::vector<Row> m_row_list; 545 std::vector<AddressRange> m_plan_valid_ranges; 546 lldb::RegisterKind m_register_kind; // The RegisterKind these register numbers 547 // are in terms of - will need to be 548 // translated to lldb native reg nums at unwind time 549 uint32_t m_return_addr_register; // The register that has the return address 550 // for the caller frame 551 // e.g. the lr on arm 552 lldb_private::ConstString 553 m_source_name; // for logging, where this UnwindPlan originated from 554 lldb_private::LazyBool m_plan_is_sourced_from_compiler; 555 lldb_private::LazyBool m_plan_is_valid_at_all_instruction_locations; 556 lldb_private::LazyBool m_plan_is_for_signal_trap; 557 }; // class UnwindPlan 558 559 } // namespace lldb_private 560 561 #endif // LLDB_SYMBOL_UNWINDPLAN_H 562