R_API int r_core_lines_initcache(RCore *core, ut64 start_addr, ut64 end_addr) { int i, line_count; int bsz = core->blocksize; char *buf; ut64 off = start_addr; ut64 baddr; if (start_addr == UT64_MAX || end_addr == UT64_MAX) { return -1; } free (core->print->lines_cache); core->print->lines_cache = R_NEWS0 (ut64, bsz); if (!core->print->lines_cache) { return -1; } { RIOSection *s = r_io_section_mget_in (core->io, core->offset); baddr = s? s->paddr: r_config_get_i (core->config, "bin.baddr"); } line_count = start_addr? 0: 1; core->print->lines_cache[0] = start_addr? 0: baddr; buf = malloc (bsz); if (!buf) { return -1; } r_cons_break_push (NULL, NULL); while (off < end_addr) { if (r_cons_is_breaked ()) { break; } r_io_read_at (core->io, off, (ut8 *) buf, bsz); for (i = 0; i < bsz; i++) { if (buf[i] == '\n') { core->print->lines_cache[line_count] = start_addr? off + i + 1: off + i + 1 + baddr; line_count++; if (line_count % bsz == 0) { ut64 *tmp = realloc (core->print->lines_cache, (line_count + bsz) * sizeof (ut64)); if (tmp) { core->print->lines_cache = tmp; } else { R_FREE (core->print->lines_cache); goto beach; } } } } off += bsz; } free (buf); r_cons_break_pop (); return line_count; beach: free (buf); r_cons_break_pop (); return -1; }
R_API void r_anal_type_match(RCore *core, RAnalFunction *fcn) { bool esil_var[STATES_SIZE] = {false}; if (!core ) { return; } if (!r_anal_emul_init (core, esil_var) || !fcn ) { r_anal_emul_restore (core, esil_var); return; } const char *pc = r_reg_get_name (core->anal->reg, R_REG_NAME_PC); ut64 addr = fcn->addr; r_reg_setv (core->dbg->reg, pc, fcn->addr); r_debug_reg_sync (core->dbg, -1, true); r_cons_break (NULL, NULL); while (!r_cons_is_breaked ()) { RAnalOp *op = r_core_anal_op (core, addr); int loop_count = sdb_num_get ( core->anal->esil->db_trace, sdb_fmt (-1, "0x%"PFMT64x".count", addr), 0); if (loop_count > LOOP_MAX) { eprintf ("Unfortunately your evilly engineered %s function trapped my most innocent `aftm` in an infinite loop.\n", fcn->name); eprintf ("I kept trace log for you to review and find out how bad things were going to happen by yourself.\n"); eprintf ("You can view this log by `ate`. Meanwhile, I will train on how to behave with such behaviour without bothering you.\n"); return; } sdb_num_set (core->anal->esil->db_trace, sdb_fmt (-1, "0x%"PFMT64x".count", addr), loop_count + 1, 0); if (!op || op->type == R_ANAL_OP_TYPE_RET) { r_anal_emul_restore (core, esil_var); return; } if (op->type == R_ANAL_OP_TYPE_CALL) { RAnalFunction *fcn_call = r_anal_get_fcn_in (core->anal, op->jump, -1); //eprintf ("in the middle of %s\n", fcn_call->name); if (fcn_call) { type_match (core, addr, fcn_call->name); } else { eprintf ("Cannot find function at 0x%08"PFMT64x"\n", op->jump); } addr += op->size; r_anal_op_free (op); r_reg_setv (core->dbg->reg, pc, addr); r_debug_reg_sync (core->dbg, -1, true); r_anal_esil_set_pc (core->anal->esil, addr); addr += stack_clean (core, addr, fcn); r_reg_setv (core->dbg->reg, pc, addr); r_debug_reg_sync (core->dbg, -1, true); r_anal_esil_set_pc (core->anal->esil, addr); continue; } else { r_core_esil_step (core, UT64_MAX, NULL); r_anal_op_free (op); } r_core_cmd0 (core, ".ar*"); addr = r_reg_getv (core->anal->reg, pc); } r_cons_break_end (); r_anal_emul_restore (core, esil_var); }
static RList * r_core_asm_back_disassemble_all(RCore *core, ut64 addr, ut64 len, ut64 max_hit_count, ut32 extra_padding){ RList *hits = r_core_asm_hit_list_new (); RCoreAsmHit dummy_value; RCoreAsmHit *hit = NULL; RAsmOp op; ut8 *buf = (ut8 *)malloc (len + extra_padding); int current_instr_len = 0; ut64 current_instr_addr = addr, current_buf_pos = len - 1, hit_count = 0; memset (&dummy_value, 0, sizeof (RCoreAsmHit)); if (!hits || !buf ){ if (hits) { r_list_purge (hits); free (hits); } free (buf); return NULL; } if (!r_io_read_at (core->io, addr-(len+extra_padding), buf, len + extra_padding)) { r_list_purge (hits); free (hits); free (buf); return NULL; } if (len == 0) { return hits; } do { if (r_cons_is_breaked ()) { break; } // reset assembler r_asm_set_pc (core->assembler, current_instr_addr); current_instr_len = len - current_buf_pos + extra_padding; IFDBG eprintf("current_buf_pos: 0x%"PFMT64x", current_instr_len: %d\n", current_buf_pos, current_instr_len); current_instr_len = r_asm_disassemble (core->assembler, &op, buf+current_buf_pos, current_instr_len); hit = r_core_asm_hit_new (); hit->addr = current_instr_addr; hit->len = current_instr_len; hit->code = NULL; r_list_add_sorted (hits, hit, ((RListComparator)rcoreasm_address_comparator)); current_buf_pos--; current_instr_addr--; hit_count++; } while ( ((int) current_buf_pos >= 0) && (int)(len - current_buf_pos) >= 0 && hit_count <= max_hit_count); free(buf); return hits; }
R_API bool r_core_dump(RCore *core, const char *file, ut64 addr, ut64 size, int append) { ut64 i; ut8 *buf; int bs = core->blocksize; FILE *fd; if (append) { fd = r_sandbox_fopen (file, "ab"); } else { r_sys_truncate (file, 0); fd = r_sandbox_fopen (file, "wb"); } if (!fd) { eprintf ("Cannot open '%s' for writing\n", file); return false; } /* some io backends seems to be buggy in those cases */ if (bs > 4096) { bs = 4096; } buf = malloc (bs); if (!buf) { eprintf ("Cannot alloc %d byte(s)\n", bs); fclose (fd); return false; } r_cons_break_push (NULL, NULL); for (i = 0; i < size; i += bs) { if (r_cons_is_breaked ()) { break; } if ((i + bs) > size) { bs = size - i; } r_io_read_at (core->io, addr + i, buf, bs); if (fwrite (buf, bs, 1, fd) < 1) { eprintf ("write error\n"); break; } } r_cons_break_pop (); fclose (fd); free (buf); return true; }
static void rtti_msvc_print_all(RVTableContext *context, int mode) { r_cons_break_push (NULL, NULL); RList *vtables = r_anal_vtable_search (context); RListIter *vtableIter; RVTableInfo *table; if (vtables) { r_list_foreach (vtables, vtableIter, table) { if (r_cons_is_breaked ()) { break; } r_anal_rtti_msvc_print_at_vtable (context, table->saddr, mode); r_cons_print ("\n"); } } r_list_free (vtables); r_cons_break_pop (); }
static void draw_vertical_line (RConsCanvas *c, int x, int y, int height) { int i; /* do not render offscreen vertical lines */ if (x + c->sx < 0) { return; } if (x + c->sx > c->w) { return; } const char *vline = useUtf8? RUNECODESTR_LINE_VERT : "|"; r_cons_break_push (NULL, NULL); for (i = y; i < y + height; i++) { if (r_cons_is_breaked ()) { break; } if (G (x, i)) { W (vline); } } r_cons_break_pop (); }
R_API ut64 r_debug_esil_step(RDebug *dbg, ut32 count) { count++; has_match = 0; r_cons_break (NULL, NULL); do { if (r_cons_is_breaked ()) break; if (has_match) { eprintf ("EsilBreak match at 0x%08"PFMT64x"\n", opc); break; } if (count>0) { count--; if (!count) { //eprintf ("Limit reached\n"); break; } } } while (r_debug_esil_stepi (dbg)); r_cons_break_end (); return opc; }
// 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) { 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; int tokcount, matchcount, count = 0; int matches = 0, addrbytes = core->assembler->addrbytes; if (!*input) { return NULL; } if (core->blocksize <= OPSZ) { 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); for (at = from, matchcount = 0; at < to; at += core->blocksize) { matches = 0; if (r_cons_is_breaked ()) { break; } if (!r_io_read_at (core->io, at, buf, core->blocksize)) { break; } idx = 0, matchcount = 0; while (addrbytes * (idx + 1) <= core->blocksize) { ut64 addr = at + idx; r_asm_set_pc (core->assembler, addr); if (!(len = r_asm_disassemble ( core->assembler, &op, buf + addrbytes * idx, core->blocksize - addrbytes * idx))) { idx = (matchcount)? tidx + 1: idx + 1; matchcount = 0; continue; } matches = strcmp (op.buf_asm, "invalid") && strcmp (op.buf_asm, "unaligned"); if (matches && tokens[matchcount]) { if (!regexp) { matches = strstr(op.buf_asm, tokens[matchcount]) != NULL; } else { rx = r_regex_new (tokens[matchcount], ""); matches = r_regex_exec (rx, op.buf_asm, 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; ", op.buf_asm); if (matchcount == tokcount - 1) { if (tokcount == 1) { tidx = idx; } if (!(hit = r_core_asm_hit_new ())) { r_list_purge (hits); free (hits); hits = NULL; 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 { idx = matchcount? tidx + 1: idx + 1; R_FREE (code); matchcount = 0; } } } r_cons_break_pop (); r_asm_set_pc (core->assembler, toff); beach: free (buf); free (ptr); free (code); r_cons_break_pop (); return hits; }
static void draw_horizontal_line (RConsCanvas *c, int x, int y, int width, int style) { const char *l_corner = "?", *r_corner = "?"; int i; if (width < 1) { return; } /* do not render offscreen horizontal lines */ if (y + c->sy < 0) { return; } if (y + c->sy > c->h) { return; } switch (style) { case APEX_DOT: if (useUtf8) { if (useUtf8Curvy) { l_corner = RUNECODESTR_CURVE_CORNER_BL; r_corner = RUNECODESTR_CURVE_CORNER_TR; } else { l_corner = RUNECODESTR_CORNER_BL; r_corner = RUNECODESTR_CORNER_TR; } } else { l_corner = "'"; r_corner = "."; } break; case DOT_APEX: if (useUtf8) { if (useUtf8Curvy) { l_corner = RUNECODESTR_CURVE_CORNER_TL; r_corner = RUNECODESTR_CURVE_CORNER_BR; } else { l_corner = RUNECODESTR_CORNER_TL; r_corner = RUNECODESTR_CORNER_BR; } } else { l_corner = "."; r_corner = "'"; } break; case REV_APEX_APEX: if (useUtf8) { if (useUtf8Curvy) { l_corner = RUNECODESTR_CURVE_CORNER_BL; r_corner = RUNECODESTR_CURVE_CORNER_BR; } else { l_corner = RUNECODESTR_CORNER_BL; r_corner = RUNECODESTR_CORNER_BR; } } else { l_corner = "`"; r_corner = "'"; } break; case DOT_DOT: if (useUtf8) { if (useUtf8Curvy) { l_corner = RUNECODESTR_CURVE_CORNER_TL; r_corner = RUNECODESTR_CURVE_CORNER_TR; } else { l_corner = RUNECODESTR_CORNER_TL; r_corner = RUNECODESTR_CORNER_TR; } } else { l_corner = r_corner = "."; } break; case NRM_DOT: if (useUtf8) { l_corner = RUNECODESTR_LINE_HORIZ; if (useUtf8Curvy) { r_corner = RUNECODESTR_CURVE_CORNER_TR; } else { r_corner = RUNECODESTR_CORNER_TR; } } else { l_corner = "-"; r_corner = "."; } break; case NRM_APEX: if (useUtf8) { l_corner = RUNECODESTR_LINE_HORIZ; if (useUtf8Curvy) { r_corner = RUNECODESTR_CURVE_CORNER_BR; } else { r_corner = RUNECODESTR_CORNER_BR; } } else { l_corner = "-"; r_corner = "'"; } break; case DOT_NRM: if (useUtf8) { if (useUtf8Curvy) { l_corner = RUNECODESTR_CURVE_CORNER_TL; } else { l_corner = RUNECODESTR_CORNER_TL; } r_corner = RUNECODESTR_LINE_HORIZ; } else { l_corner = "."; r_corner = "-"; } break; case REV_APEX_NRM: if (useUtf8) { if (useUtf8Curvy) { l_corner = RUNECODESTR_CURVE_CORNER_BL; } else { l_corner = RUNECODESTR_CORNER_BL; } r_corner = RUNECODESTR_LINE_HORIZ; } else { l_corner = "`"; r_corner = "-"; } break; case NRM_NRM: default: if (useUtf8) { l_corner = r_corner = RUNECODESTR_LINE_HORIZ; } else { l_corner = r_corner = "-"; } break; } if (G (x, y)) { W (l_corner); } const char *hline = useUtf8? RUNECODESTR_LINE_HORIZ : "-"; r_cons_break_push (NULL, NULL); for (i = x + 1; i < x + width - 1; i++) { if (r_cons_is_breaked ()) { break; } if (G (i, y)) { W (hline); } } r_cons_break_pop (); if (G (x + width - 1, y)) { W (r_corner); } }
R_API void r_cons_flush() { const char *tee = I.teefile; if (I.noflush) { return; } if (I.null) { r_cons_reset (); return; } r_cons_filter (); if (I.is_interactive && I.fdout == 1) { /* Use a pager if the output doesn't fit on the terminal window. */ if (I.pager && *I.pager && I.buffer_len > 0 && r_str_char_count (I.buffer, '\n') >= I.rows) { I.buffer[I.buffer_len-1] = 0; r_sys_cmd_str_full (I.pager, I.buffer, NULL, NULL, NULL); r_cons_reset (); } else if (I.buffer_len > CONS_MAX_USER) { #if COUNT_LINES int i, lines = 0; for (i = 0; I.buffer[i]; i++) { if (I.buffer[i] == '\n') { lines ++; } } if (lines > 0 && !r_cons_yesno ('n',"Do you want to print %d lines? (y/N)", lines)) { r_cons_reset (); return; } #else char buf[64]; char *buflen = r_num_units (buf, I.buffer_len); if (buflen && !r_cons_yesno ('n',"Do you want to print %s chars? (y/N)", buflen)) { r_cons_reset (); return; } #endif // fix | more | less problem r_cons_set_raw (1); } } if (tee && *tee) { FILE *d = r_sandbox_fopen (tee, "a+"); if (d) { if (I.buffer_len != fwrite (I.buffer, 1, I.buffer_len, d)) { eprintf ("r_cons_flush: fwrite: error (%s)\n", tee); } fclose (d); } else { eprintf ("Cannot write on '%s'\n", tee); } } r_cons_highlight (I.highlight); // is_html must be a filter, not a write endpoint if (I.is_html) { r_cons_html_print (I.buffer); } else { if (I.is_interactive && !r_sandbox_enable (false)) { if (I.linesleep > 0 && I.linesleep < 1000) { int i = 0; int pagesize = R_MAX (1, I.pagesize); char *ptr = I.buffer; char *nl = strchr (ptr, '\n'); int len = I.buffer_len; I.buffer[I.buffer_len] = 0; r_cons_break_push (NULL, NULL); while (nl && !r_cons_is_breaked ()) { r_cons_write (ptr, nl - ptr + 1); if (!(i % pagesize)) { r_sys_usleep (I.linesleep * 1000); } ptr = nl + 1; nl = strchr (ptr, '\n'); i++; } r_cons_write (ptr, I.buffer + len - ptr); r_cons_break_pop (); } else { r_cons_write (I.buffer, I.buffer_len); } } else { r_cons_write (I.buffer, I.buffer_len); } } r_cons_reset (); if (I.newline) { eprintf ("\n"); I.newline = false; } }
// 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; }
static RList *r_core_asm_back_disassemble (RCore *core, ut64 addr, int len, ut64 max_hit_count, ut8 disassmble_each_addr, ut32 extra_padding) { RList *hits;; RAsmOp op; ut8 *buf = NULL; ut8 max_invalid_b4_exit = 4, last_num_invalid = 0; int current_instr_len = 0; ut64 current_instr_addr = addr, current_buf_pos = 0, next_buf_pos = len; RCoreAsmHit dummy_value; ut32 hit_count = 0; if (disassmble_each_addr) { return r_core_asm_back_disassemble_all(core, addr, len, max_hit_count, extra_padding+1); } hits = r_core_asm_hit_list_new (); buf = malloc (len + extra_padding); if (!hits || !buf) { if (hits) { r_list_purge (hits); free (hits); } free (buf); return NULL; } if (!r_io_read_at (core->io, (addr + extra_padding) - len, buf, len + extra_padding)) { r_list_purge (hits); free (hits); free (buf); return NULL; } // // XXX - This is a heavy handed approach without a // an appropriate btree or hash table for storing // hits, because are using: // 1) Sorted RList with many inserts and searches // 2) Pruning hits to find the most optimal disassembly // greedy approach // 1) Consume previous bytes // 1a) Instruction is invalid (incr current_instr_addr) // 1b) Disasm is perfect // 1c) Disasm is underlap (disasm(current_instr_addr, next_instr_addr - current_instr_addr) short some bytes) // 1d) Disasm is overlap (disasm(current_instr_addr, next_instr_addr - current_instr_addr) over some bytes) memset (&dummy_value, 0, sizeof (RCoreAsmHit)); // disassemble instructions previous to current address, extra_padding can move the location of addr // so we need to account for that with current_buf_pos current_buf_pos = len - extra_padding - 1; next_buf_pos = len + extra_padding - 1; current_instr_addr = addr - 1; do { if (r_cons_is_breaked ()) { break; } // reset assembler r_asm_set_pc (core->assembler, current_instr_addr); current_instr_len = next_buf_pos - current_buf_pos; current_instr_len = r_asm_disassemble (core->assembler, &op, buf+current_buf_pos, current_instr_len); IFDBG { ut32 byte_cnt = current_instr_len ? current_instr_len : 1; eprintf("current_instr_addr: 0x%"PFMT64x", current_buf_pos: 0x%"PFMT64x", current_instr_len: %d \n", current_instr_addr, current_buf_pos, current_instr_len); ut8 *hex_str = (ut8*)r_hex_bin2strdup(buf+current_buf_pos, byte_cnt); eprintf ("==== current_instr_bytes: %s ",hex_str); if (current_instr_len > 0) { eprintf("op.buf_asm: %s\n", r_strbuf_get (&op.buf_asm)); } else { eprintf("op.buf_asm: <invalid>\n"); } free (hex_str); } // disassembly invalid if (current_instr_len == 0 || strstr (r_strbuf_get (&op.buf_asm), "invalid")) { if (current_instr_len == 0) { current_instr_len = 1; } add_hit_to_sorted_hits(hits, current_instr_addr, current_instr_len, /* is_valid */ false); hit_count ++; last_num_invalid ++; // disassembly perfect } else if (current_buf_pos + current_instr_len == next_buf_pos) { // i think this may be the only case where an invalid instruction will be // added because handle_forward_disassemble and handle_disassembly_overlap // are only called in cases where a valid instruction has been found. // and they are lazy, since they purge the hit list ut32 purge_results = 0; ut8 is_valid = true; IFDBG eprintf(" handling underlap case: current_instr_addr: 0x%"PFMT64x".\n", current_instr_addr); purge_results = prune_hits_in_addr_range(hits, current_instr_addr, current_instr_len, /* is_valid */ true); if (purge_results) { handle_forward_disassemble(core, hits, buf, len, current_buf_pos+current_instr_len, current_instr_addr+current_instr_len, addr); hit_count = r_list_length(hits); } add_hit_to_sorted_hits(hits, current_instr_addr, current_instr_len, is_valid); //handle_forward_disassemble(core, hits, buf, len, current_buf_pos+current_instr_len, current_instr_addr+current_instr_len, addr/*end_addr*/); hit_count ++; next_buf_pos = current_buf_pos; last_num_invalid = 0; // disassembly underlap } else if (current_buf_pos + current_instr_len < next_buf_pos) { ut32 purge_results = 0; ut8 is_valid = true; purge_results = prune_hits_in_addr_range(hits, current_instr_addr, current_instr_len, /* is_valid */ true); add_hit_to_sorted_hits(hits, current_instr_addr, current_instr_len, is_valid); if (hit_count < purge_results) { hit_count = 0; // WTF?? } else { hit_count -= purge_results; } next_buf_pos = current_buf_pos; handle_forward_disassemble(core, hits, buf, len - extra_padding, current_buf_pos+current_instr_len, current_instr_addr+current_instr_len, addr); hit_count = r_list_length(hits); last_num_invalid = 0; // disassembly overlap } else if (current_buf_pos + current_instr_len > next_buf_pos) { //ut64 value = handle_disassembly_overlap(core, hits, buf, len, current_buf_pos, current_instr_addr); next_buf_pos = current_buf_pos; hit_count = r_list_length (hits); last_num_invalid = 0; } // walk backwards by one instruction IFDBG eprintf(" current_instr_addr: 0x%"PFMT64x" current_instr_len: %d next_instr_addr: 0x%04"PFMT64x"\n", current_instr_addr, current_instr_len, next_buf_pos); IFDBG eprintf(" hit count: %d \n", hit_count ); current_instr_addr -= 1; current_buf_pos -= 1; if (hit_count >= max_hit_count && (last_num_invalid >= max_invalid_b4_exit || last_num_invalid == 0)) { break; } } while (((int) current_buf_pos >= 0) && (int)(len - current_buf_pos) >= 0); r_asm_set_pc (core->assembler, addr); free (buf); return hits; }
R_API RList *r_core_asm_bwdisassemble(RCore *core, ut64 addr, int n, int len) { RAsmOp op; // len = n * 32; // if (n > core->blocksize) n = core->blocksize; ut64 at; ut32 idx = 0, hit_count; int numinstr, asmlen, ii; const int addrbytes = core->io->addrbytes; RAsmCode *c; RList *hits = r_core_asm_hit_list_new(); if (!hits) { return NULL; } len = R_MIN (len - len % addrbytes, addrbytes * addr); if (len < 1) { r_list_free (hits); return NULL; } ut8 *buf = (ut8 *)malloc (len); if (!buf) { r_list_free (hits); return NULL; } else if (!hits) { free (buf); return NULL; } if (!r_io_read_at (core->io, addr - len / addrbytes, buf, len)) { r_list_free (hits); free (buf); return NULL; } for (idx = addrbytes; idx < len; idx += addrbytes) { if (r_cons_is_breaked ()) { break; } c = r_asm_mdisassemble (core->assembler, buf+(len-idx), idx); if (strstr (c->assembly, "invalid") || strstr (c->assembly, ".byte")) { r_asm_code_free(c); continue; } numinstr = 0; asmlen = strlen (c->assembly); for(ii = 0; ii < asmlen; ++ii) { if (c->assembly[ii] == '\n') { ++numinstr; } } r_asm_code_free(c); if (numinstr >= n || idx > 16 * n) { // assume average instruction length <= 16 break; } } at = addr - idx / addrbytes; r_asm_set_pc (core->assembler, at); for (hit_count = 0; hit_count < n; hit_count++) { int instrlen = r_asm_disassemble (core->assembler, &op, buf + len - addrbytes * (addr - at), addrbytes * (addr - at)); add_hit_to_hits (hits, at, instrlen, true); at += instrlen; } free (buf); return hits; }