bitkeeper revision 1.1098.1.1 (4107c16f_jhuAGUiMBcotuiFhO6dHQ)

Add a simple debugger for Xen and domain 0.  This isn't anything
like as complete as PDB; it can't access any userspace other than
the current process's and it can't make any changes to a running
process.  On the other hand, it's probably slightly less fragile.
The code's a lot cleaner, as well.
This commit is contained in:
sos22@donkeykong.cl.cam.ac.uk committed 2004-07-28 15:08:31 +00:00
1 parent 2faa66991b
commit b69f92f301
9 files changed
+471 -20

No files matched your search

+2
View File
@@ -449,10 +449,12 @@
3ddb79bcecupHj56ZbTa3B0FxDowMg xen/arch/x86/x86_32/entry.S
3ddb79bcHwuCQDjBICDTSis52hWguw xen/arch/x86/x86_32/mm.c
3ddb79bc4nTpGQOe6_-MbyZzkhlhFQ xen/arch/x86/x86_32/usercopy.c
4107c15e_NqNYew2EXroXz2mgTAMWQ xen/arch/x86/x86_32/xdb_trap.S
3ddb79bcOMCu9-5mKpjIh5d0qqBDPg xen/arch/x86/x86_32/xen.lds
40e96d3aLDI-nViMuYneD7VKYlZrVg xen/arch/x86/x86_64/entry.S
40e96d3ahBTZqbTViInnq0lM03vs7A xen/arch/x86/x86_64/usercopy.c
40e96d3akN3Hu_J5Bk-WXD8OGscrYQ xen/arch/x86/x86_64/xen.lds
4107c15e-VmEcLsE-7JCXZaabI8C7A xen/arch/x86/xdb.c
3ddb79bdff-gj-jFGKjOejeHLqL8Lg xen/common/Makefile
3e397e66AyyD5fYraAySWuwi9uqSXg xen/common/ac_timer.c
4022a73c_BbDFd2YJ_NQYVvKX5Oz7w xen/common/debug-linux.c
+1
View File
@@ -38,6 +38,7 @@ smh22@boulderdash.cl.cam.ac.uk
smh22@labyrinth.cl.cam.ac.uk
smh22@tempest.cl.cam.ac.uk
smh22@uridium.cl.cam.ac.uk
sos22@donkeykong.cl.cam.ac.uk
sos22@labyrinth.cl.cam.ac.uk
tlh20@elite.cl.cam.ac.uk
tlh20@labyrinth.cl.cam.ac.uk
+35
View File
@@ -0,0 +1,35 @@
.global trap_to_xendbg
.extern __trap_to_xendbg
#define SAVE_ALL_NOSEGREGS \
pushw $0; \
pushw %gs; \
pushw $0; \
pushw %fs; \
pushw $0; \
pushw %es; \
pushw $0; \
pushw %ds; \
pushl %eax; \
pushl %ebp; \
pushl %edi; \
pushl %esi; \
pushl %edx; \
pushl %ecx; \
pushl %ebx;
// Save the register state and call __trap_to_xendbg
trap_to_xendbg:
pushw $0
pushw %ss
pushl %esp //We'll fix this up later, in __trap_to_xendbg, by adding 8
pushf
pushw $0
pushw %cs
pushl 16(%esp)
1: pushl $0 // Orig_eax
SAVE_ALL_NOSEGREGS
pushl %esp
call __trap_to_xendbg
add $72, %esp
ret
+378
View File
@@ -0,0 +1,378 @@
/* Simple hacked-up version of pdb for us in post-mortem debugging of
Xen and domain 0. This should be a little cleaner, hopefully. Note
that we can't share a serial line with PDB. */
#include <xen/lib.h>
#include <asm/uaccess.h>
#include <xen/serial.h>
#include <asm/irq.h>
#include <xen/spinlock.h>
/* Printk isn't particularly safe just after we've trapped to the
debugger. so avoid it. */
#define dbg_printk(...)
static int
xendbg_serhnd = -1;
static void
xendbg_put_char(u8 data)
{
serial_putc(xendbg_serhnd, data);
}
static u8
xendbg_get_char(void)
{
u8 ch;
extern unsigned char __serial_getc(int handle);
ch = __serial_getc(xendbg_serhnd);
return ch;
}
static int
hex_char_val(unsigned char c)
{
if (c >= '0' && c <= '9')
return c - '0';
else if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
else if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
else
BUG();
}
static unsigned char
val_to_hex_char(unsigned val)
{
if (val < 10)
return val + '0';
else if (val < 16)
return val - 10 + 'a';
else
BUG();
}
/* Receive a command. Returns -1 on csum error, 0 otherwise. */
/* Does not acknowledge. */
static int
attempt_receive_packet(char *recv_buf)
{
int count;
u8 csum;
u8 received_csum;
u8 ch;
/* Skip over everything up to the first '$' */
while ((ch = xendbg_get_char()) != '$')
;
csum = 0;
for (count = 0; count < 4096; count++) {
ch = xendbg_get_char();
if (ch == '#')
break;
recv_buf[count] = ch;
csum += ch;
}
if (count == 4096) {
dbg_printk("WARNING: GDB sent a stupidly big packet.\n");
return -1;
}
recv_buf[count] = 0;
received_csum = hex_char_val(xendbg_get_char()) * 16 +
hex_char_val(xendbg_get_char());
if (received_csum == csum) {
return 0;
} else {
return -1;
}
}
/* Send a string of bytes to the debugger. */
static void
xendbg_send(const char *buf, int count)
{
int x;
for (x = 0; x < count; x++)
xendbg_put_char(buf[x]);
}
/* Receive a command, discarding up to ten packets with csum
* errors. Acknowledges all received packets. */
static int
receive_command(char *recv_buf)
{
int r;
int count;
count = 0;
do {
r = attempt_receive_packet(recv_buf);
if (r < 0)
xendbg_send("-", 1);
else
xendbg_send("+", 1);
count++;
} while (r < 0 && count < 10);
return r;
}
static void
u32_to_hex_u8(unsigned char val, char *buf)
{
if (val >= 256)
BUG();
sprintf(buf, "%.02x\n", val);
}
static void
u32_to_hex_u32(unsigned val, char *buf)
{
sprintf(buf, "%.08x\n", val);
}
static void
xendbg_send_hex_u8(unsigned char val)
{
char buf[2];
u32_to_hex_u8(val, buf);
xendbg_send(buf, 2);
}
static u8
xendbg_reply_csum;
static void
xendbg_start_reply(void)
{
xendbg_reply_csum = 0;
xendbg_send("$", 1);
}
static void
xendbg_sendrep_data(const unsigned char *data, unsigned long len)
{
int x;
for (x = 0; x < len; x++) {
xendbg_put_char(data[x]);
xendbg_reply_csum += data[x];
}
}
/* Return 0 if the reply was successfully received, !0 otherwise. */
static int
xendbg_finish_reply(void)
{
char ch;
xendbg_send("#", 1);
xendbg_send_hex_u8(xendbg_reply_csum);
ch = xendbg_get_char();
if (ch == '+')
return 0;
else
return 1;
}
static void
xendbg_sendrep_hex_u8(unsigned val)
{
char buf[2];
u32_to_hex_u8(val, buf);
xendbg_sendrep_data(buf, 2);
}
static void
xendbg_sendrep_hex_u32(unsigned val)
{
char buf[8];
u32_to_hex_u32(val, buf);
xendbg_sendrep_data(buf, 8);
}
static void
xendbg_sendrep_hex_u32_le(unsigned val)
{
val = (((val >> 0) & 0xff) << 24) |
(((val >> 8) & 0xff) << 16) |
(((val >> 16) & 0xff) << 8) |
(((val >> 24) & 0xff) << 0);
xendbg_sendrep_hex_u32(val);
}
static int
handle_memory_read_command(unsigned long addr, unsigned long length)
{
int x;
unsigned char val;
int r;
unsigned old_s_limit;
dbg_printk("Memory read starting at %lx, length %lx.\n", addr,
length);
old_s_limit = current->addr_limit.seg;
current->addr_limit.seg = ~0;
xendbg_start_reply();
for (x = 0; x < length; x++) {
r = copy_from_user(&val, (void *)(addr + x), 1);
if (r != 0) {
dbg_printk("Error reading from %lx.\n", addr + x);
break;
}
xendbg_sendrep_hex_u8(val);
}
if (x == 0)
xendbg_sendrep_data("E05", 3);
dbg_printk("Read done.\n");
current->addr_limit.seg = old_s_limit;
return xendbg_finish_reply();
}
static int
xendbg_send_reply(const char *buf)
{
xendbg_start_reply();
xendbg_sendrep_data(buf, strlen(buf));
return xendbg_finish_reply();
}
static int
handle_register_read_command(struct pt_regs *regs)
{
xendbg_start_reply();
xendbg_sendrep_hex_u32_le(regs->eax);
xendbg_sendrep_hex_u32_le(regs->ecx);
xendbg_sendrep_hex_u32_le(regs->edx);
xendbg_sendrep_hex_u32_le(regs->ebx);
xendbg_sendrep_hex_u32_le(regs->esp);
xendbg_sendrep_hex_u32_le(regs->ebp);
xendbg_sendrep_hex_u32_le(regs->esi);
xendbg_sendrep_hex_u32_le(regs->edi);
xendbg_sendrep_hex_u32_le(regs->eip);
xendbg_sendrep_hex_u32_le(regs->eflags);
xendbg_sendrep_hex_u32_le(regs->xcs);
xendbg_sendrep_hex_u32_le(regs->xss);
xendbg_sendrep_hex_u32_le(regs->xes);
xendbg_sendrep_hex_u32_le(regs->xfs);
xendbg_sendrep_hex_u32_le(regs->xgs);
return xendbg_finish_reply();
}
static unsigned long
hex_to_int(const char *start, const char **end)
{
return simple_strtol(start, (char **)end, 16);
}
static int
process_command(const char *received_packet, struct pt_regs *regs)
{
const char *ptr;
unsigned long addr, length;
int retry;
int counter;
int resume = 0;
/* Repeat until gdb acks the reply */
counter = 0;
do {
switch (received_packet[0]) {
case 'g': /* Read registers */
retry = handle_register_read_command(regs);
break;
case 'm': /* Read memory */
addr = hex_to_int(received_packet + 1, &ptr);
if (ptr == received_packet + 1 ||
ptr[0] != ',') {
xendbg_send_reply("E03");
return 0;
}
length = hex_to_int(ptr + 1, &ptr);
if (ptr[0] != 0) {
xendbg_send_reply("E04");
return 0;
}
retry =
handle_memory_read_command(addr,
length);
break;
case 'G': /* Write registers */
case 'M': /* Write memory */
retry = xendbg_send_reply("E02");
break;
case 'D':
resume = 1;
retry = xendbg_send_reply("");
break;
case 'c': /* Resume at current address */
case 's': /* Single step */
case '?':
retry = xendbg_send_reply("S01");
break;
default:
retry = xendbg_send_reply("");
break;
}
counter++;
} while (retry == 1 && counter < 10);
if (retry) {
dbg_printk("WARNING: gdb disappeared when we were trying to send it a reply.\n");
return 1;
}
return resume;
}
void
__trap_to_xendbg(struct pt_regs *regs)
{
int resume = 0;
int r;
static int xendbg_running;
static char recv_buf[4096];
if (xendbg_serhnd < 0) {
dbg_printk("Debugger not ready yet.\n");
return;
}
/* We rely on our caller to ensure we're only on one processor
* at a time... We should probably panic here, but given that
* we're a debugger we should probably be a little tolerant of
* things going wrong. */
if (xendbg_running) {
dbg_printk("WARNING WARNING WARNING: Avoiding recursive xendbg.\n");
return;
}
xendbg_running = 1;
/* trap_to_xendbg gets esp slightly wrong. Correct for this. */
regs->esp += 8;
dbg_printk("Waiting for GDB to attach to XenDBG\n");
/* Urgg... hope this is right... */
while (resume == 0) {
r = receive_command(recv_buf);
if (r < 0) {
dbg_printk("GDB disappeared, trying to resume Xen...\n");
resume = 1;
} else
resume = process_command(recv_buf, regs);
}
xendbg_running = 0;
}
void
initialize_xendbg(void)
{
extern char opt_xendbg[];
if (!strcmp(opt_xendbg, "none"))
return;
xendbg_serhnd = parse_serial_handle(opt_xendbg);
if (xendbg_serhnd == -1)
panic("Can't parse %s as XDB serial info.\n", opt_xendbg);
/* Acknowledge any spurious GDB packets. */
xendbg_put_char('+');
printk("Xendbg initialised.\n");
}
+4
View File
@@ -163,6 +163,8 @@ void domain_crash(void)
BUG();
}
extern void trap_to_xendbg(void);
void domain_shutdown(u8 reason)
{
struct domain *d;
@@ -172,6 +174,8 @@ void domain_shutdown(u8 reason)
extern void machine_restart(char *);
extern void machine_halt(void);
trap_to_xendbg();
if ( reason == 0 )
{
printk("Domain 0 halted: Our work here is done.\n");
+12
View File
@@ -64,6 +64,8 @@ int opt_ignorebiostables=0;
int opt_watchdog=0;
/* opt_pdb: Name of serial port for Xen pervasive debugger (and enable pdb) */
unsigned char opt_pdb[10] = "none";
/* opt_pdb: Name of serial port for Xen debugger (and enable xendbg) */
unsigned char opt_xendbg[10] = "none";
/* opt_tbuf_size: trace buffer size (in pages) */
unsigned int opt_tbuf_size = 10;
/* opt_sched: scheduler - default to Borrowed Virtual Time */
@@ -98,6 +100,7 @@ static struct {
{ "ignorebiostables", OPT_BOOL, &opt_ignorebiostables },
{ "watchdog", OPT_BOOL, &opt_watchdog },
{ "pdb", OPT_STR, &opt_pdb },
{ "xendbg", OPT_STR, &opt_xendbg },
{ "tbuf_size", OPT_UINT, &opt_tbuf_size },
{ "sched", OPT_STR, &opt_sched },
{ "physdev_dom0_hide", OPT_STR, &opt_physdev_dom0_hide },
@@ -108,6 +111,9 @@ static struct {
};
void initialize_xendbg(void);
void trap_to_xendbg(void);
void cmain(multiboot_info_t *mbi)
{
struct domain *new_dom;
@@ -163,6 +169,8 @@ void cmain(multiboot_info_t *mbi)
init_console();
initialize_xendbg();
/* HELLO WORLD --- start-of-day banner text. */
printk(XEN_BANNER);
printk(" http://www.cl.cam.ac.uk/netos/xen\n");
@@ -291,6 +299,10 @@ void cmain(multiboot_info_t *mbi)
shadow_mode_init();
printk("Trapping to debugger.\n");
trap_to_xendbg();
printk("Trapped to debugger and came back.\n");
/*
* We're going to setup domain0 using the module(s) that we stashed safely
* above our heap. The second module, if present, is an initrd ramdisk.
+6
View File
@@ -115,6 +115,11 @@ extern void perfc_reset(unsigned char key, void *dev_id,
struct pt_regs *regs);
#endif
void do_panic_key(unsigned char key, void *dev_id, struct pt_regs *regs)
{
panic("Panic requested from console");
}
void initialize_keytable(void)
{
add_key_handler('d', dump_registers, "dump registers");
@@ -128,4 +133,5 @@ void initialize_keytable(void)
add_key_handler('p', perfc_printall, "print performance counters");
add_key_handler('P', perfc_reset, "reset performance counters");
#endif
add_key_handler('%', do_panic_key, "Panic Xen");
}
+5 -1
View File
@@ -440,6 +440,8 @@ void console_endboot(int disable_vga)
* **************************************************************
*/
extern void trap_to_xendbg(void);
void panic(const char *fmt, ...)
{
va_list args;
@@ -450,7 +452,9 @@ void panic(const char *fmt, ...)
va_start(args, fmt);
(void)vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
trap_to_xendbg();
/* Spit out multiline message in one go. */
spin_lock_irqsave(&console_lock, flags);
__putstr("\n****************************************\n");
+28 -19
View File
@@ -420,6 +420,30 @@ static int byte_matches(int handle, unsigned char *pc)
return 0;
}
unsigned char __serial_getc(int handle)
{
uart_t *uart = &com[handle & SERHND_IDX];
unsigned char c;
/* disable_irq() may have raced execution of uart_rx(). */
while ( uart->rxbufp != uart->rxbufc )
{
c = uart->rxbuf[MASK_RXBUF_IDX(uart->rxbufc++)];
if ( byte_matches(handle, &c) )
return c;
}
/* We now wait for the UART to receive a suitable character. */
do {
while ( (inb(uart->io_base + LSR) & LSR_DR) == 0 )
barrier();
c = inb(uart->io_base + RBR);
}
while ( !byte_matches(handle, &c) );
return c;
}
unsigned char serial_getc(int handle)
{
uart_t *uart = &com[handle & SERHND_IDX];
@@ -434,26 +458,11 @@ unsigned char serial_getc(int handle)
if ( byte_matches(handle, &c) )
goto out;
}
disable_irq(uart->irq);
/* disable_irq() may have raced execution of uart_rx(). */
while ( uart->rxbufp != uart->rxbufc )
{
c = uart->rxbuf[MASK_RXBUF_IDX(uart->rxbufc++)];
if ( byte_matches(handle, &c) )
goto enable_and_out;
}
/* We now wait for the UART to receive a suitable character. */
do {
while ( (inb(uart->io_base + LSR) & LSR_DR) == 0 )
barrier();
c = inb(uart->io_base + RBR);
}
while ( !byte_matches(handle, &c) );
enable_and_out:
disable_irq(uart->irq);
c = __serial_getc(handle);
enable_irq(uart->irq);
out:
spin_unlock_irqrestore(&uart->lock, flags);
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.