xref: /minix3/sys/lib/libunwind/UnwindCursor.hpp (revision b029fb598aff7d169ad9d60ec6eafa774faef921)
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 &regs, 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