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