xref: /netbsd-src/sys/lib/libunwind/UnwindCursor.hpp (revision 6cf6fe02a981b55727c49c3d37b0d8191a98c0ee)
1 //===------------------------- UnwindCursor.hpp ---------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.TXT for details.
7 //
8 //
9 // C++ interface to lower levels of libuwind
10 //===----------------------------------------------------------------------===//
11 
12 #ifndef __UNWINDCURSOR_HPP__
13 #define __UNWINDCURSOR_HPP__
14 
15 #include <stdint.h>
16 #include <stdlib.h>
17 #include <pthread.h>
18 
19 #include "AddressSpace.hpp"
20 #include "DwarfInstructions.hpp"
21 #include "Registers.hpp"
22 
23 namespace _Unwind {
24 
25 template <typename A, typename R> class UnwindCursor {
26 public:
27   UnwindCursor(R &regs, A &as)
28       : fRegisters(regs), fAddressSpace(as), fUnwindInfoMissing(false),
29         fIsSignalFrame(false) {
30     memset(&fInfo, 0, sizeof(fInfo));
31   }
32 
33   uint64_t getIP() const { return fRegisters.getIP(); }
34 
35   void setIP(uint64_t value) { return fRegisters.setIP(value); }
36 
37   uint64_t getSP() const { return fRegisters.getSP(); }
38 
39   void setSP(uint64_t value) { return fRegisters.setSP(value); }
40 
41   bool validReg(int regNum) { return fRegisters.validRegister(regNum); }
42 
43   uint64_t getReg(int regNum) { return fRegisters.getRegister(regNum); }
44 
45   void setReg(int regNum, uint64_t value) {
46     fRegisters.setRegister(regNum, value);
47   }
48 
49   step_result step() {
50     // Bottom of stack is defined as having no more unwind info.
51     if (fUnwindInfoMissing)
52       return UNW_STEP_END;
53 
54     // Apply unwinding to register set.
55     switch (this->stepWithDwarfFDE()) {
56     case UNW_STEP_FAILED:
57       return UNW_STEP_FAILED;
58     case UNW_STEP_END:
59       return UNW_STEP_END;
60     case UNW_STEP_SUCCESS:
61       this->setInfoBasedOnIPRegister(true);
62       if (fUnwindInfoMissing)
63         return UNW_STEP_END;
64 
65       if (fInfo.extra_args)
66         setSP(getSP() + fInfo.extra_args);
67       return UNW_STEP_SUCCESS;
68     }
69     __builtin_unreachable();
70   }
71 
72   void getInfo(unw_proc_info_t *info) { *info = fInfo; }
73 
74   bool isSignalFrame() { return fIsSignalFrame; }
75   void setInfoBasedOnIPRegister(bool isReturnAddress = false);
76 
77   void jumpto() { fRegisters.jumpto(); }
78 
79 private:
80   typedef typename A::pint_t pint_t;
81   typedef uint32_t EncodedUnwindInfo;
82 
83   bool getInfoFromDwarfSection(pint_t, pint_t, uint32_t, uint32_t);
84 
85   step_result stepWithDwarfFDE() {
86     return DwarfInstructions<A, R>::stepWithDwarf(
87         fAddressSpace, this->getIP(), fInfo.unwind_info, fRegisters, &fInfo);
88   }
89 
90   unw_proc_info_t fInfo;
91   R fRegisters;
92   A &fAddressSpace;
93   bool fUnwindInfoMissing;
94   bool fIsSignalFrame;
95 };
96 
97 template <typename A, typename R>
98 void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
99   pint_t pc = this->getIP();
100 
101   // If the last line of a function is a "throw", the compiler sometimes
102   // emits no instructions after the call to __cxa_throw.  This means
103   // the return address is actually the start of the next function.
104   // To disambiguate this, back up the PC when we know it is a return
105   // address.
106   if (isReturnAddress)
107     --pc;
108 
109   pint_t fdeStart, data_base;
110   if (!fAddressSpace.findFDE(pc, fdeStart, data_base)) {
111     fUnwindInfoMissing = true;
112     return;
113   }
114   fInfo.data_base = data_base;
115 
116   typename CFI_Parser<A, R>::FDE_Info fdeInfo;
117   typename CFI_Parser<A, R>::CIE_Info cieInfo;
118   CFI_Parser<A, R>::decodeFDE(fAddressSpace, fdeStart, &fdeInfo, &cieInfo,
119                               &fInfo);
120   if (pc < fdeInfo.pcStart || pc > fdeInfo.pcEnd) {
121     fUnwindInfoMissing = true;
122     return;
123   }
124   fInfo.start_ip = fdeInfo.pcStart;
125 
126   typename CFI_Parser<A, R>::PrologInfo prolog;
127   if (!CFI_Parser<A, R>::parseFDEInstructions(fAddressSpace, fdeInfo, cieInfo,
128                                               pc, &prolog, &fInfo)) {
129     fUnwindInfoMissing = true;
130     return;
131   }
132   // Save off parsed FDE info
133   fInfo.end_ip = fdeInfo.pcEnd;
134   fInfo.lsda = fdeInfo.lsda;
135   fInfo.handler = cieInfo.personality;
136   fInfo.extra_args = prolog.spExtraArgSize;
137   fInfo.unwind_info = fdeInfo.fdeStart;
138 }
139 
140 }; // namespace _Unwind
141 
142 #endif // __UNWINDCURSOR_HPP__
143