src/debugger.c (view raw)
1#include "debugger.h"
2
3#include "arm.h"
4
5#include <signal.h>
6#include <stdio.h>
7#include <stdarg.h>
8#include <stdlib.h>
9#include <strings.h>
10#include <unistd.h>
11#include "linenoise.h"
12
13struct DebugVector {
14 struct DebugVector* next;
15 enum DVType {
16 ERROR_TYPE,
17 INT_TYPE,
18 CHAR_TYPE
19 } type;
20 union {
21 int32_t intValue;
22 const char* charValue;
23 };
24};
25
26static const char* ERROR_MISSING_ARGS = "Arguments missing";
27
28typedef void (DebuggerComamnd)(struct ARMDebugger*, struct DebugVector*);
29
30static void _breakInto(struct ARMDebugger*, struct DebugVector*);
31static void _print(struct ARMDebugger*, struct DebugVector*);
32static void _printHex(struct ARMDebugger*, struct DebugVector*);
33static void _printStatus(struct ARMDebugger*, struct DebugVector*);
34static void _readByte(struct ARMDebugger*, struct DebugVector*);
35static void _readHalfword(struct ARMDebugger*, struct DebugVector*);
36static void _readWord(struct ARMDebugger*, struct DebugVector*);
37static void _quit(struct ARMDebugger*, struct DebugVector*);
38
39struct {
40 const char* name;
41 DebuggerComamnd* command;
42} debuggerCommands[] = {
43 { "i", _printStatus },
44 { "info", _printStatus },
45 { "p", _print },
46 { "print", _print },
47 { "p/x", _printHex },
48 { "print/x", _printHex },
49 { "q", _quit },
50 { "quit", _quit },
51 { "rb", _readByte },
52 { "rh", _readHalfword },
53 { "rw", _readWord },
54 { "status", _printStatus },
55 { "x", _breakInto },
56 { 0, 0 }
57};
58
59static inline void _printPSR(union PSR psr) {
60 printf("%08X [%c%c%c%c%c%c%c]\n", psr.packed,
61 psr.n ? 'N' : '-',
62 psr.z ? 'Z' : '-',
63 psr.c ? 'C' : '-',
64 psr.v ? 'V' : '-',
65 psr.i ? 'I' : '-',
66 psr.f ? 'F' : '-',
67 psr.t ? 'T' : '-');
68}
69
70static void _handleDeath(int sig) {
71 (void)(sig);
72 printf("No debugger attached!\n");
73}
74
75static void _breakInto(struct ARMDebugger* debugger, struct DebugVector* dv) {
76 (void)(debugger);
77 (void)(dv);
78 sig_t oldSignal = signal(SIGTRAP, _handleDeath);
79 kill(getpid(), SIGTRAP);
80 signal(SIGTRAP, oldSignal);
81}
82
83static void _print(struct ARMDebugger* debugger, struct DebugVector* dv) {
84 (void)(debugger);
85 for ( ; dv; dv = dv->next) {
86 printf(" %u", dv->intValue);
87 }
88 printf("\n");
89}
90
91static void _printHex(struct ARMDebugger* debugger, struct DebugVector* dv) {
92 (void)(debugger);
93 for ( ; dv; dv = dv->next) {
94 printf(" 0x%08X", dv->intValue);
95 }
96 printf("\n");
97}
98
99static inline void _printLine(struct ARMDebugger* debugger, uint32_t address, enum ExecutionMode mode) {
100 // TODO: write a disassembler
101 if (mode == MODE_ARM) {
102 uint32_t instruction = debugger->cpu->memory->load32(debugger->cpu->memory, address);
103 printf("%08X\n", instruction);
104 } else {
105 uint16_t instruction = debugger->cpu->memory->loadU16(debugger->cpu->memory, address);
106 printf("%04X\n", instruction);
107 }
108}
109
110static void _printStatus(struct ARMDebugger* debugger, struct DebugVector* dv) {
111 (void)(dv);
112 int r;
113 for (r = 0; r < 4; ++r) {
114 printf("%08X %08X %08X %08X\n",
115 debugger->cpu->gprs[r << 2],
116 debugger->cpu->gprs[(r << 2) + 1],
117 debugger->cpu->gprs[(r << 2) + 2],
118 debugger->cpu->gprs[(r << 2) + 3]);
119 }
120 _printPSR(debugger->cpu->cpsr);
121 int instructionLength;
122 enum ExecutionMode mode = debugger->cpu->cpsr.t;
123 if (mode == MODE_ARM) {
124 instructionLength = WORD_SIZE_ARM;
125 } else {
126 instructionLength = WORD_SIZE_THUMB;
127 }
128 _printLine(debugger, debugger->cpu->gprs[ARM_PC] - instructionLength, mode);
129}
130
131static void _quit(struct ARMDebugger* debugger, struct DebugVector* dv) {
132 (void)(dv);
133 debugger->state = DEBUGGER_EXITING;
134}
135
136static void _readByte(struct ARMDebugger* debugger, struct DebugVector* dv) {
137 if (!dv || dv->type != INT_TYPE) {
138 printf("%s\n", ERROR_MISSING_ARGS);
139 return;
140 }
141 uint32_t address = dv->intValue;
142 uint8_t value = debugger->cpu->memory->loadU8(debugger->cpu->memory, address);
143 printf(" 0x%02X\n", value);
144}
145
146static void _readHalfword(struct ARMDebugger* debugger, struct DebugVector* dv) {
147 if (!dv || dv->type != INT_TYPE) {
148 printf("%s\n", ERROR_MISSING_ARGS);
149 return;
150 }
151 uint32_t address = dv->intValue;
152 uint16_t value = debugger->cpu->memory->loadU16(debugger->cpu->memory, address);
153 printf(" 0x%04X\n", value);
154}
155
156static void _readWord(struct ARMDebugger* debugger, struct DebugVector* dv) {
157 if (!dv || dv->type != INT_TYPE) {
158 printf("%s\n", ERROR_MISSING_ARGS);
159 return;
160 }
161 uint32_t address = dv->intValue;
162 uint32_t value = debugger->cpu->memory->load32(debugger->cpu->memory, address);
163 printf(" 0x%08X\n", value);
164}
165
166enum _DVParseState {
167 PARSE_ERROR = -1,
168 PARSE_ROOT = 0,
169 PARSE_EXPECT_REGISTER,
170 PARSE_EXPECT_REGISTER_2,
171 PARSE_EXPECT_LR,
172 PARSE_EXPECT_PC,
173 PARSE_EXPECT_SP,
174 PARSE_EXPECT_DECIMAL,
175 PARSE_EXPECT_HEX,
176 PARSE_EXPECT_PREFIX,
177 PARSE_EXPECT_SUFFIX,
178};
179
180static struct DebugVector* _DVParse(struct ARMDebugger* debugger, const char* string) {
181 if (!string || !string[0]) {
182 return 0;
183 }
184
185 enum _DVParseState state = PARSE_ROOT;
186 struct DebugVector dvTemp = { .type = INT_TYPE };
187 uint32_t current = 0;
188
189 while (string[0] && string[0] != ' ' && state != PARSE_ERROR) {
190 char token = string[0];
191 ++string;
192 switch (state) {
193 case PARSE_ROOT:
194 switch (token) {
195 case 'r':
196 state = PARSE_EXPECT_REGISTER;
197 break;
198 case 'p':
199 state = PARSE_EXPECT_PC;
200 break;
201 case 's':
202 state = PARSE_EXPECT_SP;
203 break;
204 case 'l':
205 state = PARSE_EXPECT_LR;
206 break;
207 case '1':
208 case '2':
209 case '3':
210 case '4':
211 case '5':
212 case '6':
213 case '7':
214 case '8':
215 case '9':
216 state = PARSE_EXPECT_DECIMAL;
217 current = token - '0';
218 break;
219 case '0':
220 state = PARSE_EXPECT_PREFIX;
221 break;
222 case '$':
223 state = PARSE_EXPECT_HEX;
224 current = 0;
225 break;
226 default:
227 state = PARSE_ERROR;
228 break;
229 };
230 break;
231 case PARSE_EXPECT_LR:
232 switch (token) {
233 case 'r':
234 current = debugger->cpu->gprs[ARM_LR];
235 state = PARSE_EXPECT_SUFFIX;
236 break;
237 default:
238 state = PARSE_ERROR;
239 break;
240 }
241 break;
242 case PARSE_EXPECT_PC:
243 switch (token) {
244 case 'c':
245 current = debugger->cpu->gprs[ARM_PC];
246 state = PARSE_EXPECT_SUFFIX;
247 break;
248 default:
249 state = PARSE_ERROR;
250 break;
251 }
252 break;
253 case PARSE_EXPECT_SP:
254 switch (token) {
255 case 'p':
256 current = debugger->cpu->gprs[ARM_SP];
257 state = PARSE_EXPECT_SUFFIX;
258 break;
259 default:
260 state = PARSE_ERROR;
261 break;
262 }
263 break;
264 case PARSE_EXPECT_REGISTER:
265 switch (token) {
266 case '0':
267 case '2':
268 case '3':
269 case '4':
270 case '5':
271 case '6':
272 case '7':
273 case '8':
274 case '9':
275 current = debugger->cpu->gprs[token - '0'];
276 state = PARSE_EXPECT_SUFFIX;
277 break;
278 case '1':
279 state = PARSE_EXPECT_REGISTER_2;
280 break;
281 default:
282 state = PARSE_ERROR;
283 break;
284 }
285 break;
286 case PARSE_EXPECT_REGISTER_2:
287 switch (token) {
288 case '0':
289 case '1':
290 case '2':
291 case '3':
292 case '4':
293 case '5':
294 current = debugger->cpu->gprs[token - '0' + 10];
295 state = PARSE_EXPECT_SUFFIX;
296 break;
297 default:
298 state = PARSE_ERROR;
299 break;
300 }
301 break;
302 case PARSE_EXPECT_DECIMAL:
303 switch (token) {
304 case '0':
305 case '1':
306 case '2':
307 case '3':
308 case '4':
309 case '5':
310 case '6':
311 case '7':
312 case '8':
313 case '9':
314 // TODO: handle overflow
315 current *= 10;
316 current += token - '0';
317 break;
318 default:
319 state = PARSE_ERROR;
320 }
321 break;
322 case PARSE_EXPECT_HEX:
323 switch (token) {
324 case '0':
325 case '1':
326 case '2':
327 case '3':
328 case '4':
329 case '5':
330 case '6':
331 case '7':
332 case '8':
333 case '9':
334 // TODO: handle overflow
335 current *= 16;
336 current += token - '0';
337 break;
338 case 'A':
339 case 'B':
340 case 'C':
341 case 'D':
342 case 'E':
343 case 'F':
344 // TODO: handle overflow
345 current *= 16;
346 current += token - 'A' + 10;
347 break;
348 case 'a':
349 case 'b':
350 case 'c':
351 case 'd':
352 case 'e':
353 case 'f':
354 // TODO: handle overflow
355 current *= 16;
356 current += token - 'a' + 10;
357 break;
358 default:
359 state = PARSE_ERROR;
360 break;
361 }
362 break;
363 case PARSE_EXPECT_PREFIX:
364 switch (token) {
365 case 'X':
366 case 'x':
367 current = 0;
368 state = PARSE_EXPECT_HEX;
369 break;
370 default:
371 state = PARSE_ERROR;
372 break;
373 }
374 break;
375 case PARSE_EXPECT_SUFFIX:
376 // TODO
377 state = PARSE_ERROR;
378 break;
379 case PARSE_ERROR:
380 // This shouldn't be reached
381 break;
382 }
383 }
384
385 struct DebugVector* dv = malloc(sizeof(struct DebugVector));
386 if (state == PARSE_ERROR) {
387 dv->type = ERROR_TYPE;
388 dv->next = 0;
389 } else {
390 dvTemp.intValue = current;
391 *dv = dvTemp;
392 if (string[0] == ' ') {
393 dv->next = _DVParse(debugger, string + 1);
394 }
395 }
396 return dv;
397}
398
399static void _DVFree(struct DebugVector* dv) {
400 struct DebugVector* next;
401 while (dv) {
402 next = dv->next;
403 free(dv);
404 dv = next;
405 }
406}
407
408static void _parse(struct ARMDebugger* debugger, const char* line) {
409 char* firstSpace = strchr(line, ' ');
410 size_t cmdLength;
411 struct DebugVector* dv = 0;
412 if (firstSpace) {
413 cmdLength = firstSpace - line;
414 dv = _DVParse(debugger, firstSpace + 1);
415 if (dv->type == ERROR_TYPE) {
416 printf("Parse error\n");
417 _DVFree(dv);
418 return;
419 }
420 } else {
421 cmdLength = strlen(line);
422 }
423
424 int i;
425 const char* name;
426 for (i = 0; (name = debuggerCommands[i].name); ++i) {
427 if (strlen(name) != cmdLength) {
428 continue;
429 }
430 if (strncasecmp(name, line, cmdLength) == 0) {
431 debuggerCommands[i].command(debugger, dv);
432 _DVFree(dv);
433 linenoiseHistoryAdd(line);
434 return;
435 }
436 }
437 _DVFree(dv);
438 ARMRun(debugger->cpu);
439 _printStatus(debugger, 0);
440}
441
442void ARMDebuggerInit(struct ARMDebugger* debugger, struct ARMCore* cpu) {
443 debugger->cpu = cpu;
444}
445
446void ARMDebuggerEnter(struct ARMDebugger* debugger) {
447 char* line;
448 _printStatus(debugger, 0);
449 while ((line = linenoise("> "))) {
450 _parse(debugger, line);
451 free(line);
452 switch (debugger->state) {
453 case DEBUGGER_EXITING:
454 return;
455 default:
456 break;
457 }
458 }
459}