From 834b2964b7ab047610da038e42d61dc8dac6339a Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 26 Oct 2010 12:49:00 -0500 Subject: kgdb,arm: fix register dump DBG_MAX_REG_NUM incorrectly had the number of indices in the GDB regs array rather than the number of registers, leading to an oops when the "rd" command is used in KDB. Cc: stable@kernel.org Signed-off-by: Rabin Vincent Signed-off-by: Jason Wessel --- arch/arm/include/asm/kgdb.h | 5 +++-- arch/arm/kernel/kgdb.c | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h index 08265993227f..48066ce9ea34 100644 --- a/arch/arm/include/asm/kgdb.h +++ b/arch/arm/include/asm/kgdb.h @@ -70,7 +70,8 @@ extern int kgdb_fault_expected; #define _GP_REGS 16 #define _FP_REGS 8 #define _EXTRA_REGS 2 -#define DBG_MAX_REG_NUM (_GP_REGS + (_FP_REGS * 3) + _EXTRA_REGS) +#define GDB_MAX_REGS (_GP_REGS + (_FP_REGS * 3) + _EXTRA_REGS) +#define DBG_MAX_REG_NUM (_GP_REGS + _FP_REGS + _EXTRA_REGS) #define KGDB_MAX_NO_CPUS 1 #define BUFMAX 400 @@ -93,7 +94,7 @@ extern int kgdb_fault_expected; #define _SPT 13 #define _LR 14 #define _PC 15 -#define _CPSR (DBG_MAX_REG_NUM - 1) +#define _CPSR (GDB_MAX_REGS - 1) /* * So that we can denote the end of a frame for tracing, diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c index d6e8b4d2e60d..778c2f7024ff 100644 --- a/arch/arm/kernel/kgdb.c +++ b/arch/arm/kernel/kgdb.c @@ -79,7 +79,7 @@ sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task) return; /* Initialize to zero */ - for (regno = 0; regno < DBG_MAX_REG_NUM; regno++) + for (regno = 0; regno < GDB_MAX_REGS; regno++) gdb_regs[regno] = 0; /* Otherwise, we have only some registers from switch_to() */ -- cgit v1.2.3 From d7ba979d45272385ce0fdf141d922e61ff48e07b Mon Sep 17 00:00:00 2001 From: Dongdong Deng Date: Wed, 18 Aug 2010 06:02:00 -0500 Subject: debug_core,x86,blackfin: Clean up hw debug disable API The kgdb_disable_hw_debug() was an architecture specific function for disabling all hardware breakpoints on a per cpu basis when entering the debug core. This patch will remove the weak function kdbg_disable_hw_debug() and change it into a call back which lives with the rest of hw breakpoint call backs in struct kgdb_arch. Signed-off-by: Dongdong Deng Signed-off-by: Jason Wessel --- arch/blackfin/kernel/kgdb.c | 3 ++- arch/x86/kernel/kgdb.c | 3 ++- include/linux/kgdb.h | 13 +++---------- kernel/debug/debug_core.c | 16 +++------------- 4 files changed, 10 insertions(+), 25 deletions(-) (limited to 'arch') diff --git a/arch/blackfin/kernel/kgdb.c b/arch/blackfin/kernel/kgdb.c index 08bc44ea6883..edae461b1c54 100644 --- a/arch/blackfin/kernel/kgdb.c +++ b/arch/blackfin/kernel/kgdb.c @@ -320,7 +320,7 @@ static void bfin_correct_hw_break(void) } } -void kgdb_disable_hw_debug(struct pt_regs *regs) +static void bfin_disable_hw_debug(struct pt_regs *regs) { /* Disable hardware debugging while we are in kgdb */ bfin_write_WPIACTL(0); @@ -406,6 +406,7 @@ struct kgdb_arch arch_kgdb_ops = { #endif .set_hw_breakpoint = bfin_set_hw_break, .remove_hw_breakpoint = bfin_remove_hw_break, + .disable_hw_break = bfin_disable_hw_debug, .remove_all_hw_break = bfin_remove_all_hw_break, .correct_hw_break = bfin_correct_hw_break, }; diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index d81cfebb848f..ec592caac4b4 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c @@ -387,7 +387,7 @@ kgdb_set_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype) * disable hardware debugging while it is processing gdb packets or * handling exception. */ -void kgdb_disable_hw_debug(struct pt_regs *regs) +static void kgdb_disable_hw_debug(struct pt_regs *regs) { int i; int cpu = raw_smp_processor_id(); @@ -724,6 +724,7 @@ struct kgdb_arch arch_kgdb_ops = { .flags = KGDB_HW_BREAKPOINT, .set_hw_breakpoint = kgdb_set_hw_break, .remove_hw_breakpoint = kgdb_remove_hw_break, + .disable_hw_break = kgdb_disable_hw_debug, .remove_all_hw_break = kgdb_remove_all_hw_break, .correct_hw_break = kgdb_correct_hw_break, }; diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h index cc96f0f23e04..092e4250a458 100644 --- a/include/linux/kgdb.h +++ b/include/linux/kgdb.h @@ -35,16 +35,6 @@ struct pt_regs; */ extern int kgdb_skipexception(int exception, struct pt_regs *regs); -/** - * kgdb_disable_hw_debug - (optional) Disable hardware debugging hook - * @regs: Current &struct pt_regs. - * - * This function will be called if the particular architecture must - * disable hardware debugging while it is processing gdb packets or - * handling exception. - */ -extern void kgdb_disable_hw_debug(struct pt_regs *regs); - struct tasklet_struct; struct task_struct; struct uart_port; @@ -243,6 +233,8 @@ extern void kgdb_arch_late(void); * breakpoint. * @remove_hw_breakpoint: Allow an architecture to specify how to remove a * hardware breakpoint. + * @disable_hw_break: Allow an architecture to specify how to disable + * hardware breakpoints for a single cpu. * @remove_all_hw_break: Allow an architecture to specify how to remove all * hardware breakpoints. * @correct_hw_break: Allow an architecture to specify how to correct the @@ -256,6 +248,7 @@ struct kgdb_arch { int (*remove_breakpoint)(unsigned long, char *); int (*set_hw_breakpoint)(unsigned long, int, enum kgdb_bptype); int (*remove_hw_breakpoint)(unsigned long, int, enum kgdb_bptype); + void (*disable_hw_break)(struct pt_regs *regs); void (*remove_all_hw_break)(void); void (*correct_hw_break)(void); }; diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c index fec596da9bd0..cefd4a11f6d9 100644 --- a/kernel/debug/debug_core.c +++ b/kernel/debug/debug_core.c @@ -209,18 +209,6 @@ int __weak kgdb_skipexception(int exception, struct pt_regs *regs) return 0; } -/** - * kgdb_disable_hw_debug - Disable hardware debugging while we in kgdb. - * @regs: Current &struct pt_regs. - * - * This function will be called if the particular architecture must - * disable hardware debugging while it is processing gdb packets or - * handling exception. - */ -void __weak kgdb_disable_hw_debug(struct pt_regs *regs) -{ -} - /* * Some architectures need cache flushes when we set/clear a * breakpoint: @@ -484,7 +472,9 @@ static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs, atomic_inc(&masters_in_kgdb); else atomic_inc(&slaves_in_kgdb); - kgdb_disable_hw_debug(ks->linux_regs); + + if (arch_kgdb_ops.disable_hw_break) + arch_kgdb_ops.disable_hw_break(regs); acquirelock: /* -- cgit v1.2.3 From ff10b88b5a05c8f1646dd15fb9f6093c1384ff6d Mon Sep 17 00:00:00 2001 From: Dongdong Deng Date: Wed, 27 Oct 2010 21:47:00 -0500 Subject: kgdb,ppc: Individual register get/set for ppc commit 534af1082329392bc29f6badf815e69ae2ae0f4c(kgdb,kdb: individual register set and and get API) introduce dbg_get_reg/dbg_set_reg API for individual register get and set. This patch implement those APIs for ppc. Signed-off-by: Dongdong Deng Signed-off-by: Jason Wessel --- arch/powerpc/include/asm/kgdb.h | 1 + arch/powerpc/kernel/kgdb.c | 188 ++++++++++++++++++++++++++-------------- 2 files changed, 126 insertions(+), 63 deletions(-) (limited to 'arch') diff --git a/arch/powerpc/include/asm/kgdb.h b/arch/powerpc/include/asm/kgdb.h index edd217006d27..9db24e77b9f4 100644 --- a/arch/powerpc/include/asm/kgdb.h +++ b/arch/powerpc/include/asm/kgdb.h @@ -31,6 +31,7 @@ static inline void arch_kgdb_breakpoint(void) asm(".long 0x7d821008"); /* twge r2, r2 */ } #define CACHE_FLUSH_IS_SAFE 1 +#define DBG_MAX_REG_NUM 70 /* The number bytes of registers we have to save depends on a few * things. For 64bit we default to not including vector registers and diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c index 7f61a3ac787c..7a9db64f3f04 100644 --- a/arch/powerpc/kernel/kgdb.c +++ b/arch/powerpc/kernel/kgdb.c @@ -194,40 +194,6 @@ static int kgdb_dabr_match(struct pt_regs *regs) ptr = (unsigned long *)ptr32; \ } while (0) - -void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) -{ - unsigned long *ptr = gdb_regs; - int reg; - - memset(gdb_regs, 0, NUMREGBYTES); - - for (reg = 0; reg < 32; reg++) - PACK64(ptr, regs->gpr[reg]); - -#ifdef CONFIG_FSL_BOOKE -#ifdef CONFIG_SPE - for (reg = 0; reg < 32; reg++) - PACK64(ptr, current->thread.evr[reg]); -#else - ptr += 32; -#endif -#else - /* fp registers not used by kernel, leave zero */ - ptr += 32 * 8 / sizeof(long); -#endif - - PACK64(ptr, regs->nip); - PACK64(ptr, regs->msr); - PACK32(ptr, regs->ccr); - PACK64(ptr, regs->link); - PACK64(ptr, regs->ctr); - PACK32(ptr, regs->xer); - - BUG_ON((unsigned long)ptr > - (unsigned long)(((void *)gdb_regs) + NUMREGBYTES)); -} - void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) { struct pt_regs *regs = (struct pt_regs *)(p->thread.ksp + @@ -271,44 +237,140 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) (unsigned long)(((void *)gdb_regs) + NUMREGBYTES)); } -#define UNPACK64(dest, ptr) do { dest = *(ptr++); } while (0) +#define GDB_SIZEOF_REG sizeof(unsigned long) +#define GDB_SIZEOF_REG_U32 sizeof(u32) -#define UNPACK32(dest, ptr) do { \ - u32 *ptr32; \ - ptr32 = (u32 *)ptr; \ - dest = *(ptr32++); \ - ptr = (unsigned long *)ptr32; \ - } while (0) +#ifdef CONFIG_FSL_BOOKE +#define GDB_SIZEOF_FLOAT_REG sizeof(unsigned long) +#else +#define GDB_SIZEOF_FLOAT_REG sizeof(u64) +#endif -void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) +struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = { - unsigned long *ptr = gdb_regs; - int reg; - - for (reg = 0; reg < 32; reg++) - UNPACK64(regs->gpr[reg], ptr); + { "r0", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[0]) }, + { "r1", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[1]) }, + { "r2", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[2]) }, + { "r3", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[3]) }, + { "r4", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[4]) }, + { "r5", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[5]) }, + { "r6", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[6]) }, + { "r7", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[7]) }, + { "r8", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[8]) }, + { "r9", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[9]) }, + { "r10", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[10]) }, + { "r11", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[11]) }, + { "r12", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[12]) }, + { "r13", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[13]) }, + { "r14", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[14]) }, + { "r15", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[15]) }, + { "r16", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[16]) }, + { "r17", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[17]) }, + { "r18", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[18]) }, + { "r19", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[19]) }, + { "r20", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[20]) }, + { "r21", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[21]) }, + { "r22", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[22]) }, + { "r23", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[23]) }, + { "r24", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[24]) }, + { "r25", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[25]) }, + { "r26", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[26]) }, + { "r27", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[27]) }, + { "r28", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[28]) }, + { "r29", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[29]) }, + { "r30", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[30]) }, + { "r31", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[31]) }, + + { "f0", GDB_SIZEOF_FLOAT_REG, 0 }, + { "f1", GDB_SIZEOF_FLOAT_REG, 1 }, + { "f2", GDB_SIZEOF_FLOAT_REG, 2 }, + { "f3", GDB_SIZEOF_FLOAT_REG, 3 }, + { "f4", GDB_SIZEOF_FLOAT_REG, 4 }, + { "f5", GDB_SIZEOF_FLOAT_REG, 5 }, + { "f6", GDB_SIZEOF_FLOAT_REG, 6 }, + { "f7", GDB_SIZEOF_FLOAT_REG, 7 }, + { "f8", GDB_SIZEOF_FLOAT_REG, 8 }, + { "f9", GDB_SIZEOF_FLOAT_REG, 9 }, + { "f10", GDB_SIZEOF_FLOAT_REG, 10 }, + { "f11", GDB_SIZEOF_FLOAT_REG, 11 }, + { "f12", GDB_SIZEOF_FLOAT_REG, 12 }, + { "f13", GDB_SIZEOF_FLOAT_REG, 13 }, + { "f14", GDB_SIZEOF_FLOAT_REG, 14 }, + { "f15", GDB_SIZEOF_FLOAT_REG, 15 }, + { "f16", GDB_SIZEOF_FLOAT_REG, 16 }, + { "f17", GDB_SIZEOF_FLOAT_REG, 17 }, + { "f18", GDB_SIZEOF_FLOAT_REG, 18 }, + { "f19", GDB_SIZEOF_FLOAT_REG, 19 }, + { "f20", GDB_SIZEOF_FLOAT_REG, 20 }, + { "f21", GDB_SIZEOF_FLOAT_REG, 21 }, + { "f22", GDB_SIZEOF_FLOAT_REG, 22 }, + { "f23", GDB_SIZEOF_FLOAT_REG, 23 }, + { "f24", GDB_SIZEOF_FLOAT_REG, 24 }, + { "f25", GDB_SIZEOF_FLOAT_REG, 25 }, + { "f26", GDB_SIZEOF_FLOAT_REG, 26 }, + { "f27", GDB_SIZEOF_FLOAT_REG, 27 }, + { "f28", GDB_SIZEOF_FLOAT_REG, 28 }, + { "f29", GDB_SIZEOF_FLOAT_REG, 29 }, + { "f30", GDB_SIZEOF_FLOAT_REG, 30 }, + { "f31", GDB_SIZEOF_FLOAT_REG, 31 }, + + { "pc", GDB_SIZEOF_REG, offsetof(struct pt_regs, nip) }, + { "msr", GDB_SIZEOF_REG, offsetof(struct pt_regs, msr) }, + { "cr", GDB_SIZEOF_REG_U32, offsetof(struct pt_regs, ccr) }, + { "lr", GDB_SIZEOF_REG, offsetof(struct pt_regs, link) }, + { "ctr", GDB_SIZEOF_REG_U32, offsetof(struct pt_regs, ctr) }, + { "xer", GDB_SIZEOF_REG, offsetof(struct pt_regs, xer) }, +}; -#ifdef CONFIG_FSL_BOOKE -#ifdef CONFIG_SPE - for (reg = 0; reg < 32; reg++) - UNPACK64(current->thread.evr[reg], ptr); +char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) +{ + if (regno >= DBG_MAX_REG_NUM || regno < 0) + return NULL; + + if (regno < 32 || regno >= 64) + /* First 0 -> 31 gpr registers*/ + /* pc, msr, ls... registers 64 -> 69 */ + memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, + dbg_reg_def[regno].size); + + if (regno >= 32 && regno < 64) { + /* FP registers 32 -> 63 */ +#if defined(CONFIG_FSL_BOOKE) && defined(CONFIG_SPE) + if (current) + memcpy(mem, current->thread.evr[regno-32], + dbg_reg_def[regno].size); #else - ptr += 32; + /* fp registers not used by kernel, leave zero */ + memset(mem, 0, dbg_reg_def[regno].size); #endif + } + + return dbg_reg_def[regno].name; +} + +int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) +{ + if (regno >= DBG_MAX_REG_NUM || regno < 0) + return -EINVAL; + + if (regno < 32 || regno >= 64) + /* First 0 -> 31 gpr registers*/ + /* pc, msr, ls... registers 64 -> 69 */ + memcpy((void *)regs + dbg_reg_def[regno].offset, mem, + dbg_reg_def[regno].size); + + if (regno >= 32 && regno < 64) { + /* FP registers 32 -> 63 */ +#if defined(CONFIG_FSL_BOOKE) && defined(CONFIG_SPE) + memcpy(current->thread.evr[regno-32], mem, + dbg_reg_def[regno].size); #else - /* fp registers not used by kernel, leave zero */ - ptr += 32 * 8 / sizeof(int); + /* fp registers not used by kernel, leave zero */ + return 0; #endif + } - UNPACK64(regs->nip, ptr); - UNPACK64(regs->msr, ptr); - UNPACK32(regs->ccr, ptr); - UNPACK64(regs->link, ptr); - UNPACK64(regs->ctr, ptr); - UNPACK32(regs->xer, ptr); - - BUG_ON((unsigned long)ptr > - (unsigned long)(((void *)gdb_regs) + NUMREGBYTES)); + return 0; } void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) -- cgit v1.2.3