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