int emu_step (emu *e, ut8 *buf) { int ret; ut64 addr = r_reg_getv (e->reg, r_reg_get_name (e->reg, R_REG_NAME_PC)); //Check Breakboints here: new return stat for that if (e->plugin->read) { if (e->plugin->min_read_sz) e->plugin->read (e, addr, buf, e->plugin->min_read_sz); else e->plugin->read (e, addr, buf, sizeof(int)); } else { if (e->plugin->min_read_sz) emu_read (e, addr, buf, e->plugin->min_read_sz); else emu_read (e, addr, buf, sizeof(int)); } if (e->plugin->deps & EMU_PLUGIN_DEP_ASM) { //only disassemble if it is necessary r_asm_set_pc (e->a, addr); if (e->plugin->min_read_sz) r_asm_disassemble (e->a, e->op, buf, e->plugin->min_read_sz); else r_asm_disassemble (e->a, e->op, buf, sizeof(int)); } if (e->plugin->deps & EMU_PLUGIN_DEP_ANAL) { //only analize if it is necessary if (e->plugin->min_read_sz) r_anal_op (e->anal, e->anop, addr, buf, e->plugin->min_read_sz); else r_anal_op (e->anal, e->anop, addr, buf, sizeof(int)); } ret = e->plugin->step (e, buf); if (e->plugin->deps & EMU_PLUGIN_DEP_ANAL) r_anal_op_fini (e->anop); return ret; }
static int iscallret(RDebug *dbg, ut64 addr) { ut8 buf[32]; if (addr == 0LL || addr == UT64_MAX) return 0; /* check if region is executable */ /* check if previous instruction is a call */ /* if x86 expect CALL to be 5 byte length */ if (dbg->arch && !strcmp (dbg->arch, "x86")) { (void)dbg->iob.read_at (dbg->iob.io, addr-5, buf, 5); if (buf[0] == 0xe8) { return 1; } if (buf[3] == 0xff /* bits 4-5 (from right) of next byte must be 01 */ && ((buf[4] & 0xf0) == 0xd0 /* Mod is 11 */ || ((buf[4] & 0xf0) == 0x10 /* Mod is 00 */ && (buf[4] & 0x06) != 0x04))) { /* R/M not 10x */ return 1; } // IMMAMISSINGANYOP } else { RAnalOp op; (void) dbg->iob.read_at (dbg->iob.io, addr-8, buf, 8); (void) r_anal_op (dbg->anal, &op, addr-8, buf, 8, R_ANAL_OP_MASK_BASIC); if (op.type == R_ANAL_OP_TYPE_CALL || op.type == R_ANAL_OP_TYPE_UCALL) { return 1; } /* delay slot */ (void) r_anal_op (dbg->anal, &op, addr-4, buf, 4, R_ANAL_OP_MASK_BASIC); if (op.type == R_ANAL_OP_TYPE_CALL || op.type == R_ANAL_OP_TYPE_UCALL) { return 1; } } return 0; }
/* optimization: avoid so many reads */ R_API int r_debug_continue_until_optype(RDebug *dbg, int type, int over) { int (*step)(RDebug *d, int n); int ret, n = 0; ut64 pc = 0; RAnalOp op; ut8 buf[64]; if (r_debug_is_dead (dbg)) return R_FALSE; if (dbg->anal && dbg->reg) { const char *pcreg = dbg->reg->name[R_REG_NAME_PC]; step = over? r_debug_step_over: r_debug_step; for (;;) { pc = r_debug_reg_get (dbg, pcreg); dbg->iob.read_at (dbg->iob.io, pc, buf, sizeof (buf)); ret = r_anal_op (dbg->anal, &op, pc, buf, sizeof (buf)); if (ret>0 && op.type&type) break; if (!step (dbg, 1)) { eprintf ("r_debug_step: failed\n"); break; } n++; } } else eprintf ("Undefined pointer at dbg->anal\n"); return n; }
static int analyze(RAnal *anal, RAnalOp *op, ut64 offset, ut8* buf, int len) { char *bytes, *optype = NULL, *stackop = NULL; int ret; ret = r_anal_op (anal, op, offset, buf, len); if (ret) { stackop = stackop2str (op->stackop); optype = optype2str (op->type); bytes = r_hex_bin2strdup (buf, ret); printf ("bytes: %s\n", bytes); printf ("type: %s\n", optype); if (op->jump != -1LL) printf ("jump: 0x%08"PFMT64x"\n", op->jump); if (op->fail != -1LL) printf ("fail: 0x%08"PFMT64x"\n", op->fail); //if (op->ref != -1LL) // printf ("ref: 0x%08"PFMT64x"\n", op->ref); if (op->val != -1LL) printf ("value: 0x%08"PFMT64x"\n", op->val); printf ("stackop: %s\n", stackop); printf ("esil: %s\n", r_strbuf_get (&op->esil)); printf ("stackptr: %"PFMT64d"\n", op->stackptr); printf ("decode str: %s\n", r_anal_op_to_string (anal, op)); printf ("--\n"); free (optype); free (stackop); free (bytes); } return ret; }
R_API int r_core_hack(RCore *core, const char *op) { bool (*hack)(RCore *core, const char *op, const RAnalOp *analop) = NULL; const char *asmarch = r_config_get (core->config, "asm.arch"); const int asmbits = core->assembler->bits; if (!asmarch) { return false; } if (strstr (asmarch, "x86")) { hack = r_core_hack_x86; } else if (strstr (asmarch, "arm")) { if (asmbits == 64) { hack = r_core_hack_arm64; } else { hack = r_core_hack_arm; } } else { eprintf ("TODO: write hacks are only for x86\n"); } if (hack) { RAnalOp analop; if (!r_anal_op (core->anal, &analop, core->offset, core->block, core->blocksize, R_ANAL_OP_MASK_ALL)) { eprintf ("anal op fail\n"); return false; } return hack (core, op, &analop); } return false; }
R_API struct r_anal_refline_t *r_anal_reflines_get(struct r_anal_t *anal, ut64 addr, ut8 *buf, ut64 len, int nlines, int linesout, int linescall) { RAnalRefline *list2, *list = R_NEW (RAnalRefline); RAnalOp op = {0}; ut8 *ptr = buf; ut8 *end = buf + len; ut64 opc = addr; int sz = 0, index = 0; INIT_LIST_HEAD (&(list->list)); end -= 8; // XXX Fix some segfaults when r_anal backends are buggy /* analyze code block */ while (ptr<end) { if (nlines != -1 && --nlines == 0) break; #if 0 if (config.interrupted) break; int dt = data_type(config.seek+bsz); if (dt != DATA_FUN && dt != DATA_CODE) { ut64 sz = data_size (config.seek+bsz); if (sz > 0) { ptr += sz; bsz += sz; continue; } } #endif addr += sz; // This can segflauta if opcode length and buffer check fails r_anal_op_fini (&op); sz = r_anal_op (anal, &op, addr, ptr, (int)(end-ptr)); if (sz > 0) { /* store data */ switch (op.type) { case R_ANAL_OP_TYPE_CALL: if (!linescall) break; case R_ANAL_OP_TYPE_CJMP: case R_ANAL_OP_TYPE_JMP: if (!linesout && (op.jump > opc+len || op.jump < opc)) goto __next; if (op.jump == 0LL) goto __next; list2 = R_NEW (RAnalRefline); list2->from = addr; list2->to = op.jump; list2->index = index++; list_add_tail (&(list2->list), &(list->list)); break; } } else sz = 1; __next: ptr += sz; } r_anal_op_fini (&op); return list; }
// XXX: very experimental R_API int r_debug_step_soft(RDebug *dbg) { int ret; ut8 buf[32]; RAnalOp op; ut64 pc0, pc1, pc2; if (r_debug_is_dead (dbg)) return R_FALSE; pc0 = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]); dbg->iob.read_at (dbg->iob.io, pc0, buf, sizeof (buf)); ret = r_anal_op (dbg->anal, &op, pc0, buf, sizeof (buf)); //eprintf ("read from pc0 = 0x%llx\n", pc0); pc1 = pc0 + op.length; //eprintf ("oplen = %d\n", op.length); //eprintf ("breakpoint at pc1 = 0x%llx\n", pc1); // XXX: Does not works for 'ret' pc2 = op.jump? op.jump: 0; //eprintf ("ADD SECOND BREAKPOINT FRO CALLS %llx\n", op.jump); //eprintf ("breakpoint 2 at pc2 = 0x%llx\n", pc2); r_bp_add_sw (dbg->bp, pc1, 4, R_BP_PROT_EXEC); if (pc2) r_bp_add_sw (dbg->bp, pc2, 4, R_BP_PROT_EXEC); r_debug_continue (dbg); //eprintf ("wait\n"); //r_debug_wait (dbg); //eprintf ("del\n"); r_bp_del (dbg->bp, pc1); if (pc2) r_bp_del (dbg->bp, pc2); return ret; }
R_API int r_debug_step_over(RDebug *dbg, int steps) { RAnalOp op; ut8 buf[64]; int ret = -1; if (r_debug_is_dead (dbg)) return R_FALSE; if (dbg->h && dbg->h->step_over) { if (steps<1) steps = 1; while (steps--) if (!dbg->h->step_over (dbg)) return R_FALSE; return R_TRUE; } if (dbg->anal && dbg->reg) { ut64 pc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]); dbg->iob.read_at (dbg->iob.io, pc, buf, sizeof (buf)); r_anal_op (dbg->anal, &op, pc, buf, sizeof (buf)); if (op.type & R_ANAL_OP_TYPE_CALL || op.type & R_ANAL_OP_TYPE_UCALL) { ut64 bpaddr = pc + op.length; r_bp_add_sw (dbg->bp, bpaddr, 1, R_BP_PROT_EXEC); ret = r_debug_continue (dbg); r_bp_del (dbg->bp, bpaddr); } else { ret = r_debug_step (dbg, 1); } } else eprintf ("Undefined debugger backend\n"); return ret; }
R_API int r_debug_esil_stepi (RDebug *d) { RAnalOp op; ut8 obuf[64]; int ret = 1; dbg = d; if (!ESIL) { ESIL = r_anal_esil_new (R_TRUE); // TODO setup something? } r_debug_reg_sync (dbg, R_REG_TYPE_GPR, R_FALSE); opc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]); dbg->iob.read_at (dbg->iob.io, opc, obuf, sizeof (obuf)); //dbg->iob.read_at (dbg->iob.io, npc, buf, sizeof (buf)); //dbg->anal->reg = dbg->reg; // hack ESIL->cb.hook_mem_read = &esilbreak_mem_read; ESIL->cb.hook_mem_write = &esilbreak_mem_write; ESIL->cb.hook_reg_read = &esilbreak_reg_read; ESIL->cb.hook_reg_write = &esilbreak_reg_write; if (prestep) { // required when a exxpression is like <= == .. // otherwise it will stop at the next instruction if (r_debug_step (dbg, 1)<1) { eprintf ("Step failed\n"); return 0; } r_debug_reg_sync (dbg, R_REG_TYPE_GPR, R_FALSE); // npc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]); } if (r_anal_op (dbg->anal, &op, opc, obuf, sizeof (obuf))) { if (esilbreak_check_pc (dbg, opc)) { eprintf ("STOP AT 0x%08"PFMT64x"\n", opc); ret = 0; } else { r_anal_esil_set_pc (ESIL, opc); eprintf ("0x%08"PFMT64x" %s\n", opc, R_STRBUF_SAFEGET (&op.esil)); (void)r_anal_esil_parse (ESIL, R_STRBUF_SAFEGET (&op.esil)); //r_anal_esil_dumpstack (ESIL); r_anal_esil_stack_free (ESIL); ret = 1; } } if (!prestep) { if (ret && !has_match) { if (r_debug_step (dbg, 1)<1) { eprintf ("Step failed\n"); return 0; } r_debug_reg_sync (dbg, R_REG_TYPE_GPR, R_FALSE); // npc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]); } } return ret; }
R_API int r_debug_continue_until_optype(RDebug *dbg, int type, int over) { int ret, n = 0; ut64 pc, buf_pc = 0; RAnalOp op; ut8 buf[DBG_BUF_SIZE]; if (r_debug_is_dead (dbg)) { return R_FALSE; } if (!dbg->anal || !dbg->reg) { eprintf ("Undefined pointer at dbg->anal\n"); return R_FALSE; } r_debug_step (dbg, 1); r_debug_reg_sync (dbg, R_REG_TYPE_GPR, R_FALSE); // Initial refill buf_pc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]); dbg->iob.read_at (dbg->iob.io, buf_pc, buf, sizeof (buf)); // step first, we dont want to check current optype for (;;) { r_debug_reg_sync (dbg, R_REG_TYPE_GPR, R_FALSE); pc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]); // Try to keep the buffer full if (pc - buf_pc > sizeof (buf)) { buf_pc = pc; dbg->iob.read_at (dbg->iob.io, buf_pc, buf, sizeof (buf)); } // Analyze the opcode if (!r_anal_op (dbg->anal, &op, pc, buf + (pc - buf_pc), sizeof (buf) - (pc - buf_pc))) { eprintf ("Decode error at %"PFMT64x"\n", pc); return R_FALSE; } if (op.type == type) break; // Step over and repeat ret = over ? r_debug_step_over (dbg, 1) : r_debug_step (dbg, 1); if (!ret) { eprintf ("r_debug_step: failed\n"); break; } n++; } return n; }
static int prevopsz (RCore *core, ut64 addr) { ut64 target = addr; ut64 base = target-OPDELTA; int len, ret, i; ut8 buf[OPDELTA*2]; RAnalOp op; r_core_read_at (core, base, buf, sizeof (buf)); for (i=0; i<sizeof (buf); i++) { ret = r_anal_op (core->anal, &op, base+i, buf+i, sizeof (buf)-i); if (!ret) continue; len = op.size; r_anal_op_fini (&op); // XXX if (len<1) continue; i += len-1; if (target == base+i+1) return len; } return 4; }
static int __esil_step(RDebug *dbg) { int oplen; ut8 buf[64]; ut64 pc = 0LL; // getreg("pc") RAnalOp op; pc = r_debug_reg_get (dbg, "pc"); /// XXX. hack to trick vaddr issue //pc = 0x100001478; memset (buf, 0, sizeof (buf)); dbg->iob.read_at (dbg->iob.io, pc, buf, 64); eprintf ("READ 0x%08"PFMT64x" %02x %02x %02x\n", pc, buf[0], buf[1], buf[2]); oplen = r_anal_op (dbg->anal, &op, pc, buf, sizeof (buf)); if (oplen>0) { if (*R_STRBUF_SAFEGET (&op.esil)) { eprintf ("ESIL: %s\n", R_STRBUF_SAFEGET (&op.esil)); } } eprintf ("TODO: ESIL STEP\n"); return true; }
R_API int r_core_hack(RCore *core, const char *op) { int (*hack)(RCore *core, const char *op, const RAnalOp *analop) = NULL; const char *asmarch = r_config_get (core->config, "asm.arch"); RAnalOp analop; if (strstr (asmarch, "x86")) { hack = r_core_hack_x86; } else if (strstr (asmarch, "arm")) { hack = r_core_hack_arm; } else { eprintf ("TODO: write hacks are only for x86\n"); } if (hack) { if (!r_anal_op (core->anal, &analop, core->offset, core->block, core->blocksize)) { eprintf ("anal op fail\n"); return false; } return hack (core, op, &analop); } return false; }
static int prevopsz (RCore *core, ut64 addr) { const int delta = 32; ut64 target = addr; ut64 base = target-delta; int len, ret, i; ut8 buf[delta*2]; RAnalOp op; r_core_read_at (core, base, buf, sizeof (buf)); for (i=0; i<sizeof (buf); i++) { ret = r_anal_op (core->anal, &op, addr+i, buf+i, sizeof (buf)-i); if (!ret) continue; len = op.length; r_anal_op_fini (&op); if (len<1) continue; i += len-1; if (target == base+i+1) return len; } return 4; }
static ut64 num_callback(RNum *userptr, const char *str, int *ok) { RCore *core = (RCore *)userptr; // XXX ? RAnalFunction *fcn; char *ptr, *bptr, *out; RFlagItem *flag; RIOSection *s; RAnalOp op; ut64 ret = 0; if (ok) *ok = R_FALSE; switch (*str) { case '[': { ut64 n = 0LL; int refsz = (core->assembler->bits & R_SYS_BITS_64)? 8: 4; const char *p = NULL; if (strlen (str)>5) p = strchr (str+5, ':'); // TODO: honor LE if (p) { refsz = atoi (str+1); str = p; } // push state { if (str[0] && str[1]) { const char *q; char *o = strdup (str+1); if (o) { q = r_num_calc_index (core->num, NULL); if (q) { if (r_str_replace_char (o, ']', 0)>0) { n = r_num_math (core->num, o); r_num_calc_index (core->num, q); } } free (o); } } } // pop state if (ok) *ok = 1; ut32 num = 0; switch (refsz) { case 8: case 4: case 2: case 1: (void)r_io_read_at (core->io, n, (ut8*)&num, refsz); r_mem_copyendian ((ut8*)&num, (ut8*)&num, refsz, !core->assembler->big_endian); return num; default: eprintf ("Invalid reference size: %d (%s)\n", refsz, str); return 0LL; } } break; case '$': if (ok) *ok = 1; // TODO: group analop-dependant vars after a char, so i can filter r_anal_op (core->anal, &op, core->offset, core->block, core->blocksize); switch (str[1]) { case '.': // can use pc, sp, a0, a1, ... return r_debug_reg_get (core->dbg, str+2); case 'k': if (str[2]!='{') { eprintf ("Expected '{' after 'k'.\n"); break; } bptr = strdup (str+3); ptr = strchr (bptr, '}'); if (ptr == NULL) { // invalid json free (bptr); break; } *ptr = '\0'; ret = 0LL; out = sdb_querys (core->sdb, NULL, 0, bptr); if (out && *out) { if (strstr (out, "$k{")) { eprintf ("Recursivity is not permitted here\n"); } else { ret = r_num_math (core->num, out); } } free (bptr); free (out); return ret; break; case '{': bptr = strdup (str+2); ptr = strchr (bptr, '}'); if (ptr != NULL) { ut64 ret; ptr[0] = '\0'; ret = r_config_get_i (core->config, bptr); free (bptr); return ret; } free (bptr); break; case 'c': return r_cons_get_size (NULL); case 'r': { int rows; r_cons_get_size (&rows); return rows; } case 'e': return r_anal_op_is_eob (&op); case 'j': return op.jump; case 'p': return r_sys_getpid (); case 'P': return (core->dbg->pid>0)? core->dbg->pid: 0; case 'f': return op.fail; case 'm': return op.ptr; // memref case 'v': return op.val; // immediate value case 'l': return op.size; case 'b': return core->blocksize; case 's': if (core->file) { return r_io_desc_size (core->io, core->file->desc); } return 0LL; case 'w': return r_config_get_i (core->config, "asm.bits") / 8; case 'S': s = r_io_section_vget (core->io, core->offset); return s? (str[2]=='S'? s->size: s->vaddr): 3; case '?': return core->num->value; case '$': return core->offset; case 'o': return r_io_section_vaddr_to_offset (core->io, core->offset); case 'C': return getref (core, atoi (str+2), 'r', R_ANAL_REF_TYPE_CALL); case 'J': return getref (core, atoi (str+2), 'r', R_ANAL_REF_TYPE_CODE); case 'D': return getref (core, atoi (str+2), 'r', R_ANAL_REF_TYPE_DATA); case 'X': return getref (core, atoi (str+2), 'x', R_ANAL_REF_TYPE_CALL); case 'I': fcn = r_anal_get_fcn_in (core->anal, core->offset, 0); return fcn? fcn->ninstr: 0; case 'F': fcn = r_anal_get_fcn_in (core->anal, core->offset, 0); return fcn? fcn->size: 0; } break; default: if (*str>'A') { // NOTE: functions override flags RAnalFunction *fcn = r_anal_fcn_find_name (core->anal, str); if (fcn) { if (ok) *ok = R_TRUE; return fcn->addr; } #if 0 ut64 addr = r_anal_fcn_label_get (core->anal, core->offset, str); if (addr != 0) { ret = addr; } else { ... } #endif if ((flag = r_flag_get (core->flags, str))) { ret = flag->offset; if (ok) *ok = R_TRUE; } } break; }
static int cmd_seek(void *data, const char *input) { RCore *core = (RCore *)data; char *cmd, *p; ut64 off; if (*input=='r') { if (input[1] && input[2]) { if (core->io->debug) { off = r_debug_reg_get (core->dbg, input+2); r_io_sundo_push (core->io, core->offset); r_core_seek (core, off, 1); } else { RReg *orig = core->dbg->reg; core->dbg->reg = core->anal->reg; off = r_debug_reg_get (core->dbg, input+2); core->dbg->reg = orig; r_core_seek (core, off, 1); } } else eprintf ("|Usage| 'sr pc' seek to program counter register\n"); } else if (*input) { const char *inputnum = strchr (input+1, ' '); int sign = 1; inputnum = inputnum? inputnum+1: input+1; off = r_num_math (core->num, inputnum); if (*inputnum== '-') off = -off; #if 0 if (input[0]!='/' && inputnum && isalpha (inputnum[0]) && off == 0) { if (!r_flag_get (core->flags, inputnum)) { eprintf ("Cannot find address for '%s'\n", inputnum); return R_FALSE; } } #endif if (input[0]==' ') { switch (input[1]) { case '-': sign=-1; case '+': input++; break; } } switch (*input) { case 'C': if (input[1]=='*') { r_core_cmd0 (core, "C*~^\"CC"); } else if (input[1]==' ') { typedef struct { ut64 addr; char *str; } MetaCallback; int count = 0; MetaCallback cb = { 0, NULL }; ut64 addr; char key[128]; const char *val, *comma; char *list = sdb_get (core->anal->sdb_meta, "meta.C", 0); char *str, *next, *cur = list; if (list) { for (;;) { cur = sdb_anext (cur, &next); addr = sdb_atoi (cur); snprintf (key, sizeof (key)-1, "meta.C.0x%"PFMT64x, addr); val = sdb_const_get (core->anal->sdb_meta, key, 0); if (val) { comma = strchr (val, ','); if (comma) { str = (char *)sdb_decode (comma+1, 0); if (strstr (str, input+2)) { r_cons_printf ("0x%08"PFMT64x" %s\n", addr, str); count++; cb.addr = addr; free (cb.str); cb.str = str; } else free (str); } } else eprintf ("sdb_const_get key not found '%s'\n", key); if (!next) break; cur = next; } } switch (count) { case 0: eprintf ("No matching comments\n"); break; case 1: off = cb.addr; r_io_sundo_push (core->io, core->offset); r_core_seek (core, off, 1); r_core_block_read (core, 0); break; default: eprintf ("Too many results\n"); break; } free (cb.str); } else eprintf ("Usage: sC[?*] comment-grep\n" "sC* list all comments\n" "sC const seek to comment matching 'const'\n"); break; case ' ': r_io_sundo_push (core->io, core->offset); r_core_seek (core, off*sign, 1); r_core_block_read (core, 0); break; case '/': { const char *pfx = r_config_get (core->config, "search.prefix"); //kwidx cfg var is ignored int kwidx = core->search->n_kws; //(int)r_config_get_i (core->config, "search.kwidx")-1; if (kwidx<0) kwidx = 0; switch (input[1]) { case ' ': case 'x': r_config_set_i (core->config, "search.count", 1); r_core_cmdf (core, "s+1; p8 ; .%s;s-1;s %s%d_0;f-%s%d_0", input, pfx, kwidx, pfx, kwidx, pfx, kwidx); r_config_set_i (core->config, "search.count", 0); break; default: eprintf ("unknown search method\n"); break; } } break; case '.': for (input++;*input=='.';input++); r_core_seek_base (core, input); break; case '*': r_io_sundo_list (core->io); break; case '+': if (input[1]!='\0') { int delta = (input[1]=='+')? core->blocksize: off; r_io_sundo_push (core->io, core->offset); r_core_seek_delta (core, delta); } else { off = r_io_sundo_redo (core->io); if (off != UT64_MAX) r_core_seek (core, off, 0); } break; case '-': if (input[1]!='\0') { int delta = (input[1]=='-') ? -core->blocksize: -off; r_io_sundo_push (core->io, core->offset); r_core_seek_delta (core, delta); } else { off = r_io_sundo (core->io, core->offset); if (off != UT64_MAX) r_core_seek (core, off, 0); } break; case 'n': r_io_sundo_push (core->io, core->offset); r_core_seek_next (core, r_config_get (core->config, "scr.nkey")); break; case 'p': r_io_sundo_push (core->io, core->offset); r_core_seek_previous (core, r_config_get (core->config, "scr.nkey")); break; case 'a': off = core->blocksize; if (input[1]&&input[2]) { cmd = strdup (input); p = strchr (cmd+2, ' '); if (p) { off = r_num_math (core->num, p+1);; *p = '\0'; } cmd[0] = 's'; // perform real seek if provided r_cmd_call (core->rcmd, cmd); free (cmd); } r_io_sundo_push (core->io, core->offset); r_core_seek_align (core, off, 0); break; case 'b': if (off == 0) off = core->offset; r_io_sundo_push (core->io, core->offset); r_core_anal_bb_seek (core, off); break; case 'f': if (strlen(input) > 2 && input[1]==' ') { RAnalFunction *fcn = r_anal_fcn_find_name (core->anal, input+2); if (fcn) { r_core_seek (core, fcn->addr, 1); } break; } RAnalFunction *fcn = r_anal_fcn_find (core->anal, core->offset, 0); if (fcn) { r_core_seek (core, fcn->addr+fcn->size, 1); } break; case 'o': { RAnalOp op; int val=0, ret, i, n = r_num_math (core->num, input+1); if (n==0) n = 1; if (n<0) { int ret = prevopsz (core, n); ret = r_anal_op (core->anal, &op, core->offset, core->block, core->blocksize); val += ret; } else for (val=i=0; i<n; i++) { ret = r_anal_op (core->anal, &op, core->offset, core->block, core->blocksize); if (ret<1) break; r_core_seek_delta (core, ret); val += ret; } core->num->value = val; } break; case 'g': { RIOSection *s = r_io_section_vget (core->io, core->offset); if (s) r_core_seek (core, s->vaddr, 1); else r_core_seek (core, 0, 1); } break; case 'G': { RIOSection *s = r_io_section_vget (core->io, core->offset); // XXX: this +2 is a hack. must fix gap between sections if (s) r_core_seek (core, s->vaddr+s->size+2, 1); else r_core_seek (core, core->file->size, 1); } break; case '?': { const char * help_message[] = { "Usage: s", "", " # Seek commands", "s", "", "Print current address", "s", " addr", "Seek to address", "s-", "", "Undo seek", "s-", " n", "Seek n bytes backward", "s--", "", "Seek blocksize bytes backward", "s+", "", "Redo seek", "s+", " n", "Seek n bytes forward", "s++", "", "Seek blocksize bytes forward", "s*", "", "List undo seek history", "s/", " DATA", "Search for next occurrence of 'DATA'", "s/x", " 9091", "Search for next occurrence of \\x90\\x91", "s.", "hexoff", "Seek honoring a base from core->offset", "sa", " [[+-]a] [asz]", "Seek asz (or bsize) aligned to addr", "sb", "", "Seek aligned to bb start", "sC", " string", "Seek to comment matching given string", "sf", "", "Seek to next function (f->addr+f->size)", "sf", " function", "Seek to address of specified function", "sg/sG", "", "Seek begin (sg) or end (sG) of section or file", "sn/sp", "", "Seek next/prev scr.nkey", "so", " [N]", "Seek to N next opcode(s)", "sr", " pc", "Seek to register", //"sp [page] seek page N (page = block)", NULL }; r_core_cmd_help(core, help_message); } break; } } else r_cons_printf ("0x%"PFMT64x"\n", core->offset); return 0; }
R_API int r_debug_continue_kill(RDebug *dbg, int sig) { ut64 pc; int retwait, ret = R_FALSE; if (!dbg) return R_FALSE; #if __WINDOWS__ r_cons_break(w32_break_process, dbg); #endif repeat: if (r_debug_is_dead (dbg)) return R_FALSE; if (dbg->h && dbg->h->cont) { r_bp_restore (dbg->bp, R_TRUE); // set sw breakpoints ret = dbg->h->cont (dbg, dbg->pid, dbg->tid, sig); dbg->reason.signum = 0; retwait = r_debug_wait (dbg); #if __WINDOWS__ if (retwait != R_DEBUG_REASON_DEAD) { ret = dbg->tid; } #endif r_bp_restore (dbg->bp, R_FALSE); // unset sw breakpoints //r_debug_recoil (dbg); if (r_debug_recoil (dbg) || (dbg->reason.type == R_DEBUG_REASON_BREAKPOINT)) { /* check if cur bp demands tracing or not */ pc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]); RBreakpointItem *b = r_bp_get_at (dbg->bp, pc); if (b) { /* check if cur bp demands tracing or not */ if (b->trace) { eprintf("hit tracepoit at: %"PFMT64x"\n",pc); } else { eprintf("hit breakpoint at: %"PFMT64x"\n",pc); } if (dbg->trace->enabled) r_debug_trace_pc (dbg); // TODO: delegate this to RCore.bphit(RCore, RBreakopintItem) if (dbg->corebind.core && dbg->corebind.bphit) { dbg->corebind.bphit (dbg->corebind.core, b); } if (b->trace) { r_debug_step (dbg, 1); goto repeat; } } } #if 0 #if __UNIX__ /* XXX Uh? */ if (dbg->stop_all_threads && dbg->pid>0) r_sandbox_kill (dbg->pid, SIGSTOP); #endif #endif r_debug_select (dbg, dbg->pid, ret); sig = 0; // clear continuation after signal if needed if (retwait == R_DEBUG_REASON_SIGNAL && dbg->reason.signum != -1) { int what = r_debug_signal_what (dbg, dbg->reason.signum); if (what & R_DBG_SIGNAL_CONT) { sig = dbg->reason.signum; eprintf ("Continue into the signal %d handler\n", sig); goto repeat; } else if (what & R_DBG_SIGNAL_SKIP) { // skip signal. requires skipping one instruction ut8 buf[64]; RAnalOp op = {0}; ut64 pc = r_debug_reg_get (dbg, "pc"); dbg->iob.read_at (dbg->iob.io, pc, buf, sizeof (buf)); r_anal_op (dbg->anal, &op, pc, buf, sizeof (buf)); if (op.size>0) { const char *signame = r_debug_signal_resolve_i (dbg, dbg->reason.signum); r_debug_reg_set (dbg, "pc", pc+op.size); eprintf ("Skip signal %d handler %s\n", dbg->reason.signum, signame); goto repeat; } else { ut64 pc = r_debug_reg_get (dbg, "pc"); eprintf ("Stalled with an exception at 0x%08"PFMT64x"\n", pc); } } } } return ret; }
R_API int r_debug_step_over(RDebug *dbg, int steps) { RAnalOp op; ut64 buf_pc, pc; ut8 buf[DBG_BUF_SIZE]; int i; if (r_debug_is_dead (dbg)) return R_FALSE; if (steps < 1) steps = 1; if (dbg->h && dbg->h->step_over) { for (i = 0; i < steps; i++) if (!dbg->h->step_over (dbg)) return R_FALSE; return i; } if (!dbg->anal || !dbg->reg) return R_FALSE; // Initial refill buf_pc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]); dbg->iob.read_at (dbg->iob.io, buf_pc, buf, sizeof (buf)); for (i = 0; i < steps; i++) { pc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]); // Try to keep the buffer full if (pc - buf_pc > sizeof (buf)) { buf_pc = pc; dbg->iob.read_at (dbg->iob.io, buf_pc, buf, sizeof (buf)); } // Analyze the opcode if (!r_anal_op (dbg->anal, &op, pc, buf + (pc - buf_pc), sizeof (buf) - (pc - buf_pc))) { eprintf ("Decode error at %"PFMT64x"\n", pc); return R_FALSE; } // Skip over all the subroutine calls if (op.type == R_ANAL_OP_TYPE_CALL || op.type == R_ANAL_OP_TYPE_CCALL || op.type == R_ANAL_OP_TYPE_UCALL || op.type == R_ANAL_OP_TYPE_UCCALL) { // Use op.fail here instead of pc+op.size to enforce anal backends to fill in this field if (!r_debug_continue_until (dbg, op.fail)) { eprintf ("Could not step over call @ 0x%"PFMT64x"\n", pc); return R_FALSE; } } else if ((op.prefix & (R_ANAL_OP_PREFIX_REP | R_ANAL_OP_PREFIX_REPNE | R_ANAL_OP_PREFIX_LOCK))) { //eprintf ("REP: skip to next instruction...\n"); if (!r_debug_continue_until (dbg, pc+op.size)) { eprintf ("step over failed over rep\n"); return R_FALSE; } } else r_debug_step (dbg, 1); } return i; }
R_API int r_debug_step_soft(RDebug *dbg) { ut8 buf[32]; ut64 pc, sp; ut64 next[2]; RAnalOp op; int br, i, ret; union { ut64 r64; ut32 r32[2]; } sp_top; if (r_debug_is_dead (dbg)) return R_FALSE; pc = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_PC]); sp = r_debug_reg_get (dbg, dbg->reg->name[R_REG_NAME_SP]); if (dbg->iob.read_at) { if (dbg->iob.read_at (dbg->iob.io, pc, buf, sizeof (buf)) < 0) return R_FALSE; } else return R_FALSE; if (!r_anal_op (dbg->anal, &op, pc, buf, sizeof (buf))) return R_FALSE; if (op.type == R_ANAL_OP_TYPE_ILL) return R_FALSE; switch (op.type) { case R_ANAL_OP_TYPE_RET: dbg->iob.read_at (dbg->iob.io, sp, (ut8 *)&sp_top, 8); next[0] = (dbg->bits == R_SYS_BITS_32) ? sp_top.r32[0] : sp_top.r64; br = 1; break; case R_ANAL_OP_TYPE_CJMP: case R_ANAL_OP_TYPE_CCALL: next[0] = op.jump; next[1] = op.fail; br = 2; break; case R_ANAL_OP_TYPE_CALL: case R_ANAL_OP_TYPE_JMP: next[0] = op.jump; br = 1; break; default: next[0] = op.addr + op.size; br = 1; break; } for (i = 0; i < br; i++) r_bp_add_sw (dbg->bp, next[i], dbg->bpsize, R_BP_PROT_EXEC); ret = r_debug_continue (dbg); for (i = 0; i < br; i++) r_bp_del (dbg->bp, next[i]); return ret; }
R_API int r_anal_bb(RAnal *anal, RAnalBlock *bb, ut64 addr, ut8 *buf, ut64 len, int head) { RAnalOp *op = NULL; int oplen, idx = 0; if (bb->addr == -1) { bb->addr = addr; } len -= 16; // XXX: hack to avoid segfault by x86im while (idx < len) { // TODO: too slow object construction if (!(op = r_anal_op_new ())) { eprintf ("Error: new (op)\n"); return R_ANAL_RET_ERROR; } if ((oplen = r_anal_op (anal, op, addr + idx, buf + idx, len - idx)) == 0) { r_anal_op_free (op); op = NULL; if (idx == 0) { VERBOSE_ANAL eprintf ("Unknown opcode at 0x%08"PFMT64x"\n", addr+idx); return R_ANAL_RET_END; } break; } if (oplen < 1) { return R_ANAL_RET_END; } r_anal_bb_set_offset (bb, bb->ninstr, addr + idx - bb->addr); idx += oplen; bb->size += oplen; bb->ninstr++; #if R_ANAL_BB_HAS_OPS r_list_append (bb->ops, op); #endif if (head) { bb->type = R_ANAL_BB_TYPE_HEAD; } switch (op->type) { case R_ANAL_OP_TYPE_CMP: r_anal_cond_free (bb->cond); bb->cond = r_anal_cond_new_from_op (op); break; case R_ANAL_OP_TYPE_CJMP: if (bb->cond) { // TODO: get values from anal backend bb->cond->type = R_ANAL_COND_EQ; } else VERBOSE_ANAL eprintf ("Unknown conditional for block 0x%"PFMT64x"\n", bb->addr); bb->conditional = 1; bb->fail = op->fail; bb->jump = op->jump; bb->type |= R_ANAL_BB_TYPE_BODY; goto beach; case R_ANAL_OP_TYPE_JMP: bb->jump = op->jump; bb->type |= R_ANAL_BB_TYPE_BODY; goto beach; case R_ANAL_OP_TYPE_UJMP: bb->type |= R_ANAL_BB_TYPE_FOOT; goto beach; case R_ANAL_OP_TYPE_RET: bb->type |= R_ANAL_BB_TYPE_LAST; goto beach; case R_ANAL_OP_TYPE_LEA: { RAnalValue *src = op->src[0]; if (src && src->reg && anal->reg) { const char *pc = anal->reg->name[R_REG_NAME_PC]; RAnalValue *dst = op->dst; if (dst && dst->reg && !strcmp (src->reg->name, pc)) { int memref = anal->bits/8; ut8 b[8]; ut64 ptr = idx+addr+src->delta; anal->iob.read_at (anal->iob.io, ptr, b, memref); r_anal_ref_add (anal, ptr, addr+idx-op->size, 'd'); } } } } r_anal_op_free (op); } return bb->size; beach: r_anal_op_free (op); return R_ANAL_RET_END; }
static ut64 num_callback(RNum *userptr, const char *str, int *ok) { RCore *core = (RCore *)userptr; // XXX ? RFlagItem *flag; RAnalOp op; ut64 ret = 0; *ok = 0; if (str[0]=='[') { int refsz = (core->assembler->bits & R_SYS_BITS_64)? 8: 4; const char *p = strchr (str+1, ':'); ut64 n; // TODO: honor endian if (p) { refsz = atoi (str+1); str = p; } // push state { const char *q = r_num_calc_index (NULL); n = r_num_math (core->num, str+1); r_num_calc_index (q); } // pop state switch (refsz) { case 8: { ut64 num = 0; r_io_read_at (core->io, n, (ut8*)&num, sizeof (num)); return num; } case 4: { ut32 num = 0; r_io_read_at (core->io, n, (ut8*)&num, sizeof (num)); return num; } case 2: { ut16 num = 0; r_io_read_at (core->io, n, (ut8*)&num, sizeof (num)); return num; } case 1: { ut8 num = 0; r_io_read_at (core->io, n, (ut8*)&num, sizeof (num)); return num; } default: eprintf ("Invalid reference size: %d\n", refsz); break; } } else if (str[0]=='$') { *ok = 1; r_anal_op (core->anal, &op, core->offset, core->block, core->blocksize); switch (str[1]) { case '{': { char *ptr, *bptr = strdup (str+2); ptr = strchr (bptr, '}'); if (ptr != NULL) { ut64 ret; ptr[0]='\0'; ret = r_config_get_i (core->config, bptr); free (bptr); return ret; } } return 0; case 'e': return op.eob; case 'j': return op.jump; case 'f': return op.fail; case 'r': return op.ref; case 'l': return op.length; case 'b': return core->blocksize; case 's': return core->file->size; case '?': return core->num->value; case '$': return core->offset; case 'o': return core->io->off; } } else if (*str>'A') { if ((flag = r_flag_get (core->flags, str))) { ret = flag->offset; *ok = R_TRUE; } else *ok = ret = 0; } return ret; }
static int cmd_seek(void *data, const char *input) { RCore *core = (RCore *)data; char *cmd, *p; ut64 off; if (*input == 'r') { if (input[1] && input[2]) { if (core->io->debug) { off = r_debug_reg_get (core->dbg, input + 2); r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print)); r_core_seek (core, off, 1); } else { RReg *orig = core->dbg->reg; core->dbg->reg = core->anal->reg; off = r_debug_reg_get (core->dbg, input + 2); core->dbg->reg = orig; r_core_seek (core, off, 1); } } else eprintf ("|Usage| 'sr PC' seek to program counter register\n"); } if (*input) { char* ptr; if ((ptr = strstr(input, "+.")) != NULL) { char* dup = strdup(input); dup[ptr - input] = '\x00'; off = r_num_math (core->num, dup + 1); core->offset = off; free (dup); } const char *inputnum = strchr (input, ' '); int sign = 1; { const char *u_num = inputnum? inputnum + 1: input + 1; off = r_num_math (core->num, u_num); if (*u_num == '-') off = -off; } #if 0 if (input[0]!='/' && inputnum && isalpha (inputnum[0]) && off == 0) { if (!r_flag_get (core->flags, inputnum)) { eprintf ("Cannot find address for '%s'\n", inputnum); return false; } } #endif if (input[0]==' ') { switch (input[1]) { case '-': sign=-1; case '+': input++; break; } } switch (*input) { case 'C': if (input[1]=='*') { r_core_cmd0 (core, "C*~^\"CC"); } else if (input[1]==' ') { typedef struct { ut64 addr; char *str; } MetaCallback; int count = 0; MetaCallback cb = { 0, NULL }; ut64 addr; char key[128]; const char *val, *comma; char *list = sdb_get (core->anal->sdb_meta, "meta.C", 0); char *str, *next, *cur = list; if (list) { for (;;) { cur = sdb_anext (cur, &next); addr = sdb_atoi (cur); snprintf (key, sizeof (key)-1, "meta.C.0x%"PFMT64x, addr); val = sdb_const_get (core->anal->sdb_meta, key, 0); if (val) { comma = strchr (val, ','); if (comma) { str = (char *)sdb_decode (comma+1, 0); if (strstr (str, input+2)) { r_cons_printf ("0x%08"PFMT64x" %s\n", addr, str); count++; cb.addr = addr; free (cb.str); cb.str = str; } else free (str); } } else eprintf ("sdb_const_get key not found '%s'\n", key); if (!next) break; cur = next; } } switch (count) { case 0: eprintf ("No matching comments\n"); break; case 1: off = cb.addr; r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print)); r_core_seek (core, off, 1); r_core_block_read (core); break; default: eprintf ("Too many results\n"); break; } free (cb.str); } else { const char *help_msg[] = { "Usage:", "sC", "Comment grep", "sC", "*", "List all comments", "sC", " str", "Seek to the first comment matching 'str'", NULL }; r_core_cmd_help (core, help_msg); } break; case ' ': r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print)); r_core_seek (core, off * sign, 1); r_core_block_read (core); break; case '/': { const char *pfx = r_config_get (core->config, "search.prefix"); ut64 from = r_config_get_i (core->config, "search.from"); //kwidx cfg var is ignored int kwidx = core->search->n_kws; //(int)r_config_get_i (core->config, "search.kwidx")-1; if (kwidx<0) kwidx = 0; switch (input[1]) { case ' ': case 'v': case 'V': case 'w': case 'W': case 'z': case 'm': case 'c': case 'A': case 'e': case 'E': case 'i': case 'R': case 'r': case '/': case 'x': r_config_set_i (core->config, "search.from", core->offset+1); r_config_set_i (core->config, "search.count", 1); r_core_cmdf (core, "s+1; %s; s-1; s %s%d_0; f-%s%d_0", input, pfx, kwidx, pfx, kwidx, pfx, kwidx); r_config_set_i (core->config, "search.from", from); r_config_set_i (core->config, "search.count", 0); break; case '?': eprintf ("Usage: s/.. arg.\n"); r_cons_printf ("/?\n"); break; default: eprintf ("unknown search method\n"); break; } } break; case '.': for (input++;*input=='.';input++); r_core_seek_base (core, input); break; case '*': case '=': case 'j': r_io_sundo_list (core->io, input[0]); break; case '+': if (input[1]!='\0') { int delta = (input[1]=='+')? core->blocksize: off; r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print)); r_core_seek_delta (core, delta); } else { RIOUndos *undo = r_io_sundo_redo (core->io); if (undo != NULL) r_core_seek (core, undo->off, 0); } break; case '-': if (input[1]!='\0') { int delta = (input[1]=='-') ? -core->blocksize: -off; r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print)); r_core_seek_delta (core, delta); } else { RIOUndos *undo = r_io_sundo (core->io, core->offset); if (undo) { r_core_seek (core, undo->off, 0); r_core_block_read (core); } } break; case 'n': r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print)); r_core_seek_next (core, r_config_get (core->config, "scr.nkey")); break; case 'p': r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print)); r_core_seek_previous (core, r_config_get (core->config, "scr.nkey")); break; case 'a': off = core->blocksize; if (input[1]&&input[2]) { cmd = strdup (input); p = strchr (cmd+2, ' '); if (p) { off = r_num_math (core->num, p+1);; *p = '\0'; } cmd[0] = 's'; // perform real seek if provided r_cmd_call (core->rcmd, cmd); free (cmd); } r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print)); r_core_seek_align (core, off, 0); break; case 'b': if (off == 0) off = core->offset; r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print)); r_core_anal_bb_seek (core, off); break; case 'f': // "sf" if (strlen(input) > 2 && input[1]==' ') { RAnalFunction *fcn = r_anal_fcn_find_name (core->anal, input+2); if (fcn) { r_core_seek (core, fcn->addr, 1); } break; } RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, 0); if (fcn) { r_core_seek (core, fcn->addr + r_anal_fcn_size (fcn), 1); } break; case 'o': // "so" { RAnalOp op; int val=0, ret, i, n = r_num_math (core->num, input+1); if (n==0) n = 1; if (n<0) { int instr_len; ut64 addr = core->offset; int numinstr = n * -1; if (r_core_prevop_addr (core, core->offset, numinstr, &addr)) { ret = core->offset - addr; } else { ret = r_core_asm_bwdis_len (core, &instr_len, &addr, numinstr); } r_core_seek (core, addr, true); val += ret; } else { for (val=i=0; i<n; i++) { ret = r_anal_op (core->anal, &op, core->offset, core->block, core->blocksize); if (ret<1) ret = 1; r_core_seek_delta (core, ret); val += ret; } } core->num->value = val; } break; case 'g': // "sg" { RIOSection *s = r_io_section_vget (core->io, core->offset); if (s) r_core_seek (core, s->vaddr, 1); else r_core_seek (core, 0, 1); } break; case 'G': // "sG" { if (!core->file) break; RIOSection *s = r_io_section_vget (core->io, core->offset); // XXX: this +2 is a hack. must fix gap between sections if (s) r_core_seek (core, s->vaddr+s->size+2, 1); else r_core_seek (core, r_io_desc_size (core->io, core->file->desc), 1); } break; case 'l': // "sl" { int sl_arg = r_num_math (core->num, input+1); const char *help_msg[] = { "Usage:", "sl+ or sl- or slc", "", "sl", " [line]", "Seek to absolute line", "sl", "[+-][line]", "Seek to relative line", "slc", "", "Clear line cache", "sll", "", "Show total number of lines", NULL }; switch (input[1]) { case 0: if (!core->print->lines_cache) { __init_seek_line (core); } __get_current_line (core); break; case ' ': if (!core->print->lines_cache) { __init_seek_line (core); } __seek_line_absolute (core, sl_arg); break; case '+': case '-': if (!core->print->lines_cache) { __init_seek_line (core); } __seek_line_relative (core, sl_arg); break; case 'c': __clean_lines_cache (core); break; case 'l': if (!core->print->lines_cache) { __init_seek_line (core); } eprintf ("%d lines\n", core->print->lines_cache_sz-1); break; case '?': r_core_cmd_help (core, help_msg); break; } } break; case ':': printPadded (core, atoi (input + 1)); break; case '?': { const char * help_message[] = { "Usage: s", "", " # Seek commands", "s", "", "Print current address", "s:", "pad", "Print current address with N padded zeros (defaults to 8)", "s", " addr", "Seek to address", "s-", "", "Undo seek", "s-", " n", "Seek n bytes backward", "s--", "", "Seek blocksize bytes backward", "s+", "", "Redo seek", "s+", " n", "Seek n bytes forward", "s++", "", "Seek blocksize bytes forward", "s[j*=]", "", "List undo seek history (JSON, =list, *r2)", "s/", " DATA", "Search for next occurrence of 'DATA'", "s/x", " 9091", "Search for next occurrence of \\x90\\x91", "s.", "hexoff", "Seek honoring a base from core->offset", "sa", " [[+-]a] [asz]", "Seek asz (or bsize) aligned to addr", "sb", "", "Seek aligned to bb start", "sC", "[?] string", "Seek to comment matching given string", "sf", "", "Seek to next function (f->addr+f->size)", "sf", " function", "Seek to address of specified function", "sg/sG", "", "Seek begin (sg) or end (sG) of section or file", "sl", "[?] [+-]line", "Seek to line", "sn/sp", "", "Seek next/prev scr.nkey", "so", " [N]", "Seek to N next opcode(s)", "sr", " pc", "Seek to register", //"sp [page] seek page N (page = block)", NULL }; r_core_cmd_help(core, help_message); } break; } } else r_cons_printf ("0x%"PFMT64x"\n", core->offset); return 0; }
static ut64 num_callback(RNum *userptr, const char *str, int *ok) { RCore *core = (RCore *)userptr; // XXX ? RAnalFunction *fcn; char *ptr, *bptr; RFlagItem *flag; RIOSection *s; RAnalOp op; ut64 ret = 0; if (ok) *ok = R_FALSE; if (*str=='[') { int refsz = (core->assembler->bits & R_SYS_BITS_64)? 8: 4; const char *p = strchr (str+5, ':'); ut64 n; // TODO: honor endian if (p) { refsz = atoi (str+1); str = p; } // push state { char *o = strdup (str+1); const char *q = r_num_calc_index (core->num, NULL); r_str_replace_char (o, ']', 0); n = r_num_math (core->num, o); r_num_calc_index (core->num, q); free (o); } // pop state switch (refsz) { case 8: { ut64 num = 0; r_io_read_at (core->io, n, (ut8*)&num, sizeof (num)); return num; } case 4: { ut32 num = 0; r_io_read_at (core->io, n, (ut8*)&num, sizeof (num)); return num; } case 2: { ut16 num = 0; r_io_read_at (core->io, n, (ut8*)&num, sizeof (num)); return num; } case 1: { ut8 num = 0; r_io_read_at (core->io, n, (ut8*)&num, sizeof (num)); return num; } default: eprintf ("Invalid reference size: %d (%s)\n", refsz, str); break; } } else if (str[0]=='$') { if (ok) *ok = 1; // TODO: group analop-dependant vars after a char, so i can filter r_anal_op (core->anal, &op, core->offset, core->block, core->blocksize); switch (str[1]) { case '.': // can use pc, sp, a0, a1, ... return r_debug_reg_get (core->dbg, str+2); case '{': bptr = strdup (str+2); ptr = strchr (bptr, '}'); if (ptr != NULL) { ut64 ret; ptr[0] = '\0'; ret = r_config_get_i (core->config, bptr); free (bptr); return ret; } break; case 'h': { int rows; r_cons_get_size (&rows); return rows; } case 'e': return op.eob; case 'j': return op.jump; case 'f': return op.fail; case 'r': return op.ref; case 'l': return op.length; case 'b': return core->blocksize; case 's': return core->file->size; case 'w': return r_config_get_i (core->config, "asm.bits") / 8; case 'S': s = r_io_section_get (core->io, r_io_section_vaddr_to_offset (core->io, core->offset)); return s? (str[2]=='S'? s->size: s->offset): 0; case '?': return core->num->value; case '$': return core->offset; case 'o': return core->io->off; case 'C': return getref (core, atoi (str+2), 'r', R_ANAL_REF_TYPE_CALL); case 'J': return getref (core, atoi (str+2), 'r', R_ANAL_REF_TYPE_CODE); case 'D': return getref (core, atoi (str+2), 'r', R_ANAL_REF_TYPE_DATA); case 'X': return getref (core, atoi (str+2), 'x', R_ANAL_REF_TYPE_CALL); case 'I': fcn = r_anal_fcn_find (core->anal, core->offset, 0); return fcn? fcn->ninstr: 0; case 'F': fcn = r_anal_fcn_find (core->anal, core->offset, 0); return fcn? fcn->size: 0; } } else if (*str>'A') { if ((flag = r_flag_get (core->flags, str))) { ret = flag->offset; if (ok) *ok = R_TRUE; } } return ret; }
// TODO: add support for byte-per-byte opcode search R_API RList *r_core_asm_strsearch(RCore *core, const char *input, ut64 from, ut64 to, int maxhits, int regexp, int everyByte, int mode) { RCoreAsmHit *hit; RAsmOp op; RList *hits; ut64 at, toff = core->offset; ut8 *buf; int align = core->search->align; RRegex* rx = NULL; char *tok, *tokens[1024], *code = NULL, *ptr; int idx, tidx = 0, len = 0; int tokcount, matchcount, count = 0; int matches = 0; const int addrbytes = core->io->addrbytes; if (!input || !*input) { return NULL; } ut64 usrimm = r_num_math (core->num, input + 1); if (core->blocksize < 8) { eprintf ("error: block size too small\n"); return NULL; } if (!(buf = (ut8 *)calloc (core->blocksize, 1))) { return NULL; } if (!(ptr = strdup (input))) { free (buf); return NULL; } if (!(hits = r_core_asm_hit_list_new ())) { free (buf); free (ptr); return NULL; } tokens[0] = NULL; for (tokcount = 0; tokcount < R_ARRAY_SIZE (tokens) - 1; tokcount++) { tok = strtok (tokcount? NULL: ptr, ";"); if (!tok) { break; } tokens[tokcount] = r_str_trim_head_tail (tok); } tokens[tokcount] = NULL; r_cons_break_push (NULL, NULL); char *opst = NULL; for (at = from, matchcount = 0; at < to; at += core->blocksize) { if (r_cons_is_breaked ()) { break; } if (!r_io_is_valid_offset (core->io, at, 0)) { break; } (void)r_io_read_at (core->io, at, buf, core->blocksize); idx = 0, matchcount = 0; while (addrbytes * (idx + 1) <= core->blocksize) { ut64 addr = at + idx; if (addr >= to) { break; } r_asm_set_pc (core->assembler, addr); if (mode == 'i') { RAnalOp analop = {0}; if (r_anal_op (core->anal, &analop, addr, buf + idx, 15, 0) < 1) { idx ++; // TODO: honor mininstrsz continue; } if (analop.val == usrimm) { if (!(hit = r_core_asm_hit_new ())) { r_list_purge (hits); R_FREE (hits); goto beach; } hit->addr = addr; hit->len = analop.size; // idx + len - tidx; if (hit->len == -1) { r_core_asm_hit_free (hit); goto beach; } r_asm_disassemble (core->assembler, &op, buf + addrbytes * idx, core->blocksize - addrbytes * idx); hit->code = r_str_newf (r_strbuf_get (&op.buf_asm)); idx = (matchcount)? tidx + 1: idx + 1; matchcount = 0; r_list_append (hits, hit); continue; } r_anal_op_fini (&analop); idx ++; // TODO: honor mininstrsz continue; } else if (mode == 'e') { RAnalOp analop = {0}; if (r_anal_op (core->anal, &analop, addr, buf + idx, 15, R_ANAL_OP_MASK_ESIL) < 1) { idx ++; // TODO: honor mininstrsz continue; } //opsz = analop.size; opst = strdup (r_strbuf_get (&analop.esil)); r_anal_op_fini (&analop); } else { if (!(len = r_asm_disassemble ( core->assembler, &op, buf + addrbytes * idx, core->blocksize - addrbytes * idx))) { idx = (matchcount)? tidx + 1: idx + 1; matchcount = 0; continue; } //opsz = op.size; opst = strdup (r_strbuf_get (&op.buf_asm)); } if (opst) { matches = strcmp (opst, "invalid") && strcmp (opst, "unaligned"); } if (matches && tokens[matchcount]) { if (!regexp) { matches = strstr (opst, tokens[matchcount]) != NULL; } else { rx = r_regex_new (tokens[matchcount], ""); if (r_regex_comp (rx, tokens[matchcount], R_REGEX_EXTENDED|R_REGEX_NOSUB) == 0) { matches = r_regex_exec (rx, opst, 0, 0, 0) == 0; } r_regex_free (rx); } } if (align && align > 1) { if (addr % align) { matches = false; } } if (matches) { code = r_str_appendf (code, "%s; ", opst); if (matchcount == tokcount - 1) { if (tokcount == 1) { tidx = idx; } if (!(hit = r_core_asm_hit_new ())) { r_list_purge (hits); R_FREE (hits); goto beach; } hit->addr = addr; hit->len = idx + len - tidx; if (hit->len == -1) { r_core_asm_hit_free (hit); goto beach; } code[strlen (code) - 2] = 0; hit->code = strdup (code); r_list_append (hits, hit); R_FREE (code); matchcount = 0; idx = tidx + 1; if (maxhits) { count++; if (count >= maxhits) { //eprintf ("Error: search.maxhits reached\n"); goto beach; } } } else if (!matchcount) { tidx = idx; matchcount++; idx += len; } else { matchcount++; idx += len; } } else { if (everyByte) { idx = matchcount? tidx + 1: idx + 1; } else { idx += R_MAX (1, len); } R_FREE (code); matchcount = 0; } R_FREE (opst); } } r_cons_break_pop (); r_asm_set_pc (core->assembler, toff); beach: free (buf); free (ptr); free (code); R_FREE (opst); r_cons_break_pop (); return hits; }