xref: /netbsd-src/sys/lib/libunwind/UnwindCursor.hpp (revision 4e5ca533a952ec83c6f2a18561ee6bfb7360a56c)
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:
UnwindCursor(R & regs,A & as)27   UnwindCursor(R &regs, A &as)
28       : fRegisters(regs), fAddressSpace(as), fUnwindInfoMissing(false),
29         fIsSignalFrame(false) {
30     memset(&fInfo, 0, sizeof(fInfo));
31   }
32 
getIP() const33   uint64_t getIP() const { return fRegisters.getIP(); }
34 
setIP(uint64_t value)35   void setIP(uint64_t value) { return fRegisters.setIP(value); }
36 
getSP() const37   uint64_t getSP() const { return fRegisters.getSP(); }
38 
setSP(uint64_t value)39   void setSP(uint64_t value) { return fRegisters.setSP(value); }
40 
validReg(int regNum)41   bool validReg(int regNum) { return fRegisters.validRegister(regNum); }
42 
getReg(int regNum)43   uint64_t getReg(int regNum) { return fRegisters.getRegister(regNum); }
44 
setReg(int regNum,uint64_t value)45   void setReg(int regNum, uint64_t value) {
46     fRegisters.setRegister(regNum, value);
47   }
48 
step()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       return UNW_STEP_SUCCESS;
65     }
66     __builtin_unreachable();
67   }
68 
getInfo(unw_proc_info_t * info)69   void getInfo(unw_proc_info_t *info) { *info = fInfo; }
70 
isSignalFrame()71   bool isSignalFrame() { return fIsSignalFrame; }
72   void setInfoBasedOnIPRegister(bool isReturnAddress = false);
73 
jumpto()74   void jumpto() { fRegisters.jumpto(); }
75 
76 private:
77   typedef typename A::pint_t pint_t;
78   typedef uint32_t EncodedUnwindInfo;
79 
80   bool getInfoFromDwarfSection(pint_t, pint_t, uint32_t, uint32_t);
81 
stepWithDwarfFDE()82   step_result stepWithDwarfFDE() {
83     return DwarfInstructions<A, R>::stepWithDwarf(
84         fAddressSpace, this->getIP(), fInfo.unwind_info, fRegisters, &fInfo);
85   }
86 
87   unw_proc_info_t fInfo;
88   R fRegisters;
89   A &fAddressSpace;
90   bool fUnwindInfoMissing;
91   bool fIsSignalFrame;
92 };
93 
94 template <typename A, typename R>
setInfoBasedOnIPRegister(bool isReturnAddress)95 void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
96   pint_t pc = this->getIP();
97 
98   // If the last line of a function is a "throw", the compiler sometimes
99   // emits no instructions after the call to __cxa_throw.  This means
100   // the return address is actually the start of the next function.
101   // To disambiguate this, back up the PC when we know it is a return
102   // address.
103   if (isReturnAddress)
104     --pc;
105 
106   pint_t fdeStart, data_base;
107   if (!fAddressSpace.findFDE(pc, fdeStart, data_base)) {
108     fUnwindInfoMissing = true;
109     return;
110   }
111   fInfo.data_base = data_base;
112 
113   typename CFI_Parser<A, R>::FDE_Info fdeInfo;
114   typename CFI_Parser<A, R>::CIE_Info cieInfo;
115   CFI_Parser<A, R>::decodeFDE(fAddressSpace, fdeStart, &fdeInfo, &cieInfo,
116                               &fInfo);
117   if (pc < fdeInfo.pcStart || pc > fdeInfo.pcEnd) {
118     fUnwindInfoMissing = true;
119     return;
120   }
121   fInfo.start_ip = fdeInfo.pcStart;
122 
123   typename CFI_Parser<A, R>::PrologInfo prolog;
124   if (!CFI_Parser<A, R>::parseFDEInstructions(fAddressSpace, fdeInfo, cieInfo,
125                                               pc, &prolog, &fInfo)) {
126     fUnwindInfoMissing = true;
127     return;
128   }
129   // Save off parsed FDE info
130   fInfo.end_ip = fdeInfo.pcEnd;
131   fInfo.lsda = fdeInfo.lsda;
132   fInfo.handler = cieInfo.personality;
133   fInfo.extra_args = prolog.spExtraArgSize;
134   fInfo.unwind_info = fdeInfo.fdeStart;
135 }
136 
137 }; // namespace _Unwind
138 
139 #endif // __UNWINDCURSOR_HPP__
140