The Pedigree Project 0.1
DwarfUnwinder.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "pedigree/kernel/Log.h"
21#include "pedigree/kernel/debugger/DwarfCfiAutomaton.h"
22#include "pedigree/kernel/debugger/DwarfState.h"
23#include "pedigree/kernel/debugger/DwarfUnwinder.h"
24#include "pedigree/kernel/processor/state.h"
25
26template <class T>
27void fillDwarfState(DwarfState& outState, const T& inState);
28
29template <class T>
30void extractDwarfState(const DwarfState* endState, const DwarfState& startState, T& outState,
31 uint32_t nReturnAddressRegister);
32
33template <>
34void fillDwarfState(DwarfState& outState, const X64ProcessorState& inState) {
35 outState.m_R[DWARF_REG_RAX] = inState.rax;
36 outState.m_R[DWARF_REG_RDX] = inState.rdx;
37 outState.m_R[DWARF_REG_RCX] = inState.rcx;
38 outState.m_R[DWARF_REG_RBX] = inState.rbx;
39 outState.m_R[DWARF_REG_RSI] = inState.rsi;
40 outState.m_R[DWARF_REG_RDI] = inState.rdi;
41 outState.m_R[DWARF_REG_RBP] = inState.rbp;
42 outState.m_R[DWARF_REG_RSP] = inState.rsp;
43 outState.m_R[DWARF_REG_R8] = inState.r8;
44 outState.m_R[DWARF_REG_R9] = inState.r9;
45 outState.m_R[DWARF_REG_R10] = inState.r10;
46 outState.m_R[DWARF_REG_R11] = inState.r11;
47 outState.m_R[DWARF_REG_R12] = inState.r12;
48 outState.m_R[DWARF_REG_R13] = inState.r13;
49 outState.m_R[DWARF_REG_R14] = inState.r14;
50 outState.m_R[DWARF_REG_R15] = inState.r15;
51 outState.m_R[DWARF_REG_RFLAGS] = inState.rflags;
52}
53
54template <>
55void extractDwarfState(const DwarfState* endState, const DwarfState& startState,
56 X64ProcessorState& outState, uint32_t nReturnAddressRegister) {
57 outState.rax = endState->getRegister(DWARF_REG_RAX, startState);
58 outState.rdx = endState->getRegister(DWARF_REG_RDX, startState);
59 outState.rcx = endState->getRegister(DWARF_REG_RCX, startState);
60 outState.rbx = endState->getRegister(DWARF_REG_RBX, startState);
61 outState.rsi = endState->getRegister(DWARF_REG_RSI, startState);
62 outState.rdi = endState->getRegister(DWARF_REG_RDI, startState);
63 outState.rbp = endState->getRegister(DWARF_REG_RBP, startState);
64 outState.rsp = endState->getCfa(startState); // Architectural rule.
65 outState.r8 = endState->getRegister(DWARF_REG_R8, startState);
66 outState.r9 = endState->getRegister(DWARF_REG_R9, startState);
67 outState.r10 = endState->getRegister(DWARF_REG_R10, startState);
68 outState.r11 = endState->getRegister(DWARF_REG_R11, startState);
69 outState.r12 = endState->getRegister(DWARF_REG_R12, startState);
70 outState.r13 = endState->getRegister(DWARF_REG_R13, startState);
71 outState.r14 = endState->getRegister(DWARF_REG_R14, startState);
72 outState.r15 = endState->getRegister(DWARF_REG_R15, startState);
73 outState.rflags = endState->getRegister(DWARF_REG_RFLAGS, startState);
74 outState.rip = endState->getRegister(nReturnAddressRegister, startState);
75}
76
77template <>
78void extractDwarfState(const DwarfState* endState, const DwarfState& startState,
79 HostedProcessorState& outState, uint32_t nReturnAddressRegister) {
81}
82
83template <>
84void fillDwarfState(DwarfState& outState, const HostedProcessorState& inState) {
86}
87
88#if ARM64
89template <>
90void fillDwarfState(DwarfState& outState, const Arm64ProcessorState& inState) {
91 for (size_t i = 0; i < 31; ++i) {
92 outState.m_R[i] = inState.x[i];
93 }
94 outState.m_R[31] = inState.sp;
95 outState.m_R[32] = inState.pc;
96 outState.m_R[33] = inState.pstate;
97}
98
99template <>
100void extractDwarfState(const DwarfState* endState, const DwarfState& startState,
101 Arm64ProcessorState& outState, uint32_t returnRegister) {
102 for (size_t i = 0; i < 31; ++i) {
103 outState.x[i] = endState->getRegister(i, startState);
104 }
105 outState.sp = endState->getCfa(startState);
106 outState.pc = endState->getRegister(returnRegister, startState);
107 outState.pstate = startState.m_R[33];
108}
109#endif
110
111#if ARMV7
112template <>
113void fillDwarfState(DwarfState& outState, const Armv7ProcessorState& inState) {
114 for (size_t i = 0; i < 13; ++i) {
115 outState.m_R[i] = inState.r[i];
116 }
117 outState.m_R[13] = inState.sp;
118 outState.m_R[14] = inState.lr;
119 outState.m_R[15] = inState.pc;
120 outState.m_R[16] = inState.cpsr;
121}
122
123template <>
124void extractDwarfState(const DwarfState* endState, const DwarfState& startState,
125 Armv7ProcessorState& outState, uint32_t returnRegister) {
126 for (size_t i = 0; i < 13; ++i) {
127 outState.r[i] = endState->getRegister(i, startState);
128 }
129 outState.sp = endState->getCfa(startState);
130 outState.lr = endState->getRegister(14, startState);
131 outState.pc = endState->getRegister(returnRegister, startState);
132 outState.cpsr = startState.m_R[16];
133}
134#endif
135
136DwarfUnwinder::DwarfUnwinder(uintptr_t nData, size_t nLength)
137 : m_nData(nData), m_nLength(nLength) {}
138
139DwarfUnwinder::~DwarfUnwinder() {}
140
141bool DwarfUnwinder::unwind(const ProcessorState& inState, ProcessorState& outState,
142 uintptr_t& frameBase) {
143 // Construct a DwarfState object and populate it.
144 DwarfState startState;
145
146 fillDwarfState(startState, inState);
147
148 // For each CIE or FDE...
149 size_t nIndex = 0;
150 while (nIndex < m_nLength) {
151 // Get the length of this entry.
152 uint32_t nLength = *reinterpret_cast<uint32_t*>(m_nData + nIndex);
153
154 nIndex += sizeof(uint32_t);
155 const uint32_t k_nCieId = 0xFFFFFFFF;
156
157 if (nLength == 0xFFFFFFFF) {
158 ERROR_NOLOCK("64-bit DWARF file detected, but not supported!");
159 return false;
160 }
161
162 // Get the type of this entry (or CIE pointer if this is a FDE).
163 uint32_t nCie = *reinterpret_cast<uint32_t*>(m_nData + nIndex);
164 nIndex += sizeof(uint32_t);
165
166 // Is this a CIE?
167 if (nCie == k_nCieId) {
168 // Skip over everything.
169 nIndex += nLength - sizeof(processor_register_t);
170 continue;
171 }
172
173 // This is a FDE. Get its initial location.
174 uintptr_t nInitialLocation = *reinterpret_cast<uintptr_t*>(m_nData + nIndex);
175 nIndex += sizeof(uintptr_t);
176
177 // Get its addressing range.
178 size_t nAddressRange = *reinterpret_cast<size_t*>(m_nData + nIndex);
179 nIndex += sizeof(size_t);
180
181 uintptr_t nInstructionStart = nIndex;
182 size_t nInstructionLength = nLength - sizeof(uint32_t) - sizeof(uintptr_t) - sizeof(size_t);
183
184 // Are we in this range?
185 if ((inState.getInstructionPointer() < nInitialLocation) ||
186 (inState.getInstructionPointer() >= nInitialLocation + nAddressRange)) {
187 nIndex += nInstructionLength;
188 continue;
189 }
190
191 // This is a FDE. Get the CIE it corresponds to.
192 uint32_t nCieEnd = *reinterpret_cast<uint32_t*>(m_nData + nCie) + nCie;
193 nCie += sizeof(uint32_t);
194 nCieEnd += sizeof(uint32_t);
195
196 // Ensure our CIE ID is correct.
197 uint32_t nCieId = *reinterpret_cast<uint32_t*>(m_nData + nCie);
198 if (nCieId != k_nCieId) {
199 WARNING_NOLOCK("DwarfUnwinder::unwind - CIE ID incorrect!");
200 return false;
201 }
202 nCie += sizeof(uint32_t);
203 nCie += 1; // Increment over version byte.
204
205 const char* pAugmentationString = reinterpret_cast<const char*>(m_nData + nCie);
206 while (*pAugmentationString++) // Pass over the augmentation string,
207 // waiting for a NULL char.
208 nCie++;
209 nCie++; // Step over null byte.
210
211 uint8_t* pData = reinterpret_cast<uint8_t*>(m_nData);
212 int32_t nCodeAlignmentFactor = decodeUleb128(pData, nCie);
213 int32_t nDataAlignmentFactor = decodeSleb128(pData, nCie);
214 uint32_t nReturnAddressRegister = 0;
215 EMIT_IF(!HOSTED) {
216 nReturnAddressRegister = decodeUleb128(pData, nCie);
217 }
218
219 DwarfCfiAutomaton automaton;
220 automaton.initialise(startState, m_nData + nCie, nCieEnd - nCie, nCodeAlignmentFactor,
221 nDataAlignmentFactor, nInitialLocation);
222 DwarfState* endState = automaton.execute(m_nData + nInstructionStart, nInstructionLength,
223 inState.getInstructionPointer());
224 frameBase = endState->getCfa(startState);
225
226 extractDwarfState(endState, startState, outState, nReturnAddressRegister);
227
228 return true;
229 }
230
231 return false;
232}
233
234uint32_t DwarfUnwinder::decodeUleb128(uint8_t* pBase, uint32_t& nOffset) {
235 uint32_t result = 0;
236 uint32_t shift = 0;
237 while (true) {
238 uint8_t byte = pBase[nOffset++];
239 result |= (byte & 0x7f) << shift;
240 if ((byte & 0x80) == 0)
241 break;
242 shift += 7;
243 }
244 return result;
245}
246
247int32_t DwarfUnwinder::decodeSleb128(uint8_t* pBase, uint32_t& nOffset) {
248 int32_t result = 0;
249 uint32_t shift = 0;
250 uint8_t byte;
251 while (true) {
252 byte = pBase[nOffset++];
253 result |= (byte & 0x7f) << shift;
254 shift += 7;
255 if ((byte & 0x80) == 0)
256 break;
257 }
258 if ((shift < sizeof(int32_t) * 8) && (byte & 0x40)) /* If sign bit of byte is set */
259 result |= -(1 << shift); /* sign extend */
260 return result;
261}
void initialise(const DwarfState &startingState, uintptr_t nCodeLocation, size_t nCodeLen, int32_t nCodeAlignmentFactor, int32_t nDataAlignmentFactor, uintptr_t nStartingPc)
DwarfState * execute(uintptr_t nCodeLocation, size_t nCodeLen, uintptr_t nBreakAt)
processor_register_t getRegister(unsigned int nRegister, const DwarfState &initialState) const
Definition DwarfState.h:136
processor_register_t m_R[DWARF_MAX_REGISTERS]
Definition DwarfState.h:202
DwarfUnwinder(uintptr_t nData, size_t nLength)
static uint32_t decodeUleb128(uint8_t *pBase, uint32_t &nOffset)
static int32_t decodeSleb128(uint8_t *pBase, uint32_t &nOffset)
uintptr_t m_nData
bool unwind(const ProcessorState &inState, ProcessorState &outState, uintptr_t &frameBase)