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