The Pedigree Project 0.1
Backtrace.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/Backtrace.h"
22#include "pedigree/kernel/debugger/DwarfUnwinder.h"
23#include "pedigree/kernel/linker/KernelElf.h"
24#include "pedigree/kernel/processor/Processor.h"
25#include "pedigree/kernel/processor/ProcessorInformation.h"
26#include "pedigree/kernel/processor/StackFrame.h"
27#include "pedigree/kernel/processor/VirtualAddressSpace.h"
28
29extern uintptr_t start;
30
31Backtrace::Backtrace() : m_nStackFrames(0) {}
32
33Backtrace::~Backtrace() {}
34
35void Backtrace::performBacktrace(InterruptState& state) {
36#ifdef DWARF
37 // Firstly, can we perform a DWARF backtrace?
38 if (KernelElf::instance().debugFrameTable() > 0 /*&& g_pKernel->debugFrameTableLength() > 0*/) {
40 return;
41 }
42#else
43 WARNING_NOLOCK("Backtracer built without DWARF enabled.");
44#endif
45 // Can we perform a "normal", base-pointer-linked-list backtrace?
46 // Don't lock on the log - we may have hit a backtrace because the Log lock
47 // deadlocked
48 WARNING_NOLOCK("Dwarf backtracing not available.");
49#if X86_COMMON || HOSTED
50 performBpBacktrace(state.getBasePointer(), state.getInstructionPointer());
51#else
52 ERROR_NOLOCK("Backtrace: No backtracing method available!");
53#endif
54}
55
56void Backtrace::performDwarfBacktrace(InterruptState& state) {
57 ProcessorState initial(state);
58 ProcessorState next;
59
60 size_t i = 0;
61 DwarfUnwinder du(KernelElf::instance().debugFrameTable(),
62 KernelElf::instance().debugFrameTableLength());
63 uintptr_t frameBase;
64 while (i < MAX_STACK_FRAMES) {
65 if (!du.unwind(initial, next, frameBase)) {
66 m_pReturnAddresses[i++] = initial.getInstructionPointer();
67 break;
68 }
69
70 m_pStates[i] = next;
71 m_pBasePointers[i] = frameBase;
72 // This may look strange but it's correct - the i'th instruction pointer
73 // is the (i-1)'th return address.
74 m_pReturnAddresses[i] = initial.getInstructionPointer();
75 initial = next;
76 i++;
77 }
78
80}
81
82void Backtrace::performBpBacktrace(uintptr_t base, uintptr_t instruction) {
83 if (base == 0)
85 if (instruction == 0)
87
88 size_t i = 1;
89 m_pBasePointers[0] = base;
90 m_pReturnAddresses[0] = instruction;
91
92 while (i < MAX_STACK_FRAMES) {
93 // Sanity check: would we fault by reading this address?
94 if (Processor::information().getVirtualAddressSpace().isMapped(reinterpret_cast<void*>(base)) &&
95 Processor::information().getVirtualAddressSpace().isMapped(
96 reinterpret_cast<void*>(base + sizeof(uintptr_t)))) {
97 uintptr_t nextAddress = *reinterpret_cast<uintptr_t*>(base);
98
99 m_pReturnAddresses[i] = *reinterpret_cast<uintptr_t*>(base + sizeof(uintptr_t));
100 m_pBasePointers[i] = nextAddress;
101
102 base = nextAddress;
103
104 m_pStates[i].setBasePointer(m_pBasePointers[i]);
105 m_pStates[i].setInstructionPointer(m_pReturnAddresses[i]);
106
107 i++;
108
109 if (nextAddress == 0)
110 break;
111 } else {
112 break;
113 }
114 }
115
116 m_nStackFrames = i;
117}
118
119void Backtrace::prettyPrint(HugeStaticString& buf, size_t nFrames, size_t nFromFrame) {
120 if (nFrames == 0 || nFrames > m_nStackFrames)
121 nFrames = m_nStackFrames;
122 // What symbol are we in?
123 // TODO grep the memory map for the right ELF to look at.
124
125 for (size_t i = nFromFrame; i < nFrames + nFromFrame; i++) {
126 uintptr_t symStart = 0;
127
129
130 const char* pSym = KernelElf::instance().globalLookupSymbol(m_pReturnAddresses[i], &symStart);
131 if (pSym == 0) {
132 row += "[";
133 row.append(m_pReturnAddresses[i], 16);
134 row += "]\n";
135 } else {
136 LargeStaticString sym(pSym);
137
138 row += "[";
139 row.append(m_pReturnAddresses[i], 16);
140 row += "] ";
141#if DEBUGGER
142 StackFrame sf(m_pStates[i], m_pBasePointers[i], sym);
143 sf.prettyPrint(row);
144#else
145 row += sym;
146 row += "\n";
147#endif
148 }
149
150 buf.append(row);
151 }
152}
153
155 return m_nStackFrames;
156}
157
158uintptr_t Backtrace::getReturnAddress(size_t n) {
159 // ASSERT(n < m_nStackFrames);
160 return m_pReturnAddresses[n];
161}
162
163uintptr_t Backtrace::getBasePointer(size_t n) {
164 // ASSERT(n < m_nStackFrames);
165 return m_pBasePointers[n];
166}
void performBacktrace(InterruptState &state)
Definition Backtrace.cc:35
size_t numStackFrames()
Definition Backtrace.cc:154
uintptr_t m_pReturnAddresses[MAX_STACK_FRAMES]
Definition Backtrace.h:84
void performBpBacktrace(uintptr_t base, uintptr_t instruction)
Definition Backtrace.cc:82
uintptr_t getBasePointer(size_t n)
Definition Backtrace.cc:163
void performDwarfBacktrace(InterruptState &state)
Definition Backtrace.cc:56
ProcessorState m_pStates[MAX_STACK_FRAMES]
Definition Backtrace.h:93
uintptr_t getReturnAddress(size_t n)
Definition Backtrace.cc:158
uintptr_t m_pBasePointers[MAX_STACK_FRAMES]
Definition Backtrace.h:88
size_t m_nStackFrames
Definition Backtrace.h:98
bool unwind(const ProcessorState &inState, ProcessorState &outState, uintptr_t &frameBase)
static KernelElf & instance()
Definition KernelElf.h:135
uintptr_t globalLookupSymbol(const char *pName)
static uintptr_t getInstructionPointer()
static ProcessorInformation & information()
static uintptr_t getBasePointer()