Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:42:53

0001 //===-- UnwindPlan.h --------------------------------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 
0009 #ifndef LLDB_SYMBOL_UNWINDPLAN_H
0010 #define LLDB_SYMBOL_UNWINDPLAN_H
0011 
0012 #include <map>
0013 #include <memory>
0014 #include <vector>
0015 
0016 #include "lldb/Core/AddressRange.h"
0017 #include "lldb/Utility/ConstString.h"
0018 #include "lldb/Utility/Stream.h"
0019 #include "lldb/lldb-private.h"
0020 
0021 namespace lldb_private {
0022 
0023 // The UnwindPlan object specifies how to unwind out of a function - where this
0024 // function saves the caller's register values before modifying them (for non-
0025 // volatile aka saved registers) and how to find this frame's Canonical Frame
0026 // Address (CFA) or Aligned Frame Address (AFA).
0027 
0028 // CFA is a DWARF's Canonical Frame Address.
0029 // Most commonly, registers are saved on the stack, offset some bytes from the
0030 // Canonical Frame Address, or CFA, which is the starting address of this
0031 // function's stack frame (the CFA is same as the eh_frame's CFA, whatever that
0032 // may be on a given architecture). The CFA address for the stack frame does
0033 // not change during the lifetime of the function.
0034 
0035 // AFA is an artificially introduced Aligned Frame Address.
0036 // It is used only for stack frames with realignment (e.g. when some of the
0037 // locals has an alignment requirement higher than the stack alignment right
0038 // after the function call). It is used to access register values saved on the
0039 // stack after the realignment (and so they are inaccessible through the CFA).
0040 // AFA usually equals the stack pointer value right after the realignment.
0041 
0042 // Internally, the UnwindPlan is structured as a vector of register locations
0043 // organized by code address in the function, showing which registers have been
0044 // saved at that point and where they are saved. It can be thought of as the
0045 // expanded table form of the DWARF CFI encoded information.
0046 
0047 // Other unwind information sources will be converted into UnwindPlans before
0048 // being added to a FuncUnwinders object.  The unwind source may be an eh_frame
0049 // FDE, a DWARF debug_frame FDE, or assembly language based prologue analysis.
0050 // The UnwindPlan is the canonical form of this information that the unwinder
0051 // code will use when walking the stack.
0052 
0053 class UnwindPlan {
0054 public:
0055   class Row {
0056   public:
0057     class AbstractRegisterLocation {
0058     public:
0059       enum RestoreType {
0060         unspecified,       // not specified, we may be able to assume this
0061                            // is the same register. gcc doesn't specify all
0062                            // initial values so we really don't know...
0063         undefined,         // reg is not available, e.g. volatile reg
0064         same,              // reg is unchanged
0065         atCFAPlusOffset,   // reg = deref(CFA + offset)
0066         isCFAPlusOffset,   // reg = CFA + offset
0067         atAFAPlusOffset,   // reg = deref(AFA + offset)
0068         isAFAPlusOffset,   // reg = AFA + offset
0069         inOtherRegister,   // reg = other reg
0070         atDWARFExpression, // reg = deref(eval(dwarf_expr))
0071         isDWARFExpression, // reg = eval(dwarf_expr)
0072         isConstant         // reg = constant
0073       };
0074 
0075       AbstractRegisterLocation() : m_location() {}
0076 
0077       bool operator==(const AbstractRegisterLocation &rhs) const;
0078 
0079       bool operator!=(const AbstractRegisterLocation &rhs) const {
0080         return !(*this == rhs);
0081       }
0082 
0083       void SetUnspecified() { m_type = unspecified; }
0084 
0085       void SetUndefined() { m_type = undefined; }
0086 
0087       void SetSame() { m_type = same; }
0088 
0089       bool IsSame() const { return m_type == same; }
0090 
0091       bool IsUnspecified() const { return m_type == unspecified; }
0092 
0093       bool IsUndefined() const { return m_type == undefined; }
0094 
0095       bool IsCFAPlusOffset() const { return m_type == isCFAPlusOffset; }
0096 
0097       bool IsAtCFAPlusOffset() const { return m_type == atCFAPlusOffset; }
0098 
0099       bool IsAFAPlusOffset() const { return m_type == isAFAPlusOffset; }
0100 
0101       bool IsAtAFAPlusOffset() const { return m_type == atAFAPlusOffset; }
0102 
0103       bool IsInOtherRegister() const { return m_type == inOtherRegister; }
0104 
0105       bool IsAtDWARFExpression() const { return m_type == atDWARFExpression; }
0106 
0107       bool IsDWARFExpression() const { return m_type == isDWARFExpression; }
0108 
0109       bool IsConstant() const { return m_type == isConstant; }
0110 
0111       void SetIsConstant(uint64_t value) {
0112         m_type = isConstant;
0113         m_location.constant_value = value;
0114       }
0115 
0116       uint64_t GetConstant() const { return m_location.constant_value; }
0117 
0118       void SetAtCFAPlusOffset(int32_t offset) {
0119         m_type = atCFAPlusOffset;
0120         m_location.offset = offset;
0121       }
0122 
0123       void SetIsCFAPlusOffset(int32_t offset) {
0124         m_type = isCFAPlusOffset;
0125         m_location.offset = offset;
0126       }
0127 
0128       void SetAtAFAPlusOffset(int32_t offset) {
0129         m_type = atAFAPlusOffset;
0130         m_location.offset = offset;
0131       }
0132 
0133       void SetIsAFAPlusOffset(int32_t offset) {
0134         m_type = isAFAPlusOffset;
0135         m_location.offset = offset;
0136       }
0137 
0138       void SetInRegister(uint32_t reg_num) {
0139         m_type = inOtherRegister;
0140         m_location.reg_num = reg_num;
0141       }
0142 
0143       uint32_t GetRegisterNumber() const {
0144         if (m_type == inOtherRegister)
0145           return m_location.reg_num;
0146         return LLDB_INVALID_REGNUM;
0147       }
0148 
0149       RestoreType GetLocationType() const { return m_type; }
0150 
0151       int32_t GetOffset() const {
0152         switch(m_type)
0153         {
0154         case atCFAPlusOffset:
0155         case isCFAPlusOffset:
0156         case atAFAPlusOffset:
0157         case isAFAPlusOffset:
0158           return m_location.offset;
0159         default:
0160           return 0;
0161         }
0162       }
0163 
0164       void GetDWARFExpr(const uint8_t **opcodes, uint16_t &len) const {
0165         if (m_type == atDWARFExpression || m_type == isDWARFExpression) {
0166           *opcodes = m_location.expr.opcodes;
0167           len = m_location.expr.length;
0168         } else {
0169           *opcodes = nullptr;
0170           len = 0;
0171         }
0172       }
0173 
0174       void SetAtDWARFExpression(const uint8_t *opcodes, uint32_t len);
0175 
0176       void SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len);
0177 
0178       const uint8_t *GetDWARFExpressionBytes() {
0179         if (m_type == atDWARFExpression || m_type == isDWARFExpression)
0180           return m_location.expr.opcodes;
0181         return nullptr;
0182       }
0183 
0184       int GetDWARFExpressionLength() {
0185         if (m_type == atDWARFExpression || m_type == isDWARFExpression)
0186           return m_location.expr.length;
0187         return 0;
0188       }
0189 
0190       void Dump(Stream &s, const UnwindPlan *unwind_plan,
0191                 const UnwindPlan::Row *row, Thread *thread, bool verbose) const;
0192 
0193     private:
0194       RestoreType m_type = unspecified; // How do we locate this register?
0195       union {
0196         // For m_type == atCFAPlusOffset or m_type == isCFAPlusOffset
0197         int32_t offset;
0198         // For m_type == inOtherRegister
0199         uint32_t reg_num; // The register number
0200         // For m_type == atDWARFExpression or m_type == isDWARFExpression
0201         struct {
0202           const uint8_t *opcodes;
0203           uint16_t length;
0204         } expr;
0205         // For m_type == isConstant
0206         uint64_t constant_value;
0207       } m_location;
0208     };
0209 
0210     class FAValue {
0211     public:
0212       enum ValueType {
0213         unspecified,            // not specified
0214         isRegisterPlusOffset,   // FA = register + offset
0215         isRegisterDereferenced, // FA = [reg]
0216         isDWARFExpression,      // FA = eval(dwarf_expr)
0217         isRaSearch,             // FA = SP + offset + ???
0218         isConstant,             // FA = constant
0219       };
0220 
0221       FAValue() : m_value() {}
0222 
0223       bool operator==(const FAValue &rhs) const;
0224 
0225       bool operator!=(const FAValue &rhs) const { return !(*this == rhs); }
0226 
0227       void SetUnspecified() { m_type = unspecified; }
0228 
0229       bool IsUnspecified() const { return m_type == unspecified; }
0230 
0231       void SetRaSearch(int32_t offset) {
0232         m_type = isRaSearch;
0233         m_value.ra_search_offset = offset;
0234       }
0235 
0236       bool IsRegisterPlusOffset() const {
0237         return m_type == isRegisterPlusOffset;
0238       }
0239 
0240       void SetIsRegisterPlusOffset(uint32_t reg_num, int32_t offset) {
0241         m_type = isRegisterPlusOffset;
0242         m_value.reg.reg_num = reg_num;
0243         m_value.reg.offset = offset;
0244       }
0245 
0246       bool IsRegisterDereferenced() const {
0247         return m_type == isRegisterDereferenced;
0248       }
0249 
0250       void SetIsRegisterDereferenced(uint32_t reg_num) {
0251         m_type = isRegisterDereferenced;
0252         m_value.reg.reg_num = reg_num;
0253       }
0254 
0255       bool IsDWARFExpression() const { return m_type == isDWARFExpression; }
0256 
0257       void SetIsDWARFExpression(const uint8_t *opcodes, uint32_t len) {
0258         m_type = isDWARFExpression;
0259         m_value.expr.opcodes = opcodes;
0260         m_value.expr.length = len;
0261       }
0262 
0263       bool IsConstant() const { return m_type == isConstant; }
0264 
0265       void SetIsConstant(uint64_t constant) {
0266         m_type = isConstant;
0267         m_value.constant = constant;
0268       }
0269 
0270       uint64_t GetConstant() const { return m_value.constant; }
0271 
0272       uint32_t GetRegisterNumber() const {
0273         if (m_type == isRegisterDereferenced || m_type == isRegisterPlusOffset)
0274           return m_value.reg.reg_num;
0275         return LLDB_INVALID_REGNUM;
0276       }
0277 
0278       ValueType GetValueType() const { return m_type; }
0279 
0280       int32_t GetOffset() const {
0281         switch (m_type) {
0282           case isRegisterPlusOffset:
0283             return m_value.reg.offset;
0284           case isRaSearch:
0285             return m_value.ra_search_offset;
0286           default:
0287             return 0;
0288         }
0289       }
0290 
0291       void IncOffset(int32_t delta) {
0292         if (m_type == isRegisterPlusOffset)
0293           m_value.reg.offset += delta;
0294       }
0295 
0296       void SetOffset(int32_t offset) {
0297         if (m_type == isRegisterPlusOffset)
0298           m_value.reg.offset = offset;
0299       }
0300 
0301       void GetDWARFExpr(const uint8_t **opcodes, uint16_t &len) const {
0302         if (m_type == isDWARFExpression) {
0303           *opcodes = m_value.expr.opcodes;
0304           len = m_value.expr.length;
0305         } else {
0306           *opcodes = nullptr;
0307           len = 0;
0308         }
0309       }
0310 
0311       const uint8_t *GetDWARFExpressionBytes() {
0312         if (m_type == isDWARFExpression)
0313           return m_value.expr.opcodes;
0314         return nullptr;
0315       }
0316 
0317       int GetDWARFExpressionLength() {
0318         if (m_type == isDWARFExpression)
0319           return m_value.expr.length;
0320         return 0;
0321       }
0322 
0323       void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread) const;
0324 
0325     private:
0326       ValueType m_type = unspecified; // How do we compute CFA value?
0327       union {
0328         struct {
0329           // For m_type == isRegisterPlusOffset or m_type ==
0330           // isRegisterDereferenced
0331           uint32_t reg_num; // The register number
0332           // For m_type == isRegisterPlusOffset
0333           int32_t offset;
0334         } reg;
0335         // For m_type == isDWARFExpression
0336         struct {
0337           const uint8_t *opcodes;
0338           uint16_t length;
0339         } expr;
0340         // For m_type == isRaSearch
0341         int32_t ra_search_offset;
0342         // For m_type = isConstant
0343         uint64_t constant;
0344       } m_value;
0345     }; // class FAValue
0346 
0347     Row();
0348 
0349     bool operator==(const Row &rhs) const;
0350 
0351     bool GetRegisterInfo(uint32_t reg_num,
0352                          AbstractRegisterLocation &register_location) const;
0353 
0354     void SetRegisterInfo(uint32_t reg_num,
0355                          const AbstractRegisterLocation register_location);
0356 
0357     void RemoveRegisterInfo(uint32_t reg_num);
0358 
0359     lldb::addr_t GetOffset() const { return m_offset; }
0360 
0361     void SetOffset(lldb::addr_t offset) { m_offset = offset; }
0362 
0363     void SlideOffset(lldb::addr_t offset) { m_offset += offset; }
0364 
0365     FAValue &GetCFAValue() { return m_cfa_value; }
0366 
0367     FAValue &GetAFAValue() { return m_afa_value; }
0368 
0369     bool SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num, int32_t offset,
0370                                               bool can_replace);
0371 
0372     bool SetRegisterLocationToIsCFAPlusOffset(uint32_t reg_num, int32_t offset,
0373                                               bool can_replace);
0374 
0375     bool SetRegisterLocationToUndefined(uint32_t reg_num, bool can_replace,
0376                                         bool can_replace_only_if_unspecified);
0377 
0378     bool SetRegisterLocationToUnspecified(uint32_t reg_num, bool can_replace);
0379 
0380     bool SetRegisterLocationToRegister(uint32_t reg_num, uint32_t other_reg_num,
0381                                        bool can_replace);
0382 
0383     bool SetRegisterLocationToSame(uint32_t reg_num, bool must_replace);
0384 
0385     /// This method does not make a copy of the \a opcodes memory, it is
0386     /// assumed to have the same lifetime as the Module this UnwindPlan will
0387     /// be registered in.
0388     bool SetRegisterLocationToIsDWARFExpression(uint32_t reg_num,
0389                                                 const uint8_t *opcodes,
0390                                                 uint32_t len, bool can_replace);
0391 
0392     bool SetRegisterLocationToIsConstant(uint32_t reg_num, uint64_t constant,
0393                                          bool can_replace);
0394 
0395     // When this UnspecifiedRegistersAreUndefined mode is
0396     // set, any register that is not specified by this Row will
0397     // be described as Undefined.
0398     // This will prevent the unwinder from iterating down the
0399     // stack looking for a spill location, or a live register value
0400     // at frame 0.
0401     // It would be used for an UnwindPlan row where we can't track
0402     // spilled registers -- for instance a jitted stack frame where
0403     // we have no unwind information or start address -- and registers
0404     // MAY have been spilled and overwritten, so providing the
0405     // spilled/live value from a newer frame may show an incorrect value.
0406     void SetUnspecifiedRegistersAreUndefined(bool unspec_is_undef) {
0407       m_unspecified_registers_are_undefined = unspec_is_undef;
0408     }
0409 
0410     bool GetUnspecifiedRegistersAreUndefined() {
0411       return m_unspecified_registers_are_undefined;
0412     }
0413 
0414     void Clear();
0415 
0416     void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread,
0417               lldb::addr_t base_addr) const;
0418 
0419   protected:
0420     typedef std::map<uint32_t, AbstractRegisterLocation> collection;
0421     lldb::addr_t m_offset = 0; // Offset into the function for this row
0422 
0423     FAValue m_cfa_value;
0424     FAValue m_afa_value;
0425     collection m_register_locations;
0426     bool m_unspecified_registers_are_undefined = false;
0427   }; // class Row
0428 
0429   typedef std::shared_ptr<Row> RowSP;
0430 
0431   UnwindPlan(lldb::RegisterKind reg_kind)
0432       : m_register_kind(reg_kind), m_return_addr_register(LLDB_INVALID_REGNUM),
0433         m_plan_is_sourced_from_compiler(eLazyBoolCalculate),
0434         m_plan_is_valid_at_all_instruction_locations(eLazyBoolCalculate),
0435         m_plan_is_for_signal_trap(eLazyBoolCalculate) {}
0436 
0437   // Performs a deep copy of the plan, including all the rows (expensive).
0438   UnwindPlan(const UnwindPlan &rhs)
0439       : m_plan_valid_address_range(rhs.m_plan_valid_address_range),
0440         m_register_kind(rhs.m_register_kind),
0441         m_return_addr_register(rhs.m_return_addr_register),
0442         m_source_name(rhs.m_source_name),
0443         m_plan_is_sourced_from_compiler(rhs.m_plan_is_sourced_from_compiler),
0444         m_plan_is_valid_at_all_instruction_locations(
0445             rhs.m_plan_is_valid_at_all_instruction_locations),
0446         m_plan_is_for_signal_trap(rhs.m_plan_is_for_signal_trap),
0447         m_lsda_address(rhs.m_lsda_address),
0448         m_personality_func_addr(rhs.m_personality_func_addr) {
0449     m_row_list.reserve(rhs.m_row_list.size());
0450     for (const RowSP &row_sp : rhs.m_row_list)
0451       m_row_list.emplace_back(new Row(*row_sp));
0452   }
0453 
0454   ~UnwindPlan() = default;
0455 
0456   void Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const;
0457 
0458   void AppendRow(const RowSP &row_sp);
0459 
0460   void InsertRow(const RowSP &row_sp, bool replace_existing = false);
0461 
0462   // Returns a pointer to the best row for the given offset into the function's
0463   // instructions. If offset is -1 it indicates that the function start is
0464   // unknown - the final row in the UnwindPlan is returned. In practice, the
0465   // UnwindPlan for a function with no known start address will be the
0466   // architectural default UnwindPlan which will only have one row.
0467   UnwindPlan::RowSP GetRowForFunctionOffset(int offset) const;
0468 
0469   lldb::RegisterKind GetRegisterKind() const { return m_register_kind; }
0470 
0471   void SetRegisterKind(lldb::RegisterKind kind) { m_register_kind = kind; }
0472 
0473   void SetReturnAddressRegister(uint32_t regnum) {
0474     m_return_addr_register = regnum;
0475   }
0476 
0477   uint32_t GetReturnAddressRegister() { return m_return_addr_register; }
0478 
0479   uint32_t GetInitialCFARegister() const {
0480     if (m_row_list.empty())
0481       return LLDB_INVALID_REGNUM;
0482     return m_row_list.front()->GetCFAValue().GetRegisterNumber();
0483   }
0484 
0485   // This UnwindPlan may not be valid at every address of the function span.
0486   // For instance, a FastUnwindPlan will not be valid at the prologue setup
0487   // instructions - only in the body of the function.
0488   void SetPlanValidAddressRange(const AddressRange &range);
0489 
0490   const AddressRange &GetAddressRange() const {
0491     return m_plan_valid_address_range;
0492   }
0493 
0494   bool PlanValidAtAddress(Address addr);
0495 
0496   bool IsValidRowIndex(uint32_t idx) const;
0497 
0498   const UnwindPlan::RowSP GetRowAtIndex(uint32_t idx) const;
0499 
0500   const UnwindPlan::RowSP GetLastRow() const;
0501 
0502   lldb_private::ConstString GetSourceName() const;
0503 
0504   void SetSourceName(const char *);
0505 
0506   // Was this UnwindPlan emitted by a compiler?
0507   lldb_private::LazyBool GetSourcedFromCompiler() const {
0508     return m_plan_is_sourced_from_compiler;
0509   }
0510 
0511   // Was this UnwindPlan emitted by a compiler?
0512   void SetSourcedFromCompiler(lldb_private::LazyBool from_compiler) {
0513     m_plan_is_sourced_from_compiler = from_compiler;
0514   }
0515 
0516   // Is this UnwindPlan valid at all instructions?  If not, then it is assumed
0517   // valid at call sites, e.g. for exception handling.
0518   lldb_private::LazyBool GetUnwindPlanValidAtAllInstructions() const {
0519     return m_plan_is_valid_at_all_instruction_locations;
0520   }
0521 
0522   // Is this UnwindPlan valid at all instructions?  If not, then it is assumed
0523   // valid at call sites, e.g. for exception handling.
0524   void SetUnwindPlanValidAtAllInstructions(
0525       lldb_private::LazyBool valid_at_all_insn) {
0526     m_plan_is_valid_at_all_instruction_locations = valid_at_all_insn;
0527   }
0528 
0529   // Is this UnwindPlan for a signal trap frame?  If so, then its saved pc
0530   // may have been set manually by the signal dispatch code and therefore
0531   // not follow a call to the child frame.
0532   lldb_private::LazyBool GetUnwindPlanForSignalTrap() const {
0533     return m_plan_is_for_signal_trap;
0534   }
0535 
0536   void SetUnwindPlanForSignalTrap(lldb_private::LazyBool is_for_signal_trap) {
0537     m_plan_is_for_signal_trap = is_for_signal_trap;
0538   }
0539 
0540   int GetRowCount() const;
0541 
0542   void Clear() {
0543     m_row_list.clear();
0544     m_plan_valid_address_range.Clear();
0545     m_register_kind = lldb::eRegisterKindDWARF;
0546     m_source_name.Clear();
0547     m_plan_is_sourced_from_compiler = eLazyBoolCalculate;
0548     m_plan_is_valid_at_all_instruction_locations = eLazyBoolCalculate;
0549     m_plan_is_for_signal_trap = eLazyBoolCalculate;
0550     m_lsda_address.Clear();
0551     m_personality_func_addr.Clear();
0552   }
0553 
0554   const RegisterInfo *GetRegisterInfo(Thread *thread, uint32_t reg_num) const;
0555 
0556   Address GetLSDAAddress() const { return m_lsda_address; }
0557 
0558   void SetLSDAAddress(Address lsda_addr) { m_lsda_address = lsda_addr; }
0559 
0560   Address GetPersonalityFunctionPtr() const { return m_personality_func_addr; }
0561 
0562   void SetPersonalityFunctionPtr(Address presonality_func_ptr) {
0563     m_personality_func_addr = presonality_func_ptr;
0564   }
0565 
0566 private:
0567   typedef std::vector<RowSP> collection;
0568   collection m_row_list;
0569   AddressRange m_plan_valid_address_range;
0570   lldb::RegisterKind m_register_kind; // The RegisterKind these register numbers
0571                                       // are in terms of - will need to be
0572   // translated to lldb native reg nums at unwind time
0573   uint32_t m_return_addr_register; // The register that has the return address
0574                                    // for the caller frame
0575                                    // e.g. the lr on arm
0576   lldb_private::ConstString
0577       m_source_name; // for logging, where this UnwindPlan originated from
0578   lldb_private::LazyBool m_plan_is_sourced_from_compiler;
0579   lldb_private::LazyBool m_plan_is_valid_at_all_instruction_locations;
0580   lldb_private::LazyBool m_plan_is_for_signal_trap;
0581 
0582   Address m_lsda_address; // Where the language specific data area exists in the
0583                           // module - used
0584                           // in exception handling.
0585   Address m_personality_func_addr; // The address of a pointer to the
0586                                    // personality function - used in
0587                                    // exception handling.
0588 };                                 // class UnwindPlan
0589 
0590 } // namespace lldb_private
0591 
0592 #endif // LLDB_SYMBOL_UNWINDPLAN_H