aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/kgdbts.c73
1 files changed, 62 insertions, 11 deletions
diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c
index 3cad9fce8054..d087456ba089 100644
--- a/drivers/misc/kgdbts.c
+++ b/drivers/misc/kgdbts.c
@@ -142,7 +142,9 @@ static int arch_needs_sstep_emulation = 1;
142#else 142#else
143static int arch_needs_sstep_emulation; 143static int arch_needs_sstep_emulation;
144#endif 144#endif
145static unsigned long cont_addr;
145static unsigned long sstep_addr; 146static unsigned long sstep_addr;
147static int restart_from_top_after_write;
146static int sstep_state; 148static int sstep_state;
147 149
148/* Storage for the registers, in GDB format. */ 150/* Storage for the registers, in GDB format. */
@@ -190,7 +192,8 @@ static int kgdbts_unreg_thread(void *ptr)
190 */ 192 */
191 while (!final_ack) 193 while (!final_ack)
192 msleep_interruptible(1500); 194 msleep_interruptible(1500);
193 195 /* Pause for any other threads to exit after final ack. */
196 msleep_interruptible(1000);
194 if (configured) 197 if (configured)
195 kgdb_unregister_io_module(&kgdbts_io_ops); 198 kgdb_unregister_io_module(&kgdbts_io_ops);
196 configured = 0; 199 configured = 0;
@@ -312,13 +315,21 @@ static int check_and_rewind_pc(char *put_str, char *arg)
312 if (addr + BREAK_INSTR_SIZE == ip) 315 if (addr + BREAK_INSTR_SIZE == ip)
313 offset = -BREAK_INSTR_SIZE; 316 offset = -BREAK_INSTR_SIZE;
314#endif 317#endif
315 if (strcmp(arg, "silent") && ip + offset != addr) { 318
319 if (arch_needs_sstep_emulation && sstep_addr &&
320 ip + offset == sstep_addr &&
321 ((!strcmp(arg, "sys_open") || !strcmp(arg, "do_fork")))) {
322 /* This is special case for emulated single step */
323 v2printk("Emul: rewind hit single step bp\n");
324 restart_from_top_after_write = 1;
325 } else if (strcmp(arg, "silent") && ip + offset != addr) {
316 eprintk("kgdbts: BP mismatch %lx expected %lx\n", 326 eprintk("kgdbts: BP mismatch %lx expected %lx\n",
317 ip + offset, addr); 327 ip + offset, addr);
318 return 1; 328 return 1;
319 } 329 }
320 /* Readjust the instruction pointer if needed */ 330 /* Readjust the instruction pointer if needed */
321 ip += offset; 331 ip += offset;
332 cont_addr = ip;
322#ifdef GDB_ADJUSTS_BREAK_OFFSET 333#ifdef GDB_ADJUSTS_BREAK_OFFSET
323 instruction_pointer_set(&kgdbts_regs, ip); 334 instruction_pointer_set(&kgdbts_regs, ip);
324#endif 335#endif
@@ -328,6 +339,8 @@ static int check_and_rewind_pc(char *put_str, char *arg)
328static int check_single_step(char *put_str, char *arg) 339static int check_single_step(char *put_str, char *arg)
329{ 340{
330 unsigned long addr = lookup_addr(arg); 341 unsigned long addr = lookup_addr(arg);
342 static int matched_id;
343
331 /* 344 /*
332 * From an arch indepent point of view the instruction pointer 345 * From an arch indepent point of view the instruction pointer
333 * should be on a different instruction 346 * should be on a different instruction
@@ -338,17 +351,28 @@ static int check_single_step(char *put_str, char *arg)
338 v2printk("Singlestep stopped at IP: %lx\n", 351 v2printk("Singlestep stopped at IP: %lx\n",
339 instruction_pointer(&kgdbts_regs)); 352 instruction_pointer(&kgdbts_regs));
340 353
341 if (sstep_thread_id != cont_thread_id && !arch_needs_sstep_emulation) { 354 if (sstep_thread_id != cont_thread_id) {
342 /* 355 /*
343 * Ensure we stopped in the same thread id as before, else the 356 * Ensure we stopped in the same thread id as before, else the
344 * debugger should continue until the original thread that was 357 * debugger should continue until the original thread that was
345 * single stepped is scheduled again, emulating gdb's behavior. 358 * single stepped is scheduled again, emulating gdb's behavior.
346 */ 359 */
347 v2printk("ThrID does not match: %lx\n", cont_thread_id); 360 v2printk("ThrID does not match: %lx\n", cont_thread_id);
361 if (arch_needs_sstep_emulation) {
362 if (matched_id &&
363 instruction_pointer(&kgdbts_regs) != addr)
364 goto continue_test;
365 matched_id++;
366 ts.idx -= 2;
367 sstep_state = 0;
368 return 0;
369 }
348 cont_instead_of_sstep = 1; 370 cont_instead_of_sstep = 1;
349 ts.idx -= 4; 371 ts.idx -= 4;
350 return 0; 372 return 0;
351 } 373 }
374continue_test:
375 matched_id = 0;
352 if (instruction_pointer(&kgdbts_regs) == addr) { 376 if (instruction_pointer(&kgdbts_regs) == addr) {
353 eprintk("kgdbts: SingleStep failed at %lx\n", 377 eprintk("kgdbts: SingleStep failed at %lx\n",
354 instruction_pointer(&kgdbts_regs)); 378 instruction_pointer(&kgdbts_regs));
@@ -390,6 +414,31 @@ static int got_break(char *put_str, char *arg)
390 return 1; 414 return 1;
391} 415}
392 416
417static void get_cont_catch(char *arg)
418{
419 /* Always send detach because the test is completed at this point */
420 fill_get_buf("D");
421}
422
423static int put_cont_catch(char *put_str, char *arg)
424{
425 /* This is at the end of the test and we catch any and all input */
426 v2printk("kgdbts: cleanup task: %lx\n", sstep_thread_id);
427 ts.idx--;
428 return 0;
429}
430
431static int emul_reset(char *put_str, char *arg)
432{
433 if (strncmp(put_str, "$OK", 3))
434 return 1;
435 if (restart_from_top_after_write) {
436 restart_from_top_after_write = 0;
437 ts.idx = -1;
438 }
439 return 0;
440}
441
393static void emul_sstep_get(char *arg) 442static void emul_sstep_get(char *arg)
394{ 443{
395 if (!arch_needs_sstep_emulation) { 444 if (!arch_needs_sstep_emulation) {
@@ -443,8 +492,7 @@ static int emul_sstep_put(char *put_str, char *arg)
443 v2printk("Stopped at IP: %lx\n", 492 v2printk("Stopped at IP: %lx\n",
444 instruction_pointer(&kgdbts_regs)); 493 instruction_pointer(&kgdbts_regs));
445 /* Want to stop at IP + break instruction size by default */ 494 /* Want to stop at IP + break instruction size by default */
446 sstep_addr = instruction_pointer(&kgdbts_regs) + 495 sstep_addr = cont_addr + BREAK_INSTR_SIZE;
447 BREAK_INSTR_SIZE;
448 break; 496 break;
449 case 2: 497 case 2:
450 if (strncmp(put_str, "$OK", 3)) { 498 if (strncmp(put_str, "$OK", 3)) {
@@ -456,6 +504,9 @@ static int emul_sstep_put(char *put_str, char *arg)
456 if (strncmp(put_str, "$T0", 3)) { 504 if (strncmp(put_str, "$T0", 3)) {
457 eprintk("kgdbts: failed continue sstep\n"); 505 eprintk("kgdbts: failed continue sstep\n");
458 return 1; 506 return 1;
507 } else {
508 char *ptr = &put_str[11];
509 kgdb_hex2long(&ptr, &sstep_thread_id);
459 } 510 }
460 break; 511 break;
461 case 4: 512 case 4:
@@ -558,13 +609,13 @@ static struct test_struct do_fork_test[] = {
558 { "c", "T0*", NULL, get_thread_id_continue }, /* Continue */ 609 { "c", "T0*", NULL, get_thread_id_continue }, /* Continue */
559 { "do_fork", "OK", sw_rem_break }, /*remove breakpoint */ 610 { "do_fork", "OK", sw_rem_break }, /*remove breakpoint */
560 { "g", "do_fork", NULL, check_and_rewind_pc }, /* check location */ 611 { "g", "do_fork", NULL, check_and_rewind_pc }, /* check location */
561 { "write", "OK", write_regs }, /* Write registers */ 612 { "write", "OK", write_regs, emul_reset }, /* Write registers */
562 { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */ 613 { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */
563 { "g", "do_fork", NULL, check_single_step }, 614 { "g", "do_fork", NULL, check_single_step },
564 { "do_fork", "OK", sw_break, }, /* set sw breakpoint */ 615 { "do_fork", "OK", sw_break, }, /* set sw breakpoint */
565 { "7", "T0*", skip_back_repeat_test }, /* Loop based on repeat_test */ 616 { "7", "T0*", skip_back_repeat_test }, /* Loop based on repeat_test */
566 { "D", "OK", NULL, final_ack_set }, /* detach and unregister I/O */ 617 { "D", "OK", NULL, final_ack_set }, /* detach and unregister I/O */
567 { "", "" }, 618 { "", "", get_cont_catch, put_cont_catch },
568}; 619};
569 620
570/* Test for hitting a breakpoint at sys_open for what ever the number 621/* Test for hitting a breakpoint at sys_open for what ever the number
@@ -576,13 +627,13 @@ static struct test_struct sys_open_test[] = {
576 { "c", "T0*", NULL, get_thread_id_continue }, /* Continue */ 627 { "c", "T0*", NULL, get_thread_id_continue }, /* Continue */
577 { "sys_open", "OK", sw_rem_break }, /*remove breakpoint */ 628 { "sys_open", "OK", sw_rem_break }, /*remove breakpoint */
578 { "g", "sys_open", NULL, check_and_rewind_pc }, /* check location */ 629 { "g", "sys_open", NULL, check_and_rewind_pc }, /* check location */
579 { "write", "OK", write_regs }, /* Write registers */ 630 { "write", "OK", write_regs, emul_reset }, /* Write registers */
580 { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */ 631 { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */
581 { "g", "sys_open", NULL, check_single_step }, 632 { "g", "sys_open", NULL, check_single_step },
582 { "sys_open", "OK", sw_break, }, /* set sw breakpoint */ 633 { "sys_open", "OK", sw_break, }, /* set sw breakpoint */
583 { "7", "T0*", skip_back_repeat_test }, /* Loop based on repeat_test */ 634 { "7", "T0*", skip_back_repeat_test }, /* Loop based on repeat_test */
584 { "D", "OK", NULL, final_ack_set }, /* detach and unregister I/O */ 635 { "D", "OK", NULL, final_ack_set }, /* detach and unregister I/O */
585 { "", "" }, 636 { "", "", get_cont_catch, put_cont_catch },
586}; 637};
587 638
588/* 639/*
@@ -725,8 +776,8 @@ static int run_simple_test(int is_get_char, int chr)
725 /* This callback is a put char which is when kgdb sends data to 776 /* This callback is a put char which is when kgdb sends data to
726 * this I/O module. 777 * this I/O module.
727 */ 778 */
728 if (ts.tst[ts.idx].get[0] == '\0' && 779 if (ts.tst[ts.idx].get[0] == '\0' && ts.tst[ts.idx].put[0] == '\0' &&
729 ts.tst[ts.idx].put[0] == '\0') { 780 !ts.tst[ts.idx].get_handler) {
730 eprintk("kgdbts: ERROR: beyond end of test on" 781 eprintk("kgdbts: ERROR: beyond end of test on"
731 " '%s' line %i\n", ts.name, ts.idx); 782 " '%s' line %i\n", ts.name, ts.idx);
732 return 0; 783 return 0;