Commit 55751145dc1e08e16df418cdd101661f5c6ac991
1 parent
22eeef4bb2
Exists in
master
and in
7 other branches
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>
Showing 2 changed files with 78 additions and 21 deletions Side-by-side Diff
include/linux/kgdb.h
... | ... | @@ -294,7 +294,7 @@ |
294 | 294 | extern struct kgdb_io *dbg_io_ops; |
295 | 295 | |
296 | 296 | extern int kgdb_hex2long(char **ptr, unsigned long *long_val); |
297 | -extern int kgdb_mem2hex(char *mem, char *buf, int count); | |
297 | +extern char *kgdb_mem2hex(char *mem, char *buf, int count); | |
298 | 298 | extern int kgdb_hex2mem(char *buf, char *mem, int count); |
299 | 299 | |
300 | 300 | extern int kgdb_isremovedbreak(unsigned long addr); |
kernel/debug/gdbstub.c
... | ... | @@ -225,7 +225,7 @@ |
225 | 225 | * buf. Return a pointer to the last char put in buf (null). May |
226 | 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 | 230 | char *tmp; |
231 | 231 | int err; |
232 | 232 | |
233 | 233 | |
... | ... | @@ -237,17 +237,16 @@ |
237 | 237 | tmp = buf + count; |
238 | 238 | |
239 | 239 | err = probe_kernel_read(tmp, mem, count); |
240 | - if (!err) { | |
241 | - while (count > 0) { | |
242 | - buf = pack_hex_byte(buf, *tmp); | |
243 | - tmp++; | |
244 | - count--; | |
245 | - } | |
246 | - | |
247 | - *buf = 0; | |
240 | + if (err) | |
241 | + return NULL; | |
242 | + while (count > 0) { | |
243 | + buf = pack_hex_byte(buf, *tmp); | |
244 | + tmp++; | |
245 | + count--; | |
248 | 246 | } |
247 | + *buf = 0; | |
249 | 248 | |
250 | - return err; | |
249 | + return buf; | |
251 | 250 | } |
252 | 251 | |
253 | 252 | /* |
... | ... | @@ -481,8 +480,7 @@ |
481 | 480 | pack_hex_byte(&remcom_out_buffer[1], ks->signo); |
482 | 481 | } |
483 | 482 | |
484 | -/* Handle the 'g' get registers request */ | |
485 | -static void gdb_cmd_getregs(struct kgdb_state *ks) | |
483 | +static void gdb_get_regs_helper(struct kgdb_state *ks) | |
486 | 484 | { |
487 | 485 | struct task_struct *thread; |
488 | 486 | void *local_debuggerinfo; |
... | ... | @@ -523,6 +521,12 @@ |
523 | 521 | */ |
524 | 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 | 530 | kgdb_mem2hex((char *)gdb_regs, remcom_out_buffer, NUMREGBYTES); |
527 | 531 | } |
528 | 532 | |
529 | 533 | |
... | ... | @@ -545,13 +549,13 @@ |
545 | 549 | char *ptr = &remcom_in_buffer[1]; |
546 | 550 | unsigned long length; |
547 | 551 | unsigned long addr; |
548 | - int err; | |
552 | + char *err; | |
549 | 553 | |
550 | 554 | if (kgdb_hex2long(&ptr, &addr) > 0 && *ptr++ == ',' && |
551 | 555 | kgdb_hex2long(&ptr, &length) > 0) { |
552 | 556 | err = kgdb_mem2hex((char *)addr, remcom_out_buffer, length); |
553 | - if (err) | |
554 | - error_packet(remcom_out_buffer, err); | |
557 | + if (!err) | |
558 | + error_packet(remcom_out_buffer, -EINVAL); | |
555 | 559 | } else { |
556 | 560 | error_packet(remcom_out_buffer, -EINVAL); |
557 | 561 | } |
... | ... | @@ -568,6 +572,52 @@ |
568 | 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 | 621 | /* Handle the 'X' memory binary write bytes */ |
572 | 622 | static void gdb_cmd_binwrite(struct kgdb_state *ks) |
573 | 623 | { |
574 | 624 | |
... | ... | @@ -874,8 +924,11 @@ |
874 | 924 | int error = 0; |
875 | 925 | int tmp; |
876 | 926 | |
877 | - /* Clear the out buffer. */ | |
927 | + /* Initialize comm buffer and globals. */ | |
878 | 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 | 933 | if (kgdb_connected) { |
881 | 934 | unsigned char thref[BUF_THREAD_ID_SIZE]; |
... | ... | @@ -892,10 +945,6 @@ |
892 | 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 | 948 | while (1) { |
900 | 949 | error = 0; |
901 | 950 | |
... | ... | @@ -920,6 +969,14 @@ |
920 | 969 | case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA..AA */ |
921 | 970 | gdb_cmd_memwrite(ks); |
922 | 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 | 980 | case 'X': /* XAA..AA,LLLL: Write LLLL bytes at address AA..AA */ |
924 | 981 | gdb_cmd_binwrite(ks); |
925 | 982 | break; |