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