aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/misc/kgdbts.c54
1 files changed, 43 insertions, 11 deletions
diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c
index 997e94d618b..3cad9fce805 100644
--- a/drivers/misc/kgdbts.c
+++ b/drivers/misc/kgdbts.c
@@ -134,6 +134,9 @@ static int force_hwbrks;
134static int hwbreaks_ok; 134static int hwbreaks_ok;
135static int hw_break_val; 135static int hw_break_val;
136static int hw_break_val2; 136static int hw_break_val2;
137static int cont_instead_of_sstep;
138static unsigned long cont_thread_id;
139static unsigned long sstep_thread_id;
137#if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || defined(CONFIG_SPARC) 140#if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || defined(CONFIG_SPARC)
138static int arch_needs_sstep_emulation = 1; 141static int arch_needs_sstep_emulation = 1;
139#else 142#else
@@ -211,7 +214,7 @@ static unsigned long lookup_addr(char *arg)
211 if (!strcmp(arg, "kgdbts_break_test")) 214 if (!strcmp(arg, "kgdbts_break_test"))
212 addr = (unsigned long)kgdbts_break_test; 215 addr = (unsigned long)kgdbts_break_test;
213 else if (!strcmp(arg, "sys_open")) 216 else if (!strcmp(arg, "sys_open"))
214 addr = (unsigned long)sys_open; 217 addr = (unsigned long)do_sys_open;
215 else if (!strcmp(arg, "do_fork")) 218 else if (!strcmp(arg, "do_fork"))
216 addr = (unsigned long)do_fork; 219 addr = (unsigned long)do_fork;
217 else if (!strcmp(arg, "hw_break_val")) 220 else if (!strcmp(arg, "hw_break_val"))
@@ -283,6 +286,16 @@ static void hw_break_val_write(void)
283 hw_break_val++; 286 hw_break_val++;
284} 287}
285 288
289static int get_thread_id_continue(char *put_str, char *arg)
290{
291 char *ptr = &put_str[11];
292
293 if (put_str[1] != 'T' || put_str[2] != '0')
294 return 1;
295 kgdb_hex2long(&ptr, &cont_thread_id);
296 return 0;
297}
298
286static int check_and_rewind_pc(char *put_str, char *arg) 299static int check_and_rewind_pc(char *put_str, char *arg)
287{ 300{
288 unsigned long addr = lookup_addr(arg); 301 unsigned long addr = lookup_addr(arg);
@@ -324,6 +337,18 @@ static int check_single_step(char *put_str, char *arg)
324 gdb_regs_to_pt_regs(kgdbts_gdb_regs, &kgdbts_regs); 337 gdb_regs_to_pt_regs(kgdbts_gdb_regs, &kgdbts_regs);
325 v2printk("Singlestep stopped at IP: %lx\n", 338 v2printk("Singlestep stopped at IP: %lx\n",
326 instruction_pointer(&kgdbts_regs)); 339 instruction_pointer(&kgdbts_regs));
340
341 if (sstep_thread_id != cont_thread_id && !arch_needs_sstep_emulation) {
342 /*
343 * Ensure we stopped in the same thread id as before, else the
344 * debugger should continue until the original thread that was
345 * single stepped is scheduled again, emulating gdb's behavior.
346 */
347 v2printk("ThrID does not match: %lx\n", cont_thread_id);
348 cont_instead_of_sstep = 1;
349 ts.idx -= 4;
350 return 0;
351 }
327 if (instruction_pointer(&kgdbts_regs) == addr) { 352 if (instruction_pointer(&kgdbts_regs) == addr) {
328 eprintk("kgdbts: SingleStep failed at %lx\n", 353 eprintk("kgdbts: SingleStep failed at %lx\n",
329 instruction_pointer(&kgdbts_regs)); 354 instruction_pointer(&kgdbts_regs));
@@ -368,7 +393,12 @@ static int got_break(char *put_str, char *arg)
368static void emul_sstep_get(char *arg) 393static void emul_sstep_get(char *arg)
369{ 394{
370 if (!arch_needs_sstep_emulation) { 395 if (!arch_needs_sstep_emulation) {
371 fill_get_buf(arg); 396 if (cont_instead_of_sstep) {
397 cont_instead_of_sstep = 0;
398 fill_get_buf("c");
399 } else {
400 fill_get_buf(arg);
401 }
372 return; 402 return;
373 } 403 }
374 switch (sstep_state) { 404 switch (sstep_state) {
@@ -398,9 +428,11 @@ static void emul_sstep_get(char *arg)
398static int emul_sstep_put(char *put_str, char *arg) 428static int emul_sstep_put(char *put_str, char *arg)
399{ 429{
400 if (!arch_needs_sstep_emulation) { 430 if (!arch_needs_sstep_emulation) {
401 if (!strncmp(put_str+1, arg, 2)) 431 char *ptr = &put_str[11];
402 return 0; 432 if (put_str[1] != 'T' || put_str[2] != '0')
403 return 1; 433 return 1;
434 kgdb_hex2long(&ptr, &sstep_thread_id);
435 return 0;
404 } 436 }
405 switch (sstep_state) { 437 switch (sstep_state) {
406 case 1: 438 case 1:
@@ -502,10 +534,10 @@ static struct test_struct bad_read_test[] = {
502static struct test_struct singlestep_break_test[] = { 534static struct test_struct singlestep_break_test[] = {
503 { "?", "S0*" }, /* Clear break points */ 535 { "?", "S0*" }, /* Clear break points */
504 { "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */ 536 { "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */
505 { "c", "T0*", }, /* Continue */ 537 { "c", "T0*", NULL, get_thread_id_continue }, /* Continue */
538 { "kgdbts_break_test", "OK", sw_rem_break }, /*remove breakpoint */
506 { "g", "kgdbts_break_test", NULL, check_and_rewind_pc }, 539 { "g", "kgdbts_break_test", NULL, check_and_rewind_pc },
507 { "write", "OK", write_regs }, /* Write registers */ 540 { "write", "OK", write_regs }, /* Write registers */
508 { "kgdbts_break_test", "OK", sw_rem_break }, /*remove breakpoint */
509 { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */ 541 { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */
510 { "g", "kgdbts_break_test", NULL, check_single_step }, 542 { "g", "kgdbts_break_test", NULL, check_single_step },
511 { "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */ 543 { "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */
@@ -523,10 +555,10 @@ static struct test_struct singlestep_break_test[] = {
523static struct test_struct do_fork_test[] = { 555static struct test_struct do_fork_test[] = {
524 { "?", "S0*" }, /* Clear break points */ 556 { "?", "S0*" }, /* Clear break points */
525 { "do_fork", "OK", sw_break, }, /* set sw breakpoint */ 557 { "do_fork", "OK", sw_break, }, /* set sw breakpoint */
526 { "c", "T0*", }, /* Continue */ 558 { "c", "T0*", NULL, get_thread_id_continue }, /* Continue */
559 { "do_fork", "OK", sw_rem_break }, /*remove breakpoint */
527 { "g", "do_fork", NULL, check_and_rewind_pc }, /* check location */ 560 { "g", "do_fork", NULL, check_and_rewind_pc }, /* check location */
528 { "write", "OK", write_regs }, /* Write registers */ 561 { "write", "OK", write_regs }, /* Write registers */
529 { "do_fork", "OK", sw_rem_break }, /*remove breakpoint */
530 { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */ 562 { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */
531 { "g", "do_fork", NULL, check_single_step }, 563 { "g", "do_fork", NULL, check_single_step },
532 { "do_fork", "OK", sw_break, }, /* set sw breakpoint */ 564 { "do_fork", "OK", sw_break, }, /* set sw breakpoint */
@@ -541,10 +573,10 @@ static struct test_struct do_fork_test[] = {
541static struct test_struct sys_open_test[] = { 573static struct test_struct sys_open_test[] = {
542 { "?", "S0*" }, /* Clear break points */ 574 { "?", "S0*" }, /* Clear break points */
543 { "sys_open", "OK", sw_break, }, /* set sw breakpoint */ 575 { "sys_open", "OK", sw_break, }, /* set sw breakpoint */
544 { "c", "T0*", }, /* Continue */ 576 { "c", "T0*", NULL, get_thread_id_continue }, /* Continue */
577 { "sys_open", "OK", sw_rem_break }, /*remove breakpoint */
545 { "g", "sys_open", NULL, check_and_rewind_pc }, /* check location */ 578 { "g", "sys_open", NULL, check_and_rewind_pc }, /* check location */
546 { "write", "OK", write_regs }, /* Write registers */ 579 { "write", "OK", write_regs }, /* Write registers */
547 { "sys_open", "OK", sw_rem_break }, /*remove breakpoint */
548 { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */ 580 { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */
549 { "g", "sys_open", NULL, check_single_step }, 581 { "g", "sys_open", NULL, check_single_step },
550 { "sys_open", "OK", sw_break, }, /* set sw breakpoint */ 582 { "sys_open", "OK", sw_break, }, /* set sw breakpoint */