The Pedigree Project  0.1
AllocationCommand.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/AllocationCommand.h"
21 #include "pedigree/kernel/Log.h"
22 #include "pedigree/kernel/debugger/Backtrace.h"
23 #include "pedigree/kernel/debugger/DebuggerIO.h"
24 #include "pedigree/kernel/linker/KernelElf.h"
25 #include "pedigree/kernel/process/Process.h"
26 #include "pedigree/kernel/process/Thread.h"
27 #include "pedigree/kernel/processor/Processor.h"
28 #include "pedigree/kernel/processor/ProcessorInformation.h"
29 #include "pedigree/kernel/utilities/Iterator.h"
30 #include "pedigree/kernel/utilities/demangle.h"
31 #include "pedigree/kernel/utilities/utility.h"
32 
33 AllocationCommand g_AllocationCommand;
34 
36  : DebuggerCommand(), Scrollable(), m_Allocations(), m_Frees(), m_nLines(0),
37  m_Tree(), m_It(), m_nIdx(0), m_bAllocating(false)
38 {
39 }
40 
42 {
43 }
44 
46  const HugeStaticString &input, HugeStaticString &output)
47 {
48 }
49 
51  const HugeStaticString &input, HugeStaticString &output,
52  InterruptState &state, DebuggerIO *pScreen)
53 {
54  postProcess();
55 
56  // How many lines do we have?
57  m_nLines = NUM_BT_FRAMES + 1;
58 
59  m_Tree.clear();
60 
61  // Perform preprocessing. Horrible O(n^2) algorithm.
62  for (Vector<Allocation *>::Iterator it = m_Allocations.begin();
63  it != m_Allocations.end(); it++)
64  {
65  Allocation *pA = *it;
66  // Create a checksum of the backtrace.
67  uintptr_t accum = 0;
68  for (int i = 0; i < NUM_BT_FRAMES; i++)
69  accum ^= pA->ra[i];
70 
71  // Along with process ID...
72  accum += pA->pid << 16;
73 
74  // Lookup the checksum.
75  Allocation *pOther = m_Tree.lookup(accum);
76  if (pOther == 0)
77  {
78  pA->n = 1;
79  m_Tree.insert(accum, pA);
80  }
81  else
82  {
83  pOther->n++;
84  }
85  }
86 
87  m_It = m_Tree.begin();
88  m_nIdx = 0;
89 
90  // Let's enter 'raw' screen mode.
91  pScreen->disableCli();
92 
93  // Initialise the Scrollable class
94  move(0, 1);
95  resize(pScreen->getWidth(), pScreen->getHeight() - 2);
96  setScrollKeys('j', 'k');
97 
98  // Clear the top status lines.
99  pScreen->drawHorizontalLine(
100  ' ', 0, 0, pScreen->getWidth() - 1, DebuggerIO::White,
101  DebuggerIO::Green);
102 
103  // Write the correct text in the upper status line.
104  pScreen->drawString(
105  "Pedigree debugger - Page allocation resolver", 0, 0, DebuggerIO::White,
106  DebuggerIO::Green);
107 
108  // Clear the bottom status lines.
109  // TODO: If we use arrow keys and page up/down keys we actually can remove
110  // the status line
111  // because the interface is then intuitive enough imho.
112  pScreen->drawHorizontalLine(
113  ' ', pScreen->getHeight() - 1, 0, pScreen->getWidth() - 1,
114  DebuggerIO::White, DebuggerIO::Green);
115 
116  // Write some helper text in the lower status line.
117  // TODO FIXME: Drawing this might screw the top status bar
118  pScreen->drawString(
119  "backspace: Page up. space: Page down. q: Quit. enter: Next allocation",
120  pScreen->getHeight() - 1, 0, DebuggerIO::White, DebuggerIO::Green);
121  pScreen->drawString(
122  "backspace", pScreen->getHeight() - 1, 0, DebuggerIO::Yellow,
123  DebuggerIO::Green);
124  pScreen->drawString(
125  "space", pScreen->getHeight() - 1, 20, DebuggerIO::Yellow,
126  DebuggerIO::Green);
127  pScreen->drawString(
128  "q", pScreen->getHeight() - 1, 38, DebuggerIO::Yellow,
129  DebuggerIO::Green);
130  pScreen->drawString(
131  "enter", pScreen->getHeight() - 1, 47, DebuggerIO::Yellow,
132  DebuggerIO::Green);
133 
134  // Main loop.
135  bool bStop = false;
136  bool bReturn = true;
137  while (!bStop)
138  {
139  refresh(pScreen);
140 
141  // Wait for input.
142  char c = 0;
143  while (!(c = pScreen->getChar()))
144  ;
145 
146  // TODO: Use arrow keys and page up/down someday
147  if (c == 'j')
148  {
149  scroll(-1);
150  }
151  else if (c == 'k')
152  {
153  scroll(1);
154  }
155  else if (c == ' ')
156  {
157  scroll(static_cast<ssize_t>(height()));
158  }
159  else if (c == 0x08)
160  {
161  scroll(-static_cast<ssize_t>(height()));
162  }
163  else if (c == '\n' || c == '\r')
164  {
165  m_nIdx++;
166  m_It++;
167  if (m_It == m_Tree.end())
168  {
169  m_It = m_Tree.begin();
170  m_nIdx = 0;
171  }
172  }
173  else if (c == 'q')
174  bStop = true;
175  }
176 
177  // HACK:: Serial connections will fill the screen with the last background
178  // colour used.
179  // Here we write a space with black background so the CLI screen
180  // doesn't get filled by some random colour!
181  pScreen->drawString(" ", 1, 0, DebuggerIO::White, DebuggerIO::Black);
182  pScreen->enableCli();
183  return bReturn;
184 }
185 
186 const char *AllocationCommand::getLine1(
187  size_t index, DebuggerIO::Colour &colour, DebuggerIO::Colour &bgColour)
188 {
189  static NormalStaticString Line;
190  Line.clear();
191 
192  Allocation *pA = m_It.value();
193 
194  bgColour = DebuggerIO::Black;
195  if (index == 0)
196  {
197  colour = DebuggerIO::Yellow;
198  Line += pA->n;
199  Line += " allocations from this source (";
200  Line += m_nIdx;
201  Line += "/";
202  Line += m_Tree.count();
203  Line += ") PID: ";
204  Line += pA->pid;
205  return Line;
206  }
207  index--;
208 
209  colour = DebuggerIO::White;
210  uintptr_t symStart = 0;
211 
212  const char *pSym =
213  KernelElf::instance().globalLookupSymbol(pA->ra[index], &symStart);
214  if (pSym == 0)
215  {
216  Line.append(pA->ra[index], 16);
217  }
218  else
219  {
220  LargeStaticString sym(pSym);
221 
222  Line += "[";
223  Line.append(symStart, 16);
224  Line += "] ";
225  static symbol_t symbol;
226  demangle(sym, &symbol);
227  Line += static_cast<const char *>(symbol.name);
228  }
229 
230  return Line;
231 }
232 const char *AllocationCommand::getLine2(
233  size_t index, size_t &colOffset, DebuggerIO::Colour &colour,
234  DebuggerIO::Colour &bgColour)
235 {
236  static LargeStaticString Line;
237  Line.clear();
238 
239  return Line;
240 }
241 
242 size_t AllocationCommand::getLineCount()
243 {
244  return m_nLines;
245 }
246 
247 void AllocationCommand::allocatePage(physical_uintptr_t page)
248 {
249  // Get a backtrace.
250  Backtrace bt;
251  bt.performBpBacktrace(0, 0);
252 
253  Allocation *pA = new Allocation;
254  pA->page = page;
255  MemoryCopy(
256  &pA->ra, bt.m_pReturnAddresses, NUM_BT_FRAMES * sizeof(uintptr_t));
257 
258 #ifdef THREADS
259  Process *pP = Processor::information().getCurrentThread()->getParent();
260  if (pP)
261  pA->pid = pP->getId();
262  else
263 #endif
264  pA->pid = -1;
265 
266  m_Allocations.pushBack(pA);
267 }
268 
269 void AllocationCommand::freePage(physical_uintptr_t page)
270 {
271  m_Frees.pushBack(reinterpret_cast<void *>(page));
272 }
273 
274 void AllocationCommand::postProcess()
275 {
276  NOTICE("Beginning free-list post processing...");
277  for (Vector<void *>::Iterator it = m_Frees.begin(); it != m_Frees.end();
278  it++)
279  {
280  physical_uintptr_t page = reinterpret_cast<physical_uintptr_t>(*it);
281 
282  // Look through the allocations vector for this address.
283  for (Vector<Allocation *>::Iterator it2 = m_Allocations.begin();
284  it2 != m_Allocations.end(); it2++)
285  {
286  if ((*it2)->page == page)
287  {
288  delete (*it2);
289  m_Allocations.erase(it2);
290  break;
291  }
292  }
293 
294  m_Frees.erase(it);
295  it = m_Frees.begin();
296  }
297  NOTICE("End free-list post processing.");
298 }
299 
300 void AllocationCommand::checkpoint()
301 {
302  NOTICE("Allocation checkpoint.");
303  // TODO delete().
304  m_Allocations.clear();
305  m_Frees.clear();
306 }
void pushBack(const T &value)
Definition: Vector.h:270
Iterator begin()
Definition: Vector.h:148
Iterator end()
Definition: Vector.h:160
virtual size_t getWidth()=0
virtual void enableCli()=0
size_t getId()
Definition: Process.h:108
A vector / dynamic array.
bool execute(const HugeStaticString &input, HugeStaticString &output, InterruptState &state, DebuggerIO *screen)
virtual char getChar()=0
static ProcessorInformation & information()
Definition: Processor.cc:45
static KernelElf & instance()
Definition: KernelElf.h:129
uintptr_t m_pReturnAddresses[MAX_STACK_FRAMES]
Definition: Backtrace.h:88
#define NOTICE(text)
Definition: Log.h:74
T * Iterator
Definition: Vector.h:37
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
void autocomplete(const HugeStaticString &input, HugeStaticString &output)
void performBpBacktrace(uintptr_t base, uintptr_t instruction)
Definition: Backtrace.cc:95
virtual void drawHorizontalLine(char c, size_t row, size_t colStart, size_t colEnd, Colour foreColour, Colour backColour)=0
void clear(bool freeMem=false)
Definition: Vector.h:337
void erase(size_t index)
Definition: Vector.h:350