diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-29 14:49:38 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-29 14:49:38 -0400 |
commit | 1e431a9d6478940c0b5fcfa1c17a336fc0683409 (patch) | |
tree | ce6b454ecbad4f535b9a18ef8605f8218a409ee6 /arch | |
parent | 75d73126fd490e26a9bdfc2338ca068e71563e0b (diff) | |
parent | ff10b88b5a05c8f1646dd15fb9f6093c1384ff6d (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:
kgdb,ppc: Individual register get/set for ppc
kgdbts: prevent re-entry to kgdbts before it unregisters
debug_core,x86,blackfin: Clean up hw debug disable API
kdb: Fix early debugging crash regression
kgdb,arm: fix register dump
kdb: fix per_cpu command to remove supress mask
kdb: Add kdb kernel module sample
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/include/asm/kgdb.h | 5 | ||||
-rw-r--r-- | arch/arm/kernel/kgdb.c | 2 | ||||
-rw-r--r-- | arch/blackfin/kernel/kgdb.c | 3 | ||||
-rw-r--r-- | arch/powerpc/include/asm/kgdb.h | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/kgdb.c | 188 | ||||
-rw-r--r-- | arch/x86/kernel/kgdb.c | 3 |
6 files changed, 134 insertions, 68 deletions
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; | |||
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 DBG_MAX_REG_NUM (_GP_REGS + (_FP_REGS * 3) + _EXTRA_REGS) | 73 | #define GDB_MAX_REGS (_GP_REGS + (_FP_REGS * 3) + _EXTRA_REGS) |
74 | #define DBG_MAX_REG_NUM (_GP_REGS + _FP_REGS + _EXTRA_REGS) | ||
74 | 75 | ||
75 | #define KGDB_MAX_NO_CPUS 1 | 76 | #define KGDB_MAX_NO_CPUS 1 |
76 | #define BUFMAX 400 | 77 | #define BUFMAX 400 |
@@ -93,7 +94,7 @@ extern int kgdb_fault_expected; | |||
93 | #define _SPT 13 | 94 | #define _SPT 13 |
94 | #define _LR 14 | 95 | #define _LR 14 |
95 | #define _PC 15 | 96 | #define _PC 15 |
96 | #define _CPSR (DBG_MAX_REG_NUM - 1) | 97 | #define _CPSR (GDB_MAX_REGS - 1) |
97 | 98 | ||
98 | /* | 99 | /* |
99 | * So that we can denote the end of a frame for tracing, | 100 | * 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) | |||
79 | return; | 79 | return; |
80 | 80 | ||
81 | /* Initialize to zero */ | 81 | /* Initialize to zero */ |
82 | for (regno = 0; regno < DBG_MAX_REG_NUM; regno++) | 82 | for (regno = 0; regno < GDB_MAX_REGS; regno++) |
83 | gdb_regs[regno] = 0; | 83 | gdb_regs[regno] = 0; |
84 | 84 | ||
85 | /* Otherwise, we have only some registers from switch_to() */ | 85 | /* Otherwise, we have only some registers from switch_to() */ |
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) | |||
320 | } | 320 | } |
321 | } | 321 | } |
322 | 322 | ||
323 | void kgdb_disable_hw_debug(struct pt_regs *regs) | 323 | static void bfin_disable_hw_debug(struct pt_regs *regs) |
324 | { | 324 | { |
325 | /* Disable hardware debugging while we are in kgdb */ | 325 | /* Disable hardware debugging while we are in kgdb */ |
326 | bfin_write_WPIACTL(0); | 326 | bfin_write_WPIACTL(0); |
@@ -406,6 +406,7 @@ struct kgdb_arch arch_kgdb_ops = { | |||
406 | #endif | 406 | #endif |
407 | .set_hw_breakpoint = bfin_set_hw_break, | 407 | .set_hw_breakpoint = bfin_set_hw_break, |
408 | .remove_hw_breakpoint = bfin_remove_hw_break, | 408 | .remove_hw_breakpoint = bfin_remove_hw_break, |
409 | .disable_hw_break = bfin_disable_hw_debug, | ||
409 | .remove_all_hw_break = bfin_remove_all_hw_break, | 410 | .remove_all_hw_break = bfin_remove_all_hw_break, |
410 | .correct_hw_break = bfin_correct_hw_break, | 411 | .correct_hw_break = bfin_correct_hw_break, |
411 | }; | 412 | }; |
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) | |||
31 | asm(".long 0x7d821008"); /* twge r2, r2 */ | 31 | asm(".long 0x7d821008"); /* twge r2, r2 */ |
32 | } | 32 | } |
33 | #define CACHE_FLUSH_IS_SAFE 1 | 33 | #define CACHE_FLUSH_IS_SAFE 1 |
34 | #define DBG_MAX_REG_NUM 70 | ||
34 | 35 | ||
35 | /* The number bytes of registers we have to save depends on a few | 36 | /* The number bytes of registers we have to save depends on a few |
36 | * things. For 64bit we default to not including vector registers and | 37 | * 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) | |||
194 | ptr = (unsigned long *)ptr32; \ | 194 | ptr = (unsigned long *)ptr32; \ |
195 | } while (0) | 195 | } while (0) |
196 | 196 | ||
197 | |||
198 | void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
199 | { | ||
200 | unsigned long *ptr = gdb_regs; | ||
201 | int reg; | ||
202 | |||
203 | memset(gdb_regs, 0, NUMREGBYTES); | ||
204 | |||
205 | for (reg = 0; reg < 32; reg++) | ||
206 | PACK64(ptr, regs->gpr[reg]); | ||
207 | |||
208 | #ifdef CONFIG_FSL_BOOKE | ||
209 | #ifdef CONFIG_SPE | ||
210 | for (reg = 0; reg < 32; reg++) | ||
211 | PACK64(ptr, current->thread.evr[reg]); | ||
212 | #else | ||
213 | ptr += 32; | ||
214 | #endif | ||
215 | #else | ||
216 | /* fp registers not used by kernel, leave zero */ | ||
217 | ptr += 32 * 8 / sizeof(long); | ||
218 | #endif | ||
219 | |||
220 | PACK64(ptr, regs->nip); | ||
221 | PACK64(ptr, regs->msr); | ||
222 | PACK32(ptr, regs->ccr); | ||
223 | PACK64(ptr, regs->link); | ||
224 | PACK64(ptr, regs->ctr); | ||
225 | PACK32(ptr, regs->xer); | ||
226 | |||
227 | BUG_ON((unsigned long)ptr > | ||
228 | (unsigned long)(((void *)gdb_regs) + NUMREGBYTES)); | ||
229 | } | ||
230 | |||
231 | void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) | 197 | void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) |
232 | { | 198 | { |
233 | struct pt_regs *regs = (struct pt_regs *)(p->thread.ksp + | 199 | 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) | |||
271 | (unsigned long)(((void *)gdb_regs) + NUMREGBYTES)); | 237 | (unsigned long)(((void *)gdb_regs) + NUMREGBYTES)); |
272 | } | 238 | } |
273 | 239 | ||
274 | #define UNPACK64(dest, ptr) do { dest = *(ptr++); } while (0) | 240 | #define GDB_SIZEOF_REG sizeof(unsigned long) |
241 | #define GDB_SIZEOF_REG_U32 sizeof(u32) | ||
275 | 242 | ||
276 | #define UNPACK32(dest, ptr) do { \ | 243 | #ifdef CONFIG_FSL_BOOKE |
277 | u32 *ptr32; \ | 244 | #define GDB_SIZEOF_FLOAT_REG sizeof(unsigned long) |
278 | ptr32 = (u32 *)ptr; \ | 245 | #else |
279 | dest = *(ptr32++); \ | 246 | #define GDB_SIZEOF_FLOAT_REG sizeof(u64) |
280 | ptr = (unsigned long *)ptr32; \ | 247 | #endif |
281 | } while (0) | ||
282 | 248 | ||
283 | void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) | 249 | struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = |
284 | { | 250 | { |
285 | unsigned long *ptr = gdb_regs; | 251 | { "r0", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[0]) }, |
286 | int reg; | 252 | { "r1", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[1]) }, |
287 | 253 | { "r2", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[2]) }, | |
288 | for (reg = 0; reg < 32; reg++) | 254 | { "r3", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[3]) }, |
289 | UNPACK64(regs->gpr[reg], ptr); | 255 | { "r4", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[4]) }, |
256 | { "r5", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[5]) }, | ||
257 | { "r6", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[6]) }, | ||
258 | { "r7", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[7]) }, | ||
259 | { "r8", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[8]) }, | ||
260 | { "r9", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[9]) }, | ||
261 | { "r10", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[10]) }, | ||
262 | { "r11", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[11]) }, | ||
263 | { "r12", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[12]) }, | ||
264 | { "r13", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[13]) }, | ||
265 | { "r14", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[14]) }, | ||
266 | { "r15", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[15]) }, | ||
267 | { "r16", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[16]) }, | ||
268 | { "r17", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[17]) }, | ||
269 | { "r18", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[18]) }, | ||
270 | { "r19", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[19]) }, | ||
271 | { "r20", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[20]) }, | ||
272 | { "r21", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[21]) }, | ||
273 | { "r22", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[22]) }, | ||
274 | { "r23", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[23]) }, | ||
275 | { "r24", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[24]) }, | ||
276 | { "r25", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[25]) }, | ||
277 | { "r26", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[26]) }, | ||
278 | { "r27", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[27]) }, | ||
279 | { "r28", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[28]) }, | ||
280 | { "r29", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[29]) }, | ||
281 | { "r30", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[30]) }, | ||
282 | { "r31", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[31]) }, | ||
283 | |||
284 | { "f0", GDB_SIZEOF_FLOAT_REG, 0 }, | ||
285 | { "f1", GDB_SIZEOF_FLOAT_REG, 1 }, | ||
286 | { "f2", GDB_SIZEOF_FLOAT_REG, 2 }, | ||
287 | { "f3", GDB_SIZEOF_FLOAT_REG, 3 }, | ||
288 | { "f4", GDB_SIZEOF_FLOAT_REG, 4 }, | ||
289 | { "f5", GDB_SIZEOF_FLOAT_REG, 5 }, | ||
290 | { "f6", GDB_SIZEOF_FLOAT_REG, 6 }, | ||
291 | { "f7", GDB_SIZEOF_FLOAT_REG, 7 }, | ||
292 | { "f8", GDB_SIZEOF_FLOAT_REG, 8 }, | ||
293 | { "f9", GDB_SIZEOF_FLOAT_REG, 9 }, | ||
294 | { "f10", GDB_SIZEOF_FLOAT_REG, 10 }, | ||
295 | { "f11", GDB_SIZEOF_FLOAT_REG, 11 }, | ||
296 | { "f12", GDB_SIZEOF_FLOAT_REG, 12 }, | ||
297 | { "f13", GDB_SIZEOF_FLOAT_REG, 13 }, | ||
298 | { "f14", GDB_SIZEOF_FLOAT_REG, 14 }, | ||
299 | { "f15", GDB_SIZEOF_FLOAT_REG, 15 }, | ||
300 | { "f16", GDB_SIZEOF_FLOAT_REG, 16 }, | ||
301 | { "f17", GDB_SIZEOF_FLOAT_REG, 17 }, | ||
302 | { "f18", GDB_SIZEOF_FLOAT_REG, 18 }, | ||
303 | { "f19", GDB_SIZEOF_FLOAT_REG, 19 }, | ||
304 | { "f20", GDB_SIZEOF_FLOAT_REG, 20 }, | ||
305 | { "f21", GDB_SIZEOF_FLOAT_REG, 21 }, | ||
306 | { "f22", GDB_SIZEOF_FLOAT_REG, 22 }, | ||
307 | { "f23", GDB_SIZEOF_FLOAT_REG, 23 }, | ||
308 | { "f24", GDB_SIZEOF_FLOAT_REG, 24 }, | ||
309 | { "f25", GDB_SIZEOF_FLOAT_REG, 25 }, | ||
310 | { "f26", GDB_SIZEOF_FLOAT_REG, 26 }, | ||
311 | { "f27", GDB_SIZEOF_FLOAT_REG, 27 }, | ||
312 | { "f28", GDB_SIZEOF_FLOAT_REG, 28 }, | ||
313 | { "f29", GDB_SIZEOF_FLOAT_REG, 29 }, | ||
314 | { "f30", GDB_SIZEOF_FLOAT_REG, 30 }, | ||
315 | { "f31", GDB_SIZEOF_FLOAT_REG, 31 }, | ||
316 | |||
317 | { "pc", GDB_SIZEOF_REG, offsetof(struct pt_regs, nip) }, | ||
318 | { "msr", GDB_SIZEOF_REG, offsetof(struct pt_regs, msr) }, | ||
319 | { "cr", GDB_SIZEOF_REG_U32, offsetof(struct pt_regs, ccr) }, | ||
320 | { "lr", GDB_SIZEOF_REG, offsetof(struct pt_regs, link) }, | ||
321 | { "ctr", GDB_SIZEOF_REG_U32, offsetof(struct pt_regs, ctr) }, | ||
322 | { "xer", GDB_SIZEOF_REG, offsetof(struct pt_regs, xer) }, | ||
323 | }; | ||
290 | 324 | ||
291 | #ifdef CONFIG_FSL_BOOKE | 325 | char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) |
292 | #ifdef CONFIG_SPE | 326 | { |
293 | for (reg = 0; reg < 32; reg++) | 327 | if (regno >= DBG_MAX_REG_NUM || regno < 0) |
294 | UNPACK64(current->thread.evr[reg], ptr); | 328 | return NULL; |
329 | |||
330 | if (regno < 32 || regno >= 64) | ||
331 | /* First 0 -> 31 gpr registers*/ | ||
332 | /* pc, msr, ls... registers 64 -> 69 */ | ||
333 | memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, | ||
334 | dbg_reg_def[regno].size); | ||
335 | |||
336 | if (regno >= 32 && regno < 64) { | ||
337 | /* FP registers 32 -> 63 */ | ||
338 | #if defined(CONFIG_FSL_BOOKE) && defined(CONFIG_SPE) | ||
339 | if (current) | ||
340 | memcpy(mem, current->thread.evr[regno-32], | ||
341 | dbg_reg_def[regno].size); | ||
295 | #else | 342 | #else |
296 | ptr += 32; | 343 | /* fp registers not used by kernel, leave zero */ |
344 | memset(mem, 0, dbg_reg_def[regno].size); | ||
297 | #endif | 345 | #endif |
346 | } | ||
347 | |||
348 | return dbg_reg_def[regno].name; | ||
349 | } | ||
350 | |||
351 | int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) | ||
352 | { | ||
353 | if (regno >= DBG_MAX_REG_NUM || regno < 0) | ||
354 | return -EINVAL; | ||
355 | |||
356 | if (regno < 32 || regno >= 64) | ||
357 | /* First 0 -> 31 gpr registers*/ | ||
358 | /* pc, msr, ls... registers 64 -> 69 */ | ||
359 | memcpy((void *)regs + dbg_reg_def[regno].offset, mem, | ||
360 | dbg_reg_def[regno].size); | ||
361 | |||
362 | if (regno >= 32 && regno < 64) { | ||
363 | /* FP registers 32 -> 63 */ | ||
364 | #if defined(CONFIG_FSL_BOOKE) && defined(CONFIG_SPE) | ||
365 | memcpy(current->thread.evr[regno-32], mem, | ||
366 | dbg_reg_def[regno].size); | ||
298 | #else | 367 | #else |
299 | /* fp registers not used by kernel, leave zero */ | 368 | /* fp registers not used by kernel, leave zero */ |
300 | ptr += 32 * 8 / sizeof(int); | 369 | return 0; |
301 | #endif | 370 | #endif |
371 | } | ||
302 | 372 | ||
303 | UNPACK64(regs->nip, ptr); | 373 | return 0; |
304 | UNPACK64(regs->msr, ptr); | ||
305 | UNPACK32(regs->ccr, ptr); | ||
306 | UNPACK64(regs->link, ptr); | ||
307 | UNPACK64(regs->ctr, ptr); | ||
308 | UNPACK32(regs->xer, ptr); | ||
309 | |||
310 | BUG_ON((unsigned long)ptr > | ||
311 | (unsigned long)(((void *)gdb_regs) + NUMREGBYTES)); | ||
312 | } | 374 | } |
313 | 375 | ||
314 | void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) | 376 | void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) |
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) | |||
387 | * disable hardware debugging while it is processing gdb packets or | 387 | * disable hardware debugging while it is processing gdb packets or |
388 | * handling exception. | 388 | * handling exception. |
389 | */ | 389 | */ |
390 | void kgdb_disable_hw_debug(struct pt_regs *regs) | 390 | static void kgdb_disable_hw_debug(struct pt_regs *regs) |
391 | { | 391 | { |
392 | int i; | 392 | int i; |
393 | int cpu = raw_smp_processor_id(); | 393 | int cpu = raw_smp_processor_id(); |
@@ -724,6 +724,7 @@ struct kgdb_arch arch_kgdb_ops = { | |||
724 | .flags = KGDB_HW_BREAKPOINT, | 724 | .flags = KGDB_HW_BREAKPOINT, |
725 | .set_hw_breakpoint = kgdb_set_hw_break, | 725 | .set_hw_breakpoint = kgdb_set_hw_break, |
726 | .remove_hw_breakpoint = kgdb_remove_hw_break, | 726 | .remove_hw_breakpoint = kgdb_remove_hw_break, |
727 | .disable_hw_break = kgdb_disable_hw_debug, | ||
727 | .remove_all_hw_break = kgdb_remove_all_hw_break, | 728 | .remove_all_hw_break = kgdb_remove_all_hw_break, |
728 | .correct_hw_break = kgdb_correct_hw_break, | 729 | .correct_hw_break = kgdb_correct_hw_break, |
729 | }; | 730 | }; |