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 /kernel/debug | |
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 'kernel/debug')
-rw-r--r-- | kernel/debug/debug_core.c | 2 | ||||
-rw-r--r-- | kernel/debug/gdbstub.c | 189 | ||||
-rw-r--r-- | kernel/debug/kdb/kdb_main.c | 132 |
3 files changed, 257 insertions, 66 deletions
diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c index 51d14fe87648..3c2d4972d235 100644 --- a/kernel/debug/debug_core.c +++ b/kernel/debug/debug_core.c | |||
@@ -605,6 +605,8 @@ cpu_master_loop: | |||
605 | if (dbg_kdb_mode) { | 605 | if (dbg_kdb_mode) { |
606 | kgdb_connected = 1; | 606 | kgdb_connected = 1; |
607 | error = kdb_stub(ks); | 607 | error = kdb_stub(ks); |
608 | if (error == -1) | ||
609 | continue; | ||
608 | kgdb_connected = 0; | 610 | kgdb_connected = 0; |
609 | } else { | 611 | } else { |
610 | error = gdb_serial_stub(ks); | 612 | error = gdb_serial_stub(ks); |
diff --git a/kernel/debug/gdbstub.c b/kernel/debug/gdbstub.c index 6e81fd59566b..481a7bd2dfe7 100644 --- a/kernel/debug/gdbstub.c +++ b/kernel/debug/gdbstub.c | |||
@@ -52,17 +52,6 @@ static unsigned long gdb_regs[(NUMREGBYTES + | |||
52 | * GDB remote protocol parser: | 52 | * GDB remote protocol parser: |
53 | */ | 53 | */ |
54 | 54 | ||
55 | static int hex(char ch) | ||
56 | { | ||
57 | if ((ch >= 'a') && (ch <= 'f')) | ||
58 | return ch - 'a' + 10; | ||
59 | if ((ch >= '0') && (ch <= '9')) | ||
60 | return ch - '0'; | ||
61 | if ((ch >= 'A') && (ch <= 'F')) | ||
62 | return ch - 'A' + 10; | ||
63 | return -1; | ||
64 | } | ||
65 | |||
66 | #ifdef CONFIG_KGDB_KDB | 55 | #ifdef CONFIG_KGDB_KDB |
67 | static int gdbstub_read_wait(void) | 56 | static int gdbstub_read_wait(void) |
68 | { | 57 | { |
@@ -123,8 +112,8 @@ static void get_packet(char *buffer) | |||
123 | buffer[count] = 0; | 112 | buffer[count] = 0; |
124 | 113 | ||
125 | if (ch == '#') { | 114 | if (ch == '#') { |
126 | xmitcsum = hex(gdbstub_read_wait()) << 4; | 115 | xmitcsum = hex_to_bin(gdbstub_read_wait()) << 4; |
127 | xmitcsum += hex(gdbstub_read_wait()); | 116 | xmitcsum += hex_to_bin(gdbstub_read_wait()); |
128 | 117 | ||
129 | if (checksum != xmitcsum) | 118 | if (checksum != xmitcsum) |
130 | /* failed checksum */ | 119 | /* failed checksum */ |
@@ -236,7 +225,7 @@ void gdbstub_msg_write(const char *s, int len) | |||
236 | * buf. Return a pointer to the last char put in buf (null). May | 225 | * buf. Return a pointer to the last char put in buf (null). May |
237 | * return an error. | 226 | * return an error. |
238 | */ | 227 | */ |
239 | int kgdb_mem2hex(char *mem, char *buf, int count) | 228 | char *kgdb_mem2hex(char *mem, char *buf, int count) |
240 | { | 229 | { |
241 | char *tmp; | 230 | char *tmp; |
242 | int err; | 231 | int err; |
@@ -248,17 +237,16 @@ int kgdb_mem2hex(char *mem, char *buf, int count) | |||
248 | tmp = buf + count; | 237 | tmp = buf + count; |
249 | 238 | ||
250 | err = probe_kernel_read(tmp, mem, count); | 239 | err = probe_kernel_read(tmp, mem, count); |
251 | if (!err) { | 240 | if (err) |
252 | while (count > 0) { | 241 | return NULL; |
253 | buf = pack_hex_byte(buf, *tmp); | 242 | while (count > 0) { |
254 | tmp++; | 243 | buf = pack_hex_byte(buf, *tmp); |
255 | count--; | 244 | tmp++; |
256 | } | 245 | count--; |
257 | |||
258 | *buf = 0; | ||
259 | } | 246 | } |
247 | *buf = 0; | ||
260 | 248 | ||
261 | return err; | 249 | return buf; |
262 | } | 250 | } |
263 | 251 | ||
264 | /* | 252 | /* |
@@ -280,8 +268,8 @@ int kgdb_hex2mem(char *buf, char *mem, int count) | |||
280 | tmp_hex = tmp_raw - 1; | 268 | tmp_hex = tmp_raw - 1; |
281 | while (tmp_hex >= buf) { | 269 | while (tmp_hex >= buf) { |
282 | tmp_raw--; | 270 | tmp_raw--; |
283 | *tmp_raw = hex(*tmp_hex--); | 271 | *tmp_raw = hex_to_bin(*tmp_hex--); |
284 | *tmp_raw |= hex(*tmp_hex--) << 4; | 272 | *tmp_raw |= hex_to_bin(*tmp_hex--) << 4; |
285 | } | 273 | } |
286 | 274 | ||
287 | return probe_kernel_write(mem, tmp_raw, count); | 275 | return probe_kernel_write(mem, tmp_raw, count); |
@@ -304,7 +292,7 @@ int kgdb_hex2long(char **ptr, unsigned long *long_val) | |||
304 | (*ptr)++; | 292 | (*ptr)++; |
305 | } | 293 | } |
306 | while (**ptr) { | 294 | while (**ptr) { |
307 | hex_val = hex(**ptr); | 295 | hex_val = hex_to_bin(**ptr); |
308 | if (hex_val < 0) | 296 | if (hex_val < 0) |
309 | break; | 297 | break; |
310 | 298 | ||
@@ -339,6 +327,32 @@ static int kgdb_ebin2mem(char *buf, char *mem, int count) | |||
339 | return probe_kernel_write(mem, c, size); | 327 | return probe_kernel_write(mem, c, size); |
340 | } | 328 | } |
341 | 329 | ||
330 | #if DBG_MAX_REG_NUM > 0 | ||
331 | void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
332 | { | ||
333 | int i; | ||
334 | int idx = 0; | ||
335 | char *ptr = (char *)gdb_regs; | ||
336 | |||
337 | for (i = 0; i < DBG_MAX_REG_NUM; i++) { | ||
338 | dbg_get_reg(i, ptr + idx, regs); | ||
339 | idx += dbg_reg_def[i].size; | ||
340 | } | ||
341 | } | ||
342 | |||
343 | void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
344 | { | ||
345 | int i; | ||
346 | int idx = 0; | ||
347 | char *ptr = (char *)gdb_regs; | ||
348 | |||
349 | for (i = 0; i < DBG_MAX_REG_NUM; i++) { | ||
350 | dbg_set_reg(i, ptr + idx, regs); | ||
351 | idx += dbg_reg_def[i].size; | ||
352 | } | ||
353 | } | ||
354 | #endif /* DBG_MAX_REG_NUM > 0 */ | ||
355 | |||
342 | /* Write memory due to an 'M' or 'X' packet. */ | 356 | /* Write memory due to an 'M' or 'X' packet. */ |
343 | static int write_mem_msg(int binary) | 357 | static int write_mem_msg(int binary) |
344 | { | 358 | { |
@@ -378,28 +392,31 @@ static void error_packet(char *pkt, int error) | |||
378 | * remapped to negative TIDs. | 392 | * remapped to negative TIDs. |
379 | */ | 393 | */ |
380 | 394 | ||
381 | #define BUF_THREAD_ID_SIZE 16 | 395 | #define BUF_THREAD_ID_SIZE 8 |
382 | 396 | ||
383 | static char *pack_threadid(char *pkt, unsigned char *id) | 397 | static char *pack_threadid(char *pkt, unsigned char *id) |
384 | { | 398 | { |
385 | char *limit; | 399 | unsigned char *limit; |
400 | int lzero = 1; | ||
401 | |||
402 | limit = id + (BUF_THREAD_ID_SIZE / 2); | ||
403 | while (id < limit) { | ||
404 | if (!lzero || *id != 0) { | ||
405 | pkt = pack_hex_byte(pkt, *id); | ||
406 | lzero = 0; | ||
407 | } | ||
408 | id++; | ||
409 | } | ||
386 | 410 | ||
387 | limit = pkt + BUF_THREAD_ID_SIZE; | 411 | if (lzero) |
388 | while (pkt < limit) | 412 | pkt = pack_hex_byte(pkt, 0); |
389 | pkt = pack_hex_byte(pkt, *id++); | ||
390 | 413 | ||
391 | return pkt; | 414 | return pkt; |
392 | } | 415 | } |
393 | 416 | ||
394 | static void int_to_threadref(unsigned char *id, int value) | 417 | static void int_to_threadref(unsigned char *id, int value) |
395 | { | 418 | { |
396 | unsigned char *scan; | 419 | put_unaligned_be32(value, id); |
397 | int i = 4; | ||
398 | |||
399 | scan = (unsigned char *)id; | ||
400 | while (i--) | ||
401 | *scan++ = 0; | ||
402 | put_unaligned_be32(value, scan); | ||
403 | } | 420 | } |
404 | 421 | ||
405 | static struct task_struct *getthread(struct pt_regs *regs, int tid) | 422 | static struct task_struct *getthread(struct pt_regs *regs, int tid) |
@@ -463,8 +480,7 @@ static void gdb_cmd_status(struct kgdb_state *ks) | |||
463 | pack_hex_byte(&remcom_out_buffer[1], ks->signo); | 480 | pack_hex_byte(&remcom_out_buffer[1], ks->signo); |
464 | } | 481 | } |
465 | 482 | ||
466 | /* Handle the 'g' get registers request */ | 483 | static void gdb_get_regs_helper(struct kgdb_state *ks) |
467 | static void gdb_cmd_getregs(struct kgdb_state *ks) | ||
468 | { | 484 | { |
469 | struct task_struct *thread; | 485 | struct task_struct *thread; |
470 | void *local_debuggerinfo; | 486 | void *local_debuggerinfo; |
@@ -505,6 +521,12 @@ static void gdb_cmd_getregs(struct kgdb_state *ks) | |||
505 | */ | 521 | */ |
506 | sleeping_thread_to_gdb_regs(gdb_regs, thread); | 522 | sleeping_thread_to_gdb_regs(gdb_regs, thread); |
507 | } | 523 | } |
524 | } | ||
525 | |||
526 | /* Handle the 'g' get registers request */ | ||
527 | static void gdb_cmd_getregs(struct kgdb_state *ks) | ||
528 | { | ||
529 | gdb_get_regs_helper(ks); | ||
508 | kgdb_mem2hex((char *)gdb_regs, remcom_out_buffer, NUMREGBYTES); | 530 | kgdb_mem2hex((char *)gdb_regs, remcom_out_buffer, NUMREGBYTES); |
509 | } | 531 | } |
510 | 532 | ||
@@ -527,13 +549,13 @@ static void gdb_cmd_memread(struct kgdb_state *ks) | |||
527 | char *ptr = &remcom_in_buffer[1]; | 549 | char *ptr = &remcom_in_buffer[1]; |
528 | unsigned long length; | 550 | unsigned long length; |
529 | unsigned long addr; | 551 | unsigned long addr; |
530 | int err; | 552 | char *err; |
531 | 553 | ||
532 | if (kgdb_hex2long(&ptr, &addr) > 0 && *ptr++ == ',' && | 554 | if (kgdb_hex2long(&ptr, &addr) > 0 && *ptr++ == ',' && |
533 | kgdb_hex2long(&ptr, &length) > 0) { | 555 | kgdb_hex2long(&ptr, &length) > 0) { |
534 | err = kgdb_mem2hex((char *)addr, remcom_out_buffer, length); | 556 | err = kgdb_mem2hex((char *)addr, remcom_out_buffer, length); |
535 | if (err) | 557 | if (!err) |
536 | error_packet(remcom_out_buffer, err); | 558 | error_packet(remcom_out_buffer, -EINVAL); |
537 | } else { | 559 | } else { |
538 | error_packet(remcom_out_buffer, -EINVAL); | 560 | error_packet(remcom_out_buffer, -EINVAL); |
539 | } | 561 | } |
@@ -550,6 +572,60 @@ static void gdb_cmd_memwrite(struct kgdb_state *ks) | |||
550 | strcpy(remcom_out_buffer, "OK"); | 572 | strcpy(remcom_out_buffer, "OK"); |
551 | } | 573 | } |
552 | 574 | ||
575 | #if DBG_MAX_REG_NUM > 0 | ||
576 | static char *gdb_hex_reg_helper(int regnum, char *out) | ||
577 | { | ||
578 | int i; | ||
579 | int offset = 0; | ||
580 | |||
581 | for (i = 0; i < regnum; i++) | ||
582 | offset += dbg_reg_def[i].size; | ||
583 | return kgdb_mem2hex((char *)gdb_regs + offset, out, | ||
584 | dbg_reg_def[i].size); | ||
585 | } | ||
586 | |||
587 | /* Handle the 'p' individual regster get */ | ||
588 | static void gdb_cmd_reg_get(struct kgdb_state *ks) | ||
589 | { | ||
590 | unsigned long regnum; | ||
591 | char *ptr = &remcom_in_buffer[1]; | ||
592 | |||
593 | kgdb_hex2long(&ptr, ®num); | ||
594 | if (regnum >= DBG_MAX_REG_NUM) { | ||
595 | error_packet(remcom_out_buffer, -EINVAL); | ||
596 | return; | ||
597 | } | ||
598 | gdb_get_regs_helper(ks); | ||
599 | gdb_hex_reg_helper(regnum, remcom_out_buffer); | ||
600 | } | ||
601 | |||
602 | /* Handle the 'P' individual regster set */ | ||
603 | static void gdb_cmd_reg_set(struct kgdb_state *ks) | ||
604 | { | ||
605 | unsigned long regnum; | ||
606 | char *ptr = &remcom_in_buffer[1]; | ||
607 | int i = 0; | ||
608 | |||
609 | kgdb_hex2long(&ptr, ®num); | ||
610 | if (*ptr++ != '=' || | ||
611 | !(!kgdb_usethread || kgdb_usethread == current) || | ||
612 | !dbg_get_reg(regnum, gdb_regs, ks->linux_regs)) { | ||
613 | error_packet(remcom_out_buffer, -EINVAL); | ||
614 | return; | ||
615 | } | ||
616 | memset(gdb_regs, 0, sizeof(gdb_regs)); | ||
617 | while (i < sizeof(gdb_regs) * 2) | ||
618 | if (hex_to_bin(ptr[i]) >= 0) | ||
619 | i++; | ||
620 | else | ||
621 | break; | ||
622 | i = i / 2; | ||
623 | kgdb_hex2mem(ptr, (char *)gdb_regs, i); | ||
624 | dbg_set_reg(regnum, gdb_regs, ks->linux_regs); | ||
625 | strcpy(remcom_out_buffer, "OK"); | ||
626 | } | ||
627 | #endif /* DBG_MAX_REG_NUM > 0 */ | ||
628 | |||
553 | /* Handle the 'X' memory binary write bytes */ | 629 | /* Handle the 'X' memory binary write bytes */ |
554 | static void gdb_cmd_binwrite(struct kgdb_state *ks) | 630 | static void gdb_cmd_binwrite(struct kgdb_state *ks) |
555 | { | 631 | { |
@@ -612,7 +688,7 @@ static void gdb_cmd_query(struct kgdb_state *ks) | |||
612 | { | 688 | { |
613 | struct task_struct *g; | 689 | struct task_struct *g; |
614 | struct task_struct *p; | 690 | struct task_struct *p; |
615 | unsigned char thref[8]; | 691 | unsigned char thref[BUF_THREAD_ID_SIZE]; |
616 | char *ptr; | 692 | char *ptr; |
617 | int i; | 693 | int i; |
618 | int cpu; | 694 | int cpu; |
@@ -632,8 +708,7 @@ static void gdb_cmd_query(struct kgdb_state *ks) | |||
632 | for_each_online_cpu(cpu) { | 708 | for_each_online_cpu(cpu) { |
633 | ks->thr_query = 0; | 709 | ks->thr_query = 0; |
634 | int_to_threadref(thref, -cpu - 2); | 710 | int_to_threadref(thref, -cpu - 2); |
635 | pack_threadid(ptr, thref); | 711 | ptr = pack_threadid(ptr, thref); |
636 | ptr += BUF_THREAD_ID_SIZE; | ||
637 | *(ptr++) = ','; | 712 | *(ptr++) = ','; |
638 | i++; | 713 | i++; |
639 | } | 714 | } |
@@ -642,8 +717,7 @@ static void gdb_cmd_query(struct kgdb_state *ks) | |||
642 | do_each_thread(g, p) { | 717 | do_each_thread(g, p) { |
643 | if (i >= ks->thr_query && !finished) { | 718 | if (i >= ks->thr_query && !finished) { |
644 | int_to_threadref(thref, p->pid); | 719 | int_to_threadref(thref, p->pid); |
645 | pack_threadid(ptr, thref); | 720 | ptr = pack_threadid(ptr, thref); |
646 | ptr += BUF_THREAD_ID_SIZE; | ||
647 | *(ptr++) = ','; | 721 | *(ptr++) = ','; |
648 | ks->thr_query++; | 722 | ks->thr_query++; |
649 | if (ks->thr_query % KGDB_MAX_THREAD_QUERY == 0) | 723 | if (ks->thr_query % KGDB_MAX_THREAD_QUERY == 0) |
@@ -858,11 +932,14 @@ int gdb_serial_stub(struct kgdb_state *ks) | |||
858 | int error = 0; | 932 | int error = 0; |
859 | int tmp; | 933 | int tmp; |
860 | 934 | ||
861 | /* Clear the out buffer. */ | 935 | /* Initialize comm buffer and globals. */ |
862 | memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer)); | 936 | memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer)); |
937 | kgdb_usethread = kgdb_info[ks->cpu].task; | ||
938 | ks->kgdb_usethreadid = shadow_pid(kgdb_info[ks->cpu].task->pid); | ||
939 | ks->pass_exception = 0; | ||
863 | 940 | ||
864 | if (kgdb_connected) { | 941 | if (kgdb_connected) { |
865 | unsigned char thref[8]; | 942 | unsigned char thref[BUF_THREAD_ID_SIZE]; |
866 | char *ptr; | 943 | char *ptr; |
867 | 944 | ||
868 | /* Reply to host that an exception has occurred */ | 945 | /* Reply to host that an exception has occurred */ |
@@ -876,10 +953,6 @@ int gdb_serial_stub(struct kgdb_state *ks) | |||
876 | put_packet(remcom_out_buffer); | 953 | put_packet(remcom_out_buffer); |
877 | } | 954 | } |
878 | 955 | ||
879 | kgdb_usethread = kgdb_info[ks->cpu].task; | ||
880 | ks->kgdb_usethreadid = shadow_pid(kgdb_info[ks->cpu].task->pid); | ||
881 | ks->pass_exception = 0; | ||
882 | |||
883 | while (1) { | 956 | while (1) { |
884 | error = 0; | 957 | error = 0; |
885 | 958 | ||
@@ -904,6 +977,14 @@ int gdb_serial_stub(struct kgdb_state *ks) | |||
904 | case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA..AA */ | 977 | case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA..AA */ |
905 | gdb_cmd_memwrite(ks); | 978 | gdb_cmd_memwrite(ks); |
906 | break; | 979 | break; |
980 | #if DBG_MAX_REG_NUM > 0 | ||
981 | case 'p': /* pXX Return gdb register XX (in hex) */ | ||
982 | gdb_cmd_reg_get(ks); | ||
983 | break; | ||
984 | case 'P': /* PXX=aaaa Set gdb register XX to aaaa (in hex) */ | ||
985 | gdb_cmd_reg_set(ks); | ||
986 | break; | ||
987 | #endif /* DBG_MAX_REG_NUM > 0 */ | ||
907 | case 'X': /* XAA..AA,LLLL: Write LLLL bytes at address AA..AA */ | 988 | case 'X': /* XAA..AA,LLLL: Write LLLL bytes at address AA..AA */ |
908 | gdb_cmd_binwrite(ks); | 989 | gdb_cmd_binwrite(ks); |
909 | break; | 990 | break; |
diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index ebe4a287419e..8577e45a9a58 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c | |||
@@ -312,7 +312,7 @@ int kdbgetularg(const char *arg, unsigned long *value) | |||
312 | 312 | ||
313 | if (endp == arg) { | 313 | if (endp == arg) { |
314 | /* | 314 | /* |
315 | * Try base 16, for us folks too lazy to type the | 315 | * Also try base 16, for us folks too lazy to type the |
316 | * leading 0x... | 316 | * leading 0x... |
317 | */ | 317 | */ |
318 | val = simple_strtoul(arg, &endp, 16); | 318 | val = simple_strtoul(arg, &endp, 16); |
@@ -325,6 +325,25 @@ int kdbgetularg(const char *arg, unsigned long *value) | |||
325 | return 0; | 325 | return 0; |
326 | } | 326 | } |
327 | 327 | ||
328 | int kdbgetu64arg(const char *arg, u64 *value) | ||
329 | { | ||
330 | char *endp; | ||
331 | u64 val; | ||
332 | |||
333 | val = simple_strtoull(arg, &endp, 0); | ||
334 | |||
335 | if (endp == arg) { | ||
336 | |||
337 | val = simple_strtoull(arg, &endp, 16); | ||
338 | if (endp == arg) | ||
339 | return KDB_BADINT; | ||
340 | } | ||
341 | |||
342 | *value = val; | ||
343 | |||
344 | return 0; | ||
345 | } | ||
346 | |||
328 | /* | 347 | /* |
329 | * kdb_set - This function implements the 'set' command. Alter an | 348 | * kdb_set - This function implements the 'set' command. Alter an |
330 | * existing environment variable or create a new one. | 349 | * existing environment variable or create a new one. |
@@ -1770,11 +1789,65 @@ static int kdb_go(int argc, const char **argv) | |||
1770 | */ | 1789 | */ |
1771 | static int kdb_rd(int argc, const char **argv) | 1790 | static int kdb_rd(int argc, const char **argv) |
1772 | { | 1791 | { |
1773 | int diag = kdb_check_regs(); | 1792 | int len = kdb_check_regs(); |
1774 | if (diag) | 1793 | #if DBG_MAX_REG_NUM > 0 |
1775 | return diag; | 1794 | int i; |
1795 | char *rname; | ||
1796 | int rsize; | ||
1797 | u64 reg64; | ||
1798 | u32 reg32; | ||
1799 | u16 reg16; | ||
1800 | u8 reg8; | ||
1801 | |||
1802 | if (len) | ||
1803 | return len; | ||
1804 | |||
1805 | for (i = 0; i < DBG_MAX_REG_NUM; i++) { | ||
1806 | rsize = dbg_reg_def[i].size * 2; | ||
1807 | if (rsize > 16) | ||
1808 | rsize = 2; | ||
1809 | if (len + strlen(dbg_reg_def[i].name) + 4 + rsize > 80) { | ||
1810 | len = 0; | ||
1811 | kdb_printf("\n"); | ||
1812 | } | ||
1813 | if (len) | ||
1814 | len += kdb_printf(" "); | ||
1815 | switch(dbg_reg_def[i].size * 8) { | ||
1816 | case 8: | ||
1817 | rname = dbg_get_reg(i, ®8, kdb_current_regs); | ||
1818 | if (!rname) | ||
1819 | break; | ||
1820 | len += kdb_printf("%s: %02x", rname, reg8); | ||
1821 | break; | ||
1822 | case 16: | ||
1823 | rname = dbg_get_reg(i, ®16, kdb_current_regs); | ||
1824 | if (!rname) | ||
1825 | break; | ||
1826 | len += kdb_printf("%s: %04x", rname, reg16); | ||
1827 | break; | ||
1828 | case 32: | ||
1829 | rname = dbg_get_reg(i, ®32, kdb_current_regs); | ||
1830 | if (!rname) | ||
1831 | break; | ||
1832 | len += kdb_printf("%s: %08x", rname, reg32); | ||
1833 | break; | ||
1834 | case 64: | ||
1835 | rname = dbg_get_reg(i, ®64, kdb_current_regs); | ||
1836 | if (!rname) | ||
1837 | break; | ||
1838 | len += kdb_printf("%s: %016llx", rname, reg64); | ||
1839 | break; | ||
1840 | default: | ||
1841 | len += kdb_printf("%s: ??", dbg_reg_def[i].name); | ||
1842 | } | ||
1843 | } | ||
1844 | kdb_printf("\n"); | ||
1845 | #else | ||
1846 | if (len) | ||
1847 | return len; | ||
1776 | 1848 | ||
1777 | kdb_dumpregs(kdb_current_regs); | 1849 | kdb_dumpregs(kdb_current_regs); |
1850 | #endif | ||
1778 | return 0; | 1851 | return 0; |
1779 | } | 1852 | } |
1780 | 1853 | ||
@@ -1782,32 +1855,67 @@ static int kdb_rd(int argc, const char **argv) | |||
1782 | * kdb_rm - This function implements the 'rm' (register modify) command. | 1855 | * kdb_rm - This function implements the 'rm' (register modify) command. |
1783 | * rm register-name new-contents | 1856 | * rm register-name new-contents |
1784 | * Remarks: | 1857 | * Remarks: |
1785 | * Currently doesn't allow modification of control or | 1858 | * Allows register modification with the same restrictions as gdb |
1786 | * debug registers. | ||
1787 | */ | 1859 | */ |
1788 | static int kdb_rm(int argc, const char **argv) | 1860 | static int kdb_rm(int argc, const char **argv) |
1789 | { | 1861 | { |
1862 | #if DBG_MAX_REG_NUM > 0 | ||
1790 | int diag; | 1863 | int diag; |
1791 | int ind = 0; | 1864 | const char *rname; |
1792 | unsigned long contents; | 1865 | int i; |
1866 | u64 reg64; | ||
1867 | u32 reg32; | ||
1868 | u16 reg16; | ||
1869 | u8 reg8; | ||
1793 | 1870 | ||
1794 | if (argc != 2) | 1871 | if (argc != 2) |
1795 | return KDB_ARGCOUNT; | 1872 | return KDB_ARGCOUNT; |
1796 | /* | 1873 | /* |
1797 | * Allow presence or absence of leading '%' symbol. | 1874 | * Allow presence or absence of leading '%' symbol. |
1798 | */ | 1875 | */ |
1799 | if (argv[1][0] == '%') | 1876 | rname = argv[1]; |
1800 | ind = 1; | 1877 | if (*rname == '%') |
1878 | rname++; | ||
1801 | 1879 | ||
1802 | diag = kdbgetularg(argv[2], &contents); | 1880 | diag = kdbgetu64arg(argv[2], ®64); |
1803 | if (diag) | 1881 | if (diag) |
1804 | return diag; | 1882 | return diag; |
1805 | 1883 | ||
1806 | diag = kdb_check_regs(); | 1884 | diag = kdb_check_regs(); |
1807 | if (diag) | 1885 | if (diag) |
1808 | return diag; | 1886 | return diag; |
1887 | |||
1888 | diag = KDB_BADREG; | ||
1889 | for (i = 0; i < DBG_MAX_REG_NUM; i++) { | ||
1890 | if (strcmp(rname, dbg_reg_def[i].name) == 0) { | ||
1891 | diag = 0; | ||
1892 | break; | ||
1893 | } | ||
1894 | } | ||
1895 | if (!diag) { | ||
1896 | switch(dbg_reg_def[i].size * 8) { | ||
1897 | case 8: | ||
1898 | reg8 = reg64; | ||
1899 | dbg_set_reg(i, ®8, kdb_current_regs); | ||
1900 | break; | ||
1901 | case 16: | ||
1902 | reg16 = reg64; | ||
1903 | dbg_set_reg(i, ®16, kdb_current_regs); | ||
1904 | break; | ||
1905 | case 32: | ||
1906 | reg32 = reg64; | ||
1907 | dbg_set_reg(i, ®32, kdb_current_regs); | ||
1908 | break; | ||
1909 | case 64: | ||
1910 | dbg_set_reg(i, ®64, kdb_current_regs); | ||
1911 | break; | ||
1912 | } | ||
1913 | } | ||
1914 | return diag; | ||
1915 | #else | ||
1809 | kdb_printf("ERROR: Register set currently not implemented\n"); | 1916 | kdb_printf("ERROR: Register set currently not implemented\n"); |
1810 | return 0; | 1917 | return 0; |
1918 | #endif | ||
1811 | } | 1919 | } |
1812 | 1920 | ||
1813 | #if defined(CONFIG_MAGIC_SYSRQ) | 1921 | #if defined(CONFIG_MAGIC_SYSRQ) |