1472758f3SLionel Sambuc //===------------------------- UnwindCursor.hpp ---------------------------===//
2472758f3SLionel Sambuc //
3472758f3SLionel Sambuc // The LLVM Compiler Infrastructure
4472758f3SLionel Sambuc //
5472758f3SLionel Sambuc // This file is dual licensed under the MIT and the University of Illinois Open
6472758f3SLionel Sambuc // Source Licenses. See LICENSE.TXT for details.
7472758f3SLionel Sambuc //
8472758f3SLionel Sambuc //
9472758f3SLionel Sambuc // C++ interface to lower levels of libuwind
10472758f3SLionel Sambuc //===----------------------------------------------------------------------===//
11472758f3SLionel Sambuc
12472758f3SLionel Sambuc #ifndef __UNWINDCURSOR_HPP__
13472758f3SLionel Sambuc #define __UNWINDCURSOR_HPP__
14472758f3SLionel Sambuc
15472758f3SLionel Sambuc #include <stdint.h>
16472758f3SLionel Sambuc #include <stdlib.h>
17472758f3SLionel Sambuc #if !defined(__minix)
18472758f3SLionel Sambuc #include <pthread.h>
19472758f3SLionel Sambuc #endif /* !defined(__minix) */
20472758f3SLionel Sambuc
21472758f3SLionel Sambuc #include "AddressSpace.hpp"
22472758f3SLionel Sambuc #include "DwarfInstructions.hpp"
23472758f3SLionel Sambuc #include "Registers.hpp"
24472758f3SLionel Sambuc
25472758f3SLionel Sambuc namespace _Unwind {
26472758f3SLionel Sambuc
27472758f3SLionel Sambuc template <typename A, typename R> class UnwindCursor {
28472758f3SLionel Sambuc public:
UnwindCursor(R & regs,A & as)29472758f3SLionel Sambuc UnwindCursor(R ®s, A &as)
30472758f3SLionel Sambuc : fRegisters(regs), fAddressSpace(as), fUnwindInfoMissing(false),
31472758f3SLionel Sambuc fIsSignalFrame(false) {
32472758f3SLionel Sambuc memset(&fInfo, 0, sizeof(fInfo));
33472758f3SLionel Sambuc }
34472758f3SLionel Sambuc
getIP() const35472758f3SLionel Sambuc uint64_t getIP() const { return fRegisters.getIP(); }
36472758f3SLionel Sambuc
setIP(uint64_t value)37472758f3SLionel Sambuc void setIP(uint64_t value) { return fRegisters.setIP(value); }
38472758f3SLionel Sambuc
getSP() const39472758f3SLionel Sambuc uint64_t getSP() const { return fRegisters.getSP(); }
40472758f3SLionel Sambuc
setSP(uint64_t value)41472758f3SLionel Sambuc void setSP(uint64_t value) { return fRegisters.setSP(value); }
42472758f3SLionel Sambuc
validReg(int regNum)43472758f3SLionel Sambuc bool validReg(int regNum) { return fRegisters.validRegister(regNum); }
44472758f3SLionel Sambuc
getReg(int regNum)45472758f3SLionel Sambuc uint64_t getReg(int regNum) { return fRegisters.getRegister(regNum); }
46472758f3SLionel Sambuc
setReg(int regNum,uint64_t value)47472758f3SLionel Sambuc void setReg(int regNum, uint64_t value) {
48472758f3SLionel Sambuc fRegisters.setRegister(regNum, value);
49472758f3SLionel Sambuc }
50472758f3SLionel Sambuc
step()51472758f3SLionel Sambuc step_result step() {
52472758f3SLionel Sambuc // Bottom of stack is defined as having no more unwind info.
53472758f3SLionel Sambuc if (fUnwindInfoMissing)
54472758f3SLionel Sambuc return UNW_STEP_END;
55472758f3SLionel Sambuc
56472758f3SLionel Sambuc // Apply unwinding to register set.
57472758f3SLionel Sambuc switch (this->stepWithDwarfFDE()) {
58472758f3SLionel Sambuc case UNW_STEP_FAILED:
59472758f3SLionel Sambuc return UNW_STEP_FAILED;
60472758f3SLionel Sambuc case UNW_STEP_END:
61472758f3SLionel Sambuc return UNW_STEP_END;
62472758f3SLionel Sambuc case UNW_STEP_SUCCESS:
63472758f3SLionel Sambuc this->setInfoBasedOnIPRegister(true);
64472758f3SLionel Sambuc if (fUnwindInfoMissing)
65472758f3SLionel Sambuc return UNW_STEP_END;
66*b029fb59SBen Gras
67*b029fb59SBen Gras if (fInfo.extra_args)
68*b029fb59SBen Gras setSP(getSP() + fInfo.extra_args);
69472758f3SLionel Sambuc return UNW_STEP_SUCCESS;
70472758f3SLionel Sambuc }
71472758f3SLionel Sambuc __builtin_unreachable();
72472758f3SLionel Sambuc }
73472758f3SLionel Sambuc
getInfo(unw_proc_info_t * info)74472758f3SLionel Sambuc void getInfo(unw_proc_info_t *info) { *info = fInfo; }
75472758f3SLionel Sambuc
isSignalFrame()76472758f3SLionel Sambuc bool isSignalFrame() { return fIsSignalFrame; }
77472758f3SLionel Sambuc void setInfoBasedOnIPRegister(bool isReturnAddress = false);
78472758f3SLionel Sambuc
jumpto()79472758f3SLionel Sambuc void jumpto() { fRegisters.jumpto(); }
80472758f3SLionel Sambuc
81472758f3SLionel Sambuc private:
82472758f3SLionel Sambuc typedef typename A::pint_t pint_t;
83472758f3SLionel Sambuc typedef uint32_t EncodedUnwindInfo;
84472758f3SLionel Sambuc
85472758f3SLionel Sambuc bool getInfoFromDwarfSection(pint_t, pint_t, uint32_t, uint32_t);
86472758f3SLionel Sambuc
stepWithDwarfFDE()87472758f3SLionel Sambuc step_result stepWithDwarfFDE() {
88472758f3SLionel Sambuc return DwarfInstructions<A, R>::stepWithDwarf(
89472758f3SLionel Sambuc fAddressSpace, this->getIP(), fInfo.unwind_info, fRegisters, &fInfo);
90472758f3SLionel Sambuc }
91472758f3SLionel Sambuc
92472758f3SLionel Sambuc unw_proc_info_t fInfo;
93472758f3SLionel Sambuc R fRegisters;
94472758f3SLionel Sambuc A &fAddressSpace;
95472758f3SLionel Sambuc bool fUnwindInfoMissing;
96472758f3SLionel Sambuc bool fIsSignalFrame;
97472758f3SLionel Sambuc };
98472758f3SLionel Sambuc
99472758f3SLionel Sambuc template <typename A, typename R>
setInfoBasedOnIPRegister(bool isReturnAddress)100472758f3SLionel Sambuc void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
101472758f3SLionel Sambuc pint_t pc = this->getIP();
102472758f3SLionel Sambuc
103472758f3SLionel Sambuc // If the last line of a function is a "throw", the compiler sometimes
104472758f3SLionel Sambuc // emits no instructions after the call to __cxa_throw. This means
105472758f3SLionel Sambuc // the return address is actually the start of the next function.
106472758f3SLionel Sambuc // To disambiguate this, back up the PC when we know it is a return
107472758f3SLionel Sambuc // address.
108472758f3SLionel Sambuc if (isReturnAddress)
109472758f3SLionel Sambuc --pc;
110472758f3SLionel Sambuc
111472758f3SLionel Sambuc pint_t fdeStart, data_base;
112472758f3SLionel Sambuc if (!fAddressSpace.findFDE(pc, fdeStart, data_base)) {
113472758f3SLionel Sambuc fUnwindInfoMissing = true;
114472758f3SLionel Sambuc return;
115472758f3SLionel Sambuc }
116472758f3SLionel Sambuc fInfo.data_base = data_base;
117472758f3SLionel Sambuc
118472758f3SLionel Sambuc typename CFI_Parser<A, R>::FDE_Info fdeInfo;
119472758f3SLionel Sambuc typename CFI_Parser<A, R>::CIE_Info cieInfo;
120472758f3SLionel Sambuc CFI_Parser<A, R>::decodeFDE(fAddressSpace, fdeStart, &fdeInfo, &cieInfo,
121472758f3SLionel Sambuc &fInfo);
122472758f3SLionel Sambuc if (pc < fdeInfo.pcStart || pc > fdeInfo.pcEnd) {
123472758f3SLionel Sambuc fUnwindInfoMissing = true;
124472758f3SLionel Sambuc return;
125472758f3SLionel Sambuc }
126472758f3SLionel Sambuc fInfo.start_ip = fdeInfo.pcStart;
127472758f3SLionel Sambuc
128472758f3SLionel Sambuc typename CFI_Parser<A, R>::PrologInfo prolog;
129472758f3SLionel Sambuc if (!CFI_Parser<A, R>::parseFDEInstructions(fAddressSpace, fdeInfo, cieInfo,
130472758f3SLionel Sambuc pc, &prolog, &fInfo)) {
131472758f3SLionel Sambuc fUnwindInfoMissing = true;
132472758f3SLionel Sambuc return;
133472758f3SLionel Sambuc }
134472758f3SLionel Sambuc // Save off parsed FDE info
135472758f3SLionel Sambuc fInfo.end_ip = fdeInfo.pcEnd;
136472758f3SLionel Sambuc fInfo.lsda = fdeInfo.lsda;
137472758f3SLionel Sambuc fInfo.handler = cieInfo.personality;
138472758f3SLionel Sambuc fInfo.extra_args = prolog.spExtraArgSize;
139472758f3SLionel Sambuc fInfo.unwind_info = fdeInfo.fdeStart;
140472758f3SLionel Sambuc }
141472758f3SLionel Sambuc
142472758f3SLionel Sambuc }; // namespace _Unwind
143472758f3SLionel Sambuc
144472758f3SLionel Sambuc #endif // __UNWINDCURSOR_HPP__
145