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