xref: /NextBSD/contrib/llvm/tools/lldb/include/lldb/Symbol/UnwindPlan.h (revision 84d351007654069f9643c8e4b4802a7f5f08ee42)
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         class CFAValue
241         {
242         public:
243 
244             enum ValueType
245             {
246                 unspecified,                  // not specified
247                 isRegisterPlusOffset,         // CFA = register + offset
248                 isRegisterDereferenced,       // CFA = [reg]
249                 isDWARFExpression             // CFA = eval(dwarf_expr)
250             };
251 
CFAValue()252             CFAValue() :
253                 m_type(unspecified),
254                 m_value()
255             {
256             }
257 
258             bool
259             operator == (const CFAValue& rhs) const;
260 
261             bool
262             operator != (const CFAValue &rhs) const
263             {
264                 return !(*this == rhs);
265             }
266 
267             void
SetUnspecified()268             SetUnspecified()
269             {
270                 m_type = unspecified;
271             }
272 
273             bool
IsUnspecified()274             IsUnspecified () const
275             {
276                 return m_type == unspecified;
277             }
278 
279             bool
IsRegisterPlusOffset()280             IsRegisterPlusOffset () const
281             {
282                 return m_type == isRegisterPlusOffset;
283             }
284 
285             void
SetIsRegisterPlusOffset(uint32_t reg_num,int32_t offset)286             SetIsRegisterPlusOffset (uint32_t reg_num, int32_t offset)
287             {
288                 m_type = isRegisterPlusOffset;
289                 m_value.reg.reg_num = reg_num;
290                 m_value.reg.offset = offset;
291             }
292 
293             bool
IsRegisterDereferenced()294             IsRegisterDereferenced () const
295             {
296                 return m_type == isRegisterDereferenced;
297             }
298 
299             void
SetIsRegisterDereferenced(uint32_t reg_num)300             SetIsRegisterDereferenced (uint32_t reg_num)
301             {
302                 m_type = isRegisterDereferenced;
303                 m_value.reg.reg_num = reg_num;
304             }
305 
306             bool
IsDWARFExpression()307             IsDWARFExpression () const
308             {
309                 return m_type == isDWARFExpression;
310             }
311 
312             void
SetIsDWARFExpression(const uint8_t * opcodes,uint32_t len)313             SetIsDWARFExpression (const uint8_t *opcodes, uint32_t len)
314             {
315                 m_type = isDWARFExpression;
316                 m_value.expr.opcodes = opcodes;
317                 m_value.expr.length = len;
318             }
319 
320             uint32_t
GetRegisterNumber()321             GetRegisterNumber () const
322             {
323                 if (m_type == isRegisterDereferenced || m_type == isRegisterPlusOffset)
324                     return m_value.reg.reg_num;
325                 return LLDB_INVALID_REGNUM;
326             }
327 
328             ValueType
GetValueType()329             GetValueType () const
330             {
331                 return m_type;
332             }
333 
334             int32_t
GetOffset()335             GetOffset () const
336             {
337                 if (m_type == isRegisterPlusOffset)
338                     return m_value.reg.offset;
339                 return 0;
340             }
341 
IncOffset(int32_t delta)342             void IncOffset (int32_t delta)
343             {
344                 if (m_type == isRegisterPlusOffset)
345                     m_value.reg.offset += delta;
346             }
347 
SetOffset(int32_t offset)348             void SetOffset (int32_t offset)
349             {
350                 if (m_type == isRegisterPlusOffset)
351                     m_value.reg.offset = offset;
352             }
353 
354             void
GetDWARFExpr(const uint8_t ** opcodes,uint16_t & len)355             GetDWARFExpr (const uint8_t **opcodes, uint16_t& len) const
356             {
357                 if (m_type == isDWARFExpression)
358                 {
359                     *opcodes = m_value.expr.opcodes;
360                     len = m_value.expr.length;
361                 }
362                 else
363                 {
364                     *opcodes = NULL;
365                     len = 0;
366                 }
367             }
368 
369             const uint8_t *
GetDWARFExpressionBytes()370             GetDWARFExpressionBytes ()
371             {
372                 if (m_type == isDWARFExpression)
373                     return m_value.expr.opcodes;
374                 return NULL;
375             }
376 
377             int
GetDWARFExpressionLength()378             GetDWARFExpressionLength ()
379             {
380                 if (m_type == isDWARFExpression)
381                     return m_value.expr.length;
382                 return 0;
383             }
384 
385             void
386             Dump (Stream &s,
387                   const UnwindPlan* unwind_plan,
388                   Thread* thread) const;
389 
390         private:
391             ValueType m_type;            // How do we compute CFA value?
392             union
393             {
394                 struct {
395                     // For m_type == isRegisterPlusOffset or m_type == isRegisterDereferenced
396                     uint32_t reg_num; // The register number
397                     // For m_type == isRegisterPlusOffset
398                     int32_t offset;
399                 } reg;
400                 // For m_type == isDWARFExpression
401                 struct {
402                     const uint8_t *opcodes;
403                     uint16_t length;
404                 } expr;
405             } m_value;
406         }; // class CFAValue
407 
408     public:
409         Row ();
410 
411         Row (const UnwindPlan::Row& rhs) = default;
412 
413         bool
414         operator == (const Row &rhs) const;
415 
416         bool
417         GetRegisterInfo (uint32_t reg_num, RegisterLocation& register_location) const;
418 
419         void
420         SetRegisterInfo (uint32_t reg_num, const RegisterLocation register_location);
421 
422         void
423         RemoveRegisterInfo (uint32_t reg_num);
424 
425         lldb::addr_t
GetOffset()426         GetOffset() const
427         {
428             return m_offset;
429         }
430 
431         void
SetOffset(lldb::addr_t offset)432         SetOffset(lldb::addr_t offset)
433         {
434             m_offset = offset;
435         }
436 
437         void
SlideOffset(lldb::addr_t offset)438         SlideOffset(lldb::addr_t offset)
439         {
440             m_offset += offset;
441         }
442 
GetCFAValue()443         CFAValue& GetCFAValue()
444         {
445             return m_cfa_value;
446         }
447 
448         bool
449         SetRegisterLocationToAtCFAPlusOffset (uint32_t reg_num,
450                                               int32_t offset,
451                                               bool can_replace);
452 
453         bool
454         SetRegisterLocationToIsCFAPlusOffset (uint32_t reg_num,
455                                               int32_t offset,
456                                               bool can_replace);
457 
458         bool
459         SetRegisterLocationToUndefined (uint32_t reg_num,
460                                         bool can_replace,
461                                         bool can_replace_only_if_unspecified);
462 
463         bool
464         SetRegisterLocationToUnspecified (uint32_t reg_num,
465                                           bool can_replace);
466 
467         bool
468         SetRegisterLocationToRegister (uint32_t reg_num,
469                                        uint32_t other_reg_num,
470                                        bool can_replace);
471 
472         bool
473         SetRegisterLocationToSame (uint32_t reg_num,
474                                    bool must_replace);
475 
476         void
477         Clear ();
478 
479         void
480         Dump (Stream& s, const UnwindPlan* unwind_plan, Thread* thread, lldb::addr_t base_addr) const;
481 
482     protected:
483         typedef std::map<uint32_t, RegisterLocation> collection;
484         lldb::addr_t m_offset;      // Offset into the function for this row
485 
486         CFAValue m_cfa_value;
487         collection m_register_locations;
488     }; // class Row
489 
490 public:
491 
492     typedef std::shared_ptr<Row> RowSP;
493 
UnwindPlan(lldb::RegisterKind reg_kind)494     UnwindPlan (lldb::RegisterKind reg_kind) :
495         m_row_list (),
496         m_plan_valid_address_range (),
497         m_register_kind (reg_kind),
498         m_return_addr_register (LLDB_INVALID_REGNUM),
499         m_source_name (),
500         m_plan_is_sourced_from_compiler (eLazyBoolCalculate),
501         m_plan_is_valid_at_all_instruction_locations (eLazyBoolCalculate),
502         m_lsda_address (),
503         m_personality_func_addr ()
504     {
505     }
506 
507     // Performs a deep copy of the plan, including all the rows (expensive).
UnwindPlan(const UnwindPlan & rhs)508     UnwindPlan (const UnwindPlan &rhs) :
509         m_plan_valid_address_range (rhs.m_plan_valid_address_range),
510         m_register_kind (rhs.m_register_kind),
511         m_return_addr_register (rhs.m_return_addr_register),
512         m_source_name (rhs.m_source_name),
513         m_plan_is_sourced_from_compiler (rhs.m_plan_is_sourced_from_compiler),
514         m_plan_is_valid_at_all_instruction_locations (rhs.m_plan_is_valid_at_all_instruction_locations),
515         m_lsda_address (rhs.m_lsda_address),
516         m_personality_func_addr (rhs.m_personality_func_addr)
517     {
518         m_row_list.reserve (rhs.m_row_list.size());
519         for (const RowSP &row_sp: rhs.m_row_list)
520             m_row_list.emplace_back (new Row (*row_sp));
521     }
522 
~UnwindPlan()523     ~UnwindPlan ()
524 	{
525 	}
526 
527     void
528     Dump (Stream& s, Thread* thread, lldb::addr_t base_addr) const;
529 
530     void
531     AppendRow (const RowSP& row_sp);
532 
533     void
534     InsertRow (const RowSP& row_sp);
535 
536     // Returns a pointer to the best row for the given offset into the function's instructions.
537     // If offset is -1 it indicates that the function start is unknown - the final row in the UnwindPlan is returned.
538     // In practice, the UnwindPlan for a function with no known start address will be the architectural default
539     // UnwindPlan which will only have one row.
540     UnwindPlan::RowSP
541     GetRowForFunctionOffset (int offset) const;
542 
543     lldb::RegisterKind
GetRegisterKind()544     GetRegisterKind () const
545     {
546         return m_register_kind;
547     }
548 
549     void
SetRegisterKind(lldb::RegisterKind kind)550     SetRegisterKind (lldb::RegisterKind kind)
551     {
552         m_register_kind = kind;
553     }
554 
555     void
SetReturnAddressRegister(uint32_t regnum)556     SetReturnAddressRegister (uint32_t regnum)
557     {
558         m_return_addr_register = regnum;
559     }
560 
561     uint32_t
GetReturnAddressRegister(void)562     GetReturnAddressRegister (void)
563     {
564         return m_return_addr_register;
565     }
566 
567     uint32_t
GetInitialCFARegister()568     GetInitialCFARegister () const
569     {
570         if (m_row_list.empty())
571             return LLDB_INVALID_REGNUM;
572         return m_row_list.front()->GetCFAValue().GetRegisterNumber();
573     }
574 
575     // This UnwindPlan may not be valid at every address of the function span.
576     // For instance, a FastUnwindPlan will not be valid at the prologue setup
577     // instructions - only in the body of the function.
578     void
579     SetPlanValidAddressRange (const AddressRange& range);
580 
581     const AddressRange &
GetAddressRange()582     GetAddressRange () const
583     {
584         return m_plan_valid_address_range;
585     }
586 
587     bool
588     PlanValidAtAddress (Address addr);
589 
590     bool
591     IsValidRowIndex (uint32_t idx) const;
592 
593     const UnwindPlan::RowSP
594     GetRowAtIndex (uint32_t idx) const;
595 
596     const UnwindPlan::RowSP
597     GetLastRow () const;
598 
599     lldb_private::ConstString
600     GetSourceName () const;
601 
602     void
603     SetSourceName (const char *);
604 
605     // Was this UnwindPlan emitted by a compiler?
606     lldb_private::LazyBool
GetSourcedFromCompiler()607     GetSourcedFromCompiler () const
608     {
609         return m_plan_is_sourced_from_compiler;
610     }
611 
612     // Was this UnwindPlan emitted by a compiler?
613     void
SetSourcedFromCompiler(lldb_private::LazyBool from_compiler)614     SetSourcedFromCompiler (lldb_private::LazyBool from_compiler)
615     {
616         m_plan_is_sourced_from_compiler = from_compiler;
617     }
618 
619     // Is this UnwindPlan valid at all instructions?  If not, then it is assumed valid at call sites,
620     // e.g. for exception handling.
621     lldb_private::LazyBool
GetUnwindPlanValidAtAllInstructions()622     GetUnwindPlanValidAtAllInstructions () const
623     {
624         return m_plan_is_valid_at_all_instruction_locations;
625     }
626 
627     // Is this UnwindPlan valid at all instructions?  If not, then it is assumed valid at call sites,
628     // e.g. for exception handling.
629     void
SetUnwindPlanValidAtAllInstructions(lldb_private::LazyBool valid_at_all_insn)630     SetUnwindPlanValidAtAllInstructions (lldb_private::LazyBool valid_at_all_insn)
631     {
632         m_plan_is_valid_at_all_instruction_locations = valid_at_all_insn;
633     }
634 
635     int
636     GetRowCount () const;
637 
638     void
Clear()639     Clear()
640     {
641         m_row_list.clear();
642         m_plan_valid_address_range.Clear();
643         m_register_kind = lldb::eRegisterKindDWARF;
644         m_source_name.Clear();
645         m_plan_is_sourced_from_compiler = eLazyBoolCalculate;
646         m_plan_is_valid_at_all_instruction_locations = eLazyBoolCalculate;
647         m_lsda_address.Clear();
648         m_personality_func_addr.Clear();
649     }
650 
651     const RegisterInfo *
652     GetRegisterInfo (Thread* thread, uint32_t reg_num) const;
653 
654     Address
GetLSDAAddress()655     GetLSDAAddress () const
656     {
657         return m_lsda_address;
658     }
659 
660     void
SetLSDAAddress(Address lsda_addr)661     SetLSDAAddress (Address lsda_addr)
662     {
663         m_lsda_address = lsda_addr;
664     }
665 
666     Address
GetPersonalityFunctionPtr()667     GetPersonalityFunctionPtr () const
668     {
669         return m_personality_func_addr;
670     }
671 
672     void
SetPersonalityFunctionPtr(Address presonality_func_ptr)673     SetPersonalityFunctionPtr (Address presonality_func_ptr)
674     {
675         m_personality_func_addr = presonality_func_ptr;
676     }
677 
678 private:
679 
680 
681     typedef std::vector<RowSP> collection;
682     collection m_row_list;
683     AddressRange m_plan_valid_address_range;
684     lldb::RegisterKind m_register_kind;   // The RegisterKind these register numbers are in terms of - will need to be
685                                           // translated to lldb native reg nums at unwind time
686     uint32_t m_return_addr_register;      // The register that has the return address for the caller frame
687                                           // e.g. the lr on arm
688     lldb_private::ConstString m_source_name;  // for logging, where this UnwindPlan originated from
689     lldb_private::LazyBool m_plan_is_sourced_from_compiler;
690     lldb_private::LazyBool m_plan_is_valid_at_all_instruction_locations;
691 
692     Address m_lsda_address;                 // Where the language specific data area exists in the module - used
693                                             // in exception handling.
694     Address m_personality_func_addr;        // The address of a pointer to the personality function - used in
695                                             // exception handling.
696 }; // class UnwindPlan
697 
698 } // namespace lldb_private
699 
700 #endif //liblldb_UnwindPlan_h
701