Commit 55751145dc1e08e16df418cdd101661f5c6ac991

Authored by Jason Wessel
1 parent 22eeef4bb2

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, &regnum);
  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, &regnum);
  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;