The Pedigree Project 0.1
MemoryInspector.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/commands/MemoryInspector.h"
21#include "pedigree/kernel/processor/Processor.h"
22#include "pedigree/kernel/processor/ProcessorInformation.h"
23#include "pedigree/kernel/processor/VirtualAddressSpace.h"
24#include "pedigree/kernel/processor/state.h"
25
27
29
31 output = "<Address> | <Register name>";
32}
33
35 InterruptState& state, DebuggerIO* pScreen) {
36 uintptr_t nAddress;
37 if (input == "memory")
38 nAddress = 0;
39 else {
40 static LargeStaticString addrString;
41 addrString = input;
42 if (!tryGoto(addrString, nAddress, state)) {
43 output = "Bad address or register.\n";
44 return true;
45 }
46 }
47 // Is the terminal wide enough to do 16-character wide display?
48 if (pScreen->getWidth() >= 87)
49 m_nCharsPerLine = 16;
50 if (pScreen->getWidth() >= 138)
51 m_nCharsPerLine = 32;
52
53 // Let's enter 'raw' screen mode.
54 pScreen->disableCli();
55
56 // Initialise the Scrollable class
57 move(0, 1);
58 resize(pScreen->getWidth(), pScreen->getHeight() - 3);
59 setScrollKeys('j', 'k');
60
61 // Clear the top status lines.
62 pScreen->drawHorizontalLine(' ', 0, 0, pScreen->getWidth() - 1, DebuggerIO::White,
63 DebuggerIO::Green);
64
65 // Write the correct text in the upper status line.
66 pScreen->drawString("Pedigree debugger - Memory inspector", 0, 0, DebuggerIO::White,
67 DebuggerIO::Green);
68
69 resetStatusLine(pScreen);
70
71 scrollTo(nAddress / m_nCharsPerLine);
72
73 // Main loop.
74 bool bStop = false;
75 while (!bStop) {
76 refresh(pScreen);
77
78 // Wait for input.
79 char c;
80 while ((c = pScreen->getChar()) == 0)
81 ;
82
83 // TODO: Use arrow keys and page up/down someday
84 if (c == 'j')
85 scroll(-1);
86 else if (c == 'k')
87 scroll(1);
88 else if (c == ' ')
89 scroll(static_cast<ssize_t>(height()));
90 else if (c == 0x08)
91 scroll(-static_cast<ssize_t>(height()));
92 else if (c == 'q')
93 bStop = true;
94 else if (c == 'g')
95 doGoto(pScreen, state);
96 else if (c == '/')
97 doSearch(true, pScreen, state);
98 else if (c == '?')
99 doSearch(false, pScreen, state);
100 }
101
102 // HACK:: Serial connections will fill the screen with the last background
103 // colour used.
104 // Here we write a space with black background so the CLI screen
105 // doesn't get filled by some random colour!
106 pScreen->drawString(" ", 1, 0, DebuggerIO::White, DebuggerIO::Black);
107 pScreen->enableCli();
108 return true;
109}
110
111const char* MemoryInspector::getLine1(size_t index, DebuggerIO::Colour& colour,
112 DebuggerIO::Colour& bgColour) {
113 colour = DebuggerIO::DarkGrey;
114 uintptr_t nLine = index * m_nCharsPerLine;
115 static NormalStaticString str;
116 str.clear();
117 str.append(nLine, 16, sizeof(uintptr_t) * 2, '0');
118 return str;
119}
120
121const char* MemoryInspector::getLine2(size_t index, size_t& colOffset, DebuggerIO::Colour& colour,
122 DebuggerIO::Colour& bgColour) {
123 colOffset = sizeof(uintptr_t) * 2 + 1;
124 // Get the line we want.
125 uintptr_t nLine = index * m_nCharsPerLine;
126 // Is it paged in?
127 if (!Processor::information().getVirtualAddressSpace().isMapped(reinterpret_cast<void*>(nLine))) {
128 colour = DebuggerIO::Red;
129 return "Memory not mapped.";
130 } else {
131 uint8_t* pLine = reinterpret_cast<uint8_t*>(nLine);
132 static LargeStaticString str;
133 str.clear();
134 for (unsigned int i = 0; i < m_nCharsPerLine; i++) {
135 str.append(pLine[i], 16, 2, '0');
136 str += ' ';
137 if (((i + 1) % 8 == 0) && ((i + 1) < m_nCharsPerLine))
138 str += "- ";
139 }
140
141 str += " ";
142 for (unsigned int i = 0; i < m_nCharsPerLine; i++) {
143 if (pLine[i] >= 33 && pLine[i] <= 126)
144 str.append(static_cast<char>(pLine[i]), 1);
145 else
146 str += '.';
147 }
148
149 return str;
150 }
151}
152
153size_t MemoryInspector::getLineCount() {
154// We have as many lines as the entirety of the address space / 8.
155// TODO: Please verify that this is correct, JamesM :-)
156#if BITS_32
157 return 0x20000000;
158#elif BITS_64
159 return 0x2000000000000000;
160#endif
161}
162
163void MemoryInspector::resetStatusLine(DebuggerIO* pScreen) {
164 // Clear the bottom status lines.
165 // TODO: If we use arrow keys and page up/down keys we actually can remove
166 // the status line
167 // because the interface is then intuitive enough imho.
168 pScreen->drawHorizontalLine(' ', pScreen->getHeight() - 1, 0, pScreen->getWidth() - 1,
169 DebuggerIO::White, DebuggerIO::Green);
170
171 // Write some helper text in the lower status line.
172 // TODO FIXME: Drawing this might screw the top status bar
173 pScreen->drawString(
174 "backspace: Page up. space: Page down. q: Quit. /,?: Fwd/Rev search. "
175 "g: Goto.",
176 pScreen->getHeight() - 1, 0, DebuggerIO::White, DebuggerIO::Green);
177 pScreen->drawString("backspace", pScreen->getHeight() - 1, 0, DebuggerIO::Yellow,
178 DebuggerIO::Green);
179 pScreen->drawString("space", pScreen->getHeight() - 1, 20, DebuggerIO::Yellow, DebuggerIO::Green);
180 pScreen->drawString("q", pScreen->getHeight() - 1, 38, DebuggerIO::Yellow, DebuggerIO::Green);
181 pScreen->drawString("/,?", pScreen->getHeight() - 1, 47, DebuggerIO::Yellow, DebuggerIO::Green);
182 pScreen->drawString("g", pScreen->getHeight() - 1, 68, DebuggerIO::Yellow, DebuggerIO::Green);
183}
184
185void MemoryInspector::doGoto(DebuggerIO* pScreen, InterruptState& state) {
186 static LargeStaticString str;
187 str.clear();
188 while (1) {
189 // Erase the bottom line.
190 pScreen->drawHorizontalLine(' ', pScreen->getHeight() - 2, 0, pScreen->getWidth() - 1,
191 DebuggerIO::White, DebuggerIO::Black);
192 // Print helper text.
193 pScreen->drawString("[Go to address or register value]", pScreen->getHeight() - 2, 0,
194 DebuggerIO::White, DebuggerIO::Black);
195 // Print current string contents.
196 pScreen->drawString(str, pScreen->getHeight() - 2, 35, DebuggerIO::White, DebuggerIO::Black);
197 // Get a character.
198 char c;
199 while ((c = pScreen->getChar()) == 0)
200 ;
201 if (c == '\n' || c == '\r')
202 break;
203 else if (c == 0x08)
204 str.stripLast();
205 else
206 str += c;
207 }
208
209 pScreen->drawHorizontalLine(' ', pScreen->getHeight() - 2, 0, pScreen->getWidth() - 1,
210 DebuggerIO::White, DebuggerIO::Black);
211
212 uintptr_t nAddress;
213 if (!tryGoto(str, nAddress, state)) {
214 pScreen->drawString("Bad address or register.", pScreen->getHeight() - 2, 0, DebuggerIO::Red,
215 DebuggerIO::Black);
216 } else {
217 scrollTo(nAddress / m_nCharsPerLine);
218 }
219}
220
221void MemoryInspector::doSearch(bool bForward, DebuggerIO* pScreen, InterruptState& state) {
222 static LargeStaticString str;
223 static LargeStaticString str2;
224 str.clear();
225 while (1) {
226 // Erase the bottom line.
227 pScreen->drawHorizontalLine(' ', pScreen->getHeight() - 2, 0, pScreen->getWidth() - 1,
228 DebuggerIO::White, DebuggerIO::Black);
229 // Print helper text.
230 if (bForward)
231 pScreen->drawString("[Search] ", pScreen->getHeight() - 2, 0, DebuggerIO::White,
232 DebuggerIO::Black);
233 else
234 pScreen->drawString("[Reverse]", pScreen->getHeight() - 2, 0, DebuggerIO::White,
235 DebuggerIO::Black);
236 // Print current string contents.
237 pScreen->drawString(str, pScreen->getHeight() - 2, 10, DebuggerIO::White, DebuggerIO::Black);
238 // Get a character.
239 char c;
240 while ((c = pScreen->getChar()) == 0)
241 ;
242 if (c == '\n' || c == '\r')
243 break;
244 else if (c == 0x08)
245 str.stripLast();
246 else
247 str += c;
248 }
249
250 pScreen->drawHorizontalLine(' ', pScreen->getHeight() - 2, 0, pScreen->getWidth() - 1,
251 DebuggerIO::White, DebuggerIO::Black);
252
253 unsigned int nChars = 0;
254 uint8_t pChars[8];
255
256 // Valid search?
257 if (str[0] == '"') {
258 // Ascii search.
259 str.stripFirst();
260 str.stripLast();
261
262 if (str.length() > 8) {
263 pScreen->drawString("Search string too long (> 8 characters)", pScreen->getHeight() - 2, 0,
264 DebuggerIO::Red, DebuggerIO::Black);
265 return;
266 }
267
268 nChars = str.length();
269 for (size_t i = 0; i < str.length(); i++)
270 pChars[i] = str[i];
271 } else {
272 // Assume hex integer.
273 if (str.left(2) == "0x")
274 str.stripFirst(2);
275 nChars = str.length() / 2;
276 if (nChars >= 8) {
277 pScreen->drawString("Hex string too long, 8 bytes max.", pScreen->getHeight() - 2, 0,
278 DebuggerIO::Red, DebuggerIO::Black);
279 return;
280 }
281 for (size_t i = 0; i < nChars; i++) {
282 // Get our nibbles.
283 TinyStaticString mystr;
284 mystr += str[i * 2];
285 mystr += str[i * 2 + 1];
286 // Convert.
287 int nConverted = mystr.intValue(16);
288 // Failed?
289 if (nConverted == -1) {
290 pScreen->drawString("Malformed hexadecimal number.", pScreen->getHeight() - 2, 0,
291 DebuggerIO::Red, DebuggerIO::Black);
292 return;
293 }
294 pChars[nChars - i - 1] = static_cast<uint8_t>(nConverted);
295 }
296 }
297
298 if (bForward)
299 str = "[Search for ";
300 else
301 str = "[Reverse for ";
302 for (size_t i = 0; i < nChars; i++) {
303 str.append(pChars[i], 16, 2, '0');
304 str += ' ';
305 }
306 str += ": over ?(K|M) of memory]";
307 pScreen->drawString(str, pScreen->getHeight() - 2, 0, DebuggerIO::White, DebuggerIO::Black);
308
309 str2.clear();
310 while (1) {
311 // Erase the bottom line.
312 pScreen->drawHorizontalLine(' ', pScreen->getHeight() - 2, 0, pScreen->getWidth() - 1,
313 DebuggerIO::White, DebuggerIO::Black);
314 // Print helper text.
315 pScreen->drawString(str, pScreen->getHeight() - 2, 0, DebuggerIO::White, DebuggerIO::Black);
316 // Print current string contents.
317 pScreen->drawString(str2, pScreen->getHeight() - 2, str.length() + 1, DebuggerIO::White,
318 DebuggerIO::Black);
319 // Get a character.
320 char c;
321 while ((c = pScreen->getChar()) == 0)
322 ;
323 if (c == '\n' || c == '\r')
324 break;
325 else if (c == 0x08)
326 str2.stripLast();
327 else
328 str2 += c;
329 }
330
331 // Erase the bottom line.
332 pScreen->drawHorizontalLine(' ', pScreen->getHeight() - 2, 0, pScreen->getWidth() - 1,
333 DebuggerIO::White, DebuggerIO::Black);
334 str = str2.right(1);
335 char suffix = str[0];
336 if (suffix == 'M' || suffix == 'K')
337 str2.stripLast();
338 int num = str2.intValue();
339 if (num == -1) {
340 pScreen->drawString("Malformed number.", pScreen->getHeight() - 2, 0, DebuggerIO::Red,
341 DebuggerIO::Black);
342 return;
343 }
344 size_t nRange = static_cast<size_t>(num);
345 if (suffix == 'K')
346 nRange *= 1024;
347 else if (suffix == 'M')
348 nRange *= 1048576;
349
350 pScreen->drawString("Searching...", pScreen->getHeight() - 2, 0, DebuggerIO::Green,
351 DebuggerIO::Black);
352
353 // Do the search.
354}
355
356bool MemoryInspector::tryGoto(LargeStaticString& str, uintptr_t& result, InterruptState& state) {
357 for (size_t i = 0; i < state.getRegisterCount(); i++) {
358 LargeStaticString reg(state.getRegisterName(i));
359 if (reg == str) {
360 result = state.getRegister(i);
361 return true;
362 }
363 }
364 uintptr_t n = str.uintptrValue();
365 if (n == ~0UL)
366 return false;
367 else {
368 result = n;
369 return true;
370 }
371}
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
bool execute(const HugeStaticString &input, HugeStaticString &output, InterruptState &state, DebuggerIO *screen)
void autocomplete(const HugeStaticString &input, HugeStaticString &output)
static ProcessorInformation & information()
StaticString right(int n) const