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