static int check_and_rewind_pc(char *put_str, char *arg) { unsigned long addr = lookup_addr(arg); unsigned long ip; int offset = 0; kgdb_hex2mem(&put_str[1], (char *)kgdbts_gdb_regs, NUMREGBYTES); gdb_regs_to_pt_regs(kgdbts_gdb_regs, &kgdbts_regs); ip = instruction_pointer(&kgdbts_regs); v2printk("Stopped at IP: %lx\n", ip); #ifdef GDB_ADJUSTS_BREAK_OFFSET /* On some arches, a breakpoint stop requires it to be decremented */ if (addr + BREAK_INSTR_SIZE == ip) offset = -BREAK_INSTR_SIZE; #endif if (strcmp(arg, "silent") && ip + offset != addr) { eprintk("kgdbts: BP mismatch %lx expected %lx\n", ip + offset, addr); return 1; } /* Readjust the instruction pointer if needed */ ip += offset; #ifdef GDB_ADJUSTS_BREAK_OFFSET instruction_pointer_set(&kgdbts_regs, ip); #endif return 0; }
static int check_and_rewind_pc(char *put_str, char *arg) { unsigned long addr = lookup_addr(arg); int offset = 0; kgdb_hex2mem(&put_str[1], (char *)kgdbts_gdb_regs, NUMREGBYTES); gdb_regs_to_pt_regs(kgdbts_gdb_regs, &kgdbts_regs); v2printk("Stopped at IP: %lx\n", instruction_pointer(&kgdbts_regs)); #ifdef CONFIG_X86 /* On x86 a breakpoint stop requires it to be decremented */ if (addr + 1 == kgdbts_regs.ip) offset = -1; #endif if (strcmp(arg, "silent") && instruction_pointer(&kgdbts_regs) + offset != addr) { eprintk("kgdbts: BP mismatch %lx expected %lx\n", instruction_pointer(&kgdbts_regs) + offset, addr); return 1; } #ifdef CONFIG_X86 /* On x86 adjust the instruction pointer if needed */ kgdbts_regs.ip += offset; #endif return 0; }
static int emul_sstep_put(char *put_str, char *arg) { if (!arch_needs_sstep_emulation) { char *ptr = &put_str[11]; if (put_str[1] != 'T' || put_str[2] != '0') return 1; kgdb_hex2long(&ptr, &sstep_thread_id); return 0; } switch (sstep_state) { case 1: /* validate the "g" packet to get the IP */ kgdb_hex2mem(&put_str[1], (char *)kgdbts_gdb_regs, NUMREGBYTES); gdb_regs_to_pt_regs(kgdbts_gdb_regs, &kgdbts_regs); v2printk("Stopped at IP: %lx\n", instruction_pointer(&kgdbts_regs)); /* Want to stop at IP + break instruction size by default */ sstep_addr = cont_addr + BREAK_INSTR_SIZE; break; case 2: if (strncmp(put_str, "$OK", 3)) { eprintk("kgdbts: failed sstep break set\n"); return 1; } break; case 3: if (strncmp(put_str, "$T0", 3)) { eprintk("kgdbts: failed continue sstep\n"); return 1; } else { char *ptr = &put_str[11]; kgdb_hex2long(&ptr, &sstep_thread_id); } break; case 4: if (strncmp(put_str, "$OK", 3)) { eprintk("kgdbts: failed sstep break unset\n"); return 1; } /* Single step is complete so continue on! */ sstep_state = 0; return 0; default: eprintk("kgdbts: ERROR failed sstep put emulation\n"); } /* Continue on the same test line until emulation is complete */ ts.idx--; return 0; }
static int check_single_step(char *put_str, char *arg) { unsigned long addr = lookup_addr(arg); static int matched_id; /* * From an arch indepent point of view the instruction pointer * should be on a different instruction */ kgdb_hex2mem(&put_str[1], (char *)kgdbts_gdb_regs, NUMREGBYTES); gdb_regs_to_pt_regs(kgdbts_gdb_regs, &kgdbts_regs); v2printk("Singlestep stopped at IP: %lx\n", instruction_pointer(&kgdbts_regs)); if (sstep_thread_id != cont_thread_id) { /* * Ensure we stopped in the same thread id as before, else the * debugger should continue until the original thread that was * single stepped is scheduled again, emulating gdb's behavior. */ v2printk("ThrID does not match: %lx\n", cont_thread_id); if (arch_needs_sstep_emulation) { if (matched_id && instruction_pointer(&kgdbts_regs) != addr) goto continue_test; matched_id++; ts.idx -= 2; sstep_state = 0; return 0; } cont_instead_of_sstep = 1; ts.idx -= 4; return 0; } continue_test: matched_id = 0; if (instruction_pointer(&kgdbts_regs) == addr) { eprintk("kgdbts: SingleStep failed at %lx\n", instruction_pointer(&kgdbts_regs)); return 1; } return 0; }
static int check_single_step(char *put_str, char *arg) { unsigned long addr = lookup_addr(arg); /* * From an arch indepent point of view the instruction pointer * should be on a different instruction */ kgdb_hex2mem(&put_str[1], (char *)kgdbts_gdb_regs, NUMREGBYTES); gdb_regs_to_pt_regs(kgdbts_gdb_regs, &kgdbts_regs); v2printk("Singlestep stopped at IP: %lx\n", instruction_pointer(&kgdbts_regs)); if (instruction_pointer(&kgdbts_regs) == addr) { eprintk("kgdbts: SingleStep failed at %lx\n", instruction_pointer(&kgdbts_regs)); return 1; } return 0; }
static int check_and_rewind_pc(char *put_str, char *arg) { unsigned long addr = lookup_addr(arg); unsigned long ip; int offset = 0; kgdb_hex2mem(&put_str[1], (char *)kgdbts_gdb_regs, NUMREGBYTES); gdb_regs_to_pt_regs(kgdbts_gdb_regs, &kgdbts_regs); ip = instruction_pointer(&kgdbts_regs); v2printk("Stopped at IP: %lx\n", ip); #ifdef GDB_ADJUSTS_BREAK_OFFSET /* On some arches, a breakpoint stop requires it to be decremented */ if (addr + BREAK_INSTR_SIZE == ip) offset = -BREAK_INSTR_SIZE; #endif if (arch_needs_sstep_emulation && sstep_addr && ip + offset == sstep_addr && ((!strcmp(arg, "sys_open") || !strcmp(arg, "do_fork")))) { /* This is special case for emulated single step */ v2printk("Emul: rewind hit single step bp\n"); restart_from_top_after_write = 1; } else if (strcmp(arg, "silent") && ip + offset != addr) { eprintk("kgdbts: BP mismatch %lx expected %lx\n", ip + offset, addr); return 1; } /* Readjust the instruction pointer if needed */ ip += offset; cont_addr = ip; #ifdef GDB_ADJUSTS_BREAK_OFFSET instruction_pointer_set(&kgdbts_regs, ip); #endif return 0; }