diff options
author | Jason Wessel <jason.wessel@windriver.com> | 2010-08-05 10:22:21 -0400 |
---|---|---|
committer | Jason Wessel <jason.wessel@windriver.com> | 2010-08-05 10:22:21 -0400 |
commit | 55751145dc1e08e16df418cdd101661f5c6ac991 (patch) | |
tree | c166155b118da5768341e4678478c5dd508a2b17 /kernel/debug/gdbstub.c | |
parent | 22eeef4bb2a7fd225089c0044060ed1fbf091958 (diff) |
gdbstub: Implement gdbserial 'p' and 'P' packets
The gdbserial 'p' and 'P' packets allow gdb to individually get and
set registers instead of querying for all the available registers.
Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
Diffstat (limited to 'kernel/debug/gdbstub.c')
-rw-r--r-- | kernel/debug/gdbstub.c | 97 |
1 files changed, 77 insertions, 20 deletions
diff --git a/kernel/debug/gdbstub.c b/kernel/debug/gdbstub.c index 006bad8905d3..4ef9dddf4588 100644 --- a/kernel/debug/gdbstub.c +++ b/kernel/debug/gdbstub.c | |||
@@ -225,7 +225,7 @@ void gdbstub_msg_write(const char *s, int len) | |||
225 | * 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 |
226 | * return an error. | 226 | * return an error. |
227 | */ | 227 | */ |
228 | int kgdb_mem2hex(char *mem, char *buf, int count) | 228 | char *kgdb_mem2hex(char *mem, char *buf, int count) |
229 | { | 229 | { |
230 | char *tmp; | 230 | char *tmp; |
231 | int err; | 231 | int err; |
@@ -237,17 +237,16 @@ int kgdb_mem2hex(char *mem, char *buf, int count) | |||
237 | tmp = buf + count; | 237 | tmp = buf + count; |
238 | 238 | ||
239 | err = probe_kernel_read(tmp, mem, count); | 239 | err = probe_kernel_read(tmp, mem, count); |
240 | if (!err) { | 240 | if (err) |
241 | while (count > 0) { | 241 | return NULL; |
242 | buf = pack_hex_byte(buf, *tmp); | 242 | while (count > 0) { |
243 | tmp++; | 243 | buf = pack_hex_byte(buf, *tmp); |
244 | count--; | 244 | tmp++; |
245 | } | 245 | count--; |
246 | |||
247 | *buf = 0; | ||
248 | } | 246 | } |
247 | *buf = 0; | ||
249 | 248 | ||
250 | return err; | 249 | return buf; |
251 | } | 250 | } |
252 | 251 | ||
253 | /* | 252 | /* |
@@ -481,8 +480,7 @@ static void gdb_cmd_status(struct kgdb_state *ks) | |||
481 | pack_hex_byte(&remcom_out_buffer[1], ks->signo); | 480 | pack_hex_byte(&remcom_out_buffer[1], ks->signo); |
482 | } | 481 | } |
483 | 482 | ||
484 | /* Handle the 'g' get registers request */ | 483 | static void gdb_get_regs_helper(struct kgdb_state *ks) |
485 | static void gdb_cmd_getregs(struct kgdb_state *ks) | ||
486 | { | 484 | { |
487 | struct task_struct *thread; | 485 | struct task_struct *thread; |
488 | void *local_debuggerinfo; | 486 | void *local_debuggerinfo; |
@@ -523,6 +521,12 @@ static void gdb_cmd_getregs(struct kgdb_state *ks) | |||
523 | */ | 521 | */ |
524 | sleeping_thread_to_gdb_regs(gdb_regs, thread); | 522 | sleeping_thread_to_gdb_regs(gdb_regs, thread); |
525 | } | 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); | ||
526 | kgdb_mem2hex((char *)gdb_regs, remcom_out_buffer, NUMREGBYTES); | 530 | kgdb_mem2hex((char *)gdb_regs, remcom_out_buffer, NUMREGBYTES); |
527 | } | 531 | } |
528 | 532 | ||
@@ -545,13 +549,13 @@ static void gdb_cmd_memread(struct kgdb_state *ks) | |||
545 | char *ptr = &remcom_in_buffer[1]; | 549 | char *ptr = &remcom_in_buffer[1]; |
546 | unsigned long length; | 550 | unsigned long length; |
547 | unsigned long addr; | 551 | unsigned long addr; |
548 | int err; | 552 | char *err; |
549 | 553 | ||
550 | if (kgdb_hex2long(&ptr, &addr) > 0 && *ptr++ == ',' && | 554 | if (kgdb_hex2long(&ptr, &addr) > 0 && *ptr++ == ',' && |
551 | kgdb_hex2long(&ptr, &length) > 0) { | 555 | kgdb_hex2long(&ptr, &length) > 0) { |
552 | err = kgdb_mem2hex((char *)addr, remcom_out_buffer, length); | 556 | err = kgdb_mem2hex((char *)addr, remcom_out_buffer, length); |
553 | if (err) | 557 | if (!err) |
554 | error_packet(remcom_out_buffer, err); | 558 | error_packet(remcom_out_buffer, -EINVAL); |
555 | } else { | 559 | } else { |
556 | error_packet(remcom_out_buffer, -EINVAL); | 560 | error_packet(remcom_out_buffer, -EINVAL); |
557 | } | 561 | } |
@@ -568,6 +572,52 @@ static void gdb_cmd_memwrite(struct kgdb_state *ks) | |||
568 | strcpy(remcom_out_buffer, "OK"); | 572 | strcpy(remcom_out_buffer, "OK"); |
569 | } | 573 | } |
570 | 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 | |||
608 | kgdb_hex2long(&ptr, ®num); | ||
609 | if (*ptr++ != '=' || | ||
610 | !(!kgdb_usethread || kgdb_usethread == current) || | ||
611 | !dbg_get_reg(regnum, gdb_regs, ks->linux_regs)) { | ||
612 | error_packet(remcom_out_buffer, -EINVAL); | ||
613 | return; | ||
614 | } | ||
615 | kgdb_hex2mem(ptr, (char *)gdb_regs, dbg_reg_def[regnum].size); | ||
616 | dbg_set_reg(regnum, gdb_regs, ks->linux_regs); | ||
617 | strcpy(remcom_out_buffer, "OK"); | ||
618 | } | ||
619 | #endif /* DBG_MAX_REG_NUM > 0 */ | ||
620 | |||
571 | /* Handle the 'X' memory binary write bytes */ | 621 | /* Handle the 'X' memory binary write bytes */ |
572 | static void gdb_cmd_binwrite(struct kgdb_state *ks) | 622 | static void gdb_cmd_binwrite(struct kgdb_state *ks) |
573 | { | 623 | { |
@@ -874,8 +924,11 @@ int gdb_serial_stub(struct kgdb_state *ks) | |||
874 | int error = 0; | 924 | int error = 0; |
875 | int tmp; | 925 | int tmp; |
876 | 926 | ||
877 | /* Clear the out buffer. */ | 927 | /* Initialize comm buffer and globals. */ |
878 | memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer)); | 928 | memset(remcom_out_buffer, 0, sizeof(remcom_out_buffer)); |
929 | kgdb_usethread = kgdb_info[ks->cpu].task; | ||
930 | ks->kgdb_usethreadid = shadow_pid(kgdb_info[ks->cpu].task->pid); | ||
931 | ks->pass_exception = 0; | ||
879 | 932 | ||
880 | if (kgdb_connected) { | 933 | if (kgdb_connected) { |
881 | unsigned char thref[BUF_THREAD_ID_SIZE]; | 934 | unsigned char thref[BUF_THREAD_ID_SIZE]; |
@@ -892,10 +945,6 @@ int gdb_serial_stub(struct kgdb_state *ks) | |||
892 | put_packet(remcom_out_buffer); | 945 | put_packet(remcom_out_buffer); |
893 | } | 946 | } |
894 | 947 | ||
895 | kgdb_usethread = kgdb_info[ks->cpu].task; | ||
896 | ks->kgdb_usethreadid = shadow_pid(kgdb_info[ks->cpu].task->pid); | ||
897 | ks->pass_exception = 0; | ||
898 | |||
899 | while (1) { | 948 | while (1) { |
900 | error = 0; | 949 | error = 0; |
901 | 950 | ||
@@ -920,6 +969,14 @@ int gdb_serial_stub(struct kgdb_state *ks) | |||
920 | case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA..AA */ | 969 | case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA..AA */ |
921 | gdb_cmd_memwrite(ks); | 970 | gdb_cmd_memwrite(ks); |
922 | break; | 971 | break; |
972 | #if DBG_MAX_REG_NUM > 0 | ||
973 | case 'p': /* pXX Return gdb register XX (in hex) */ | ||
974 | gdb_cmd_reg_get(ks); | ||
975 | break; | ||
976 | case 'P': /* PXX=aaaa Set gdb register XX to aaaa (in hex) */ | ||
977 | gdb_cmd_reg_set(ks); | ||
978 | break; | ||
979 | #endif /* DBG_MAX_REG_NUM > 0 */ | ||
923 | case 'X': /* XAA..AA,LLLL: Write LLLL bytes at address AA..AA */ | 980 | case 'X': /* XAA..AA,LLLL: Write LLLL bytes at address AA..AA */ |
924 | gdb_cmd_binwrite(ks); | 981 | gdb_cmd_binwrite(ks); |
925 | break; | 982 | break; |