diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-05 18:59:48 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-05 18:59:48 -0400 |
| commit | 89a6c8cb9e6e11b6e3671dce7e037789b8f7cf62 (patch) | |
| tree | 12b16a8abe303fd86c156ddfbb86caa469e45a98 /arch | |
| parent | 03c0c29aff7e56b722eb6c47eace222b140d0377 (diff) | |
| parent | 3fa43aba08c5b5a4b407e402606fbe463239b14a (diff) | |
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/linux-2.6-kgdb
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/linux-2.6-kgdb:
debug_core,kdb: fix crash when arch does not have single step
kgdb,x86: use macro HBP_NUM to replace magic number 4
kgdb,mips: remove unused kgdb_cpu_doing_single_step operations
mm,kdb,kgdb: Add a debug reference for the kdb kmap usage
KGDB: Remove set but unused newPC
ftrace,kdb: Allow dumping a specific cpu's buffer with ftdump
ftrace,kdb: Extend kdb to be able to dump the ftrace buffer
kgdb,powerpc: Replace hardcoded offset by BREAK_INSTR_SIZE
arm,kgdb: Add ability to trap into debugger on notify_die
gdbstub: do not directly use dbg_reg_def[] in gdb_cmd_reg_set()
gdbstub: Implement gdbserial 'p' and 'P' packets
kgdb,arm: Individual register get/set for arm
kgdb,mips: Individual register get/set for mips
kgdb,x86: Individual register get/set for x86
kgdb,kdb: individual register set and and get API
gdbstub: Optimize kgdb's "thread:" response for the gdb serial protocol
kgdb: remove custom hex_to_bin()implementation
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 67af4b841984..08265993227f 100644 --- a/arch/arm/include/asm/kgdb.h +++ b/arch/arm/include/asm/kgdb.h | |||
| @@ -70,11 +70,11 @@ extern int kgdb_fault_expected; | |||
| 70 | #define _GP_REGS 16 | 70 | #define _GP_REGS 16 |
| 71 | #define _FP_REGS 8 | 71 | #define _FP_REGS 8 |
| 72 | #define _EXTRA_REGS 2 | 72 | #define _EXTRA_REGS 2 |
| 73 | #define GDB_MAX_REGS (_GP_REGS + (_FP_REGS * 3) + _EXTRA_REGS) | 73 | #define DBG_MAX_REG_NUM (_GP_REGS + (_FP_REGS * 3) + _EXTRA_REGS) |
| 74 | 74 | ||
| 75 | #define KGDB_MAX_NO_CPUS 1 | 75 | #define KGDB_MAX_NO_CPUS 1 |
| 76 | #define BUFMAX 400 | 76 | #define BUFMAX 400 |
| 77 | #define NUMREGBYTES (GDB_MAX_REGS << 2) | 77 | #define NUMREGBYTES (DBG_MAX_REG_NUM << 2) |
| 78 | #define NUMCRITREGBYTES (32 << 2) | 78 | #define NUMCRITREGBYTES (32 << 2) |
| 79 | 79 | ||
| 80 | #define _R0 0 | 80 | #define _R0 0 |
| @@ -93,7 +93,7 @@ extern int kgdb_fault_expected; | |||
| 93 | #define _SPT 13 | 93 | #define _SPT 13 |
| 94 | #define _LR 14 | 94 | #define _LR 14 |
| 95 | #define _PC 15 | 95 | #define _PC 15 |
| 96 | #define _CPSR (GDB_MAX_REGS - 1) | 96 | #define _CPSR (DBG_MAX_REG_NUM - 1) |
| 97 | 97 | ||
| 98 | /* | 98 | /* |
| 99 | * So that we can denote the end of a frame for tracing, | 99 | * 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 c868a8864117..778c2f7024ff 100644 --- a/arch/arm/kernel/kgdb.c +++ b/arch/arm/kernel/kgdb.c | |||
| @@ -10,57 +10,62 @@ | |||
| 10 | * Deepak Saxena <dsaxena@plexity.net> | 10 | * Deepak Saxena <dsaxena@plexity.net> |
| 11 | */ | 11 | */ |
| 12 | #include <linux/irq.h> | 12 | #include <linux/irq.h> |
| 13 | #include <linux/kdebug.h> | ||
| 13 | #include <linux/kgdb.h> | 14 | #include <linux/kgdb.h> |
| 14 | #include <asm/traps.h> | 15 | #include <asm/traps.h> |
| 15 | 16 | ||
| 16 | /* Make a local copy of the registers passed into the handler (bletch) */ | 17 | struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = |
| 17 | void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs) | ||
| 18 | { | 18 | { |
| 19 | int regno; | 19 | { "r0", 4, offsetof(struct pt_regs, ARM_r0)}, |
| 20 | 20 | { "r1", 4, offsetof(struct pt_regs, ARM_r1)}, | |
| 21 | /* Initialize all to zero. */ | 21 | { "r2", 4, offsetof(struct pt_regs, ARM_r2)}, |
| 22 | for (regno = 0; regno < GDB_MAX_REGS; regno++) | 22 | { "r3", 4, offsetof(struct pt_regs, ARM_r3)}, |
| 23 | gdb_regs[regno] = 0; | 23 | { "r4", 4, offsetof(struct pt_regs, ARM_r4)}, |
| 24 | { "r5", 4, offsetof(struct pt_regs, ARM_r5)}, | ||
| 25 | { "r6", 4, offsetof(struct pt_regs, ARM_r6)}, | ||
| 26 | { "r7", 4, offsetof(struct pt_regs, ARM_r7)}, | ||
| 27 | { "r8", 4, offsetof(struct pt_regs, ARM_r8)}, | ||
| 28 | { "r9", 4, offsetof(struct pt_regs, ARM_r9)}, | ||
| 29 | { "r10", 4, offsetof(struct pt_regs, ARM_r10)}, | ||
| 30 | { "fp", 4, offsetof(struct pt_regs, ARM_fp)}, | ||
| 31 | { "ip", 4, offsetof(struct pt_regs, ARM_ip)}, | ||
| 32 | { "sp", 4, offsetof(struct pt_regs, ARM_sp)}, | ||
| 33 | { "lr", 4, offsetof(struct pt_regs, ARM_lr)}, | ||
| 34 | { "pc", 4, offsetof(struct pt_regs, ARM_pc)}, | ||
| 35 | { "f0", 12, -1 }, | ||
| 36 | { "f1", 12, -1 }, | ||
| 37 | { "f2", 12, -1 }, | ||
| 38 | { "f3", 12, -1 }, | ||
| 39 | { "f4", 12, -1 }, | ||
| 40 | { "f5", 12, -1 }, | ||
| 41 | { "f6", 12, -1 }, | ||
| 42 | { "f7", 12, -1 }, | ||
| 43 | { "fps", 4, -1 }, | ||
| 44 | { "cpsr", 4, offsetof(struct pt_regs, ARM_cpsr)}, | ||
| 45 | }; | ||
| 24 | 46 | ||
| 25 | gdb_regs[_R0] = kernel_regs->ARM_r0; | 47 | char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) |
| 26 | gdb_regs[_R1] = kernel_regs->ARM_r1; | 48 | { |
| 27 | gdb_regs[_R2] = kernel_regs->ARM_r2; | 49 | if (regno >= DBG_MAX_REG_NUM || regno < 0) |
| 28 | gdb_regs[_R3] = kernel_regs->ARM_r3; | 50 | return NULL; |
| 29 | gdb_regs[_R4] = kernel_regs->ARM_r4; | 51 | |
| 30 | gdb_regs[_R5] = kernel_regs->ARM_r5; | 52 | if (dbg_reg_def[regno].offset != -1) |
| 31 | gdb_regs[_R6] = kernel_regs->ARM_r6; | 53 | memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, |
| 32 | gdb_regs[_R7] = kernel_regs->ARM_r7; | 54 | dbg_reg_def[regno].size); |
| 33 | gdb_regs[_R8] = kernel_regs->ARM_r8; | 55 | else |
| 34 | gdb_regs[_R9] = kernel_regs->ARM_r9; | 56 | memset(mem, 0, dbg_reg_def[regno].size); |
| 35 | gdb_regs[_R10] = kernel_regs->ARM_r10; | 57 | return dbg_reg_def[regno].name; |
| 36 | gdb_regs[_FP] = kernel_regs->ARM_fp; | ||
| 37 | gdb_regs[_IP] = kernel_regs->ARM_ip; | ||
| 38 | gdb_regs[_SPT] = kernel_regs->ARM_sp; | ||
| 39 | gdb_regs[_LR] = kernel_regs->ARM_lr; | ||
| 40 | gdb_regs[_PC] = kernel_regs->ARM_pc; | ||
| 41 | gdb_regs[_CPSR] = kernel_regs->ARM_cpsr; | ||
| 42 | } | 58 | } |
| 43 | 59 | ||
| 44 | /* Copy local gdb registers back to kgdb regs, for later copy to kernel */ | 60 | int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) |
| 45 | void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs) | ||
| 46 | { | 61 | { |
| 47 | kernel_regs->ARM_r0 = gdb_regs[_R0]; | 62 | if (regno >= DBG_MAX_REG_NUM || regno < 0) |
| 48 | kernel_regs->ARM_r1 = gdb_regs[_R1]; | 63 | return -EINVAL; |
| 49 | kernel_regs->ARM_r2 = gdb_regs[_R2]; | 64 | |
| 50 | kernel_regs->ARM_r3 = gdb_regs[_R3]; | 65 | if (dbg_reg_def[regno].offset != -1) |
| 51 | kernel_regs->ARM_r4 = gdb_regs[_R4]; | 66 | memcpy((void *)regs + dbg_reg_def[regno].offset, mem, |
| 52 | kernel_regs->ARM_r5 = gdb_regs[_R5]; | 67 | dbg_reg_def[regno].size); |
| 53 | kernel_regs->ARM_r6 = gdb_regs[_R6]; | 68 | return 0; |
| 54 | kernel_regs->ARM_r7 = gdb_regs[_R7]; | ||
| 55 | kernel_regs->ARM_r8 = gdb_regs[_R8]; | ||
| 56 | kernel_regs->ARM_r9 = gdb_regs[_R9]; | ||
| 57 | kernel_regs->ARM_r10 = gdb_regs[_R10]; | ||
| 58 | kernel_regs->ARM_fp = gdb_regs[_FP]; | ||
| 59 | kernel_regs->ARM_ip = gdb_regs[_IP]; | ||
| 60 | kernel_regs->ARM_sp = gdb_regs[_SPT]; | ||
| 61 | kernel_regs->ARM_lr = gdb_regs[_LR]; | ||
| 62 | kernel_regs->ARM_pc = gdb_regs[_PC]; | ||
| 63 | kernel_regs->ARM_cpsr = gdb_regs[_CPSR]; | ||
| 64 | } | 69 | } |
| 65 | 70 | ||
| 66 | void | 71 | void |
| @@ -176,6 +181,33 @@ void kgdb_roundup_cpus(unsigned long flags) | |||
| 176 | local_irq_disable(); | 181 | local_irq_disable(); |
| 177 | } | 182 | } |
| 178 | 183 | ||
| 184 | static int __kgdb_notify(struct die_args *args, unsigned long cmd) | ||
| 185 | { | ||
| 186 | struct pt_regs *regs = args->regs; | ||
| 187 | |||
| 188 | if (kgdb_handle_exception(1, args->signr, cmd, regs)) | ||
| 189 | return NOTIFY_DONE; | ||
| 190 | return NOTIFY_STOP; | ||
| 191 | } | ||
| 192 | static int | ||
| 193 | kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr) | ||
| 194 | { | ||
| 195 | unsigned long flags; | ||
| 196 | int ret; | ||
| 197 | |||
| 198 | local_irq_save(flags); | ||
| 199 | ret = __kgdb_notify(ptr, cmd); | ||
| 200 | local_irq_restore(flags); | ||
| 201 | |||
| 202 | return ret; | ||
| 203 | } | ||
| 204 | |||
| 205 | static struct notifier_block kgdb_notifier = { | ||
| 206 | .notifier_call = kgdb_notify, | ||
| 207 | .priority = -INT_MAX, | ||
| 208 | }; | ||
| 209 | |||
| 210 | |||
| 179 | /** | 211 | /** |
| 180 | * kgdb_arch_init - Perform any architecture specific initalization. | 212 | * kgdb_arch_init - Perform any architecture specific initalization. |
| 181 | * | 213 | * |
| @@ -184,6 +216,11 @@ void kgdb_roundup_cpus(unsigned long flags) | |||
| 184 | */ | 216 | */ |
| 185 | int kgdb_arch_init(void) | 217 | int kgdb_arch_init(void) |
| 186 | { | 218 | { |
| 219 | int ret = register_die_notifier(&kgdb_notifier); | ||
| 220 | |||
| 221 | if (ret != 0) | ||
| 222 | return ret; | ||
| 223 | |||
| 187 | register_undef_hook(&kgdb_brkpt_hook); | 224 | register_undef_hook(&kgdb_brkpt_hook); |
| 188 | register_undef_hook(&kgdb_compiled_brkpt_hook); | 225 | register_undef_hook(&kgdb_compiled_brkpt_hook); |
| 189 | 226 | ||
| @@ -200,6 +237,7 @@ void kgdb_arch_exit(void) | |||
| 200 | { | 237 | { |
| 201 | unregister_undef_hook(&kgdb_brkpt_hook); | 238 | unregister_undef_hook(&kgdb_brkpt_hook); |
| 202 | unregister_undef_hook(&kgdb_compiled_brkpt_hook); | 239 | unregister_undef_hook(&kgdb_compiled_brkpt_hook); |
| 240 | unregister_die_notifier(&kgdb_notifier); | ||
| 203 | } | 241 | } |
| 204 | 242 | ||
| 205 | /* | 243 | /* |
diff --git a/arch/mips/include/asm/kgdb.h b/arch/mips/include/asm/kgdb.h index 19002d605ac4..e6c0b0e14ccb 100644 --- a/arch/mips/include/asm/kgdb.h +++ b/arch/mips/include/asm/kgdb.h | |||
| @@ -8,28 +8,27 @@ | |||
| 8 | #if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) || \ | 8 | #if (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) || \ |
| 9 | (_MIPS_ISA == _MIPS_ISA_MIPS32) | 9 | (_MIPS_ISA == _MIPS_ISA_MIPS32) |
| 10 | 10 | ||
| 11 | #define KGDB_GDB_REG_SIZE 32 | 11 | #define KGDB_GDB_REG_SIZE 32 |
| 12 | #define GDB_SIZEOF_REG sizeof(u32) | ||
| 12 | 13 | ||
| 13 | #elif (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) || \ | 14 | #elif (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) || \ |
| 14 | (_MIPS_ISA == _MIPS_ISA_MIPS64) | 15 | (_MIPS_ISA == _MIPS_ISA_MIPS64) |
| 15 | 16 | ||
| 16 | #ifdef CONFIG_32BIT | 17 | #ifdef CONFIG_32BIT |
| 17 | #define KGDB_GDB_REG_SIZE 32 | 18 | #define KGDB_GDB_REG_SIZE 32 |
| 19 | #define GDB_SIZEOF_REG sizeof(u32) | ||
| 18 | #else /* CONFIG_CPU_32BIT */ | 20 | #else /* CONFIG_CPU_32BIT */ |
| 19 | #define KGDB_GDB_REG_SIZE 64 | 21 | #define KGDB_GDB_REG_SIZE 64 |
| 22 | #define GDB_SIZEOF_REG sizeof(u64) | ||
| 20 | #endif | 23 | #endif |
| 21 | #else | 24 | #else |
| 22 | #error "Need to set KGDB_GDB_REG_SIZE for MIPS ISA" | 25 | #error "Need to set KGDB_GDB_REG_SIZE for MIPS ISA" |
| 23 | #endif /* _MIPS_ISA */ | 26 | #endif /* _MIPS_ISA */ |
| 24 | 27 | ||
| 25 | #define BUFMAX 2048 | 28 | #define BUFMAX 2048 |
| 26 | #if (KGDB_GDB_REG_SIZE == 32) | 29 | #define DBG_MAX_REG_NUM 72 |
| 27 | #define NUMREGBYTES (90*sizeof(u32)) | 30 | #define NUMREGBYTES (DBG_MAX_REG_NUM * sizeof(GDB_SIZEOF_REG)) |
| 28 | #define NUMCRITREGBYTES (12*sizeof(u32)) | 31 | #define NUMCRITREGBYTES (12 * sizeof(GDB_SIZEOF_REG)) |
| 29 | #else | ||
| 30 | #define NUMREGBYTES (90*sizeof(u64)) | ||
| 31 | #define NUMCRITREGBYTES (12*sizeof(u64)) | ||
| 32 | #endif | ||
| 33 | #define BREAK_INSTR_SIZE 4 | 32 | #define BREAK_INSTR_SIZE 4 |
| 34 | #define CACHE_FLUSH_IS_SAFE 0 | 33 | #define CACHE_FLUSH_IS_SAFE 0 |
| 35 | 34 | ||
diff --git a/arch/mips/kernel/kgdb.c b/arch/mips/kernel/kgdb.c index 9b78ff6e9b84..1f4e2fa64140 100644 --- a/arch/mips/kernel/kgdb.c +++ b/arch/mips/kernel/kgdb.c | |||
| @@ -50,6 +50,151 @@ static struct hard_trap_info { | |||
| 50 | { 0, 0} /* Must be last */ | 50 | { 0, 0} /* Must be last */ |
| 51 | }; | 51 | }; |
| 52 | 52 | ||
| 53 | struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = | ||
| 54 | { | ||
| 55 | { "zero", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[0]) }, | ||
| 56 | { "at", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[1]) }, | ||
| 57 | { "v0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[2]) }, | ||
| 58 | { "v1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[3]) }, | ||
| 59 | { "a0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[4]) }, | ||
| 60 | { "a1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[5]) }, | ||
| 61 | { "a2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[6]) }, | ||
| 62 | { "a3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[7]) }, | ||
| 63 | { "t0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[8]) }, | ||
| 64 | { "t1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[9]) }, | ||
| 65 | { "t2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[10]) }, | ||
| 66 | { "t3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[11]) }, | ||
| 67 | { "t4", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[12]) }, | ||
| 68 | { "t5", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[13]) }, | ||
| 69 | { "t6", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[14]) }, | ||
| 70 | { "t7", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[15]) }, | ||
| 71 | { "s0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[16]) }, | ||
| 72 | { "s1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[17]) }, | ||
| 73 | { "s2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[18]) }, | ||
| 74 | { "s3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[19]) }, | ||
| 75 | { "s4", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[20]) }, | ||
| 76 | { "s5", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[21]) }, | ||
| 77 | { "s6", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[22]) }, | ||
| 78 | { "s7", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[23]) }, | ||
| 79 | { "t8", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[24]) }, | ||
| 80 | { "t9", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[25]) }, | ||
| 81 | { "k0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[26]) }, | ||
| 82 | { "k1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[27]) }, | ||
| 83 | { "gp", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[28]) }, | ||
| 84 | { "sp", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[29]) }, | ||
| 85 | { "s8", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[30]) }, | ||
| 86 | { "ra", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[31]) }, | ||
| 87 | { "sr", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_status) }, | ||
| 88 | { "lo", GDB_SIZEOF_REG, offsetof(struct pt_regs, lo) }, | ||
| 89 | { "hi", GDB_SIZEOF_REG, offsetof(struct pt_regs, hi) }, | ||
| 90 | { "bad", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_badvaddr) }, | ||
| 91 | { "cause", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_cause) }, | ||
| 92 | { "pc", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_epc) }, | ||
| 93 | { "f0", GDB_SIZEOF_REG, 0 }, | ||
| 94 | { "f1", GDB_SIZEOF_REG, 1 }, | ||
| 95 | { "f2", GDB_SIZEOF_REG, 2 }, | ||
| 96 | { "f3", GDB_SIZEOF_REG, 3 }, | ||
| 97 | { "f4", GDB_SIZEOF_REG, 4 }, | ||
| 98 | { "f5", GDB_SIZEOF_REG, 5 }, | ||
| 99 | { "f6", GDB_SIZEOF_REG, 6 }, | ||
| 100 | { "f7", GDB_SIZEOF_REG, 7 }, | ||
| 101 | { "f8", GDB_SIZEOF_REG, 8 }, | ||
| 102 | { "f9", GDB_SIZEOF_REG, 9 }, | ||
| 103 | { "f10", GDB_SIZEOF_REG, 10 }, | ||
| 104 | { "f11", GDB_SIZEOF_REG, 11 }, | ||
| 105 | { "f12", GDB_SIZEOF_REG, 12 }, | ||
| 106 | { "f13", GDB_SIZEOF_REG, 13 }, | ||
| 107 | { "f14", GDB_SIZEOF_REG, 14 }, | ||
| 108 | { "f15", GDB_SIZEOF_REG, 15 }, | ||
| 109 | { "f16", GDB_SIZEOF_REG, 16 }, | ||
| 110 | { "f17", GDB_SIZEOF_REG, 17 }, | ||
| 111 | { "f18", GDB_SIZEOF_REG, 18 }, | ||
| 112 | { "f19", GDB_SIZEOF_REG, 19 }, | ||
| 113 | { "f20", GDB_SIZEOF_REG, 20 }, | ||
| 114 | { "f21", GDB_SIZEOF_REG, 21 }, | ||
| 115 | { "f22", GDB_SIZEOF_REG, 22 }, | ||
| 116 | { "f23", GDB_SIZEOF_REG, 23 }, | ||
| 117 | { "f24", GDB_SIZEOF_REG, 24 }, | ||
| 118 | { "f25", GDB_SIZEOF_REG, 25 }, | ||
| 119 | { "f26", GDB_SIZEOF_REG, 26 }, | ||
| 120 | { "f27", GDB_SIZEOF_REG, 27 }, | ||
| 121 | { "f28", GDB_SIZEOF_REG, 28 }, | ||
| 122 | { "f29", GDB_SIZEOF_REG, 29 }, | ||
| 123 | { "f30", GDB_SIZEOF_REG, 30 }, | ||
| 124 | { "f31", GDB_SIZEOF_REG, 31 }, | ||
| 125 | { "fsr", GDB_SIZEOF_REG, 0 }, | ||
| 126 | { "fir", GDB_SIZEOF_REG, 0 }, | ||
| 127 | }; | ||
| 128 | |||
| 129 | int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) | ||
| 130 | { | ||
| 131 | int fp_reg; | ||
| 132 | |||
| 133 | if (regno < 0 || regno >= DBG_MAX_REG_NUM) | ||
| 134 | return -EINVAL; | ||
| 135 | |||
| 136 | if (dbg_reg_def[regno].offset != -1 && regno < 38) { | ||
| 137 | memcpy((void *)regs + dbg_reg_def[regno].offset, mem, | ||
| 138 | dbg_reg_def[regno].size); | ||
| 139 | } else if (current && dbg_reg_def[regno].offset != -1 && regno < 72) { | ||
| 140 | /* FP registers 38 -> 69 */ | ||
| 141 | if (!(regs->cp0_status & ST0_CU1)) | ||
| 142 | return 0; | ||
| 143 | if (regno == 70) { | ||
| 144 | /* Process the fcr31/fsr (register 70) */ | ||
| 145 | memcpy((void *)¤t->thread.fpu.fcr31, mem, | ||
| 146 | dbg_reg_def[regno].size); | ||
| 147 | goto out_save; | ||
| 148 | } else if (regno == 71) { | ||
| 149 | /* Ignore the fir (register 71) */ | ||
| 150 | goto out_save; | ||
| 151 | } | ||
| 152 | fp_reg = dbg_reg_def[regno].offset; | ||
| 153 | memcpy((void *)¤t->thread.fpu.fpr[fp_reg], mem, | ||
| 154 | dbg_reg_def[regno].size); | ||
| 155 | out_save: | ||
| 156 | restore_fp(current); | ||
| 157 | } | ||
| 158 | |||
| 159 | return 0; | ||
| 160 | } | ||
| 161 | |||
| 162 | char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) | ||
| 163 | { | ||
| 164 | int fp_reg; | ||
| 165 | |||
| 166 | if (regno >= DBG_MAX_REG_NUM || regno < 0) | ||
| 167 | return NULL; | ||
| 168 | |||
| 169 | if (dbg_reg_def[regno].offset != -1 && regno < 38) { | ||
| 170 | /* First 38 registers */ | ||
| 171 | memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, | ||
| 172 | dbg_reg_def[regno].size); | ||
| 173 | } else if (current && dbg_reg_def[regno].offset != -1 && regno < 72) { | ||
| 174 | /* FP registers 38 -> 69 */ | ||
| 175 | if (!(regs->cp0_status & ST0_CU1)) | ||
| 176 | goto out; | ||
| 177 | save_fp(current); | ||
| 178 | if (regno == 70) { | ||
| 179 | /* Process the fcr31/fsr (register 70) */ | ||
| 180 | memcpy(mem, (void *)¤t->thread.fpu.fcr31, | ||
| 181 | dbg_reg_def[regno].size); | ||
| 182 | goto out; | ||
| 183 | } else if (regno == 71) { | ||
| 184 | /* Ignore the fir (register 71) */ | ||
| 185 | memset(mem, 0, dbg_reg_def[regno].size); | ||
| 186 | goto out; | ||
| 187 | } | ||
| 188 | fp_reg = dbg_reg_def[regno].offset; | ||
| 189 | memcpy(mem, (void *)¤t->thread.fpu.fpr[fp_reg], | ||
| 190 | dbg_reg_def[regno].size); | ||
| 191 | } | ||
| 192 | |||
| 193 | out: | ||
| 194 | return dbg_reg_def[regno].name; | ||
| 195 | |||
| 196 | } | ||
| 197 | |||
| 53 | void arch_kgdb_breakpoint(void) | 198 | void arch_kgdb_breakpoint(void) |
| 54 | { | 199 | { |
| 55 | __asm__ __volatile__( | 200 | __asm__ __volatile__( |
| @@ -84,64 +229,6 @@ static int compute_signal(int tt) | |||
| 84 | return SIGHUP; /* default for things we don't know about */ | 229 | return SIGHUP; /* default for things we don't know about */ |
| 85 | } | 230 | } |
| 86 | 231 | ||
| 87 | void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
| 88 | { | ||
| 89 | int reg; | ||
| 90 | |||
| 91 | #if (KGDB_GDB_REG_SIZE == 32) | ||
| 92 | u32 *ptr = (u32 *)gdb_regs; | ||
| 93 | #else | ||
| 94 | u64 *ptr = (u64 *)gdb_regs; | ||
| 95 | #endif | ||
| 96 | |||
| 97 | for (reg = 0; reg < 32; reg++) | ||
| 98 | *(ptr++) = regs->regs[reg]; | ||
| 99 | |||
| 100 | *(ptr++) = regs->cp0_status; | ||
| 101 | *(ptr++) = regs->lo; | ||
| 102 | *(ptr++) = regs->hi; | ||
| 103 | *(ptr++) = regs->cp0_badvaddr; | ||
| 104 | *(ptr++) = regs->cp0_cause; | ||
| 105 | *(ptr++) = regs->cp0_epc; | ||
| 106 | |||
| 107 | /* FP REGS */ | ||
| 108 | if (!(current && (regs->cp0_status & ST0_CU1))) | ||
| 109 | return; | ||
| 110 | |||
| 111 | save_fp(current); | ||
| 112 | for (reg = 0; reg < 32; reg++) | ||
| 113 | *(ptr++) = current->thread.fpu.fpr[reg]; | ||
| 114 | } | ||
| 115 | |||
| 116 | void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
| 117 | { | ||
| 118 | int reg; | ||
| 119 | |||
| 120 | #if (KGDB_GDB_REG_SIZE == 32) | ||
| 121 | const u32 *ptr = (u32 *)gdb_regs; | ||
| 122 | #else | ||
| 123 | const u64 *ptr = (u64 *)gdb_regs; | ||
| 124 | #endif | ||
| 125 | |||
| 126 | for (reg = 0; reg < 32; reg++) | ||
| 127 | regs->regs[reg] = *(ptr++); | ||
| 128 | |||
| 129 | regs->cp0_status = *(ptr++); | ||
| 130 | regs->lo = *(ptr++); | ||
| 131 | regs->hi = *(ptr++); | ||
| 132 | regs->cp0_badvaddr = *(ptr++); | ||
| 133 | regs->cp0_cause = *(ptr++); | ||
| 134 | regs->cp0_epc = *(ptr++); | ||
| 135 | |||
| 136 | /* FP REGS from current */ | ||
| 137 | if (!(current && (regs->cp0_status & ST0_CU1))) | ||
| 138 | return; | ||
| 139 | |||
| 140 | for (reg = 0; reg < 32; reg++) | ||
| 141 | current->thread.fpu.fpr[reg] = *(ptr++); | ||
| 142 | restore_fp(current); | ||
| 143 | } | ||
| 144 | |||
| 145 | /* | 232 | /* |
| 146 | * Similar to regs_to_gdb_regs() except that process is sleeping and so | 233 | * Similar to regs_to_gdb_regs() except that process is sleeping and so |
| 147 | * we may not be able to get all the info. | 234 | * we may not be able to get all the info. |
| @@ -242,7 +329,7 @@ static struct notifier_block kgdb_notifier = { | |||
| 242 | }; | 329 | }; |
| 243 | 330 | ||
| 244 | /* | 331 | /* |
| 245 | * Handle the 's' and 'c' commands | 332 | * Handle the 'c' command |
| 246 | */ | 333 | */ |
| 247 | int kgdb_arch_handle_exception(int vector, int signo, int err_code, | 334 | int kgdb_arch_handle_exception(int vector, int signo, int err_code, |
| 248 | char *remcom_in_buffer, char *remcom_out_buffer, | 335 | char *remcom_in_buffer, char *remcom_out_buffer, |
| @@ -250,20 +337,14 @@ int kgdb_arch_handle_exception(int vector, int signo, int err_code, | |||
| 250 | { | 337 | { |
| 251 | char *ptr; | 338 | char *ptr; |
| 252 | unsigned long address; | 339 | unsigned long address; |
| 253 | int cpu = smp_processor_id(); | ||
| 254 | 340 | ||
| 255 | switch (remcom_in_buffer[0]) { | 341 | switch (remcom_in_buffer[0]) { |
| 256 | case 's': | ||
| 257 | case 'c': | 342 | case 'c': |
| 258 | /* handle the optional parameter */ | 343 | /* handle the optional parameter */ |
| 259 | ptr = &remcom_in_buffer[1]; | 344 | ptr = &remcom_in_buffer[1]; |
| 260 | if (kgdb_hex2long(&ptr, &address)) | 345 | if (kgdb_hex2long(&ptr, &address)) |
| 261 | regs->cp0_epc = address; | 346 | regs->cp0_epc = address; |
| 262 | 347 | ||
| 263 | atomic_set(&kgdb_cpu_doing_single_step, -1); | ||
| 264 | if (remcom_in_buffer[0] == 's') | ||
| 265 | atomic_set(&kgdb_cpu_doing_single_step, cpu); | ||
| 266 | |||
| 267 | return 0; | 348 | return 0; |
| 268 | } | 349 | } |
| 269 | 350 | ||
diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c index 82a7b228c81a..7f61a3ac787c 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) | |||
| 129 | return 0; | 129 | return 0; |
| 130 | 130 | ||
| 131 | if (*(u32 *) (regs->nip) == *(u32 *) (&arch_kgdb_ops.gdb_bpt_instr)) | 131 | if (*(u32 *) (regs->nip) == *(u32 *) (&arch_kgdb_ops.gdb_bpt_instr)) |
| 132 | regs->nip += 4; | 132 | regs->nip += BREAK_INSTR_SIZE; |
| 133 | 133 | ||
| 134 | return 1; | 134 | return 1; |
| 135 | } | 135 | } |
diff --git a/arch/x86/include/asm/kgdb.h b/arch/x86/include/asm/kgdb.h index 006da3687cdc..396f5b5fc4d7 100644 --- a/arch/x86/include/asm/kgdb.h +++ b/arch/x86/include/asm/kgdb.h | |||
| @@ -39,9 +39,11 @@ enum regnames { | |||
| 39 | GDB_FS, /* 14 */ | 39 | GDB_FS, /* 14 */ |
| 40 | GDB_GS, /* 15 */ | 40 | GDB_GS, /* 15 */ |
| 41 | }; | 41 | }; |
| 42 | #define GDB_ORIG_AX 41 | ||
| 43 | #define DBG_MAX_REG_NUM 16 | ||
| 42 | #define NUMREGBYTES ((GDB_GS+1)*4) | 44 | #define NUMREGBYTES ((GDB_GS+1)*4) |
| 43 | #else /* ! CONFIG_X86_32 */ | 45 | #else /* ! CONFIG_X86_32 */ |
| 44 | enum regnames64 { | 46 | enum regnames { |
| 45 | GDB_AX, /* 0 */ | 47 | GDB_AX, /* 0 */ |
| 46 | GDB_BX, /* 1 */ | 48 | GDB_BX, /* 1 */ |
| 47 | GDB_CX, /* 2 */ | 49 | GDB_CX, /* 2 */ |
| @@ -59,15 +61,15 @@ enum regnames64 { | |||
| 59 | GDB_R14, /* 14 */ | 61 | GDB_R14, /* 14 */ |
| 60 | GDB_R15, /* 15 */ | 62 | GDB_R15, /* 15 */ |
| 61 | GDB_PC, /* 16 */ | 63 | GDB_PC, /* 16 */ |
| 64 | GDB_PS, /* 17 */ | ||
| 65 | GDB_CS, /* 18 */ | ||
| 66 | GDB_SS, /* 19 */ | ||
| 62 | }; | 67 | }; |
| 63 | 68 | #define GDB_ORIG_AX 57 | |
| 64 | enum regnames32 { | 69 | #define DBG_MAX_REG_NUM 20 |
| 65 | GDB_PS = 34, | 70 | /* 17 64 bit regs and 3 32 bit regs */ |
| 66 | GDB_CS, | 71 | #define NUMREGBYTES ((17 * 8) + (3 * 4)) |
| 67 | GDB_SS, | 72 | #endif /* ! CONFIG_X86_32 */ |
| 68 | }; | ||
| 69 | #define NUMREGBYTES ((GDB_SS+1)*4) | ||
| 70 | #endif /* CONFIG_X86_32 */ | ||
| 71 | 73 | ||
| 72 | static inline void arch_kgdb_breakpoint(void) | 74 | static inline void arch_kgdb_breakpoint(void) |
| 73 | { | 75 | { |
diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index 01ab17ae2ae7..ef10940e1af0 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c | |||
| @@ -49,55 +49,94 @@ | |||
| 49 | #include <asm/system.h> | 49 | #include <asm/system.h> |
| 50 | #include <asm/apic.h> | 50 | #include <asm/apic.h> |
| 51 | 51 | ||
| 52 | /** | 52 | struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = |
| 53 | * pt_regs_to_gdb_regs - Convert ptrace regs to GDB regs | ||
| 54 | * @gdb_regs: A pointer to hold the registers in the order GDB wants. | ||
| 55 | * @regs: The &struct pt_regs of the current process. | ||
| 56 | * | ||
| 57 | * Convert the pt_regs in @regs into the format for registers that | ||
| 58 | * GDB expects, stored in @gdb_regs. | ||
| 59 | */ | ||
| 60 | void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
| 61 | { | 53 | { |
| 62 | #ifndef CONFIG_X86_32 | 54 | #ifdef CONFIG_X86_32 |
| 63 | u32 *gdb_regs32 = (u32 *)gdb_regs; | 55 | { "ax", 4, offsetof(struct pt_regs, ax) }, |
| 56 | { "cx", 4, offsetof(struct pt_regs, cx) }, | ||
| 57 | { "dx", 4, offsetof(struct pt_regs, dx) }, | ||
| 58 | { "bx", 4, offsetof(struct pt_regs, bx) }, | ||
| 59 | { "sp", 4, offsetof(struct pt_regs, sp) }, | ||
| 60 | { "bp", 4, offsetof(struct pt_regs, bp) }, | ||
| 61 | { "si", 4, offsetof(struct pt_regs, si) }, | ||
| 62 | { "di", 4, offsetof(struct pt_regs, di) }, | ||
| 63 | { "ip", 4, offsetof(struct pt_regs, ip) }, | ||
| 64 | { "flags", 4, offsetof(struct pt_regs, flags) }, | ||
| 65 | { "cs", 4, offsetof(struct pt_regs, cs) }, | ||
| 66 | { "ss", 4, offsetof(struct pt_regs, ss) }, | ||
| 67 | { "ds", 4, offsetof(struct pt_regs, ds) }, | ||
| 68 | { "es", 4, offsetof(struct pt_regs, es) }, | ||
| 69 | { "fs", 4, -1 }, | ||
| 70 | { "gs", 4, -1 }, | ||
| 71 | #else | ||
| 72 | { "ax", 8, offsetof(struct pt_regs, ax) }, | ||
| 73 | { "bx", 8, offsetof(struct pt_regs, bx) }, | ||
| 74 | { "cx", 8, offsetof(struct pt_regs, cx) }, | ||
| 75 | { "dx", 8, offsetof(struct pt_regs, dx) }, | ||
| 76 | { "si", 8, offsetof(struct pt_regs, dx) }, | ||
| 77 | { "di", 8, offsetof(struct pt_regs, di) }, | ||
| 78 | { "bp", 8, offsetof(struct pt_regs, bp) }, | ||
| 79 | { "sp", 8, offsetof(struct pt_regs, sp) }, | ||
| 80 | { "r8", 8, offsetof(struct pt_regs, r8) }, | ||
| 81 | { "r9", 8, offsetof(struct pt_regs, r9) }, | ||
| 82 | { "r10", 8, offsetof(struct pt_regs, r10) }, | ||
| 83 | { "r11", 8, offsetof(struct pt_regs, r11) }, | ||
| 84 | { "r12", 8, offsetof(struct pt_regs, r12) }, | ||
| 85 | { "r13", 8, offsetof(struct pt_regs, r13) }, | ||
| 86 | { "r14", 8, offsetof(struct pt_regs, r14) }, | ||
| 87 | { "r15", 8, offsetof(struct pt_regs, r15) }, | ||
| 88 | { "ip", 8, offsetof(struct pt_regs, ip) }, | ||
| 89 | { "flags", 4, offsetof(struct pt_regs, flags) }, | ||
| 90 | { "cs", 4, offsetof(struct pt_regs, cs) }, | ||
| 91 | { "ss", 4, offsetof(struct pt_regs, ss) }, | ||
| 64 | #endif | 92 | #endif |
| 65 | gdb_regs[GDB_AX] = regs->ax; | 93 | }; |
| 66 | gdb_regs[GDB_BX] = regs->bx; | 94 | |
| 67 | gdb_regs[GDB_CX] = regs->cx; | 95 | int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) |
| 68 | gdb_regs[GDB_DX] = regs->dx; | 96 | { |
| 69 | gdb_regs[GDB_SI] = regs->si; | 97 | if ( |
| 70 | gdb_regs[GDB_DI] = regs->di; | ||
| 71 | gdb_regs[GDB_BP] = regs->bp; | ||
| 72 | gdb_regs[GDB_PC] = regs->ip; | ||
| 73 | #ifdef CONFIG_X86_32 | 98 | #ifdef CONFIG_X86_32 |
| 74 | gdb_regs[GDB_PS] = regs->flags; | 99 | regno == GDB_SS || regno == GDB_FS || regno == GDB_GS || |
| 75 | gdb_regs[GDB_DS] = regs->ds; | 100 | #endif |
| 76 | gdb_regs[GDB_ES] = regs->es; | 101 | regno == GDB_SP || regno == GDB_ORIG_AX) |
| 77 | gdb_regs[GDB_CS] = regs->cs; | 102 | return 0; |
| 78 | gdb_regs[GDB_FS] = 0xFFFF; | 103 | |
| 79 | gdb_regs[GDB_GS] = 0xFFFF; | 104 | if (dbg_reg_def[regno].offset != -1) |
| 80 | if (user_mode_vm(regs)) { | 105 | memcpy((void *)regs + dbg_reg_def[regno].offset, mem, |
| 81 | gdb_regs[GDB_SS] = regs->ss; | 106 | dbg_reg_def[regno].size); |
| 82 | gdb_regs[GDB_SP] = regs->sp; | 107 | return 0; |
| 83 | } else { | 108 | } |
| 84 | gdb_regs[GDB_SS] = __KERNEL_DS; | 109 | |
| 85 | gdb_regs[GDB_SP] = kernel_stack_pointer(regs); | 110 | char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) |
| 111 | { | ||
| 112 | if (regno == GDB_ORIG_AX) { | ||
| 113 | memcpy(mem, ®s->orig_ax, sizeof(regs->orig_ax)); | ||
| 114 | return "orig_ax"; | ||
| 86 | } | 115 | } |
| 87 | #else | 116 | if (regno >= DBG_MAX_REG_NUM || regno < 0) |
| 88 | gdb_regs[GDB_R8] = regs->r8; | 117 | return NULL; |
| 89 | gdb_regs[GDB_R9] = regs->r9; | 118 | |
| 90 | gdb_regs[GDB_R10] = regs->r10; | 119 | if (dbg_reg_def[regno].offset != -1) |
| 91 | gdb_regs[GDB_R11] = regs->r11; | 120 | memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, |
| 92 | gdb_regs[GDB_R12] = regs->r12; | 121 | dbg_reg_def[regno].size); |
| 93 | gdb_regs[GDB_R13] = regs->r13; | 122 | |
| 94 | gdb_regs[GDB_R14] = regs->r14; | 123 | switch (regno) { |
| 95 | gdb_regs[GDB_R15] = regs->r15; | 124 | #ifdef CONFIG_X86_32 |
| 96 | gdb_regs32[GDB_PS] = regs->flags; | 125 | case GDB_SS: |
| 97 | gdb_regs32[GDB_CS] = regs->cs; | 126 | if (!user_mode_vm(regs)) |
| 98 | gdb_regs32[GDB_SS] = regs->ss; | 127 | *(unsigned long *)mem = __KERNEL_DS; |
| 99 | gdb_regs[GDB_SP] = kernel_stack_pointer(regs); | 128 | break; |
| 129 | case GDB_SP: | ||
| 130 | if (!user_mode_vm(regs)) | ||
| 131 | *(unsigned long *)mem = kernel_stack_pointer(regs); | ||
| 132 | break; | ||
| 133 | case GDB_GS: | ||
| 134 | case GDB_FS: | ||
| 135 | *(unsigned long *)mem = 0xFFFF; | ||
| 136 | break; | ||
| 100 | #endif | 137 | #endif |
| 138 | } | ||
| 139 | return dbg_reg_def[regno].name; | ||
| 101 | } | 140 | } |
| 102 | 141 | ||
| 103 | /** | 142 | /** |
| @@ -150,54 +189,13 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) | |||
| 150 | gdb_regs[GDB_SP] = p->thread.sp; | 189 | gdb_regs[GDB_SP] = p->thread.sp; |
| 151 | } | 190 | } |
| 152 | 191 | ||
| 153 | /** | ||
| 154 | * gdb_regs_to_pt_regs - Convert GDB regs to ptrace regs. | ||
| 155 | * @gdb_regs: A pointer to hold the registers we've received from GDB. | ||
| 156 | * @regs: A pointer to a &struct pt_regs to hold these values in. | ||
| 157 | * | ||
| 158 | * Convert the GDB regs in @gdb_regs into the pt_regs, and store them | ||
| 159 | * in @regs. | ||
| 160 | */ | ||
| 161 | void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
| 162 | { | ||
| 163 | #ifndef CONFIG_X86_32 | ||
| 164 | u32 *gdb_regs32 = (u32 *)gdb_regs; | ||
| 165 | #endif | ||
| 166 | regs->ax = gdb_regs[GDB_AX]; | ||
| 167 | regs->bx = gdb_regs[GDB_BX]; | ||
| 168 | regs->cx = gdb_regs[GDB_CX]; | ||
| 169 | regs->dx = gdb_regs[GDB_DX]; | ||
| 170 | regs->si = gdb_regs[GDB_SI]; | ||
| 171 | regs->di = gdb_regs[GDB_DI]; | ||
| 172 | regs->bp = gdb_regs[GDB_BP]; | ||
| 173 | regs->ip = gdb_regs[GDB_PC]; | ||
| 174 | #ifdef CONFIG_X86_32 | ||
| 175 | regs->flags = gdb_regs[GDB_PS]; | ||
| 176 | regs->ds = gdb_regs[GDB_DS]; | ||
| 177 | regs->es = gdb_regs[GDB_ES]; | ||
| 178 | regs->cs = gdb_regs[GDB_CS]; | ||
| 179 | #else | ||
| 180 | regs->r8 = gdb_regs[GDB_R8]; | ||
| 181 | regs->r9 = gdb_regs[GDB_R9]; | ||
| 182 | regs->r10 = gdb_regs[GDB_R10]; | ||
| 183 | regs->r11 = gdb_regs[GDB_R11]; | ||
| 184 | regs->r12 = gdb_regs[GDB_R12]; | ||
| 185 | regs->r13 = gdb_regs[GDB_R13]; | ||
| 186 | regs->r14 = gdb_regs[GDB_R14]; | ||
| 187 | regs->r15 = gdb_regs[GDB_R15]; | ||
| 188 | regs->flags = gdb_regs32[GDB_PS]; | ||
| 189 | regs->cs = gdb_regs32[GDB_CS]; | ||
| 190 | regs->ss = gdb_regs32[GDB_SS]; | ||
| 191 | #endif | ||
| 192 | } | ||
| 193 | |||
| 194 | static struct hw_breakpoint { | 192 | static struct hw_breakpoint { |
| 195 | unsigned enabled; | 193 | unsigned enabled; |
| 196 | unsigned long addr; | 194 | unsigned long addr; |
| 197 | int len; | 195 | int len; |
| 198 | int type; | 196 | int type; |
| 199 | struct perf_event **pev; | 197 | struct perf_event **pev; |
| 200 | } breakinfo[4]; | 198 | } breakinfo[HBP_NUM]; |
| 201 | 199 | ||
| 202 | static unsigned long early_dr7; | 200 | static unsigned long early_dr7; |
| 203 | 201 | ||
| @@ -205,7 +203,7 @@ static void kgdb_correct_hw_break(void) | |||
| 205 | { | 203 | { |
| 206 | int breakno; | 204 | int breakno; |
| 207 | 205 | ||
| 208 | for (breakno = 0; breakno < 4; breakno++) { | 206 | for (breakno = 0; breakno < HBP_NUM; breakno++) { |
| 209 | struct perf_event *bp; | 207 | struct perf_event *bp; |
| 210 | struct arch_hw_breakpoint *info; | 208 | struct arch_hw_breakpoint *info; |
| 211 | int val; | 209 | int val; |
| @@ -292,10 +290,10 @@ kgdb_remove_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype) | |||
| 292 | { | 290 | { |
| 293 | int i; | 291 | int i; |
| 294 | 292 | ||
| 295 | for (i = 0; i < 4; i++) | 293 | for (i = 0; i < HBP_NUM; i++) |
| 296 | if (breakinfo[i].addr == addr && breakinfo[i].enabled) | 294 | if (breakinfo[i].addr == addr && breakinfo[i].enabled) |
| 297 | break; | 295 | break; |
| 298 | if (i == 4) | 296 | if (i == HBP_NUM) |
| 299 | return -1; | 297 | return -1; |
| 300 | 298 | ||
| 301 | if (hw_break_release_slot(i)) { | 299 | if (hw_break_release_slot(i)) { |
| @@ -313,7 +311,7 @@ static void kgdb_remove_all_hw_break(void) | |||
| 313 | int cpu = raw_smp_processor_id(); | 311 | int cpu = raw_smp_processor_id(); |
| 314 | struct perf_event *bp; | 312 | struct perf_event *bp; |
| 315 | 313 | ||
| 316 | for (i = 0; i < 4; i++) { | 314 | for (i = 0; i < HBP_NUM; i++) { |
| 317 | if (!breakinfo[i].enabled) | 315 | if (!breakinfo[i].enabled) |
| 318 | continue; | 316 | continue; |
| 319 | bp = *per_cpu_ptr(breakinfo[i].pev, cpu); | 317 | 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) | |||
| 333 | { | 331 | { |
| 334 | int i; | 332 | int i; |
| 335 | 333 | ||
| 336 | for (i = 0; i < 4; i++) | 334 | for (i = 0; i < HBP_NUM; i++) |
| 337 | if (!breakinfo[i].enabled) | 335 | if (!breakinfo[i].enabled) |
| 338 | break; | 336 | break; |
| 339 | if (i == 4) | 337 | if (i == HBP_NUM) |
| 340 | return -1; | 338 | return -1; |
| 341 | 339 | ||
| 342 | switch (bptype) { | 340 | switch (bptype) { |
| @@ -397,7 +395,7 @@ void kgdb_disable_hw_debug(struct pt_regs *regs) | |||
| 397 | 395 | ||
| 398 | /* Disable hardware debugging while we are in kgdb: */ | 396 | /* Disable hardware debugging while we are in kgdb: */ |
| 399 | set_debugreg(0UL, 7); | 397 | set_debugreg(0UL, 7); |
| 400 | for (i = 0; i < 4; i++) { | 398 | for (i = 0; i < HBP_NUM; i++) { |
| 401 | if (!breakinfo[i].enabled) | 399 | if (!breakinfo[i].enabled) |
| 402 | continue; | 400 | continue; |
| 403 | if (dbg_is_early) { | 401 | if (dbg_is_early) { |
| @@ -458,7 +456,6 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, | |||
| 458 | { | 456 | { |
| 459 | unsigned long addr; | 457 | unsigned long addr; |
| 460 | char *ptr; | 458 | char *ptr; |
| 461 | int newPC; | ||
| 462 | 459 | ||
| 463 | switch (remcomInBuffer[0]) { | 460 | switch (remcomInBuffer[0]) { |
| 464 | case 'c': | 461 | case 'c': |
| @@ -469,8 +466,6 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, | |||
| 469 | linux_regs->ip = addr; | 466 | linux_regs->ip = addr; |
| 470 | case 'D': | 467 | case 'D': |
| 471 | case 'k': | 468 | case 'k': |
| 472 | newPC = linux_regs->ip; | ||
| 473 | |||
| 474 | /* clear the trace bit */ | 469 | /* clear the trace bit */ |
| 475 | linux_regs->flags &= ~X86_EFLAGS_TF; | 470 | linux_regs->flags &= ~X86_EFLAGS_TF; |
| 476 | atomic_set(&kgdb_cpu_doing_single_step, -1); | 471 | atomic_set(&kgdb_cpu_doing_single_step, -1); |
| @@ -645,7 +640,7 @@ void kgdb_arch_late(void) | |||
| 645 | attr.bp_len = HW_BREAKPOINT_LEN_1; | 640 | attr.bp_len = HW_BREAKPOINT_LEN_1; |
| 646 | attr.bp_type = HW_BREAKPOINT_W; | 641 | attr.bp_type = HW_BREAKPOINT_W; |
| 647 | attr.disabled = 1; | 642 | attr.disabled = 1; |
| 648 | for (i = 0; i < 4; i++) { | 643 | for (i = 0; i < HBP_NUM; i++) { |
| 649 | if (breakinfo[i].pev) | 644 | if (breakinfo[i].pev) |
| 650 | continue; | 645 | continue; |
| 651 | breakinfo[i].pev = register_wide_hw_breakpoint(&attr, NULL); | 646 | breakinfo[i].pev = register_wide_hw_breakpoint(&attr, NULL); |
