/* * Read address at location and return updated location. */ db_addr_t db_read_address(db_addr_t loc, int short_addr, int regmodrm, int rex, struct i_addr *addrp) { int mod, rm, sib, index, disp, size; size = (short_addr ? LONG : QUAD); mod = f_mod(regmodrm); rm = f_rm(regmodrm, rex); if (mod == 3) { addrp->is_reg = TRUE; addrp->disp = rm; return (loc); } addrp->is_reg = FALSE; addrp->index = 0; if (rm == 4 || rm == 12) { get_value_inc(sib, loc, 1, FALSE); rm = sib_base(sib, rex); index = sib_index(sib, rex); if (index != 4) addrp->index = db_reg[size][index]; addrp->ss = sib_ss(sib); } switch (mod) { case 0: if (rm == 5) { get_value_inc(addrp->disp, loc, 4, FALSE); addrp->base = 0; } else { addrp->disp = 0; addrp->base = db_reg[size][rm]; } break; case 1: get_value_inc(disp, loc, 1, TRUE); addrp->disp = disp; addrp->base = db_reg[size][rm]; break; case 2: get_value_inc(disp, loc, 4, FALSE); addrp->disp = disp; addrp->base = db_reg[size][rm]; break; } return (loc); }
/* * Disassemble 3DNow! instruction and return updated location. */ db_addr_t db_disasm_3dnow(db_addr_t loc, int short_addr, int size, int rex, char *seg) { int regmodrm, sib, displacement, opcode; get_value_inc(regmodrm, loc, 1, FALSE); get_value_inc(sib, loc, 1, FALSE); get_value_inc(displacement, loc, 1, FALSE); get_value_inc(opcode, loc, 1, FALSE); /* XXX fix later... */ db_printf("<3DNow! instruction>"); return (loc); }
/* * Disassemble floating-point ("escape") instruction * and return updated location. */ db_addr_t db_disasm_esc(db_addr_t loc, int inst, int short_addr, int size, int rex, char *seg) { int regmodrm; struct finst *fp; int mod; struct i_addr address; char * name; get_value_inc(regmodrm, loc, 1, FALSE); fp = &db_Esc_inst[inst - 0xd8][f_reg(regmodrm, 0)]; mod = f_mod(regmodrm); if (mod != 3) { if (*fp->f_name == '\0') { db_printf("<bad instruction>"); return (loc); } /* * Normal address modes. */ loc = db_read_address(loc, short_addr, regmodrm, rex, &address); db_printf("%s", fp->f_name); switch (fp->f_size) { case SNGL: db_printf("s"); break; case DBLR: db_printf("l"); break; case EXTR: db_printf("t"); break; case WORD: db_printf("s"); break; case LONG: db_printf("l"); break; case QUAD: db_printf("q"); break; default: break; } db_printf("\t"); db_print_address(seg, BYTE, &address); } else { /* * 'reg-reg' - special formats */ switch (fp->f_rrmode) { case op2(ST,STI): name = (fp->f_rrname) ? fp->f_rrname : fp->f_name; db_printf("%s\t%%st,%%st(%d)",name, f_rm(regmodrm, 0)); break; case op2(STI,ST): name = (fp->f_rrname) ? fp->f_rrname : fp->f_name; db_printf("%s\t%%st(%d),%%st",name, f_rm(regmodrm, 0)); break; case op1(STI): name = (fp->f_rrname) ? fp->f_rrname : fp->f_name; db_printf("%s\t%%st(%d)",name, f_rm(regmodrm, 0)); break; case op1(X): name = ((char * const *)fp->f_rrname)[f_rm(regmodrm,0)]; if (*name == '\0') goto bad; db_printf("%s", name); break; case op1(XA): name = ((char * const *)fp->f_rrname)[f_rm(regmodrm,0)]; if (*name == '\0') goto bad; db_printf("%s\t%%ax", name); break; default: bad: db_printf("<bad instruction>"); break; } } return (loc); }
/* * Disassemble instruction at 'loc'. 'altfmt' specifies an * (optional) alternate format. Return address of start of * next instruction. */ db_addr_t db_disasm(db_addr_t loc, boolean_t altfmt) { int inst; int size; int short_addr; char * seg; struct inst * ip; char * i_name; int i_size; int i_mode; int regmodrm = 0; boolean_t first; int displ; int prefix; long imm; int imm2; int len; int rex = 0; int segovr_grp; int repe, repne; struct i_addr address; db_addr_t loc_orig = loc; char tmpfmt[28]; get_value_inc(inst, loc, 1, FALSE); short_addr = FALSE; size = LONG; seg = 0; segovr_grp = 0; repe = 0; repne = 0; /* * Get prefixes */ prefix = TRUE; do { switch (inst) { case 0x66: /* data16 */ size = WORD; break; case 0x67: short_addr = TRUE; break; case 0x26: segovr_grp++; db_printf(" <segment override prefix ignored>"); break; case 0x36: db_printf(" <segment override prefix ignored>"); segovr_grp++; break; case 0x2e: db_printf(" <segment override prefix ignored>"); segovr_grp++; break; case 0x3e: db_printf(" <segment override prefix ignored>"); segovr_grp++; break; case 0x64: segovr_grp++; seg = "%fs"; break; case 0x65: segovr_grp++; seg = "%gs"; break; case 0xf0: db_printf("lock "); break; case 0xf2: repne++; break; case 0xf3: repe++; break; default: prefix = FALSE; break; } if (prefix) get_value_inc(inst, loc, 1, FALSE); } while (prefix); if (segovr_grp > 1) seg = "<bad segment override prefix combination> "; if (repe > 0 && repne > 0) db_printf("<bad repeat prefex combination> "); else if (repe > 0) db_printf("repe "); /* XXX "rep" if not CMPSx or SCASx */ else if (repne > 0) db_printf("repne "); if (inst >= 0x40 && inst <= 0x4f) { // rex page 14 rex = inst; if (REX_W(rex)) size = QUAD; get_value_inc(inst, loc, 1, FALSE); } if (inst >= 0xd8 && inst <= 0xdf) { loc = db_disasm_esc(loc, inst, short_addr, size, rex, seg); goto done; } if (inst == 0x0f) { get_value_inc(inst, loc, 1, FALSE); if (inst == 0x0f) { loc = db_disasm_3dnow(loc, short_addr, size, rex, seg); goto done; } ip = db_inst_0f[inst>>4]; if (ip == 0) ip = &db_bad_inst; else ip = &ip[inst&0xf]; } else {
/* * Read address at location and return updated location. */ db_addr_t db_read_address(db_addr_t loc, int short_addr, int regmodrm, struct i_addr *addrp) { int mod, rm, sib, index, disp; mod = f_mod(regmodrm); rm = f_rm(regmodrm); if (mod == 3) { addrp->is_reg = TRUE; addrp->disp = rm; return (loc); } addrp->is_reg = FALSE; addrp->index = 0; if (short_addr) { addrp->index = 0; addrp->ss = 0; switch (mod) { case 0: if (rm == 6) { get_value_inc(disp, loc, 2, FALSE); addrp->disp = disp; addrp->base = 0; } else { addrp->disp = 0; addrp->base = db_index_reg_16[rm]; } break; case 1: get_value_inc(disp, loc, 1, TRUE); disp &= 0xffff; addrp->disp = disp; addrp->base = db_index_reg_16[rm]; break; case 2: get_value_inc(disp, loc, 2, FALSE); addrp->disp = disp; addrp->base = db_index_reg_16[rm]; break; } } else { if (rm == 4) { get_value_inc(sib, loc, 1, FALSE); rm = sib_base(sib); index = sib_index(sib); if (index != 4) addrp->index = db_reg[LONG][index]; addrp->ss = sib_ss(sib); } switch (mod) { case 0: if (rm == 5) { get_value_inc(addrp->disp, loc, 4, FALSE); addrp->base = 0; } else { addrp->disp = 0; addrp->base = db_reg[LONG][rm]; } break; case 1: get_value_inc(disp, loc, 1, TRUE); addrp->disp = disp; addrp->base = db_reg[LONG][rm]; break; case 2: get_value_inc(disp, loc, 4, FALSE); addrp->disp = disp; addrp->base = db_reg[LONG][rm]; break; } } return (loc); }
/* * Disassemble instruction at 'loc'. 'altfmt' specifies an * (optional) alternate format. Return address of start of * next instruction. */ db_addr_t db_disasm(db_addr_t loc, boolean_t altfmt) { int inst; int size; int short_addr; char * seg; struct inst * ip; char * i_name; int i_size; int i_mode; int regmodrm = 0; boolean_t first; int displ; int prefix; int imm; int imm2; int len; struct i_addr address; char tmpfmt[24]; get_value_inc(inst, loc, 1, FALSE); short_addr = FALSE; size = LONG; seg = 0; /* * Get prefixes */ prefix = TRUE; do { switch (inst) { case 0x66: /* data16 */ size = WORD; break; case 0x67: short_addr = TRUE; break; case 0x26: seg = "%es"; break; case 0x36: seg = "%ss"; break; case 0x2e: seg = "%cs"; break; case 0x3e: seg = "%ds"; break; case 0x64: seg = "%fs"; break; case 0x65: seg = "%gs"; break; case 0xf0: db_printf("lock "); break; case 0xf2: db_printf("repne "); break; case 0xf3: db_printf("repe "); /* XXX repe VS rep */ break; default: prefix = FALSE; break; } if (prefix) get_value_inc(inst, loc, 1, FALSE); } while (prefix); if (inst >= 0xd8 && inst <= 0xdf) { loc = db_disasm_esc(loc, inst, short_addr, size, seg); db_printf("\n"); return (loc); } if (inst == 0x0f) { get_value_inc(inst, loc, 1, FALSE); ip = db_inst_0f[inst>>4]; if (ip == 0) ip = &db_bad_inst; else ip = &ip[inst&0xf]; } else {
/* * Read address at location and return updated location. */ static db_addr_t db_read_address(db_addr_t loc, int short_addr, int rex, int regmodrm, struct i_addr *addrp) { int mod, rm, sib, index, disp, size, have_sib; mod = f_mod(rex, regmodrm); rm = f_rm(rex, regmodrm); if (mod == 3) { addrp->is_reg = TRUE; addrp->disp = rm; return (loc); } addrp->is_reg = FALSE; addrp->index = NULL; if (short_addr) size = LONG; else size = QUAD; if ((rm & 0x7) == 4) { get_value_inc(sib, loc, 1, FALSE); rm = sib_base(rex, sib); index = sib_index(rex, sib); if (index != 4) addrp->index = db_reg[1][size][index]; addrp->ss = sib_ss(rex, sib); have_sib = 1; } else have_sib = 0; switch (mod) { case 0: if (rm == 5) { get_value_inc(addrp->disp, loc, 4, FALSE); if (have_sib) addrp->base = NULL; else if (short_addr) addrp->base = "%eip"; else addrp->base = "%rip"; } else { addrp->disp = 0; addrp->base = db_reg[1][size][rm]; } break; case 1: get_value_inc(disp, loc, 1, TRUE); addrp->disp = disp; addrp->base = db_reg[1][size][rm]; break; case 2: get_value_inc(disp, loc, 4, FALSE); addrp->disp = disp; addrp->base = db_reg[1][size][rm]; break; } return (loc); }
/* * Disassemble instruction at 'loc'. 'altfmt' specifies an * (optional) alternate format. Return address of start of * next instruction. */ db_addr_t db_disasm( db_addr_t loc, bool altfmt) { int inst; int size; int short_addr; const char * seg; const struct inst * ip; const char * i_name; int i_size; int i_mode; int regmodrm = 0; bool first; int displ; int prefix; int imm; int imm2; int len; struct i_addr address; #ifdef _KERNEL pt_entry_t *pte, *pde; /* * Don't try to disassemble the location if the mapping is invalid. * If we do, we'll fault, and end up debugging the debugger! * in the case of largepages, "pte" is really the pde and "pde" is * really the entry for the pdp itself. */ if ((vaddr_t)loc >= VM_MIN_KERNEL_ADDRESS) pte = kvtopte((vaddr_t)loc); else pte = vtopte((vaddr_t)loc); pde = vtopte((vaddr_t)pte); if ((*pde & PG_V) == 0 || (*pte & PG_V) == 0) { db_printf("invalid address\n"); return (loc); } #endif get_value_inc(inst, loc, 1, false); short_addr = false; size = LONG; seg = 0; /* * Get prefixes */ prefix = true; do { switch (inst) { case 0x66: /* data16 */ size = WORD; break; case 0x67: short_addr = true; break; case 0x26: seg = "%es"; break; case 0x36: seg = "%ss"; break; case 0x2e: seg = "%cs"; break; case 0x3e: seg = "%ds"; break; case 0x64: seg = "%fs"; break; case 0x65: seg = "%gs"; break; case 0xf0: db_printf("lock "); break; case 0xf2: db_printf("repne "); break; case 0xf3: db_printf("repe "); /* XXX repe VS rep */ break; default: prefix = false; break; } if (prefix) get_value_inc(inst, loc, 1, false); } while (prefix); if (inst >= 0xd8 && inst <= 0xdf) { loc = db_disasm_esc(loc, inst, short_addr, size, seg); db_printf("\n"); return (loc); } if (inst == 0x0f) { get_value_inc(inst, loc, 1, false); ip = db_inst_0f[inst>>4]; if (ip == 0) ip = &db_bad_inst; else ip = &ip[inst&0xf]; } else {