Home | History | Annotate | Download | only in Symbol
      1 #ifndef liblldb_UnwindPlan_h
      2 #define liblldb_UnwindPlan_h
      3 
      4 #include "lldb/lldb-private.h"
      5 #include "lldb/Core/AddressRange.h"
      6 #include "lldb/Core/Stream.h"
      7 #include "lldb/Core/ConstString.h"
      8 
      9 #include <map>
     10 #include <vector>
     11 
     12 namespace lldb_private {
     13 
     14 // The UnwindPlan object specifies how to unwind out of a function - where
     15 // this function saves the caller's register values before modifying them
     16 // (for non-volatile aka saved registers) and how to find this frame's
     17 // Canonical Frame Address (CFA).
     18 
     19 // Most commonly, registers are saved on the stack, offset some bytes from
     20 // the Canonical Frame Address, or CFA, which is the starting address of
     21 // this function's stack frame (the CFA is same as the eh_frame's CFA,
     22 // whatever that may be on a given architecture).
     23 // The CFA address for the stack frame does not change during
     24 // the lifetime of the function.
     25 
     26 // Internally, the UnwindPlan is structured as a vector of register locations
     27 // organized by code address in the function, showing which registers have been
     28 // saved at that point and where they are saved.
     29 // It can be thought of as the expanded table form of the DWARF CFI
     30 // encoded information.
     31 
     32 // Other unwind information sources will be converted into UnwindPlans before
     33 // being added to a FuncUnwinders object.  The unwind source may be
     34 // an eh_frame FDE, a DWARF debug_frame FDE, or assembly language based
     35 // prologue analysis.
     36 // The UnwindPlan is the canonical form of this information that the unwinder
     37 // code will use when walking the stack.
     38 
     39 class UnwindPlan {
     40 public:
     41 
     42     class Row {
     43     public:
     44         class RegisterLocation
     45         {
     46         public:
     47 
     48             enum RestoreType
     49                 {
     50                     unspecified,        // not specified, we may be able to assume this
     51                                         // is the same register. gcc doesn't specify all
     52                                         // initial values so we really don't know...
     53                     undefined,          // reg is not available, e.g. volatile reg
     54                     same,               // reg is unchanged
     55                     atCFAPlusOffset,    // reg = deref(CFA + offset)
     56                     isCFAPlusOffset,    // reg = CFA + offset
     57                     inOtherRegister,    // reg = other reg
     58                     atDWARFExpression,  // reg = deref(eval(dwarf_expr))
     59                     isDWARFExpression   // reg = eval(dwarf_expr)
     60                 };
     61 
     62             RegisterLocation() :
     63                 m_type(unspecified),
     64                 m_location()
     65             {
     66             }
     67 
     68             bool
     69             operator == (const RegisterLocation& rhs) const;
     70 
     71             bool
     72             operator != (const RegisterLocation &rhs) const
     73             {
     74                 return !(*this == rhs);
     75             }
     76 
     77             void
     78             SetUnspecified()
     79             {
     80                 m_type = unspecified;
     81             }
     82 
     83             void
     84             SetUndefined()
     85             {
     86                 m_type = undefined;
     87             }
     88 
     89             void
     90             SetSame()
     91             {
     92                 m_type = same;
     93             }
     94 
     95             bool
     96             IsSame () const
     97             {
     98                 return m_type == same;
     99             }
    100 
    101             bool
    102             IsUnspecified () const
    103             {
    104                 return m_type == unspecified;
    105             }
    106 
    107             bool
    108             IsCFAPlusOffset () const
    109             {
    110                 return m_type == isCFAPlusOffset;
    111             }
    112 
    113             bool
    114             IsAtCFAPlusOffset () const
    115             {
    116                 return m_type == atCFAPlusOffset;
    117             }
    118 
    119             bool
    120             IsInOtherRegister () const
    121             {
    122                 return m_type == inOtherRegister;
    123             }
    124 
    125             bool
    126             IsAtDWARFExpression () const
    127             {
    128                 return m_type == atDWARFExpression;
    129             }
    130 
    131             bool
    132             IsDWARFExpression () const
    133             {
    134                 return m_type == isDWARFExpression;
    135             }
    136 
    137             void
    138             SetAtCFAPlusOffset (int32_t offset)
    139             {
    140                 m_type = atCFAPlusOffset;
    141                 m_location.offset = offset;
    142             }
    143 
    144             void
    145             SetIsCFAPlusOffset (int32_t offset)
    146             {
    147                 m_type = isCFAPlusOffset;
    148                 m_location.offset = offset;
    149             }
    150 
    151             void
    152             SetInRegister (uint32_t reg_num)
    153             {
    154                 m_type = inOtherRegister;
    155                 m_location.reg_num = reg_num;
    156             }
    157 
    158             uint32_t
    159             GetRegisterNumber () const
    160             {
    161                 if (m_type == inOtherRegister)
    162                     return m_location.reg_num;
    163                 return LLDB_INVALID_REGNUM;
    164             }
    165 
    166             RestoreType
    167             GetLocationType () const
    168             {
    169                 return m_type;
    170             }
    171 
    172             int32_t
    173             GetOffset () const
    174             {
    175                 if (m_type == atCFAPlusOffset || m_type == isCFAPlusOffset)
    176                     return m_location.offset;
    177                 return 0;
    178             }
    179 
    180             void
    181             GetDWARFExpr (const uint8_t **opcodes, uint16_t& len) const
    182             {
    183                 if (m_type == atDWARFExpression || m_type == isDWARFExpression)
    184                 {
    185                     *opcodes = m_location.expr.opcodes;
    186                     len = m_location.expr.length;
    187                 }
    188                 else
    189                 {
    190                     *opcodes = NULL;
    191                     len = 0;
    192                 }
    193             }
    194 
    195             void
    196             SetAtDWARFExpression (const uint8_t *opcodes, uint32_t len);
    197 
    198             void
    199             SetIsDWARFExpression (const uint8_t *opcodes, uint32_t len);
    200 
    201             const uint8_t *
    202             GetDWARFExpressionBytes ()
    203             {
    204                 if (m_type == atDWARFExpression || m_type == isDWARFExpression)
    205                     return m_location.expr.opcodes;
    206                 return NULL;
    207             }
    208 
    209             int
    210             GetDWARFExpressionLength ()
    211             {
    212                 if (m_type == atDWARFExpression || m_type == isDWARFExpression)
    213                     return m_location.expr.length;
    214                 return 0;
    215             }
    216 
    217             void
    218             Dump (Stream &s,
    219                   const UnwindPlan* unwind_plan,
    220                   const UnwindPlan::Row* row,
    221                   Thread* thread,
    222                   bool verbose) const;
    223 
    224         private:
    225             RestoreType m_type;            // How do we locate this register?
    226             union
    227             {
    228                 // For m_type == atCFAPlusOffset or m_type == isCFAPlusOffset
    229                 int32_t offset;
    230                 // For m_type == inOtherRegister
    231                 uint32_t reg_num; // The register number
    232                 // For m_type == atDWARFExpression or m_type == isDWARFExpression
    233                 struct {
    234                     const uint8_t *opcodes;
    235                     uint16_t length;
    236                 } expr;
    237             } m_location;
    238         };
    239 
    240     public:
    241         Row ();
    242 
    243         Row (const UnwindPlan::Row& rhs) :
    244             m_offset             (rhs.m_offset),
    245             m_cfa_reg_num        (rhs.m_cfa_reg_num),
    246             m_cfa_offset         (rhs.m_cfa_offset),
    247             m_register_locations (rhs.m_register_locations)
    248         {
    249         }
    250 
    251         bool
    252         operator == (const Row &rhs) const;
    253 
    254         bool
    255         GetRegisterInfo (uint32_t reg_num, RegisterLocation& register_location) const;
    256 
    257         void
    258         SetRegisterInfo (uint32_t reg_num, const RegisterLocation register_location);
    259 
    260         lldb::addr_t
    261         GetOffset() const
    262         {
    263             return m_offset;
    264         }
    265 
    266         void
    267         SetOffset(lldb::addr_t offset)
    268         {
    269             m_offset = offset;
    270         }
    271 
    272         void
    273         SlideOffset(lldb::addr_t offset)
    274         {
    275             m_offset += offset;
    276         }
    277 
    278         uint32_t
    279         GetCFARegister () const
    280         {
    281             return m_cfa_reg_num;
    282         }
    283 
    284         bool
    285         SetRegisterLocationToAtCFAPlusOffset (uint32_t reg_num,
    286                                               int32_t offset,
    287                                               bool can_replace);
    288 
    289         bool
    290         SetRegisterLocationToIsCFAPlusOffset (uint32_t reg_num,
    291                                               int32_t offset,
    292                                               bool can_replace);
    293 
    294         bool
    295         SetRegisterLocationToUndefined (uint32_t reg_num,
    296                                         bool can_replace,
    297                                         bool can_replace_only_if_unspecified);
    298 
    299         bool
    300         SetRegisterLocationToUnspecified (uint32_t reg_num,
    301                                           bool can_replace);
    302 
    303         bool
    304         SetRegisterLocationToRegister (uint32_t reg_num,
    305                                        uint32_t other_reg_num,
    306                                        bool can_replace);
    307 
    308         bool
    309         SetRegisterLocationToSame (uint32_t reg_num,
    310                                    bool must_replace);
    311 
    312 
    313 
    314         void
    315         SetCFARegister (uint32_t reg_num);
    316 
    317         int32_t
    318         GetCFAOffset () const
    319         {
    320             return m_cfa_offset;
    321         }
    322 
    323         void
    324         SetCFAOffset (int32_t offset)
    325         {
    326             m_cfa_offset = offset;
    327         }
    328 
    329         void
    330         Clear ();
    331 
    332         void
    333         Dump (Stream& s, const UnwindPlan* unwind_plan, Thread* thread, lldb::addr_t base_addr) const;
    334 
    335     protected:
    336         typedef std::map<uint32_t, RegisterLocation> collection;
    337         lldb::addr_t m_offset;      // Offset into the function for this row
    338         uint32_t m_cfa_reg_num;     // The Call Frame Address register number
    339         int32_t  m_cfa_offset;      // The offset from the CFA for this row
    340         collection m_register_locations;
    341     }; // class Row
    342 
    343 public:
    344 
    345     typedef std::shared_ptr<Row> RowSP;
    346 
    347     UnwindPlan (lldb::RegisterKind reg_kind) :
    348         m_row_list (),
    349         m_plan_valid_address_range (),
    350         m_register_kind (reg_kind),
    351         m_return_addr_register (LLDB_INVALID_REGNUM),
    352         m_source_name (),
    353         m_plan_is_sourced_from_compiler (eLazyBoolCalculate),
    354         m_plan_is_valid_at_all_instruction_locations (eLazyBoolCalculate)
    355     {
    356     }
    357 
    358     ~UnwindPlan ()
    359 	{
    360 	}
    361 
    362     void
    363     Dump (Stream& s, Thread* thread, lldb::addr_t base_addr) const;
    364 
    365     void
    366     AppendRow (const RowSP& row_sp);
    367 
    368     // Returns a pointer to the best row for the given offset into the function's instructions.
    369     // If offset is -1 it indicates that the function start is unknown - the final row in the UnwindPlan is returned.
    370     // In practice, the UnwindPlan for a function with no known start address will be the architectural default
    371     // UnwindPlan which will only have one row.
    372     UnwindPlan::RowSP
    373     GetRowForFunctionOffset (int offset) const;
    374 
    375     lldb::RegisterKind
    376     GetRegisterKind () const
    377     {
    378         return m_register_kind;
    379     }
    380 
    381     void
    382     SetRegisterKind (lldb::RegisterKind kind)
    383     {
    384         m_register_kind = kind;
    385     }
    386 
    387     void
    388     SetReturnAddressRegister (uint32_t regnum)
    389     {
    390         m_return_addr_register = regnum;
    391     }
    392 
    393     uint32_t
    394     GetReturnAddressRegister (void)
    395     {
    396         return m_return_addr_register;
    397     }
    398 
    399     uint32_t
    400     GetInitialCFARegister () const
    401     {
    402         if (m_row_list.empty())
    403             return LLDB_INVALID_REGNUM;
    404         return m_row_list.front()->GetCFARegister();
    405     }
    406 
    407     // This UnwindPlan may not be valid at every address of the function span.
    408     // For instance, a FastUnwindPlan will not be valid at the prologue setup
    409     // instructions - only in the body of the function.
    410     void
    411     SetPlanValidAddressRange (const AddressRange& range);
    412 
    413     const AddressRange &
    414     GetAddressRange () const
    415     {
    416         return m_plan_valid_address_range;
    417     }
    418 
    419     bool
    420     PlanValidAtAddress (Address addr);
    421 
    422     bool
    423     IsValidRowIndex (uint32_t idx) const;
    424 
    425     const UnwindPlan::RowSP
    426     GetRowAtIndex (uint32_t idx) const;
    427 
    428     const UnwindPlan::RowSP
    429     GetLastRow () const;
    430 
    431     lldb_private::ConstString
    432     GetSourceName () const;
    433 
    434     void
    435     SetSourceName (const char *);
    436 
    437     // Was this UnwindPlan emitted by a compiler?
    438     lldb_private::LazyBool
    439     GetSourcedFromCompiler () const
    440     {
    441         return m_plan_is_sourced_from_compiler;
    442     }
    443 
    444     // Was this UnwindPlan emitted by a compiler?
    445     void
    446     SetSourcedFromCompiler (lldb_private::LazyBool from_compiler)
    447     {
    448         m_plan_is_sourced_from_compiler = from_compiler;
    449     }
    450 
    451     // Is this UnwindPlan valid at all instructions?  If not, then it is assumed valid at call sites,
    452     // e.g. for exception handling.
    453     lldb_private::LazyBool
    454     GetUnwindPlanValidAtAllInstructions () const
    455     {
    456         return m_plan_is_valid_at_all_instruction_locations;
    457     }
    458 
    459     // Is this UnwindPlan valid at all instructions?  If not, then it is assumed valid at call sites,
    460     // e.g. for exception handling.
    461     void
    462     SetUnwindPlanValidAtAllInstructions (lldb_private::LazyBool valid_at_all_insn)
    463     {
    464         m_plan_is_valid_at_all_instruction_locations = valid_at_all_insn;
    465     }
    466 
    467     int
    468     GetRowCount () const;
    469 
    470     void
    471     Clear()
    472     {
    473         m_row_list.clear();
    474         m_plan_valid_address_range.Clear();
    475         m_register_kind = lldb::eRegisterKindDWARF;
    476         m_source_name.Clear();
    477     }
    478 
    479     const RegisterInfo *
    480     GetRegisterInfo (Thread* thread, uint32_t reg_num) const;
    481 
    482 private:
    483 
    484 
    485     typedef std::vector<RowSP> collection;
    486     collection m_row_list;
    487     AddressRange m_plan_valid_address_range;
    488     lldb::RegisterKind m_register_kind;   // The RegisterKind these register numbers are in terms of - will need to be
    489                                           // translated to lldb native reg nums at unwind time
    490     uint32_t m_return_addr_register;      // The register that has the return address for the caller frame
    491                                           // e.g. the lr on arm
    492     lldb_private::ConstString m_source_name;  // for logging, where this UnwindPlan originated from
    493     lldb_private::LazyBool m_plan_is_sourced_from_compiler;
    494     lldb_private::LazyBool m_plan_is_valid_at_all_instruction_locations;
    495 }; // class UnwindPlan
    496 
    497 } // namespace lldb_private
    498 
    499 #endif //liblldb_UnwindPlan_h
    500