summaryrefslogtreecommitdiff
path: root/src/arch/amd64/debugger.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/amd64/debugger.c')
-rw-r--r--src/arch/amd64/debugger.c342
1 files changed, 206 insertions, 136 deletions
diff --git a/src/arch/amd64/debugger.c b/src/arch/amd64/debugger.c
index 2356e4a..a1fa968 100644
--- a/src/arch/amd64/debugger.c
+++ b/src/arch/amd64/debugger.c
@@ -1,7 +1,7 @@
#include <lib.h>
#include <stddef.h>
-#include <serial.h>
#include <backtrace.h>
+#include <serial.h>
#include "debugger.h"
struct dr6 {
@@ -73,183 +73,217 @@ struct breakpoint {
uint8_t rw;
uint8_t used;
uint8_t enable;
+ uint8_t instr_len;
};
-static size_t dbg_steps = 0;
+static int dbg_steps = 0;
static int dbg_continue = 0;
static struct breakpoint bkps[4] = {{0}, {0}, {0}, {0}};
-static void dbg_putc(char c) {
- serial_out(c);
-}
-
-static void dbg_puts(char *msg) {
- serial_out_str(msg);
-}
-
-static char dbg_getc() {
- return serial_in();
+static size_t debugger_read(char *buf, size_t len) {
+ char *p = buf;
+ size_t result;
+ while (p < buf + len - 1) {
+ char ch = serial_in();
+ switch (ch) {
+ case '\r':
+ goto end;
+ case '\x7f':
+ if (p > buf) {
+ p--;
+ kputs("\x08 \x08");
+ }
+ break;
+ default:
+ kputc(ch);
+ *p++ = ch;
+ }
+ }
+end:
+ result = p - buf;
+ kputc('\n');
+ for(; p < buf + len; p++) {
+ *p = 0;
+ }
+ return result;
}
static void debugger_msg(int cause, struct dr6 dr6) {
- char buf[24];
switch (cause) {
case DEBUG_INT3:
- dbg_puts("dbg: reached int3");
+ kputs("dbg: reached int3");
break;
case DEBUG_FAULT:
- dbg_puts("dbg: a fault occured");
+ kputs("dbg: a fault occured");
break;
case DEBUG_DBG:
if (dr6.bs)
- dbg_puts("dbg: finished steps");
- else if (dr6.b0)
- dbg_puts("dbg: reached breakpoint 0");
+ kputs("dbg: finished steps");
+ if (dr6.b0)
+ kputs("dbg: reached breakpoint 0");
else if (dr6.b1)
- dbg_puts("dbg: reached breakpoint 1");
+ kputs("dbg: reached breakpoint 1");
else if (dr6.b2)
- dbg_puts("dbg: reached breakpoint 2");
+ kputs("dbg: reached breakpoint 2");
else if (dr6.b3)
- dbg_puts("dbg: reached breakpoint 3");
+ kputs("dbg: reached breakpoint 3");
}
if (dbg_steps > 0) {
- ultoa(dbg_steps, buf, 10);
- dbg_puts(" (");
- dbg_puts(buf);
- dbg_puts(" steps left)");
+ kprintf(" (%d steps left)", dbg_steps);
}
if (dbg_continue > 0) {
- dbg_puts(" (paused continue)");
- }
- dbg_puts("\n");
-}
-
-static void debugger_print_reg(char *name, uint64_t val) {
- char buf[24];
- char *end;
- dbg_puts(name);
- dbg_puts(": 0x");
-
- end = ultoa(val, buf, 16);
- for (int i = 0; i < 16 - (end - buf); i++) {
- dbg_putc('0');
+ kputs(" (paused continue)");
}
- dbg_puts(buf);
-
- dbg_puts(" (");
- end = ultoa(val, buf, 10);
- dbg_puts(buf);
- dbg_puts(")\n");
+ kputs("\n");
}
static void debugger_print_regs(struct isr_regs *state) {
- debugger_print_reg("rax", state->rax);
- debugger_print_reg("rbx", state->rbx);
- debugger_print_reg("rcx", state->rcx);
- debugger_print_reg("rdx", state->rdx);
- debugger_print_reg("rsi", state->rsi);
- debugger_print_reg("rdi", state->rdi);
- debugger_print_reg("rsp", state->rsp);
- debugger_print_reg("rbp", state->rbp);
- debugger_print_reg("r8 ", state->r8 );
- debugger_print_reg("r9 ", state->r9 );
- debugger_print_reg("r10", state->r10);
- debugger_print_reg("r11", state->r11);
- debugger_print_reg("r12", state->r12);
- debugger_print_reg("r13", state->r13);
- debugger_print_reg("r14", state->r14);
- debugger_print_reg("r15", state->r15);
- dbg_puts("---\n");
- debugger_print_reg("rip", state->rip);
- dbg_puts("---\n");
- debugger_print_reg("rflags", state->rflags);
+ kprintf("rax: %#016lx (%lu)\n", state->rax, state->rax);
+ kprintf("rbx: %#016lx (%lu)\n", state->rbx, state->rbx);
+ kprintf("rcx: %#016lx (%lu)\n", state->rcx, state->rcx);
+ kprintf("rdx: %#016lx (%lu)\n", state->rdx, state->rdx);
+ kprintf("rsi: %#016lx (%lu)\n", state->rsi, state->rsi);
+ kprintf("rdi: %#016lx (%lu)\n", state->rdi, state->rdi);
+ kprintf("rsp: %#016lx (%lu)\n", state->rsp, state->rsp);
+ kprintf("rbp: %#016lx (%lu)\n", state->rbp, state->rbp);
+ kprintf("r8 : %#016lx (%lu)\n", state->r8 , state->r8 );
+ kprintf("r9 : %#016lx (%lu)\n", state->r9 , state->r9 );
+ kprintf("r10: %#016lx (%lu)\n", state->r10, state->r10);
+ kprintf("r11: %#016lx (%lu)\n", state->r11, state->r11);
+ kprintf("r12: %#016lx (%lu)\n", state->r12, state->r12);
+ kprintf("r13: %#016lx (%lu)\n", state->r13, state->r13);
+ kprintf("r14: %#016lx (%lu)\n", state->r14, state->r14);
+ kprintf("r15: %#016lx (%lu)\n", state->r15, state->r15);
+ kputs("---\n");
+ kprintf("rip: %#016lx (%lu)\n", state->rip, state->rip);
+ kputs("---\n");
+ kprintf("rflags: %#016lx (%lu)\n", state->rflags, state->rflags);
struct rflags *rflags = (struct rflags *)state->rflags;
- dbg_puts("rflags: ");
- if(rflags->cf) dbg_puts("CF ");
- if(rflags->pf) dbg_puts("PF ");
- if(rflags->af) dbg_puts("AF ");
- if(rflags->zf) dbg_puts("ZF ");
- if(rflags->sf) dbg_puts("SF ");
- if(rflags->tf) dbg_puts("TF ");
- if(rflags->if_) dbg_puts("IF ");
- if(rflags->df) dbg_puts("DF ");
- if(rflags->of) dbg_puts("OF ");
- if(rflags->iopl) dbg_puts("IOPL ");
- if(rflags->nt) dbg_puts("NT ");
- if(rflags->md) dbg_puts("MD ");
- if(rflags->rf) dbg_puts("RF ");
- if(rflags->vm) dbg_puts("VM ");
- if(rflags->ac) dbg_puts("AC ");
- if(rflags->vif) dbg_puts("VIF ");
- if(rflags->vip) dbg_puts("VIP ");
- if(rflags->id) dbg_puts("ID ");
- dbg_putc('\n');
+ kputs("rflags: ");
+ if(rflags->cf) kputs("CF ");
+ if(rflags->pf) kputs("PF ");
+ if(rflags->af) kputs("AF ");
+ if(rflags->zf) kputs("ZF ");
+ if(rflags->sf) kputs("SF ");
+ if(rflags->tf) kputs("TF ");
+ if(rflags->if_) kputs("IF ");
+ if(rflags->df) kputs("DF ");
+ if(rflags->of) kputs("OF ");
+ if(rflags->iopl) kputs("IOPL ");
+ if(rflags->nt) kputs("NT ");
+ if(rflags->md) kputs("MD ");
+ if(rflags->rf) kputs("RF ");
+ if(rflags->vm) kputs("VM ");
+ if(rflags->ac) kputs("AC ");
+ if(rflags->vif) kputs("VIF ");
+ if(rflags->vip) kputs("VIP ");
+ if(rflags->id) kputs("ID ");
+ kputs("\n");
}
#define PROMPT_LEN 60
-static int debugger_handle_bkp_cmd(char *buf) {
- if (buf[0] == 'l') {
+static int debugger_handle_bkp_cmd(char *msg) {
+ if (msg[0] == 'l') {
// list breakpoints
- char buf[20];
for (int i = 0; i < 4; i++) {
- dbg_puts("breakpoint ");
- dbg_putc('0' + i);
- dbg_puts(": ");
struct breakpoint bkp = bkps[i];
if(!bkp.used) {
- dbg_puts("unset\n");
+ kprintf("breakpoint %d: unset\n", i);
continue;
}
- dbg_puts(" 0x");
- ultoa(bkp.addr, buf, 16);
- dbg_puts(buf);
- dbg_puts(" len=");
- switch (bkp.len) {
- case 0x0: dbg_putc('1'); break;
- case 0x1: dbg_putc('2'); break;
- case 0x2: dbg_putc('8'); break;
- case 0x3: dbg_putc('4'); break;
- }
- dbg_puts(" trigger=");
- switch (bkp.rw) {
- case 0x0: dbg_puts("x "); break;
- case 0x1: dbg_puts("w "); break;
- case 0x2: dbg_puts("io"); break;
- case 0x3: dbg_puts("rw"); break;
- }
- dbg_puts(bkp.enable ? " enabled" : " disabled");
+ const char *lenstrs[] = {"1", "2", "8", "4"};
+ const char *rwstrs[] = {"x ", "w ", "io", "rw"};
+ kprintf(
+ "breakpoint %d: %#016lx len=%s trigger=%s instrlen=%01d %s\n",
+ i,
+ bkp.addr,
+ lenstrs[bkp.len],
+ rwstrs[bkp.rw],
+ bkp.instr_len,
+ bkp.enable ? " enabled" : " disabled"
+ );
}
return 1;
- } else if (buf[0] == 'd') {
+ } else if (msg[0] == 'd') {
// disable breakpoints
bkps[0].enable = 0;
bkps[1].enable = 0;
bkps[2].enable = 0;
bkps[3].enable = 0;
+ kputs("disabled breakpoints\n");
return 1;
- } else if (buf[0] == 'c') {
+ } else if (msg[0] == 'c') {
// clear breakpoints
bkps[0].used = 0;
bkps[1].used = 0;
bkps[2].used = 0;
bkps[3].used = 0;
+ kputs("cleared breakpoints\n");
+ return 1;
+ } else if (msg[0] <= '0' && msg[0] >= '3') {
+ kputs("invalid breakpoint command\n");
+ return 1;
+ }
+ char buf[64];
+ int id = msg[0] - '0';
+ switch (msg[1]) {
+ case 'e':
+ bkps[id].enable = bkps[id].used;
+ kprintf("enabled breakpoint %d\n", id);
+ return 1;
+ case 'd':
+ bkps[id].enable = 0;
+ kprintf("disabled breakpoint %d\n", id);
+ return 1;
+ case 'c':
+ bkps[id].used = 0;
+ kprintf("cleared breakpoint %d\n", id);
return 1;
- } else if (buf[0] <= '0' && buf[0] >= '3') {
- dbg_puts("invalid breakpoint command\n");
+ case 'a':
+ kputs("addr> 0x");
+ debugger_read(buf, 64);
+ bkps[id].addr = strtoll(buf, NULL, 16);
+ kputs("len (1/2/4/8)> ");
+ debugger_read(buf, 64);
+ switch (buf[0]) {
+ case '1': bkps[id].len = 0x0; break;
+ case '2': bkps[id].len = 0x1; break;
+ case '8': bkps[id].len = 0x2; break;
+ case '4': bkps[id].len = 0x3; break;
+ default: bkps[id].len = 0x0; break;
+ }
+ kputs("cond (x/w/io/rw)> ");
+ debugger_read(buf, 64);
+ switch ((int)buf[0] * 256 + (int)buf[1]) {
+ case (int)'x'*256 + (int)0: bkps[id].rw = 0x0; break;
+ case (int)'w'*256 + (int)0: bkps[id].rw = 0x1; break;
+ case (int)'i'*256 + (int)'o': bkps[id].rw = 0x2; break;
+ case (int)'r'*256 + (int)'w': bkps[id].rw = 0x3; break;
+ default: bkps[id].len = 0x0; break;
+ }
+ kputs("instr len (1..15)> ");
+ debugger_read(buf, 64);
+ bkps[id].instr_len = strtoi(buf, NULL, 10);
+ kputs("enable (y/n)> ");
+ debugger_read(buf, 64);
+ bkps[id].used = 1;
+ bkps[id].enable = !(buf[0] == 'n' || buf[0] == 'N');
+ kprintf("added breakpoint %d\n", id);
+ return 1;
+ default:
+ kputs("invalid breakpoint command\n");
return 1;
}
- // TODO set breakpoints
- return 1;
}
static void debugger_load_bkps() {
struct dr7 dr7;
__asm__ volatile ("mov %%dr7, %0" : "=r"(dr7));
dr7.g0 = bkps[0].enable & bkps[0].used;
- dr7.g1 = bkps[1].enable & bkps[0].used;
- dr7.g2 = bkps[2].enable & bkps[0].used;
- dr7.g3 = bkps[3].enable & bkps[0].used;
+ dr7.g1 = bkps[1].enable & bkps[1].used;
+ dr7.g2 = bkps[2].enable & bkps[2].used;
+ dr7.g3 = bkps[3].enable & bkps[3].used;
dr7.l0 = 0;
dr7.l1 = 0;
dr7.l2 = 0;
@@ -263,19 +297,16 @@ static void debugger_load_bkps() {
dr7.len2 = bkps[2].len;
dr7.len3 = bkps[3].len;
__asm__ volatile ("mov %0, %%dr7" : : "r"(dr7));
+ __asm__ volatile ("mov %0, %%dr0" : : "r"(bkps[0].addr));
+ __asm__ volatile ("mov %0, %%dr1" : : "r"(bkps[1].addr));
+ __asm__ volatile ("mov %0, %%dr2" : : "r"(bkps[2].addr));
+ __asm__ volatile ("mov %0, %%dr3" : : "r"(bkps[3].addr));
}
static int debugger_prompt(struct isr_regs *state) {
- char buf[PROMPT_LEN];
- char *p = buf;
- dbg_puts("dbg> ");
- while ((*p = dbg_getc()) != '\r' && p < buf + PROMPT_LEN - 1) {
- dbg_putc(*p++);
- }
- dbg_putc('\n');
- for(; p < buf + PROMPT_LEN; p++) {
- *p = 0;
- }
+ kputs("dbg> ");
+ char buf[64];
+ debugger_read(buf, 64);
struct rflags *rflags = (struct rflags *)&state->rflags;
@@ -283,7 +314,7 @@ static int debugger_prompt(struct isr_regs *state) {
case '\0': // nothing entered
return 1;
case 'h': // help
- dbg_puts("see debugger.c for help information\n");
+ kputs("see debugger.c for help information\n");
return 1;
case 'q': // quit
return 0;
@@ -302,6 +333,36 @@ static int debugger_prompt(struct isr_regs *state) {
dbg_steps = atol(buf + 1) - 1;
//if (dbg_steps < 0) dbg_steps = 0;
return 0;
+ case 'm': // memory
+ {
+ kputs("addr> 0x");
+ debugger_read(buf, 64);
+ uint64_t start = (~0xF) & strtoll(buf, NULL, 16);
+
+ kputs("len> 0x");
+ debugger_read(buf, 64);
+ uint64_t len = (~0xF) & strtoll(buf, NULL, 16);
+
+ for (uint64_t a = start; a <= start + len; a += 0x10) {
+ kprintf("%08lx: ", a);
+ for (uint64_t b = 0; b < 0x10; b++) {
+ kprintf("%02x ", *(uint8_t *)(a + b));
+ if (b % 0x08 == 7) {
+ kputc(' ');
+ }
+ }
+ kputs("|");
+ for (uint64_t b = 0; b < 0x10; b++) {
+ uint8_t ch = *(uint8_t *)(a + b);
+ if (ch < 0x20 || ch >= 0x7f) {
+ ch = '.';
+ }
+ kputc(ch);
+ }
+ kputs("|\n");
+ }
+ return 1;
+ }
case 'b': // breakpoints
{
int res = debugger_handle_bkp_cmd(buf+1);
@@ -309,7 +370,7 @@ static int debugger_prompt(struct isr_regs *state) {
return res;
}
default:
- dbg_puts("unknown command\n");
+ kputs("unknown command\n");
return 1;
}
}
@@ -318,9 +379,7 @@ void debugger(struct isr_regs *state, int cause) {
struct dr6 dr6;
__asm__ volatile ("mov %%dr6, %0" : "=r"(dr6));
- if (dr6.b0 || dr6.b1 || dr6.b2 || dr6.b3) {
-
- } else {
+ if (!(dr6.b0 || dr6.b1 || dr6.b2 || dr6.b3)) {
if (dr6.bs && dbg_steps > 0) {
dbg_steps--;
return;
@@ -333,11 +392,22 @@ void debugger(struct isr_regs *state, int cause) {
debugger_msg(cause, dr6);
+ kputs("hi\n");
+
dbg_steps = 0;
dbg_continue = 0;
- struct rflags *rflags = (struct rflags *)&state->rflags;
- rflags->tf = 0;
+ ((struct rflags *)&state->rflags)->tf = 0;
+
+ if (dr6.b0) {
+ state->rip += bkps[0].instr_len;
+ } else if (dr6.b1) {
+ state->rip += bkps[1].instr_len;
+ } else if (dr6.b2) {
+ state->rip += bkps[2].instr_len;
+ } else if (dr6.b3) {
+ state->rip += bkps[3].instr_len;
+ }
while (debugger_prompt(state));
}