diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/include/asm/kgdb.h | 6 | ||||
-rw-r--r-- | arch/arm/kernel/kgdb.c | 124 | ||||
-rw-r--r-- | arch/mips/include/asm/kgdb.h | 19 | ||||
-rw-r--r-- | arch/mips/kernel/kgdb.c | 211 | ||||
-rw-r--r-- | arch/powerpc/kernel/kgdb.c | 2 | ||||
-rw-r--r-- | arch/x86/include/asm/kgdb.h | 20 | ||||
-rw-r--r-- | arch/x86/kernel/kgdb.c | 189 |
7 files changed, 343 insertions, 228 deletions
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h index 67af4b8..0826599 100644 --- a/arch/arm/include/asm/kgdb.h +++ b/arch/arm/include/asm/kgdb.h @@ -70,11 +70,11 @@ extern int kgdb_fault_expected; #define _GP_REGS 16 #define _FP_REGS 8 #define _EXTRA_REGS 2 -#define GDB_MAX_REGS (_GP_REGS + (_FP_REGS * 3) + _EXTRA_REGS) +#define DBG_MAX_REG_NUM (_GP_REGS + (_FP_REGS * 3) + _EXTRA_REGS) #define KGDB_MAX_NO_CPUS 1 #define BUFMAX 400 -#define NUMREGBYTES (GDB_MAX_REGS << 2) +#define NUMREGBYTES (DBG_MAX_REG_NUM << 2) #define NUMCRITREGBYTES (32 << 2) #define _R0 0 @@ -93,7 +93,7 @@ extern int kgdb_fault_expected; #define _SPT 13 #define _LR 14 #define _PC 15 -#define _CPSR (GDB_MAX_REGS - 1) +#define _CPSR (DBG_MAX_REG_NUM - 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 c868a88..778c2f7 100644 --- a/arch/arm/kernel/kgdb.c +++ b/arch/arm/kernel/kgdb.c @@ -10,57 +10,62 @@ * Deepak Saxena <dsaxena@plexity.net> */ #include <linux/irq.h> +#include <linux/kdebug.h> #include <linux/kgdb.h> #include <asm/traps.h> -/* Make a local copy of the registers passed into the handler (bletch) */ -void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs) +struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = { - int regno; - - /* Initialize all to zero. */ - for (regno = 0; regno < GDB_MAX_REGS; regno++) - gdb_regs[regno] = 0; + { "r0", 4, offsetof(struct pt_regs, ARM_r0)}, + { "r1", 4, offsetof(struct pt_regs, ARM_r1)}, + { "r2", 4, offsetof(struct pt_regs, ARM_r2)}, + { "r3", 4, offsetof(struct pt_regs, ARM_r3)}, + { "r4", 4, offsetof(struct pt_regs, ARM_r4)}, + { "r5", 4, offsetof(struct pt_regs, ARM_r5)}, + { "r6", 4, offsetof(struct pt_regs, ARM_r6)}, + { "r7", 4, offsetof(struct pt_regs, ARM_r7)}, + { "r8", 4, offsetof(struct pt_regs, ARM_r8)}, + { "r9", 4, offsetof(struct pt_regs, ARM_r9)}, + { "r10", 4, offsetof(struct pt_regs, ARM_r10)}, + { "fp", 4, offsetof(struct pt_regs, ARM_fp)}, + { "ip", 4, offsetof(struct pt_regs, ARM_ip)}, + { "sp", 4, offsetof(struct pt_regs, ARM_sp)}, + { "lr", 4, offsetof(struct pt_regs, ARM_lr)}, + { "pc", 4, offsetof(struct pt_regs, ARM_pc)}, + { "f0", 12, -1 }, + { "f1", 12, -1 }, + { "f2", 12, -1 }, + { "f3", 12, -1 }, + { "f4", 12, -1 }, + { "f5", 12, -1 }, + { "f6", 12, -1 }, + { "f7", 12, -1 }, + { "fps", 4, -1 }, + { "cpsr", 4, offsetof(struct pt_regs, ARM_cpsr)}, +}; - gdb_regs[_R0] = kernel_regs->ARM_r0; - gdb_regs[_R1] = kernel_regs->ARM_r1; - gdb_regs[_R2] = kernel_regs->ARM_r2; - gdb_regs[_R3] = kernel_regs->ARM_r3; - gdb_regs[_R4] = kernel_regs->ARM_r4; - gdb_regs[_R5] = kernel_regs->ARM_r5; - gdb_regs[_R6] = kernel_regs->ARM_r6; - gdb_regs[_R7] = kernel_regs->ARM_r7; - gdb_regs[_R8] = kernel_regs->ARM_r8; - gdb_regs[_R9] = kernel_regs->ARM_r9; - gdb_regs[_R10] = kernel_regs->ARM_r10; - gdb_regs[_FP] = kernel_regs->ARM_fp; - gdb_regs[_IP] = kernel_regs->ARM_ip; - gdb_regs[_SPT] = kernel_regs->ARM_sp; - gdb_regs[_LR] = kernel_regs->ARM_lr; - gdb_regs[_PC] = kernel_regs->ARM_pc; - gdb_regs[_CPSR] = kernel_regs->ARM_cpsr; +char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) +{ + if (regno >= DBG_MAX_REG_NUM || regno < 0) + return NULL; + + if (dbg_reg_def[regno].offset != -1) + memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, + dbg_reg_def[regno].size); + else + memset(mem, 0, dbg_reg_def[regno].size); + return dbg_reg_def[regno].name; } -/* Copy local gdb registers back to kgdb regs, for later copy to kernel */ -void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs) +int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) { - kernel_regs->ARM_r0 = gdb_regs[_R0]; - kernel_regs->ARM_r1 = gdb_regs[_R1]; - kernel_regs->ARM_r2 = gdb_regs[_R2]; - kernel_regs->ARM_r3 = gdb_regs[_R3]; - kernel_regs->ARM_r4 = gdb_regs[_R4]; - kernel_regs->ARM_r5 = gdb_regs[_R5]; - kernel_regs->ARM_r6 = gdb_regs[_R6]; - kernel_regs->ARM_r7 = gdb_regs[_R7]; - kernel_regs->ARM_r8 = gdb_regs[_R8]; - kernel_regs->ARM_r9 = gdb_regs[_R9]; - kernel_regs->ARM_r10 = gdb_regs[_R10]; - kernel_regs->ARM_fp = gdb_regs[_FP]; - kernel_regs->ARM_ip = gdb_regs[_IP]; - kernel_regs->ARM_sp = gdb_regs[_SPT]; - kernel_regs->ARM_lr = gdb_regs[_LR]; - kernel_regs->ARM_pc = gdb_regs[_PC]; - kernel_regs->ARM_cpsr = gdb_regs[_CPSR]; + if (regno >= DBG_MAX_REG_NUM || regno < 0) + return -EINVAL; + + if (dbg_reg_def[regno].offset != -1) + memcpy((void *)regs + dbg_reg_def[regno].offset, mem, + dbg_reg_def[regno].size); + return 0; } void @@ -176,6 +181,33 @@ void kgdb_roundup_cpus(unsigned long flags) local_irq_disable(); } +static int __kgdb_notify(struct die_args *args, unsigned long cmd) +{ + struct pt_regs *regs = args->regs; + + if (kgdb_handle_exception(1, args->signr, cmd, regs)) + return NOTIFY_DONE; + return NOTIFY_STOP; +} +static int +kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr) +{ + unsigned long flags; + int ret; + + local_irq_save(flags); + ret = __kgdb_notify(ptr, cmd); + local_irq_restore(flags); + + return ret; +} + +static struct notifier_block kgdb_notifier = { + .notifier_call = kgdb_notify, + .priority = -INT_MAX, +}; + + /** * kgdb_arch_init - Perform any architecture specific initalization. * @@ -184,6 +216,11 @@ void kgdb_roundup_cpus(unsigned long flags) */ int kgdb_arch_init(void) { + int ret = register_die_notifier(&kgdb_notifier); + + if (ret != 0) + return ret; + register_undef_hook(&kgdb_brkpt_hook); register_undef_hook(&kgdb_compiled_brkpt_hook); @@ -200,6 +237,7 @@ void kgdb_arch_exit(void) { unregister_undef_hook(&kgdb_brkpt_hook); unregister_undef_hook(&kgdb_compiled_brkpt_hook); + unregister_die_notifier(&kgdb_notifier); } /* diff --git a/arch/mips/include/asm/kgdb.h b/arch/mips/include/asm/kgdb.h index 19002d6..e6c0b0e 100644 --- a/arch/mips/include/asm/kgdb.h +++ b/arch/mips/include/asm/kgdb.h @@ -8,28 +8,27 @@ #if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) || \ (_MIPS_ISA == _MIPS_ISA_MIPS32) -#define KGDB_GDB_REG_SIZE 32 +#define KGDB_GDB_REG_SIZE 32 +#define GDB_SIZEOF_REG sizeof(u32) #elif (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) || \ (_MIPS_ISA == _MIPS_ISA_MIPS64) #ifdef CONFIG_32BIT -#define KGDB_GDB_REG_SIZE 32 +#define KGDB_GDB_REG_SIZE 32 +#define GDB_SIZEOF_REG sizeof(u32) #else /* CONFIG_CPU_32BIT */ -#define KGDB_GDB_REG_SIZE 64 +#define KGDB_GDB_REG_SIZE 64 +#define GDB_SIZEOF_REG sizeof(u64) #endif #else #error "Need to set KGDB_GDB_REG_SIZE for MIPS ISA" #endif /* _MIPS_ISA */ #define BUFMAX 2048 -#if (KGDB_GDB_REG_SIZE == 32) -#define NUMREGBYTES (90*sizeof(u32)) -#define NUMCRITREGBYTES (12*sizeof(u32)) -#else -#define NUMREGBYTES (90*sizeof(u64)) -#define NUMCRITREGBYTES (12*sizeof(u64)) -#endif +#define DBG_MAX_REG_NUM 72 +#define NUMREGBYTES (DBG_MAX_REG_NUM * sizeof(GDB_SIZEOF_REG)) +#define NUMCRITREGBYTES (12 * sizeof(GDB_SIZEOF_REG)) #define BREAK_INSTR_SIZE 4 #define CACHE_FLUSH_IS_SAFE 0 diff --git a/arch/mips/kernel/kgdb.c b/arch/mips/kernel/kgdb.c index 9b78ff6..1f4e2fa 100644 --- a/arch/mips/kernel/kgdb.c +++ b/arch/mips/kernel/kgdb.c @@ -50,6 +50,151 @@ static struct hard_trap_info { { 0, 0} /* Must be last */ }; +struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = +{ + { "zero", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[0]) }, + { "at", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[1]) }, + { "v0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[2]) }, + { "v1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[3]) }, + { "a0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[4]) }, + { "a1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[5]) }, + { "a2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[6]) }, + { "a3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[7]) }, + { "t0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[8]) }, + { "t1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[9]) }, + { "t2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[10]) }, + { "t3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[11]) }, + { "t4", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[12]) }, + { "t5", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[13]) }, + { "t6", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[14]) }, + { "t7", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[15]) }, + { "s0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[16]) }, + { "s1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[17]) }, + { "s2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[18]) }, + { "s3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[19]) }, + { "s4", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[20]) }, + { "s5", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[21]) }, + { "s6", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[22]) }, + { "s7", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[23]) }, + { "t8", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[24]) }, + { "t9", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[25]) }, + { "k0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[26]) }, + { "k1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[27]) }, + { "gp", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[28]) }, + { "sp", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[29]) }, + { "s8", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[30]) }, + { "ra", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[31]) }, + { "sr", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_status) }, + { "lo", GDB_SIZEOF_REG, offsetof(struct pt_regs, lo) }, + { "hi", GDB_SIZEOF_REG, offsetof(struct pt_regs, hi) }, + { "bad", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_badvaddr) }, + { "cause", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_cause) }, + { "pc", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_epc) }, + { "f0", GDB_SIZEOF_REG, 0 }, + { "f1", GDB_SIZEOF_REG, 1 }, + { "f2", GDB_SIZEOF_REG, 2 }, + { "f3", GDB_SIZEOF_REG, 3 }, + { "f4", GDB_SIZEOF_REG, 4 }, + { "f5", GDB_SIZEOF_REG, 5 }, + { "f6", GDB_SIZEOF_REG, 6 }, + { "f7", GDB_SIZEOF_REG, 7 }, + { "f8", GDB_SIZEOF_REG, 8 }, + { "f9", GDB_SIZEOF_REG, 9 }, + { "f10", GDB_SIZEOF_REG, 10 }, + { "f11", GDB_SIZEOF_REG, 11 }, + { "f12", GDB_SIZEOF_REG, 12 }, + { "f13", GDB_SIZEOF_REG, 13 }, + { "f14", GDB_SIZEOF_REG, 14 }, + { "f15", GDB_SIZEOF_REG, 15 }, + { "f16", GDB_SIZEOF_REG, 16 }, + { "f17", GDB_SIZEOF_REG, 17 }, + { "f18", GDB_SIZEOF_REG, 18 }, + { "f19", GDB_SIZEOF_REG, 19 }, + { "f20", GDB_SIZEOF_REG, 20 }, + { "f21", GDB_SIZEOF_REG, 21 }, + { "f22", GDB_SIZEOF_REG, 22 }, + { "f23", GDB_SIZEOF_REG, 23 }, + { "f24", GDB_SIZEOF_REG, 24 }, + { "f25", GDB_SIZEOF_REG, 25 }, + { "f26", GDB_SIZEOF_REG, 26 }, + { "f27", GDB_SIZEOF_REG, 27 }, + { "f28", GDB_SIZEOF_REG, 28 }, + { "f29", GDB_SIZEOF_REG, 29 }, + { "f30", GDB_SIZEOF_REG, 30 }, + { "f31", GDB_SIZEOF_REG, 31 }, + { "fsr", GDB_SIZEOF_REG, 0 }, + { "fir", GDB_SIZEOF_REG, 0 }, +}; + +int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) +{ + int fp_reg; + + if (regno < 0 || regno >= DBG_MAX_REG_NUM) + return -EINVAL; + + if (dbg_reg_def[regno].offset != -1 && regno < 38) { + memcpy((void *)regs + dbg_reg_def[regno].offset, mem, + dbg_reg_def[regno].size); + } else if (current && dbg_reg_def[regno].offset != -1 && regno < 72) { + /* FP registers 38 -> 69 */ + if (!(regs->cp0_status & ST0_CU1)) + return 0; + if (regno == 70) { + /* Process the fcr31/fsr (register 70) */ + memcpy((void *)¤t->thread.fpu.fcr31, mem, + dbg_reg_def[regno].size); + goto out_save; + } else if (regno == 71) { + /* Ignore the fir (register 71) */ + goto out_save; + } + fp_reg = dbg_reg_def[regno].offset; + memcpy((void *)¤t->thread.fpu.fpr[fp_reg], mem, + dbg_reg_def[regno].size); +out_save: + restore_fp(current); + } + + return 0; +} + +char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) +{ + int fp_reg; + + if (regno >= DBG_MAX_REG_NUM || regno < 0) + return NULL; + + if (dbg_reg_def[regno].offset != -1 && regno < 38) { + /* First 38 registers */ + memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, + dbg_reg_def[regno].size); + } else if (current && dbg_reg_def[regno].offset != -1 && regno < 72) { + /* FP registers 38 -> 69 */ + if (!(regs->cp0_status & ST0_CU1)) + goto out; + save_fp(current); + if (regno == 70) { + /* Process the fcr31/fsr (register 70) */ + memcpy(mem, (void *)¤t->thread.fpu.fcr31, + dbg_reg_def[regno].size); + goto out; + } else if (regno == 71) { + /* Ignore the fir (register 71) */ + memset(mem, 0, dbg_reg_def[regno].size); + goto out; + } + fp_reg = dbg_reg_def[regno].offset; + memcpy(mem, (void *)¤t->thread.fpu.fpr[fp_reg], + dbg_reg_def[regno].size); + } + +out: + return dbg_reg_def[regno].name; + +} + void arch_kgdb_breakpoint(void) { __asm__ __volatile__( @@ -84,64 +229,6 @@ static int compute_signal(int tt) return SIGHUP; /* default for things we don't know about */ } -void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) -{ - int reg; - -#if (KGDB_GDB_REG_SIZE == 32) - u32 *ptr = (u32 *)gdb_regs; -#else - u64 *ptr = (u64 *)gdb_regs; -#endif - - for (reg = 0; reg < 32; reg++) - *(ptr++) = regs->regs[reg]; - - *(ptr++) = regs->cp0_status; - *(ptr++) = regs->lo; - *(ptr++) = regs->hi; - *(ptr++) = regs->cp0_badvaddr; - *(ptr++) = regs->cp0_cause; - *(ptr++) = regs->cp0_epc; - - /* FP REGS */ - if (!(current && (regs->cp0_status & ST0_CU1))) - return; - - save_fp(current); - for (reg = 0; reg < 32; reg++) - *(ptr++) = current->thread.fpu.fpr[reg]; -} - -void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) -{ - int reg; - -#if (KGDB_GDB_REG_SIZE == 32) - const u32 *ptr = (u32 *)gdb_regs; -#else - const u64 *ptr = (u64 *)gdb_regs; -#endif - - for (reg = 0; reg < 32; reg++) - regs->regs[reg] = *(ptr++); - - regs->cp0_status = *(ptr++); - regs->lo = *(ptr++); - regs->hi = *(ptr++); - regs->cp0_badvaddr = *(ptr++); - regs->cp0_cause = *(ptr++); - regs->cp0_epc = *(ptr++); - - /* FP REGS from current */ - if (!(current && (regs->cp0_status & ST0_CU1))) - return; - - for (reg = 0; reg < 32; reg++) - current->thread.fpu.fpr[reg] = *(ptr++); - restore_fp(current); -} - /* * Similar to regs_to_gdb_regs() except that process is sleeping and so * we may not be able to get all the info. @@ -242,7 +329,7 @@ static struct notifier_block kgdb_notifier = { }; /* - * Handle the 's' and 'c' commands + * Handle the 'c' command */ int kgdb_arch_handle_exception(int vector, int signo, int err_code, char *remcom_in_buffer, char *remcom_out_buffer, @@ -250,20 +337,14 @@ int kgdb_arch_handle_exception(int vector, int signo, int err_code, { char *ptr; unsigned long address; - int cpu = smp_processor_id(); switch (remcom_in_buffer[0]) { - case 's': case 'c': /* handle the optional parameter */ ptr = &remcom_in_buffer[1]; if (kgdb_hex2long(&ptr, &address)) regs->cp0_epc = address; - atomic_set(&kgdb_cpu_doing_single_step, -1); - if (remcom_in_buffer[0] == 's') - atomic_set(&kgdb_cpu_doing_single_step, cpu); - return 0; } diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c index 82a7b22..7f61a3a 100644 --- a/arch/powerpc/kernel/kgdb.c +++ b/arch/powerpc/kernel/kgdb.c @@ -129,7 +129,7 @@ static int kgdb_handle_breakpoint(struct pt_regs *regs) return 0; if (*(u32 *) (regs->nip) == *(u32 *) (&arch_kgdb_ops.gdb_bpt_instr)) - regs->nip += 4; + regs->nip += BREAK_INSTR_SIZE; return 1; } diff --git a/arch/x86/include/asm/kgdb.h b/arch/x86/include/asm/kgdb.h index 006da36..396f5b5 100644 --- a/arch/x86/include/asm/kgdb.h +++ b/arch/x86/include/asm/kgdb.h @@ -39,9 +39,11 @@ enum regnames { GDB_FS, /* 14 */ GDB_GS, /* 15 */ }; +#define GDB_ORIG_AX 41 +#define DBG_MAX_REG_NUM 16 #define NUMREGBYTES ((GDB_GS+1)*4) #else /* ! CONFIG_X86_32 */ -enum regnames64 { +enum regnames { GDB_AX, /* 0 */ GDB_BX, /* 1 */ GDB_CX, /* 2 */ @@ -59,15 +61,15 @@ enum regnames64 { GDB_R14, /* 14 */ GDB_R15, /* 15 */ GDB_PC, /* 16 */ + GDB_PS, /* 17 */ + GDB_CS, /* 18 */ + GDB_SS, /* 19 */ }; - -enum regnames32 { - GDB_PS = 34, - GDB_CS, - GDB_SS, -}; -#define NUMREGBYTES ((GDB_SS+1)*4) -#endif /* CONFIG_X86_32 */ +#define GDB_ORIG_AX 57 +#define DBG_MAX_REG_NUM 20 +/* 17 64 bit regs and 3 32 bit regs */ +#define NUMREGBYTES ((17 * 8) + (3 * 4)) +#endif /* ! CONFIG_X86_32 */ static inline void arch_kgdb_breakpoint(void) { diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index 01ab17a..ef10940 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c @@ -49,55 +49,94 @@ #include <asm/system.h> #include <asm/apic.h> -/** - * pt_regs_to_gdb_regs - Convert ptrace regs to GDB regs - * @gdb_regs: A pointer to hold the registers in the order GDB wants. - * @regs: The &struct pt_regs of the current process. - * - * Convert the pt_regs in @regs into the format for registers that - * GDB expects, stored in @gdb_regs. - */ -void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) +struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = { -#ifndef CONFIG_X86_32 - u32 *gdb_regs32 = (u32 *)gdb_regs; +#ifdef CONFIG_X86_32 + { "ax", 4, offsetof(struct pt_regs, ax) }, + { "cx", 4, offsetof(struct pt_regs, cx) }, + { "dx", 4, offsetof(struct pt_regs, dx) }, + { "bx", 4, offsetof(struct pt_regs, bx) }, + { "sp", 4, offsetof(struct pt_regs, sp) }, + { "bp", 4, offsetof(struct pt_regs, bp) }, + { "si", 4, offsetof(struct pt_regs, si) }, + { "di", 4, offsetof(struct pt_regs, di) }, + { "ip", 4, offsetof(struct pt_regs, ip) }, + { "flags", 4, offsetof(struct pt_regs, flags) }, + { "cs", 4, offsetof(struct pt_regs, cs) }, + { "ss", 4, offsetof(struct pt_regs, ss) }, + { "ds", 4, offsetof(struct pt_regs, ds) }, + { "es", 4, offsetof(struct pt_regs, es) }, + { "fs", 4, -1 }, + { "gs", 4, -1 }, +#else + { "ax", 8, offsetof(struct pt_regs, ax) }, + { "bx", 8, offsetof(struct pt_regs, bx) }, + { "cx", 8, offsetof(struct pt_regs, cx) }, + { "dx", 8, offsetof(struct pt_regs, dx) }, + { "si", 8, offsetof(struct pt_regs, dx) }, + { "di", 8, offsetof(struct pt_regs, di) }, + { "bp", 8, offsetof(struct pt_regs, bp) }, + { "sp", 8, offsetof(struct pt_regs, sp) }, + { "r8", 8, offsetof(struct pt_regs, r8) }, + { "r9", 8, offsetof(struct pt_regs, r9) }, + { "r10", 8, offsetof(struct pt_regs, r10) }, + { "r11", 8, offsetof(struct pt_regs, r11) }, + { "r12", 8, offsetof(struct pt_regs, r12) }, + { "r13", 8, offsetof(struct pt_regs, r13) }, + { "r14", 8, offsetof(struct pt_regs, r14) }, + { "r15", 8, offsetof(struct pt_regs, r15) }, + { "ip", 8, offsetof(struct pt_regs, ip) }, + { "flags", 4, offsetof(struct pt_regs, flags) }, + { "cs", 4, offsetof(struct pt_regs, cs) }, + { "ss", 4, offsetof(struct pt_regs, ss) }, #endif - gdb_regs[GDB_AX] = regs->ax; - gdb_regs[GDB_BX] = regs->bx; - gdb_regs[GDB_CX] = regs->cx; - gdb_regs[GDB_DX] = regs->dx; - gdb_regs[GDB_SI] = regs->si; - gdb_regs[GDB_DI] = regs->di; - gdb_regs[GDB_BP] = regs->bp; - gdb_regs[GDB_PC] = regs->ip; +}; + +int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) +{ + if ( #ifdef CONFIG_X86_32 - gdb_regs[GDB_PS] = regs->flags; - gdb_regs[GDB_DS] = regs->ds; - gdb_regs[GDB_ES] = regs->es; - gdb_regs[GDB_CS] = regs->cs; - gdb_regs[GDB_FS] = 0xFFFF; - gdb_regs[GDB_GS] = 0xFFFF; - if (user_mode_vm(regs)) { - gdb_regs[GDB_SS] = regs->ss; - gdb_regs[GDB_SP] = regs->sp; - } else { - gdb_regs[GDB_SS] = __KERNEL_DS; - gdb_regs[GDB_SP] = kernel_stack_pointer(regs); + regno == GDB_SS || regno == GDB_FS || regno == GDB_GS || +#endif + regno == GDB_SP || regno == GDB_ORIG_AX) + return 0; + + if (dbg_reg_def[regno].offset != -1) + memcpy((void *)regs + dbg_reg_def[regno].offset, mem, + dbg_reg_def[regno].size); + return 0; +} + +char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) +{ + if (regno == GDB_ORIG_AX) { + memcpy(mem, ®s->orig_ax, sizeof(regs->orig_ax)); + return "orig_ax"; } -#else - gdb_regs[GDB_R8] = regs->r8; - gdb_regs[GDB_R9] = regs->r9; - gdb_regs[GDB_R10] = regs->r10; - gdb_regs[GDB_R11] = regs->r11; - gdb_regs[GDB_R12] = regs->r12; - gdb_regs[GDB_R13] = regs->r13; - gdb_regs[GDB_R14] = regs->r14; - gdb_regs[GDB_R15] = regs->r15; - gdb_regs32[GDB_PS] = regs->flags; - gdb_regs32[GDB_CS] = regs->cs; - gdb_regs32[GDB_SS] = regs->ss; - gdb_regs[GDB_SP] = kernel_stack_pointer(regs); + if (regno >= DBG_MAX_REG_NUM || regno < 0) + return NULL; + + if (dbg_reg_def[regno].offset != -1) + memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, + dbg_reg_def[regno].size); + + switch (regno) { +#ifdef CONFIG_X86_32 + case GDB_SS: + if (!user_mode_vm(regs)) + *(unsigned long *)mem = __KERNEL_DS; + break; + case GDB_SP: + if (!user_mode_vm(regs)) + *(unsigned long *)mem = kernel_stack_pointer(regs); + break; + case GDB_GS: + case GDB_FS: + *(unsigned long *)mem = 0xFFFF; + break; #endif + } + return dbg_reg_def[regno].name; } /** @@ -150,54 +189,13 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) gdb_regs[GDB_SP] = p->thread.sp; } -/** - * gdb_regs_to_pt_regs - Convert GDB regs to ptrace regs. - * @gdb_regs: A pointer to hold the registers we've received from GDB. - * @regs: A pointer to a &struct pt_regs to hold these values in. - * - * Convert the GDB regs in @gdb_regs into the pt_regs, and store them - * in @regs. - */ -void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) -{ -#ifndef CONFIG_X86_32 - u32 *gdb_regs32 = (u32 *)gdb_regs; -#endif - regs->ax = gdb_regs[GDB_AX]; - regs->bx = gdb_regs[GDB_BX]; - regs->cx = gdb_regs[GDB_CX]; - regs->dx = gdb_regs[GDB_DX]; - regs->si = gdb_regs[GDB_SI]; - regs->di = gdb_regs[GDB_DI]; - regs->bp = gdb_regs[GDB_BP]; - regs->ip = gdb_regs[GDB_PC]; -#ifdef CONFIG_X86_32 - regs->flags = gdb_regs[GDB_PS]; - regs->ds = gdb_regs[GDB_DS]; - regs->es = gdb_regs[GDB_ES]; - regs->cs = gdb_regs[GDB_CS]; -#else - regs->r8 = gdb_regs[GDB_R8]; - regs->r9 = gdb_regs[GDB_R9]; - regs->r10 = gdb_regs[GDB_R10]; - regs->r11 = gdb_regs[GDB_R11]; - regs->r12 = gdb_regs[GDB_R12]; - regs->r13 = gdb_regs[GDB_R13]; - regs->r14 = gdb_regs[GDB_R14]; - regs->r15 = gdb_regs[GDB_R15]; - regs->flags = gdb_regs32[GDB_PS]; - regs->cs = gdb_regs32[GDB_CS]; - regs->ss = gdb_regs32[GDB_SS]; -#endif -} - static struct hw_breakpoint { unsigned enabled; unsigned long addr; int len; int type; struct perf_event **pev; -} breakinfo[4]; +} breakinfo[HBP_NUM]; static unsigned long early_dr7; @@ -205,7 +203,7 @@ static void kgdb_correct_hw_break(void) { int breakno; - for (breakno = 0; breakno < 4; breakno++) { + for (breakno = 0; breakno < HBP_NUM; breakno++) { struct perf_event *bp; struct arch_hw_breakpoint *info; int val; @@ -292,10 +290,10 @@ kgdb_remove_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype) { int i; - for (i = 0; i < 4; i++) + for (i = 0; i < HBP_NUM; i++) if (breakinfo[i].addr == addr && breakinfo[i].enabled) break; - if (i == 4) + if (i == HBP_NUM) return -1; if (hw_break_release_slot(i)) { @@ -313,7 +311,7 @@ static void kgdb_remove_all_hw_break(void) int cpu = raw_smp_processor_id(); struct perf_event *bp; - for (i = 0; i < 4; i++) { + for (i = 0; i < HBP_NUM; i++) { if (!breakinfo[i].enabled) continue; bp = *per_cpu_ptr(breakinfo[i].pev, cpu); @@ -333,10 +331,10 @@ kgdb_set_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype) { int i; - for (i = 0; i < 4; i++) + for (i = 0; i < HBP_NUM; i++) if (!breakinfo[i].enabled) break; - if (i == 4) + if (i == HBP_NUM) return -1; switch (bptype) { @@ -397,7 +395,7 @@ void kgdb_disable_hw_debug(struct pt_regs *regs) /* Disable hardware debugging while we are in kgdb: */ set_debugreg(0UL, 7); - for (i = 0; i < 4; i++) { + for (i = 0; i < HBP_NUM; i++) { if (!breakinfo[i].enabled) continue; if (dbg_is_early) { @@ -458,7 +456,6 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, { unsigned long addr; char *ptr; - int newPC; switch (remcomInBuffer[0]) { case 'c': @@ -469,8 +466,6 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, linux_regs->ip = addr; case 'D': case 'k': - newPC = linux_regs->ip; - /* clear the trace bit */ linux_regs->flags &= ~X86_EFLAGS_TF; atomic_set(&kgdb_cpu_doing_single_step, -1); @@ -645,7 +640,7 @@ void kgdb_arch_late(void) attr.bp_len = HW_BREAKPOINT_LEN_1; attr.bp_type = HW_BREAKPOINT_W; attr.disabled = 1; - for (i = 0; i < 4; i++) { + for (i = 0; i < HBP_NUM; i++) { if (breakinfo[i].pev) continue; breakinfo[i].pev = register_wide_hw_breakpoint(&attr, NULL); |