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 ®s, 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