R_API void r_cons_canvas_line_back_edge (RConsCanvas *c, int x, int y, int x2, int y2, RCanvasLineStyle *style, int ybendpoint1, int xbendpoint, int ybendpoint2, int isvert) { int min_x1 = R_MIN (x, xbendpoint); int min_x2 = R_MIN (x2, xbendpoint); int diff_x1 = R_ABS (x - xbendpoint); int diff_x2 = R_ABS (x2 - xbendpoint); int diff_y = R_ABS ((y + ybendpoint1 + 1) - (y2 - ybendpoint2- 1)); int w1 = diff_x1 == 0 ? 0 : diff_x1 + 1; int w2 = diff_x2 == 0 ? 0 : diff_x2 + 1; apply_line_style (c, x, y, x2, y2, style, isvert); if (isvert) { draw_vertical_line (c, x, y + 1, ybendpoint1 + 1); draw_horizontal_line (c, min_x1, y + ybendpoint1 + 2, w1, REV_APEX_APEX); draw_vertical_line (c, xbendpoint, y2 - ybendpoint2 + 1, diff_y - 1); draw_horizontal_line (c, min_x2, y2 - ybendpoint2, w2, DOT_DOT); draw_vertical_line (c, x2, y2 - ybendpoint2 + 1, ybendpoint2); } else { int miny1 = R_MIN (y, xbendpoint); int miny2 = R_MIN (y2, xbendpoint); int diff_y1 = R_ABS (y - xbendpoint); int diff_y2 = R_ABS (y2 - xbendpoint); draw_horizontal_line (c, x + 1, y, 1 + ybendpoint1 + 1, xbendpoint > y ? NRM_DOT : NRM_APEX); draw_vertical_line (c, x + 1 + ybendpoint1 + 1, miny1 + 1, diff_y1 - 1); draw_horizontal_line (c, x2 - ybendpoint2, xbendpoint, (x + 1 + ybendpoint1 + 1) - (x2 - ybendpoint2) + 1, xbendpoint > y ? REV_APEX_APEX : DOT_DOT); draw_vertical_line (c, x2 - ybendpoint2, miny2 + 1, diff_y2 - 1); draw_horizontal_line (c, x2 - ybendpoint2, y2, ybendpoint2 + 1, xbendpoint > y ? DOT_NRM : REV_APEX_NRM); } }
R_API void r_cons_canvas_line_square (RConsCanvas *c, int x, int y, int x2, int y2, RCanvasLineStyle *style) { int min_x = R_MIN (x, x2); int diff_x = R_ABS (x - x2); int diff_y = R_ABS (y - y2); apply_line_style (c, x, y, x2, y2, style, 1); // -- // TODO: find if there's any collision in this line if (y2 - y > 1) { int hl = diff_y / 2 - 1; int hl2 = diff_y - hl; int w = diff_x == 0 ? 0 : diff_x + 1; int style = min_x == x ? APEX_DOT : DOT_APEX; draw_vertical_line (c, x, y + 1, hl); draw_vertical_line (c, x2, y + hl + 1, hl2); draw_horizontal_line (c, min_x, y + hl + 1, w, style); } else { if (y2 == y) { draw_horizontal_line (c, min_x, y, diff_x + 1, DOT_DOT); } else { if (x != x2) { draw_horizontal_line (c, min_x, y, diff_x + 1, REV_APEX_APEX); } draw_vertical_line (c, x2, y2, diff_y); } } c->attr = Color_RESET; }
R_API double r_prof_end(struct r_prof_t *p) { tv end, diff, *begin = &p->begin; int sign; gettimeofday (&end, NULL); sign = timeval_subtract (&diff, begin, &end); p->result = R_ABS (((double)(diff.tv_sec) + ((double)diff.tv_usec / 1000000.))); return R_ABS (sign); }
R_API void r_cons_canvas_line_square_defined (RConsCanvas *c, int x, int y, int x2, int y2, RCanvasLineStyle *style, int bendpoint, int isvert) { int min_x = R_MIN (x, x2); int diff_x = R_ABS (x - x2); int diff_y = R_ABS (y - y2); int min_y = R_MIN (y, y2); apply_line_style (c, x, y, x2, y2, style, isvert); if (isvert) { if (x2 == x) { draw_vertical_line (c, x, y + 1, diff_y); } else if (y2 - y > 1) { int h1 = 1 + bendpoint; int h2 = diff_y - h1; int w = diff_x == 0 ? 0 : diff_x + 1; int style = min_x == x ? APEX_DOT : DOT_APEX; draw_vertical_line (c, x, y + 1, h1); draw_horizontal_line (c, min_x, y + bendpoint + 2, w, style); draw_vertical_line (c, x2, y + h1 + 1 + 1, h2); } else { //TODO: currently copy-pasted if (y2 == y) { draw_horizontal_line (c, min_x, y, diff_x + 1, DOT_DOT); } else { if (x != x2) { draw_horizontal_line (c, min_x, y, diff_x + 1, REV_APEX_APEX); } draw_vertical_line (c, x2, y2, diff_y-2); } } } else { if (y2 == y) { draw_horizontal_line (c, min_x + 1, y, diff_x, NRM_NRM); } else if (x2 - x > 1) { int w1 = 1 + bendpoint; int w2 = diff_x - w1; //int h = diff_x;// == 0 ? 0 : diff_x + 1; //int style = min_x == x ? APEX_DOT : DOT_APEX; //draw_vertical_line (c, x, y + 1, h1); draw_horizontal_line (c, x + 1, y, w1 + 1, y2 > y ? NRM_DOT : NRM_APEX); //draw_horizontal_line (c, min_x, y + bendpoint + 2, w, style); draw_vertical_line (c, x + 1 + w1, min_y + 1, diff_y - 1); //draw_vertical_line (c, x2, y + h1 + 1 + 1, h2); draw_horizontal_line (c, x + 1 + w1, y2, w2, y2 < y ? DOT_NRM : REV_APEX_NRM); } } c->attr = Color_RESET; }
R_API ut8 r_hash_deviation(const ut8 *b, ut64 len) { int i, c; for (c = i = 0, len--; i < len; i++) { c += R_ABS (b[i + 1] - b[i]); } return c; }
void EditorWidget::wheelEvent(QWheelEvent *qwheelevent){ if(ATOMIC_GET(is_starting_up)==true) return; if (MIXER_is_saving()) return; struct Tracker_Windows *window=static_cast<struct Tracker_Windows*>(root->song->tracker_windows); int num_lines = R_ABS(qwheelevent->delta()/120); //printf(" Got wheel event %d\n",qwheelevent->delta()/120); DO_GFX( { /* if(qwheelevent->delta()<0) ScrollEditorDown(window,num_lines * getScrollMultiplication()); else ScrollEditorUp(window,num_lines * getScrollMultiplication()); */ if (qwheelevent->modifiers() & Qt::ControlModifier) { if (qwheelevent->delta() > 0) zoom(1,window->l.num); else zoom(-1,window->l.num); #if 0 } else if (qwheelevent->modifiers() & Qt::ShiftModifier) { tevent.ID=TR_KEYBOARD; if(qwheelevent->delta()<0) tevent.SubID=EVENT_LEFTARROW; else tevent.SubID=EVENT_RIGHTARROW; for(int i=0;i<num_lines;i++) EventReciever(&tevent,window); #endif } else { tevent.ID=TR_KEYBOARD; if(qwheelevent->delta()<0) tevent.SubID=EVENT_DOWNARROW; else tevent.SubID=EVENT_UPARROW; for(int i=0;i<num_lines;i++) EventReciever(&tevent,window); } });
R_API int r_diff_buffers_static(RDiff *d, const ut8 *a, int la, const ut8 *b, int lb) { int i, len; int hit = 0; la = R_ABS (la); lb = R_ABS (lb); if (la != lb) { len = R_MIN(la, lb); eprintf ("Buffer truncated to %d bytes (%d not compared)\n", len, R_ABS(lb-la)); } else { len = la; } for (i = 0; i < len; i++) { if (a[i] != b[i]) { hit++; } else { if (hit > 0) { int ra = la - (i - hit); int rb = lb - (i - hit); struct r_diff_op_t o = { .a_off = d->off_a+i-hit, .a_buf = a+i-hit, .a_len = R_MIN (hit, ra), .b_off = d->off_b+i-hit, .b_buf = b+i-hit, .b_len = R_MIN (hit, rb) }; d->callback (d, d->user, &o); hit = 0; } } } if (hit > 0) { int ra = la - (i - hit); int rb = lb - (i - hit); struct r_diff_op_t o = { .a_off = d->off_a+i-hit, .a_buf = a+i-hit, .a_len = R_MIN (hit, ra), .b_off = d->off_b+i-hit, .b_buf = b+i-hit, .b_len = R_MIN (hit, rb) }; d->callback (d, d->user, &o); hit = 0; } return 0; }
void GFX_Point( struct Tracker_Windows *window, int color, int brightness, int x,int y, int where ) { if(where==PAINT_DIRECTLY){ RError("GFX_Point can not be called with where==PAINT_DIRECTLY"); return; } if(color>=16 || color<0){ RError("Illegal color: %d",color); color = R_ABS(color) % 16; } brightness = R_BOUNDARIES(0, brightness, MAX_BRIGHTNESS); #if 0 OS_GFX_Point(window,color,brightness,x,y,where); return; #endif struct Points *point=points[color][brightness]; if(point==NULL) points[color][brightness] = point = calloc(1,sizeof(struct Points)); int pos = point->pos; if(point->pos==point->size){ point->size = R_MAX(128,point->size*2); point->x=realloc(point->x,point->size*sizeof(uint16_t)); point->y=realloc(point->y,point->size*sizeof(uint16_t)); } point->x[pos] = x; point->y[pos] = y; point->pos = pos+1; is_dirty=true; }
R_API RSearchKeyword* r_search_keyword_new_hexmask(const char *kwstr, const char *data) { RSearchKeyword *ks = NULL; ut8 *kw, *bm; if (kwstr != NULL) { int len = strlen (kwstr); kw = malloc (len+4); bm = malloc (len+4); if (kw != NULL && bm != NULL) { len = r_hex_str2binmask (kwstr, (ut8*)kw, (ut8*)bm); if (len<0) len = -len+1; if (len>0) ks = r_search_keyword_new (kw, R_ABS (len), bm, len, data); } free (kw); free (bm); } return ks; }
static void setprintmode (RCore *core, int n) { RAsmOp op; if (n>0) { core->printidx = R_ABS ((core->printidx+1)%NPF); } else { if (core->printidx) core->printidx--; else core->printidx = NPF-1; } switch (core->printidx) { case 0: core->inc = 16; break; case 1: case 2: core->inc = r_asm_disassemble (core->assembler, &op, core->block, 32); break; } }
static int analop(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len) { static int omode = 0; #if USE_ITER_API static #endif cs_insn *insn = NULL; int mode = (a->bits==64)? CS_MODE_64: (a->bits==32)? CS_MODE_32: (a->bits==16)? CS_MODE_16: 0; int n, ret; int regsz = 4; if (handle && mode != omode) { cs_close (&handle); handle = 0; } omode = mode; if (handle == 0) { ret = cs_open (CS_ARCH_X86, mode, &handle); if (ret != CS_ERR_OK) { handle = 0; return 0; } } switch (a->bits) { case 64: regsz = 8; break; case 16: regsz = 2; break; default: case 32: regsz = 4; break; } memset (op, '\0', sizeof (RAnalOp)); op->cycles = 1; // aprox op->type = R_ANAL_OP_TYPE_NULL; op->jump = UT64_MAX; op->fail = UT64_MAX; op->ptr = op->val = UT64_MAX; op->src[0] = NULL; op->src[1] = NULL; op->size = 0; op->delay = 0; r_strbuf_init (&op->esil); cs_option (handle, CS_OPT_DETAIL, CS_OPT_ON); // capstone-next #if USE_ITER_API { ut64 naddr = addr; size_t size = len; if (insn == NULL) insn = cs_malloc (handle); n = cs_disasm_iter (handle, (const uint8_t**)&buf, &size, (uint64_t*)&naddr, insn); } #else n = cs_disasm (handle, (const ut8*)buf, len, addr, 1, &insn); #endif struct Getarg gop = { .handle = handle, .insn = insn, .bits = a->bits }; if (n<1) { op->type = R_ANAL_OP_TYPE_ILL; } else { int rs = a->bits/8; const char *pc = (a->bits==16)?"ip": (a->bits==32)?"eip":"rip"; const char *sp = (a->bits==16)?"sp": (a->bits==32)?"esp":"rsp"; const char *bp = (a->bits==16)?"bp": (a->bits==32)?"ebp":"rbp"; op->size = insn->size; op->family = 0; op->prefix = 0; switch (insn->detail->x86.prefix[0]) { case X86_PREFIX_REPNE: op->prefix |= R_ANAL_OP_PREFIX_REPNE; break; case X86_PREFIX_REP: op->prefix |= R_ANAL_OP_PREFIX_REP; break; case X86_PREFIX_LOCK: op->prefix |= R_ANAL_OP_PREFIX_LOCK; break; } switch (insn->id) { case X86_INS_FNOP: case X86_INS_NOP: case X86_INS_PAUSE: op->type = R_ANAL_OP_TYPE_NOP; if (a->decode) esilprintf (op, ","); break; case X86_INS_HLT: op->type = R_ANAL_OP_TYPE_TRAP; break; case X86_INS_FBLD: case X86_INS_FBSTP: case X86_INS_FCOMPP: case X86_INS_FDECSTP: case X86_INS_FEMMS: case X86_INS_FFREE: case X86_INS_FICOM: case X86_INS_FICOMP: case X86_INS_FINCSTP: case X86_INS_FNCLEX: case X86_INS_FNINIT: case X86_INS_FNSTCW: case X86_INS_FNSTSW: case X86_INS_FPATAN: case X86_INS_FPREM: case X86_INS_FPREM1: case X86_INS_FPTAN: #if CS_API_MAJOR >=4 case X86_INS_FFREEP: #endif case X86_INS_FRNDINT: case X86_INS_FRSTOR: case X86_INS_FNSAVE: case X86_INS_FSCALE: case X86_INS_FSETPM: case X86_INS_FSINCOS: case X86_INS_FNSTENV: case X86_INS_FXAM: case X86_INS_FXSAVE: case X86_INS_FXSAVE64: case X86_INS_FXTRACT: case X86_INS_FYL2X: case X86_INS_FYL2XP1: case X86_INS_FISTTP: case X86_INS_FSQRT: case X86_INS_FXCH: case X86_INS_FTST: case X86_INS_FUCOMPI: case X86_INS_FUCOMI: case X86_INS_FUCOMPP: case X86_INS_FUCOMP: case X86_INS_FUCOM: op->type = R_ANAL_OP_TYPE_SUB; op->family = R_ANAL_OP_FAMILY_FPU; break; case X86_INS_FLDCW: case X86_INS_FLDENV: case X86_INS_FLDL2E: case X86_INS_FLDL2T: case X86_INS_FLDLG2: case X86_INS_FLDLN2: case X86_INS_FLDPI: case X86_INS_FLDZ: case X86_INS_FLD1: case X86_INS_FLD: op->type = R_ANAL_OP_TYPE_LOAD; op->family = R_ANAL_OP_FAMILY_FPU; break; case X86_INS_FIST: case X86_INS_FISTP: case X86_INS_FST: case X86_INS_FSTP: case X86_INS_FSTPNCE: case X86_INS_FXRSTOR: case X86_INS_FXRSTOR64: op->type = R_ANAL_OP_TYPE_STORE; op->family = R_ANAL_OP_FAMILY_FPU; break; case X86_INS_FDIV: case X86_INS_FIDIV: case X86_INS_FDIVP: case X86_INS_FDIVR: case X86_INS_FIDIVR: case X86_INS_FDIVRP: case X86_INS_FSUBR: case X86_INS_FISUBR: case X86_INS_FSUBRP: case X86_INS_FSUB: case X86_INS_FISUB: case X86_INS_FSUBP: op->type = R_ANAL_OP_TYPE_SUB; op->family = R_ANAL_OP_FAMILY_FPU; break; case X86_INS_FMUL: case X86_INS_FIMUL: case X86_INS_FMULP: op->type = R_ANAL_OP_TYPE_MUL; op->family = R_ANAL_OP_FAMILY_FPU; break; case X86_INS_CLI: case X86_INS_STI: op->type = R_ANAL_OP_TYPE_SWI; op->family = R_ANAL_OP_FAMILY_PRIV; break; case X86_INS_CLC: case X86_INS_STC: case X86_INS_CLAC: case X86_INS_CLGI: case X86_INS_CLTS: case X86_INS_CLWB: case X86_INS_STAC: case X86_INS_STGI: op->type = R_ANAL_OP_TYPE_MOV; op->family = R_ANAL_OP_FAMILY_CPU; break; // cmov case X86_INS_SETNE: case X86_INS_SETNO: case X86_INS_SETNP: case X86_INS_SETNS: case X86_INS_SETO: case X86_INS_SETP: case X86_INS_SETS: case X86_INS_SETL: case X86_INS_SETLE: case X86_INS_SETB: case X86_INS_SETG: case X86_INS_SETAE: case X86_INS_SETA: case X86_INS_SETBE: case X86_INS_SETE: case X86_INS_SETGE: op->type = R_ANAL_OP_TYPE_CMOV; op->family = 0; if (a->decode) { char *dst = getarg (&gop, 0, 0, NULL); switch (insn->id) { case X86_INS_SETE: esilprintf (op, "zf,%s,=", dst); break; case X86_INS_SETNE: esilprintf (op, "zf,!,%s,=", dst); break; case X86_INS_SETO: esilprintf (op, "of,%s,=", dst); break; case X86_INS_SETNO: esilprintf (op, "of,!,%s,=", dst); break; case X86_INS_SETP: esilprintf (op, "pf,%s,=", dst); break; case X86_INS_SETNP: esilprintf (op, "pf,!,%s,=", dst); break; case X86_INS_SETS: esilprintf (op, "sf,%s,=", dst); break; case X86_INS_SETNS: esilprintf (op, "sf,!,%s,=", dst); break; case X86_INS_SETB: esilprintf (op, "cf,%s,=", dst); break; case X86_INS_SETAE: esilprintf (op, "cf,!,%s,=", dst); break; /* TODO */ #if 0 SETLE/SETNG Sets the byte in the operand to 1 if the Zero Flag is set or the Sign Flag is not equal to the Overflow Flag, otherwise sets the operand to 0. SETBE/SETNA Sets the byte in the operand to 1 if the Carry Flag or the Zero Flag is set, otherwise sets the operand to 0. SETL/SETNGE Sets the byte in the operand to 1 if the Sign Flag is not equal to the Overflow Flag, otherwise sets the operand to 0. case X86_INS_SETL: esilprintf (op, "pf,!,%s,=", dst); break; case X86_INS_SETLE: esilprintf (op, "pf,!,%s,=", dst); break; case X86_INS_SETG: esilprintf (op, "pf,!,%s,=", dst); break; case X86_INS_SETA: esilprintf (op, "pf,!,%s,=", dst); break; case X86_INS_SETBE: esilprintf (op, "pf,!,%s,=", dst); break; case X86_INS_SETGE: esilprintf (op, "pf,!,%s,=", dst); break; break; #endif } free (dst); } break; // cmov case X86_INS_MOVSS: case X86_INS_CMOVA: case X86_INS_CMOVAE: case X86_INS_CMOVB: case X86_INS_CMOVBE: case X86_INS_FCMOVBE: case X86_INS_FCMOVB: case X86_INS_CMOVE: case X86_INS_FCMOVE: case X86_INS_CMOVG: case X86_INS_CMOVGE: case X86_INS_CMOVL: case X86_INS_CMOVLE: case X86_INS_FCMOVNBE: case X86_INS_FCMOVNB: case X86_INS_CMOVNE: case X86_INS_FCMOVNE: case X86_INS_CMOVNO: case X86_INS_CMOVNP: case X86_INS_FCMOVNU: case X86_INS_CMOVNS: case X86_INS_CMOVO: case X86_INS_CMOVP: case X86_INS_FCMOVU: case X86_INS_CMOVS: // mov case X86_INS_MOV: case X86_INS_MOVAPS: case X86_INS_MOVAPD: case X86_INS_MOVZX: case X86_INS_MOVUPS: case X86_INS_MOVABS: case X86_INS_MOVHPD: case X86_INS_MOVHPS: case X86_INS_MOVLPD: case X86_INS_MOVLPS: case X86_INS_MOVBE: case X86_INS_MOVSB: case X86_INS_MOVSD: case X86_INS_MOVSQ: case X86_INS_MOVSX: case X86_INS_MOVSXD: case X86_INS_MOVSW: case X86_INS_MOVD: case X86_INS_MOVQ: case X86_INS_MOVDQ2Q: { op->type = R_ANAL_OP_TYPE_MOV; op->ptr = UT64_MAX; switch (INSOP(0).type) { case X86_OP_MEM: op->ptr = INSOP(0).mem.disp; op->refptr = INSOP(0).size; if (INSOP(0).mem.base == X86_REG_RIP) { op->ptr += addr + insn->size; } else if (INSOP(0).mem.base == X86_REG_RBP || INSOP(0).mem.base == X86_REG_EBP) { op->ptr = UT64_MAX; op->stackop = R_ANAL_STACK_SET; op->stackptr = regsz; } else { op->ptr = UT64_MAX; } if (a->decode) { if (op->prefix & R_ANAL_OP_PREFIX_REP) { int width = INSOP(0).size; const char *src = cs_reg_name(handle, INSOP(1).mem.base); const char *dst = cs_reg_name(handle, INSOP(0).mem.base); const char *counter = (a->bits==16)?"cx": (a->bits==32)?"ecx":"rcx"; esilprintf (op, "%s,!,?{,BREAK,},%s,DUP,%s,DUP,"\ "%s,[%d],%s,=[%d],df,?{,%d,%s,-=,%d,%s,-=,},"\ "df,!,?{,%d,%s,+=,%d,%s,+=,},%s,--=,%s," \ "?{,8,GOTO,},%s,=,%s,=", counter, src, dst, src, width, dst, width, width, src, width, dst, width, src, width, dst, counter, counter, dst, src); } else { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, NULL); esilprintf (op, "%s,%s", src, dst); free (src); free (dst); } } break; default: if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,%s,=", src, dst); free (src); free (dst); } break; } if (op->refptr<1 || op->ptr == UT64_MAX) { switch (INSOP(1).type) { case X86_OP_MEM: op->ptr = INSOP(1).mem.disp; op->refptr = INSOP(1).size; if (INSOP(1).mem.base == X86_REG_RIP) { op->ptr += addr + insn->size; } else if (INSOP(1).mem.base == X86_REG_RBP || INSOP(1).mem.base == X86_REG_EBP) { op->stackop = R_ANAL_STACK_GET; op->stackptr = regsz; } break; case X86_OP_IMM: if (INSOP(1).imm > 10) op->ptr = INSOP(1).imm; break; default: break; } } } break; case X86_INS_SHL: case X86_INS_SHLD: case X86_INS_SHLX: op->type = R_ANAL_OP_TYPE_SHL; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "<<"); esilprintf (op, "%s,%s,$z,zf,=", src, dst); free (src); free (dst); } break; case X86_INS_SAR: case X86_INS_SARX: op->type = R_ANAL_OP_TYPE_SAR; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, ">>"); esilprintf (op, "%s,%s,$z,zf,=", src, dst); free (src); free (dst); } break; case X86_INS_SAL: op->type = R_ANAL_OP_TYPE_SAL; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "<<"); esilprintf (op, "%s,%s,$z,zf,=", src, dst); free (src); free (dst); } break; case X86_INS_SALC: op->type = R_ANAL_OP_TYPE_SAL; if (a->decode) { esilprintf (op, "$z,DUP,zf,=,al,="); } break; case X86_INS_SHR: case X86_INS_SHRD: case X86_INS_SHRX: op->type = R_ANAL_OP_TYPE_SHR; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,%s,>>=,$z,zf,=", src, dst); free (src); free (dst); } break; case X86_INS_CMP: case X86_INS_CMPPD: case X86_INS_CMPPS: case X86_INS_CMPSW: case X86_INS_CMPSD: case X86_INS_CMPSQ: case X86_INS_CMPSB: case X86_INS_CMPSS: case X86_INS_TEST: if (insn->id == X86_INS_TEST) { op->type = R_ANAL_OP_TYPE_ACMP; //compare via and if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "0,%s,%s,&,==,$z,zf,=,$p,pf,=,$s,sf,=,0,cf,=,0,of,=", src, dst); free (src); free (dst); } } else { op->type = R_ANAL_OP_TYPE_CMP; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,%s,==,$z,zf,=,$b%d,cf,=,$p,pf,=,$s,sf,=", src, dst, (INSOP(0).size*8)); free (src); free (dst); } } switch (INSOP(0).type) { case X86_OP_MEM: op->ptr = INSOP(0).mem.disp; op->refptr = INSOP(0).size; if (INSOP(0).mem.base == X86_REG_RIP) { op->ptr += addr + insn->size; } else if (INSOP(0).mem.base == X86_REG_RBP || INSOP(0).mem.base == X86_REG_EBP) { op->stackop = R_ANAL_STACK_SET; op->stackptr = regsz; } op->ptr = INSOP(1).imm; break; default: switch (INSOP(1).type) { case X86_OP_MEM: op->ptr = INSOP(1).mem.disp; op->refptr = INSOP(1).size; if (INSOP(1).mem.base == X86_REG_RIP) { op->ptr += addr + insn->size; } else if (INSOP(1).mem.base == X86_REG_RBP || INSOP(1).mem.base == X86_REG_EBP) { op->stackop = R_ANAL_STACK_SET; op->stackptr = regsz; } break; case X86_OP_IMM: op->ptr = INSOP(1).imm; break; default: break; } break; } break; case X86_INS_LEA: op->type = R_ANAL_OP_TYPE_LEA; if (a->decode) { char *src = getarg (&gop, 0, 0, NULL); char *dst = getarg (&gop, 1, 2, NULL); esilprintf (op, "%s,%s,=", dst, src); free (src); free (dst); } switch (INSOP(1).type) { case X86_OP_MEM: op->ptr = INSOP(1).mem.disp; op->refptr = INSOP(1).size; switch (INSOP(1).mem.base) { case X86_REG_RIP: op->ptr += addr + op->size; break; case X86_REG_RBP: case X86_REG_EBP: op->stackop = R_ANAL_STACK_GET; op->stackptr = regsz; break; default: /* unhandled */ break; } break; case X86_OP_IMM: if (INSOP(1).imm > 10) op->ptr = INSOP(1).imm; break; default: break; } break; case X86_INS_ENTER: case X86_INS_PUSH: case X86_INS_PUSHAW: case X86_INS_PUSHAL: case X86_INS_PUSHF: { char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "%d,%s,-=,%s,%s,=[%d]", rs, sp, dst, sp, rs); free (dst); } switch (INSOP(0).type) { case X86_OP_IMM: op->ptr = INSOP(0).imm; op->type = R_ANAL_OP_TYPE_PUSH; break; default: op->type = R_ANAL_OP_TYPE_UPUSH; break; } op->stackop = R_ANAL_STACK_INC; op->stackptr = regsz; break; case X86_INS_LEAVE: op->type = R_ANAL_OP_TYPE_POP; if (a->decode) { esilprintf (op, "%s,%s,=,%s,[%d],%s,=,%d,%s,+=", bp, sp, sp, rs, bp, rs, sp); } op->stackop = R_ANAL_STACK_INC; op->stackptr = -regsz; break; case X86_INS_POP: case X86_INS_POPF: case X86_INS_POPAW: case X86_INS_POPAL: case X86_INS_POPCNT: op->type = R_ANAL_OP_TYPE_POP; if (a->decode) { char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,[%d],%s,=,%d,%s,+=", sp, rs, dst, rs, sp); free (dst); } op->stackop = R_ANAL_STACK_INC; op->stackptr = -regsz; break; case X86_INS_RET: case X86_INS_RETF: case X86_INS_RETFQ: case X86_INS_IRET: case X86_INS_IRETD: case X86_INS_IRETQ: case X86_INS_SYSRET: op->type = R_ANAL_OP_TYPE_RET; if (a->decode) esilprintf (op, "%s,[%d],%s,=,%d,%s,+=", sp, rs, pc, rs, sp); op->stackop = R_ANAL_STACK_INC; op->stackptr = -regsz; break; case X86_INS_INT3: if (a->decode) esilprintf (op, "3,$"); op->type = R_ANAL_OP_TYPE_TRAP; // TRAP break; case X86_INS_INT1: if (a->decode) esilprintf (op, "1,$"); op->type = R_ANAL_OP_TYPE_SWI; // TRAP break; case X86_INS_INT: if (a->decode) esilprintf (op, "%d,$", R_ABS((int)INSOP(0).imm)); op->type = R_ANAL_OP_TYPE_SWI; break; case X86_INS_SYSCALL: op->type = R_ANAL_OP_TYPE_SWI; break; case X86_INS_INTO: case X86_INS_VMCALL: case X86_INS_VMMCALL: op->type = R_ANAL_OP_TYPE_TRAP; if (a->decode) esilprintf (op, "%d,$", (int)INSOP(0).imm); break; case X86_INS_JL: case X86_INS_JLE: case X86_INS_JA: case X86_INS_JAE: case X86_INS_JB: case X86_INS_JBE: case X86_INS_JCXZ: case X86_INS_JECXZ: case X86_INS_JRCXZ: case X86_INS_JO: case X86_INS_JNO: case X86_INS_JS: case X86_INS_JNS: case X86_INS_JP: case X86_INS_JNP: case X86_INS_JE: case X86_INS_JNE: case X86_INS_JG: case X86_INS_JGE: case X86_INS_LOOP: case X86_INS_LOOPE: case X86_INS_LOOPNE: op->type = R_ANAL_OP_TYPE_CJMP; op->jump = INSOP(0).imm; op->fail = addr+op->size; const char *cnt = (a->bits==16)?"cx":(a->bits==32)?"ecx":"rcx"; if (a->decode) { char *dst = getarg (&gop, 0, 2, NULL); switch (insn->id) { case X86_INS_JL: esilprintf (op, "of,sf,^,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JLE: esilprintf (op, "of,sf,^,zf,|,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JA: esilprintf (op, "cf,zf,|,!,?{,%s,%s,=,}",dst, pc); break; case X86_INS_JAE: esilprintf (op, "cf,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JB: esilprintf (op, "cf,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JO: esilprintf (op, "of,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JNO: esilprintf (op, "of,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JE: esilprintf (op, "zf,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JGE: esilprintf (op, "of,!,sf,^,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JNE: esilprintf (op, "zf,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JG: esilprintf (op, "sf,of,!,^,zf,!,&,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JS: esilprintf (op, "sf,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JNS: esilprintf (op, "sf,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JP: esilprintf (op, "pf,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JNP: esilprintf (op, "pf,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JBE: esilprintf (op, "zf,cf,|,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JCXZ: esilprintf (op, "cx,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JECXZ: esilprintf (op, "ecx,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JRCXZ: esilprintf (op, "rcx,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_LOOP: esilprintf (op, "1,%s,-=,%s,?{,%s,%s,=,}", cnt, cnt, dst, pc); break; case X86_INS_LOOPE: esilprintf (op, "1,%s,-=,%s,?{,zf,?{,%s,%s,=,},}", cnt, cnt, dst, pc); break; case X86_INS_LOOPNE: esilprintf (op, "1,%s,-=,%s,?{,zf,!,?{,%s,%s,=,},}", cnt, cnt, dst, pc); break; } free (dst); } break; case X86_INS_CALL: case X86_INS_LCALL: switch (INSOP(0).type) { case X86_OP_IMM: op->type = R_ANAL_OP_TYPE_CALL; // TODO: what if UCALL? // TODO: use imm_size op->jump = INSOP(0).imm; op->fail = addr+op->size; break; case X86_OP_MEM: op->type = R_ANAL_OP_TYPE_UCALL; op->jump = UT64_MAX; if (INSOP(0).mem.base == 0) { op->ptr = INSOP(0).mem.disp; } break; default: op->type = R_ANAL_OP_TYPE_UCALL; op->jump = UT64_MAX; break; } if (a->decode) { char* arg = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s," "%d,%s,-=,%s," "=[]," "%s,%s,=", pc, rs, sp, sp, arg, pc); free (arg); } break; case X86_INS_JMP: case X86_INS_LJMP: if (a->decode) { char *src = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,%s,=", src, pc); free (src); } // TODO: what if UJMP? switch (INSOP(0).type) { case X86_OP_IMM: op->jump = INSOP(0).imm; op->type = R_ANAL_OP_TYPE_JMP; if (a->decode) { ut64 dst = INSOP(0).imm; esilprintf (op, "0x%"PFMT64x",%s,=", dst, pc); } break; case X86_OP_MEM: op->type = R_ANAL_OP_TYPE_UJMP; if (INSOP(0).mem.base == X86_REG_RIP) { op->ptr = INSOP(0).mem.disp; op->ptr += addr + insn->size; op->refptr = 8; } else { cs_x86_op in = INSOP(0); if (in.mem.index == 0 && in.mem.base == 0 && in.mem.scale == 1) { op->type = R_ANAL_OP_TYPE_UJMP; op->ptr = in.mem.disp; if (a->decode) { esilprintf (op, "0x%"PFMT64x",[],%s,=", op->ptr, pc); } } } break; case X86_OP_REG: case X86_OP_FP: default: // other? op->type = R_ANAL_OP_TYPE_UJMP; break; } break; case X86_INS_IN: case X86_INS_INSW: case X86_INS_INSD: case X86_INS_INSB: case X86_INS_OUT: case X86_INS_OUTSB: case X86_INS_OUTSD: case X86_INS_OUTSW: op->type = R_ANAL_OP_TYPE_IO; break; case X86_INS_VXORPD: case X86_INS_VXORPS: case X86_INS_VPXORD: case X86_INS_VPXORQ: case X86_INS_VPXOR: case X86_INS_XORPS: case X86_INS_KXORW: case X86_INS_PXOR: case X86_INS_XOR: op->type = R_ANAL_OP_TYPE_XOR; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "^"); esilprintf (op, "%s,%s,$z,zf,=,$p,pf,=,0,cf,=,0,of,=,$s,sf,=", src, dst); free (src); free (dst); } break; case X86_INS_OR: op->type = R_ANAL_OP_TYPE_OR; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,%s,|=", src, dst); free (src); free (dst); } break; case X86_INS_INC: op->type = R_ANAL_OP_TYPE_ADD; op->val = 1; if (a->decode) { char *src = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,++=", src); free (src); } break; case X86_INS_DEC: op->type = R_ANAL_OP_TYPE_SUB; op->val = 1; if (a->decode) { char *src = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,--=", src); free (src); } break; case X86_INS_SUB: case X86_INS_PSUBB: case X86_INS_PSUBW: case X86_INS_PSUBD: case X86_INS_PSUBQ: case X86_INS_PSUBSB: case X86_INS_PSUBSW: case X86_INS_PSUBUSB: case X86_INS_PSUBUSW: op->type = R_ANAL_OP_TYPE_SUB; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "-"); esilprintf (op, "%s,%s,$c,cf,=,$z,zf,=,$s,sf,=,$o,of,=", src, dst); // TODO: update flags free (src); free (dst); } if (INSOP(0).type == X86_OP_REG && INSOP(1).type == X86_OP_IMM) { if (INSOP(0).reg == X86_REG_RSP || INSOP(0).reg == X86_REG_ESP) { op->stackop = R_ANAL_STACK_INC; op->stackptr = INSOP(1).imm; } } break; case X86_INS_LIDT: op->type = R_ANAL_OP_TYPE_LOAD; op->family = R_ANAL_OP_FAMILY_PRIV; break; case X86_INS_SIDT: op->type = R_ANAL_OP_TYPE_STORE; op->family = R_ANAL_OP_FAMILY_PRIV; break; case X86_INS_RDRAND: case X86_INS_RDSEED: case X86_INS_RDMSR: case X86_INS_RDPMC: case X86_INS_RDTSC: case X86_INS_RDTSCP: case X86_INS_CRC32: case X86_INS_SHA1MSG1: case X86_INS_SHA1MSG2: case X86_INS_SHA1NEXTE: case X86_INS_SHA1RNDS4: case X86_INS_SHA256MSG1: case X86_INS_SHA256MSG2: case X86_INS_SHA256RNDS2: case X86_INS_AESDECLAST: case X86_INS_AESDEC: case X86_INS_AESENCLAST: case X86_INS_AESENC: case X86_INS_AESIMC: case X86_INS_AESKEYGENASSIST: // AES instructions op->family = R_ANAL_OP_FAMILY_CRYPTO; op->type = R_ANAL_OP_TYPE_MOV; // XXX break; case X86_INS_AND: case X86_INS_ANDN: case X86_INS_ANDPD: case X86_INS_ANDPS: case X86_INS_ANDNPD: case X86_INS_ANDNPS: op->type = R_ANAL_OP_TYPE_AND; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "&"); // TODO: update of = cf = 0 // TODO: update sf, zf and pf // TODO: af is undefined esilprintf (op, "0,of,=,0,cf,=," // set carry and overflow flags "%s,%s," // set reg value "$z,zf,=," // update zero flag "$s,sf,=," // update sign flag "$o,pf,=", // update parity flag // TODO: add sign and parity flags here src, dst); free (src); free (dst); } break; case X86_INS_DIV: case X86_INS_IDIV: op->type = R_ANAL_OP_TYPE_DIV; if (a->decode) { int width = INSOP(0).size; char *dst = getarg (&gop, 0, 0, NULL); const char *r_ax = (width==2)?"ax": (width==4)?"eax":"rax"; const char *r_dx = (width==2)?"dx": (width==4)?"edx":"rdx"; // TODO update flags & handle signedness esilprintf (op, "%s,%s,%%,%s,=,%s,%s,/,%s,=", dst, r_ax, r_dx, dst, r_ax, r_ax); free (dst); } break; case X86_INS_MUL: case X86_INS_MULX: case X86_INS_MULPD: case X86_INS_MULPS: case X86_INS_MULSD: case X86_INS_MULSS: op->type = R_ANAL_OP_TYPE_MUL; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "*"); if (!src && dst) { switch (dst[0]) { case 'r': src = strdup ("rax"); break; case 'e': src = strdup ("eax"); break; default: src = strdup ("al"); break; } } esilprintf (op, "%s,%s", src, dst); free (src); free (dst); } break; case X86_INS_PACKSSDW: case X86_INS_PACKSSWB: case X86_INS_PACKUSWB: op->type = R_ANAL_OP_TYPE_MOV; op->family = R_ANAL_OP_FAMILY_MMX; break; case X86_INS_PADDB: case X86_INS_PADDD: case X86_INS_PADDW: case X86_INS_PADDSB: case X86_INS_PADDSW: case X86_INS_PADDUSB: case X86_INS_PADDUSW: op->type = R_ANAL_OP_TYPE_ADD; op->family = R_ANAL_OP_FAMILY_MMX; break; case X86_INS_FADD: case X86_INS_FADDP: op->family = R_ANAL_OP_FAMILY_FPU; /* pass thru */ case X86_INS_ADD: case X86_INS_ADDPS: case X86_INS_ADDSD: case X86_INS_ADDSS: case X86_INS_ADDSUBPD: case X86_INS_ADDSUBPS: case X86_INS_ADDPD: case X86_INS_XADD: op->type = R_ANAL_OP_TYPE_ADD; if (a->decode) { if (INSOP(0).type == X86_OP_MEM) { char *src = getarg (&gop, 1, 0, NULL); char *src2 = getarg (&gop, 0, 0, NULL); char *dst = getarg (&gop, 0, 1, NULL); // TODO: update flags esilprintf (op, "%s,%s,+,%s", src, src2, dst); free (src); free (src2); free (dst); } else { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "+"); esilprintf (op, "%s,%s", src, dst); // TODO: update flags free (src); free (dst); } } if (INSOP(0).type == X86_OP_REG && INSOP(1).type == X86_OP_IMM) { if (INSOP(0).reg == X86_REG_RSP || INSOP(0).reg == X86_REG_ESP) { op->stackop = R_ANAL_STACK_INC; op->stackptr = -INSOP(1).imm; } } break; /* Direction flag */ case X86_INS_CLD: op->type = R_ANAL_OP_TYPE_MOV; op->family = R_ANAL_OP_FAMILY_CPU; if (a->decode) esilprintf (op, "0,df,="); break; case X86_INS_STD: op->type = R_ANAL_OP_TYPE_MOV; op->family = R_ANAL_OP_FAMILY_CPU; if (a->decode) esilprintf (op, "1,df,="); break; } switch (insn->id) { case X86_INS_MOVAPS: //cvtss2sd case X86_INS_ADDSD: //cvtss2sd case X86_INS_SUBSD: //cvtss2sd case X86_INS_MULSD: //cvtss2sd case X86_INS_CVTSS2SD: //cvtss2sd case X86_INS_MOVSS: case X86_INS_MOVSD: op->family = R_ANAL_OP_FAMILY_MMX; break; } } //#if X86_GRP_PRIVILEGE>0 if (insn) { #if HAVE_CSGRP_PRIVILEGE if (cs_insn_group (handle, insn, X86_GRP_PRIVILEGE)) op->family = R_ANAL_OP_FAMILY_PRIV; #endif #if !USE_ITER_API cs_free (insn, n); #endif } //cs_close (&handle); return op->size; }
static int analop(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len) { static int omode = 0; #if USE_ITER_API static #endif cs_insn *insn = NULL; int mode = (a->bits==64)? CS_MODE_64: (a->bits==32)? CS_MODE_32: (a->bits==16)? CS_MODE_16: 0; int n, ret; int regsz = 4; if (handle && mode != omode) { cs_close (&handle); handle = 0; } omode = mode; if (handle == 0) { ret = cs_open (CS_ARCH_X86, mode, &handle); if (ret != CS_ERR_OK) { handle = 0; return 0; } } #if 0 if (len>3 && !memcmp (buf, "\xff\xff\xff\xff", 4)) return 0; #endif switch (a->bits) { case 64: regsz = 8; break; case 16: regsz = 2; break; default: regsz = 4; break; // 32 } memset (op, '\0', sizeof (RAnalOp)); op->cycles = 1; // aprox op->type = R_ANAL_OP_TYPE_NULL; op->jump = UT64_MAX; op->fail = UT64_MAX; op->ptr = op->val = UT64_MAX; op->src[0] = NULL; op->src[1] = NULL; op->size = 0; op->delay = 0; r_strbuf_init (&op->esil); cs_option (handle, CS_OPT_DETAIL, CS_OPT_ON); // capstone-next #if USE_ITER_API { ut64 naddr = addr; size_t size = len; if (insn == NULL) insn = cs_malloc (handle); n = cs_disasm_iter (handle, (const uint8_t**)&buf, &size, (uint64_t*)&naddr, insn); } #else n = cs_disasm (handle, (const ut8*)buf, len, addr, 1, &insn); #endif struct Getarg gop = { .handle = handle, .insn = insn, .bits = a->bits }; if (n<1) { op->type = R_ANAL_OP_TYPE_ILL; } else { int rs = a->bits/8; const char *pc = (a->bits==16)?"ip": (a->bits==32)?"eip":"rip"; const char *sp = (a->bits==16)?"sp": (a->bits==32)?"esp":"rsp"; const char *bp = (a->bits==16)?"bp": (a->bits==32)?"ebp":"rbp"; op->size = insn->size; op->family = R_ANAL_OP_FAMILY_CPU; // almost everything is CPU op->prefix = 0; switch (insn->detail->x86.prefix[0]) { case X86_PREFIX_REPNE: op->prefix |= R_ANAL_OP_PREFIX_REPNE; break; case X86_PREFIX_REP: op->prefix |= R_ANAL_OP_PREFIX_REP; break; case X86_PREFIX_LOCK: op->prefix |= R_ANAL_OP_PREFIX_LOCK; break; } switch (insn->id) { case X86_INS_FNOP: op->family = R_ANAL_OP_FAMILY_FPU; /* fallthru */ case X86_INS_NOP: case X86_INS_PAUSE: op->type = R_ANAL_OP_TYPE_NOP; if (a->decode) esilprintf (op, ","); break; case X86_INS_HLT: op->type = R_ANAL_OP_TYPE_TRAP; break; case X86_INS_FBLD: case X86_INS_FBSTP: case X86_INS_FCOMPP: case X86_INS_FDECSTP: case X86_INS_FEMMS: case X86_INS_FFREE: case X86_INS_FICOM: case X86_INS_FICOMP: case X86_INS_FINCSTP: case X86_INS_FNCLEX: case X86_INS_FNINIT: case X86_INS_FNSTCW: case X86_INS_FNSTSW: case X86_INS_FPATAN: case X86_INS_FPREM: case X86_INS_FPREM1: case X86_INS_FPTAN: #if CS_API_MAJOR >=4 case X86_INS_FFREEP: #endif case X86_INS_FRNDINT: case X86_INS_FRSTOR: case X86_INS_FNSAVE: case X86_INS_FSCALE: case X86_INS_FSETPM: case X86_INS_FSINCOS: case X86_INS_FNSTENV: case X86_INS_FXAM: case X86_INS_FXSAVE: case X86_INS_FXSAVE64: case X86_INS_FXTRACT: case X86_INS_FYL2X: case X86_INS_FYL2XP1: case X86_INS_FISTTP: case X86_INS_FSQRT: case X86_INS_FXCH: op->family = R_ANAL_OP_FAMILY_FPU; op->type = R_ANAL_OP_TYPE_STORE; break; case X86_INS_FTST: case X86_INS_FUCOMPI: case X86_INS_FUCOMI: case X86_INS_FUCOMPP: case X86_INS_FUCOMP: case X86_INS_FUCOM: op->family = R_ANAL_OP_FAMILY_FPU; op->type = R_ANAL_OP_TYPE_CMP; break; case X86_INS_FABS: op->type = R_ANAL_OP_TYPE_ABS; op->family = R_ANAL_OP_FAMILY_FPU; break; case X86_INS_FLDCW: case X86_INS_FLDENV: case X86_INS_FLDL2E: case X86_INS_FLDL2T: case X86_INS_FLDLG2: case X86_INS_FLDLN2: case X86_INS_FLDPI: case X86_INS_FLDZ: case X86_INS_FLD1: case X86_INS_FLD: op->type = R_ANAL_OP_TYPE_LOAD; op->family = R_ANAL_OP_FAMILY_FPU; break; case X86_INS_FIST: case X86_INS_FISTP: case X86_INS_FST: case X86_INS_FSTP: case X86_INS_FSTPNCE: case X86_INS_FXRSTOR: case X86_INS_FXRSTOR64: op->type = R_ANAL_OP_TYPE_STORE; op->family = R_ANAL_OP_FAMILY_FPU; break; case X86_INS_FDIV: case X86_INS_FIDIV: case X86_INS_FDIVP: case X86_INS_FDIVR: case X86_INS_FIDIVR: case X86_INS_FDIVRP: op->type = R_ANAL_OP_TYPE_DIV; op->family = R_ANAL_OP_FAMILY_FPU; break; case X86_INS_FSUBR: case X86_INS_FISUBR: case X86_INS_FSUBRP: case X86_INS_FSUB: case X86_INS_FISUB: case X86_INS_FSUBP: op->type = R_ANAL_OP_TYPE_SUB; op->family = R_ANAL_OP_FAMILY_FPU; break; case X86_INS_FMUL: case X86_INS_FIMUL: case X86_INS_FMULP: op->type = R_ANAL_OP_TYPE_MUL; op->family = R_ANAL_OP_FAMILY_FPU; break; case X86_INS_CLI: case X86_INS_STI: op->type = R_ANAL_OP_TYPE_SWI; op->family = R_ANAL_OP_FAMILY_PRIV; break; case X86_INS_CLC: case X86_INS_STC: case X86_INS_CLAC: case X86_INS_CLGI: case X86_INS_CLTS: #if CS_API_MAJOR >= 4 case X86_INS_CLWB: #endif case X86_INS_STAC: case X86_INS_STGI: op->type = R_ANAL_OP_TYPE_MOV; break; // cmov case X86_INS_SETNE: case X86_INS_SETNO: case X86_INS_SETNP: case X86_INS_SETNS: case X86_INS_SETO: case X86_INS_SETP: case X86_INS_SETS: case X86_INS_SETL: case X86_INS_SETLE: case X86_INS_SETB: case X86_INS_SETG: case X86_INS_SETAE: case X86_INS_SETA: case X86_INS_SETBE: case X86_INS_SETE: case X86_INS_SETGE: op->type = R_ANAL_OP_TYPE_CMOV; op->family = 0; if (a->decode) { char *dst = getarg (&gop, 0, 0, NULL); switch (insn->id) { case X86_INS_SETE: esilprintf (op, "zf,%s,=", dst); break; case X86_INS_SETNE: esilprintf (op, "zf,!,%s,=", dst); break; case X86_INS_SETO: esilprintf (op, "of,%s,=", dst); break; case X86_INS_SETNO: esilprintf (op, "of,!,%s,=", dst); break; case X86_INS_SETP: esilprintf (op, "pf,%s,=", dst); break; case X86_INS_SETNP: esilprintf (op, "pf,!,%s,=", dst); break; case X86_INS_SETS: esilprintf (op, "sf,%s,=", dst); break; case X86_INS_SETNS: esilprintf (op, "sf,!,%s,=", dst); break; case X86_INS_SETB: esilprintf (op, "cf,%s,=", dst); break; case X86_INS_SETAE: esilprintf (op, "cf,!,%s,=", dst); break; /* TODO */ #if 0 SETLE/SETNG Sets the byte in the operand to 1 if the Zero Flag is set or the Sign Flag is not equal to the Overflow Flag, otherwise sets the operand to 0. SETBE/SETNA Sets the byte in the operand to 1 if the Carry Flag or the Zero Flag is set, otherwise sets the operand to 0. SETL/SETNGE Sets the byte in the operand to 1 if the Sign Flag is not equal to the Overflow Flag, otherwise sets the operand to 0. case X86_INS_SETL: esilprintf (op, "pf,!,%s,=", dst); break; case X86_INS_SETLE: esilprintf (op, "pf,!,%s,=", dst); break; case X86_INS_SETG: esilprintf (op, "pf,!,%s,=", dst); break; case X86_INS_SETA: esilprintf (op, "pf,!,%s,=", dst); break; case X86_INS_SETBE: esilprintf (op, "pf,!,%s,=", dst); break; case X86_INS_SETGE: esilprintf (op, "pf,!,%s,=", dst); break; break; #endif } free (dst); } break; // cmov case X86_INS_FCMOVBE: case X86_INS_FCMOVB: case X86_INS_FCMOVNBE: case X86_INS_FCMOVNB: case X86_INS_FCMOVE: case X86_INS_FCMOVNE: case X86_INS_FCMOVNU: case X86_INS_FCMOVU: op->family = R_ANAL_OP_FAMILY_FPU; op->type = R_ANAL_OP_TYPE_MOV; break; case X86_INS_CMOVA: case X86_INS_CMOVAE: case X86_INS_CMOVB: case X86_INS_CMOVBE: case X86_INS_CMOVE: case X86_INS_CMOVG: case X86_INS_CMOVGE: case X86_INS_CMOVL: case X86_INS_CMOVLE: case X86_INS_CMOVNE: case X86_INS_CMOVNO: case X86_INS_CMOVNP: case X86_INS_CMOVNS: case X86_INS_CMOVO: case X86_INS_CMOVP: case X86_INS_CMOVS: op->type = R_ANAL_OP_TYPE_CMOV; break; // mov case X86_INS_MOVSS: case X86_INS_MOV: case X86_INS_MOVAPS: case X86_INS_MOVAPD: case X86_INS_MOVZX: case X86_INS_MOVUPS: case X86_INS_MOVABS: case X86_INS_MOVHPD: case X86_INS_MOVHPS: case X86_INS_MOVLPD: case X86_INS_MOVLPS: case X86_INS_MOVBE: case X86_INS_MOVSB: case X86_INS_MOVSD: case X86_INS_MOVSQ: case X86_INS_MOVSX: case X86_INS_MOVSXD: case X86_INS_MOVSW: case X86_INS_MOVD: case X86_INS_MOVQ: case X86_INS_MOVDQ2Q: { op->type = R_ANAL_OP_TYPE_MOV; op->ptr = UT64_MAX; switch (INSOP(0).type) { case X86_OP_MEM: op->ptr = INSOP(0).mem.disp; op->refptr = INSOP(0).size; if (INSOP(0).mem.base == X86_REG_RIP) { op->ptr += addr + insn->size; } else if (INSOP(0).mem.base == X86_REG_RBP || INSOP(0).mem.base == X86_REG_EBP) { op->stackop = R_ANAL_STACK_SET; op->stackptr = regsz; } else { if (op->ptr < 0x1000) op->ptr = UT64_MAX; } if (a->decode) { if (op->prefix & R_ANAL_OP_PREFIX_REP) { int width = INSOP(0).size; const char *src = cs_reg_name(handle, INSOP(1).mem.base); const char *dst = cs_reg_name(handle, INSOP(0).mem.base); const char *counter = (a->bits==16)?"cx": (a->bits==32)?"ecx":"rcx"; esilprintf (op, "%s,!,?{,BREAK,},%s,NUM,%s,NUM,"\ "%s,[%d],%s,=[%d],df,?{,%d,%s,-=,%d,%s,-=,},"\ "df,!,?{,%d,%s,+=,%d,%s,+=,},%s,--=,%s," \ "?{,8,GOTO,},%s,=,%s,=", counter, src, dst, src, width, dst, width, width, src, width, dst, width, src, width, dst, counter, counter, dst, src); } else { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, NULL); esilprintf (op, "%s,%s", src, dst); free (src); free (dst); } } break; case X86_OP_REG: { char *dst = getarg (&gop, 0, 0, NULL); op->dst = r_anal_value_new (); op->dst->reg = r_reg_get (a->reg, dst, R_REG_TYPE_GPR); op->src[0] = r_anal_value_new (); if (INSOP(1).type == X86_OP_MEM) { op->src[0]->delta = INSOP(1).mem.disp; } free (dst); } default: if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,%s,=", src, dst); free (src); free (dst); } break; } if (op->refptr<1 || op->ptr == UT64_MAX) { switch (INSOP(1).type) { case X86_OP_MEM: op->ptr = INSOP(1).mem.disp; op->refptr = INSOP(1).size; if (INSOP(1).mem.base == X86_REG_RIP) { op->ptr += addr + insn->size; } else if (INSOP(1).mem.base == X86_REG_RBP || INSOP(1).mem.base == X86_REG_EBP) { op->stackop = R_ANAL_STACK_GET; op->stackptr = regsz; } break; case X86_OP_IMM: if (INSOP(1).imm > 10) op->ptr = INSOP(1).imm; break; default: break; } } } break; case X86_INS_ROL: case X86_INS_RCL: // TODO: RCL Still does not work as intended // - Set flags op->type = R_ANAL_OP_TYPE_ROL; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,%s,<<<,%s,=", src, dst, dst); free (src); free (dst); } break; case X86_INS_ROR: case X86_INS_RCR: // TODO: RCR Still does not work as intended // - Set flags op->type = R_ANAL_OP_TYPE_ROR; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,%s,>>>,%s,=", src, dst, dst); free (src); free (dst); } break; case X86_INS_SHL: case X86_INS_SHLD: case X86_INS_SHLX: // TODO: Set CF: Carry flag is the last bit shifted out due to // this operation. It is undefined for SHL and SHR where the // number of bits shifted is greater than the size of the // destination. op->type = R_ANAL_OP_TYPE_SHL; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "<<"); esilprintf (op, "%s,%s,$z,zf,=,$p,pf,=,$s,sf,=", src, dst); free (src); free (dst); } break; case X86_INS_SAR: case X86_INS_SARX: // TODO: Set CF. See case X86_INS_SHL for more details. op->type = R_ANAL_OP_TYPE_SAR; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, ">>"); esilprintf (op, "%s,%s,$z,zf,=,$p,pf,=,$s,sf,=", src, dst); free (src); free (dst); } break; case X86_INS_SAL: // TODO: Set CF: See case X86_INS_SAL for more details. op->type = R_ANAL_OP_TYPE_SAL; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "<<"); esilprintf (op, "%s,%s,$z,zf,=,$p,pf,=,$s,sf,=", src, dst); free (src); free (dst); } break; case X86_INS_SALC: op->type = R_ANAL_OP_TYPE_SAL; if (a->decode) { esilprintf (op, "$z,DUP,zf,=,al,="); } break; case X86_INS_SHR: case X86_INS_SHRD: case X86_INS_SHRX: // TODO: Set CF: See case X86_INS_SAL for more details. op->type = R_ANAL_OP_TYPE_SHR; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,%s,>>=,$z,zf,=,$p,pf,=,$s,sf,=", src, dst); free (src); free (dst); } break; case X86_INS_CMP: case X86_INS_CMPPD: case X86_INS_CMPPS: case X86_INS_CMPSW: case X86_INS_CMPSD: case X86_INS_CMPSQ: case X86_INS_CMPSB: case X86_INS_CMPSS: case X86_INS_TEST: if (insn->id == X86_INS_TEST) { op->type = R_ANAL_OP_TYPE_ACMP; //compare via and if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "0,%s,%s,&,==,$z,zf,=,$p,pf,=,$s,sf,=,0,cf,=,0,of,=", src, dst); free (src); free (dst); } } else { op->type = R_ANAL_OP_TYPE_CMP; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,%s,==,$z,zf,=,$b%d,cf,=,$p,pf,=,$s,sf,=", src, dst, (INSOP(0).size*8)); free (src); free (dst); } } switch (INSOP(0).type) { case X86_OP_MEM: op->ptr = INSOP(0).mem.disp; op->refptr = INSOP(0).size; if (INSOP(0).mem.base == X86_REG_RIP) { op->ptr += addr + insn->size; } else if (INSOP(0).mem.base == X86_REG_RBP || INSOP(0).mem.base == X86_REG_EBP) { op->stackop = R_ANAL_STACK_SET; op->stackptr = regsz; } op->ptr = INSOP(1).imm; break; default: switch (INSOP(1).type) { case X86_OP_MEM: op->ptr = INSOP(1).mem.disp; op->refptr = INSOP(1).size; if (INSOP(1).mem.base == X86_REG_RIP) { op->ptr += addr + insn->size; } else if (INSOP(1).mem.base == X86_REG_RBP || INSOP(1).mem.base == X86_REG_EBP) { op->stackop = R_ANAL_STACK_SET; op->stackptr = regsz; } break; case X86_OP_IMM: op->ptr = INSOP(1).imm; break; default: break; } break; } break; case X86_INS_LEA: op->type = R_ANAL_OP_TYPE_LEA; if (a->decode) { char *src = getarg (&gop, 0, 0, NULL); char *dst = getarg (&gop, 1, 2, NULL); esilprintf (op, "%s,%s,=", dst, src); free (src); free (dst); } switch (INSOP(1).type) { case X86_OP_MEM: op->ptr = INSOP(1).mem.disp; op->refptr = INSOP(1).size; switch (INSOP(1).mem.base) { case X86_REG_RIP: op->ptr += addr + op->size; break; case X86_REG_RBP: case X86_REG_EBP: op->stackop = R_ANAL_STACK_GET; op->stackptr = regsz; break; default: /* unhandled */ break; } break; case X86_OP_IMM: if (INSOP(1).imm > 10) op->ptr = INSOP(1).imm; break; default: break; } break; case X86_INS_ENTER: case X86_INS_PUSH: case X86_INS_PUSHAW: case X86_INS_PUSHAL: case X86_INS_PUSHF: { char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "%d,%s,-=,%s,%s,=[%d]", rs, sp, dst, sp, rs); free (dst); } switch (INSOP(0).type) { case X86_OP_IMM: op->ptr = INSOP(0).imm; op->type = R_ANAL_OP_TYPE_PUSH; break; default: op->type = R_ANAL_OP_TYPE_UPUSH; break; } op->stackop = R_ANAL_STACK_INC; op->stackptr = regsz; break; case X86_INS_LEAVE: op->type = R_ANAL_OP_TYPE_POP; if (a->decode) { esilprintf (op, "%s,%s,=,%s,[%d],%s,=,%d,%s,+=", bp, sp, sp, rs, bp, rs, sp); } op->stackop = R_ANAL_STACK_INC; op->stackptr = -regsz; break; case X86_INS_POP: case X86_INS_POPF: case X86_INS_POPAW: case X86_INS_POPAL: case X86_INS_POPCNT: op->type = R_ANAL_OP_TYPE_POP; if (a->decode) { char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,[%d],%s,=,%d,%s,+=", sp, rs, dst, rs, sp); free (dst); } op->stackop = R_ANAL_STACK_INC; op->stackptr = -regsz; break; case X86_INS_RET: case X86_INS_RETF: case X86_INS_RETFQ: case X86_INS_IRET: case X86_INS_IRETD: case X86_INS_IRETQ: case X86_INS_SYSRET: op->type = R_ANAL_OP_TYPE_RET; if (a->decode) esilprintf (op, "%s,[%d],%s,=,%d,%s,+=", sp, rs, pc, rs, sp); op->stackop = R_ANAL_STACK_INC; op->stackptr = -regsz; break; case X86_INS_INT3: if (a->decode) esilprintf (op, "3,$"); op->type = R_ANAL_OP_TYPE_TRAP; // TRAP break; case X86_INS_INT1: if (a->decode) esilprintf (op, "1,$"); op->type = R_ANAL_OP_TYPE_SWI; // TRAP break; case X86_INS_INT: if (a->decode) esilprintf (op, "%d,$", R_ABS((int)INSOP(0).imm)); op->type = R_ANAL_OP_TYPE_SWI; break; case X86_INS_SYSCALL: op->type = R_ANAL_OP_TYPE_SWI; break; case X86_INS_INTO: case X86_INS_VMCALL: case X86_INS_VMMCALL: op->type = R_ANAL_OP_TYPE_TRAP; if (a->decode) esilprintf (op, "%d,$", (int)INSOP(0).imm); break; case X86_INS_JL: case X86_INS_JLE: case X86_INS_JA: case X86_INS_JAE: case X86_INS_JB: case X86_INS_JBE: case X86_INS_JCXZ: case X86_INS_JECXZ: case X86_INS_JRCXZ: case X86_INS_JO: case X86_INS_JNO: case X86_INS_JS: case X86_INS_JNS: case X86_INS_JP: case X86_INS_JNP: case X86_INS_JE: case X86_INS_JNE: case X86_INS_JG: case X86_INS_JGE: case X86_INS_LOOP: case X86_INS_LOOPE: case X86_INS_LOOPNE: op->type = R_ANAL_OP_TYPE_CJMP; op->jump = INSOP(0).imm; op->fail = addr+op->size; const char *cnt = (a->bits==16)?"cx":(a->bits==32)?"ecx":"rcx"; if (a->decode) { char *dst = getarg (&gop, 0, 2, NULL); switch (insn->id) { case X86_INS_JL: esilprintf (op, "of,sf,^,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JLE: esilprintf (op, "of,sf,^,zf,|,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JA: esilprintf (op, "cf,zf,|,!,?{,%s,%s,=,}",dst, pc); break; case X86_INS_JAE: esilprintf (op, "cf,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JB: esilprintf (op, "cf,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JO: esilprintf (op, "of,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JNO: esilprintf (op, "of,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JE: esilprintf (op, "zf,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JGE: esilprintf (op, "of,!,sf,^,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JNE: esilprintf (op, "zf,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JG: esilprintf (op, "sf,of,!,^,zf,!,&,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JS: esilprintf (op, "sf,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JNS: esilprintf (op, "sf,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JP: esilprintf (op, "pf,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JNP: esilprintf (op, "pf,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JBE: esilprintf (op, "zf,cf,|,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JCXZ: esilprintf (op, "cx,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JECXZ: esilprintf (op, "ecx,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_JRCXZ: esilprintf (op, "rcx,!,?{,%s,%s,=,}", dst, pc); break; case X86_INS_LOOP: esilprintf (op, "1,%s,-=,%s,?{,%s,%s,=,}", cnt, cnt, dst, pc); break; case X86_INS_LOOPE: esilprintf (op, "1,%s,-=,%s,?{,zf,?{,%s,%s,=,},}", cnt, cnt, dst, pc); break; case X86_INS_LOOPNE: esilprintf (op, "1,%s,-=,%s,?{,zf,!,?{,%s,%s,=,},}", cnt, cnt, dst, pc); break; } free (dst); } break; case X86_INS_CALL: case X86_INS_LCALL: switch (INSOP(0).type) { case X86_OP_IMM: op->type = R_ANAL_OP_TYPE_CALL; // TODO: what if UCALL? // TODO: use imm_size op->jump = INSOP(0).imm; op->fail = addr+op->size; break; case X86_OP_MEM: op->type = R_ANAL_OP_TYPE_UCALL; op->jump = UT64_MAX; if (INSOP(0).mem.base == 0) { op->ptr = INSOP(0).mem.disp; } break; default: op->type = R_ANAL_OP_TYPE_UCALL; op->jump = UT64_MAX; break; } if (a->decode) { char* arg = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s," "%d,%s,-=,%s," "=[]," "%s,%s,=", pc, rs, sp, sp, arg, pc); free (arg); } break; case X86_INS_JMP: case X86_INS_LJMP: if (a->decode) { char *src = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,%s,=", src, pc); free (src); } // TODO: what if UJMP? switch (INSOP(0).type) { case X86_OP_IMM: op->jump = INSOP(0).imm; op->type = R_ANAL_OP_TYPE_JMP; if (a->decode) { ut64 dst = INSOP(0).imm; esilprintf (op, "0x%"PFMT64x",%s,=", dst, pc); } break; case X86_OP_MEM: op->type = R_ANAL_OP_TYPE_UJMP; op->ptr = INSOP(0).mem.disp; if (INSOP(0).mem.base == X86_REG_RIP) { op->ptr += addr + insn->size; op->refptr = 8; } else { cs_x86_op in = INSOP(0); if (in.mem.index == 0 && in.mem.base == 0 && in.mem.scale == 1) { if (a->decode) { esilprintf (op, "0x%"PFMT64x",[],%s,=", op->ptr, pc); } } } break; case X86_OP_REG: { char *src = getarg (&gop, 0, 0, NULL); op->src[0] = r_anal_value_new (); op->src[0]->reg = r_reg_get (a->reg, src, R_REG_TYPE_GPR); free (src); //XXX fallthrough } case X86_OP_FP: default: // other? op->type = R_ANAL_OP_TYPE_UJMP; op->ptr = UT64_MAX; break; } break; case X86_INS_IN: case X86_INS_INSW: case X86_INS_INSD: case X86_INS_INSB: op->type = R_ANAL_OP_TYPE_IO; op->type2 = 0; break; case X86_INS_OUT: case X86_INS_OUTSB: case X86_INS_OUTSD: case X86_INS_OUTSW: op->type = R_ANAL_OP_TYPE_IO; op->type2 = 1; break; case X86_INS_VXORPD: case X86_INS_VXORPS: case X86_INS_VPXORD: case X86_INS_VPXORQ: case X86_INS_VPXOR: case X86_INS_XORPS: case X86_INS_KXORW: case X86_INS_PXOR: case X86_INS_XOR: op->type = R_ANAL_OP_TYPE_XOR; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "^"); esilprintf (op, "%s,%s,$z,zf,=,$p,pf,=,$s,sf,=,0,cf,=,0,of,=", src, dst); free (src); free (dst); } break; case X86_INS_OR: // The OF and CF flags are cleared; the SF, ZF, and PF flags are // set according to the result. The state of the AF flag is // undefined. op->type = R_ANAL_OP_TYPE_OR; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "%s,%s,|=,0,of,=,0,cf,=,$s,sf,=,$z,zf,=,$p,pf,=", src, dst); free (src); free (dst); } break; case X86_INS_INC: // The CF flag is not affected. The OF, SF, ZF, AF, and PF flags // are set according to the result. op->type = R_ANAL_OP_TYPE_ADD; op->val = 1; if (a->decode) { char *src = getarg (&gop, 0, 0, NULL); if (strchr (src, '[')) { char *dst = r_str_replace (strdup (src), "[", "=[", 1); esilprintf (op, "1,%s,++,%s,$o,of,=,$s,sf,=,$z,zf,=,$p,pf,=", src, dst); free (dst); } else { esilprintf (op, "%s,++=,$o,of,=,$s,sf,=,$z,zf,=,$p,pf,=", src); } free (src); } break; case X86_INS_DEC: // The CF flag is not affected. The OF, SF, ZF, AF, and PF flags // are set according to the result. op->type = R_ANAL_OP_TYPE_SUB; op->val = 1; if (a->decode) { char *src = getarg (&gop, 0, 0, NULL); //esilprintf (op, "%s,--=,$o,of,=,$s,sf,=,$z,zf,=,$p,pf,=", src); esilprintf (op, "1,%s,[4],-,%s,=[4],$o,of,=,$s,sf,=,$z,zf,=,$p,pf,=", src, src); free (src); } break; case X86_INS_PSUBB: case X86_INS_PSUBW: case X86_INS_PSUBD: case X86_INS_PSUBQ: case X86_INS_PSUBSB: case X86_INS_PSUBSW: case X86_INS_PSUBUSB: case X86_INS_PSUBUSW: op->type = R_ANAL_OP_TYPE_SUB; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "-"); esilprintf (op, "%s,%s", src, dst); free(src); free(dst); } break; case X86_INS_SUB: op->type = R_ANAL_OP_TYPE_SUB; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "-"); // Set OF, SF, ZF, AF, PF, and CF flags. // We use $b rather than $c here as the carry flag really // represents a "borrow" esilprintf (op, "%s,%s,$o,of,=,$s,sf,=,$z,zf,=,$p,pf,=,$b,cf,=", src, dst); free (src); free (dst); } if (INSOP(0).type == X86_OP_REG && INSOP(1).type == X86_OP_IMM) { if (INSOP(0).reg == X86_REG_RSP || INSOP(0).reg == X86_REG_ESP) { op->stackop = R_ANAL_STACK_INC; op->stackptr = INSOP(1).imm; } } break; case X86_INS_SBB: // dst = dst - (src + cf) op->type = R_ANAL_OP_TYPE_SUB; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 0, NULL); esilprintf (op, "cf,%s,+,%s,-=,$o,of,=,$s,sf,=,$z,zf,=,$p,pf,=,$b,cf,=", src, dst); free (src); free (dst); } break; case X86_INS_LIDT: op->type = R_ANAL_OP_TYPE_LOAD; op->family = R_ANAL_OP_FAMILY_PRIV; break; case X86_INS_SIDT: op->type = R_ANAL_OP_TYPE_STORE; op->family = R_ANAL_OP_FAMILY_PRIV; break; case X86_INS_RDRAND: case X86_INS_RDSEED: case X86_INS_RDMSR: case X86_INS_RDPMC: case X86_INS_RDTSC: case X86_INS_RDTSCP: case X86_INS_CRC32: case X86_INS_SHA1MSG1: case X86_INS_SHA1MSG2: case X86_INS_SHA1NEXTE: case X86_INS_SHA1RNDS4: case X86_INS_SHA256MSG1: case X86_INS_SHA256MSG2: case X86_INS_SHA256RNDS2: case X86_INS_AESDECLAST: case X86_INS_AESDEC: case X86_INS_AESENCLAST: case X86_INS_AESENC: case X86_INS_AESIMC: case X86_INS_AESKEYGENASSIST: // AES instructions op->family = R_ANAL_OP_FAMILY_CRYPTO; op->type = R_ANAL_OP_TYPE_MOV; // XXX break; case X86_INS_AND: case X86_INS_ANDN: case X86_INS_ANDPD: case X86_INS_ANDPS: case X86_INS_ANDNPD: case X86_INS_ANDNPS: op->type = R_ANAL_OP_TYPE_AND; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "&"); esilprintf (op, "%s,%s,0,of,=,0,cf,=,$z,zf,=,$s,sf,=,$o,pf,=", src, dst); free (src); free (dst); } break; case X86_INS_IDIV: op->type = R_ANAL_OP_TYPE_DIV; if (a->decode) { char *a0 = getarg (&gop, 0, 0, NULL); char *a1 = getarg (&gop, 1, 0, NULL); char *a2 = getarg (&gop, 2, 0, NULL); // TODO update flags & handle signedness if (!a2 && !a1) { // TODO: IDIV rbx not implemented. this is just a workaround // http://www.tptp.cc/mirrors/siyobik.info/instruction/IDIV.html // Divides (signed) the value in the AX, DX:AX, or EDX:EAX registers (dividend) by the source operand (divisor) and stores the result in the AX (AH:AL), DX:AX, or EDX:EAX registers. The source operand can be a general-purpose register or a memory location. The action of this instruction depends on the operand size (dividend/divisor), as shown in the following table: // IDIV RBX == RDX:RAX /= RBX esilprintf (op, "%s,%s,/=", a0, "rax"); } else { esilprintf (op, "%s,%s,/,%s,=", a2, a1, a0); } free (a0); free (a1); free (a2); } break; case X86_INS_DIV: op->type = R_ANAL_OP_TYPE_DIV; if (a->decode) { int width = INSOP(0).size; char *dst = getarg (&gop, 0, 0, NULL); const char *r_ax = (width==2)?"ax": (width==4)?"eax":"rax"; const char *r_dx = (width==2)?"dx": (width==4)?"edx":"rdx"; // TODO update flags & handle signedness esilprintf (op, "%s,%s,%%,%s,=,%s,%s,/,%s,=", dst, r_ax, r_dx, dst, r_ax, r_ax); free (dst); } break; case X86_INS_IMUL: op->type = R_ANAL_OP_TYPE_MUL; if (a->decode) { char *a0 = getarg (&gop, 0, 0, NULL); char *a1 = getarg (&gop, 1, 0, NULL); char *a2 = getarg (&gop, 2, 0, NULL); if (a2) { // TODO update flags & handle signedness esilprintf (op, "%s,%s,*,%s,=", a2, a1, a0); free (a2); } else { if (a1) { esilprintf (op, "%s,%s,*=", a1, a0); } else { esilprintf (op, "%s,%s,*=", a0, "rax"); } } free (a0); free (a1); } break; case X86_INS_MUL: case X86_INS_MULX: case X86_INS_MULPD: case X86_INS_MULPS: case X86_INS_MULSD: case X86_INS_MULSS: op->type = R_ANAL_OP_TYPE_MUL; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "*"); if (!src && dst) { switch (dst[0]) { case 'r': src = strdup ("rax"); break; case 'e': src = strdup ("eax"); break; default: src = strdup ("al"); break; } } esilprintf (op, "%s,%s", src, dst); free (src); free (dst); } break; case X86_INS_PACKSSDW: case X86_INS_PACKSSWB: case X86_INS_PACKUSWB: op->type = R_ANAL_OP_TYPE_MOV; op->family = R_ANAL_OP_FAMILY_MMX; break; case X86_INS_PADDB: case X86_INS_PADDD: case X86_INS_PADDW: case X86_INS_PADDSB: case X86_INS_PADDSW: case X86_INS_PADDUSB: case X86_INS_PADDUSW: op->type = R_ANAL_OP_TYPE_ADD; op->family = R_ANAL_OP_FAMILY_MMX; break; case X86_INS_XCHG: op->type = R_ANAL_OP_TYPE_MOV; op->family = R_ANAL_OP_FAMILY_CPU; { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, NULL); esilprintf (op, "%s,%s,%s,=,%s,=", src, dst, src, dst); free (src); free (dst); } break; case X86_INS_XADD: /* xchg + add */ op->type = R_ANAL_OP_TYPE_ADD; op->family = R_ANAL_OP_FAMILY_CPU; { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, NULL); if (src == dst) { esilprintf (op, "%s,%s,+,%s", src, dst, dst); } else { esilprintf (op, "%s,%s,%s,=,%s,=," "%s,%s,+,%s", src, dst, src, dst, src, dst, dst); } free (src); free (dst); } break; case X86_INS_FADD: case X86_INS_FADDP: op->family = R_ANAL_OP_FAMILY_FPU; /* pass thru */ case X86_INS_ADDPS: case X86_INS_ADDSD: case X86_INS_ADDSS: case X86_INS_ADDSUBPD: case X86_INS_ADDSUBPS: case X86_INS_ADDPD: // The OF, SF, ZF, AF, CF, and PF flags are set according to the // result. op->type = R_ANAL_OP_TYPE_ADD; if (a->decode) { if (INSOP(0).type == X86_OP_MEM) { char *src = getarg (&gop, 1, 0, NULL); char *src2 = getarg (&gop, 0, 0, NULL); char *dst = getarg (&gop, 0, 1, NULL); esilprintf (op, "%s,%s,+,%s", src, src2, dst); free (src); free (src2); free (dst); } else { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "+"); esilprintf (op, "%s,%s", src, dst); free (src); free (dst); } } if (INSOP(0).type == X86_OP_REG && INSOP(1).type == X86_OP_IMM) { if (INSOP(0).reg == X86_REG_RSP || INSOP(0).reg == X86_REG_ESP) { op->stackop = R_ANAL_STACK_INC; op->stackptr = -INSOP(1).imm; } } break; case X86_INS_ADD: // The OF, SF, ZF, AF, CF, and PF flags are set according to the // result. op->type = R_ANAL_OP_TYPE_ADD; if (a->decode) { if (INSOP(0).type == X86_OP_MEM) { char *src = getarg (&gop, 1, 0, NULL); char *src2 = getarg (&gop, 0, 0, NULL); char *dst = getarg (&gop, 0, 1, NULL); esilprintf (op, "%s,%s,+,%s,$o,of,=,$s,sf,=,$z,zf,=,$p,pf,=,$c,cf,=", src, src2, dst); free (src); free (src2); free (dst); } else { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 1, "+"); esilprintf (op, "%s,%s,$o,of,=,$s,sf,=,$z,zf,=,$p,pf,=,$c,cf,=", src, dst); free (src); free (dst); } } if (INSOP(0).type == X86_OP_REG && INSOP(1).type == X86_OP_IMM) { if (INSOP(0).reg == X86_REG_RSP || INSOP(0).reg == X86_REG_ESP) { op->stackop = R_ANAL_STACK_INC; op->stackptr = -INSOP(1).imm; } } break; case X86_INS_ADC: op->type = R_ANAL_OP_TYPE_ADD; if (a->decode) { char *src = getarg (&gop, 1, 0, NULL); char *dst = getarg (&gop, 0, 0, NULL); // dst = dst + src + cf // NOTE: We would like to add the carry first before adding the // source to ensure that the flag computation from $c belongs // to the operation of adding dst += src rather than the one // that adds carry (as esil only keeps track of the last // addition to set the flags). esilprintf (op, "cf,%s,+,%s,+=,$o,of,=,$s,sf,=,$z,zf,=,$p,pf,=,$c,cf,=", src, dst); free (src); free (dst); } break; /* Direction flag */ case X86_INS_CLD: op->type = R_ANAL_OP_TYPE_MOV; if (a->decode) esilprintf (op, "0,df,="); break; case X86_INS_STD: op->type = R_ANAL_OP_TYPE_MOV; if (a->decode) esilprintf (op, "1,df,="); break; } switch (insn->id) { case X86_INS_MOVAPS: //cvtss2sd case X86_INS_ADDSD: //cvtss2sd case X86_INS_SUBSD: //cvtss2sd case X86_INS_MULSD: //cvtss2sd case X86_INS_CVTSS2SD: //cvtss2sd case X86_INS_MOVSS: case X86_INS_MOVSD: op->family = R_ANAL_OP_FAMILY_MMX; break; } } //#if X86_GRP_PRIVILEGE>0 if (insn) { #if HAVE_CSGRP_PRIVILEGE if (cs_insn_group (handle, insn, X86_GRP_PRIVILEGE)) op->family = R_ANAL_OP_FAMILY_PRIV; #endif #if !USE_ITER_API cs_free (insn, n); #endif } //cs_close (&handle); return op->size; }
static void Glissando( struct WBlocks *wblock, struct WTracks *wtrack, struct Notes *note1 ){ // struct Notes *note; struct Notes *note2=NextNote(note1); float f1,f,f2; Place p; int notenote; int notediff; if(note2==NULL) return; notediff=R_ABS(note2->note-note1->note); if(notediff==0 || notediff==1) return; f1=GetfloatFromPlacement(¬e1->l.p); f2=GetfloatFromPlacement(¬e2->l.p); bool up = note2->note > note1->note; for(notenote=note1->note;;){ if (up) notenote++; else notenote--; if (up){ if (notenote>=note2->note) break; } else { if (notenote<=note2->note) break; } f=f1+( R_ABS(note1->note-notenote)*(f2-f1) / notediff ); if (f<0) f=0; if (f>=wblock->block->num_lines) break; Float2Placement(f,&p); InsertNote( wblock, wtrack, &p,NULL, notenote, (int)(note1->velocity+( ((f-f1)*(note2->velocity-note1->velocity))/(f2-f1) )), false ); } }
R_API int r_diff_buffers_static(RDiff *d, const ut8 *a, int la, const ut8 *b, int lb) { int i, len; int hit = 0; la = R_ABS(la); lb = R_ABS(lb); if (la != lb) { len = R_MIN(la, lb); fprintf(stderr, "Buffer truncated to %d bytes (%d not compared)\n", len, R_ABS(lb-la)); } else len = la; for(i = 0; i<len; i++) { if (a[i]!=b[i]) { hit++; } else { if (hit>0) { struct r_diff_op_t o = { .a_off = d->off_a+i-hit, .a_buf = a+i-hit, .a_len = hit, .b_off = d->off_b+i-hit, .b_buf = b+i-hit, .b_len = hit }; d->callback (d, d->user, &o); hit = 0; } } } if (hit>0) { struct r_diff_op_t o = { .a_off = d->off_a+i-hit, .a_buf = a+i-hit, .a_len = hit, .b_off = d->off_b+i-hit, .b_buf = b+i-hit, .b_len = hit }; d->callback (d, d->user, &o); hit = 0; } return 0; } // XXX: temporary files are R_API int r_diff_buffers_radiff(RDiff *d, const ut8 *a, int la, const ut8 *b, int lb) { char *ptr, *str, buf[64], oop = 0; int ret, atl, btl, hit; ut8 at[128], bt[128]; ut64 ooa, oob; FILE *fd; hit = atl = btl = 0; ooa = oob = 0LL; oop = -1; r_file_dump (".a", a, la, 0); r_file_dump (".b", b, lb, 0); r_sys_cmd ("radiff -d .a .b | rsc uncolor > .d"); fd = fopen (".d", "r"); if (!fd) return 0; while (!feof (fd)) { ut64 oa, ob; // offset int ba, bb = 0; // byte char op; // operation oa = ob = 0LL; if (!fgets (buf, 63, fd)) break; if (feof (fd)) break; str = buf; ptr = strchr (buf, ' '); if (!ptr) continue; *ptr='\0'; sscanf (str, "0x%08"PFMT64x"", &oa); str = r_str_ichr (ptr+1, ' '); if (*str!='|'&&*str!='>'&&*str!='<') { ptr = strchr (str, ' '); if (!ptr) continue; *ptr='\0'; sscanf (str, "%02x", &ba); } else ba = 0; str = r_str_ichr (ptr+1, ' '); ptr = strchr (str, ' '); if (!ptr) continue; *ptr='\0'; sscanf (str, "%c", &op); str = r_str_ichr (ptr+1, ' '); if (str[0]!='0' || str[1]!='x') { ptr = strchr(str, ' '); if (!ptr) continue; *ptr = '\0'; sscanf (str, "%02x", &bb); } str = ptr+1; ptr = strchr (str, '\n'); if (!ptr) continue; *ptr='\0'; sscanf (str, "0x%08"PFMT64x"", &ob); if (oop == op || oop==-1) { if (hit == 0) { ooa = oa; oob = ob; } at[atl] = ba; bt[btl] = bb; switch (op) { case '|': atl++; btl++; break; case '>': btl++; break; case '<': atl++; break; } hit++; } else { if (hit>0) { struct r_diff_op_t o = { .a_off = ooa, .a_buf = at, .a_len = atl, .b_off = oob, .b_buf = bt, .b_len = btl }; ret = d->callback(d, d->user, &o); if (!ret) break; atl = btl = 0; hit = 0; } } oop = op; } if (hit > 0) { struct r_diff_op_t o = { .a_off = ooa, .a_buf = at, .a_len = atl, .b_off = oob, .b_buf = bt, .b_len = btl }; if (!d->callback (d, d->user, &o)) { fclose (fd); return 0; } atl = btl = 0; hit = 0; } fclose (fd); unlink (".a"); unlink (".b"); unlink (".d"); return 0; } R_API int r_diff_buffers(RDiff *d, const ut8 *a, ut32 la, const ut8 *b, ut32 lb) { if (d->delta) { return r_diff_buffers_delta (d, a, la, b, lb); } return r_diff_buffers_static (d, a, la, b, lb); } /* TODO: Move into r_util maybe? */ R_API bool r_diff_buffers_distance(RDiff *d, const ut8 *a, ut32 la, const ut8 *b, ut32 lb, ut32 *distance, double *similarity) { const bool verbose = d? d->verbose: false; /* More memory efficient version on Levenshtein Distance from: https://en.wikipedia.org/wiki/Levenshtein_distance http://www.codeproject.com/Articles/13525/Fast-memory-efficient-Levenshtein-algorithm ObM.. 8/July/2016 - More time efficient Levenshtein Distance. Now runs in about O(N*sum(MDistance)) instead of O(NM) In real world testing the speedups for similar files are immense. Processing of radiff2 -sV routerA/firmware_extract/bin/httpd routerB/firmware_extract/bin/httpd reduced from 28 hours to about 13 minutes. */ int i, j; const ut8 *aBufPtr; const ut8 *bBufPtr; ut32 aLen; ut32 bLen; // temp pointer will be used to switch v0 and v1 after processing the inner loop. int *temp; int *v0, *v1; // We need these variables outside the context of the loops as we need to // survive multiple loop iterations. // start and stop are used in our inner loop // colMin tells us the current 'best' edit distance. // extendStop & extendStart are used when we get 'double up' edge conditions // that require us to keep some more data. int start = 0; int stop = 0; int smallest; int colMin = 0; int extendStop = 0; int extendStart = 0; //we could move cost into the 'i' loop. int cost = 0; // loops can get very big, this can be removed, but it's currently in there for debugging // and optimisation testing. ut64 loops = 0; // We need the longest file to be 'A' because our optimisation tries to stop and start // around the diagonal. // AAAAAAA // B* // B * // B *____ // if we have them the other way around and we terminate on the diagonal, we won't have // inspected all the bytes of file B.. // AAAA // B* // B * // B * // B * // B ? if (la < lb) { aBufPtr = b; bBufPtr = a; aLen = lb; bLen = la; } else { aBufPtr = a; bBufPtr = b; aLen = la; bLen = lb; } stop = bLen; // Preliminary tests //Do we have both files a & b, and are they at least one byte? if (!aBufPtr || !bBufPtr || aLen < 1 || bLen < 1) { return false; } //IF the files are the same size and are identical, then we have matching files if (aLen == bLen && !memcmp (aBufPtr, bBufPtr, aLen)) { if (distance) { *distance = 0; } if (similarity) { *similarity = 1.0; } return true; } // Only calloc if we have to do some processing // calloc v0 & v1 and check they initialised v0 = (int*) calloc ((bLen + 3), sizeof (int)); if (!v0) { eprintf ("Error: cannot allocate %i bytes.", bLen + 3); return false; } v1 = (int*) calloc ((bLen + 3), sizeof (int)); if (!v1) { eprintf ("Error: cannot allocate %i bytes", 2 * (bLen + 3)); free (v0); return false; } // initialise v0 and v1. // With optimisiation we only strictly we only need to initialise v0[0..2]=0..2 & v1[0] = 1; for (i = 0; i < bLen + 1 ; i++) { v0[i] = i; v1[i] = i + 1; } // Outer loop = the length of the longest input file. for (i = 0; i < aLen; i++) { // We're going to stop the inner loop at: // bLen (so we don't run off the end of our array) // or 'two below the diagonal' PLUS any extension we need for 'double up' edge values // (see extendStop for logic) stop = R_MIN ((i + extendStop + 2), bLen); // We need a value in the result column (v1[start]). // If you look at the loop below, we need it because we look at v1[j] as one of the // potential shortest edit distances. // In all cases where the edit distance can't 'reach', // the value of v1[start] simply increments. if (start > bLen) { break; } v1[start] = v0[start] + 1; // need to have a bigger number in colMin than we'll ever encounter in the inner loop colMin = aLen; // Inner loop does all the work: for (j = start; j <= stop; j++) { loops++; // The main levenshtein comparison: cost = (aBufPtr[i] == bBufPtr[j]) ? 0 : 1; smallest = R_MIN ((v1[j] + 1), (v0[j + 1] + 1)); smallest = R_MIN (smallest, (v0[j] + cost)); // populate the next two entries in v1. // only really required if this is the last loop. if (j + 2 > bLen + 3) { break; } v1[j + 1] = smallest; v1[j + 2] = smallest + 1; // If we have seen a smaller number, it's the new column Minimum colMin = R_MIN ((colMin), (smallest)); } // We're going to start at i+1 next iteration // The column minimum is the current edit distance // This distance is the minimum 'search width' from the optimal 'i' diagonal // The extendStart picks up an edge case where we have a match on the first iteration // We update extendStart after we've set start for the next iteration. start = i + 1 - colMin - extendStart; // If the last processed entry is a match, AND // the current byte in 'a' and the previous processed entry in 'b' aren't a match // then we need to extend our search below the optimal 'i' diagonal. because we'll // have a vertical double up condition in our last two values of the results column. // j-2 is used because j++ increments prior to loop exit in the processing loop above. if (!cost && aBufPtr[i] != bBufPtr[j - 2]) { extendStop ++; } // If new start would be a match then we have a horizontal 'double up' // which means we need to keep an extra row of data // so don't increment the start counter this time, BUT keep // extendStart up our sleeves for next iteration. if (i + 1 < aLen && start < bLen && aBufPtr[i + 1] == bBufPtr[start]) { start --; extendStart ++; } //Switch v0 and v1 pointers via temp pointer temp = v0; v0 = v1; v1 = temp; //Print a processing update every 10K of outer loop if (verbose && i % 10000==0) { eprintf ("\rProcessing %d of %d\r", i, aLen); } } //Clean up output on loop exit (purely aesthetic) if (verbose) { eprintf ("\rProcessing %d of %d (loops=%llu)\n", i, aLen,loops); } if (distance) { // the final distance is the last byte we processed in the inner loop. // v0 is used instead of v1 because we switched the pointers before exiting the outer loop *distance = v0[stop]; if (similarity) { double diff = (double) (*distance) / (double) (R_MAX (aLen, bLen)); *similarity = (double)1 - diff; } } free (v0); free (v1); return true; }
R_API int r_diff_buffers_static(RDiff *d, const ut8 *a, int la, const ut8 *b, int lb) { int i, len; int hit = 0; la = R_ABS(la); lb = R_ABS(lb); if (la != lb) { len = R_MIN(la, lb); fprintf(stderr, "Buffer truncated to %d bytes (%d not compared)\n", len, R_ABS(lb-la)); } else len = la; for(i = 0; i<len; i++) { if (a[i]!=b[i]) { hit++; } else { if (hit>0) { struct r_diff_op_t o = { .a_off = d->off_a+i-hit, .a_buf = a+i-hit, .a_len = hit, .b_off = d->off_b+i-hit, .b_buf = b+i-hit, .b_len = hit }; d->callback (d, d->user, &o); hit = 0; } } } if (hit>0) { struct r_diff_op_t o = { .a_off = d->off_a+i-hit, .a_buf = a+i-hit, .a_len = hit, .b_off = d->off_b+i-hit, .b_buf = b+i-hit, .b_len = hit }; d->callback (d, d->user, &o); hit = 0; } return 0; } // XXX: temporary files are R_API int r_diff_buffers_radiff(RDiff *d, const ut8 *a, int la, const ut8 *b, int lb) { char *ptr, *str, buf[64], oop = 0; int ret, atl, btl, hit; ut8 at[128], bt[128]; ut64 ooa, oob; FILE *fd; hit = atl = btl = 0; ooa = oob = 0LL; oop = -1; r_file_dump (".a", a, la, 0); r_file_dump (".b", b, lb, 0); r_sys_cmd ("radiff -d .a .b | rsc uncolor > .d"); fd = fopen (".d", "r"); while (!feof (fd)) { ut64 oa, ob; // offset int ba, bb = 0; // byte char op; // operation oa = ob = 0LL; if (!fgets (buf, 63, fd)) break; if (feof (fd)) break; str = buf; ptr = strchr (buf, ' '); if (!ptr) continue; *ptr='\0'; sscanf (str, "0x%08"PFMT64x"", &oa); str = r_str_ichr (ptr+1, ' '); if (*str!='|'&&*str!='>'&&*str!='<') { ptr = strchr (str, ' '); if (!ptr) continue; *ptr='\0'; sscanf (str, "%02x", &ba); } else ba = 0; str = r_str_ichr (ptr+1, ' '); ptr = strchr (str, ' '); if (!ptr) continue; *ptr='\0'; sscanf (str, "%c", &op); str = r_str_ichr (ptr+1, ' '); if (str[0]!='0' || str[1]!='x') { ptr = strchr(str, ' '); if (!ptr) continue; *ptr = '\0'; sscanf (str, "%02x", &bb); } str = ptr+1; ptr = strchr (str, '\n'); if (!ptr) continue; *ptr='\0'; sscanf (str, "0x%08"PFMT64x"", &ob); if (oop == op || oop==-1) { if (hit == 0) { ooa = oa; oob = ob; } at[atl] = ba; bt[btl] = bb; switch (op) { case '|': atl++; btl++; break; case '>': btl++; break; case '<': atl++; break; } hit++; } else { if (hit>0) { struct r_diff_op_t o = { .a_off = ooa, .a_buf = at, .a_len = atl, .b_off = oob, .b_buf = bt, .b_len = btl }; ret = d->callback(d, d->user, &o); if (!ret) break; atl = btl = 0; hit = 0; } } oop = op; } if (hit>0) { struct r_diff_op_t o = { .a_off = ooa, .a_buf = at, .a_len = atl, .b_off = oob, .b_buf = bt, .b_len = btl }; if (!d->callback (d, d->user, &o)) { fclose (fd); return 0; } atl = btl = 0; hit = 0; } fclose (fd); unlink (".a"); unlink (".b"); unlink (".d"); return 0; } R_API int r_diff_buffers(RDiff *d, const ut8 *a, ut32 la, const ut8 *b, ut32 lb) { if (d->delta) return r_diff_buffers_delta (d, a, la, b, lb); return r_diff_buffers_static (d, a, la, b, lb); } /* TODO: Move into r_util maybe? */ R_API int r_diff_buffers_distance(RDiff *d, const ut8 *a, ut32 la, const ut8 *b, ut32 lb, ut32 *distance, double *similarity) { int i, j, cost, tmin, **m; if (!a || !b || la < 1 || lb < 1) return R_FALSE; if ((m = malloc ((la+1) * sizeof(int*))) == NULL) return R_FALSE; for(i = 0; i <= la; i++) if ((m[i] = malloc ((lb+1) * sizeof(int))) == NULL) { while (i--) free (m[i]); free (m); return R_FALSE; } for (i = 0; i <= la; i++) m[i][0] = i; for (j = 0; j <= lb; j++) m[0][j] = j; for (i = 1; i <= la; i++) { for (j = 1; j <= lb; j++) { if (a[i-1] == b[j-1]) cost = 0; else cost = 1; tmin = R_MIN (m[i-1][j] + 1, m[i][j-1] + 1); m[i][j] = R_MIN (tmin, m[i-1][j-1] + cost); } } if (distance != NULL) *distance = m[la][lb]; if (similarity != NULL) *similarity = (double)1 - (double)(m[la][lb])/(double)(R_MAX(la, lb)); for(i = 0; i <= la; i++) free (m[i]); free (m); return R_TRUE; }
R_API int r_core_visual_cmd(RCore *core, int ch) { RAsmOp op; char buf[4096]; int i, ret, offscreen, cols = core->print->cols; ch = r_cons_arrow_to_hjkl (ch); ch = visual_nkey (core, ch); if (ch<2) return 1; // do we need hotkeys for data references? not only calls? if (ch>='0'&& ch<='9') { r_io_sundo_push (core->io, core->offset); r_core_seek (core, core->asmqjmps[ch-'0'], 1); r_core_block_read (core, 1); } else switch (ch) { case 9: // tab { // XXX: unify diff mode detection ut64 f = r_config_get_i (core->config, "diff.from"); ut64 t = r_config_get_i (core->config, "diff.to"); if (f == t && f == 0) { core->print->col = core->print->col==1? 2: 1; } else { ut64 delta = core->offset - f; r_core_seek (core, t+delta, 1); r_config_set_i (core->config, "diff.from", t); r_config_set_i (core->config, "diff.to", f); } } break; case 'c': // XXX dupped flag imho setcursor (core, curset ^ 1); break; case 'd': r_core_visual_define (core); break; case 'D': setdiff (core); break; case 'C': color ^= 1; if (color) flags |= R_PRINT_FLAGS_COLOR; else flags &= ~(flags&R_PRINT_FLAGS_COLOR); r_config_set_i (core->config, "scr.color", color); r_print_set_flags (core->print, flags); break; case 'f': { int range; char name[256], *n; r_line_set_prompt ("flag name: "); if (r_cons_fgets (name, sizeof (name), 0, NULL) >=0 && *name) { n = r_str_chop (name); if (*name=='-') { if (*n) r_flag_unset (core->flags, n+1, NULL); } else { range = curset? (R_ABS (cursor-ocursor)+1): 1; if (range<1) range = 1; if (*n) r_flag_set (core->flags, n, core->offset + cursor, range, 1); } } } break; case 'F': r_flag_unset_i (core->flags, core->offset + cursor, NULL); break; case 'n': r_core_seek_next (core, r_config_get (core->config, "scr.nkey")); break; case 'N': r_core_seek_previous (core, r_config_get (core->config, "scr.nkey")); break; case 'A': { int oc = curset; ut64 off = curset? core->offset+cursor : core->offset; curset = 0; r_core_visual_asm (core, off); curset = oc; } break; case 'a': if (core->file && !(core->file->rwx & 2)) { r_cons_printf ("\nFile has been opened in read-only mode. Use -w flag\n"); r_cons_any_key (); return R_TRUE; } r_cons_printf ("Enter assembler opcodes separated with ';':\n"); r_cons_show_cursor (R_TRUE); r_cons_flush (); r_cons_set_raw (R_FALSE); strcpy (buf, "wa "); r_line_set_prompt (":> "); if (r_cons_fgets (buf+3, 1000, 0, NULL) <0) buf[0]='\0'; if (*buf) { if (curset) r_core_seek (core, core->offset + cursor, 0); r_core_cmd (core, buf, R_TRUE); if (curset) r_core_seek (core, core->offset - cursor, 1); } r_cons_show_cursor (R_FALSE); r_cons_set_raw (R_TRUE); break; case 'i': case 'I': if (core->file && !(core->file->rwx & 2)) { r_cons_printf ("\nFile has been opened in read-only mode. Use -w flag\n"); r_cons_any_key (); return R_TRUE; } r_cons_show_cursor (R_TRUE); r_cons_flush (); r_cons_set_raw (0); if (ch=='I') { strcpy (buf, "wow "); r_line_set_prompt ("insert hexpair block: "); if (r_cons_fgets (buf+4, sizeof (buf)-3, 0, NULL) <0) buf[0]='\0'; char *p = strdup (buf); int cur = core->print->cur; if (cur>=core->blocksize) cur = core->print->cur-1; snprintf (buf, sizeof (buf), "%s @ $$0!%i", p, core->blocksize-cursor); r_core_cmd (core, buf, 0); free (p); break; } if (core->print->col==2) { strcpy (buf, "w "); r_line_set_prompt ("insert string: "); if (r_cons_fgets (buf+2, sizeof (buf)-3, 0, NULL) <0) buf[0]='\0'; } else { strcpy (buf, "wx "); r_line_set_prompt ("insert hex: "); if (r_cons_fgets (buf+3, sizeof (buf)-4, 0, NULL) <0) buf[0]='\0'; } if (curset) r_core_seek (core, core->offset + cursor, 0); r_core_cmd (core, buf, 1); if (curset) r_core_seek (core, core->offset - cursor, 1); r_cons_set_raw (1); r_cons_show_cursor (R_FALSE); break; case 'e': r_core_visual_config (core); break; case 'M': r_core_visual_mounts (core); break; case 't': r_core_visual_trackflags (core); break; case 'x': { int count = 0; RList *xrefs = NULL; RAnalRef *refi; RListIter *iter; RAnalFunction *fun; if ((xrefs = r_anal_xref_get (core->anal, core->offset))) { r_cons_printf ("XREFS:\n"); if (r_list_empty (xrefs)) { r_cons_printf ("\tNo XREF found at 0x%"PFMT64x"\n", core->offset); r_cons_any_key (); r_cons_clear00 (); } else { r_list_foreach (xrefs, iter, refi) { fun = r_anal_fcn_find (core->anal, refi->addr, R_ANAL_FCN_TYPE_NULL); r_cons_printf ("\t[%i] %s XREF 0x%08"PFMT64x" (%s)\n", count, refi->type==R_ANAL_REF_TYPE_CODE?"CODE (JMP)": refi->type==R_ANAL_REF_TYPE_CALL?"CODE (CALL)":"DATA", refi->addr, fun?fun->name:"unk"); if (++count > 9) break; } } } else xrefs = NULL;
R_API int r_core_visual_cmd(RCore *core, int ch) { RAsmOp op; ut64 offset = core->offset; char buf[4096]; int i, ret, offscreen, cols = core->print->cols, delta = 0; ch = r_cons_arrow_to_hjkl (ch); ch = visual_nkey (core, ch); if (ch<2) return 1; // do we need hotkeys for data references? not only calls? if (ch>='0'&& ch<='9') { ut64 off = core->asmqjmps[ch-'0']; if (off != UT64_MAX) { int delta = R_ABS ((st64)off-(st64)offset); r_io_sundo_push (core->io, offset); if (curset && delta<100) { cursor = delta; } else { r_core_visual_seek_animation (core, off); //r_core_seek (core, off, 1); } r_core_block_read (core, 1); } } else switch (ch) { case 0x0d: { r_cons_enable_mouse (R_TRUE); RAnalOp *op = r_core_anal_op (core, core->offset+cursor); if (op) { if (op->type == R_ANAL_OP_TYPE_JMP || op->type == R_ANAL_OP_TYPE_CJMP || op->type == R_ANAL_OP_TYPE_CALL) { r_io_sundo_push (core->io, offset); r_core_visual_seek_animation(core, op->jump); } } r_anal_op_free (op); } break; case 90: // shift+tab if (!strcmp (printfmt[0], "x")) printfmt[0] = "pxa"; else printfmt[0] = "x"; break; case 9: // tab { // XXX: unify diff mode detection ut64 f = r_config_get_i (core->config, "diff.from"); ut64 t = r_config_get_i (core->config, "diff.to"); if (f == t && f == 0) { core->print->col = core->print->col==1? 2: 1; } else { ut64 delta = offset - f; r_core_seek (core, t+delta, 1); r_config_set_i (core->config, "diff.from", t); r_config_set_i (core->config, "diff.to", f); } } break; case 'a': if (core->file && !(core->file->rwx & 2)) { r_cons_printf ("\nFile has been opened in read-only mode. Use -w flag\n"); r_cons_any_key (); return R_TRUE; } r_cons_printf ("Enter assembler opcodes separated with ';':\n"); showcursor (core, R_TRUE); r_cons_flush (); r_cons_set_raw (R_FALSE); strcpy (buf, "wa "); r_line_set_prompt (":> "); if (r_cons_fgets (buf+3, 1000, 0, NULL) <0) buf[0]='\0'; if (*buf) { if (curset) r_core_seek (core, core->offset + cursor, 0); r_core_cmd (core, buf, R_TRUE); if (curset) r_core_seek (core, core->offset - cursor, 1); } showcursor (core, R_FALSE); r_cons_set_raw (R_TRUE); break; case '!': r_cons_2048(); break; case 'o': visual_offset (core); break; case 'A': { int oc = curset; ut64 off = curset? core->offset+cursor : core->offset; curset = 0; r_core_visual_asm (core, off); curset = oc; } break; case 'c': setcursor (core, curset?0:1); break; case 'C': color = color? 0: 1; r_config_set_i (core->config, "scr.color", color); break; case 'd': r_core_visual_define (core); break; case 'D': setdiff (core); break; case 'f': { int range, min, max; char name[256], *n; r_line_set_prompt ("flag name: "); showcursor (core, R_TRUE); if (r_cons_fgets (name, sizeof (name), 0, NULL) >=0 && *name) { n = r_str_chop (name); if (*name=='-') { if (*n) r_flag_unset (core->flags, n+1, NULL); } else { if (ocursor != -1) { min = R_MIN (cursor, ocursor); max = R_MAX (cursor, ocursor); } else { min = max = cursor; } range = max-min+1; if (range<1) range = 1; if (*n) r_flag_set (core->flags, n, core->offset + min, range, 1); } } } showcursor (core, R_FALSE); break; case 'F': r_flag_unset_i (core->flags, core->offset + cursor, NULL); break; case 'n': r_core_seek_next (core, r_config_get (core->config, "scr.nkey")); break; case 'N': r_core_seek_previous (core, r_config_get (core->config, "scr.nkey")); break; case 'i': case 'I': if (core->file && !(core->file->rwx & 2)) { r_cons_printf ("\nFile has been opened in read-only mode. Use -w flag\n"); r_cons_any_key (); return R_TRUE; } showcursor (core, R_TRUE); r_cons_flush (); r_cons_set_raw (0); if (ch=='I') { strcpy (buf, "wow "); r_line_set_prompt ("insert hexpair block: "); if (r_cons_fgets (buf+4, sizeof (buf)-5, 0, NULL) <0) buf[0]='\0'; char *p = strdup (buf); int cur = core->print->cur; if (cur>=core->blocksize) cur = core->print->cur-1; snprintf (buf, sizeof (buf), "%s @ $$0!%i", p, core->blocksize-cursor); r_core_cmd (core, buf, 0); free (p); break; } delta = (ocursor!=-1)? R_MIN (cursor, ocursor): cursor; if (core->print->col==2) { strcpy (buf, "\"w "); r_line_set_prompt ("insert string: "); if (r_cons_fgets (buf+3, sizeof (buf)-4, 0, NULL) <0) buf[0]='\0'; strcat (buf, "\""); } else { r_line_set_prompt ("insert hex: "); if (ocursor != -1) { int bs = R_ABS (cursor-ocursor)+1; core->blocksize = bs; strcpy (buf, "wow "); } else { strcpy (buf, "wx "); } if (r_cons_fgets (buf+strlen (buf), sizeof (buf)-strlen (buf), 0, NULL) <0) buf[0]='\0'; } if (curset) r_core_seek (core, core->offset + delta, 0); r_core_cmd (core, buf, 1); if (curset) r_core_seek (core, offset, 1); r_cons_set_raw (1); showcursor (core, R_FALSE); break; case 'R': r_core_cmd0 (core, "ecr"); break; case 'e': r_core_visual_config (core); break; case 'E': r_core_visual_colors (core); break; case 'M': r_core_visual_mounts (core); break; case 't': r_core_visual_trackflags (core); break; case 'x': { int count = 0; RList *xrefs = NULL; RAnalRef *refi; RListIter *iter; RAnalFunction *fun; if ((xrefs = r_anal_xref_get (core->anal, core->offset))) { r_cons_gotoxy (1, 1); r_cons_printf ("[GOTO XREF]> \n"); if (r_list_empty (xrefs)) { r_cons_printf ("\tNo XREF found at 0x%"PFMT64x"\n", core->offset); r_cons_any_key (); r_cons_clear00 (); } else { r_list_foreach (xrefs, iter, refi) { fun = r_anal_fcn_find (core->anal, refi->addr, R_ANAL_FCN_TYPE_NULL); r_cons_printf (" [%i] 0x%08"PFMT64x" %s XREF 0x%08"PFMT64x" (%s) \n", count, refi->at, refi->type==R_ANAL_REF_TYPE_CODE?"CODE (JMP)": refi->type==R_ANAL_REF_TYPE_CALL?"CODE (CALL)":"DATA", refi->addr, fun?fun->name:"unk"); if (++count > 9) break; } } } else xrefs = NULL;
R_API void r_cons_canvas_line (RConsCanvas *c, int x, int y, int x2, int y2, int style) { int i, onscreen; switch (style) { // vertical arrow line case 0: // if (G (x, y)) W ("v"); if (G (x2, y2)) W ("V"); if (x==x2) { int min = R_MIN (y,y2)+1; int max = R_MAX (y,y2); for (i=min; i<max; i++) { if (G (x,i)) W ("|"); } } else { // -- // TODO: find if there's any collision in this line int hl = R_ABS (y-y2) / 2; int hl2 = R_ABS (y-y2)-hl; hl--; if (y2 > (y+1)) { for (i=0; i<hl; i++) { if (G (x,y+i+1)) W ("|"); } for (i=0; i<hl2; i++) { if (G (x2, y+hl+i+1)) W ("|"); } int w = R_ABS (x-x2); char *row = malloc (w+2); if (x>x2) { w++; row[0] = '.'; if (w>2) memset (row+1, '-', w-2); row[w-1] = '\''; row[w] = 0; onscreen = G (x2+w,y+hl+1); i = G (x2, y+hl+1); if (!onscreen) onscreen = i; } else { row[0] = '`'; if (w>1) memset (row+1, '-', w-1); row[w] = '.'; row[w+1] = 0; onscreen = G (x+w,y+1+hl); i = G (x,y+1+hl); if (!onscreen) onscreen = i; } if (onscreen) W (row); free (row); } else { int minx = R_MIN (x, x2); //if (y >= y2) { int rl = R_ABS (x-x2)/2; int rl2 = R_ABS (x-x2)-rl+1; int vl = (R_ABS(y-y2))+1; if (y+1==y2) vl--; for (i=0; i<vl; i++) { if (G (minx+rl,y2+i)) W ("|"); } int w = rl; char *row = malloc (w+1); if (x>x2) { row[0] = '.'; if (w>2) memset (row+1, '-', w-2); if (w>0) row[w-1] = '.'; row[w] = 0; onscreen = G (x2,y2-1); } else { row[0] = '`'; if (w>2) memset (row+1, '-', w-2); if (w>0) row[w-1] = '\''; row[w] = 0; onscreen = G (x+1,y+1); } if (onscreen) W (row); w = rl2; free (row); row = malloc (rl2+1); if (x>x2) { row[0] = '`'; memset (row+1, '-', w-2); row[w-1] = '\''; row[w] = 0; onscreen = G (x2+rl, y+1); } else { row[0] = '.'; memset (row+1, '-', w-2); row[w-1] = '.'; row[w] = 0; onscreen = G (x+rl, y2-1); } if (onscreen) W (row); free (row); } } break; } }
R_API int r_diff_buffers_static(RDiff *d, const ut8 *a, int la, const ut8 *b, int lb) { int i, len; int hit = 0; la = R_ABS(la); lb = R_ABS(lb); if (la != lb) { len = R_MIN(la, lb); fprintf(stderr, "Buffer truncated to %d bytes (%d not compared)\n", len, R_ABS(lb-la)); } else len = la; for(i = 0; i<len; i++) { if (a[i]!=b[i]) { hit++; } else { if (hit>0) { struct r_diff_op_t o = { .a_off = d->off_a+i-hit, .a_buf = a+i-hit, .a_len = hit, .b_off = d->off_b+i-hit, .b_buf = b+i-hit, .b_len = hit }; d->callback (d, d->user, &o); hit = 0; } } } if (hit>0) { struct r_diff_op_t o = { .a_off = d->off_a+i-hit, .a_buf = a+i-hit, .a_len = hit, .b_off = d->off_b+i-hit, .b_buf = b+i-hit, .b_len = hit }; d->callback (d, d->user, &o); hit = 0; } return 0; } // XXX: temporary files are R_API int r_diff_buffers_radiff(RDiff *d, const ut8 *a, int la, const ut8 *b, int lb) { char *ptr, *str, buf[64], oop = 0; int ret, atl, btl, hit; ut8 at[128], bt[128]; ut64 ooa, oob; FILE *fd; hit = atl = btl = 0; ooa = oob = 0LL; oop = -1; r_file_dump (".a", a, la, 0); r_file_dump (".b", b, lb, 0); r_sys_cmd ("radiff -d .a .b | rsc uncolor > .d"); fd = fopen (".d", "r"); if (!fd) return 0; while (!feof (fd)) { ut64 oa, ob; // offset int ba, bb = 0; // byte char op; // operation oa = ob = 0LL; if (!fgets (buf, 63, fd)) break; if (feof (fd)) break; str = buf; ptr = strchr (buf, ' '); if (!ptr) continue; *ptr='\0'; sscanf (str, "0x%08"PFMT64x"", &oa); str = r_str_ichr (ptr+1, ' '); if (*str!='|'&&*str!='>'&&*str!='<') { ptr = strchr (str, ' '); if (!ptr) continue; *ptr='\0'; sscanf (str, "%02x", &ba); } else ba = 0; str = r_str_ichr (ptr+1, ' '); ptr = strchr (str, ' '); if (!ptr) continue; *ptr='\0'; sscanf (str, "%c", &op); str = r_str_ichr (ptr+1, ' '); if (str[0]!='0' || str[1]!='x') { ptr = strchr(str, ' '); if (!ptr) continue; *ptr = '\0'; sscanf (str, "%02x", &bb); } str = ptr+1; ptr = strchr (str, '\n'); if (!ptr) continue; *ptr='\0'; sscanf (str, "0x%08"PFMT64x"", &ob); if (oop == op || oop==-1) { if (hit == 0) { ooa = oa; oob = ob; } at[atl] = ba; bt[btl] = bb; switch (op) { case '|': atl++; btl++; break; case '>': btl++; break; case '<': atl++; break; } hit++; } else { if (hit>0) { struct r_diff_op_t o = { .a_off = ooa, .a_buf = at, .a_len = atl, .b_off = oob, .b_buf = bt, .b_len = btl }; ret = d->callback(d, d->user, &o); if (!ret) break; atl = btl = 0; hit = 0; } } oop = op; } if (hit > 0) { struct r_diff_op_t o = { .a_off = ooa, .a_buf = at, .a_len = atl, .b_off = oob, .b_buf = bt, .b_len = btl }; if (!d->callback (d, d->user, &o)) { fclose (fd); return 0; } atl = btl = 0; hit = 0; } fclose (fd); unlink (".a"); unlink (".b"); unlink (".d"); return 0; } R_API int r_diff_buffers(RDiff *d, const ut8 *a, ut32 la, const ut8 *b, ut32 lb) { if (d->delta) { return r_diff_buffers_delta (d, a, la, b, lb); } return r_diff_buffers_static (d, a, la, b, lb); } /* TODO: Move into r_util maybe? */ R_API bool r_diff_buffers_distance(RDiff *d, const ut8 *a, ut32 la, const ut8 *b, ut32 lb, ut32 *distance, double *similarity) { const bool verbose = d? d->verbose: false; /* More memory efficient version on Levenshtein Distance from: https://en.wikipedia.org/wiki/Levenshtein_distance http://www.codeproject.com/Articles/13525/Fast-memory-efficient-Levenshtein-algorithm ObM.. */ int i, j; /* TODO: ensure those pointers are allocated */ int *v0 = (int*) calloc ((lb + 1), sizeof (int)); int *v1 = (int*) calloc ((lb + 1), sizeof (int)); if (!a || !b || la < 1 || lb < 1) { free (v0); free (v1); return false; } if (la == lb && !memcmp (a, b, la)) { if (distance) { *distance = 0; } if (similarity) { *similarity = 1.0; } free (v0); free (v1); return true; } for (i = 0; i < lb + 1 ; i++) { v0[i] = i; } for (i = 0; i < la; i++) { v1[0] = i + 1; for (j = 0; j < lb; j++) { int cost = (a[i] == b[j]) ? 0 : 1; int smallest = R_MIN ((v1[j] + 1), (v0[j + 1] + 1)); smallest = R_MIN (smallest, (v0[j] + cost)); v1[j + 1] = smallest; } for (j = 0; j < lb + 1; j++) { v0[j] = v1[j]; } if (verbose && (i % 10000 == 0)) eprintf ("Processing %d of %d\r", i, la - 1); } if (verbose) { eprintf ("\rProcessing %d of %d\n", i, la - 1); } if (distance) { *distance = v1[lb]; if (similarity) { double diff = (double) (*distance) / (double) (R_MAX (la, lb)); *similarity = (double)1 - diff; } } free (v0); free (v1); return true; }