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 void emul_sstep_get(char *arg) { if (!arch_needs_sstep_emulation) { fill_get_buf(arg); return; } switch (sstep_state) { case 0: v2printk("Emulate single step\n"); /* Start by looking at the current PC */ fill_get_buf("g"); break; case 1: /* set breakpoint */ break_helper("Z0", NULL, sstep_addr); break; case 2: /* Continue */ fill_get_buf("c"); break; case 3: /* Clear breakpoint */ break_helper("z0", NULL, sstep_addr); break; default: eprintk("kgdbts: ERROR failed sstep get emulation\n"); } sstep_state++; }
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 put_cont_catch(char *put_str, char *arg) { /* This is at the end of the test and we catch any and all input */ v2printk("kgdbts: cleanup task: %lx\n", sstep_thread_id); 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 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_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; }
static void fill_get_buf(char *buf) { unsigned char checksum = 0; int count = 0; char ch; strcpy(get_buf, "$"); strcat(get_buf, buf); while ((ch = buf[count])) { checksum += ch; count++; } strcat(get_buf, "#"); get_buf[count + 2] = hex_asc_hi(checksum); get_buf[count + 3] = hex_asc_lo(checksum); get_buf[count + 4] = '\0'; v2printk("get%i: %s\n", ts.idx, get_buf); }
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 run_simple_test(int is_get_char, int chr) { int ret = 0; if (is_get_char) { /* Send an ACK on the get if a prior put completed and set the * send ack variable */ if (send_ack) { send_ack = 0; return '+'; } /* On the first get char, fill the transmit buffer and then * take from the get_string. */ if (get_buf_cnt == 0) { if (ts.tst[ts.idx].get_handler) ts.tst[ts.idx].get_handler(ts.tst[ts.idx].get); else fill_get_buf(ts.tst[ts.idx].get); } if (get_buf[get_buf_cnt] == '\0') { eprintk("kgdbts: ERROR GET: EOB on '%s' at %i\n", ts.name, ts.idx); get_buf_cnt = 0; fill_get_buf("D"); } ret = get_buf[get_buf_cnt]; get_buf_cnt++; return ret; } /* This callback is a put char which is when kgdb sends data to * this I/O module. */ if (ts.tst[ts.idx].get[0] == '\0' && ts.tst[ts.idx].put[0] == '\0') { eprintk("kgdbts: ERROR: beyond end of test on" " '%s' line %i\n", ts.name, ts.idx); return 0; } if (put_buf_cnt >= BUFMAX) { eprintk("kgdbts: ERROR: put buffer overflow on" " '%s' line %i\n", ts.name, ts.idx); put_buf_cnt = 0; return 0; } /* Ignore everything until the first valid packet start '$' */ if (put_buf_cnt == 0 && chr != '$') return 0; put_buf[put_buf_cnt] = chr; put_buf_cnt++; /* End of packet == #XX so look for the '#' */ if (put_buf_cnt > 3 && put_buf[put_buf_cnt - 3] == '#') { if (put_buf_cnt >= BUFMAX) { eprintk("kgdbts: ERROR: put buffer overflow on" " '%s' line %i\n", ts.name, ts.idx); put_buf_cnt = 0; return 0; } put_buf[put_buf_cnt] = '\0'; v2printk("put%i: %s\n", ts.idx, put_buf); /* Trigger check here */ if (ts.validate_put && ts.validate_put(put_buf)) { eprintk("kgdbts: ERROR PUT: end of test " "buffer on '%s' line %i expected %s got %s\n", ts.name, ts.idx, ts.tst[ts.idx].put, put_buf); } ts.idx++; put_buf_cnt = 0; get_buf_cnt = 0; send_ack = 1; } return 0; }
/* This is noinline such that it can be used for a single location to * place a breakpoint */ static noinline void kgdbts_break_test(void) { v2printk("kgdbts: breakpoint complete\n"); }