UnwindPlan.h revision 37816a3429a075e19b74f64fd642d5a5d7ec6f2f
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
12namespace 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
39class UnwindPlan {
40public:
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
343public:
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
482private:
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