The Pedigree Project 0.1
SlamCommand.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/debugger/DebuggerIO.h"
21#include "pedigree/kernel/debugger/commands/SlamCommand.h"
22#include "pedigree/kernel/linker/KernelElf.h"
23#include "pedigree/kernel/machine/Machine.h"
24#include "pedigree/kernel/machine/Serial.h"
25#include "pedigree/kernel/utilities/Iterator.h"
26#include "pedigree/kernel/utilities/demangle.h"
27#include "pedigree/kernel/utilities/utility.h"
28
29SlamCommand g_SlamCommand;
30
32 : DebuggerCommand(), Scrollable(), m_Tree(), m_It(), m_nLines(0), m_nIdx(0), m_Lock(false) {}
33
35
37
39 InterruptState& state, DebuggerIO* pScreen) {
40 bool bs = m_Lock;
41 m_Lock = true;
42
43 // How many lines do we have?
44 m_nLines = NUM_SLAM_BT_FRAMES + 1;
45
46 m_It = m_Tree.begin();
47 m_nIdx = 0;
48
49 // Let's enter 'raw' screen mode.
50 pScreen->disableCli();
51
52 // Initialise the Scrollable class
53 move(0, 1);
54 resize(pScreen->getWidth(), pScreen->getHeight() - 2);
55 setScrollKeys('j', 'k');
56
57 // Clear the top status lines.
58 pScreen->drawHorizontalLine(' ', 0, 0, pScreen->getWidth() - 1, DebuggerIO::White,
59 DebuggerIO::Green);
60
61 // Write the correct text in the upper status line.
62 pScreen->drawString("Pedigree debugger - Slam allocation resolver", 0, 0, DebuggerIO::White,
63 DebuggerIO::Green);
64
65 // Clear the bottom status lines.
66 // TODO: If we use arrow keys and page up/down keys we actually can remove
67 // the status line
68 // because the interface is then intuitive enough imho.
69 pScreen->drawHorizontalLine(' ', pScreen->getHeight() - 1, 0, pScreen->getWidth() - 1,
70 DebuggerIO::White, DebuggerIO::Green);
71
72 // Write some helper text in the lower status line.
73 // TODO FIXME: Drawing this might screw the top status bar
74 pScreen->drawString("q: Quit. c: Clean. d: Dump to serial. enter: Next allocation.",
75 pScreen->getHeight() - 1, 0, DebuggerIO::White, DebuggerIO::Green);
76 pScreen->drawString("q", pScreen->getHeight() - 1, 0, DebuggerIO::Yellow, DebuggerIO::Green);
77 pScreen->drawString("c", pScreen->getHeight() - 1, 9, DebuggerIO::Yellow, DebuggerIO::Green);
78 pScreen->drawString("d", pScreen->getHeight() - 1, 19, DebuggerIO::Yellow, DebuggerIO::Green);
79 pScreen->drawString("enter", pScreen->getHeight() - 1, 38, DebuggerIO::Yellow, DebuggerIO::Green);
80
81 // Main loop.
82 bool bStop = false;
83 bool bReturn = true;
84 while (!bStop) {
85 refresh(pScreen);
86
87 // Wait for input.
88 char c = 0;
89 while (!(c = pScreen->getChar()))
90 ;
91
92 // TODO: Use arrow keys and page up/down someday
93 if (c == 'j') {
94 scroll(-1);
95 } else if (c == 'k') {
96 scroll(1);
97 } else if (c == ' ') {
98 scroll(static_cast<ssize_t>(height()));
99 } else if (c == 0x08) {
100 scroll(-static_cast<ssize_t>(height()));
101 } else if (c == '\n' || c == '\r') {
102 m_nIdx++;
103 m_It++;
104 if (m_It == m_Tree.end()) {
105 m_It = m_Tree.begin();
106 m_nIdx = 0;
107 }
108 } else if (c == 'c') {
109 clean();
110 m_It = m_Tree.begin();
111 m_nIdx = 0;
112 } else if (c == 'd') {
113 Machine::instance().getSerial(0)->write_str("AllocDump {\n");
114 for (m_It = m_Tree.begin(); m_It != m_Tree.end(); m_It++) {
115 SlamAllocation* pA = m_It.value();
117 str.clear();
118 str += "Alloc {\nBacktrace [";
119 for (int i = 0; i < NUM_SLAM_BT_FRAMES; i++) {
120 str += "0x";
121 str.append(pA->bt[i], 16);
122 str += "=\\";
123 uintptr_t symStart = 0;
124 const char* pSym = KernelElf::instance().globalLookupSymbol(pA->bt[i], &symStart);
125 if (pSym == 0)
126 str.append(pA->bt[i], 16);
127 else {
128 LargeStaticString sym(pSym);
129 static symbol_t symbol;
130 demangle(sym, &symbol);
131 str += static_cast<const char*>(symbol.name);
132 }
133 str += "=\\, ";
134 }
135 str += "]\nNum ";
136 str += pA->n;
137 str += "\nSz ";
138 str += pA->size;
139 str += "\n}\n";
140 Machine::instance().getSerial(0)->write_str(str);
141 }
142 Machine::instance().getSerial(0)->write_str("}\n");
143 } else if (c == 'q')
144 bStop = true;
145 }
146
147 // HACK:: Serial connections will fill the screen with the last background
148 // colour used.
149 // Here we write a space with black background so the CLI screen
150 // doesn't get filled by some random colour!
151 pScreen->drawString(" ", 1, 0, DebuggerIO::White, DebuggerIO::Black);
152 pScreen->enableCli();
153 m_Lock = bs;
154 return bReturn;
155}
156
157const char* SlamCommand::getLine1(size_t index, DebuggerIO::Colour& colour,
158 DebuggerIO::Colour& bgColour) {
159 static NormalStaticString Line;
160 Line.clear();
161
162 SlamAllocation* pA = m_It.value();
163
164 bgColour = DebuggerIO::Black;
165 if (index == 0) {
166 colour = DebuggerIO::Yellow;
167 Line += pA->n;
168 Line += " allocations from this source (";
169 Line += m_nIdx;
170 Line += "/";
171 Line += m_Tree.count();
172 Line += ") Size: ";
173 if (pA->size >= 1024 * 1024) {
174 Line += (pA->size / (1024 * 1024));
175 Line += "MB";
176 } else if (pA->size >= 1024) {
177 Line += (pA->size / 1024);
178 Line += "KB";
179 } else {
180 Line += pA->size;
181 Line += "B";
182 }
183 return Line;
184 }
185 index--;
186
187 colour = DebuggerIO::White;
188 uintptr_t symStart = 0;
189
190 const char* pSym = KernelElf::instance().globalLookupSymbol(pA->bt[index], &symStart);
191 if (pSym == 0) {
192 Line.append(pA->bt[index], 16);
193 } else {
194 LargeStaticString sym(pSym);
195
196 Line += "[";
197 Line.append(symStart, 16);
198 Line += "] ";
199 static symbol_t symbol;
200 demangle(sym, &symbol);
201 Line += static_cast<const char*>(symbol.name);
202 }
203
204 return Line;
205}
206const char* SlamCommand::getLine2(size_t index, size_t& colOffset, DebuggerIO::Colour& colour,
207 DebuggerIO::Colour& bgColour) {
208 static LargeStaticString Line;
209 Line.clear();
210
211 return Line;
212}
213
214size_t SlamCommand::getLineCount() {
215 return m_nLines;
216}
217
218void SlamCommand::addAllocation(uintptr_t* backtrace, size_t requested) {
219 if (m_Lock)
220 return;
221 m_Lock = true;
222
223 uintptr_t accum = 0;
224
225 // Checksum it
226 for (int i = 0; i < NUM_SLAM_BT_FRAMES; i++)
227 accum ^= backtrace[i];
228
229 // Lookup the checksum.
230 SlamAllocation* pOther = m_Tree.lookup(accum);
231 if (!pOther) {
232 SlamAllocation* pAlloc = new SlamAllocation;
233 MemoryCopy(&pAlloc->bt, backtrace, NUM_SLAM_BT_FRAMES * sizeof(uintptr_t));
234 pAlloc->n = 1;
235 pAlloc->size = requested;
236 m_Tree.insert(accum, pAlloc);
237 } else {
238 pOther->size += requested;
239 pOther->n++;
240 }
241 m_Lock = false;
242}
243
244void SlamCommand::removeAllocation(uintptr_t* backtrace, size_t requested) {
245 if (m_Lock)
246 return;
247 m_Lock = true;
248
249 uintptr_t accum = 0;
250
251 // Checksum it
252 for (int i = 0; i < NUM_SLAM_BT_FRAMES; i++)
253 accum ^= backtrace[i];
254
255 // Lookup the checksum.
256 SlamAllocation* pAlloc = m_Tree.lookup(accum);
257 if (pAlloc) {
258 if (pAlloc->n == 1)
259 m_Tree.remove(accum);
260 else
261 pAlloc->n--;
262 }
263 m_Lock = false;
264}
virtual void enableCli()=0
virtual void drawString(const char *str, size_t row, size_t col, Colour foreColour, Colour backColour)=0
virtual size_t getWidth()=0
virtual void drawHorizontalLine(char c, size_t row, size_t colStart, size_t colEnd, Colour foreColour, Colour backColour)=0
virtual char getChar()=0
static KernelElf & instance()
Definition KernelElf.h:135
uintptr_t globalLookupSymbol(const char *pName)
virtual Serial * getSerial(size_t n)=0
bool execute(const HugeStaticString &input, HugeStaticString &output, InterruptState &state, DebuggerIO *screen)
void autocomplete(const HugeStaticString &input, HugeStaticString &output)