Isaku Yamahata
2006-Jan-10 07:31 UTC
[Xen-devel] [PATCH] cdb: split cdb into arch independet/dependet part
split cdb into arch independent/dependet part. This is needed for cdb on xen/ia64 which I will post later. Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp> diff -r 45fdc28bd5e0 -r b1068ef4ffb0 xen/arch/x86/cdb.c --- a/xen/arch/x86/cdb.c Tue Jan 10 15:46:24 2006 +0900 +++ b/xen/arch/x86/cdb.c Tue Jan 10 15:51:03 2006 +0900 @@ -1,40 +1,12 @@ -/* Simple hacked-up version of pdb for use 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. */ -/* We try to avoid assuming much about what the rest of the system is - doing. In particular, dynamic memory allocation is out of the - question. */ -/* Resuming after we''ve stopped used to work, but more through luck - than any actual intention. It doesn''t at the moment. */ -#include <xen/lib.h> -#include <asm/uaccess.h> -#include <xen/spinlock.h> -#include <xen/serial.h> -#include <xen/irq.h> +/* + * x86-specific cdb routines + */ #include <asm/debugger.h> -#include <xen/init.h> -#include <xen/smp.h> -#include <xen/console.h> -#include <asm/apic.h> - -/* Printk isn''t particularly safe just after we''ve trapped to the - debugger. so avoid it. */ -#define dbg_printk(...) - -static char opt_cdb[30] = "none"; -string_param("cdb", opt_cdb); - -struct xendbg_context { - int serhnd; - u8 reply_csum; - int currently_attached:1; -}; /* Like copy_from_user, but safe to call with interrupts disabled. - Trust me, and don''t look behind the curtain. */ -static unsigned -dbg_copy_from_user(void *dest, const void *src, unsigned len) +unsigned +xendbg_arch_copy_from_user(void *dest, const void *src, unsigned len) { int __d0, __d1, __d2; ASSERT(!local_irq_is_enabled()); @@ -60,117 +32,6 @@ return __d2; } -static void -xendbg_put_char(u8 data, struct xendbg_context *ctx) -{ - ctx->reply_csum += data; - serial_putc(ctx->serhnd, data); -} - -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(); - return -1; -} - -/* Receive a command. Returns -1 on csum error, 0 otherwise. */ -/* Does not acknowledge. */ -static int -attempt_receive_packet(char *recv_buf, struct xendbg_context *ctx) -{ - int count; - u8 csum; - u8 received_csum; - u8 ch; - - /* Skip over everything up to the first ''$'' */ - while ((ch = serial_getc(ctx->serhnd)) != ''$'') - ; - csum = 0; - for (count = 0; count < 4096; count++) { - ch = serial_getc(ctx->serhnd); - 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(serial_getc(ctx->serhnd)) * 16 + - hex_char_val(serial_getc(ctx->serhnd)); - 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, struct xendbg_context *ctx) -{ - int x; - for (x = 0; x < count; x++) - xendbg_put_char(buf[x], ctx); -} - -/* Receive a command, discarding up to ten packets with csum - * errors. Acknowledges all received packets. */ -static int -receive_command(char *recv_buf, struct xendbg_context *ctx) -{ - int r; - int count; - - count = 0; - do { - r = attempt_receive_packet(recv_buf, ctx); - if (r < 0) - xendbg_put_char(''-'', ctx); - else - xendbg_put_char(''+'', ctx); - count++; - } while (r < 0 && count < 10); - return r; -} - -static void -xendbg_start_reply(struct xendbg_context *ctx) -{ - xendbg_put_char(''$'', ctx); - ctx->reply_csum = 0; -} - -/* Return 0 if the reply was successfully received, !0 otherwise. */ -static int -xendbg_finish_reply(struct xendbg_context *ctx) -{ - char ch; - char buf[3]; - - sprintf(buf, "%.02x\n", ctx->reply_csum); - - xendbg_put_char(''#'', ctx); - xendbg_send(buf, 2, ctx); - - ch = serial_getc(ctx->serhnd); - if (ch == ''+'') - return 0; - else - return 1; -} - /* Swap the order of the bytes in a work. */ static inline unsigned bswab32(unsigned val) @@ -181,43 +42,8 @@ (((val >> 24) & 0xff) << 0); } -static int -handle_memory_read_command(unsigned long addr, unsigned long length, - struct xendbg_context *ctx) -{ - int x; - unsigned char val; - int r; - char buf[2]; - - dbg_printk("Memory read starting at %lx, length %lx.\n", addr, - length); - xendbg_start_reply(ctx); - for (x = 0; x < length; x++) { - r = dbg_copy_from_user(&val, (void *)(addr + x), 1); - if (r != 0) { - dbg_printk("Error reading from %lx.\n", addr + x); - break; - } - sprintf(buf, "%.02x", val); - xendbg_send(buf, 2, ctx); - } - if (x == 0) - xendbg_send("E05", 3, ctx); - dbg_printk("Read done.\n"); - return xendbg_finish_reply(ctx); -} - -static int -xendbg_send_reply(const char *buf, struct xendbg_context *ctx) -{ - xendbg_start_reply(ctx); - xendbg_send(buf, strlen(buf), ctx); - return xendbg_finish_reply(ctx); -} - -static int -handle_register_read_command(struct cpu_user_regs *regs, struct xendbg_context *ctx) +int +xendbg_arch_handle_register_read_command(struct cpu_user_regs *regs, struct xendbg_context *ctx) { char buf[121]; @@ -242,173 +68,17 @@ return xendbg_send_reply(buf, ctx); } -static int -process_command(char *received_packet, struct cpu_user_regs *regs, - struct xendbg_context *ctx) +int +xendbg_arch_handle_register_get_command(unsigned long regnum, struct cpu_user_regs *regs, struct xendbg_context *ctx) { - 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, ctx); - ASSERT(!local_irq_is_enabled()); - break; - case ''m'': /* Read memory */ - addr = simple_strtoul(received_packet + 1, &ptr, 16); - if (ptr == received_packet + 1 || - ptr[0] != '','') { - xendbg_send_reply("E03", ctx); - return 0; - } - length = simple_strtoul(ptr + 1, &ptr, 16); - if (ptr[0] != 0) { - xendbg_send_reply("E04", ctx); - return 0; - } - retry - handle_memory_read_command(addr, - length, - ctx); - ASSERT(!local_irq_is_enabled()); - break; - case ''G'': /* Write registers */ - case ''M'': /* Write memory */ - retry = xendbg_send_reply("E02", ctx); - break; - case ''D'': - resume = 1; - ctx->currently_attached = 0; - retry = xendbg_send_reply("", ctx); - break; - case ''c'': /* Resume at current address */ - ctx->currently_attached = 1; - resume = 1; - retry = 0; - break; - case ''Z'': /* We need to claim to support these or gdb - won''t let you continue the process. */ - case ''z'': - retry = xendbg_send_reply("OK", ctx); - break; - - case ''s'': /* Single step */ - case ''?'': - retry = xendbg_send_reply("S01", ctx); - break; - default: - retry = xendbg_send_reply("", ctx); - 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; + return xendbg_send_reply("", ctx); } -static struct xendbg_context -xdb_ctx = { - serhnd : -1 -}; - -int -__trap_to_cdb(struct cpu_user_regs *regs) -{ - int resume = 0; - int r; - static atomic_t xendbg_running = ATOMIC_INIT(1); - static char recv_buf[4096]; - unsigned flags; - - if (xdb_ctx.serhnd < 0) { - dbg_printk("Debugger not ready yet.\n"); - return 0; - } - - /* 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. */ - /* We don''t want to use a spin lock here, because we''re doing - two distinct things: - - 1 -- we don''t want to run on more than one processor at a time, - and - 2 -- we want to do something sensible if we re-enter ourselves. - - Spin locks are good for 1, but useless for 2. */ - if (!atomic_dec_and_test(&xendbg_running)) { - printk("WARNING WARNING WARNING: Avoiding recursive xendbg.\n"); - atomic_inc(&xendbg_running); - return 0; - } - - smp_send_stop(); - - /* Try to make things a little more stable by disabling - interrupts while we''re here. */ - local_irq_save(flags); - - watchdog_disable(); - console_start_sync(); - - /* Shouldn''t really do this, but otherwise we stop for no - obvious reason, which is Bad */ - printk("Waiting for GDB to attach to XenDBG\n"); - - /* If gdb is already attached, tell it we''ve stopped again. */ - if (xdb_ctx.currently_attached) { - do { - r = xendbg_send_reply("S01", &xdb_ctx); - } while (r != 0); - } - - while (resume == 0) { - ASSERT(!local_irq_is_enabled()); - r = receive_command(recv_buf, &xdb_ctx); - ASSERT(!local_irq_is_enabled()); - if (r < 0) { - dbg_printk("GDB disappeared, trying to resume Xen...\n"); - resume = 1; - } else { - ASSERT(!local_irq_is_enabled()); - resume = process_command(recv_buf, regs, &xdb_ctx); - ASSERT(!local_irq_is_enabled()); - } - } - - console_end_sync(); - watchdog_enable(); - atomic_inc(&xendbg_running); - - local_irq_restore(flags); - - return 0; -} - -static int -initialize_xendbg(void) -{ - if (!strcmp(opt_cdb, "none")) - return 0; - xdb_ctx.serhnd = serial_parse_handle(opt_cdb); - if (xdb_ctx.serhnd == -1) - panic("Can''t parse %s as CDB serial info.\n", opt_cdb); - - /* Acknowledge any spurious GDB packets. */ - xendbg_put_char(''+'', &xdb_ctx); - - printk("Xendbg initialised.\n"); - return 0; -} - -__initcall(initialize_xendbg); +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -r 45fdc28bd5e0 -r b1068ef4ffb0 xen/common/Makefile --- a/xen/common/Makefile Tue Jan 10 15:46:24 2006 +0900 +++ b/xen/common/Makefile Tue Jan 10 15:51:03 2006 +0900 @@ -3,6 +3,9 @@ ifneq ($(perfc),y) OBJS := $(subst perfc.o,,$(OBJS)) +endif +ifneq ($(crash_debug),y) +OBJS := $(patsubst cdb.o,,$(OBJS)) endif default: common.o diff -r 45fdc28bd5e0 -r b1068ef4ffb0 xen/include/asm-x86/debugger.h --- a/xen/include/asm-x86/debugger.h Tue Jan 10 15:46:24 2006 +0900 +++ b/xen/include/asm-x86/debugger.h Tue Jan 10 15:51:03 2006 +0900 @@ -41,6 +41,8 @@ if ( debugger_trap_fatal(_v, _r) ) return EXCRET_fault_fixed; #if defined(CRASH_DEBUG) + +#include <xen/debugger.h> extern int __trap_to_cdb(struct cpu_user_regs *r); diff -r 45fdc28bd5e0 -r b1068ef4ffb0 xen/common/cdb.c --- /dev/null Thu Jan 1 00:00:00 1970 +0000 +++ b/xen/common/cdb.c Tue Jan 10 15:51:03 2006 +0900 @@ -0,0 +1,369 @@ +/* Simple hacked-up version of pdb for use 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. */ +/* We try to avoid assuming much about what the rest of the system is + doing. In particular, dynamic memory allocation is out of the + question. */ +/* Resuming after we''ve stopped used to work, but more through luck + than any actual intention. It doesn''t at the moment. */ +#include <xen/lib.h> +#include <asm/uaccess.h> +#include <xen/spinlock.h> +#include <xen/serial.h> +#include <xen/irq.h> +#include <asm/debugger.h> +#include <xen/init.h> +#include <xen/smp.h> +#include <xen/console.h> + +/* Printk isn''t particularly safe just after we''ve trapped to the + debugger. so avoid it. */ +#define dbg_printk(...) +//#define dbg_printk(...) printk(__VA_ARGS__) + +//#define CONFIG_CDB_NO_CSUM +#undef CONFIG_CDB_NO_CSUM + +static char opt_cdb[30] = "none"; +string_param("cdb", opt_cdb); + +static void +xendbg_put_char(u8 data, struct xendbg_context *ctx) +{ + ctx->reply_csum += data; + serial_putc(ctx->serhnd, data); +} + +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(); + return -1; +} + +/* Receive a command. Returns -1 on csum error, 0 otherwise. */ +/* Does not acknowledge. */ +static int +attempt_receive_packet(char *recv_buf, struct xendbg_context *ctx) +{ + int count; + u8 csum; + u8 received_csum; + u8 ch; + + /* Skip over everything up to the first ''$'' */ + while ((ch = serial_getc(ctx->serhnd)) != ''$'') + ; + csum = 0; + for (count = 0; count < 4096; count++) { + ch = serial_getc(ctx->serhnd); + 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(serial_getc(ctx->serhnd)) * 16 + + hex_char_val(serial_getc(ctx->serhnd)); +#ifdef CONFIG_CDB_NO_CSUM + return 0; +#else + if (received_csum == csum) { + return 0; + } else { + return -1; + } +#endif +} + +/* Send a string of bytes to the debugger. */ +static void +xendbg_send(const char *buf, int count, struct xendbg_context *ctx) +{ + int x; + for (x = 0; x < count; x++) + xendbg_put_char(buf[x], ctx); +} + +/* Receive a command, discarding up to ten packets with csum + * errors. Acknowledges all received packets. */ +static int +receive_command(char *recv_buf, struct xendbg_context *ctx) +{ + int r; + int count; + + count = 0; + do { + r = attempt_receive_packet(recv_buf, ctx); + if (r < 0) + xendbg_put_char(''-'', ctx); + else + xendbg_put_char(''+'', ctx); + count++; + } while (r < 0 && count < 10); + return r; +} + +static void +xendbg_start_reply(struct xendbg_context *ctx) +{ + xendbg_put_char(''$'', ctx); + ctx->reply_csum = 0; +} + +/* Return 0 if the reply was successfully received, !0 otherwise. */ +static int +xendbg_finish_reply(struct xendbg_context *ctx) +{ + char ch; + char buf[3]; + + sprintf(buf, "%.02x\n", ctx->reply_csum); + + xendbg_put_char(''#'', ctx); + xendbg_send(buf, 2, ctx); + + ch = serial_getc(ctx->serhnd); + if (ch == ''+'') + return 0; + else + return 1; +} + +static int +handle_memory_read_command(unsigned long addr, unsigned long length, + struct xendbg_context *ctx) +{ + int x; + unsigned char val; + int r; + char buf[2]; + + dbg_printk("Memory read starting at %lx, length %lx.\n", addr, + length); + xendbg_start_reply(ctx); + for (x = 0; x < length; x++) { + r = xendbg_arch_copy_from_user(&val, (void *)(addr + x), 1); + if (r != 0) { + dbg_printk("Error reading from %lx.\n", addr + x); + break; + } + sprintf(buf, "%.02x", val); + xendbg_send(buf, 2, ctx); + } + if (x == 0) + xendbg_send("E05", 3, ctx); + dbg_printk("Read done.\n"); + return xendbg_finish_reply(ctx); +} + +int +xendbg_send_reply(const char *buf, struct xendbg_context *ctx) +{ + xendbg_start_reply(ctx); + xendbg_send(buf, strlen(buf), ctx); + return xendbg_finish_reply(ctx); +} + +static int +process_command(char *received_packet, struct cpu_user_regs *regs, + struct xendbg_context *ctx) +{ + 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 = xendbg_arch_handle_register_read_command(regs, ctx); + ASSERT(!local_irq_is_enabled()); + break; + case ''m'': /* Read memory */ + addr = simple_strtoul(received_packet + 1, &ptr, 16); + if (ptr == received_packet + 1 || + ptr[0] != '','') { + xendbg_send_reply("E03", ctx); + return 0; + } + length = simple_strtoul(ptr + 1, &ptr, 16); + if (ptr[0] != 0) { + xendbg_send_reply("E04", ctx); + return 0; + } + retry = handle_memory_read_command(addr, + length, + ctx); + ASSERT(!local_irq_is_enabled()); + break; + case ''G'': /* Write registers */ + case ''M'': /* Write memory */ + retry = xendbg_send_reply("E02", ctx); + break; + case ''D'': + resume = 1; + ctx->currently_attached = 0; + retry = xendbg_send_reply("", ctx); + break; + case ''c'': /* Resume at current address */ + ctx->currently_attached = 1; + resume = 1; + retry = 0; + break; + case ''p'': /* read register */ + addr = simple_strtoul(received_packet + 1, &ptr, 16); + if (ptr == received_packet + 1) { + xendbg_send_reply("E03", ctx); + return 0; + } + if (ptr[0] != 0) { + xendbg_send_reply("E04", ctx); + return 0; + } + retry = xendbg_arch_handle_register_get_command(addr, regs, ctx); + break; + case ''Z'': /* We need to claim to support these or gdb + won''t let you continue the process. */ + case ''z'': + retry = xendbg_send_reply("OK", ctx); + break; + + case ''s'': /* Single step */ + case ''?'': + retry = xendbg_send_reply("S01", ctx); + break; + default: + retry = xendbg_send_reply("", ctx); + 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; +} + +static struct xendbg_context +xdb_ctx = { + serhnd : -1 +}; + +int +__trap_to_cdb(struct cpu_user_regs *regs) +{ + int resume = 0; + int r; + static atomic_t xendbg_running = ATOMIC_INIT(1); + static char recv_buf[4096]; + unsigned flags; + + if (xdb_ctx.serhnd < 0) { + dbg_printk("Debugger not ready yet.\n"); + return 0; + } + + /* 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. */ + /* We don''t want to use a spin lock here, because we''re doing + two distinct things: + + 1 -- we don''t want to run on more than one processor at a time, + and + 2 -- we want to do something sensible if we re-enter ourselves. + + Spin locks are good for 1, but useless for 2. */ + if (!atomic_dec_and_test(&xendbg_running)) { + printk("WARNING WARNING WARNING: Avoiding recursive xendbg.\n"); + atomic_inc(&xendbg_running); + return 0; + } + + smp_send_stop(); + + /* Try to make things a little more stable by disabling + interrupts while we''re here. */ + local_irq_save(flags); + + watchdog_disable(); + console_start_sync(); + + /* Shouldn''t really do this, but otherwise we stop for no + obvious reason, which is Bad */ + printk("Waiting for GDB to attach to XenDBG\n"); + + /* If gdb is already attached, tell it we''ve stopped again. */ + if (xdb_ctx.currently_attached) { + do { + r = xendbg_send_reply("S01", &xdb_ctx); + } while (r != 0); + } + + while (resume == 0) { + ASSERT(!local_irq_is_enabled()); + r = receive_command(recv_buf, &xdb_ctx); + ASSERT(!local_irq_is_enabled()); + if (r < 0) { + dbg_printk("GDB disappeared, trying to resume Xen...\n"); + resume = 1; + } else { + ASSERT(!local_irq_is_enabled()); + resume = process_command(recv_buf, regs, &xdb_ctx); + ASSERT(!local_irq_is_enabled()); + } + } + + console_end_sync(); + watchdog_enable(); + atomic_inc(&xendbg_running); + + local_irq_restore(flags); + + return 0; +} + +static int +initialize_xendbg(void) +{ + if (!strcmp(opt_cdb, "none")) + return 0; + xdb_ctx.serhnd = serial_parse_handle(opt_cdb); + if (xdb_ctx.serhnd == -1) + panic("Can''t parse %s as CDB serial info.\n", opt_cdb); + + /* Acknowledge any spurious GDB packets. */ + xendbg_put_char(''+'', &xdb_ctx); + + printk("Xendbg initialised.\n"); + return 0; +} + +__initcall(initialize_xendbg); + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -r 45fdc28bd5e0 -r b1068ef4ffb0 xen/include/xen/debugger.h --- /dev/null Thu Jan 1 00:00:00 1970 +0000 +++ b/xen/include/xen/debugger.h Tue Jan 10 15:51:03 2006 +0900 @@ -0,0 +1,18 @@ +#ifndef __XEN_DEBUGGER_H__ +#define __XEN_DEBUGGER_H__ + +struct xendbg_context { + int serhnd; + u8 reply_csum; + int currently_attached:1; +}; + +/* interface to arch specific routines */ +int xendbg_send_reply(const char *buf, struct xendbg_context *ctx); + +/* arch specific routines */ +unsigned int xendbg_arch_copy_from_user(void *dest, const void *src, unsigned len); +int xendbg_arch_handle_register_read_command(struct cpu_user_regs *regs, struct xendbg_context *ctx); +int xendbg_arch_handle_register_get_command(unsigned long regnum, struct cpu_user_regs *regs, struct xendbg_context *ctx); + +#endif /* __XEN_DEBUGGER_H__ */ -- yamahata _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
cdb for xen/ia64. stolen from kgdb the routine which gets register value. this includes a bug fix of kgdb/ia64. Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp> diff -r b1068ef4ffb0 -r 0722cc73a7a2 xen/arch/ia64/Makefile --- a/xen/arch/ia64/Makefile Tue Jan 10 15:51:03 2006 +0900 +++ b/xen/arch/ia64/Makefile Tue Jan 10 15:59:11 2006 +0900 @@ -22,6 +22,10 @@ memset.o strlen.o memcpy_mck.o \ __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \ __divdi3.o __udivdi3.o __moddi3.o __umoddi3.o + +ifeq ($(crash_debug),y) +OBJS += cdb.o +endif # xen stack unwinder # unwind_decoder.c is included in unwind.c diff -r b1068ef4ffb0 -r 0722cc73a7a2 xen/arch/ia64/vmx/vmx_process.c --- a/xen/arch/ia64/vmx/vmx_process.c Tue Jan 10 15:51:03 2006 +0900 +++ b/xen/arch/ia64/vmx/vmx_process.c Tue Jan 10 15:59:11 2006 +0900 @@ -41,6 +41,7 @@ #include <asm/regionreg.h> #include <asm/privop.h> #include <asm/ia64_int.h> +#include <asm/debugger.h> //#include <asm/hpsim_ssc.h> #include <asm/dom_fw.h> #include <asm/vmx_vcpu.h> @@ -107,6 +108,13 @@ if (running_on_sim) do_ssc(vcpu_get_gr_nat(current,36), regs); else do_ssc(vcpu_get_gr_nat(current,36), regs); } +#endif +#ifdef CRASH_DEBUG + if ((iim == 0 || iim == CDB_BREAK_NUM) && !user_mode(regs)) { + if (iim == 0) + show_registers(regs); + debugger_trap_fatal(0 /* don''t care */, regs); + } else #endif if (iim == d->arch.breakimm) { struct ia64_pal_retval y; diff -r b1068ef4ffb0 -r 0722cc73a7a2 xen/arch/ia64/xen/hyperprivop.S --- a/xen/arch/ia64/xen/hyperprivop.S Tue Jan 10 15:51:03 2006 +0900 +++ b/xen/arch/ia64/xen/hyperprivop.S Tue Jan 10 15:59:11 2006 +0900 @@ -12,6 +12,7 @@ #include <asm/offsets.h> #include <asm/processor.h> #include <asm/system.h> +#include <asm/debugger.h> #include <public/arch-ia64.h> diff -r b1068ef4ffb0 -r 0722cc73a7a2 xen/arch/ia64/xen/ivt.S --- a/xen/arch/ia64/xen/ivt.S Tue Jan 10 15:51:03 2006 +0900 +++ b/xen/arch/ia64/xen/ivt.S Tue Jan 10 15:59:11 2006 +0900 @@ -15,6 +15,7 @@ #define sys_call_table 0 #define sys_ni_syscall 0 #include <asm/vhpt.h> +#include <asm/debugger.h> #endif /* * arch/ia64/kernel/ivt.S diff -r b1068ef4ffb0 -r 0722cc73a7a2 xen/arch/ia64/xen/process.c --- a/xen/arch/ia64/xen/process.c Tue Jan 10 15:51:03 2006 +0900 +++ b/xen/arch/ia64/xen/process.c Tue Jan 10 15:59:11 2006 +0900 @@ -31,6 +31,7 @@ #include <asm/dom_fw.h> #include "hpsim_ssc.h" #include <xen/multicall.h> +#include <asm/debugger.h> extern unsigned long vcpu_get_itir_on_fault(struct vcpu *, UINT64); extern void die_if_kernel(char *str, struct pt_regs *regs, long err); @@ -662,7 +663,7 @@ ia64_handle_break (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long iim) { struct domain *d = (struct domain *) current->domain; - struct vcpu *v = (struct domain *) current; + struct vcpu *v = current; extern unsigned long running_on_sim; if (first_break) { @@ -673,7 +674,14 @@ if (iim == 0x80001 || iim == 0x80002) { //FIXME: don''t hardcode constant if (running_on_sim) do_ssc(vcpu_get_gr(current,36), regs); else do_ssc(vcpu_get_gr(current,36), regs); - } + } +#ifdef CRASH_DEBUG + else if ((iim == 0 || iim == CDB_BREAK_NUM) && !user_mode(regs)) { + if (iim == 0) + show_registers(regs); + debugger_trap_fatal(0 /* don''t care */, regs); + } +#endif else if (iim == d->arch.breakimm) { /* by default, do not continue */ v->arch.hypercall_continuation = 0; diff -r b1068ef4ffb0 -r 0722cc73a7a2 xen/arch/ia64/xen/xenmisc.c --- a/xen/arch/ia64/xen/xenmisc.c Tue Jan 10 15:51:03 2006 +0900 +++ b/xen/arch/ia64/xen/xenmisc.c Tue Jan 10 15:59:11 2006 +0900 @@ -18,6 +18,7 @@ #include <xen/softirq.h> #include <public/sched.h> #include <asm/vhpt.h> +#include <asm/debugger.h> efi_memory_desc_t ia64_efi_io_md; EXPORT_SYMBOL(ia64_efi_io_md); @@ -357,6 +358,11 @@ va_end(args); printf(buf); if (regs) show_registers(regs); + if (regs) { + debugger_trap_fatal(0 /* don''t care */, regs); + } else { + debugger_trap_immediate(); + } domain_pause_by_systemcontroller(current->domain); v->domain->shutdown_code = SHUTDOWN_crash; set_bit(_DOMF_shutdown, v->domain->domain_flags); diff -r b1068ef4ffb0 -r 0722cc73a7a2 xen/include/asm-ia64/debugger.h --- a/xen/include/asm-ia64/debugger.h Tue Jan 10 15:51:03 2006 +0900 +++ b/xen/include/asm-ia64/debugger.h Tue Jan 10 15:59:11 2006 +0900 @@ -24,6 +24,54 @@ #include <xen/softirq.h> +// this number is an arbitary number which is not used for any other purpose +// __builtin_trap(), FORCE_CRASH() 0x0 +// ski 0x80001, 0x80002 +// kdb 0x80100, 0x80101 +// kprobe 0x80200, jprobe 0x80300 +// kgdb 0x6665 +// gdb 0x99998 (#define IA64_BREAKPOINT 0x00003333300LL) + +// cdb should handle 0 and CDB_BREAK_NUM. +#define CDB_BREAK_NUM 0x80800 + + +#ifndef __ASSEMBLY__ + +#include <xen/debugger.h> + +// NOTE: on xen struct pt_regs = struct cpu_user_regs +// see include/asm-ia64/linux-xen/asm/ptrace.h +#ifdef CRASH_DEBUG +// crash_debug=y + +/* The main trap handlers use these helper macros which include early bail. */ +static inline int debugger_trap_entry( + unsigned int vector, struct cpu_user_regs *regs) +{ + return 0; +} + +extern int __trap_to_cdb(struct cpu_user_regs *r); +static inline int debugger_trap_fatal( + unsigned int vector, struct cpu_user_regs *regs) +{ + (void)__trap_to_cdb(regs); + return 0; +} + +#define ____debugger_trap_immediate(b) __asm__ __volatile__ ("break.m "#b"\n") +#define __debugger_trap_immediate(b) ____debugger_trap_immediate(b) +#define debugger_trap_immediate() __debugger_trap_immediate(CDB_BREAK_NUM) + +//XXX temporal work around +#ifndef CONFIG_SMP +#define smp_send_stop() /* nothing */ +#endif + +#elif defined DOMU_DEBUG +// domu_debug=y +#warning "domu_debug is not implemented yet." /* The main trap handlers use these helper macros which include early bail. */ static inline int debugger_trap_entry( unsigned int vector, struct cpu_user_regs *regs) @@ -37,6 +85,23 @@ return 0; } -#define debugger_trap_immediate() do {} while(0) +#define debugger_trap_immediate() ((void)0) +#else +/* The main trap handlers use these helper macros which include early bail. */ +static inline int debugger_trap_entry( + unsigned int vector, struct cpu_user_regs *regs) +{ + return 0; +} + +static inline int debugger_trap_fatal( + unsigned int vector, struct cpu_user_regs *regs) +{ + return 0; +} + +#define debugger_trap_immediate() ((void)0) +#endif +#endif // __ASSEMBLLY__ #endif /* __ASM_DEBUGGER_H__ */ diff -r b1068ef4ffb0 -r 0722cc73a7a2 xen/arch/ia64/xen/cdb.c --- /dev/null Thu Jan 1 00:00:00 1970 +0000 +++ b/xen/arch/ia64/xen/cdb.c Tue Jan 10 15:59:11 2006 +0900 @@ -0,0 +1,652 @@ +/* + * ia64-specific cdb routines + * cdb xen/ia64 by Isaku Yamahta <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * some routines are stolen from kgdb/ia64. + */ +/* + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + +/* + * Copyright (C) 2000-2001 VERITAS Software Corporation. + */ +/* + * Contributor: Lake Stevens Instrument Division$ + * Written by: Glenn Engel $ + * Updated by: Amit Kale<akale@veritas.com> + * Modified for 386 by Jim Kingdon, Cygnus Support. + * Origianl kgdb, compatibility with 2.1.xx kernel by David Grothe <dave@gcom.com> + * + */ + + +#include <xen/lib.h> +#include <asm/byteorder.h> +#include <asm/debugger.h> +#include <asm/uaccess.h> + +#define USE_UNWIND + +#ifdef USE_UNWIND +#include <asm/unwind.h> +#endif + +/* Printk isn''t particularly safe just after we''ve trapped to the + debugger. so avoid it. */ +#define dbg_printk(...) +//#define dbg_printk(...) printk(__VA_ARGS__) + +/* Like copy_from_user, but safe to call with interrupts disabled. + Trust me, and don''t look behind the curtain. */ +unsigned +xendbg_arch_copy_from_user(void *dest, const void *src, unsigned len) +{ + int val; + __asm__ __volatile__( + "cmp4.eq p6, p0 = r0, %1\n" + "(p6) br.cond.dptk 2f\n" + "[1:]\n" + ".xdata4 \"__ex_table\", 99f-., 2f-.;\n" + "[99:] ld1 %0 = [%3], 1\n" + ";;\n" + ".xdata4 \"__ex_table\", 99f-., 2f-.;\n" + "[99:] st1 [%2] = %0, 1\n" + "adds %1 = -1, %1\n" + ";;\n" + "cmp4.eq p0, p6 = r0, %1\n" + "(p6) br.cond.dptk 1b\n" + "[2:]\n" + : "=r"(val), "=r"(len), "=r"(dest), "=r"(src) + : "1"(len), "2"(dest), "3"(src) + : "memory", "p6"); + return len; +} + +int +xendbg_arch_handle_register_read_command(struct cpu_user_regs *regs, struct xendbg_context *ctx) +{ + return xendbg_send_reply("", ctx); +} + +#define NUM_REGS 590 +#define REGISTER_BYTES (NUM_REGS*8+128*8) +#define REGISTER_BYTE(N) (((N) * 8) + ((N) <= IA64_FR0_REGNUM ? 0 : 8 * (((N) > IA64_FR127_REGNUM) ? 128 : (N) - IA64_FR0_REGNUM))) +#define REGISTER_SIZE(N) (((N) >= IA64_FR0_REGNUM && (N) <= IA64_FR127_REGNUM) ? 16 : 8) + +#define IA64_GR0_REGNUM 0 +#define IA64_FR0_REGNUM 128 +#define IA64_FR127_REGNUM (IA64_FR0_REGNUM+127) +#define IA64_PR0_REGNUM 256 +#define IA64_BR0_REGNUM 320 +#define IA64_VFP_REGNUM 328 +#define IA64_PR_REGNUM 330 +#define IA64_IP_REGNUM 331 +#define IA64_PSR_REGNUM 332 +#define IA64_CFM_REGNUM 333 +#define IA64_AR0_REGNUM 334 +#define IA64_NAT0_REGNUM 462 +#define IA64_NAT31_REGNUM (IA64_NAT0_REGNUM+31) +#define IA64_NAT32_REGNUM (IA64_NAT0_REGNUM+32) +#define IA64_RSC_REGNUM (IA64_AR0_REGNUM+16) +#define IA64_BSP_REGNUM (IA64_AR0_REGNUM+17) +#define IA64_BSPSTORE_REGNUM (IA64_AR0_REGNUM+18) +#define IA64_RNAT_REGNUM (IA64_AR0_REGNUM+19) +#define IA64_FCR_REGNUM (IA64_AR0_REGNUM+21) +#define IA64_EFLAG_REGNUM (IA64_AR0_REGNUM+24) +#define IA64_CSD_REGNUM (IA64_AR0_REGNUM+25) +#define IA64_SSD_REGNUM (IA64_AR0_REGNUM+26) +#define IA64_CFLG_REGNUM (IA64_AR0_REGNUM+27) +#define IA64_FSR_REGNUM (IA64_AR0_REGNUM+28) +#define IA64_FIR_REGNUM (IA64_AR0_REGNUM+29) +#define IA64_FDR_REGNUM (IA64_AR0_REGNUM+30) +#define IA64_CCV_REGNUM (IA64_AR0_REGNUM+32) +#define IA64_UNAT_REGNUM (IA64_AR0_REGNUM+36) +#define IA64_FPSR_REGNUM (IA64_AR0_REGNUM+40) +#define IA64_ITC_REGNUM (IA64_AR0_REGNUM+44) +#define IA64_PFS_REGNUM (IA64_AR0_REGNUM+64) +#define IA64_LC_REGNUM (IA64_AR0_REGNUM+65) +#define IA64_EC_REGNUM (IA64_AR0_REGNUM+66) + +#ifndef USE_UNWIND +struct regs_to_cpu_user_resgs_index { + unsigned int reg; + unsigned int ptregoff; +}; + +#define ptoff(V) ((unsigned int)&((struct cpu_user_regs*)0x0)->V) + +// gr +static const struct regs_to_cpu_user_resgs_index +gr_reg_to_cpu_user_regs_index[] = { + {IA64_GR0_REGNUM + 8, ptoff(r8)}, + {IA64_GR0_REGNUM + 9, ptoff(r9)}, + {IA64_GR0_REGNUM + 10, ptoff(r10)}, + {IA64_GR0_REGNUM + 11, ptoff(r11)}, + {IA64_GR0_REGNUM + 1, ptoff(r1)}, + {IA64_GR0_REGNUM + 12, ptoff(r12)}, + {IA64_GR0_REGNUM + 13, ptoff(r13)}, + {IA64_GR0_REGNUM + 15, ptoff(r15)}, + + {IA64_GR0_REGNUM + 14, ptoff(r14)}, + {IA64_GR0_REGNUM + 2, ptoff(r2)}, + {IA64_GR0_REGNUM + 3, ptoff(r3)}, + {IA64_GR0_REGNUM + 16, ptoff(r16)}, + {IA64_GR0_REGNUM + 17, ptoff(r17)}, + {IA64_GR0_REGNUM + 18, ptoff(r18)}, + {IA64_GR0_REGNUM + 19, ptoff(r19)}, + {IA64_GR0_REGNUM + 20, ptoff(r20)}, + {IA64_GR0_REGNUM + 21, ptoff(r21)}, + {IA64_GR0_REGNUM + 22, ptoff(r22)}, + {IA64_GR0_REGNUM + 23, ptoff(r23)}, + {IA64_GR0_REGNUM + 24, ptoff(r24)}, + {IA64_GR0_REGNUM + 25, ptoff(r25)}, + {IA64_GR0_REGNUM + 26, ptoff(r26)}, + {IA64_GR0_REGNUM + 27, ptoff(r27)}, + {IA64_GR0_REGNUM + 28, ptoff(r28)}, + {IA64_GR0_REGNUM + 29, ptoff(r29)}, + {IA64_GR0_REGNUM + 30, ptoff(r30)}, + {IA64_GR0_REGNUM + 31, ptoff(r31)}, + + {IA64_GR0_REGNUM + 4, ptoff(r4)}, + {IA64_GR0_REGNUM + 5, ptoff(r5)}, + {IA64_GR0_REGNUM + 6, ptoff(r6)}, + {IA64_GR0_REGNUM + 7, ptoff(r7)}, +}; +static const int gr_reg_to_cpu_user_regs_index_max + sizeof(gr_reg_to_cpu_user_regs_index) / + sizeof(gr_reg_to_cpu_user_regs_index[0]); + +// br +static const struct regs_to_cpu_user_resgs_index +br_reg_to_cpu_user_regs_index[] = { + {IA64_BR0_REGNUM + 0, ptoff(b0)}, + {IA64_BR0_REGNUM + 6, ptoff(b6)}, + {IA64_BR0_REGNUM + 7, ptoff(b7)}, +}; +static const int br_reg_to_cpu_user_regs_index_max + sizeof(br_reg_to_cpu_user_regs_index) / + sizeof(br_reg_to_cpu_user_regs_index[0]); + +// f +static const struct regs_to_cpu_user_resgs_index +fr_reg_to_cpu_user_regs_index[] = { + {IA64_FR0_REGNUM + 6, ptoff(f6)}, + {IA64_FR0_REGNUM + 7, ptoff(f7)}, + {IA64_FR0_REGNUM + 8, ptoff(f8)}, + {IA64_FR0_REGNUM + 9, ptoff(f9)}, + {IA64_FR0_REGNUM + 10, ptoff(f10)}, + {IA64_FR0_REGNUM + 11, ptoff(f11)}, +}; +static const int fr_reg_to_cpu_user_regs_index_max + sizeof(fr_reg_to_cpu_user_regs_index) / + sizeof(fr_reg_to_cpu_user_regs_index[0]); + + +int +xendbg_arch_handle_register_get_command(unsigned long regnum, struct cpu_user_regs *regs, struct xendbg_context *ctx) +{ + unsigned long reg = IA64_IP_REGNUM; + char buf[9]; + int i; + + dbg_printk("Register read regnum = 0x%lx\n", regnum); + if (IA64_GR0_REGNUM <= regnum && regnum <= IA64_GR0_REGNUM + 31) { + for (i = 0; i < gr_reg_to_cpu_user_regs_index_max; i++) { + if (gr_reg_to_cpu_user_regs_index[i].reg == regnum) { + reg = *(unsigned long*)(((char*)regs) + gr_reg_to_cpu_user_regs_index[i].ptregoff); + break; + } + } + if (i == gr_reg_to_cpu_user_regs_index_max) { + goto out_err; + } + } else if (IA64_BR0_REGNUM <= regnum && regnum <= IA64_BR0_REGNUM + 7) { + for (i = 0; i < br_reg_to_cpu_user_regs_index_max; i++) { + if (br_reg_to_cpu_user_regs_index[i].reg == regnum) { + reg = *(unsigned long*)(((char*)regs) + br_reg_to_cpu_user_regs_index[i].ptregoff); + break; + } + } + if (i == br_reg_to_cpu_user_regs_index_max) { + goto out_err; + } + } else if (IA64_FR0_REGNUM + 6 <= regnum && regnum <= IA64_FR0_REGNUM + 11) { + for (i = 0; i < fr_reg_to_cpu_user_regs_index_max; i++) { + if (fr_reg_to_cpu_user_regs_index[i].reg == regnum) { + reg = *(unsigned long*)(((char*)regs) + fr_reg_to_cpu_user_regs_index[i].ptregoff); + break; + } + } + if (i == fr_reg_to_cpu_user_regs_index_max) { + goto out_err; + } + } else if (regnum == IA64_CSD_REGNUM) { + reg = regs->ar_csd; + } else if (regnum == IA64_SSD_REGNUM) { + reg = regs->ar_ssd; + } else if (regnum == IA64_PSR_REGNUM) { + reg = regs->cr_ipsr; + } else if (regnum == IA64_IP_REGNUM) { + reg = regs->cr_iip; + } else if (regnum == IA64_CFM_REGNUM) { + reg = regs->cr_ifs; + } else if (regnum == IA64_UNAT_REGNUM) { + reg = regs->ar_unat; + } else if (regnum == IA64_PFS_REGNUM) { + reg = regs->ar_pfs; + } else if (regnum == IA64_RSC_REGNUM) { + reg = regs->ar_rsc; + } else if (regnum == IA64_RNAT_REGNUM) { + reg = regs->ar_rnat; + } else if (regnum == IA64_BSPSTORE_REGNUM) { + reg = regs->ar_bspstore; + } else if (regnum == IA64_PR_REGNUM) { + reg = regs->pr; + } else if (regnum == IA64_FPSR_REGNUM) { + reg = regs->ar_fpsr; + } else if (regnum == IA64_CCV_REGNUM) { + reg = regs->ar_ccv; + } else { + // emul_unat, rfi_pfs + goto out_err; + } + + dbg_printk("Register read regnum = 0x%lx, val = 0x%lx\n", regnum, reg); + sprintf(buf, "%.08lx", swab64(reg)); +out: + return xendbg_send_reply(buf, ctx); + +out_err: + dbg_printk("Register read unsupported regnum = 0x%lx\n", regnum); + sprintf(buf, "%s", "x"); + goto out; +} +#else + +#define ptoff(V) ((unsigned int) &((struct pt_regs *)0x0)->V) +struct reg_to_ptreg_index { + unsigned int reg; + unsigned int ptregoff; +}; +struct reg_to_ptreg_index gr_reg_to_ptreg_index[] = { + {IA64_GR0_REGNUM + 8, ptoff(r8)}, + {IA64_GR0_REGNUM + 9, ptoff(r9)}, + {IA64_GR0_REGNUM + 10, ptoff(r10)}, + {IA64_GR0_REGNUM + 11, ptoff(r11)}, + {IA64_GR0_REGNUM + 1, ptoff(r1)}, + {IA64_GR0_REGNUM + 12, ptoff(r12)}, + {IA64_GR0_REGNUM + 13, ptoff(r13)}, + {IA64_GR0_REGNUM + 14, ptoff(r14)}, + {IA64_GR0_REGNUM + 15, ptoff(r15)}, + {IA64_GR0_REGNUM + 2, ptoff(r2)}, + {IA64_GR0_REGNUM + 3, ptoff(r3)}, +}; + +struct reg_to_ptreg_index br_reg_to_ptreg_index[] = { + {IA64_BR0_REGNUM, ptoff(b0)}, + {IA64_BR0_REGNUM + 6, ptoff(b6)}, + {IA64_BR0_REGNUM + 7, ptoff(b7)}, +}; + +extern atomic_t cpu_doing_single_step; + +#ifndef XEN +void kgdb_get_reg(char *outbuffer, int regnum, struct unw_frame_info *info, + struct pt_regs *ptregs) +#else +static int +kgdb_get_reg(int regnum, struct unw_frame_info *info, + struct cpu_user_regs* ptregs, + unsigned long* __reg, struct pt_fpreg* __freg) +#endif +{ + unsigned long reg, size = 0, *mem = ® + char nat; +#ifndef XEN + struct ia64_fpreg freg; +#else + struct pt_fpreg freg; +#endif + int i; + + if ((regnum >= IA64_GR0_REGNUM && regnum <= (IA64_GR0_REGNUM + 1)) || + (regnum >= (IA64_GR0_REGNUM + 4) && regnum <= (IA64_GR0_REGNUM + 7)) + || (regnum >= (IA64_GR0_REGNUM + 16) + && regnum <= (IA64_GR0_REGNUM + 31))) { + unw_access_gr(info, regnum - IA64_GR0_REGNUM, ®, &nat, 0); + size = sizeof(reg); + } else + if ((regnum >= (IA64_GR0_REGNUM + 2) + && regnum <= (IA64_GR0_REGNUM + 3)) + || (regnum >= (IA64_GR0_REGNUM + 8) + && regnum <= (IA64_GR0_REGNUM + 15))) { + if (ptregs) { + for (i = 0; i < (sizeof(gr_reg_to_ptreg_index) / + sizeof(gr_reg_to_ptreg_index[0])); i++) + if (gr_reg_to_ptreg_index[i].reg == regnum) { + reg = *((unsigned long *) + (((void *)ptregs) + + gr_reg_to_ptreg_index[i].ptregoff)); + break; + } + } else + unw_access_gr(info, regnum - IA64_GR0_REGNUM, ®, + &nat, 0); + size = sizeof(reg); + } else if (regnum >= IA64_BR0_REGNUM && regnum <= (IA64_BR0_REGNUM + 7)) + switch (regnum) { + case IA64_BR0_REGNUM: + case IA64_BR0_REGNUM + 6: + case IA64_BR0_REGNUM + 7: + if (ptregs) { + for (i = 0; i < (sizeof(br_reg_to_ptreg_index) / + sizeof(br_reg_to_ptreg_index + [0])); i++) + if (br_reg_to_ptreg_index[i].reg =+ regnum) { + reg = *((unsigned long *) + (((void *)ptregs) + + br_reg_to_ptreg_index + [i].ptregoff)); + break; + } + } else + unw_access_br(info, regnum - IA64_BR0_REGNUM, + ®, 0); + size = sizeof(reg); + break; + case IA64_BR0_REGNUM + 1: + case IA64_BR0_REGNUM + 2: + case IA64_BR0_REGNUM + 3: + case IA64_BR0_REGNUM + 4: + case IA64_BR0_REGNUM + 5: + unw_access_br(info, regnum - IA64_BR0_REGNUM, ®, 0); + size = sizeof(reg); + break; + } else if (regnum >= IA64_FR0_REGNUM + && regnum <= (IA64_FR0_REGNUM + 127)) + switch (regnum) { + case IA64_FR0_REGNUM + 6: + case IA64_FR0_REGNUM + 7: + case IA64_FR0_REGNUM + 8: + case IA64_FR0_REGNUM + 9: + case IA64_FR0_REGNUM + 10: + case IA64_FR0_REGNUM + 11: + case IA64_FR0_REGNUM + 12: + if (!ptregs) +#ifndef XEN + unw_access_fr(info, regnum - IA64_FR0_REGNUM, + &freg, 0); +#else + //XXX struct ia64_fpreg and struct pt_fpreg are same. + unw_access_fr(info, regnum - IA64_FR0_REGNUM, + (struct ia64_fpreg*)&freg, 0); +#endif + else { + freg + *(&ptregs->f6 + + (regnum - (IA64_FR0_REGNUM + 6))); + } + size = sizeof(freg); + mem = (unsigned long *)&freg; + break; + default: +#ifndef XEN + unw_access_fr(info, regnum - IA64_FR0_REGNUM, &freg, 0); +#else + //XXX struct ia64_fpreg and struct pt_fpreg are same. + unw_access_fr(info, regnum - IA64_FR0_REGNUM, (struct ia64_fpreg*)&freg, 0); +#endif + break; + } else if (regnum == IA64_IP_REGNUM) { + if (!ptregs) + unw_get_ip(info, ®); + else + reg = ptregs->cr_iip; + size = sizeof(reg); + } else if (regnum == IA64_CFM_REGNUM) { + if (!ptregs) + unw_get_cfm(info, ®); + else + reg = ptregs->cr_ifs; + size = sizeof(reg); + } else if (regnum == IA64_PSR_REGNUM) { +#ifndef XEN + if (!ptregs && kgdb_usethread) + ptregs = (struct pt_regs *) + ((unsigned long)kgdb_usethread + IA64_STK_OFFSET) - + 1; +#endif + if (ptregs) + reg = ptregs->cr_ipsr; + size = sizeof(reg); + } else if (regnum == IA64_PR_REGNUM) { + if (ptregs) + reg = ptregs->pr; + else + unw_access_pr(info, ®, 0); + size = sizeof(reg); + } else if (regnum == IA64_BSP_REGNUM) { + unw_get_bsp(info, ®); + size = sizeof(reg); + } else if (regnum >= IA64_AR0_REGNUM && regnum <= IA64_EC_REGNUM) + switch (regnum) { + case IA64_CSD_REGNUM: + if (ptregs) + reg = ptregs->ar_csd; + else + unw_access_ar(info, UNW_AR_CSD, ®, 0); + size = sizeof(reg); + break; + case IA64_SSD_REGNUM: + if (ptregs) + reg = ptregs->ar_ssd; + else + unw_access_ar(info, UNW_AR_SSD, ®, 0); + size = sizeof(reg); + break; + case IA64_UNAT_REGNUM: + if (ptregs) + reg = ptregs->ar_unat; + else + unw_access_ar(info, UNW_AR_UNAT, ®, 0); + size = sizeof(reg); + break; + case IA64_RNAT_REGNUM: + unw_access_ar(info, UNW_AR_RNAT, ®, 0); + size = sizeof(reg); + break; + case IA64_BSPSTORE_REGNUM: + unw_access_ar(info, UNW_AR_BSPSTORE, ®, 0); + size = sizeof(reg); + break; + case IA64_PFS_REGNUM: + unw_access_ar(info, UNW_AR_PFS, ®, 0); + size = sizeof(reg); + break; + case IA64_LC_REGNUM: + unw_access_ar(info, UNW_AR_LC, ®, 0); + size = sizeof(reg); + break; + case IA64_EC_REGNUM: + unw_access_ar(info, UNW_AR_EC, ®, 0); + size = sizeof(reg); + break; + case IA64_FPSR_REGNUM: + if (ptregs) + reg = ptregs->ar_fpsr; + else + unw_access_ar(info, UNW_AR_FPSR, ®, 0); + size = sizeof(reg); + break; + case IA64_RSC_REGNUM: + if (ptregs) + reg = ptregs->ar_rsc; + else + unw_access_ar(info, UNW_AR_RNAT, ®, 0); + size = sizeof(reg); + break; + case IA64_CCV_REGNUM: + unw_access_ar(info, UNW_AR_CCV, ®, 0); + size = sizeof(reg); + break; + } + +#ifndef XEN + if (size) { + kgdb_mem2hex((char *)mem, outbuffer, size); + outbuffer[size * 2] = 0; + } else + strcpy(outbuffer, "E0"); + + return; +#else + if (size) { + if (size == sizeof(reg)) { + *__reg = reg; + } else { + BUG_ON(size != sizeof(freg)); + *__freg = freg; + } + return 0; + } + + return -1; +#endif +} + + +#ifndef XEN +static int inline kgdb_get_blocked_state(struct task_struct *p, + struct unw_frame_info *unw) +#else +static int +kgdb_get_blocked_state(struct vcpu *p, + struct cpu_user_regs *regs, + struct unw_frame_info *unw) +#endif +{ + unsigned long ip; + int count = 0; + +#ifndef XEN + unw_init_from_blocked_task(unw, p); +#endif + ip = 0UL; + do { + if (unw_unwind(unw) < 0) + return -1; + unw_get_ip(unw, &ip); +#ifndef XEN + if (!in_sched_functions(ip)) + break; +#else + dbg_printk("ip 0x%lx cr_iip 0x%lx\n", ip, regs->cr_iip); + if (ip == regs->cr_iip) + break; +#endif + } while (count++ < 16); + + if (!ip) + return -1; + else + return 0; +} + +struct xendbg_callback_arg +{ + struct cpu_user_regs* regs; + unsigned long regnum; + unsigned long* reg; + struct pt_fpreg* freg; + + int error; + // 1: not supported + // 0: success + // -1: failure +}; + +static void +xendbg_get_reg_callback(struct unw_frame_info* info, void* __arg) +{ + struct xendbg_callback_arg* arg = (struct xendbg_callback_arg*)__arg; + + if (kgdb_get_blocked_state(current, arg->regs, info) < 0) { + dbg_printk("%s: kgdb_get_blocked_state failed\n", __func__); + arg->error = -1; + return; + } + if (kgdb_get_reg(arg->regnum, info, arg->regs, arg->reg, arg->freg) < 0) { + dbg_printk("%s: kgdb_get_reg failed\n", __func__); + arg->error = 1; + return; + } + arg->error = 0; + return; +} + +int +xendbg_arch_handle_register_get_command(unsigned long regnum, + struct cpu_user_regs *regs, + struct xendbg_context *ctx) +{ + struct xendbg_callback_arg arg; + unsigned long reg; + struct pt_fpreg freg; + char buf[16 * 2 + 1]; + + if (regnum >= NUM_REGS) { + dbg_printk("%s: regnum %ld\n", __func__, regnum); + goto out_err; + } + + arg.regs = regs; + arg.regnum = regnum; + arg.reg = ® + arg.freg = &freg; + arg.error = 0; + unw_init_running(&xendbg_get_reg_callback, (void*)&arg); + if (arg.error < 0) { + dbg_printk("%s: xendbg_get_reg_callback failed\n", __func__); + goto out_err; + } + + if (arg.error > 0) { + // notify gdb that this register is not supported. + // see fetch_register_using_p() in gdb/remote.c. + sprintf(buf, "%s", "x"); + } else if (IA64_FR0_REGNUM <= regnum && regnum <= IA64_FR0_REGNUM + 127) { + sprintf(buf, "%.016lx", swab64(freg.u.bits[0])); + sprintf(buf + 16, "%.016lx", swab64(freg.u.bits[1])); + } else { + sprintf(buf, "%.016lx", swab64(reg)); + } +out: + return xendbg_send_reply(buf, ctx); + +out_err: + dbg_printk("Register read unsupported regnum = 0x%lx\n", regnum); + sprintf(buf, "%s", "E0"); + goto out; +} +#endif + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ -- yamahata _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Hollis Blanchard
2006-Jan-10 14:32 UTC
Re: [Xen-devel] [PATCH] cdb: split cdb into arch independet/dependet part
On Jan 10, 2006, at 1:31 AM, Isaku Yamahata wrote:> split cdb into arch independent/dependet part.What does "cdb" mean? Perhaps this is a good opportunity to rename the file to something like "gdbstub". Within function names, I am ok with "xendbg", but would again prefer "gdb". I''ve done something similar for the PowerPC port (see http://xenbits.xensource.com/ext/xenppc-unstable.hg?cmd=file; filenode=e5b74ffbc35667adbe0fc2cf263bdae46d90e3ed;file=xen/common/ gdbstub.c). I don''t claim that code is ideal, but it''s working enough to let me focus on other things. I have a few requests for your arch-neutral code...> +int > +__trap_to_cdb(struct cpu_user_regs *regs)Please have this take an extra argument. We can make it an opaque "cookie" if necessary. On PowerPC, we have more than one exception handler wired up to drop into GDB. The same thing is probably useful on other architectures as well, e.g. drop into GDB if somebody branches to 0 in the hypervisor. This extra argument indicates the source of the exception, and is translated by an arch-specific hook into a signal number. This allows us to provide signals like SIGSEGV to indicate bad memory references. Please provide arch-specific entry() and exit() hooks. On PowerPC, we save and restore the CPU timers in these. int __trap_to_cdb(struct cpu_user_regs *regs, ulong cookie) { arch_xendbg_entry(regs); signal = arch_xendbg_signal(regs, cookie); ... arch_xendbg_exit(regs); } I see that some commands, such as ''s'', ''G'', and ''M'' are unimplemented. Instead of rejecting them in the arch-neutral section, please have that done in the arch-specific section. For example, we have implemented all of those commands in PPC code.> + retry = xendbg_arch_handle_register_get_command(addr, regs, ctx);I hope we can name these something shorter...> +__initcall(initialize_xendbg);I believe this should be an explicit call from architecture code. initcall is far too late for some early debugging, and only the architecture code knows when this call can be made. -- Hollis Blanchard IBM Linux Technology Center _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Isaku Yamahata
2006-Jan-11 08:56 UTC
Re: [Xen-devel] [PATCH] cdb: split cdb into arch independet/dependet part
On Tue, Jan 10, 2006 at 08:32:19AM -0600, Hollis Blanchard wrote:> What does "cdb" mean? Perhaps this is a good opportunity to rename the > file to something like "gdbstub". Within function names, I am ok with > "xendbg", but would again prefer "gdb".I just followed the original x86 way. If a kind of clean up patch is accepted, I am also ok with any prefix. PPC gdbstub has more functionality than x86, ia64. So if there is no objections, I will make a patch based on gdb stub in ppc repository using "gdb" prefix. -- yamahata _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Keir Fraser
2006-Jan-11 10:11 UTC
Re: [Xen-devel] [PATCH] cdb: split cdb into arch independet/dependet part
On 11 Jan 2006, at 08:56, Isaku Yamahata wrote:> I just followed the original x86 way. > If a kind of clean up patch is accepted, I am also ok with any prefix. > > PPC gdbstub has more functionality than x86, ia64. > So if there is no objections, I will make a patch based on gdb stub > in ppc repository using "gdb" prefix.Please do. -- Keir _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Isaku Yamahata
2006-Jan-13 11:28 UTC
Re: [Xen-devel] [PATCH] cdb: split cdb into arch independet/dependet part
Hi. attached the updated one. I tested only very roughly. Hollis, is this patch ok for ppc version? thanks. -- yamahata _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Hollis Blanchard
2006-Jan-13 15:46 UTC
Re: [Xen-devel] [PATCH] cdb: split cdb into arch independet/dependet part
On Jan 13, 2006, at 5:28 AM, Isaku Yamahata wrote:> > attached the updated one. I tested only very roughly. > Hollis, is this patch ok for ppc version?Thanks Isaku! This whole patch has whitespace issues though; please replace your tabs with 4 spaces.> + . = ALIGN(32); > + __gdbstub_text_start = . ; > + *(.gdbstub.text) > + __gdbstub_text_end = . ; > + . = ALIGN(32) ;...> +/* Append this to the declaration of any function needed to be used by > + * the gdb stub. Any functions marked with this will not be allowed > + * to have a breakpoint set in them. */ > +#define __gdbstub __attribute__((section(".gdbstub.text")))These make sense if we want to avoid setting a breakpoint in GDB stub code or code called by the GDB stub, such as serial output. However, these symbols aren''t currently used. (You probably inherited this from the PPC stub.) At least it''s worth a TODO comment, possibly in gdb_cmd_write_mem(): we shouldn''t be writing to memory between those two symbols.> +/* XXX move to some shared location... */ > +char > +hex2char(unsigned long x)With hex2char, char2hex, str2hex, str2ulong, I expect that they will be needed in the arch-specific gdb backends. Actually I guess they just need to be added to gdbstub.h; I''m not sure why I added that comment.> + for (ctx->in_bytes = 0; ctx->in_bytes < sizeof(ctx->in_buf); > ctx->in_bytes++) {Exceeds 80 chars.> +#ifdef CONFIG_GDB_NO_CSUM > + return 0; > +#else > + if (received_csum == csum) { > + return 0; > + } else { > + return -1; > + } > +#endifWhat is this about? As far as I know, the GDB protocol unconditionally requires the checksum.> + //XXX optimization to use best native load size...> + //XXX optimization to use best native store sizeI think it''s reasonable to leave it up to the arch code to decide what size access to use, so these comments could go.> + .signum = 1, > + > + .in_bytes = 0, > + > + .out_offset = 0,Blank lines.> + /* Try to make things a little more stable by disabling > + interrupts while we''re here. */ > + local_irq_save(flags);...> + local_irq_restore(flags);Shouldn''t we enter __trap_to_gdb with interrupts disabled already? That''s how it''s done on PPC, I believe x86 can choose in the IDT, and I''m sure IA64 can too? Hmm, actually, how does this interact with interrupt-driven ns16550? -- Hollis Blanchard IBM Linux Technology Center _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Keir Fraser
2006-Jan-13 16:20 UTC
Re: [Xen-devel] [PATCH] cdb: split cdb into arch independet/dependet part
On 13 Jan 2006, at 15:46, Hollis Blanchard wrote:>> + /* Try to make things a little more stable by disabling >> + interrupts while we''re here. */ >> + local_irq_save(flags); > ... >> + local_irq_restore(flags); > > Shouldn''t we enter __trap_to_gdb with interrupts disabled already? > That''s how it''s done on PPC, I believe x86 can choose in the IDT, and > I''m sure IA64 can too?That''s true if it''s a hardware-generated trap to debugger. Breakpoint exceptions, manual calls to trap into the debugger, etc all might enter the stub with ints enabled. So irqsave/restore is a reasonable safeguard.> Hmm, actually, how does this interact with interrupt-driven ns16550?The serial subsystem supports a synchronous polled mode of operation. You can put a COM port in polled mode by calling serial_start_sync(). -- Keir _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Isaku Yamahata
2006-Jan-14 01:53 UTC
Re: [Xen-devel] [PATCH] cdb: split cdb into arch independet/dependet part
Hi. Thanks for your review. I updated the patch following your comments except the interrupt-related related comment. I included your signed-off-by to the patch, is it ok? On Fri, Jan 13, 2006 at 09:46:04AM -0600, Hollis Blanchard wrote:> Thanks Isaku! This whole patch has whitespace issues though; please > replace your tabs with 4 spaces.untabified.> >+ . = ALIGN(32); > >+ __gdbstub_text_start = . ; > >+ *(.gdbstub.text) > >+ __gdbstub_text_end = . ; > >+ . = ALIGN(32) ; > ... > >+/* Append this to the declaration of any function needed to be used by > >+ * the gdb stub. Any functions marked with this will not be allowed > >+ * to have a breakpoint set in them. */ > >+#define __gdbstub __attribute__((section(".gdbstub.text"))) > > These make sense if we want to avoid setting a breakpoint in GDB stub > code or code called by the GDB stub, such as serial output. However, > these symbols aren''t currently used. (You probably inherited this from > the PPC stub.) At least it''s worth a TODO comment, possibly in > gdb_cmd_write_mem(): we shouldn''t be writing to memory between those > two symbols.added __gdbstub_text_start, __gdbstub_text_end declarations and a comment above gdb_cmd_write_mem()> >+/* XXX move to some shared location... */ > >+char > >+hex2char(unsigned long x) > > With hex2char, char2hex, str2hex, str2ulong, I expect that they will be > needed in the arch-specific gdb backends. Actually I guess they just > need to be added to gdbstub.h; I''m not sure why I added that comment.added protptypes to gdb.h and removed two XXX comments.> >+ for (ctx->in_bytes = 0; ctx->in_bytes < sizeof(ctx->in_buf); > >ctx->in_bytes++) { > Exceeds 80 chars.fixed.> >+#ifdef CONFIG_GDB_NO_CSUM > >+ return 0; > >+#else > >+ if (received_csum == csum) { > >+ return 0; > >+ } else { > >+ return -1; > >+ } > >+#endif > What is this about? As far as I know, the GDB protocol unconditionally > requires the checksum.removed.> >+ //XXX optimization to use best native load size > ... > >+ //XXX optimization to use best native store size > I think it''s reasonable to leave it up to the arch code to decide what > size access to use, so these comments could go.removed these comments.> >+ .signum = 1, > >+ > >+ .in_bytes = 0, > >+ > >+ .out_offset = 0, > > Blank lines.removed blank lines.> >+ /* Try to make things a little more stable by disabling > >+ interrupts while we''re here. */ > >+ local_irq_save(flags); > ... > >+ local_irq_restore(flags); > Shouldn''t we enter __trap_to_gdb with interrupts disabled already? > That''s how it''s done on PPC, I believe x86 can choose in the IDT, and > I''m sure IA64 can too?Left as it was. As Keir explained, it is a good safe guard. -- yamahata _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Keir Fraser
2006-Jan-14 09:07 UTC
Re: [Xen-devel] [PATCH] cdb: split cdb into arch independet/dependet part
On 14 Jan 2006, at 01:53, Isaku Yamahata wrote:>>> +/* Append this to the declaration of any function needed to be used >>> by >>> + * the gdb stub. Any functions marked with this will not be allowed >>> + * to have a breakpoint set in them. */ >>> +#define __gdbstub __attribute__((section(".gdbstub.text"))) >> >> These make sense if we want to avoid setting a breakpoint in GDB stub >> code or code called by the GDB stub, such as serial output. However, >> these symbols aren''t currently used. (You probably inherited this from >> the PPC stub.) At least it''s worth a TODO comment, possibly in >> gdb_cmd_write_mem(): we shouldn''t be writing to memory between those >> two symbols. > > added __gdbstub_text_start, __gdbstub_text_end declarations and > a comment above gdb_cmd_write_mem()Is this really worthwhile? The gdbstub will be using calling functions outside this range, so it''s not a comprehensive solution for disallowing breakpoints in gdb mode. For that I think you''d need to clear all breakpoints on entry to gdbstub and re-set them on exit. I''d prefer to avoid extra section directives unless they''re clearly useful. -- Keir _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Isaku Yamahata
2006-Jan-14 11:30 UTC
Re: [Xen-devel] [PATCH] cdb: split cdb into arch independet/dependet part
On Sat, Jan 14, 2006 at 09:07:15AM +0000, Keir Fraser wrote:> Is this really worthwhile? The gdbstub will be using calling functions > outside this range, so it''s not a comprehensive solution for > disallowing breakpoints in gdb mode. For that I think you''d need to > clear all breakpoints on entry to gdbstub and re-set them on exit. > > I''d prefer to avoid extra section directives unless they''re clearly > useful.The current gdbstub doesn''t support breakpoints anyway, and it is beyond my purpose to implement such functionality. So I removed the __gdbstub related code and toss this issue to those who want/implement breakpoints in the future. -- yamahata _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Isaku Yamahata
2006-Jan-23 07:55 UTC
[Xen-devel] [PATCH] gdbstub for xen/ia64 (was Re: [Xen-ia64-devel] [PATCH] cdb for xen/ia64)
gdbstub for xen/ia64 catched up recent common gdbstub and kgdb/ia64. # HG changeset patch # User yamahata@valinux.co.jp # Node ID aeebe099dae6d13beebd8c879dc011d5a1e4ff78 # Parent ea582eba5cd2bc3edc3c1dd7416a902c574602d2 ia64 specific part of gdbstub. Signed-off-by: Isaku Yamahtata <yamahata@valinux.co.jp> diff -r ea582eba5cd2 -r aeebe099dae6 xen/arch/ia64/Makefile --- a/xen/arch/ia64/Makefile Mon Jan 23 12:25:55 2006 +0900 +++ b/xen/arch/ia64/Makefile Mon Jan 23 16:46:19 2006 +0900 @@ -22,6 +22,10 @@ memset.o strlen.o memcpy_mck.o \ __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \ __divdi3.o __udivdi3.o __moddi3.o __umoddi3.o + +ifeq ($(crash_debug),y) +OBJS += gdbstub.o +endif # xen stack unwinder # unwind_decoder.c is included in unwind.c diff -r ea582eba5cd2 -r aeebe099dae6 xen/arch/ia64/vmx/vmx_process.c --- a/xen/arch/ia64/vmx/vmx_process.c Mon Jan 23 12:25:55 2006 +0900 +++ b/xen/arch/ia64/vmx/vmx_process.c Mon Jan 23 16:46:19 2006 +0900 @@ -41,6 +41,7 @@ #include <asm/regionreg.h> #include <asm/privop.h> #include <asm/ia64_int.h> +#include <asm/debugger.h> //#include <asm/hpsim_ssc.h> #include <asm/dom_fw.h> #include <asm/vmx_vcpu.h> @@ -107,6 +108,14 @@ if (running_on_sim) do_ssc(vcpu_get_gr_nat(current,36), regs); else do_ssc(vcpu_get_gr_nat(current,36), regs); } +#endif +#ifdef CRASH_DEBUG + if ((iim == 0 || iim == CDB_BREAK_NUM) && !user_mode(regs) && + IS_VMM_ADDRESS(regs->cr_iip)) { + if (iim == 0) + show_registers(regs); + debugger_trap_fatal(0 /* don''t care */, regs); + } else #endif if (iim == d->arch.breakimm) { struct ia64_pal_retval y; diff -r ea582eba5cd2 -r aeebe099dae6 xen/arch/ia64/xen/hyperprivop.S --- a/xen/arch/ia64/xen/hyperprivop.S Mon Jan 23 12:25:55 2006 +0900 +++ b/xen/arch/ia64/xen/hyperprivop.S Mon Jan 23 16:46:19 2006 +0900 @@ -12,6 +12,7 @@ #include <asm/offsets.h> #include <asm/processor.h> #include <asm/system.h> +#include <asm/debugger.h> #include <public/arch-ia64.h> @@ -549,7 +550,12 @@ (p7) br.spnt.many 1f ;; cmp.eq p7,p0=r17,r0 (p7) br.spnt.few dispatch_break_fault ;; -1: +#ifdef CRASH_DEBUG + movl r21=CDB_BREAK_NUM ;; + cmp.eq p7,p0=r17,r21 +(p7) br.spnt.few dispatch_break_fault ;; +#endif +1: #if 1 /* special handling in case running on simulator */ movl r20=first_break;; ld4 r23=[r20];; diff -r ea582eba5cd2 -r aeebe099dae6 xen/arch/ia64/xen/ivt.S --- a/xen/arch/ia64/xen/ivt.S Mon Jan 23 12:25:55 2006 +0900 +++ b/xen/arch/ia64/xen/ivt.S Mon Jan 23 16:46:19 2006 +0900 @@ -15,6 +15,7 @@ #define sys_call_table 0 #define sys_ni_syscall 0 #include <asm/vhpt.h> +#include <asm/debugger.h> #endif /* * arch/ia64/kernel/ivt.S @@ -841,6 +842,13 @@ ;; cmp.eq p7,p0=r17,r0 (p7) br.spnt.few dispatch_break_fault ;; +#ifdef CRASH_DEBUG + // panic can occur before domain0 is created. + // in such case referencing XSI_PSR_IC causes nested_dtlb_miss + movl r18=CDB_BREAK_NUM ;; + cmp.eq p7,p0=r17,r18 ;; +(p7) br.spnt.few dispatch_break_fault ;; +#endif movl r18=XSI_PSR_IC ;; ld8 r19=[r18] diff -r ea582eba5cd2 -r aeebe099dae6 xen/arch/ia64/xen/process.c --- a/xen/arch/ia64/xen/process.c Mon Jan 23 12:25:55 2006 +0900 +++ b/xen/arch/ia64/xen/process.c Mon Jan 23 16:46:19 2006 +0900 @@ -31,6 +31,7 @@ #include <asm/dom_fw.h> #include "hpsim_ssc.h" #include <xen/multicall.h> +#include <asm/debugger.h> extern unsigned long vcpu_get_itir_on_fault(struct vcpu *, UINT64); extern void die_if_kernel(char *str, struct pt_regs *regs, long err); @@ -652,7 +653,7 @@ ia64_handle_break (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long iim) { struct domain *d = (struct domain *) current->domain; - struct vcpu *v = (struct domain *) current; + struct vcpu *v = current; extern unsigned long running_on_sim; if (first_break) { @@ -663,7 +664,14 @@ if (iim == 0x80001 || iim == 0x80002) { //FIXME: don''t hardcode constant if (running_on_sim) do_ssc(vcpu_get_gr(current,36), regs); else do_ssc(vcpu_get_gr(current,36), regs); - } + } +#ifdef CRASH_DEBUG + else if ((iim == 0 || iim == CDB_BREAK_NUM) && !user_mode(regs)) { + if (iim == 0) + show_registers(regs); + debugger_trap_fatal(0 /* don''t care */, regs); + } +#endif else if (iim == d->arch.breakimm) { /* by default, do not continue */ v->arch.hypercall_continuation = 0; diff -r ea582eba5cd2 -r aeebe099dae6 xen/arch/ia64/xen/xenmisc.c --- a/xen/arch/ia64/xen/xenmisc.c Mon Jan 23 12:25:55 2006 +0900 +++ b/xen/arch/ia64/xen/xenmisc.c Mon Jan 23 16:46:19 2006 +0900 @@ -18,6 +18,7 @@ #include <xen/softirq.h> #include <public/sched.h> #include <asm/vhpt.h> +#include <asm/debugger.h> efi_memory_desc_t ia64_efi_io_md; EXPORT_SYMBOL(ia64_efi_io_md); @@ -356,6 +357,11 @@ va_end(args); printf(buf); if (regs) show_registers(regs); + if (regs) { + debugger_trap_fatal(0 /* don''t care */, regs); + } else { + debugger_trap_immediate(); + } domain_pause_by_systemcontroller(current->domain); v->domain->shutdown_code = SHUTDOWN_crash; set_bit(_DOMF_shutdown, v->domain->domain_flags); diff -r ea582eba5cd2 -r aeebe099dae6 xen/common/Makefile --- a/xen/common/Makefile Mon Jan 23 12:25:55 2006 +0900 +++ b/xen/common/Makefile Mon Jan 23 16:46:19 2006 +0900 @@ -3,6 +3,9 @@ ifneq ($(perfc),y) OBJS := $(subst perfc.o,,$(OBJS)) +endif +ifneq ($(crash_debug),y) +OBJS := $(patsubst cdb.o,,$(OBJS)) endif ifneq ($(crash_debug),y) OBJS := $(patsubst gdbstub.o,,$(OBJS)) diff -r ea582eba5cd2 -r aeebe099dae6 xen/include/asm-ia64/debugger.h --- a/xen/include/asm-ia64/debugger.h Mon Jan 23 12:25:55 2006 +0900 +++ b/xen/include/asm-ia64/debugger.h Mon Jan 23 16:46:19 2006 +0900 @@ -24,6 +24,54 @@ #include <xen/softirq.h> +// this number is an arbitary number which is not used for any other purpose +// __builtin_trap(), FORCE_CRASH() 0x0 +// ski 0x80001, 0x80002 +// kdb 0x80100, 0x80101 +// kprobe 0x80200, jprobe 0x80300 +// kgdb 0x6665 +// gdb 0x99998 (#define IA64_BREAKPOINT 0x00003333300LL) + +// cdb should handle 0 and CDB_BREAK_NUM. +#define CDB_BREAK_NUM 0x80800 + + +#ifndef __ASSEMBLY__ + +#include <xen/gdbstub.h> + +// NOTE: on xen struct pt_regs = struct cpu_user_regs +// see include/asm-ia64/linux-xen/asm/ptrace.h +#ifdef CRASH_DEBUG +// crash_debug=y + +/* The main trap handlers use these helper macros which include early bail. */ +static inline int debugger_trap_entry( + unsigned int vector, struct cpu_user_regs *regs) +{ + return 0; +} + +extern int __trap_to_cdb(struct cpu_user_regs *r); +static inline int debugger_trap_fatal( + unsigned int vector, struct cpu_user_regs *regs) +{ + (void)__trap_to_gdb(regs, vector); + return 0; +} + +#define ____debugger_trap_immediate(b) __asm__ __volatile__ ("break.m "#b"\n") +#define __debugger_trap_immediate(b) ____debugger_trap_immediate(b) +#define debugger_trap_immediate() __debugger_trap_immediate(CDB_BREAK_NUM) + +//XXX temporal work around +#ifndef CONFIG_SMP +#define smp_send_stop() /* nothing */ +#endif + +#elif defined DOMU_DEBUG +// domu_debug=y +#warning "domu_debug is not implemented yet." /* The main trap handlers use these helper macros which include early bail. */ static inline int debugger_trap_entry( unsigned int vector, struct cpu_user_regs *regs) @@ -37,6 +85,23 @@ return 0; } -#define debugger_trap_immediate() do {} while(0) +#define debugger_trap_immediate() ((void)0) +#else +/* The main trap handlers use these helper macros which include early bail. */ +static inline int debugger_trap_entry( + unsigned int vector, struct cpu_user_regs *regs) +{ + return 0; +} + +static inline int debugger_trap_fatal( + unsigned int vector, struct cpu_user_regs *regs) +{ + return 0; +} + +#define debugger_trap_immediate() ((void)0) +#endif +#endif // __ASSEMBLLY__ #endif /* __ASM_DEBUGGER_H__ */ diff -r ea582eba5cd2 -r aeebe099dae6 xen/arch/ia64/xen/gdbstub.c --- /dev/null Thu Jan 1 00:00:00 1970 +0000 +++ b/xen/arch/ia64/xen/gdbstub.c Mon Jan 23 16:46:19 2006 +0900 @@ -0,0 +1,811 @@ +/* + * ia64-specific cdb routines + * cdb xen/ia64 by Isaku Yamahta <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * some routines are stolen from kgdb/ia64. + */ +/* + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + +/* + * Copyright (C) 2000-2001 VERITAS Software Corporation. + */ +/* + * Contributor: Lake Stevens Instrument Division$ + * Written by: Glenn Engel $ + * Updated by: Amit Kale<akale@veritas.com> + * Modified for 386 by Jim Kingdon, Cygnus Support. + * Origianl kgdb, compatibility with 2.1.xx kernel by David Grothe <dave@gcom.com> + * + */ + + +#include <xen/lib.h> +#include <asm/byteorder.h> +#include <asm/debugger.h> +#include <asm/uaccess.h> + +#define USE_UNWIND + +#ifdef USE_UNWIND +#include <asm/unwind.h> +#endif + +/* Printk isn''t particularly safe just after we''ve trapped to the + debugger. so avoid it. */ +#define dbg_printk(...) +//#define dbg_printk(...) printk(__VA_ARGS__) + +u16 +gdb_arch_signal_num(struct cpu_user_regs *regs, unsigned long cookie) +{ + /* XXX */ + return 1; +} + +void +gdb_arch_read_reg_array(struct cpu_user_regs *regs, struct gdb_context *ctx) +{ + gdb_send_reply("", ctx); +} + +void +gdb_arch_write_reg_array(struct cpu_user_regs *regs, const char* buf, + struct gdb_context *ctx) +{ + /* XXX TODO */ + gdb_send_reply("E02", ctx); +} + +/* Like copy_from_user, but safe to call with interrupts disabled. + Trust me, and don''t look behind the curtain. */ +unsigned +gdb_arch_copy_from_user(void *dest, const void *src, unsigned len) +{ + int val; + __asm__ __volatile__( + "cmp4.eq p6, p0 = r0, %1\n" + "(p6) br.cond.dptk 2f\n" + "[1:]\n" + ".xdata4 \"__ex_table\", 99f-., 2f-.;\n" + "[99:] ld1 %0 = [%3], 1\n" + ";;\n" + ".xdata4 \"__ex_table\", 99f-., 2f-.;\n" + "[99:] st1 [%2] = %0, 1\n" + "adds %1 = -1, %1\n" + ";;\n" + "cmp4.eq p0, p6 = r0, %1\n" + "(p6) br.cond.dptk 1b\n" + "[2:]\n" + : "=r"(val), "=r"(len), "=r"(dest), "=r"(src) + : "1"(len), "2"(dest), "3"(src) + : "memory", "p6"); + return len; +} + +unsigned int +gdb_arch_copy_to_user(void *dest, const void *src, unsigned len) +{ + /* XXX */ + return len; +} + +#define NUM_REGS 590 +#define REGISTER_BYTES (NUM_REGS*8+128*8) +#define REGISTER_BYTE(N) (((N) * 8) \ + + ((N) <= IA64_FR0_REGNUM ? \ + 0 : 8 * (((N) > IA64_FR127_REGNUM) ? 128 : (N) - IA64_FR0_REGNUM))) +#define REGISTER_SIZE(N) \ + (((N) >= IA64_FR0_REGNUM && (N) <= IA64_FR127_REGNUM) ? 16 : 8) +#define IA64_GR0_REGNUM 0 +#define IA64_FR0_REGNUM 128 +#define IA64_FR127_REGNUM (IA64_FR0_REGNUM+127) +#define IA64_PR0_REGNUM 256 +#define IA64_BR0_REGNUM 320 +#define IA64_VFP_REGNUM 328 +#define IA64_PR_REGNUM 330 +#define IA64_IP_REGNUM 331 +#define IA64_PSR_REGNUM 332 +#define IA64_CFM_REGNUM 333 +#define IA64_AR0_REGNUM 334 +#define IA64_NAT0_REGNUM 462 +#define IA64_NAT31_REGNUM (IA64_NAT0_REGNUM+31) +#define IA64_NAT32_REGNUM (IA64_NAT0_REGNUM+32) +#define IA64_RSC_REGNUM (IA64_AR0_REGNUM+16) +#define IA64_BSP_REGNUM (IA64_AR0_REGNUM+17) +#define IA64_BSPSTORE_REGNUM (IA64_AR0_REGNUM+18) +#define IA64_RNAT_REGNUM (IA64_AR0_REGNUM+19) +#define IA64_FCR_REGNUM (IA64_AR0_REGNUM+21) +#define IA64_EFLAG_REGNUM (IA64_AR0_REGNUM+24) +#define IA64_CSD_REGNUM (IA64_AR0_REGNUM+25) +#define IA64_SSD_REGNUM (IA64_AR0_REGNUM+26) +#define IA64_CFLG_REGNUM (IA64_AR0_REGNUM+27) +#define IA64_FSR_REGNUM (IA64_AR0_REGNUM+28) +#define IA64_FIR_REGNUM (IA64_AR0_REGNUM+29) +#define IA64_FDR_REGNUM (IA64_AR0_REGNUM+30) +#define IA64_CCV_REGNUM (IA64_AR0_REGNUM+32) +#define IA64_UNAT_REGNUM (IA64_AR0_REGNUM+36) +#define IA64_FPSR_REGNUM (IA64_AR0_REGNUM+40) +#define IA64_ITC_REGNUM (IA64_AR0_REGNUM+44) +#define IA64_PFS_REGNUM (IA64_AR0_REGNUM+64) +#define IA64_LC_REGNUM (IA64_AR0_REGNUM+65) +#define IA64_EC_REGNUM (IA64_AR0_REGNUM+66) + +#ifndef USE_UNWIND +struct regs_to_cpu_user_resgs_index { + unsigned int reg; + unsigned int ptregoff; +}; + +#define ptoff(V) ((unsigned int)&((struct cpu_user_regs*)0x0)->V) + +// gr +static const struct regs_to_cpu_user_resgs_index +gr_reg_to_cpu_user_regs_index[] = { + {IA64_GR0_REGNUM + 8, ptoff(r8)}, + {IA64_GR0_REGNUM + 9, ptoff(r9)}, + {IA64_GR0_REGNUM + 10, ptoff(r10)}, + {IA64_GR0_REGNUM + 11, ptoff(r11)}, + {IA64_GR0_REGNUM + 1, ptoff(r1)}, + {IA64_GR0_REGNUM + 12, ptoff(r12)}, + {IA64_GR0_REGNUM + 13, ptoff(r13)}, + {IA64_GR0_REGNUM + 15, ptoff(r15)}, + + {IA64_GR0_REGNUM + 14, ptoff(r14)}, + {IA64_GR0_REGNUM + 2, ptoff(r2)}, + {IA64_GR0_REGNUM + 3, ptoff(r3)}, + {IA64_GR0_REGNUM + 16, ptoff(r16)}, + {IA64_GR0_REGNUM + 17, ptoff(r17)}, + {IA64_GR0_REGNUM + 18, ptoff(r18)}, + {IA64_GR0_REGNUM + 19, ptoff(r19)}, + {IA64_GR0_REGNUM + 20, ptoff(r20)}, + {IA64_GR0_REGNUM + 21, ptoff(r21)}, + {IA64_GR0_REGNUM + 22, ptoff(r22)}, + {IA64_GR0_REGNUM + 23, ptoff(r23)}, + {IA64_GR0_REGNUM + 24, ptoff(r24)}, + {IA64_GR0_REGNUM + 25, ptoff(r25)}, + {IA64_GR0_REGNUM + 26, ptoff(r26)}, + {IA64_GR0_REGNUM + 27, ptoff(r27)}, + {IA64_GR0_REGNUM + 28, ptoff(r28)}, + {IA64_GR0_REGNUM + 29, ptoff(r29)}, + {IA64_GR0_REGNUM + 30, ptoff(r30)}, + {IA64_GR0_REGNUM + 31, ptoff(r31)}, + + {IA64_GR0_REGNUM + 4, ptoff(r4)}, + {IA64_GR0_REGNUM + 5, ptoff(r5)}, + {IA64_GR0_REGNUM + 6, ptoff(r6)}, + {IA64_GR0_REGNUM + 7, ptoff(r7)}, +}; +static const int gr_reg_to_cpu_user_regs_index_max + sizeof(gr_reg_to_cpu_user_regs_index) / + sizeof(gr_reg_to_cpu_user_regs_index[0]); + +// br +static const struct regs_to_cpu_user_resgs_index +br_reg_to_cpu_user_regs_index[] = { + {IA64_BR0_REGNUM + 0, ptoff(b0)}, + {IA64_BR0_REGNUM + 6, ptoff(b6)}, + {IA64_BR0_REGNUM + 7, ptoff(b7)}, +}; +static const int br_reg_to_cpu_user_regs_index_max + sizeof(br_reg_to_cpu_user_regs_index) / + sizeof(br_reg_to_cpu_user_regs_index[0]); + +// f +static const struct regs_to_cpu_user_resgs_index +fr_reg_to_cpu_user_regs_index[] = { + {IA64_FR0_REGNUM + 6, ptoff(f6)}, + {IA64_FR0_REGNUM + 7, ptoff(f7)}, + {IA64_FR0_REGNUM + 8, ptoff(f8)}, + {IA64_FR0_REGNUM + 9, ptoff(f9)}, + {IA64_FR0_REGNUM + 10, ptoff(f10)}, + {IA64_FR0_REGNUM + 11, ptoff(f11)}, +}; +static const int fr_reg_to_cpu_user_regs_index_max + sizeof(fr_reg_to_cpu_user_regs_index) / + sizeof(fr_reg_to_cpu_user_regs_index[0]); + + +void +gdb_arch_read_reg(unsigned long regnum, struct cpu_user_regs *regs, + struct gdb_context *ctx) +{ + unsigned long reg = IA64_IP_REGNUM; + char buf[9]; + int i; + + dbg_printk("Register read regnum = 0x%lx\n", regnum); + if (IA64_GR0_REGNUM <= regnum && regnum <= IA64_GR0_REGNUM + 31) { + for (i = 0; i < gr_reg_to_cpu_user_regs_index_max; i++) { + if (gr_reg_to_cpu_user_regs_index[i].reg == regnum) { + reg = *(unsigned long*)(((char*)regs) + gr_reg_to_cpu_user_regs_index[i].ptregoff); + break; + } + } + if (i == gr_reg_to_cpu_user_regs_index_max) { + goto out_err; + } + } else if (IA64_BR0_REGNUM <= regnum && regnum <= IA64_BR0_REGNUM + 7) { + for (i = 0; i < br_reg_to_cpu_user_regs_index_max; i++) { + if (br_reg_to_cpu_user_regs_index[i].reg == regnum) { + reg = *(unsigned long*)(((char*)regs) + br_reg_to_cpu_user_regs_index[i].ptregoff); + break; + } + } + if (i == br_reg_to_cpu_user_regs_index_max) { + goto out_err; + } + } else if (IA64_FR0_REGNUM + 6 <= regnum && regnum <= IA64_FR0_REGNUM + 11) { + for (i = 0; i < fr_reg_to_cpu_user_regs_index_max; i++) { + if (fr_reg_to_cpu_user_regs_index[i].reg == regnum) { + reg = *(unsigned long*)(((char*)regs) + fr_reg_to_cpu_user_regs_index[i].ptregoff); + break; + } + } + if (i == fr_reg_to_cpu_user_regs_index_max) { + goto out_err; + } + } else if (regnum == IA64_CSD_REGNUM) { + reg = regs->ar_csd; + } else if (regnum == IA64_SSD_REGNUM) { + reg = regs->ar_ssd; + } else if (regnum == IA64_PSR_REGNUM) { + reg = regs->cr_ipsr; + } else if (regnum == IA64_IP_REGNUM) { + reg = regs->cr_iip; + } else if (regnum == IA64_CFM_REGNUM) { + reg = regs->cr_ifs; + } else if (regnum == IA64_UNAT_REGNUM) { + reg = regs->ar_unat; + } else if (regnum == IA64_PFS_REGNUM) { + reg = regs->ar_pfs; + } else if (regnum == IA64_RSC_REGNUM) { + reg = regs->ar_rsc; + } else if (regnum == IA64_RNAT_REGNUM) { + reg = regs->ar_rnat; + } else if (regnum == IA64_BSPSTORE_REGNUM) { + reg = regs->ar_bspstore; + } else if (regnum == IA64_PR_REGNUM) { + reg = regs->pr; + } else if (regnum == IA64_FPSR_REGNUM) { + reg = regs->ar_fpsr; + } else if (regnum == IA64_CCV_REGNUM) { + reg = regs->ar_ccv; + } else { + // emul_unat, rfi_pfs + goto out_err; + } + + dbg_printk("Register read regnum = 0x%lx, val = 0x%lx\n", regnum, reg); + sprintf(buf, "%.08lx", swab64(reg)); +out: + return gdb_send_reply(buf, ctx); + +out_err: + dbg_printk("Register read unsupported regnum = 0x%lx\n", regnum); + sprintf(buf, "%s", "x"); + goto out; +} +#else + +#define ptoff(V) ((unsigned int) &((struct pt_regs *)0x0)->V) +struct reg_to_ptreg_index { + unsigned int reg; + unsigned int ptregoff; +}; + +static struct reg_to_ptreg_index gr_reg_to_ptreg_index[] = { + {IA64_GR0_REGNUM + 1, ptoff(r1)}, + {IA64_GR0_REGNUM + 2, ptoff(r2)}, + {IA64_GR0_REGNUM + 3, ptoff(r3)}, + {IA64_GR0_REGNUM + 8, ptoff(r8)}, + {IA64_GR0_REGNUM + 9, ptoff(r9)}, + {IA64_GR0_REGNUM + 10, ptoff(r10)}, + {IA64_GR0_REGNUM + 11, ptoff(r11)}, + {IA64_GR0_REGNUM + 12, ptoff(r12)}, + {IA64_GR0_REGNUM + 13, ptoff(r13)}, + {IA64_GR0_REGNUM + 14, ptoff(r14)}, + {IA64_GR0_REGNUM + 15, ptoff(r15)}, + {IA64_GR0_REGNUM + 16, ptoff(r16)}, + {IA64_GR0_REGNUM + 17, ptoff(r17)}, + {IA64_GR0_REGNUM + 18, ptoff(r18)}, + {IA64_GR0_REGNUM + 19, ptoff(r19)}, + {IA64_GR0_REGNUM + 20, ptoff(r20)}, + {IA64_GR0_REGNUM + 21, ptoff(r21)}, + {IA64_GR0_REGNUM + 22, ptoff(r22)}, + {IA64_GR0_REGNUM + 23, ptoff(r23)}, + {IA64_GR0_REGNUM + 24, ptoff(r24)}, + {IA64_GR0_REGNUM + 25, ptoff(r25)}, + {IA64_GR0_REGNUM + 26, ptoff(r26)}, + {IA64_GR0_REGNUM + 27, ptoff(r27)}, + {IA64_GR0_REGNUM + 28, ptoff(r28)}, + {IA64_GR0_REGNUM + 29, ptoff(r29)}, + {IA64_GR0_REGNUM + 30, ptoff(r30)}, + {IA64_GR0_REGNUM + 31, ptoff(r31)}, +}; + +static struct reg_to_ptreg_index br_reg_to_ptreg_index[] = { + {IA64_BR0_REGNUM, ptoff(b0)}, + {IA64_BR0_REGNUM + 6, ptoff(b6)}, + {IA64_BR0_REGNUM + 7, ptoff(b7)}, +}; + +static struct reg_to_ptreg_index ar_reg_to_ptreg_index[] = { + {IA64_PFS_REGNUM, ptoff(ar_pfs)}, + {IA64_UNAT_REGNUM, ptoff(ar_unat)}, + {IA64_RNAT_REGNUM, ptoff(ar_rnat)}, + {IA64_BSPSTORE_REGNUM, ptoff(ar_bspstore)}, + {IA64_RSC_REGNUM, ptoff(ar_rsc)}, + {IA64_CSD_REGNUM, ptoff(ar_csd)}, + {IA64_SSD_REGNUM, ptoff(ar_ssd)}, + {IA64_FPSR_REGNUM, ptoff(ar_fpsr)}, + {IA64_CCV_REGNUM, ptoff(ar_ccv)}, +}; + +#ifndef XEN +extern atomic_t cpu_doing_single_step; +#endif + +static int kgdb_gr_reg(int regnum, struct unw_frame_info *info, + unsigned long *reg, int rw) +{ + char nat; + + if ((regnum >= IA64_GR0_REGNUM && regnum <= (IA64_GR0_REGNUM + 1)) || + (regnum >= (IA64_GR0_REGNUM + 4) && + regnum <= (IA64_GR0_REGNUM + 7))) + return !unw_access_gr(info, regnum - IA64_GR0_REGNUM, + reg, &nat, rw); + else + return 0; +} +static int kgdb_gr_ptreg(int regnum, struct pt_regs * ptregs, + struct unw_frame_info *info, unsigned long *reg, int rw) +{ + int i, result = 1; + char nat; + + if (!((regnum >= (IA64_GR0_REGNUM + 2) && + regnum <= (IA64_GR0_REGNUM + 3)) || + (regnum >= (IA64_GR0_REGNUM + 8) && + regnum <= (IA64_GR0_REGNUM + 15)) || + (regnum >= (IA64_GR0_REGNUM + 16) && + regnum <= (IA64_GR0_REGNUM + 31)))) + return 0; + else if (rw && ptregs) { + for (i = 0; i < ARRAY_SIZE(gr_reg_to_ptreg_index); i++) + if (gr_reg_to_ptreg_index[i].reg == regnum) { + *((unsigned long *)(((void *)ptregs) + + gr_reg_to_ptreg_index[i].ptregoff)) = *reg; + break; + } + } else if (!rw && ptregs) { + for (i = 0; i < ARRAY_SIZE(gr_reg_to_ptreg_index); i++) + if (gr_reg_to_ptreg_index[i].reg == regnum) { + *reg = *((unsigned long *) + (((void *)ptregs) + + gr_reg_to_ptreg_index[i].ptregoff)); + break; + } + } else + result = !unw_access_gr(info, regnum - IA64_GR0_REGNUM, + reg, &nat, rw); + return result; +} + +static int kgdb_br_reg(int regnum, struct pt_regs * ptregs, + struct unw_frame_info *info, unsigned long *reg, int rw) +{ + int i, result = 1; + + if (!(regnum >= IA64_BR0_REGNUM && regnum <= (IA64_BR0_REGNUM + 7))) + return 0; + + switch (regnum) { + case IA64_BR0_REGNUM: + case IA64_BR0_REGNUM + 6: + case IA64_BR0_REGNUM + 7: + if (rw) { + for (i = 0; i < ARRAY_SIZE(br_reg_to_ptreg_index); i++) + if (br_reg_to_ptreg_index[i].reg == regnum) { + *((unsigned long *) + (((void *)ptregs) + + br_reg_to_ptreg_index[i].ptregoff)) + *reg; + break; + } + } else + for (i = 0; i < ARRAY_SIZE(br_reg_to_ptreg_index); i++) + if (br_reg_to_ptreg_index[i].reg == regnum) { + *reg = *((unsigned long *) + (((void *)ptregs) + + br_reg_to_ptreg_index[i]. + ptregoff)); + break; + } + break; + case IA64_BR0_REGNUM + 1: + case IA64_BR0_REGNUM + 2: + case IA64_BR0_REGNUM + 3: + case IA64_BR0_REGNUM + 4: + case IA64_BR0_REGNUM + 5: + result = !unw_access_br(info, regnum - IA64_BR0_REGNUM, + reg, rw); + break; + } + + return result; +} + +static int kgdb_fr_reg(int regnum, char *inbuffer, struct pt_regs * ptregs, + struct unw_frame_info *info, unsigned long *reg, + struct ia64_fpreg *freg, int rw) +{ + int result = 1; + + if (!(regnum >= IA64_FR0_REGNUM && regnum <= (IA64_FR0_REGNUM + 127))) + return 0; + + switch (regnum) { + case IA64_FR0_REGNUM + 6: + case IA64_FR0_REGNUM + 7: + case IA64_FR0_REGNUM + 8: + case IA64_FR0_REGNUM + 9: + case IA64_FR0_REGNUM + 10: + case IA64_FR0_REGNUM + 11: + case IA64_FR0_REGNUM + 12: + if (rw) { +#ifndef XEN + char *ptr = inbuffer; + + freg->u.bits[0] = *reg; + kgdb_hex2long(&ptr, &freg->u.bits[1]); + *(&ptregs->f6 + (regnum - (IA64_FR0_REGNUM + 6))) + *freg; +#else + printk("%s: %d: writing to fpreg is not supported.\n", + __func__, __LINE__); +#endif + break; + } else if (!ptregs) + result = !unw_access_fr(info, regnum - IA64_FR0_REGNUM, + freg, rw); + else +#ifndef XEN + *freg + *(&ptregs->f6 + (regnum - (IA64_FR0_REGNUM + 6))); +#else + //XXX struct ia64_fpreg and struct pt_fpreg are same. + *freg = *((struct ia64_fpreg*)(&ptregs->f6 + + (regnum - (IA64_FR0_REGNUM + 6)))); +#endif + break; + default: + if (!rw) + result = !unw_access_fr(info, regnum - IA64_FR0_REGNUM, + freg, rw); + else + result = 0; + break; + } + + return result; +} + +static int kgdb_ar_reg(int regnum, struct pt_regs * ptregs, + struct unw_frame_info *info, unsigned long *reg, int rw) +{ + int result = 0, i; + + if (!(regnum >= IA64_AR0_REGNUM && regnum <= IA64_EC_REGNUM)) + return 0; + + if (rw && ptregs) { + for (i = 0; i < ARRAY_SIZE(ar_reg_to_ptreg_index); i++) + if (ar_reg_to_ptreg_index[i].reg == regnum) { + *((unsigned long *) (((void *)ptregs) + + ar_reg_to_ptreg_index[i].ptregoff)) + *reg; + result = 1; + break; + } + } else if (ptregs) { + for (i = 0; i < ARRAY_SIZE(ar_reg_to_ptreg_index); i++) + if (ar_reg_to_ptreg_index[i].reg == regnum) { + *reg = *((unsigned long *) (((void *)ptregs) + + ar_reg_to_ptreg_index[i].ptregoff)); + result = 1; + break; + } + } + + if (result) + return result; + + result = 1; + + switch (regnum) { + case IA64_CSD_REGNUM: + result = !unw_access_ar(info, UNW_AR_CSD, reg, rw); + break; + case IA64_SSD_REGNUM: + result = !unw_access_ar(info, UNW_AR_SSD, reg, rw); + break; + case IA64_UNAT_REGNUM: + result = !unw_access_ar(info, UNW_AR_RNAT, reg, rw); + break; + case IA64_RNAT_REGNUM: + result = !unw_access_ar(info, UNW_AR_RNAT, reg, rw); + break; + case IA64_BSPSTORE_REGNUM: + result = !unw_access_ar(info, UNW_AR_RNAT, reg, rw); + break; + case IA64_PFS_REGNUM: + result = !unw_access_ar(info, UNW_AR_RNAT, reg, rw); + break; + case IA64_LC_REGNUM: + result = !unw_access_ar(info, UNW_AR_LC, reg, rw); + break; + case IA64_EC_REGNUM: + result = !unw_access_ar(info, UNW_AR_EC, reg, rw); + break; + case IA64_FPSR_REGNUM: + result = !unw_access_ar(info, UNW_AR_FPSR, reg, rw); + break; + case IA64_RSC_REGNUM: + result = !unw_access_ar(info, UNW_AR_RSC, reg, rw); + break; + case IA64_CCV_REGNUM: + result = !unw_access_ar(info, UNW_AR_CCV, reg, rw); + break; + default: + result = 0; + } + + return result; +} + +#ifndef XEN +void kgdb_get_reg(char *outbuffer, int regnum, struct unw_frame_info *info, + struct pt_regs *ptregs) +#else +static int +kgdb_get_reg(int regnum, struct unw_frame_info *info, + struct cpu_user_regs* ptregs, + unsigned long* __reg, struct ia64_fpreg* __freg) +#endif +{ + unsigned long reg, size = 0, *mem = ® + struct ia64_fpreg freg; + + if (kgdb_gr_reg(regnum, info, ®, 0) || + kgdb_gr_ptreg(regnum, ptregs, info, ®, 0) || + kgdb_br_reg(regnum, ptregs, info, ®, 0) || + kgdb_ar_reg(regnum, ptregs, info, ®, 0)) + size = sizeof(reg); + else if (kgdb_fr_reg(regnum, NULL, ptregs, info, ®, &freg, 0)) { + size = sizeof(freg); + mem = (unsigned long *)&freg; + } else if (regnum == IA64_IP_REGNUM) { + if (!ptregs) { + unw_get_ip(info, ®); + size = sizeof(reg); + } else { + reg = ptregs->cr_iip; + size = sizeof(reg); + } + } else if (regnum == IA64_CFM_REGNUM) { + if (!ptregs) + unw_get_cfm(info, ®); + else + reg = ptregs->cr_ifs; + size = sizeof(reg); + } else if (regnum == IA64_PSR_REGNUM) { +#ifndef XEN + if (!ptregs && kgdb_usethread) + ptregs = (struct pt_regs *) + ((unsigned long)kgdb_usethread + + IA64_STK_OFFSET) - 1; +#endif + if (ptregs) + reg = ptregs->cr_ipsr; + size = sizeof(reg); + } else if (regnum == IA64_PR_REGNUM) { + if (ptregs) + reg = ptregs->pr; + else + unw_access_pr(info, ®, 0); + size = sizeof(reg); + } else if (regnum == IA64_BSP_REGNUM) { + unw_get_bsp(info, ®); + size = sizeof(reg); + } + +#ifndef XEN + if (size) { + kgdb_mem2hex((char *) mem, outbuffer, size); + outbuffer[size*2] = 0; + } + else + strcpy(outbuffer, "E0"); + + return; +#else + if (size) { + if (size == sizeof(reg)) { + *__reg = reg; + } else { + BUG_ON(size != sizeof(freg)); + *__freg = freg; + } + return 0; + } + + return -1; +#endif +} + +#ifndef XEN +static int inline kgdb_get_blocked_state(struct task_struct *p, + struct unw_frame_info *unw) +#else +static int +kgdb_get_blocked_state(struct vcpu *p, + struct cpu_user_regs *regs, + struct unw_frame_info *unw) +#endif +{ + unsigned long ip; + int count = 0; + +#ifndef XEN + unw_init_from_blocked_task(unw, p); +#endif + ip = 0UL; + do { + if (unw_unwind(unw) < 0) + return -1; + unw_get_ip(unw, &ip); +#ifndef XEN + if (!in_sched_functions(ip)) + break; +#else + dbg_printk("ip 0x%lx cr_iip 0x%lx\n", ip, regs->cr_iip); + if (ip == regs->cr_iip) + break; +#endif + } while (count++ < 16); + + if (!ip) + return -1; + else + return 0; +} + +struct gdb_callback_arg +{ + struct cpu_user_regs* regs; + unsigned long regnum; + unsigned long* reg; + struct pt_fpreg* freg; + + int error; + // 1: not supported + // 0: success + // -1: failure +}; + +static void +gdb_get_reg_callback(struct unw_frame_info* info, void* __arg) +{ + struct gdb_callback_arg* arg = (struct gdb_callback_arg*)__arg; + + if (kgdb_get_blocked_state(current, arg->regs, info) < 0) { + dbg_printk("%s: kgdb_get_blocked_state failed\n", __func__); + arg->error = -1; + return; + } + //XXX struct ia64_fpreg and struct pt_fpreg are same. + if (kgdb_get_reg(arg->regnum, info, arg->regs, arg->reg, + (struct ia64_fpreg*)arg->freg) < 0) { + dbg_printk("%s: kgdb_get_reg failed\n", __func__); + arg->error = 1; + return; + } + arg->error = 0; + return; +} + +void +gdb_arch_read_reg(unsigned long regnum, struct cpu_user_regs *regs, + struct gdb_context *ctx) +{ + struct gdb_callback_arg arg; + unsigned long reg; + struct pt_fpreg freg; + char buf[16 * 2 + 1]; + + if (regnum >= NUM_REGS) { + dbg_printk("%s: regnum %ld\n", __func__, regnum); + goto out_err; + } + + arg.regs = regs; + arg.regnum = regnum; + arg.reg = ® + arg.freg = &freg; + arg.error = 0; + unw_init_running(&gdb_get_reg_callback, (void*)&arg); + if (arg.error < 0) { + dbg_printk("%s: gdb_get_reg_callback failed\n", __func__); + goto out_err; + } + + if (arg.error > 0) { + // notify gdb that this register is not supported. + // see fetch_register_using_p() in gdb/remote.c. + sprintf(buf, "%s", "x"); + } else if (IA64_FR0_REGNUM <= regnum && regnum <= IA64_FR0_REGNUM + 127) { + sprintf(buf, "%.016lx", swab64(freg.u.bits[0])); + sprintf(buf + 16, "%.016lx", swab64(freg.u.bits[1])); + } else { + sprintf(buf, "%.016lx", swab64(reg)); + } +out: + return gdb_send_reply(buf, ctx); + +out_err: + dbg_printk("Register read unsupported regnum = 0x%lx\n", regnum); + sprintf(buf, "%s", "E0"); + goto out; +} +#endif + +void +gdb_arch_resume(struct cpu_user_regs *regs, + unsigned long addr, unsigned long type, + struct gdb_context *ctx) +{ + /* XXX */ + if (type == GDB_STEP) { + gdb_send_reply("S01", ctx); + } +} + +void +gdb_arch_print_state(struct cpu_user_regs *regs) +{ + /* XXX */ +} + +void +gdb_arch_enter(struct cpu_user_regs *regs) +{ + /* nothing */ +} + +void +gdb_arch_exit(struct cpu_user_regs *regs) +{ + /* nothing */ +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ -- yamahata _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel