static void gdb_cmd_rm_brk(uint8_t *data, size_t len) { uint64_t type; size_t size; offset_t addr; int rc; if(!__gdb_setup_brk_op(data, len, &type, &size, &addr)) return; switch(type) { case GDB_BRK_TYPE_MEM: rc = dbg_soft_del(addr); break; case GDB_BRK_TYPE_HRD_X: case GDB_BRK_TYPE_HRD_W: case GDB_BRK_TYPE_HRD_RW: rc = dbg_hard_brk_del(addr, type-1, size-1); break; default: gdb_unsupported(); return; } if(rc == DBG_BRK_OK) { gdb_ok(); return; } gdb_err_mem(); }
static void gdb_vmm_wr_sysreg(uint8_t *data, size_t len) { raw64_t *reg, value; size_t size; if(!__gdb_setup_reg_op(data, len, ®, &size, &value, 1, 1)) { debug(GDBSTUB_CMD, "write sysreg failed\n"); return; } if(reg == (raw64_t*)&__cr0 && __resolve_cr0_wr((cr0_reg_t*)&value) == VM_FAIL) goto __err; else if(reg == (raw64_t*)&__cr3 && __resolve_cr3_wr((cr3_reg_t*)&value) == VM_FAIL) goto __err; else if(reg == (raw64_t*)&__cr4 && __resolve_cr4_wr((cr4_reg_t*)&value) == VM_FAIL) goto __err; else reg->raw = value.raw; gdb_ok(); return; __err: debug(GDBSTUB_CMD, "invalid wr to control register\n"); gdb_err_inv(); }
static void gdb_vmm_npg_set_pte(uint8_t *data, size_t len) { uint64_t args[2]; loc_t addr; npg_pte64_t npte, *opte; if(!__gdb_vmm_parse_args(data, len, args, 2)) { gdb_nak(); return; } addr.raw = args[0]; opte = _npg_get_pte(addr.linear); if(!opte) { debug(GDBSTUB_CMD, "no npg pte for 0x%x\n", addr.raw); gdb_err_mem(); return; } npte.raw = args[1]; opte->raw = npte.raw; npg_invlpg(addr.linear); gdb_ok(); }
static void gdb_cmd_kill() { debug(GDBSTUB_CMD, "gdb kill\n"); gdb_reset(); gdb_ok(); return; }
static void gdb_vmm_clear_idt_event(uint8_t __unused__ *data, size_t __unused__ len) { if(__injecting_event()) __clear_event_injection(); gdb_ok(); }
static void gdb_cmd_detach() { debug(GDBSTUB_CMD, "gdb detach\n"); gdb_reset(); gdb_ok(); gdb_wait_ack(); return; }
/* gdb_q(): * Query. Not sure what this is for, but according to Gatliff's * article, just do it... */ int gdb_q(char *line) { line++; if (strncmp(line,"Offsets",7) == 0) return(gdb_response("Text=0;Data=0;Bss=0")); else return(gdb_ok()); }
static void gdb_vmm_keep_active_cr3(uint8_t __unused__ *data, size_t __unused__ len) { if(ctrl_cr3_enabled()) { ctrl_set_cr3_keep(1); gdb_ok(); return; } gdb_err_inv(); }
static void gdb_vmm_set_active_cr3(uint8_t *data, size_t len) { cr3_reg_t val; if(!gdb_get_number(data, len, (uint64_t*)&val.raw, 0)) { gdb_nak(); return; } ctrl_active_cr3_enable(val); gdb_ok(); }
static void gdb_vmm_npg_unmap(uint8_t *data, size_t len) { uint64_t args[2]; if(!__gdb_vmm_parse_args(data, len, args, 2)) { gdb_nak(); return; } npg_unmap((offset_t)args[0], (offset_t)args[1]); gdb_ok(); }
static void gdb_vmm_wr_cr_rd_mask(uint8_t *data, size_t len) { raw64_t val; if(!gdb_get_number(data, len, (uint64_t*)&val.raw, 0)) { gdb_nak(); return; } ctrl_usr_set_cr_rd(val.wlow); gdb_ok(); }
static void gdb_vmm_set_affinity(uint8_t *data, size_t len) { raw64_t val; if(!gdb_get_number(data, len, (uint64_t*)&val.raw, 0)) { gdb_nak(); return; } ctrl_set_affinity(val.blow); gdb_ok(); debug(GDBSTUB_CMD, "set affinity to %d\n", val.blow); }
static void gdb_vmm_wr_excp_mask(uint8_t *data, size_t len) { raw64_t val; if(!gdb_get_number(data, len, (uint64_t*)&val.raw, 0)) { gdb_nak(); return; } info->vmm.ctrl.usr.excp = val.low; __update_exception_mask(); gdb_ok(); }
static void gdb_vmm_wr_cr_wr_mask(uint8_t *data, size_t len) { raw64_t val; if(!gdb_get_number(data, len, (uint64_t*)&val.raw, 0)) { gdb_nak(); return; } debug(GDBSTUB_CMD, "write cr mask 0x%x\n", val.wlow); ctrl_usr_set_cr_wr(val.wlow); gdb_ok(); }
static void gdb_cmd_thread(uint8_t *data) { switch(*data) { case 'g': case 'c': /* ignore thread-id */ debug(GDBSTUB_CMD, "gdb ok for thread\n"); gdb_ok(); break; default : debug(GDBSTUB_CMD, "thread unsupported\n"); gdb_unsupported(); break; } }
static void gdb_cmd_wr_reg(uint8_t *data, size_t len) { raw64_t *reg, value; size_t size; if(!__gdb_setup_reg_op(data, len, ®, &size, &value, 1, 0)) return; switch(size) { case 2: reg->wlow = value.wlow; break; case 4: reg->low = value.low; break; case 8: reg->raw = value.raw; break; } gdb_ok(); }
static void gdb_cmd_wr_mem(uint8_t *data, size_t len) { offset_t addr; loc_t bytes; size_t size, lbytes, can, i; uint8_t store[128]; if(!__gdb_setup_mem_op(data, len, &addr, &size, &bytes)) return; debug(GDBSTUB_CMD, "write mem: addr 0x%X size %D\n", addr, size); lbytes = (size_t)data + len - bytes.linear; if(lbytes/2 != size) { debug(GDBSTUB_CMD, "gdb cmd_wr_mem missing bytes\n"); gdb_unsupported(); } while(size) { can = min(size, sizeof(store)); for(i=0 ; i<can ; i++, bytes.u16++) { if(!__hex_to_uint8(bytes.u8, &store[i])) { debug(GDBSTUB_CMD, "gdb cmd_wr_mem invalid byte\n"); gdb_unsupported(); } } if(!gdb_mem_write(addr, store, can)) { debug(GDBSTUB_CMD, "access failure\n"); gdb_err_mem(); return; } addr += can; size -= can; } gdb_ok(); }
static int __gdb_vmm_mem_rw_parse(uint8_t *data, size_t len, loc_t *addr, size_t *sz) { uint64_t args[2]; if(!__gdb_vmm_parse_args(data, len, args, 2)) { gdb_nak(); return 0; } addr->raw = args[0]; *sz = (size_t)args[1]; gdb_ok(); gdb_wait_ack(); return 1; }
/* gdb_M(): * GDB memory write command... * Incoming command format is... * * MADDR,LEN:DATA#CC * * where: * 'M' is the "memory read" request * 'ADDR' is the address from which the data is to be read * 'LEN' is the number of bytes to be read * 'DATA' is the ascii data * * STATUS: This function has been tested with m68k-elf-gdb (xtools) * and appears to work ok. */ int gdb_M(char *line) { int len, i; char *lp; uchar *addr, buf[3]; addr = (uchar *)strtol(line+1,&lp,16); len = (int)strtol(lp+1,&lp,16); lp++; buf[2] = 0; for(i=0;i<len;i++) { buf[0] = *lp++; buf[1] = *lp++; *addr++ = (uchar)strtol((char *)buf,0,16); } gdb_ok(); return(0); }
/* gdb_P(): * Store to a register. */ int gdb_P(char *line) { char *lp; int rnum; ulong rval; line++; rnum = strtol(line,&lp,16); if (rnum >= REGTBL_SIZE) { gdb_err(GDBERR_RNUMOOR); return(-1); } lp++; rval = strtol(lp,0,16); self_ecl(rval); putreg(gdb_regtbl[rnum],rval); gdb_ok(); return(0); }
/* gdb_m(): * GDB memory read command... * Incoming command format is... * * mADDR,LEN#CC * * where: * 'm' is the "memory read" request * 'ADDR' is the address from which the data is to be read * 'LEN' is the number of bytes to be read * */ int gdb_m(char *line) { int len, i; char *lp; uchar *addr, *resp, buf[128]; addr = (uchar *)strtol(line+1,&lp,16); len = (int)strtol(lp+1,0,16); if (len) { if (len*2 >= sizeof(buf)) { gdb_err(GDBERR_NOSPACE); } else { resp = buf; for(i=0;i<len;i++,addr++) resp += sprintf((char *)resp,"%02x",*addr); gdb_response((char *)buf); } } else gdb_ok(); return(0); }
/* gdb_X(): * Similar to gdb_M() except that the data is in binary. * The characters '$', '#' and 0x7d are escaped using 0x7d. */ int gdb_X(char *line) { int len, i; char *lp; uchar *addr; addr = (uchar *)strtol(line+1,&lp,16); len = (int)strtol(lp+1,&lp,16); lp++; for(i=0;i<len;i++) { if ((*lp == 0x7d) && ((*(lp+1) == 0x03) || (*(lp+1) == 0x04) || (*(lp+1) == 0x5d))) { *addr++ = *(lp+1) | 0x20; lp += 2; } else *addr++ = *lp++; } gdb_ok(); return(0); }
/* gdb_cmd(): * First function called out of the monitor's command interpreter. It * does a basic syntax verification and then passes parameters to the * appropriate handler above. * Incoming syntax is * * $ CMD # CSUM (of CMD) * * where: * $ is the ascii '$' character (0x24) * # is the ascii '#' character (0x23) * CMD is some command line consisting of a command and arguments * CSUM is the checksum of the characters in CMD * * for example: * * $m4015bc,2#5a * * Returns... * 0 if command is not processed; * 1 if command is processed; * -1 if command is processed but has an error; * * If this code detects an error, then send an error code back to GDB. * According to the article, there are no defined error codes in GDB so * we will use the following... * 1 indicates a missing '#' at the end of the incoming cmd string. * 2 indicates a bad checksum calculation. * 3 indicates some command processing error. * 4 indicates bad 'X' command parsing. */ int gdb_cmd(uchar *line) { char *comma, *colon, *cp, *bp, buf[32]; int len, clen, err, i; uchar mycsum, incsum; gdbContinueFptr = (void(*)())0; /* If the command is 'X', then we have to treat it "special" because * it contains binary data... */ if (line[1] == 'X') { comma = strchr((char *)line,','); colon = strchr((char *)line,':'); if ((comma) && (colon)) { bp = buf; cp = (char *)line; while(cp <= colon) *bp++ = *cp++; *bp = 0; gdbTrace("GDB_CMD: '%s'\n",buf); } else { gdbTrace("GDB_CMD: 'X'\n"); gdb_err(GDBERR_BADXFMT); /* Unexpected 'X' command format */ } } else if (line[0] == 0x03) { gdbTrace("GDB_CTRLC\n"); gdb_sig(2); return(1); } else { gdbTrace("GDB_CMD: '%s'\n",line); len = strlen((char *)line); if (line[len-3] != '#') { gdb_err(GDBERR_NOHASH); /* Missing ending '#' */ return(-1); } clen = len - 3; mycsum = 0; for(i=1;i<clen;i++) mycsum += line[i]; incsum = (uchar)strtol((char *)line+len-2,(char **)0,16); if (mycsum != incsum) { gdb_err(GDBERR_BADCSUM); /* Checksum failure */ return(-1); } } err = 0; line++; switch(*line) { case 'm': /* Memory read */ err = gdb_m((char *)line); break; case 'M': /* Memory write (Ascii-coded-hex) */ err = gdb_M((char *)line); break; case 'X': /* Memory write (Binary) */ err = gdb_X((char *)line); break; case 's': /* Step */ gdb_response("S05"); break; case 'c': /* Continue */ gdb_c((char *)line); break; case '?': /* Last signal */ gdb_response("S05"); break; case 'g': /* get all registers */ gdb_g((char *)line); break; case 'q': /* Query */ gdb_q((char *)line); break; case 'P': /* PRR=HHHHHHHH... reg*/ gdb_P((char *)line); break; case 'H': /* Thread */ gdb_ok(); break; case 'k': /* Quit */ gdb_ok(); break; default: /* Unknown... return empty response. */ gdb_response(""); break; } if (err) { gdb_err(GDBERR_GENERR); /* Command processing error */ } return(1); }
static void gdb_vmm_set_lbr(uint8_t __unused__ *data, size_t __unused__ len) { __enable_lbr(); gdb_ok(); }
static void gdb_vmm_del_lbr(uint8_t __unused__ *data, size_t __unused__ len) { __disable_lbr(); gdb_ok(); }
static void gdb_vmm_del_active_cr3(uint8_t __unused__ *data, size_t __unused__ len) { ctrl_active_cr3_disable(); gdb_ok(); }