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/arm | |
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/arm')
-rw-r--r-- | arch/arm/include/asm/kgdb.h | 6 | ||||
-rw-r--r-- | arch/arm/kernel/kgdb.c | 124 |
2 files changed, 84 insertions, 46 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 | /* |