• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
RegisterLocation()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
SetUnspecified()78             SetUnspecified()
79             {
80                 m_type = unspecified;
81             }
82 
83             void
SetUndefined()84             SetUndefined()
85             {
86                 m_type = undefined;
87             }
88 
89             void
SetSame()90             SetSame()
91             {
92                 m_type = same;
93             }
94 
95             bool
IsSame()96             IsSame () const
97             {
98                 return m_type == same;
99             }
100 
101             bool
IsUnspecified()102             IsUnspecified () const
103             {
104                 return m_type == unspecified;
105             }
106 
107             bool
IsCFAPlusOffset()108             IsCFAPlusOffset () const
109             {
110                 return m_type == isCFAPlusOffset;
111             }
112 
113             bool
IsAtCFAPlusOffset()114             IsAtCFAPlusOffset () const
115             {
116                 return m_type == atCFAPlusOffset;
117             }
118 
119             bool
IsInOtherRegister()120             IsInOtherRegister () const
121             {
122                 return m_type == inOtherRegister;
123             }
124 
125             bool
IsAtDWARFExpression()126             IsAtDWARFExpression () const
127             {
128                 return m_type == atDWARFExpression;
129             }
130 
131             bool
IsDWARFExpression()132             IsDWARFExpression () const
133             {
134                 return m_type == isDWARFExpression;
135             }
136 
137             void
SetAtCFAPlusOffset(int32_t offset)138             SetAtCFAPlusOffset (int32_t offset)
139             {
140                 m_type = atCFAPlusOffset;
141                 m_location.offset = offset;
142             }
143 
144             void
SetIsCFAPlusOffset(int32_t offset)145             SetIsCFAPlusOffset (int32_t offset)
146             {
147                 m_type = isCFAPlusOffset;
148                 m_location.offset = offset;
149             }
150 
151             void
SetInRegister(uint32_t reg_num)152             SetInRegister (uint32_t reg_num)
153             {
154                 m_type = inOtherRegister;
155                 m_location.reg_num = reg_num;
156             }
157 
158             uint32_t
GetRegisterNumber()159             GetRegisterNumber () const
160             {
161                 if (m_type == inOtherRegister)
162                     return m_location.reg_num;
163                 return LLDB_INVALID_REGNUM;
164             }
165 
166             RestoreType
GetLocationType()167             GetLocationType () const
168             {
169                 return m_type;
170             }
171 
172             int32_t
GetOffset()173             GetOffset () const
174             {
175                 if (m_type == atCFAPlusOffset || m_type == isCFAPlusOffset)
176                     return m_location.offset;
177                 return 0;
178             }
179 
180             void
GetDWARFExpr(const uint8_t ** opcodes,uint16_t & len)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 *
GetDWARFExpressionBytes()202             GetDWARFExpressionBytes ()
203             {
204                 if (m_type == atDWARFExpression || m_type == isDWARFExpression)
205                     return m_location.expr.opcodes;
206                 return NULL;
207             }
208 
209             int
GetDWARFExpressionLength()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 
Row(const UnwindPlan::Row & rhs)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
GetOffset()261         GetOffset() const
262         {
263             return m_offset;
264         }
265 
266         void
SetOffset(lldb::addr_t offset)267         SetOffset(lldb::addr_t offset)
268         {
269             m_offset = offset;
270         }
271 
272         void
SlideOffset(lldb::addr_t offset)273         SlideOffset(lldb::addr_t offset)
274         {
275             m_offset += offset;
276         }
277 
278         uint32_t
GetCFARegister()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
GetCFAOffset()318         GetCFAOffset () const
319         {
320             return m_cfa_offset;
321         }
322 
323         void
SetCFAOffset(int32_t offset)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 
UnwindPlan(lldb::RegisterKind reg_kind)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 
~UnwindPlan()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
GetRegisterKind()376     GetRegisterKind () const
377     {
378         return m_register_kind;
379     }
380 
381     void
SetRegisterKind(lldb::RegisterKind kind)382     SetRegisterKind (lldb::RegisterKind kind)
383     {
384         m_register_kind = kind;
385     }
386 
387     void
SetReturnAddressRegister(uint32_t regnum)388     SetReturnAddressRegister (uint32_t regnum)
389     {
390         m_return_addr_register = regnum;
391     }
392 
393     uint32_t
GetReturnAddressRegister(void)394     GetReturnAddressRegister (void)
395     {
396         return m_return_addr_register;
397     }
398 
399     uint32_t
GetInitialCFARegister()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 &
GetAddressRange()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
GetSourcedFromCompiler()439     GetSourcedFromCompiler () const
440     {
441         return m_plan_is_sourced_from_compiler;
442     }
443 
444     // Was this UnwindPlan emitted by a compiler?
445     void
SetSourcedFromCompiler(lldb_private::LazyBool from_compiler)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
GetUnwindPlanValidAtAllInstructions()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
SetUnwindPlanValidAtAllInstructions(lldb_private::LazyBool valid_at_all_insn)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
Clear()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