diff options
Diffstat (limited to 'kernel')
| -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; |
