radare2/libr/core/disasm.c

4425 lines
117 KiB
C
Raw Normal View History

/* radare - LGPL - Copyright 2009-2016 - nibble, pancake, dso */
#include "r_core.h"
2013-07-18 20:20:23 +00:00
#include "r_cons.h"
2013-11-06 01:10:53 +00:00
#define HASRETRY 1
2014-06-25 00:30:42 +00:00
#define HAVE_LOCALS 1
#define DEFAULT_NARGS 4
2015-12-17 19:18:50 +00:00
#define R_MIDFLAGS_SHOW 1
#define R_MIDFLAGS_REALIGN 2
2016-11-02 11:10:50 +00:00
#define R_MIDFLAGS_SYMALIGN 3
2015-12-17 19:18:50 +00:00
#define COLOR(ds, field) (ds->show_color ? ds->field : "")
#define COLOR_CONST(ds, color) (ds->show_color ? Color_ ## color : "")
#define COLOR_RESET(ds) COLOR_CONST(ds, RESET)
2016-04-08 10:18:28 +00:00
static const char* r_vline_a[] = {
2016-10-24 09:54:03 +00:00
"|", // LINE_VERT
2013-07-18 20:20:23 +00:00
"|-", // LINE_CROSS
2016-10-24 09:54:03 +00:00
"-", // LINE_HORIZ
"!", // LINE_UP
",", // LUP_CORNER
2013-07-18 20:20:23 +00:00
"\\", // RDWN_CORNER
2016-10-24 09:54:03 +00:00
"/", // RUP_CORNER
"`", // LDWN_CORNER
2013-07-18 20:20:23 +00:00
"->", // ARROW_RIGHT
"=<", // ARROW_LEFT
};
static const char* r_vline_u[] = {
2013-07-18 20:20:23 +00:00
"", // LINE_VERT
"", // LINE_CROSS
"", // LINE_HORIZ
"", // LINE_UP
2016-10-24 09:54:03 +00:00
//"┌", // LUP_CORNER
"", // LUP_CORNER
2016-10-20 23:24:40 +00:00
"", // RDWN_CORNER
"", // RUP_CORNER
"", // LDWN_CORNER
">", // ARROW_RIGHT
"<", // ARROW_LEFT
2013-07-18 20:20:23 +00:00
};
2014-01-20 00:42:16 +00:00
// TODO: what about using bit shifting and enum for keys? see libr/util/bitmap.c
// the problem of this is that the fields will be more opaque to bindings, but we will earn some bits
typedef struct r_disam_options_t {
RCore *core;
2015-02-07 23:30:25 +00:00
char str[1024], strsub[1024];
bool use_esil;
bool show_color;
bool show_color_bytes;
int colorop;
int acase;
bool show_flgoff;
int atabs;
int atabsonce;
int atabsoff;
int decode;
int pseudo;
int filter;
int interactive;
int varsub;
bool show_lines;
bool show_lines_ret;
bool show_lines_call;
int linesright;
int tracespace;
int cyclespace;
int cmtfold;
int show_indent;
bool show_dwarf;
bool show_size;
bool show_trace;
bool show_family;
bool asm_describe;
int linesout;
int adistrick;
int asm_demangle;
bool show_offset;
2016-11-01 22:30:36 +00:00
bool show_offdec; // dupe for r_print->flags
bool show_bbline;
bool show_emu;
bool show_emu_str;
bool show_emu_write;
bool show_section;
int show_section_col;
bool show_symbols;
int show_symbols_col;
bool show_offseg;
bool show_flags;
bool show_bytes;
bool show_reloff;
bool show_reloff_flags;
bool show_comments;
bool show_jmphints;
bool show_leahints;
bool show_slow;
int cmtcol;
bool show_fcnlines;
bool show_calls;
bool show_cmtflgrefs;
bool show_cycles;
bool show_stackptr;
bool show_spacy;
bool show_xrefs;
bool show_cmtrefs;
bool show_functions;
bool show_fcncalls;
bool show_hints;
bool show_marks;
int cursor;
int show_comment_right_default;
int flagspace_ports;
int show_flag_in_bytes;
int lbytes;
int show_comment_right;
char *pre;
char *ocomment;
int linesopts;
int lastfail;
int oldbits;
int ocols;
int lcols;
int nb, nbytes;
int show_utf8;
int lines;
int oplen;
bool show_varxs;
bool show_vars;
int midflags;
const char *pal_comment;
const char *color_comment;
const char *color_fname;
const char *color_floc;
const char *color_fline;
const char *color_flow;
const char *color_flag;
const char *color_label;
const char *color_other;
const char *color_nop;
const char *color_bin;
const char *color_math;
const char *color_jmp;
const char *color_cjmp;
const char *color_call;
const char *color_cmp;
const char *color_swi;
const char *color_trap;
const char *color_ret;
const char *color_push;
const char *color_pop;
const char *color_reg;
const char *color_num;
2014-05-16 02:07:03 +00:00
const char *color_mov;
const char *color_invalid;
const char *color_gui_cflow;
const char *color_gui_dataoffset;
const char *color_gui_background;
const char *color_gui_alt_background;
const char *color_gui_border;
RFlagItem *lastflag;
RAnalHint *hint;
2016-05-30 10:35:39 +00:00
RPrint *print;
ut64 esil_old_pc;
ut8* esil_regstate;
2016-06-08 21:33:31 +00:00
bool esil_likely;
int l;
int middle;
int indent_level;
int indent_space;
char *line;
char *refline, *refline2;
char *comment;
char *opstr;
char *osl, *sl;
int stackptr, ostackptr;
int index;
ut64 at, addr, dest;
int tries, cbytes, idx;
ut8 mi_found, retry, toro;
RAsmOp asmop;
RAnalOp analop;
RAnalFunction *fcn;
const ut8 *buf;
int len;
int maxrefs;
char *prev_ins;
bool prev_ins_eq;
int prev_ins_count;
bool show_nodup;
bool has_description;
// caches
char *_tabsbuf;
int _tabsoff;
} RDisasmState;
2016-05-30 10:35:39 +00:00
static void ds_setup_print_pre(RDisasmState *ds, bool tail, bool middle);
static void ds_setup_pre(RDisasmState *ds, bool tail, bool middle);
static void ds_print_pre(RDisasmState *ds);
static void ds_beginline(RDisasmState *ds, RAnalFunction *f, bool nopre);
static void ds_print_esil_anal(RDisasmState *ds);
static void ds_reflines_init(RDisasmState *ds);
static void ds_align_comment(RDisasmState *ds);
static RDisasmState * ds_init(RCore * core);
static void ds_set_pre(RDisasmState *ds, const char * str);
static void ds_build_op_str(RDisasmState *ds);
static void ds_pre_xrefs(RDisasmState *ds);
static void ds_show_xrefs(RDisasmState *ds);
static void ds_atabs_option(RDisasmState *ds);
static void ds_show_functions(RDisasmState *ds);
static void ds_show_comments_right(RDisasmState *ds);
static void ds_show_flags(RDisasmState *ds);
static void ds_update_ref_lines(RDisasmState *ds);
static int ds_disassemble(RDisasmState *ds, ut8 *buf, int len);
static void ds_control_flow_comments(RDisasmState *ds);
static void ds_print_lines_right(RDisasmState *ds);
static void ds_print_lines_left(RDisasmState *ds);
static void ds_print_cycles(RDisasmState *ds);
static void ds_print_family(RDisasmState *ds);
static void ds_print_stackptr(RDisasmState *ds);
static void ds_print_offset(RDisasmState *ds);
static void ds_print_op_size(RDisasmState *ds);
static void ds_print_trace(RDisasmState *ds);
static void ds_adistrick_comments(RDisasmState *ds);
static int ds_print_meta_infos(RDisasmState *ds, ut8* buf, int len, int idx );
static void ds_print_opstr(RDisasmState *ds);
static void ds_print_color_reset(RDisasmState *ds);
static int ds_print_middle(RDisasmState *ds, int ret);
static bool ds_print_labels(RDisasmState *ds, RAnalFunction *f);
static void ds_print_import_name(RDisasmState *ds);
static void ds_print_fcn_name(RDisasmState *ds);
static void ds_print_as_string(RDisasmState *ds);
static void ds_print_core_vmode(RDisasmState *ds);
static void ds_print_dwarf(RDisasmState *ds);
static void ds_print_asmop_payload(RDisasmState *ds);
static void ds_print_op_push_info(RDisasmState *ds);
static void ds_print_comments_right(RDisasmState *ds);
static void ds_print_ptr(RDisasmState *ds, int len, int idx);
2014-01-20 00:42:16 +00:00
static int cmpaddr(const void *_a, const void *_b) {
const RAnalBlock *a = _a, *b = _b;
return (a->addr > b->addr);
}
2014-01-20 00:42:16 +00:00
static void get_bits_comment(RCore *core, RAnalFunction *f, char *cmt, int cmt_size) {
if (core && f && cmt && cmt_size > 0 && f->bits && f->bits != core->assembler->bits) {
2016-06-02 01:19:31 +00:00
const char *asm_arch = r_config_get (core->config, "asm.arch");
if (asm_arch && *asm_arch && strstr (asm_arch, "arm")) {
switch (f->bits) {
case 16: strcpy (cmt, " (thumb)"); break;
case 32: strcpy (cmt, " (arm)"); break;
case 64: strcpy (cmt, " (aarch64)"); break;
}
} else {
snprintf (cmt, cmt_size, " (%d bits)", f->bits);
}
} else {
if (cmt) {
cmt[0] = 0;
}
}
}
2016-05-30 10:35:39 +00:00
static const char * get_section_name(RCore *core, ut64 addr) {
static char section[128] = "";
static ut64 oaddr = UT64_MAX;
RIOSection *s;
if (oaddr == addr) {
return section;
}
s = r_io_section_vget (core->io, addr);
if (s) {
snprintf (section, sizeof (section)-1, "%10s ", s->name);
} else {
RListIter *iter;
RDebugMap *map;
*section = 0;
r_list_foreach (core->dbg->maps, iter, map) {
if (addr >= map->addr && addr < map->addr_end) {
2015-06-01 13:34:26 +00:00
const char *mn = r_str_lchr (map->name, '/');
if (mn) {
strncpy (section, mn + 1, sizeof (section) - 1);
2015-06-01 13:34:26 +00:00
} else {
strncpy (section, map->name, sizeof (section) - 1);
2015-06-01 13:34:26 +00:00
}
break;
}
}
}
oaddr = addr;
return section;
}
static void ds_print_spacy(RDisasmState *ds, int pre) {
RCore *core = ds->core;
RAnalFunction *f = NULL;
2016-10-06 01:13:02 +00:00
if (pre) {
r_cons_newline ();
}
if (ds->show_functions) {
f = r_anal_get_fcn_in (core->anal, ds->at, R_ANAL_FCN_TYPE_NULL);
if (!f) {
r_cons_print (" ");
2016-05-30 10:35:39 +00:00
ds_print_lines_left (ds);
}
}
2016-05-30 10:35:39 +00:00
if (f) ds_beginline (ds, f, true);
ds_print_offset (ds);
2016-10-06 01:13:02 +00:00
if (!pre) {
r_cons_newline ();
}
}
2016-05-30 10:35:39 +00:00
static RDisasmState * ds_init(RCore *core) {
RDisasmState *ds = R_NEW0 (RDisasmState);
if (!ds) {
return NULL;
}
ds->core = core;
2014-01-20 00:42:16 +00:00
ds->pal_comment = core->cons->pal.comment;
#define P(x) (core->cons && core->cons->pal.x)? core->cons->pal.x
ds->color_comment = P(comment): Color_CYAN;
ds->color_fname = P(fname): Color_RED;
ds->color_floc = P(floc): Color_MAGENTA;
ds->color_fline = P(fline): Color_CYAN;
ds->color_flow = P(flow): Color_CYAN;
ds->color_flag = P(flag): Color_CYAN;
ds->color_label = P(label): Color_CYAN;
ds->color_other = P(other): Color_WHITE;
ds->color_nop = P(nop): Color_BLUE;
ds->color_bin = P(bin): Color_YELLOW;
ds->color_math = P(math): Color_YELLOW;
ds->color_jmp = P(jmp): Color_GREEN;
ds->color_cjmp = P(cjmp): Color_GREEN;
ds->color_call = P(call): Color_BGREEN;
ds->color_cmp = P(cmp): Color_MAGENTA;
ds->color_swi = P(swi): Color_MAGENTA;
ds->color_trap = P(trap): Color_BRED;
ds->color_ret = P(ret): Color_RED;
ds->color_push = P(push): Color_YELLOW;
ds->color_pop = P(pop): Color_BYELLOW;
ds->color_reg = P(reg): Color_YELLOW;
2015-06-14 00:42:39 +00:00
ds->color_num = P(num): Color_CYAN;
ds->color_mov = P(mov): Color_WHITE;
ds->color_invalid = P(invalid): Color_BRED;
ds->color_gui_cflow = P(gui_cflow): Color_YELLOW;
ds->color_gui_dataoffset = P(gui_dataoffset): Color_YELLOW;
ds->color_gui_background = P(gui_background): Color_BLACK;
ds->color_gui_alt_background = P(gui_alt_background): Color_GRAY;
ds->color_gui_border = P(gui_border): Color_BGGRAY;
2014-01-20 00:42:16 +00:00
ds->use_esil = r_config_get_i (core->config, "asm.esil");
ds->show_flgoff = r_config_get_i (core->config, "asm.flgoff");
ds->show_nodup = r_config_get_i (core->config, "asm.nodup");
ds->show_spacy = r_config_get_i (core->config, "asm.spacy");
2014-01-20 00:42:16 +00:00
ds->show_color = r_config_get_i (core->config, "scr.color");
ds->show_color_bytes = r_config_get_i (core->config, "scr.color.bytes"); // maybe rename to asm.color.bytes
ds->colorop = r_config_get_i (core->config, "scr.color.ops"); // XXX confusing name // asm.color.inst (mnemonic + operands) ?
2014-01-20 00:42:16 +00:00
ds->show_utf8 = r_config_get_i (core->config, "scr.utf8");
ds->acase = r_config_get_i (core->config, "asm.ucase");
ds->atabs = r_config_get_i (core->config, "asm.tabs");
ds->atabsonce = r_config_get_i (core->config, "asm.tabsonce");
ds->atabsoff = r_config_get_i (core->config, "asm.tabsoff");
ds->midflags = r_config_get_i (core->config, "asm.midflags");
2014-01-20 00:42:16 +00:00
ds->decode = r_config_get_i (core->config, "asm.decode");
ds->pseudo = r_config_get_i (core->config, "asm.pseudo");
ds->filter = r_config_get_i (core->config, "asm.filter");
ds->interactive = r_config_get_i (core->config, "scr.interactive");
2014-01-20 00:42:16 +00:00
ds->varsub = r_config_get_i (core->config, "asm.varsub");
2015-11-19 22:12:08 +00:00
core->parser->relsub = r_config_get_i (core->config, "asm.relsub");
ds->show_vars = r_config_get_i (core->config, "asm.vars");
ds->show_varxs = r_config_get_i (core->config, "asm.varxs");
ds->maxrefs = r_config_get_i (core->config, "asm.maxrefs");
2014-01-20 00:42:16 +00:00
ds->show_lines = r_config_get_i (core->config, "asm.lines");
ds->linesright = r_config_get_i (core->config, "asm.linesright");
ds->show_indent = r_config_get_i (core->config, "asm.indent");
ds->indent_space = r_config_get_i (core->config, "asm.indentspace");
ds->tracespace = r_config_get_i (core->config, "asm.tracespace");
ds->cyclespace = r_config_get_i (core->config, "asm.cyclespace");
ds->show_dwarf = r_config_get_i (core->config, "asm.dwarf");
ds->show_lines_call = r_config_get_i (core->config, "asm.lines.call");
ds->show_lines_ret = r_config_get_i (core->config, "asm.lines.ret");
2014-01-20 00:42:16 +00:00
ds->show_size = r_config_get_i (core->config, "asm.size");
ds->show_trace = r_config_get_i (core->config, "asm.trace");
ds->linesout = r_config_get_i (core->config, "asm.linesout");
ds->adistrick = r_config_get_i (core->config, "asm.middle"); // TODO: find better name
ds->asm_demangle = r_config_get_i (core->config, "asm.demangle");
ds->asm_describe = r_config_get_i (core->config, "asm.describe");
2014-01-20 00:42:16 +00:00
ds->show_offset = r_config_get_i (core->config, "asm.offset");
2016-11-01 22:30:36 +00:00
ds->show_offdec = r_config_get_i (core->config, "asm.decoff");
ds->show_bbline = r_config_get_i (core->config, "asm.bbline");
2014-11-22 04:39:52 +00:00
ds->show_section = r_config_get_i (core->config, "asm.section");
ds->show_section_col = r_config_get_i (core->config, "asm.section.col");
ds->show_symbols = r_config_get_i (core->config, "asm.symbol");
ds->show_symbols_col = r_config_get_i (core->config, "asm.symbol.col");
2015-09-11 21:46:09 +00:00
ds->show_emu = r_config_get_i (core->config, "asm.emu");
2016-01-14 23:17:15 +00:00
ds->show_emu_str = r_config_get_i (core->config, "asm.emustr");
ds->show_emu_write = r_config_get_i (core->config, "asm.emuwrite");
2014-01-20 00:42:16 +00:00
ds->show_offseg = r_config_get_i (core->config, "asm.segoff");
ds->show_flags = r_config_get_i (core->config, "asm.flags");
ds->show_bytes = r_config_get_i (core->config, "asm.bytes");
ds->show_reloff = r_config_get_i (core->config, "asm.reloff");
ds->show_reloff_flags = r_config_get_i (core->config, "asm.reloff.flags");
ds->show_fcnlines = r_config_get_i (core->config, "asm.fcnlines");
2014-01-20 00:42:16 +00:00
ds->show_comments = r_config_get_i (core->config, "asm.comments");
ds->show_jmphints = r_config_get_i (core->config, "asm.jmphints");
ds->show_leahints = r_config_get_i (core->config, "asm.leahints");
ds->show_slow = r_config_get_i (core->config, "asm.slow");
ds->show_calls = r_config_get_i (core->config, "asm.calls");
2015-10-03 11:52:52 +00:00
ds->show_family = r_config_get_i (core->config, "asm.family");
ds->cmtcol = r_config_get_i (core->config, "asm.cmtcol");
2014-01-20 00:42:16 +00:00
ds->show_cmtflgrefs = r_config_get_i (core->config, "asm.cmtflgrefs");
2014-02-10 22:01:19 +00:00
ds->show_cycles = r_config_get_i (core->config, "asm.cycles");
2014-01-20 00:42:16 +00:00
ds->show_stackptr = r_config_get_i (core->config, "asm.stackptr");
ds->show_xrefs = r_config_get_i (core->config, "asm.xrefs");
ds->show_cmtrefs = r_config_get_i (core->config, "asm.cmtrefs");
ds->cmtfold = r_config_get_i (core->config, "asm.cmtfold");
2014-01-20 00:42:16 +00:00
ds->show_functions = r_config_get_i (core->config, "asm.functions");
ds->show_fcncalls = r_config_get_i (core->config, "asm.fcncalls");
2014-01-20 00:42:16 +00:00
ds->nbytes = r_config_get_i (core->config, "asm.nbytes");
2014-02-25 00:35:23 +00:00
core->print->bytespace = r_config_get_i (core->config, "asm.bytespace");
2014-01-20 00:42:16 +00:00
ds->cursor = 0;
ds->nb = 0;
ds->flagspace_ports = r_flag_space_get (core->flags, "ports");
ds->lbytes = r_config_get_i (core->config, "asm.lbytes");
ds->show_comment_right_default = r_config_get_i (core->config, "asm.cmtright");
ds->show_comment_right = r_config_get_i (core->config, "asm.cmtright"); // XX conflict with show_comment_right_default
ds->show_flag_in_bytes = r_config_get_i (core->config, "asm.flagsinbytes");
Add asm.hints and handle CDOV deoptimization CDIV deoptimization =================== This patch implements hints in the disassembler that aim to assist the user in reading compiler-optimized divisions by analysing the involved magic number. Background ========== Since integer divisions are usually very expensive on most architectures, compilers try very hard to substitute them with cheaper operations. One of the more advanced substitutions is described in the book __Hacker's Delight__, chapter 10. An actual implementation of the described algorithm in LLVM can be found in the functions: `TargetLowering::BuildSDIV()` and `APInt::magic()`. The optimization approximately transforms e.g. ```asm xor edx, edx idiv 39 ``` into ```asm mov eax, edi mov edx, 0xd20d20d3 imul edx lea eax, [rdx + rdi] sar edi, 0x1f sar eax, 5 sub eax, edi ``` Reading the optimized version and __seeing__ the constant 39 seems difficult. Therefore I try to provide a small hint to the user. Limitations =========== * The current implementation only takes the magic number into account, therefore it may result in false positives. * Due to the nature of the optimization, the given hint may be off by a power of two. Fixing this would require to analyse the following shift instructions. * The hint is only shown in the line containing the magic number. The user still has to know which of the following instructions belong to the optimization. TODO ==== * Implement the corresponding analysis for unsigned integers * Implement the corresponding analysis for 64-bit integers. * Improve the heuristic by also looking at the next few instructions. ( I don't really know how to iterate over the instructions in the disassember in a non-deprecated way. Maybe someone can drop me a hint? ) * Implement an exact analysis using the actual dataflow in radeco and use it to revert the optimization. ( I suppose this is outside the scope of radare )
2016-06-15 13:18:04 +00:00
ds->show_hints = r_config_get_i (core->config, "asm.hints");
ds->show_marks = r_config_get_i (core->config, "asm.marks");
2014-04-23 02:19:21 +00:00
ds->pre = strdup (" ");
2014-01-20 00:42:16 +00:00
ds->ocomment = NULL;
ds->linesopts = 0;
ds->lastfail = 0;
ds->oldbits = 0;
ds->ocols = 0;
ds->lcols = 0;
ds->esil_old_pc = UT64_MAX;
ds->esil_regstate = NULL;
2016-06-08 21:33:31 +00:00
ds->esil_likely = false;
if (ds->show_flag_in_bytes) {
ds->show_flags = 0;
}
if (r_config_get_i (core->config, "asm.lineswide")) {
2014-01-20 00:42:16 +00:00
ds->linesopts |= R_ANAL_REFLINE_TYPE_WIDE;
}
if (core->cons->vline) {
2016-08-16 11:38:40 +00:00
if (ds->show_utf8) {
ds->linesopts |= R_ANAL_REFLINE_TYPE_UTF8;
2016-08-16 11:38:40 +00:00
}
}
2016-09-23 14:28:48 +00:00
if (ds->show_lines) {
ds->ocols += 10; // XXX
}
if (ds->show_offset) {
ds->ocols += 14;
}
2016-10-20 23:24:40 +00:00
ds->lcols = ds->ocols + 2;
2016-09-23 14:28:48 +00:00
if (ds->show_bytes) {
ds->ocols += 20;
}
if (ds->show_trace) {
ds->ocols += 8;
}
if (ds->show_stackptr) {
ds->ocols += 4;
}
2014-01-20 00:42:16 +00:00
/* disasm */ ds->ocols += 20;
2016-10-20 23:24:40 +00:00
ds->nb = ds->nbytes? (1 + ds->nbytes * 2): 0;
2014-01-20 00:42:16 +00:00
ds->tries = 3;
if (core->print->cur_enabled) {
if (core->print->cur < 0) {
core->print->cur = 0;
}
2014-01-20 00:42:16 +00:00
ds->cursor = core->print->cur;
} else {
ds->cursor = -1;
}
if (r_config_get_i (core->config, "asm.lineswide")) {
2014-01-20 00:42:16 +00:00
ds->linesopts |= R_ANAL_REFLINE_TYPE_WIDE;
}
if (core->cons->vline) {
2016-10-20 23:24:40 +00:00
if (ds->show_utf8) {
ds->linesopts |= R_ANAL_REFLINE_TYPE_UTF8;
}
}
2014-01-20 00:42:16 +00:00
return ds;
}
static ut64 lastaddr = UT64_MAX;
2016-05-30 10:35:39 +00:00
static void ds_reflines_fini(RDisasmState *ds) {
RAnal *anal = ds->core->anal;
2016-04-03 21:52:36 +00:00
r_list_free (anal->reflines);
r_list_free (anal->reflines2);
anal->reflines = NULL;
anal->reflines2 = NULL;
2016-04-03 22:17:57 +00:00
R_FREE (ds->refline);
R_FREE (ds->refline2);
2016-04-03 21:52:36 +00:00
}
2016-05-30 10:35:39 +00:00
static void ds_reflines_init(RDisasmState *ds) {
RAnal *anal = ds->core->anal;
lastaddr = UT64_MAX;
2016-05-30 10:35:39 +00:00
2014-01-20 00:42:16 +00:00
if (ds->show_lines) {
2016-05-30 10:35:39 +00:00
ds_reflines_fini (ds);
anal->reflines = r_anal_reflines_get (anal,
ds->addr, ds->buf, ds->len, ds->l,
ds->linesout, ds->show_lines_call);
anal->reflines2 = r_anal_reflines_get (anal,
ds->addr, ds->buf, ds->len, ds->l,
2014-01-20 00:42:16 +00:00
ds->linesout, 1);
2016-04-03 22:52:45 +00:00
} else {
r_list_free (anal->reflines);
r_list_free (anal->reflines2);
anal->reflines = anal->reflines2 = NULL;
}
}
2016-05-30 10:35:39 +00:00
static void ds_reflines_fcn_init(RDisasmState *ds, RAnalFunction *fcn, const ut8* buf) {
RCore *core = ds->core;
RAnal *anal = core->anal;
if (ds->show_lines) {
// TODO: make anal->reflines implicit
free (anal->reflines); // TODO: leak
2016-09-23 14:28:48 +00:00
anal->reflines = r_anal_reflines_fcn_get (anal, fcn, -1, ds->linesout, ds->show_lines_call);
free (anal->reflines2); // TODO: leak
2016-09-23 14:28:48 +00:00
anal->reflines2 = r_anal_reflines_fcn_get (anal, fcn, -1, ds->linesout, 1);
} else {
2016-04-03 22:52:45 +00:00
r_list_free (anal->reflines);
r_list_free (anal->reflines2);
anal->reflines = anal->reflines2 = NULL;
}
}
2016-05-30 10:35:39 +00:00
static void ds_free(RDisasmState *ds) {
2014-01-20 00:42:16 +00:00
if (!ds) return;
2016-05-30 10:35:39 +00:00
RCore *core = ds->core;
2014-01-20 00:42:16 +00:00
if (core && ds->oldbits) {
r_config_set_i (core->config, "asm.bits", ds->oldbits);
ds->oldbits = 0;
}
2014-01-20 00:42:16 +00:00
r_anal_op_fini (&ds->analop);
2015-09-28 09:21:23 +00:00
r_anal_hint_free (ds->hint);
2014-01-20 00:42:16 +00:00
free (ds->comment);
free (ds->pre);
free (ds->line);
free (ds->refline);
free (ds->refline2);
free (ds->opstr);
free (ds->osl);
free (ds->sl);
free (ds->_tabsbuf);
2014-01-20 00:42:16 +00:00
free (ds);
}
2016-05-30 10:35:39 +00:00
static void ds_set_pre(RDisasmState *ds, const char * str) {
if (!ds->show_fcnlines) {
if (ds->pre && !*ds->pre) {
return;
}
str = "";
}
2014-01-20 00:42:16 +00:00
free (ds->pre);
ds->pre = strdup (str);
}
/* XXX move to r_print */
static char *colorize_asm_string(RCore *core, RDisasmState *ds) {
char *spacer = NULL;
char *source = ds->opstr? ds->opstr: ds->asmop.buf_asm;
if (!ds->show_color || !ds->colorop) {
2015-10-20 21:37:20 +00:00
return strdup (source);
}
r_cons_strcat (r_print_color_op_type (core->print, ds->analop.type));
// workaround dummy colorizer in case of paired commands (tms320 & friends)
spacer = strstr (source, "||");
if (spacer) {
char *scol1, *s1 = r_str_ndup (source, spacer - source);
char *scol2, *s2 = strdup (spacer + 2);
2015-10-20 21:37:20 +00:00
scol1 = r_print_colorize_opcode (s1, ds->color_reg, ds->color_num);
free (s1);
scol2 = r_print_colorize_opcode (s2, ds->color_reg, ds->color_num);
free (s2);
2016-09-23 14:28:48 +00:00
if (!scol1) {
scol1 = strdup ("");
}
if (!scol2) {
scol2 = strdup ("");
}
2016-10-26 23:42:00 +00:00
source = malloc (strlen (scol1) + strlen (scol2) + 2 + 1); // reuse source variable
sprintf (source, "%s||%s", scol1, scol2);
free (scol1);
free (scol2);
return source;
}
return r_print_colorize_opcode (source, ds->color_reg, ds->color_num);
}
2016-05-30 10:35:39 +00:00
static void ds_build_op_str(RDisasmState *ds) {
RCore *core = ds->core;
if (!ds->opstr) {
ds->opstr = strdup (ds->asmop.buf_asm);
}
/* initialize */
core->parser->hint = ds->hint;
if (ds->varsub && ds->opstr) {
RAnalFunction *f = r_anal_get_fcn_in (core->anal,
ds->at, R_ANAL_FCN_TYPE_NULL);
core->parser->varlist = r_anal_var_list_dynamic;
2015-11-19 22:12:08 +00:00
r_parse_varsub (core->parser, f, ds->at, ds->analop.size,
ds->opstr, ds->strsub, sizeof (ds->strsub));
2015-02-07 23:30:25 +00:00
if (*ds->strsub) {
free (ds->opstr);
ds->opstr = strdup (ds->strsub);
}
}
2016-10-26 23:42:00 +00:00
char *asm_str = colorize_asm_string (core, ds);
2014-01-20 00:42:16 +00:00
if (ds->decode) {
char *tmpopstr = r_anal_op_to_string (core->anal, &ds->analop);
// TODO: Use data from code analysis..not raw ds->analop here
// if we want to get more information
ds->opstr = tmpopstr? tmpopstr: asm_str? strdup (asm_str): strdup ("");
2015-03-30 10:52:04 +00:00
} else {
if (ds->hint && ds->hint->opcode) {
free (ds->opstr);
ds->opstr = strdup (ds->hint->opcode);
}
if (ds->filter) {
int ofs = core->parser->flagspace;
int fs = ds->flagspace_ports;
if (ds->analop.type == R_ANAL_OP_TYPE_IO) {
core->parser->notin_flagspace = -1;
core->parser->flagspace = fs;
} else {
2015-03-30 10:52:04 +00:00
if (fs != -1) {
core->parser->notin_flagspace = fs;
core->parser->flagspace = fs;
} else {
core->parser->notin_flagspace = -1;
core->parser->flagspace = -1;
}
}
2016-09-23 14:28:48 +00:00
r_parse_filter (core->parser, core->flags, asm_str, ds->str, sizeof (ds->str), core->print->big_endian);
2015-03-30 10:52:04 +00:00
core->parser->flagspace = ofs;
free (ds->opstr);
ds->opstr = strdup (ds->str);
core->parser->flagspace = ofs; // ???
} else {
if (!ds->opstr) {
ds->opstr = strdup (asm_str? asm_str: "");
}
2015-03-30 10:52:04 +00:00
}
}
2014-01-20 00:42:16 +00:00
if (ds->use_esil) {
if (*R_STRBUF_SAFEGET (&ds->analop.esil)) {
free (ds->opstr);
ds->opstr = strdup (R_STRBUF_SAFEGET (&ds->analop.esil));
} else {
char *p = malloc (strlen (ds->opstr) + 6); /* What's up '\0' ? */
if (p) {
strcpy (p, "TODO,");
strcpy (p + 5, ds->opstr);
free (ds->opstr);
ds->opstr = p;
}
}
}
free (asm_str);
}
//removed hints bits from since r_anal_build_range_on_hints along with
//r_core_seek_archbits will be used instead. The ranges are built from hints
R_API RAnalHint *r_core_hint_begin(RCore *core, RAnalHint* hint, ut64 at) {
static char *hint_arch = NULL;
static char *hint_syntax = NULL;
2015-09-28 09:21:23 +00:00
r_anal_hint_free (hint);
hint = r_anal_hint_get (core->anal, at);
if (hint_arch) {
r_config_set (core->config, "asm.arch", hint_arch);
hint_arch = NULL;
}
if (hint_syntax) {
r_config_set (core->config, "asm.syntax", hint_syntax);
hint_syntax = NULL;
}
if (hint) {
/* arch */
if (hint->arch) {
2016-09-23 14:28:48 +00:00
if (!hint_arch) {
hint_arch = strdup (r_config_get (core->config, "asm.arch"));
}
r_config_set (core->config, "asm.arch", hint->arch);
}
/* arch */
if (hint->syntax) {
2016-09-23 14:28:48 +00:00
if (!hint_syntax) {
hint_syntax = strdup (r_config_get (core->config, "asm.syntax"));
}
r_config_set (core->config, "asm.syntax", hint->syntax);
}
}
return hint;
}
2016-05-30 10:35:39 +00:00
static void ds_beginline(RDisasmState *ds, RAnalFunction *f, bool nopre) {
const char *pre;
2016-05-30 10:35:39 +00:00
ds_setup_pre(ds, false, false);
pre = ds->pre;
if (nopre) {
2016-09-23 14:28:48 +00:00
if (*pre == '/' || *pre == '\\') {
pre = " ";
2016-09-23 14:28:48 +00:00
}
}
if (ds->show_functions && ds->show_fcnlines) {
if (*pre == '\\') {
2016-05-30 10:35:39 +00:00
ds_set_pre (ds, ds->core->cons->vline[LINE_VERT]);
}
2016-05-30 10:35:39 +00:00
ds_print_pre (ds);
}
char *tmp = ds->line;
ds->line = ds->refline2;
2016-05-30 10:35:39 +00:00
ds_print_lines_left (ds);
ds->line = tmp;
}
2016-05-30 10:35:39 +00:00
static void ds_pre_xrefs(RDisasmState *ds) {
RCore *core = ds->core;
if (ds->show_fcnlines) {
2016-05-30 10:35:39 +00:00
ds_setup_pre (ds, false, false);
if (*ds->pre != ' '){
2016-10-06 01:13:02 +00:00
ds_set_pre (ds, core->cons->vline[LINE_VERT]);
ds->pre = r_str_concat (ds->pre, " ");
}
}
2016-05-30 10:35:39 +00:00
ds_print_pre (ds);
char *tmp = ds->line;
ds->line = ds->refline2;
2016-05-30 10:35:39 +00:00
ds_print_lines_left (ds);
ds->line = tmp;
}
static void ds_show_refs(RDisasmState *ds) {
RList *list;
RAnalRef *ref;
RListIter *iter;
RFlagItem *flagi, *flagat;
char *cmt;
if (!ds->show_cmtrefs) {
return;
}
list = r_anal_xrefs_get_from (ds->core->anal, ds->at);
r_list_foreach (list, iter, ref) {
cmt = r_meta_get_string (ds->core->anal, R_META_TYPE_COMMENT, ref->addr);
flagi = r_flag_get_i (ds->core->flags, ref->addr);
flagat = r_flag_get_at (ds->core->flags, ref->addr);
ds_align_comment (ds);
if (ds->show_color) {
r_cons_strcat (ds->color_comment);
}
if (flagi && flagat && (strcmp (flagi->name, flagat->name) != 0)) {
r_cons_printf (" ; (%s)", flagi->name);
}
if (cmt) {
r_cons_printf (" ; (%s)", cmt);
}
if (ref->type & R_ANAL_REF_TYPE_CALL) {
RAnalOp aop;
ut8 buf[12];
r_core_read_at (ds->core, ref->at, buf, sizeof (buf));
r_anal_op (ds->core->anal, &aop, ref->at, buf, sizeof (buf));
2016-09-22 16:06:10 +00:00
if ((aop.type & R_ANAL_OP_TYPE_MASK) == R_ANAL_OP_TYPE_UCALL) {
RAnalFunction * fcn = r_anal_get_fcn_at (ds->core->anal,
ref->addr, R_ANAL_FCN_TYPE_NULL);
if (fcn) {
r_cons_printf (" ; %s", fcn->name);
} else {
r_cons_printf (" ; 0x%" PFMT64x, ref->addr);
}
}
}
ds_print_color_reset (ds);
}
}
2016-05-30 10:35:39 +00:00
static void ds_show_xrefs(RDisasmState *ds) {
RList *xrefs;
RAnalRef *refi;
RListIter *iter;
2016-05-30 10:35:39 +00:00
RCore *core = ds->core;
2016-02-07 20:44:35 +00:00
bool demangle = r_config_get_i (core->config, "bin.demangle");
const char *lang = demangle ? r_config_get (core->config, "bin.lang") : NULL;
char *name, *tmp;
int count = 0;
2016-09-23 14:28:48 +00:00
if (!ds->show_xrefs) {
2016-02-07 20:44:35 +00:00
return;
2016-09-23 14:28:48 +00:00
}
if (!ds->show_comments) {
2016-02-07 20:44:35 +00:00
return;
2016-09-23 14:28:48 +00:00
}
/* show xrefs */
xrefs = r_anal_xref_get (core->anal, ds->at);
2016-09-23 14:28:48 +00:00
if (!xrefs) {
return;
}
if (r_list_length (xrefs) > ds->maxrefs) {
int cols = r_cons_get_size (NULL);
cols -= 15;
cols /= 23;
2016-05-30 10:35:39 +00:00
ds_pre_xrefs (ds);
2016-09-23 14:28:48 +00:00
r_cons_printf ("%s; XREFS: ", ds->show_color? ds->pal_comment: "");
r_list_foreach (xrefs, iter, refi) {
r_cons_printf ("%s 0x%08"PFMT64x" ",
r_anal_xrefs_type_tostring (refi->type), refi->addr);
if (count == cols) {
if (iter->n) {
2016-05-30 10:35:39 +00:00
ds_print_color_reset (ds);
r_cons_newline ();
2016-05-30 10:35:39 +00:00
ds_pre_xrefs (ds);
2016-09-23 14:28:48 +00:00
r_cons_printf ("%s; XREFS: ", ds->show_color? ds->pal_comment: "");
}
count = 0;
2016-09-23 14:28:48 +00:00
} else {
count++;
}
}
2016-05-30 10:35:39 +00:00
ds_print_color_reset (ds);
r_cons_newline ();
r_list_free (xrefs);
return;
}
r_list_foreach (xrefs, iter, refi) {
if (refi->at == ds->at) {
RAnalFunction *fun = r_anal_get_fcn_in (
core->anal, refi->addr, -1);
2016-02-07 20:44:35 +00:00
name = strdup (fun ? fun->name : "unk");
if (demangle) {
tmp = r_bin_demangle (core->bin->cur, lang, name);
if (tmp) {
free (name);
2016-05-24 20:22:15 +00:00
name = tmp;
2016-02-07 20:44:35 +00:00
}
}
2016-05-30 10:35:39 +00:00
ds_pre_xrefs (ds);
r_cons_printf ("%s; %s XREF from 0x%08"PFMT64x" (%s)%s\n",
COLOR (ds, pal_comment),
r_anal_xrefs_type_tostring (refi->type),
refi->addr,
2016-02-07 20:44:35 +00:00
name,
COLOR_RESET (ds));
2016-02-07 20:44:35 +00:00
R_FREE (name);
}
}
r_list_free (xrefs);
}
2016-05-30 10:35:39 +00:00
static void ds_atabs_option(RDisasmState *ds) {
int n, i = 0, comma = 0, word = 0;
int size, brackets = 0;
char *t, *b;
2016-09-23 14:28:48 +00:00
if (!ds || !ds->atabs) {
return;
2016-09-23 14:28:48 +00:00
}
size = strlen (ds->asmop.buf_asm) * (ds->atabs + 1) * 4;
2016-09-26 22:00:09 +00:00
if (size < 1 || size < strlen (ds->asmop.buf_asm)) {
return;
2016-09-23 14:28:48 +00:00
}
free (ds->opstr);
2016-09-26 22:00:09 +00:00
ds->opstr = b = malloc (size + 1);
strncpy (b, ds->asmop.buf_asm, R_MIN (size, R_ASM_BUFSIZE));
b[size] = 0;
for (; *b; b++, i++) {
2016-09-26 22:00:09 +00:00
if (*b == '(' || *b == '[') {
2016-09-23 14:28:48 +00:00
brackets++;
}
2016-09-26 22:00:09 +00:00
if (*b == ')' || *b == ']') {
2016-09-23 14:28:48 +00:00
brackets--;
}
2016-09-26 22:00:09 +00:00
if (*b == ',') {
2016-09-23 14:28:48 +00:00
comma = 1;
}
2016-09-26 22:00:09 +00:00
if (*b != ' ') {
2016-09-23 14:28:48 +00:00
continue;
}
if (word > 0 && !comma) {
continue; //&& b[1]=='[') continue;
}
if (brackets > 0) {
continue;
}
comma = 0;
brackets = 0;
n = (ds->atabs-i);
2016-09-26 22:00:09 +00:00
t = strdup (b + 1); //XXX slow!
2016-09-23 14:28:48 +00:00
if (n < 1) {
n = 1;
}
memset (b, ' ', n);
b += n;
strcpy (b, t);
free (t);
i = 0;
word++;
if (ds->atabsonce) {
break;
}
}
}
static int handleMidFlags(RCore *core, RDisasmState *ds, bool print) {
RFlagItem *fi;
int i;
for (i = 1; i < ds->oplen; i++) {
fi = r_flag_get_i (core->flags, ds->at + i);
if (fi) {
2016-06-13 23:52:46 +00:00
if (!strncmp (fi->name, "str.", 4)) {
ds->midflags = R_MIDFLAGS_REALIGN;
return i;
}
if (!strncmp (fi->name, "reloc.", 6)) {
if (print) {
r_cons_printf ("(%s)\n", fi->name);
}
continue;
}
2016-11-02 11:10:50 +00:00
if (ds->midflags == R_MIDFLAGS_SYMALIGN) {
if (!strncmp (fi->name, "sym.", 4)) {
return i;
}
continue;
}
return i;
}
}
return 0;
}
2016-05-30 10:35:39 +00:00
static void ds_print_show_cursor(RDisasmState *ds) {
RCore *core = ds->core;
char res[] = " ";
void *p;
int q, t;
2016-09-23 14:28:48 +00:00
if (!ds->show_marks) {
return;
2016-09-23 14:28:48 +00:00
}
q = core->print->cur_enabled &&
2014-05-04 15:21:05 +00:00
ds->cursor >= ds->index &&
ds->cursor < (ds->index + ds->asmop.size);
p = r_bp_get_at (core->dbg->bp, ds->at);
t = ds->midflags && handleMidFlags (core, ds, false) > 0;
2016-09-23 14:28:48 +00:00
if (p) {
res[0] = 'b';
}
if (t) {
res[1] = '~';
}
if (q) {
if (ds->cursor == ds->index) {
res[2] = '*';
} else {
int i = 2, diff = ds->cursor - ds->index;
2016-09-23 14:28:48 +00:00
if (diff > 9) {
res[i++] = '0' + (diff / 10);
}
res[i] = '0' + (diff % 10);
}
}
r_cons_strcat (res);
}
static int var_comparator(const RAnalVar *a, const RAnalVar *b){
2016-09-23 14:28:48 +00:00
if (a && b) {
return a->delta > b->delta;
}
2015-09-14 10:35:38 +00:00
return false;
2015-03-30 14:03:11 +00:00
}
2016-09-09 17:28:47 +00:00
//TODO: this function is a temporary fix. All analysis should be based on realsize. However, now for same architectures realisze is not used
2016-09-13 22:22:43 +00:00
static ut32 tmp_get_realsize (RAnalFunction *f) {
2016-09-09 17:28:47 +00:00
ut32 size = r_anal_fcn_realsize (f);
2016-09-13 22:22:43 +00:00
return (size > 0) ? size : r_anal_fcn_size (f);
2016-09-09 17:28:47 +00:00
}
2016-05-30 10:35:39 +00:00
static void ds_show_functions(RDisasmState *ds) {
RAnalFunction *f;
2016-05-30 10:35:39 +00:00
RCore *core = ds->core;
2016-05-14 09:04:07 +00:00
bool demangle, call;
2016-02-16 01:08:09 +00:00
const char *lang;
2016-02-07 20:44:35 +00:00
char *fcn_name;
char *sign;
2016-05-30 10:35:39 +00:00
if (!ds->show_functions) {
return;
}
2016-02-16 01:08:09 +00:00
demangle = r_config_get_i (core->config, "bin.demangle");
2016-05-14 09:04:07 +00:00
call = r_config_get_i (core->config, "asm.calls");
2016-02-16 01:08:09 +00:00
lang = demangle ? r_config_get (core->config, "bin.lang") : NULL;
f = r_anal_get_fcn_in (core->anal, ds->at, R_ANAL_FCN_TYPE_NULL);
if (!f || (f->addr != ds->at)) {
return;
}
2016-02-07 20:44:35 +00:00
if (demangle) {
fcn_name = r_bin_demangle (core->bin->cur, lang, f->name);
2016-09-23 14:28:48 +00:00
if (!fcn_name) {
2016-02-07 20:44:35 +00:00
fcn_name = strdup (f->name);
2016-09-23 14:28:48 +00:00
}
2016-02-07 20:44:35 +00:00
} else {
fcn_name = f->name;
}
sign = r_anal_fcn_to_string (core->anal, f);
if (f->type == R_ANAL_FCN_TYPE_LOC) {
r_cons_printf ("%s%s ", COLOR (ds, color_fline),
core->cons->vline[LINE_CROSS]); // |-
r_cons_printf ("%s%s%s %d\n", COLOR (ds, color_floc),
fcn_name, COLOR_RESET (ds), r_anal_fcn_size (f));
} else {
const char *space = ds->show_fcnlines ? " " : "";
const char *fcntype;
char cmt[32];
get_bits_comment (core, f, cmt, sizeof (cmt));
switch (f->type) {
case R_ANAL_FCN_TYPE_FCN:
case R_ANAL_FCN_TYPE_SYM:
fcntype = "fcn"; break;
case R_ANAL_FCN_TYPE_IMP:
fcntype = "imp"; break;
default:
fcntype = "loc"; break;
}
2014-12-14 22:08:05 +00:00
#if SLOW_BUT_OK
int corner = (f->size <= ds->analop.size) ? RDWN_CORNER : LINE_VERT;
corner = LINE_VERT; // 99% of cases
RFlagItem *item = r_flag_get_i (core->flags, f->addr);
corner = item ? LINE_VERT : RDWN_CORNER;
if (item) {
corner = 0;
}
2014-01-20 00:42:16 +00:00
#endif
2016-10-20 23:24:40 +00:00
ds_set_pre (ds, core->cons->vline[CORNER_TL]);
if (ds->show_flgoff) {
r_cons_printf ("%s%s", COLOR (ds, color_fline), ds->pre);
if (ds->show_fcnlines) {
r_cons_printf (" ");
}
2016-05-30 10:35:39 +00:00
ds_print_lines_left (ds);
ds_print_offset (ds);
r_cons_printf ("%s%s%s(%s) %s%s%s %d\n",
space, COLOR_RESET (ds), COLOR (ds, color_fname),
2016-09-09 17:28:47 +00:00
fcntype, fcn_name, cmt, COLOR_RESET (ds), tmp_get_realsize (f));
} else {
r_cons_printf ("%s%s%s%s%s(%s) %s%s%s %d\n",
COLOR (ds, color_fline), ds->pre,
space, COLOR_RESET (ds), COLOR (ds, color_fname),
2016-09-09 17:28:47 +00:00
fcntype, fcn_name, cmt, COLOR_RESET (ds), tmp_get_realsize (f));
}
}
2016-09-23 14:28:48 +00:00
if (sign) {
2016-02-07 20:44:35 +00:00
r_cons_printf ("// %s\n", sign);
2016-09-23 14:28:48 +00:00
}
R_FREE (sign);
2016-05-30 10:35:39 +00:00
ds_set_pre (ds, core->cons->vline[LINE_VERT]);
if (ds->show_fcnlines) {
2016-02-07 20:44:35 +00:00
ds->pre = r_str_concat (ds->pre, " ");
}
ds->stackptr = 0;
if (ds->show_vars) {
char spaces[32];
2016-05-14 09:04:07 +00:00
RAnalVar *var;
RListIter *iter;
RList *args = r_anal_var_list (core->anal, f, 'b');
RList *regs = r_anal_var_list (core->anal, f, 'r');
RList *sp_vars = r_anal_var_list (core->anal, f, 's');
2015-03-30 22:49:45 +00:00
r_list_sort (args, (RListComparator)var_comparator);
r_list_sort (regs, (RListComparator)var_comparator);
r_list_sort (sp_vars, (RListComparator)var_comparator);
2016-05-14 09:04:07 +00:00
if (call) {
r_cons_printf ("%s%s%s %s %s%s (",
COLOR (ds, color_fline), ds->pre,
COLOR_RESET (ds), COLOR (ds, color_fname),
fcn_name, COLOR_RESET (ds));
bool comma = true;
bool arg_bp = false;
int tmp_len;
r_list_foreach (regs, iter, var) {
tmp_len = strlen (var->type);
r_cons_printf ("%s%s%s%s", var->type,
tmp_len && var->type[tmp_len - 1] == '*' ? "" : " ",
var->name, iter->n ? ", " : "");
}
2016-05-14 09:04:07 +00:00
r_list_foreach (args, iter, var) {
if (var->delta > 0) {
if (!r_list_empty (regs) && comma) {
r_cons_printf (", ");
comma = false;
}
arg_bp = true;
tmp_len = strlen (var->type);
r_cons_printf ("%s%s%s%s", var->type,
tmp_len && var->type[tmp_len - 1] =='*' ? "" : " ",
var->name, iter->n ? ", " : "");
}
}
comma = true;
r_list_foreach (sp_vars, iter, var) {
if (var->delta > f->stack) {
2016-09-23 14:28:48 +00:00
if ((arg_bp || !r_list_empty (regs)) && comma) {
comma = false;
r_cons_printf (", ");
}
tmp_len = strlen (var->type);
r_cons_printf ("%s%s%s%s", var->type,
tmp_len && var->type[tmp_len - 1] =='*' ? "" : " ",
var->name, iter->n ? ", " : "");
}
2016-05-14 09:04:07 +00:00
}
r_cons_printf (");\n");
}
r_list_join (args, sp_vars);
r_list_join (args, regs);
2015-03-30 14:03:11 +00:00
r_list_foreach (args, iter, var) {
char *tmp;
int idx;
RAnal *anal = ds->core->anal;
memset (spaces, ' ', sizeof(spaces));
idx = 12 - strlen (var->name);
2016-09-23 14:28:48 +00:00
if (idx < 0) {
idx = 0;
}
spaces[idx] = 0;
2016-05-30 10:35:39 +00:00
ds_setup_print_pre (ds, false, true);
tmp = ds->line;
ds->line = ds->refline2;
2016-05-30 10:35:39 +00:00
ds_print_lines_left (ds);
ds->line = tmp;
2016-04-04 22:56:48 +00:00
if (ds->show_flgoff) {
2016-05-30 10:35:39 +00:00
ds_print_offset (ds);
r_cons_printf (" ");
2016-04-04 22:56:48 +00:00
}
r_cons_printf ("%s; ", COLOR (ds, color_other));
switch (var->kind) {
case 'b':
if (var->delta > 0) {
r_cons_printf ("arg %s %s @ %s+0x%x",
var->type, var->name,
anal->reg->name[R_REG_NAME_BP],
var->delta);
} else {
r_cons_printf ("var %s %s @ %s-0x%x",
var->type, var->name,
anal->reg->name[R_REG_NAME_BP],
-var->delta);
}
break;
case 'r': {
RRegItem *i = r_reg_index_get (anal->reg, var->delta);
if (!i) {
eprintf("Register not found");
break;
}
r_cons_printf ("reg %s %s @ %s",
var->type, var->name, i->name);
}
break;
case 's':
if ( var->delta < f->stack) {
r_cons_printf ("var %s %s @ %s+0x%x",
var->type, var->name,
anal->reg->name[R_REG_NAME_SP],
var->delta);
} else {
r_cons_printf ("arg %s %s @ %s+0x%x",
var->type, var->name,
anal->reg->name[R_REG_NAME_SP],
var->delta);
}
break;
}
char *comment = r_meta_get_var_comment (anal, var->kind, var->delta, f->addr);
if (comment) {
2016-06-13 11:09:46 +00:00
r_cons_printf (" %s; %s", COLOR(ds,color_comment),comment);
}
r_cons_println (COLOR_RESET (ds));
2014-12-18 11:54:36 +00:00
}
r_list_free (regs);
// it's already empty, but rlist instance is still there
r_list_free (args);
r_list_free (sp_vars);
}
if (demangle) {
2016-02-07 20:44:35 +00:00
free (fcn_name);
}
}
2016-05-30 10:35:39 +00:00
static void ds_setup_print_pre(RDisasmState *ds, bool tail, bool middle) {
ds_setup_pre (ds, tail, middle);
ds_print_pre (ds);
}
2016-05-30 10:35:39 +00:00
static void ds_setup_pre(RDisasmState *ds, bool tail, bool middle) {
RCore *core = ds->core;
RAnalFunction *f;
2016-05-30 10:35:39 +00:00
2016-09-23 14:28:48 +00:00
if (!ds->show_functions) {
return;
}
f = r_anal_get_fcn_in (core->anal, ds->at, R_ANAL_FCN_TYPE_NULL);
if (f) {
if (f->addr == ds->at) {
if (ds->analop.size == r_anal_fcn_size (f) && !middle) {
2016-10-20 23:24:40 +00:00
ds_set_pre (ds, core->cons->vline[CORNER_BL]);
} else {
2016-05-30 10:35:39 +00:00
ds_set_pre (ds, core->cons->vline[LINE_VERT]);
}
} else if (f->addr + r_anal_fcn_size (f) - ds->analop.size == ds->at) {
2016-10-20 23:24:40 +00:00
ds_set_pre (ds, core->cons->vline[CORNER_BL]);
} else if (r_anal_fcn_is_in_offset (f, ds->at)) {
2016-05-30 10:35:39 +00:00
ds_set_pre (ds, core->cons->vline[LINE_VERT]);
}
if (ds->show_fcnlines) {
ds->pre = r_str_concat (ds->pre, " ");
}
if (tail) {
r_str_replace_char (ds->pre, '\\', ' ');
r_str_replace_char (ds->pre, '|', '\\');
}
}
}
2016-05-30 10:35:39 +00:00
static void ds_print_pre(RDisasmState *ds) {
RCore *core = ds->core;
RAnalFunction *f;
2016-05-30 10:35:39 +00:00
if (!ds->show_functions) {
return;
}
f = r_anal_get_fcn_in (core->anal, ds->at, R_ANAL_FCN_TYPE_NULL);
if (f) {
r_cons_printf ("%s%s%s", COLOR (ds, color_fline),
ds->pre, COLOR_RESET (ds));
} else {
if (ds->show_lines) {
r_cons_printf (" ");
} else if (ds->show_fcnlines) {
r_cons_printf (" ");
}
}
}
2016-05-30 10:35:39 +00:00
static void ds_show_comments_right(RDisasmState *ds) {
int linelen, maxclen ;
2016-05-30 10:35:39 +00:00
RCore *core = ds->core;
RAnalFunction *f;
RFlagItem *item;
/* show comment at right? */
int scr = ds->show_comment_right;
2016-05-17 08:36:33 +00:00
if (!ds->show_comments) {
return;
2016-05-17 08:36:33 +00:00
}
f = r_anal_get_fcn_in (core->anal, ds->at, R_ANAL_FCN_TYPE_NULL);
item = r_flag_get_i (core->flags, ds->at);
ds->comment = r_meta_get_string (core->anal, R_META_TYPE_COMMENT, ds->at);
if (!ds->comment && item && item->comment && *item->comment) {
ds->ocomment = item->comment;
ds->comment = strdup (item->comment);
}
2016-05-17 08:36:33 +00:00
if (!ds->comment) {
return;
2016-05-17 08:36:33 +00:00
}
2016-09-23 14:28:48 +00:00
maxclen = strlen (ds->comment) + 5;
linelen = maxclen;
if (ds->show_comment_right_default) {
if (ds->ocols+maxclen < core->cons->columns) {
if (ds->comment && *ds->comment && strlen (ds->comment)<maxclen) {
2016-09-23 14:28:48 +00:00
if (!strchr (ds->comment, '\n')) { // more than one line?
ds->show_comment_right = 1;
2016-09-23 14:28:48 +00:00
}
}
}
}
if (!ds->show_comment_right) {
int infun, mycols = ds->lcols;
2016-09-23 14:28:48 +00:00
if (mycols + linelen + 10 > core->cons->columns) {
mycols = 0;
2016-09-23 14:28:48 +00:00
}
mycols /= 2;
2016-09-23 14:28:48 +00:00
if (ds->show_color) {
r_cons_strcat (ds->pal_comment);
}
#if OLD_COMMENTS
r_cons_strcat ("; ");
// XXX: always prefix with ; the comments
2016-09-23 14:28:48 +00:00
if (*ds->comment != ';') {
r_cons_strcat (" ; ");
}
r_cons_strcat_justify (ds->comment, mycols, ';');
#else
infun = f && (f->addr != ds->at);
if (infun) {
char *str = strdup (ds->show_color ? ds->color_fline : "");
str = r_str_concat (str, core->cons->vline[LINE_VERT]);
if (ds->show_color) {
str = r_str_concat (str, ds->color_flow);
}
// color refline
str = r_str_concat (str, " ");
str = r_str_concat (str, ds->refline2);
// color comment
if (ds->show_color) {
str = r_str_concat (str, ds->color_comment);
}
str = r_str_concat (str, "; ");
ds->comment = r_str_prefix_all (ds->comment, str);
free (str);
} else {
ds->comment = r_str_prefix_all (ds->comment, " ; ");
}
/* print multiline comment */
if (ds->cmtfold) {
char * p = strdup (ds->comment);
char *q = strchr (p, '\n');
if (q) {
*q = 0;
r_cons_strcat (p);
r_cons_strcat (" ; [z] unfold");
}
free (p);
} else {
r_cons_strcat (ds->comment);
}
#endif
2016-09-23 14:28:48 +00:00
if (ds->show_color) {
ds_print_color_reset (ds);
}
r_cons_newline ();
2016-05-30 10:35:39 +00:00
R_FREE (ds->comment);
/* flag one */
if (item && item->comment && ds->ocomment != item->comment) {
2016-09-23 14:28:48 +00:00
if (ds->show_color) {
r_cons_strcat (ds->pal_comment);
}
r_cons_newline ();
r_cons_strcat (" ; ");
r_cons_strcat_justify (item->comment, mycols, ';');
r_cons_newline ();
2016-09-23 14:28:48 +00:00
if (ds->show_color) {
ds_print_color_reset (ds);
}
}
}
ds->show_comment_right = scr;
}
2016-05-30 10:35:39 +00:00
static void ds_show_flags(RDisasmState *ds) {
//const char *beginch;
RFlagItem *flag;
RListIter *iter;
RAnalFunction *f;
const RList /*RFlagList*/ *flaglist;
//bool printed = false;
if (!ds->show_flags) {
return;
}
2016-05-30 10:35:39 +00:00
RCore *core = ds->core;
f = r_anal_get_fcn_in (core->anal, ds->at, R_ANAL_FCN_TYPE_NULL);
flaglist = r_flag_get_list (core->flags, ds->at);
r_list_foreach (flaglist, iter, flag) {
if (f && f->addr == flag->offset && !strcmp (flag->name, f->name)) {
// do not show flags that have the same name as the function
continue;
}
if (ds->show_flgoff) {
if (f) {
2016-05-30 10:35:39 +00:00
ds_beginline (ds, f, false);
} else {
2016-05-30 10:35:39 +00:00
ds_print_lines_left (ds);
2016-04-04 22:56:48 +00:00
r_cons_printf (" ");
}
2016-05-30 10:35:39 +00:00
ds_print_offset (ds);
r_cons_printf (" ");
} else {
r_cons_printf ((f && ds->at > f->addr)?"| ": " ");
2016-05-30 10:35:39 +00:00
ds_print_lines_left (ds);
r_cons_printf (";-- ");
}
if (ds->show_color)
r_cons_strcat (ds->color_flag);
//beginch = (iter->p && printed) ? ", " : "";
if (ds->asm_demangle && flag->realname) {
const char *lang = r_config_get (core->config, "bin.lang");
char *name = r_bin_demangle (core->bin->cur, lang, flag->realname);
r_cons_printf ("%s:\n", name? name: flag->realname);
R_FREE (name);
} else {
r_cons_printf ("%s:\n", flag->name);
}
//printed = true;
}
if (ds->show_spacy) {
if (!r_list_empty (flaglist)) {
ds_print_spacy(ds, false);
}
}
}
2016-05-30 10:35:39 +00:00
static void ds_update_ref_lines(RDisasmState *ds) {
2014-01-20 00:42:16 +00:00
if (ds->show_lines) {
2016-05-30 10:35:39 +00:00
ds->line = r_anal_reflines_str (ds->core, ds->at, ds->linesopts);
2016-04-03 22:17:57 +00:00
free (ds->refline);
2016-04-04 20:30:11 +00:00
ds->refline = ds->line? strdup (ds->line): NULL;
2016-04-03 22:17:57 +00:00
free (ds->refline2);
2016-05-30 10:35:39 +00:00
ds->refline2 = r_anal_reflines_str (ds->core, ds->at,
ds->linesopts | R_ANAL_REFLINE_TYPE_MIDDLE);
2015-08-30 21:34:21 +00:00
if (ds->line) {
2016-09-23 14:28:48 +00:00
if (strchr (ds->line, '<')) {
2015-08-30 21:34:21 +00:00
ds->indent_level++;
2016-09-23 14:28:48 +00:00
}
if (strchr (ds->line, '>')) {
2015-08-30 21:34:21 +00:00
ds->indent_level--;
2016-09-23 14:28:48 +00:00
}
2015-08-30 21:34:21 +00:00
} else {
ds->indent_level = 0;
}
} else {
2016-05-30 10:35:39 +00:00
R_FREE (ds->line);
2014-01-20 00:42:16 +00:00
free (ds->refline);
free (ds->refline2);
ds->refline = strdup ("");
ds->refline2 = strdup ("");
}
}
2016-05-30 10:35:39 +00:00
static int ds_disassemble(RDisasmState *ds, ut8 *buf, int len) {
RCore *core = ds->core;
2016-04-20 23:38:08 +00:00
int ret;
if (ds->hint && ds->hint->size) {
ds->oplen = ds->hint->size;
}
2016-04-20 23:38:08 +00:00
if (ds->hint && ds->hint->opcode) {
free (ds->opstr);
ds->opstr = strdup (ds->hint->opcode);
return true;
}
ret = r_asm_disassemble (core->assembler, &ds->asmop, buf, len);
if (ds->asmop.size < 1) {
ds->asmop.size = 1;
}
if (ds->show_nodup) {
const char *opname = (ret < 1)? "invalid": ds->asmop.buf_asm;
if (ds->prev_ins && !strcmp (ds->prev_ins, opname)) {
if (!ds->prev_ins_eq) {
ds->prev_ins_eq = true;
r_cons_printf ("...");
}
ds->prev_ins_count ++;
return -31337;
}
if (ds->prev_ins_eq) {
r_cons_printf ("dup (%d)\n", ds->prev_ins_count);
}
ds->prev_ins_count = 0;
ds->prev_ins_eq = false;
if (ds->prev_ins) {
R_FREE (ds->prev_ins);
}
ds->prev_ins = strdup (ds->asmop.buf_asm);
}
2014-01-20 00:42:16 +00:00
ds->oplen = ds->asmop.size;
if (ret < 1) {
ret = -1;
#if HASRETRY
if (!ds->cbytes && ds->tries > 0) {
2014-01-20 00:42:16 +00:00
ds->addr = core->assembler->pc;
ds->tries--;
ds->idx = 0;
ds->retry = 1;
return ret;
}
#endif
2014-01-20 00:42:16 +00:00
ds->lastfail = 1;
2016-09-23 14:28:48 +00:00
ds->asmop.size = (ds->hint && ds->hint->size) ? ds->hint->size : 1;
ds->oplen = ds->asmop.size;
} else {
2014-01-20 00:42:16 +00:00
ds->lastfail = 0;
2016-09-23 14:28:48 +00:00
ds->asmop.size = (ds->hint && ds->hint->size) ? ds->hint->size : r_asm_op_get_size (&ds->asmop);
ds->oplen = ds->asmop.size;
}
2014-01-20 00:42:16 +00:00
if (ds->pseudo) {
2016-09-23 14:28:48 +00:00
r_parse_parse (core->parser, ds->opstr ? ds->opstr : ds->asmop.buf_asm, ds->str);
2014-01-20 00:42:16 +00:00
free (ds->opstr);
ds->opstr = strdup (ds->str);
}
2016-09-23 14:28:48 +00:00
if (ds->acase) {
r_str_case (ds->asmop.buf_asm, 1);
}
return ret;
}
2016-05-30 10:35:39 +00:00
static void ds_control_flow_comments(RDisasmState *ds) {
2014-01-20 00:42:16 +00:00
if (ds->show_comments && ds->show_cmtflgrefs) {
RFlagItem *item;
2014-01-20 00:42:16 +00:00
switch (ds->analop.type) {
case R_ANAL_OP_TYPE_JMP:
case R_ANAL_OP_TYPE_CJMP:
case R_ANAL_OP_TYPE_CALL:
2016-05-30 10:35:39 +00:00
item = r_flag_get_i (ds->core->flags, ds->analop.jump);
if (item && item->comment) {
2016-09-23 14:28:48 +00:00
if (ds->show_color) {
r_cons_strcat (ds->pal_comment);
}
2016-05-30 10:35:39 +00:00
ds_align_comment (ds);
r_cons_printf (" ; ref to %s: %s\n", item->name, item->comment);
2016-05-30 10:35:39 +00:00
ds_print_color_reset (ds);
}
break;
}
}
}
2016-05-30 10:35:39 +00:00
static void ds_print_lines_right(RDisasmState *ds){
2014-01-20 00:42:16 +00:00
if (ds->linesright && ds->show_lines && ds->line) {
r_cons_printf ("%s%s%s", COLOR (ds, color_flow), ds->line, COLOR_RESET (ds));
}
}
static void printCol(RDisasmState *ds, char *sect, int cols, const char *color) {
int pre, post;
if (cols < 8) cols = 8;
int outsz = cols + 32;
char *out = malloc (outsz);
2016-09-23 14:28:48 +00:00
if (!out) {
return;
}
memset (out, ' ', outsz);
int sect_len = strlen (sect);
if (sect_len > cols) {
sect[cols-2] = '.';
sect[cols-1] = '.';
sect[cols] = 0;
}
if (ds->show_color) {
pre = strlen (color) + 1;
post = strlen (color) + 1 + strlen (Color_RESET);
snprintf (out, outsz-pre, "%s %s", color, sect);
strcat (out, Color_RESET);
out[outsz-1] = 0;
} else {
strcpy (out + 1, sect);
pre = 1;
post = 0;
}
out[strlen (out)] = ' ';
out[cols + post] = 0;
r_cons_strcat (out);
free (out);
}
2016-05-30 10:35:39 +00:00
static void ds_print_lines_left(RDisasmState *ds) {
RCore *core = ds->core;
2014-11-22 04:39:52 +00:00
if (ds->show_section) {
2016-05-30 10:35:39 +00:00
char *sect = strdup (get_section_name (core, ds->at));
printCol (ds, sect, ds->show_section_col, ds->color_reg);
free (sect);
2014-11-22 04:39:52 +00:00
}
if (ds->show_symbols) {
static RFlagItem sfi = {0};
const char *name = "";
int delta = 0;
if (ds->fcn) {
sfi.offset = ds->fcn->addr;
sfi.name = ds->fcn->name;
ds->lastflag = &sfi;
} else {
RFlagItem *fi = r_flag_get_at (core->flags, ds->at);
if (fi) { // && (!ds->lastflag || fi->offset != ds->at)) {
sfi.offset = fi->offset;
sfi.name = fi->name;
ds->lastflag = &sfi;
}
}
if (ds->lastflag && ds->lastflag->name) {
name = ds->lastflag->name;
delta = ds->at - ds->lastflag->offset;
}
{
char * str = r_str_newf ("%s + %-4d", name, delta);
printCol (ds, str, ds->show_symbols_col, ds->color_num);
free (str);
}
}
2014-01-20 00:42:16 +00:00
if (!ds->linesright && ds->show_lines && ds->line) {
r_cons_printf ("%s%s%s", COLOR (ds, color_flow), ds->line, COLOR_RESET (ds));
}
}
2016-05-30 10:35:39 +00:00
static void ds_print_family(RDisasmState *ds) {
2015-10-03 11:52:52 +00:00
if (ds->show_family) {
const char *familystr = r_anal_op_family_to_string (ds->analop.family);
r_cons_printf ("%5s ", familystr);
}
}
2016-05-30 10:35:39 +00:00
static void ds_print_cycles(RDisasmState *ds) {
if (ds->show_cycles) {
2016-09-23 14:28:48 +00:00
if (!ds->analop.failcycles) {
r_cons_printf ("%3d ", ds->analop.cycles);
2016-09-23 14:28:48 +00:00
} else {
r_cons_printf ("%3d %3d ", ds->analop.cycles, ds->analop.failcycles);
}
}
if (ds->cyclespace) {
char spaces [32];
int times = R_MIN (ds->analop.cycles/4, 30); // limit to 30
memset (spaces, ' ', sizeof (spaces));
spaces[times] = 0;
r_cons_strcat (spaces);
}
2014-02-10 22:01:19 +00:00
}
2016-05-30 10:35:39 +00:00
static void ds_print_stackptr(RDisasmState *ds) {
2014-01-20 00:42:16 +00:00
if (ds->show_stackptr) {
r_cons_printf ("%5d%s", ds->stackptr,
ds->analop.type == R_ANAL_OP_TYPE_CALL?">":
ds->analop.stackop == R_ANAL_STACK_ALIGN? "=":
ds->stackptr > ds->ostackptr? "+":
ds->stackptr < ds->ostackptr? "-": " ");
2014-01-20 00:42:16 +00:00
ds->ostackptr = ds->stackptr;
switch (ds->analop.stackop) {
case R_ANAL_STACK_RESET:
ds->stackptr = 0;
break;
case R_ANAL_STACK_INC:
ds->stackptr += ds->analop.stackptr;
break;
}
/* XXX if we reset the stackptr 'ret 0x4' has not effect.
* Use RAnalFunction->RAnalOp->stackptr? */
2014-01-20 00:42:16 +00:00
if (ds->analop.type == R_ANAL_OP_TYPE_RET)
ds->stackptr = 0;
}
}
2016-05-30 10:35:39 +00:00
static void ds_print_offset(RDisasmState *ds) {
RCore *core = ds->core;
r_print_set_screenbounds (core->print, ds->at);
2015-01-11 23:11:06 +00:00
if (ds->show_offset) {
static RFlagItem sfi = {0};
const char *label = NULL;
RFlagItem *fi;
int delta = -1;
if (ds->show_reloff) {
RAnalFunction *f = r_anal_get_fcn_at (core->anal, ds->at, R_ANAL_FCN_TYPE_NULL);
if (!f) {
f = r_anal_get_fcn_in (core->anal, ds->at, R_ANAL_FCN_TYPE_NULL);
}
if (f) {
delta = ds->at - f->addr;
sfi.name = f->name;
sfi.offset = f->addr;
ds->lastflag = &sfi;
label = f->name;
} else {
if (ds->show_reloff_flags) {
/* XXX: this is wrong if starting to disasm after a flag */
fi = r_flag_get_i (core->flags, ds->at);
if (fi) {
ds->lastflag = fi;
}
if (ds->lastflag) {
if (ds->lastflag->offset == ds->at) {
delta = 0;
} else {
delta = ds->at - ds->lastflag->offset;
}
} else {
delta = ds->at - core->offset;
}
if (ds->lastflag) {
label = ds->lastflag->name;
}
}
}
if (!ds->lastflag) {
delta = 0;
}
}
r_print_offset (core->print, ds->at, (ds->at == ds->dest),
2016-11-01 22:30:36 +00:00
ds->show_offseg, ds->show_offdec, delta, label);
2015-01-11 23:11:06 +00:00
}
if (ds->atabsoff > 0) {
if (ds->_tabsoff != ds->atabsoff) {
char *b = ds->_tabsbuf;
// TODO optimize to avoid down resizing
b = malloc (ds->atabsoff + 1);
if (b) {
memset (b, ' ', ds->atabsoff);
b[ds->atabsoff] = 0;
free (ds->_tabsbuf);
ds->_tabsbuf = b;
ds->_tabsoff = ds->atabsoff;
}
}
r_cons_strcat (ds->_tabsbuf);
}
}
2016-05-30 10:35:39 +00:00
static void ds_print_op_size(RDisasmState *ds) {
if (ds->show_size) {
int size = ds->oplen;
r_cons_printf ("%d ", size); //ds->analop.size);
}
}
2016-05-30 10:35:39 +00:00
static void ds_print_trace(RDisasmState *ds) {
RDebugTracepoint *tp = NULL;
2014-01-20 00:42:16 +00:00
if (ds->show_trace) {
2016-05-30 10:35:39 +00:00
tp = r_debug_trace_get (ds->core->dbg, ds->at);
r_cons_printf ("%02x:%04x ", tp?tp->times:0, tp?tp->count:0);
}
if (ds->tracespace) {
char spaces [32];
int times;
2016-09-23 14:28:48 +00:00
if (!tp) {
2016-05-30 10:35:39 +00:00
tp = r_debug_trace_get (ds->core->dbg, ds->at);
2016-09-23 14:28:48 +00:00
}
if (tp) {
times = R_MIN (tp->times, 30); // limit to 30
memset (spaces, ' ', sizeof (spaces));
spaces[times] = 0;
r_cons_strcat (spaces);
}
}
}
2016-05-30 10:35:39 +00:00
static void ds_adistrick_comments(RDisasmState *ds) {
if (ds->adistrick) {
2016-05-30 10:35:39 +00:00
ds->middle = r_anal_reflines_middle (ds->core->anal,
ds->core->anal->reflines, ds->at, ds->analop.size);
}
}
2016-05-30 10:35:39 +00:00
static bool ds_print_data_type(RCore *core, const ut8 *buf, int ib, int size) {
const char *type = NULL;
char msg[64];
const int isSigned = (ib == 1 || ib == 8 || ib == 10)? 1: 0;
switch (size) {
case 1: type = isSigned? ".char": ".byte"; break;
case 2: type = isSigned? ".int16": ".word"; break;
case 4: type = isSigned? ".int32": ".dword"; break;
case 8: type = isSigned? ".int64": ".qword"; break;
default: return false;
}
2016-05-24 20:22:15 +00:00
ut64 n = r_read_ble (buf, core->print->big_endian, size * 8);
switch (ib) {
case 1:
r_str_bits (msg, buf, size * 8, NULL);
r_cons_printf ("%s %sb", type, msg);
break;
case 8:
r_cons_printf ("%s %oo", type, n);
break;
case 10:
r_cons_printf ("%s %d", type, n);
break;
default:
switch (size) {
case 1:
r_cons_printf ("%s 0x%02x", type, n);
break;
case 2:
r_cons_printf ("%s 0x%04x", type, n);
break;
case 4:
r_cons_printf ("%s 0x%08x", type, n);
break;
case 8:
r_cons_printf ("%s 0x%016" PFMT64x, type, n);
break;
default:
return false;
}
}
if (size == 4 || size == 8) {
RFlagItem *fi = r_flag_get_i (core->flags, n);
2016-09-22 16:06:10 +00:00
if (fi) {
r_cons_printf (" ; %s", fi->name);
}
}
return true;
}
2016-05-30 10:35:39 +00:00
static int ds_print_meta_infos(RDisasmState *ds, ut8* buf, int len, int idx) {
int ret = 0;
const char *infos, *metas;
char key[100];
RAnalMetaItem MI, *mi = &MI;
2016-05-30 10:35:39 +00:00
RCore * core = ds->core;
Sdb *s = core->anal->sdb_meta;
snprintf (key, sizeof (key)-1, "meta.0x%"PFMT64x, ds->at);
infos = sdb_const_get (s, key, 0);
2016-09-22 16:06:10 +00:00
ds->mi_found = 0;
if (infos) {
for (;*infos; infos++) {
/* XXX wtf, must use anal.meta.deserialize() */
char *p, *q;
if (*infos == ',') {
continue;
}
2016-09-22 16:06:10 +00:00
snprintf (key, sizeof (key)-1, "meta.%c.0x%"PFMT64x, *infos, ds->at);
metas = sdb_const_get (s, key, 0);
MI.size = sdb_array_get_num (s, key, 0, 0);
MI.type = *infos;
MI.from = ds->at;
MI.to = ds->at + MI.size;
if (metas) {
p = strchr (metas, ',');
if (!p) {
continue;
2016-05-18 10:19:27 +00:00
}
2016-09-22 16:06:10 +00:00
MI.space = atoi (p + 1);
q = strchr (p + 1, ',');
if (!q) {
continue;
}
MI.str = (char*)sdb_decode (q + 1, 0);
} else {
MI.str = NULL;
}
// TODO: implement ranged meta find (if not at the begging of function..
char *out = NULL;
int hexlen;
int delta;
if (mi) {
switch (mi->type) {
case R_META_TYPE_STRING:
{
out = r_str_escape (mi->str);
r_cons_printf (" .string %s\"%s\"%s ; len=%"PFMT64d,
COLOR_CONST (ds, YELLOW), out, COLOR_RESET (ds),
mi->size);
free (out);
delta = ds->at - mi->from;
ds->oplen = mi->size - delta;
ds->asmop.size = (int)mi->size;
//i += mi->size-1; // wtf?
R_FREE (ds->line);
R_FREE (ds->refline);
R_FREE (ds->refline2);
ds->mi_found = 1;
break;
}
case R_META_TYPE_HIDE:
r_cons_printf ("(%d bytes hidden)", mi->size);
ds->asmop.size = mi->size;
ds->oplen = mi->size;
ds->mi_found = 1;
break;
case R_META_TYPE_DATA:
hexlen = len - idx;
delta = ds->at-mi->from;
if (mi->size < hexlen) {
hexlen = mi->size;
}
ds->oplen = mi->size;
core->print->flags &= ~R_PRINT_FLAGS_HEADER;
if (!ds_print_data_type (core, buf + idx, ds->hint? ds->hint->immbase: 0, mi->size)) {
r_cons_printf ("hex length=%" PFMT64d " delta=%d\n", mi->size , delta);
r_print_hexdump (core->print, ds->at, buf+idx, hexlen-delta, 16, 1);
}
core->inc = 16;
core->print->flags |= R_PRINT_FLAGS_HEADER;
ds->asmop.size = ret = (int)mi->size; //-delta;
R_FREE (ds->line);
R_FREE (ds->refline);
R_FREE (ds->refline2);
ds->mi_found = 1;
break;
case R_META_TYPE_FORMAT:
r_cons_printf ("format %s {\n", mi->str);
r_print_format (core->print, ds->at, buf+idx, len-idx, mi->str, R_PRINT_MUSTSEE, NULL, NULL);
r_cons_printf ("} %d", mi->size);
ds->oplen = ds->asmop.size = ret = (int)mi->size;
R_FREE (ds->line);
R_FREE (ds->refline);
R_FREE (ds->refline2);
ds->mi_found = 1;
break;
}
}
2016-09-22 16:06:10 +00:00
if (MI.str) {
free (MI.str);
MI.str = NULL;
}
2014-05-04 15:21:05 +00:00
}
}
return ret;
}
2016-05-30 10:35:39 +00:00
static void ds_instruction_mov_lea(RDisasmState *ds, int idx) {
RCore *core = ds->core;
RAnalValue *src;
2016-05-30 10:35:39 +00:00
2014-01-20 00:42:16 +00:00
switch (ds->analop.type) {
2015-03-23 23:08:48 +00:00
case R_ANAL_OP_TYPE_LENGTH:
case R_ANAL_OP_TYPE_CAST:
2015-10-18 20:14:06 +00:00
case R_ANAL_OP_TYPE_CMOV:
case R_ANAL_OP_TYPE_MOV:
2014-01-20 00:42:16 +00:00
src = ds->analop.src[0];
if (src && src->memref>0 && src->reg) {
2014-07-30 20:41:54 +00:00
if (core->anal->reg) {
const char *pc = core->anal->reg->name[R_REG_NAME_PC];
2014-01-20 00:42:16 +00:00
RAnalValue *dst = ds->analop.dst;
2016-09-23 14:28:48 +00:00
if (dst && dst->reg && dst->reg->name) {
if (src->reg->name && pc && !strcmp (src->reg->name, pc)) {
RFlagItem *item;
ut8 b[8];
ut64 ptr = idx + ds->addr + src->delta + ds->analop.size;
ut64 off = 0LL;
r_core_read_at (core, ptr, b, src->memref);
off = r_mem_get_num (b, src->memref);
item = r_flag_get_i (core->flags, off);
//TODO: introduce env for this print?
r_cons_printf ("; MOV %s = [0x%"PFMT64x"] = 0x%"PFMT64x" %s\n",
dst->reg->name, ptr, off, item?item->name: "");
}
}
}
}
break;
// TODO: get from meta anal?
case R_ANAL_OP_TYPE_LEA:
2014-01-20 00:42:16 +00:00
src = ds->analop.src[0];
2014-05-22 11:21:34 +00:00
if (src && src->reg && core->anal->reg && *(core->anal->reg->name)) {
const char *pc = core->anal->reg->name[R_REG_NAME_PC];
2014-01-20 00:42:16 +00:00
RAnalValue *dst = ds->analop.dst;
if (dst && dst->reg && src->reg->name && pc && !strcmp (src->reg->name, pc)) {
2014-01-18 00:55:03 +00:00
int index = 0;
int memref = core->assembler->bits/8;
RFlagItem *item;
ut8 b[64];
2014-01-20 00:42:16 +00:00
ut64 ptr = index+ds->addr+src->delta+ds->analop.size;
ut64 off = 0LL;
r_core_read_at (core, ptr, b, sizeof (b)); //memref);
off = r_mem_get_num (b, memref);
item = r_flag_get_i (core->flags, off);
if (ds->show_leahints) {
char s[64];
r_str_ncpy (s, (const char *)b, sizeof (s));
r_cons_printf ("; LEA %s = [0x%"PFMT64x"] = 0x%"PFMT64x" \"%s\"\n",
dst->reg->name, ptr, off, item?item->name: s);
}
}
}
}
}
Add asm.hints and handle CDOV deoptimization CDIV deoptimization =================== This patch implements hints in the disassembler that aim to assist the user in reading compiler-optimized divisions by analysing the involved magic number. Background ========== Since integer divisions are usually very expensive on most architectures, compilers try very hard to substitute them with cheaper operations. One of the more advanced substitutions is described in the book __Hacker's Delight__, chapter 10. An actual implementation of the described algorithm in LLVM can be found in the functions: `TargetLowering::BuildSDIV()` and `APInt::magic()`. The optimization approximately transforms e.g. ```asm xor edx, edx idiv 39 ``` into ```asm mov eax, edi mov edx, 0xd20d20d3 imul edx lea eax, [rdx + rdi] sar edi, 0x1f sar eax, 5 sub eax, edi ``` Reading the optimized version and __seeing__ the constant 39 seems difficult. Therefore I try to provide a small hint to the user. Limitations =========== * The current implementation only takes the magic number into account, therefore it may result in false positives. * Due to the nature of the optimization, the given hint may be off by a power of two. Fixing this would require to analyse the following shift instructions. * The hint is only shown in the line containing the magic number. The user still has to know which of the following instructions belong to the optimization. TODO ==== * Implement the corresponding analysis for unsigned integers * Implement the corresponding analysis for 64-bit integers. * Improve the heuristic by also looking at the next few instructions. ( I don't really know how to iterate over the instructions in the disassember in a non-deprecated way. Maybe someone can drop me a hint? ) * Implement an exact analysis using the actual dataflow in radeco and use it to revert the optimization. ( I suppose this is outside the scope of radare )
2016-06-15 13:18:04 +00:00
static st64 revert_cdiv_magic(st64 magic) {
ut64 amagic = llabs (magic);
2016-06-16 21:48:01 +00:00
const st64 N = ST64_MAX;
2016-06-17 10:37:18 +00:00
st64 E, candidate;
short s;
if (amagic < 0xFFFFFF || amagic > UT32_MAX) {
Add asm.hints and handle CDOV deoptimization CDIV deoptimization =================== This patch implements hints in the disassembler that aim to assist the user in reading compiler-optimized divisions by analysing the involved magic number. Background ========== Since integer divisions are usually very expensive on most architectures, compilers try very hard to substitute them with cheaper operations. One of the more advanced substitutions is described in the book __Hacker's Delight__, chapter 10. An actual implementation of the described algorithm in LLVM can be found in the functions: `TargetLowering::BuildSDIV()` and `APInt::magic()`. The optimization approximately transforms e.g. ```asm xor edx, edx idiv 39 ``` into ```asm mov eax, edi mov edx, 0xd20d20d3 imul edx lea eax, [rdx + rdi] sar edi, 0x1f sar eax, 5 sub eax, edi ``` Reading the optimized version and __seeing__ the constant 39 seems difficult. Therefore I try to provide a small hint to the user. Limitations =========== * The current implementation only takes the magic number into account, therefore it may result in false positives. * Due to the nature of the optimization, the given hint may be off by a power of two. Fixing this would require to analyse the following shift instructions. * The hint is only shown in the line containing the magic number. The user still has to know which of the following instructions belong to the optimization. TODO ==== * Implement the corresponding analysis for unsigned integers * Implement the corresponding analysis for 64-bit integers. * Improve the heuristic by also looking at the next few instructions. ( I don't really know how to iterate over the instructions in the disassember in a non-deprecated way. Maybe someone can drop me a hint? ) * Implement an exact analysis using the actual dataflow in radeco and use it to revert the optimization. ( I suppose this is outside the scope of radare )
2016-06-15 13:18:04 +00:00
return 0;
}
if (magic < 0) {
2016-06-17 10:37:18 +00:00
magic += 1LL << 32;
Add asm.hints and handle CDOV deoptimization CDIV deoptimization =================== This patch implements hints in the disassembler that aim to assist the user in reading compiler-optimized divisions by analysing the involved magic number. Background ========== Since integer divisions are usually very expensive on most architectures, compilers try very hard to substitute them with cheaper operations. One of the more advanced substitutions is described in the book __Hacker's Delight__, chapter 10. An actual implementation of the described algorithm in LLVM can be found in the functions: `TargetLowering::BuildSDIV()` and `APInt::magic()`. The optimization approximately transforms e.g. ```asm xor edx, edx idiv 39 ``` into ```asm mov eax, edi mov edx, 0xd20d20d3 imul edx lea eax, [rdx + rdi] sar edi, 0x1f sar eax, 5 sub eax, edi ``` Reading the optimized version and __seeing__ the constant 39 seems difficult. Therefore I try to provide a small hint to the user. Limitations =========== * The current implementation only takes the magic number into account, therefore it may result in false positives. * Due to the nature of the optimization, the given hint may be off by a power of two. Fixing this would require to analyse the following shift instructions. * The hint is only shown in the line containing the magic number. The user still has to know which of the following instructions belong to the optimization. TODO ==== * Implement the corresponding analysis for unsigned integers * Implement the corresponding analysis for 64-bit integers. * Improve the heuristic by also looking at the next few instructions. ( I don't really know how to iterate over the instructions in the disassember in a non-deprecated way. Maybe someone can drop me a hint? ) * Implement an exact analysis using the actual dataflow in radeco and use it to revert the optimization. ( I suppose this is outside the scope of radare )
2016-06-15 13:18:04 +00:00
}
2016-06-17 10:37:18 +00:00
for (s = 0; s < 16; s++) {
E = 1LL << (32 + s);
Add asm.hints and handle CDOV deoptimization CDIV deoptimization =================== This patch implements hints in the disassembler that aim to assist the user in reading compiler-optimized divisions by analysing the involved magic number. Background ========== Since integer divisions are usually very expensive on most architectures, compilers try very hard to substitute them with cheaper operations. One of the more advanced substitutions is described in the book __Hacker's Delight__, chapter 10. An actual implementation of the described algorithm in LLVM can be found in the functions: `TargetLowering::BuildSDIV()` and `APInt::magic()`. The optimization approximately transforms e.g. ```asm xor edx, edx idiv 39 ``` into ```asm mov eax, edi mov edx, 0xd20d20d3 imul edx lea eax, [rdx + rdi] sar edi, 0x1f sar eax, 5 sub eax, edi ``` Reading the optimized version and __seeing__ the constant 39 seems difficult. Therefore I try to provide a small hint to the user. Limitations =========== * The current implementation only takes the magic number into account, therefore it may result in false positives. * Due to the nature of the optimization, the given hint may be off by a power of two. Fixing this would require to analyse the following shift instructions. * The hint is only shown in the line containing the magic number. The user still has to know which of the following instructions belong to the optimization. TODO ==== * Implement the corresponding analysis for unsigned integers * Implement the corresponding analysis for 64-bit integers. * Improve the heuristic by also looking at the next few instructions. ( I don't really know how to iterate over the instructions in the disassember in a non-deprecated way. Maybe someone can drop me a hint? ) * Implement an exact analysis using the actual dataflow in radeco and use it to revert the optimization. ( I suppose this is outside the scope of radare )
2016-06-15 13:18:04 +00:00
candidate = (E + magic - 1) / magic;
if (candidate > 0) {
if ( ((N * magic) >> (32 + s)) == (N / candidate) ) {
return candidate;
}
Add asm.hints and handle CDOV deoptimization CDIV deoptimization =================== This patch implements hints in the disassembler that aim to assist the user in reading compiler-optimized divisions by analysing the involved magic number. Background ========== Since integer divisions are usually very expensive on most architectures, compilers try very hard to substitute them with cheaper operations. One of the more advanced substitutions is described in the book __Hacker's Delight__, chapter 10. An actual implementation of the described algorithm in LLVM can be found in the functions: `TargetLowering::BuildSDIV()` and `APInt::magic()`. The optimization approximately transforms e.g. ```asm xor edx, edx idiv 39 ``` into ```asm mov eax, edi mov edx, 0xd20d20d3 imul edx lea eax, [rdx + rdi] sar edi, 0x1f sar eax, 5 sub eax, edi ``` Reading the optimized version and __seeing__ the constant 39 seems difficult. Therefore I try to provide a small hint to the user. Limitations =========== * The current implementation only takes the magic number into account, therefore it may result in false positives. * Due to the nature of the optimization, the given hint may be off by a power of two. Fixing this would require to analyse the following shift instructions. * The hint is only shown in the line containing the magic number. The user still has to know which of the following instructions belong to the optimization. TODO ==== * Implement the corresponding analysis for unsigned integers * Implement the corresponding analysis for 64-bit integers. * Improve the heuristic by also looking at the next few instructions. ( I don't really know how to iterate over the instructions in the disassember in a non-deprecated way. Maybe someone can drop me a hint? ) * Implement an exact analysis using the actual dataflow in radeco and use it to revert the optimization. ( I suppose this is outside the scope of radare )
2016-06-15 13:18:04 +00:00
}
}
return 0;
}
static void ds_cdiv_optimization(RDisasmState *ds) {
char *esil;
char *end, *comma;
st64 imm;
st64 divisor;
2016-09-23 14:28:48 +00:00
if (!ds->show_hints) {
Add asm.hints and handle CDOV deoptimization CDIV deoptimization =================== This patch implements hints in the disassembler that aim to assist the user in reading compiler-optimized divisions by analysing the involved magic number. Background ========== Since integer divisions are usually very expensive on most architectures, compilers try very hard to substitute them with cheaper operations. One of the more advanced substitutions is described in the book __Hacker's Delight__, chapter 10. An actual implementation of the described algorithm in LLVM can be found in the functions: `TargetLowering::BuildSDIV()` and `APInt::magic()`. The optimization approximately transforms e.g. ```asm xor edx, edx idiv 39 ``` into ```asm mov eax, edi mov edx, 0xd20d20d3 imul edx lea eax, [rdx + rdi] sar edi, 0x1f sar eax, 5 sub eax, edi ``` Reading the optimized version and __seeing__ the constant 39 seems difficult. Therefore I try to provide a small hint to the user. Limitations =========== * The current implementation only takes the magic number into account, therefore it may result in false positives. * Due to the nature of the optimization, the given hint may be off by a power of two. Fixing this would require to analyse the following shift instructions. * The hint is only shown in the line containing the magic number. The user still has to know which of the following instructions belong to the optimization. TODO ==== * Implement the corresponding analysis for unsigned integers * Implement the corresponding analysis for 64-bit integers. * Improve the heuristic by also looking at the next few instructions. ( I don't really know how to iterate over the instructions in the disassember in a non-deprecated way. Maybe someone can drop me a hint? ) * Implement an exact analysis using the actual dataflow in radeco and use it to revert the optimization. ( I suppose this is outside the scope of radare )
2016-06-15 13:18:04 +00:00
return;
2016-09-23 14:28:48 +00:00
}
Add asm.hints and handle CDOV deoptimization CDIV deoptimization =================== This patch implements hints in the disassembler that aim to assist the user in reading compiler-optimized divisions by analysing the involved magic number. Background ========== Since integer divisions are usually very expensive on most architectures, compilers try very hard to substitute them with cheaper operations. One of the more advanced substitutions is described in the book __Hacker's Delight__, chapter 10. An actual implementation of the described algorithm in LLVM can be found in the functions: `TargetLowering::BuildSDIV()` and `APInt::magic()`. The optimization approximately transforms e.g. ```asm xor edx, edx idiv 39 ``` into ```asm mov eax, edi mov edx, 0xd20d20d3 imul edx lea eax, [rdx + rdi] sar edi, 0x1f sar eax, 5 sub eax, edi ``` Reading the optimized version and __seeing__ the constant 39 seems difficult. Therefore I try to provide a small hint to the user. Limitations =========== * The current implementation only takes the magic number into account, therefore it may result in false positives. * Due to the nature of the optimization, the given hint may be off by a power of two. Fixing this would require to analyse the following shift instructions. * The hint is only shown in the line containing the magic number. The user still has to know which of the following instructions belong to the optimization. TODO ==== * Implement the corresponding analysis for unsigned integers * Implement the corresponding analysis for 64-bit integers. * Improve the heuristic by also looking at the next few instructions. ( I don't really know how to iterate over the instructions in the disassember in a non-deprecated way. Maybe someone can drop me a hint? ) * Implement an exact analysis using the actual dataflow in radeco and use it to revert the optimization. ( I suppose this is outside the scope of radare )
2016-06-15 13:18:04 +00:00
switch (ds->analop.type) {
case R_ANAL_OP_TYPE_MOV:
case R_ANAL_OP_TYPE_MUL:
esil = R_STRBUF_SAFEGET (&ds->analop.esil);
while (esil) {
comma = strstr (esil, ",");
2016-09-23 14:28:48 +00:00
if (!comma) {
break;
}
Add asm.hints and handle CDOV deoptimization CDIV deoptimization =================== This patch implements hints in the disassembler that aim to assist the user in reading compiler-optimized divisions by analysing the involved magic number. Background ========== Since integer divisions are usually very expensive on most architectures, compilers try very hard to substitute them with cheaper operations. One of the more advanced substitutions is described in the book __Hacker's Delight__, chapter 10. An actual implementation of the described algorithm in LLVM can be found in the functions: `TargetLowering::BuildSDIV()` and `APInt::magic()`. The optimization approximately transforms e.g. ```asm xor edx, edx idiv 39 ``` into ```asm mov eax, edi mov edx, 0xd20d20d3 imul edx lea eax, [rdx + rdi] sar edi, 0x1f sar eax, 5 sub eax, edi ``` Reading the optimized version and __seeing__ the constant 39 seems difficult. Therefore I try to provide a small hint to the user. Limitations =========== * The current implementation only takes the magic number into account, therefore it may result in false positives. * Due to the nature of the optimization, the given hint may be off by a power of two. Fixing this would require to analyse the following shift instructions. * The hint is only shown in the line containing the magic number. The user still has to know which of the following instructions belong to the optimization. TODO ==== * Implement the corresponding analysis for unsigned integers * Implement the corresponding analysis for 64-bit integers. * Improve the heuristic by also looking at the next few instructions. ( I don't really know how to iterate over the instructions in the disassember in a non-deprecated way. Maybe someone can drop me a hint? ) * Implement an exact analysis using the actual dataflow in radeco and use it to revert the optimization. ( I suppose this is outside the scope of radare )
2016-06-15 13:18:04 +00:00
imm = strtol (esil, &end, 10);
if (comma && comma == end) {
divisor = revert_cdiv_magic (imm);
if (divisor) {
r_cons_printf (" ; CDIV: %lld * 2^n", divisor);
break;
}
}
esil = comma + 1;
Add asm.hints and handle CDOV deoptimization CDIV deoptimization =================== This patch implements hints in the disassembler that aim to assist the user in reading compiler-optimized divisions by analysing the involved magic number. Background ========== Since integer divisions are usually very expensive on most architectures, compilers try very hard to substitute them with cheaper operations. One of the more advanced substitutions is described in the book __Hacker's Delight__, chapter 10. An actual implementation of the described algorithm in LLVM can be found in the functions: `TargetLowering::BuildSDIV()` and `APInt::magic()`. The optimization approximately transforms e.g. ```asm xor edx, edx idiv 39 ``` into ```asm mov eax, edi mov edx, 0xd20d20d3 imul edx lea eax, [rdx + rdi] sar edi, 0x1f sar eax, 5 sub eax, edi ``` Reading the optimized version and __seeing__ the constant 39 seems difficult. Therefore I try to provide a small hint to the user. Limitations =========== * The current implementation only takes the magic number into account, therefore it may result in false positives. * Due to the nature of the optimization, the given hint may be off by a power of two. Fixing this would require to analyse the following shift instructions. * The hint is only shown in the line containing the magic number. The user still has to know which of the following instructions belong to the optimization. TODO ==== * Implement the corresponding analysis for unsigned integers * Implement the corresponding analysis for 64-bit integers. * Improve the heuristic by also looking at the next few instructions. ( I don't really know how to iterate over the instructions in the disassember in a non-deprecated way. Maybe someone can drop me a hint? ) * Implement an exact analysis using the actual dataflow in radeco and use it to revert the optimization. ( I suppose this is outside the scope of radare )
2016-06-15 13:18:04 +00:00
}
}
// /TODO: check following SHR instructions
Add asm.hints and handle CDOV deoptimization CDIV deoptimization =================== This patch implements hints in the disassembler that aim to assist the user in reading compiler-optimized divisions by analysing the involved magic number. Background ========== Since integer divisions are usually very expensive on most architectures, compilers try very hard to substitute them with cheaper operations. One of the more advanced substitutions is described in the book __Hacker's Delight__, chapter 10. An actual implementation of the described algorithm in LLVM can be found in the functions: `TargetLowering::BuildSDIV()` and `APInt::magic()`. The optimization approximately transforms e.g. ```asm xor edx, edx idiv 39 ``` into ```asm mov eax, edi mov edx, 0xd20d20d3 imul edx lea eax, [rdx + rdi] sar edi, 0x1f sar eax, 5 sub eax, edi ``` Reading the optimized version and __seeing__ the constant 39 seems difficult. Therefore I try to provide a small hint to the user. Limitations =========== * The current implementation only takes the magic number into account, therefore it may result in false positives. * Due to the nature of the optimization, the given hint may be off by a power of two. Fixing this would require to analyse the following shift instructions. * The hint is only shown in the line containing the magic number. The user still has to know which of the following instructions belong to the optimization. TODO ==== * Implement the corresponding analysis for unsigned integers * Implement the corresponding analysis for 64-bit integers. * Improve the heuristic by also looking at the next few instructions. ( I don't really know how to iterate over the instructions in the disassember in a non-deprecated way. Maybe someone can drop me a hint? ) * Implement an exact analysis using the actual dataflow in radeco and use it to revert the optimization. ( I suppose this is outside the scope of radare )
2016-06-15 13:18:04 +00:00
}
2016-05-30 10:35:39 +00:00
static void ds_print_show_bytes(RDisasmState *ds) {
RCore* core = ds->core;
char *nstr, *str = NULL, pad[64];
char *flagstr = NULL;
int oldFlags = core->print->flags;
char extra[64];
int j, k;
if (!ds->show_bytes || ds->nb < 1) {
return;
}
if (!ds->show_color_bytes) {
core->print->flags &= ~R_PRINT_FLAGS_COLOR;
}
strcpy (extra, " ");
if (ds->show_flag_in_bytes) {
flagstr = r_flag_get_liststr (core->flags, ds->at);
}
if (flagstr) {
str = flagstr;
if (ds->nb > 0) {
k = ds->nb-strlen (flagstr) - 1;
2016-06-09 16:17:51 +00:00
if (k < 0 || k > sizeof(pad)) k = 0;
for (j = 0; j < k; j++) {
pad[j] = ' ';
}
pad[j] = '\0';
} else {
2016-06-09 16:17:51 +00:00
pad[0] = 0;
}
} else {
if (ds->show_flag_in_bytes) {
2016-06-09 16:17:51 +00:00
k = ds->nb - 1;
if (k < 0 || k > sizeof (pad)) {
k = 0;
}
for (j = 0; j < k; j++) {
pad[j] = ' ';
}
pad[j] = '\0';
str = strdup ("");
} else {
2014-01-20 00:42:16 +00:00
str = strdup (ds->asmop.buf_hex);
if (r_str_ansi_len (str) > ds->nb) {
char *p = (char *)r_str_ansi_chrn (str, ds->nb);
if (p) {
p[0] = '.';
p[1] = '\0';
}
}
2016-05-30 10:35:39 +00:00
ds->print->cur_enabled = (ds->cursor != -1);
nstr = r_print_hexpair (ds->print, str, ds->index);
if (ds->print->bytespace) {
k = (ds->nb + (ds->nb / 2)) - r_str_ansi_len (nstr) + 2;
2014-02-25 00:35:23 +00:00
} else {
k = ds->nb - r_str_ansi_len (nstr) + 1;
2014-02-25 00:35:23 +00:00
}
if (k > 0) {
// setting to sizeof screw up the disasm
if (k > sizeof (pad)) {
k = 18;
}
for (j = 0; j < k; j++) {
pad[j] = ' ';
}
pad[j] = 0;
if (ds->lbytes) {
// hack to align bytes left
strcpy (extra, pad);
*pad = 0;
}
2015-04-08 20:28:21 +00:00
} else {
pad[0] = 0;
}
2014-02-25 00:35:23 +00:00
free (str);
str = nstr;
}
}
if (ds->show_color) {
r_cons_printf ("%s%s %s"Color_RESET, pad, str, extra);
} else {
r_cons_printf ("%s%s %s", pad, str, extra);
}
free (str);
core->print->flags = oldFlags;
}
2016-05-30 10:35:39 +00:00
static void ds_print_indent(RDisasmState *ds) {
if (ds->show_indent) {
char indent[128];
int num = ds->indent_level * ds->indent_space;
if (num < 0) {
num = 0;
}
if (num >= sizeof (indent)) {
num = sizeof (indent) - 1;
}
2014-08-17 18:30:28 +00:00
memset (indent, ' ', num);
indent[num] = 0;
r_cons_strcat (indent);
}
}
2016-05-30 10:35:39 +00:00
static void ds_print_opstr(RDisasmState *ds) {
ds_print_indent (ds);
2014-01-20 00:42:16 +00:00
r_cons_strcat (ds->opstr);
2016-05-30 10:35:39 +00:00
ds_print_color_reset (ds);
}
2016-05-30 10:35:39 +00:00
static void ds_print_color_reset(RDisasmState *ds) {
if (ds->show_color) {
r_cons_strcat (Color_RESET);
}
}
2016-05-30 10:35:39 +00:00
static int ds_print_middle(RDisasmState *ds, int ret) {
2014-01-20 00:42:16 +00:00
if (ds->middle != 0) {
ret -= ds->middle;
2016-05-30 10:35:39 +00:00
ds_align_comment (ds);
2016-09-23 14:28:48 +00:00
if (ds->show_color) {
r_cons_strcat (ds->pal_comment);
}
r_cons_printf (" ; *middle* %d", ret);
2016-09-23 14:28:48 +00:00
if (ds->show_color) {
r_cons_strcat (Color_RESET);
}
}
return ret;
}
2016-05-30 10:35:39 +00:00
static bool ds_print_labels(RDisasmState *ds, RAnalFunction *f) {
RCore *core = ds->core;
const char *label;
if (!f) {
f = r_anal_get_fcn_in (core->anal, ds->at, 0);
}
label = r_anal_fcn_label_at (core->anal, f, ds->at);
if (!label) {
return false;
}
if (ds->show_color) {
r_cons_strcat (ds->color_label);
r_cons_printf (" .%s:\n", label);
2016-05-30 10:35:39 +00:00
ds_print_color_reset (ds);
} else {
r_cons_printf (" .%s:\n", label);
}
return true;
}
2016-05-30 10:35:39 +00:00
static void ds_print_import_name(RDisasmState *ds) {
2014-04-02 20:30:39 +00:00
RListIter *iter = NULL;
RBinReloc *rel = NULL;
2016-05-30 10:35:39 +00:00
RCore * core = ds->core;
2014-04-02 20:30:39 +00:00
switch (ds->analop.type) {
case R_ANAL_OP_TYPE_JMP:
case R_ANAL_OP_TYPE_CJMP:
case R_ANAL_OP_TYPE_CALL:
if (core->bin->cur->o->imports && core->bin->cur->o->relocs) {
r_list_foreach (core->bin->cur->o->relocs, iter, rel) {
if ((rel->vaddr == ds->analop.jump) &&
(rel->import != NULL)) {
if (ds->show_color) {
r_cons_strcat (ds->color_fname);
2014-04-02 20:30:39 +00:00
}
// TODO: handle somehow ordinals import
ds_align_comment (ds);
r_cons_printf (" ; (imp.%s)", rel->import->name);
ds_print_color_reset (ds);
2014-04-02 20:30:39 +00:00
}
}
}
2014-04-02 20:30:39 +00:00
}
}
2016-05-30 10:35:39 +00:00
static void ds_print_fcn_name(RDisasmState *ds) {
int delta;
const char *label;
2014-06-25 00:30:42 +00:00
RAnalFunction *f;
2016-05-30 10:35:39 +00:00
RCore *core = ds->core;
if (!ds->show_comments) {
2014-11-18 22:53:27 +00:00
return;
}
2014-01-20 00:42:16 +00:00
switch (ds->analop.type) {
case R_ANAL_OP_TYPE_IO:
{
const int imm = (int)ds->analop.val;
RSyscall *sc = ds->core->anal->syscall;
const char *ioname = r_syscall_get_io (sc, imm);
if (ioname && *ioname) {
ds_align_comment (ds);
if (ds->show_color) {
r_cons_strcat (ds->color_comment);
}
r_cons_printf (" ; IO %s", ioname);
ds->has_description = true;
}
}
break;
case R_ANAL_OP_TYPE_JMP:
case R_ANAL_OP_TYPE_CJMP:
case R_ANAL_OP_TYPE_CALL:
2016-09-23 14:28:48 +00:00
f = r_anal_get_fcn_in (core->anal, ds->analop.jump, R_ANAL_FCN_TYPE_NULL);
if (f && !strstr (ds->opstr, f->name)) {
if (ds->show_color) {
r_cons_strcat (ds->color_fname);
}
//beginline (core, ds, f);
// print label
delta = ds->analop.jump - f->addr;
label = r_anal_fcn_label_at (core->anal, f, ds->analop.jump);
if (label) {
2016-05-30 10:35:39 +00:00
ds_align_comment (ds);
2016-05-30 02:22:20 +00:00
r_cons_printf (" ; %s.%s", f->name, label);
} else {
RAnalFunction *f2 = r_anal_get_fcn_in (core->anal, ds->at, 0);
if (f != f2) {
2016-05-30 10:35:39 +00:00
ds_align_comment (ds);
2016-09-23 14:28:48 +00:00
if (delta > 0) {
2016-05-30 02:22:20 +00:00
r_cons_printf (" ; %s+0x%x", f->name, delta);
2016-09-23 14:28:48 +00:00
} else if (delta < 0) {
2016-05-30 02:22:20 +00:00
r_cons_printf (" ; %s-0x%x", f->name, -delta);
} else {
2016-05-30 02:22:20 +00:00
r_cons_printf (" ; %s", f->name);
2015-04-11 23:28:26 +00:00
}
}
}
2016-05-30 10:35:39 +00:00
ds_print_color_reset (ds);
}
break;
}
}
2014-01-20 00:42:16 +00:00
2016-05-30 10:35:39 +00:00
static void ds_print_core_vmode(RDisasmState *ds) {
char *shortcut = NULL;
2016-05-30 10:35:39 +00:00
RCore *core = ds->core;
if (!ds->show_jmphints) {
return;
}
if (core->vmode) {
switch (ds->analop.type) { // & R_ANAL_OP_TYPE_MASK) {
case R_ANAL_OP_TYPE_LEA:
if (ds->show_leahints) {
ds_align_comment(ds);
2016-09-23 14:28:48 +00:00
if (ds->show_color) {
r_cons_strcat (ds->pal_comment);
}
shortcut = r_core_add_asmqjmp (core, ds->analop.ptr);
if (shortcut) {
r_cons_printf (" ;[%s]", shortcut);
free (shortcut);
} else {
r_cons_strcat (" ;[?]");
}
if (ds->show_color) r_cons_strcat (Color_RESET);
}
break;
case R_ANAL_OP_TYPE_UCALL:
case R_ANAL_OP_TYPE_UCALL | R_ANAL_OP_TYPE_REG | R_ANAL_OP_TYPE_IND:
case R_ANAL_OP_TYPE_UCALL | R_ANAL_OP_TYPE_IND:
ds_align_comment (ds);
if (ds->show_color) {
r_cons_strcat (ds->pal_comment);
}
shortcut = r_core_add_asmqjmp (core, ds->analop.ptr);
if (shortcut) {
r_cons_printf (" ;[%s]", shortcut);
free (shortcut);
} else {
r_cons_strcat (" ;[?]");
}
if (ds->show_color) {
r_cons_strcat (Color_RESET);
}
break;
case R_ANAL_OP_TYPE_RCALL:
break;
case R_ANAL_OP_TYPE_JMP:
case R_ANAL_OP_TYPE_CJMP:
case R_ANAL_OP_TYPE_CALL:
case R_ANAL_OP_TYPE_COND | R_ANAL_OP_TYPE_CALL:
2016-05-30 10:35:39 +00:00
ds_align_comment (ds);
if (ds->show_color) {
r_cons_strcat (ds->pal_comment);
}
shortcut = r_core_add_asmqjmp (core, ds->analop.jump);
if (shortcut) {
r_cons_printf (" ;[%s]", shortcut);
free (shortcut);
} else {
r_cons_strcat (" ;[?]");
}
if (ds->show_color) {
r_cons_strcat (Color_RESET);
}
break;
}
}
}
// modifies anal register state
#if 0
2016-05-30 10:35:39 +00:00
static void ds_print_cc_update(RDisasmState *ds) {
// declare static since this variable is reused locally, and needs to maintain
// state
static RAnalCC cc = {0};
2016-05-30 10:35:39 +00:00
RCore *core = ds->core;
if (!ds->show_comments || !ds->show_fcncalls)
return;
2014-01-20 00:42:16 +00:00
if (!r_anal_cc_update (core->anal, &cc, &ds->analop)) {
if (ds->show_functions) {
RAnalFunction *f = r_anal_get_fcn_in (core->anal, ds->at, R_ANAL_FCN_TYPE_NULL);
char tmp[128];
char *ccstr = r_anal_cc_to_string (core->anal, &cc);
tmp[0] = 0;
2014-01-20 00:42:16 +00:00
r_anal_cc_update (core->anal, &cc, &ds->analop);
if (ccstr) {
RFlagItem *flag = r_flag_get_at (core->flags, cc.jump);
if (flag && ccstr) {
int delta = 0;
if (f) { delta = cc.jump-flag->offset; }
if (!strncmp (flag->name, ccstr, strlen (flag->name))) {
if (ccstr[strlen (flag->name)] == '(') {
tmp[0] = 0;
} else {
if (delta)
snprintf (tmp, sizeof (tmp)-1, " ; %s+%d", flag->name, delta);
else snprintf (tmp, sizeof (tmp)-1, " ; %s", flag->name);
}
} else {
if (delta)
snprintf (tmp, sizeof (tmp)-1, " ; %s+%d", flag->name, delta);
else snprintf (tmp, sizeof (tmp)-1, " ; %s", flag->name);
}
}
if (ds->show_calls) {
2016-05-30 10:35:39 +00:00
const char *sn = ds->show_section? get_section_name (core, ds->at): "";
int cmtright = ds->show_comment_right;
if (core->cons->columns < 120) {
cmtright = 0;
}
// if doesnt fits in screen newline
if (cmtright) {
2016-05-30 10:35:39 +00:00
ds_align_comment (ds);
r_cons_printf (" %s%s; %s%s%s", COLOR_RESET (ds),
COLOR (ds, pal_comment), ccstr, tmp, COLOR_RESET (ds));
} else {
r_cons_printf ("\n%s%s%s%s%s %s^-%s %s%s%s",
COLOR (ds, color_fline), ds->pre, COLOR (ds, color_flow),
sn, ds->refline, COLOR_RESET (ds), COLOR (ds, pal_comment),
ccstr, tmp, COLOR_RESET (ds));
}
}
free (ccstr);
if (f) {
2016-05-30 10:35:39 +00:00
ds_set_pre (ds, core->cons->vline[LINE_VERT]);
2014-01-20 00:42:16 +00:00
ds->pre = r_str_concat (ds->pre, " ");
} else {
2016-05-30 10:35:39 +00:00
ds_set_pre (ds, " ");
}
}
}
r_anal_cc_reset (&cc);
}
}
#endif
// align for comment
2016-05-30 10:35:39 +00:00
static void ds_align_comment(RDisasmState *ds) {
const int cmtcol = ds->cmtcol;
if (ds->show_comment_right_default) {
char *ll = r_cons_lastline ();
if (ll) {
int cstrlen = strlen (ll);
int cols, ansilen = r_str_ansi_len (ll);
int utf8len = r_utf8_strlen ((const ut8*)ll);
2016-09-23 14:28:48 +00:00
int cells = utf8len - (cstrlen - ansilen);
2016-05-30 10:35:39 +00:00
cols = ds->interactive ? ds->core->cons->columns : 1024;
//cols = r_cons_get_size (NULL);
2016-09-23 14:28:48 +00:00
if (cmtcol + 16 >= cols) {
int len = cmtcol - cells;
r_cons_memset (' ', len);
} else if (cells < cmtcol) {
int len = cmtcol - cells;
2016-09-23 14:28:48 +00:00
if (len < cols) {
r_cons_memset (' ', len);
2016-09-23 14:28:48 +00:00
}
}
}
}
}
2016-05-30 10:35:39 +00:00
static void ds_print_dwarf(RDisasmState *ds) {
2014-01-20 00:42:16 +00:00
if (ds->show_dwarf) {
int len = strlen (ds->opstr);
2016-05-31 20:13:33 +00:00
if (len < 30) {
len = 30 - len;
}
ds->sl = r_bin_addr2text (ds->core->bin, ds->at, true);
2014-01-20 00:42:16 +00:00
if (ds->sl) {
if ((!ds->osl || (ds->osl && strcmp (ds->sl, ds->osl)))) {
2016-05-31 20:13:33 +00:00
char *chopstr, *line = strdup (ds->sl);
if (!line) {
return;
}
r_str_replace_char (line, '\t', ' ');
r_str_replace_char (line, '\x1b', ' ');
r_str_replace_char (line, '\r', ' ');
r_str_replace_char (line, '\n', '\x00');
2016-05-31 20:13:33 +00:00
chopstr = r_str_chop (line);
if (!*chopstr) {
free (line);
return;
}
2014-12-18 11:54:36 +00:00
// handle_set_pre (ds, " ");
2016-05-30 10:35:39 +00:00
ds_align_comment (ds);
if (ds->show_color) {
2016-05-31 20:13:33 +00:00
r_cons_printf ("%s ; %s"Color_RESET, ds->pal_comment, chopstr);
} else {
2016-05-31 20:13:33 +00:00
r_cons_printf (" ; %s", chopstr);
}
2014-01-20 00:42:16 +00:00
free (ds->osl);
ds->osl = ds->sl;
ds->sl = NULL;
free (line);
}
}
}
}
2016-05-30 10:35:39 +00:00
static void ds_print_asmop_payload(RDisasmState *ds) {
if (ds->show_varxs) {
// XXX asume analop is filled
//r_anal_op (core->anal, &ds->analop, ds->at, core->block+i, core->blocksize-i);
int v = ds->analop.ptr;
switch (ds->analop.stackop) {
case R_ANAL_STACK_GET:
2016-09-23 14:28:48 +00:00
if (v < 0) {
r_cons_printf (" ; local.get %d", -v);
} else {
r_cons_printf (" ; arg.get %d", v);
}
break;
case R_ANAL_STACK_SET:
2016-09-23 14:28:48 +00:00
if (v < 0) {
r_cons_printf (" ; local.set %d", -v);
} else {
r_cons_printf (" ; arg.set %d", v);
}
break;
}
}
2014-01-20 00:42:16 +00:00
if (ds->asmop.payload != 0)
r_cons_printf ("\n; .. payload of %d bytes", ds->asmop.payload);
}
2016-05-30 10:35:39 +00:00
static void ds_print_op_push_info(RDisasmState *ds){
2014-01-20 00:42:16 +00:00
switch (ds->analop.type) {
case R_ANAL_OP_TYPE_PUSH:
2014-01-20 00:42:16 +00:00
if (ds->analop.val) {
2016-05-30 10:35:39 +00:00
RFlagItem *flag = r_flag_get_i (ds->core->flags, ds->analop.val);
if (flag) r_cons_printf (" ; %s", flag->name);
}
break;
}
}
2016-05-30 10:35:39 +00:00
static void ds_comment_newline(RDisasmState *ds) {
2015-06-04 23:00:41 +00:00
const char *sn;
2016-09-23 14:28:48 +00:00
if (ds->show_comment_right) {
return;
}
2016-05-30 10:35:39 +00:00
sn = ds->show_section ? get_section_name (ds->core, ds->at) : "";
ds_align_comment (ds);
r_cons_printf ("\n%s%s%s%s%s ^- %s", COLOR (ds, color_fline),
ds->pre, sn, ds->refline, COLOR_RESET (ds),
COLOR (ds, pal_comment));
2015-06-04 23:00:41 +00:00
}
/* convert numeric value in opcode to ascii char or number */
2016-05-30 10:35:39 +00:00
static void ds_print_ptr(RDisasmState *ds, int len, int idx) {
RCore *core = ds->core;
ut64 p = ds->analop.ptr;
2016-09-12 21:11:38 +00:00
ut64 v = ds->analop.val;
2014-11-18 23:26:26 +00:00
int aligned = 0;
2016-05-30 02:20:04 +00:00
#define DOALIGN() \
if (!aligned) { \
2016-05-30 10:35:39 +00:00
ds_align_comment (ds); \
2016-05-30 02:20:04 +00:00
if (ds->show_color) r_cons_printf (ds->pal_comment); \
aligned = 1; \
}
2016-05-30 10:35:39 +00:00
2016-09-23 14:28:48 +00:00
if (!ds->show_comments) {
2014-11-18 22:48:25 +00:00
return;
2016-09-23 14:28:48 +00:00
}
if (!ds->show_slow) {
return;
}
2016-09-23 14:28:48 +00:00
if (((char)v > 0) && v >= '!' && v <= '~') {
2016-09-12 21:11:38 +00:00
char ch = v;
DOALIGN();
r_cons_printf (" ; '%c'", ch);
}
if (p == UT64_MAX) {
/* do nothing */
} else if (((st64)p) > 0) {
const char *kind;
char *msg = calloc (sizeof (char), len);
RFlagItem *f, *f2;
r_io_read_at (core->io, p, (ut8*)msg, len - 1);
if (ds->analop.refptr) {
ut64 num = r_read_ble (msg, core->print->big_endian, ds->analop.refptr*8);
st64 n = (st64)num;
st32 n32 = (st32)(n & UT32_MAX);
2016-05-30 02:20:04 +00:00
DOALIGN();
2015-04-03 15:25:07 +00:00
if (ds->analop.type == R_ANAL_OP_TYPE_LEA) {
2016-05-30 10:35:39 +00:00
ds_comment_newline (ds);
const char *flag = "";
2015-04-03 15:25:07 +00:00
f = r_flag_get_i (core->flags, p);
2016-09-23 14:28:48 +00:00
if (f) {
flag = f->name;
}
2016-03-13 20:56:46 +00:00
r_cons_printf (" ; 0x%"PFMT64x"%s%s", p, *flag?" ; ":"", flag);
2015-04-03 15:25:07 +00:00
} else {
2015-07-17 09:33:16 +00:00
f = NULL;
if (n == UT32_MAX || n == UT64_MAX) {
r_cons_printf (" ; [0x%"PFMT64x":%d]=-1", p, ds->analop.refptr);
2015-04-03 15:25:07 +00:00
} else if (n == n32 && (n32>-512 && n32 <512)) {
r_cons_printf (" ; [0x%"PFMT64x":%d]=%"PFMT64d, p, ds->analop.refptr, n);
2015-04-03 15:25:07 +00:00
} else {
const char *kind, *flag = "";
char *msg2 = NULL;
2015-04-03 15:25:07 +00:00
f = r_flag_get_i (core->flags, n);
if (f) {
flag = f->name;
} else {
msg2 = calloc (sizeof (char), len);
2016-06-02 01:19:31 +00:00
r_io_read_at (core->io, n, (ut8*)msg2, len - 1);
msg2[len-1] = 0;
kind = r_anal_data_kind (core->anal, p, (const ut8*)msg2, len - 1);
if (kind && !strcmp (kind, "text")) {
r_str_filter (msg2, 0);
if (*msg2) {
char *lala = r_str_newf ("\"%s\"", msg2);
free (msg2);
flag = msg2 = lala;
}
}
}
// try to guess what's in there
2016-09-23 14:28:48 +00:00
r_cons_printf (" ; [0x%"PFMT64x":%d]=0x%"PFMT64x"%s%s", p, ds->analop.refptr, n, (flag&&*flag)?" ":"", flag);
free (msg2);
2015-04-03 15:25:07 +00:00
}
// not just for LEA
f2 = r_flag_get_i (core->flags, p);
if (f2 && f != f2) {
r_cons_printf (" LEA %s", f2->name);
}
}
}
#if 1
2016-09-22 16:06:10 +00:00
if (!IS_PRINTABLE (*msg)) {
*msg = 0;
2016-09-22 16:06:10 +00:00
} else {
msg[len-1] = 0;
}
#endif
f = r_flag_get_i (core->flags, p);
if (f) {
r_str_filter (msg, 0);
2016-05-30 10:35:39 +00:00
ds_comment_newline (ds);
2014-11-18 23:26:26 +00:00
DOALIGN();
if (*msg) {
2016-09-23 14:28:48 +00:00
if (strlen (msg) == 1) {
//could be a wide string
int i = 0;
r_cons_printf (" ; \"");
for (i = 0; i < len; i++) {
if (!msg[i]) {
break;
}
if (IS_PRINTABLE (msg[i])) {
r_cons_printf ("%c", msg[i]);
} else {
r_cons_printf ("\\x%02x", msg[i]);
}
if (!msg[i+1]) {
i++;
}
}
r_cons_printf ("\" @ 0x%"PFMT64x, p);
} else {
r_cons_printf (" ; \"%s\" @ 0x%"PFMT64x, msg, p);
}
} else {
r_cons_printf (" ; %s", f->name);
}
} else {
if (p == UT64_MAX || p == UT32_MAX) {
2014-11-18 23:26:26 +00:00
DOALIGN();
r_cons_printf (" ; -1", p);
2016-09-22 16:06:10 +00:00
} else if (((char)p > 0) && p >= '!' && p <= '~') {
char ch = p;
2014-11-18 23:26:26 +00:00
DOALIGN();
r_cons_printf (" ; '%c'", ch);
} else if (p > 10) {
2016-09-22 16:06:10 +00:00
if ((st64)p < 0) {
// resolve local var if possible
RAnalVar *v = r_anal_var_get (core->anal, ds->at, 'v', 1, (int)p);
2014-11-18 23:26:26 +00:00
DOALIGN();
if (v) {
r_cons_printf (" ; var %s", v->name);
r_anal_var_free (v);
} else {
r_cons_printf (" ; var %d", (int)-p);
}
} else {
if (r_core_anal_address (core, p) & R_ANAL_ADDR_TYPE_ASCII) {
2016-09-23 14:28:48 +00:00
int i = 0;
r_str_filter (msg, 0);
2014-11-18 23:26:26 +00:00
if (*msg) {
DOALIGN();
2016-09-23 14:28:48 +00:00
if (strlen (msg) == 1) {
//handle wide string if that is the case
r_cons_printf (" ; \"");
for (i = 0; i < len; i++) {
if (!msg[i]) {
break;
}
if (IS_PRINTABLE (msg[i])) {
r_cons_printf ("%c", msg[i]);
} else {
r_cons_printf ("\\x%02x", msg[i]);
}
if (!msg[i+1]) {
i++;
}
}
r_cons_printf ("\" 0x%08"PFMT64x" ", p);
} else {
r_cons_printf (" ; \"%s\" 0x%08"PFMT64x" ", msg, p);
}
2014-11-18 23:26:26 +00:00
}
}
}
}
kind = r_anal_data_kind (core->anal, p, (const ut8*)msg, len - 1);
if (kind) {
if (!strcmp (kind, "text")) {
r_str_filter (msg, 0);
if (*msg) {
2016-09-23 14:28:48 +00:00
int i;
2014-11-18 23:26:26 +00:00
DOALIGN();
if (strlen (msg) == 1) {
2016-09-23 14:28:48 +00:00
r_cons_printf (" ; \"");
for (i = 0; i < len; i++) {
if (!msg[i]) {
break;
}
if (IS_PRINTABLE (msg[i])) {
r_cons_printf ("%c", msg[i]);
} else {
r_cons_printf ("\\x%02x", msg[i]);
}
if (!msg[i+1]) {
//wide string?
i++;
}
}
r_cons_printf ("\"");
} else {
r_cons_printf (" ; \"%s\"", msg);
}
}
} else if (!strcmp (kind, "invalid")){
int *n = (int*)&p;
2014-11-13 02:59:51 +00:00
if (*n>-0xfff && *n < 0xfff) {
2014-11-18 23:26:26 +00:00
DOALIGN();
r_cons_printf (" ; %d", *n);
2014-11-13 02:59:51 +00:00
}
} else {
//r_cons_printf (" ; %s", kind);
}
// TODO: check for more data kinds
}
}
free (msg);
2016-09-21 09:00:52 +00:00
} else {
ds_print_as_string (ds);
}
if (aligned && ds->show_color) {
r_cons_printf (Color_RESET);
}
}
2014-11-03 15:24:04 +00:00
// TODO: Use sdb in rbin to accelerate this
// we shuold use aligned reloc addresses instead of iterating all of them
static RBinReloc *getreloc(RCore *core, ut64 addr, int size) {
RList *list;
RBinReloc *r;
RListIter *iter;
2016-09-23 14:28:48 +00:00
if (size < 1 || addr == UT64_MAX) {
return NULL;
}
2014-11-03 15:24:04 +00:00
list = r_bin_get_relocs (core->bin);
#if 0
addr addr+size
|__._______|
|
reloc
#endif
r_list_foreach (list, iter, r) {
2016-09-23 14:28:48 +00:00
if ((r->vaddr >= addr) && (r->vaddr<(addr+size))) {
2014-11-03 15:24:04 +00:00
return r;
2016-09-23 14:28:48 +00:00
}
2014-11-03 15:24:04 +00:00
}
return NULL;
}
2016-05-30 10:35:39 +00:00
static void ds_print_relocs(RDisasmState *ds) {
RCore *core = ds->core;
2014-11-03 15:24:04 +00:00
RBinReloc *rel = getreloc (core, ds->at, ds->analop.size);
2016-05-30 10:35:39 +00:00
2014-11-03 15:24:04 +00:00
if (rel) {
2016-11-01 00:14:23 +00:00
const int cmtcol = ds->cmtcol;
char *ll = r_cons_lastline ();
int cstrlen = strlen (ll);
int cols, ansilen = r_str_ansi_len (ll);
int utf8len = r_utf8_strlen ((const ut8*)ll);
int cells = utf8len - (cstrlen - ansilen);
int len = cmtcol - cells;
r_cons_memset (' ', len);
2016-09-23 14:28:48 +00:00
if (rel->import) {
r_cons_printf (" ; RELOC %d %s", rel->type, rel->import->name);
2016-09-23 14:28:48 +00:00
} else if (rel->symbol) {
r_cons_printf (" ; RELOC %d %s", rel->type, rel->symbol->name);
2016-09-23 14:28:48 +00:00
} else {
r_cons_printf (" ; RELOC %d ", rel->type);
}
2014-11-03 15:24:04 +00:00
}
}
static int mymemwrite0(RAnalEsil *esil, ut64 addr, const ut8 *buf, int len) {
return 0;
}
static int mymemwrite1(RAnalEsil *esil, ut64 addr, const ut8 *buf, int len) {
return 1;
}
static int myregwrite(RAnalEsil *esil, const char *name, ut64 *val) {
2015-09-10 20:28:04 +00:00
char str[64], *msg = NULL;
ut32 *n32 = (ut32*)str;
RDisasmState *ds = esil->user;
2016-06-08 21:33:31 +00:00
if (ds) {
ds->esil_likely = true;
if (!ds->show_slow) {
return 0;
}
}
memset (str, 0, sizeof (str));
if (*val != 0LL) {
#if 0
RFlagItem *fi = r_flag_get_i (esil->anal->flb.f, val);
if (fi) {
strncpy (str, fi->name, sizeof (str)-1);
}
if (!str[0]) {
(void)r_io_read_at (esil->anal->iob.io, val, (ut8*)str, sizeof (str)-1);
2015-09-10 20:28:04 +00:00
str[sizeof (str)-1] = 0;
if (*str && r_str_is_printable (str)) {
// do nothing
msg = r_str_newf ("\"%s\"", str);
} else {
2015-09-10 20:28:04 +00:00
str[0] = 0;
if (*n32 == 0) {
2016-01-14 23:17:15 +00:00
// msg = strdup ("NULL");
2015-09-10 20:28:04 +00:00
} else if (*n32 == UT32_MAX) {
/* nothing */
} else {
2016-06-08 21:33:31 +00:00
if (ds && !ds->show_emu_str) {
2016-01-14 23:17:15 +00:00
msg = r_str_newf ("-> 0x%x", *n32);
}
2015-09-10 20:28:04 +00:00
}
}
2015-09-10 20:28:04 +00:00
} else {
msg = r_str_newf ("%s", str);
}
#endif
(void)r_io_read_at (esil->anal->iob.io, *val, (ut8*)str, sizeof (str)-1);
str[sizeof (str)-1] = 0;
if (*str && r_str_is_printable (str)) {
// do nothing
msg = r_str_newf ("\"%s\"", str);
} else {
str[0] = 0;
2016-09-23 14:28:48 +00:00
if (!*n32) {
// msg = strdup ("NULL");
} else if (*n32 == UT32_MAX) {
/* nothing */
} else {
if (ds && !ds->show_emu_str) {
msg = r_str_newf ("-> 0x%x", *n32);
}
}
}
RFlagItem *fi = r_flag_get_i (esil->anal->flb.f, *val);
if (fi) {
msg = r_str_concatf (msg, " %s", fi->name);
}
}
2016-06-08 21:33:31 +00:00
if (ds && ds->show_emu_str) {
2016-09-23 14:28:48 +00:00
if (msg && *msg) {
r_cons_printf (" ; %s", msg);
2016-09-23 14:28:48 +00:00
}
2016-01-14 23:17:15 +00:00
} else {
r_cons_printf (" ; %s=0x%"PFMT64x" %s", name, *val, msg? msg: "");
2016-01-14 23:17:15 +00:00
}
free (msg);
return 0;
}
2016-05-30 10:35:39 +00:00
static void ds_print_esil_anal_init(RDisasmState *ds) {
RCore *core = ds->core;
const char *pc = r_reg_get_name (core->anal->reg, R_REG_NAME_PC);
ds->esil_old_pc = r_reg_getv (core->anal->reg, pc);
2016-09-23 14:28:48 +00:00
if (!ds->esil_old_pc || ds->esil_old_pc == UT64_MAX) {
ds->esil_old_pc = core->offset;
}
2015-09-11 21:46:09 +00:00
if (!ds->show_emu) {
return;
}
if (!core->anal->esil) {
int iotrap = r_config_get_i (core->config, "esil.iotrap");
int stacksize = r_config_get_i (core->config, "esil.stacksize");
2016-01-20 16:13:30 +00:00
if (!(core->anal->esil = r_anal_esil_new (stacksize, iotrap))) {
R_FREE (ds->esil_regstate);
2016-01-20 16:13:30 +00:00
return;
}
2016-08-05 11:35:44 +00:00
r_anal_esil_setup (core->anal->esil, core->anal, 0, 0, 1);
}
2016-06-10 14:14:07 +00:00
core->anal->esil->user = ds;
free (ds->esil_regstate);
R_FREE (core->anal->last_disasm_reg);
2016-04-21 00:25:49 +00:00
if (core->anal->gp) {
r_reg_setv (core->anal->reg, "gp", core->anal->gp);
2016-04-21 00:25:49 +00:00
}
ds->esil_regstate = r_reg_arena_peek (core->anal->reg);
}
2016-05-30 10:35:39 +00:00
static void ds_print_esil_anal_fini(RDisasmState *ds) {
if (ds->show_emu && ds->esil_regstate) {
2016-05-30 10:35:39 +00:00
RCore* core = ds->core;
core->anal->last_disasm_reg = r_reg_arena_peek (core->anal->reg);
const char *pc = r_reg_get_name (core->anal->reg, R_REG_NAME_PC);
r_reg_arena_poke (core->anal->reg, ds->esil_regstate);
r_reg_setv (core->anal->reg, pc, ds->esil_old_pc);
R_FREE (ds->esil_regstate);
}
}
2016-05-30 10:35:39 +00:00
static void ds_print_bbline(RDisasmState *ds) {
RAnalBlock *bb;
if (!ds->show_bbline || !ds->fcn) return;
bb = r_anal_fcn_bbget (ds->fcn, ds->at);
if (bb) {
2016-05-30 10:35:39 +00:00
ds_setup_print_pre (ds, false, false);
ds_update_ref_lines (ds);
2016-02-23 14:31:24 +00:00
if (!ds->linesright && ds->show_lines && ds->line) {
r_cons_printf ("%s%s%s", COLOR (ds, color_flow),
ds->refline2, COLOR_RESET (ds));
}
2015-12-28 02:07:00 +00:00
r_cons_printf("|\n");
}
}
static void get_fcn_args_info(RAnal *anal, const char *fcn_name, int arg_num, const char * cc, const char **name,
char **orig_c_type, char **c_type, const char **fmt, ut64 *size, const char **source) {
*name = r_anal_type_func_args_name (anal, fcn_name, arg_num);
*orig_c_type = r_anal_type_func_args_type (anal, fcn_name, arg_num);
if (!strncmp("const ", *orig_c_type, 6)) {
*c_type = *orig_c_type+6;
} else {
*c_type = *orig_c_type;
}
const char *query = sdb_fmt (-1, "type.%s", *c_type);
*fmt = sdb_const_get (anal->sdb_types, query, 0);
const char *t_query = sdb_fmt (-1, "type.%s.size", *c_type);
*size = sdb_num_get (anal->sdb_types, t_query, 0) / 8;
*source = r_anal_cc_arg (anal, cc, arg_num+1);
}
static void print_fcn_arg(RCore *core, const char *type, const char *name, const char *fmt, const ut64 addr, const int on_stack) {
//r_cons_newline ();
r_cons_printf ("%s", type);
r_core_cmdf (core, "pf %s%s %s @ 0x%08"PFMT64x, (on_stack==1)?"*":"", fmt, name, addr);
r_cons_chop ();
r_cons_chop ();
}
static void delete_last_comment(RDisasmState *ds) {
if (ds->show_comment_right_default) {
char *ll = r_cons_lastline ();
if (ll) {
char * begin = strstr (ll, "; ");
if (begin) {
int cstrlen = strlen (ll);
r_cons_drop (cstrlen - (int)(begin - ll));
}
}
}
}
static char * resolve_fcn_name(RAnal *anal, const char * func_name) {
const char * name = NULL;
const char * str = func_name;
if (r_anal_type_func_exist (anal, func_name)) {
return strdup (func_name);
}
name = func_name;
while ((str = strchr (str, '.'))) {
name = str+1;
str++;
}
if (r_anal_type_func_exist (anal, name)) {
return strdup (name);
}
return r_anal_type_func_guess (anal, (char*)func_name);
}
// modifies anal register state
2016-05-30 10:35:39 +00:00
static void ds_print_esil_anal(RDisasmState *ds) {
RCore *core = ds->core;
RAnalEsil *esil = core->anal->esil;
const char *pc;
int i, ioc, nargs;
2016-08-07 17:05:55 +00:00
if (!esil) {
ds_print_esil_anal_init (ds);
esil = core->anal->esil;
}
if (!ds->show_comments || !ds->show_emu) {
goto beach;
2015-09-09 22:41:19 +00:00
}
{
const RAnalMetaItem *mi = r_meta_find (core->anal, ds->at, R_META_TYPE_ANY, 0);
if (mi) {
goto beach;
2016-09-23 14:28:48 +00:00
}
}
if (ds->show_color) {
r_cons_strcat (ds->pal_comment);
}
ioc = r_config_get_i (core->config, "io.cache");
r_config_set (core->config, "io.cache", "true");
2016-05-30 10:35:39 +00:00
ds_align_comment (ds);
esil = core->anal->esil;
pc = r_reg_get_name (core->anal->reg, R_REG_NAME_PC);
r_reg_setv (core->anal->reg, pc, ds->at + ds->analop.size);
//r_reg_setv (core->anal->reg, pc, ds->at);
esil->cb.hook_reg_write = myregwrite;
if (ds->show_emu_write) {
esil->cb.hook_mem_write = mymemwrite0;
} else {
esil->cb.hook_mem_write = mymemwrite1;
}
ds->esil_likely = 0;
r_anal_esil_set_pc (esil, ds->at);
r_anal_esil_parse (esil, R_STRBUF_SAFEGET (&ds->analop.esil));
r_anal_esil_stack_free (esil);
switch (ds->analop.type) {
case R_ANAL_OP_TYPE_SWI: {
char *s = cmd_syscall_dostr (core, -1);
if (s) {
r_cons_printf ("; %s", s);
free (s);
}
} break;
case R_ANAL_OP_TYPE_CJMP:
if (ds->esil_likely) {
r_cons_printf ("; likely");
} else {
r_cons_printf ("; unlikely");
}
break;
case R_ANAL_OP_TYPE_UCALL:
case R_ANAL_OP_TYPE_ICALL:
case R_ANAL_OP_TYPE_RCALL:
case R_ANAL_OP_TYPE_IRCALL:
case R_ANAL_OP_TYPE_CALL:
{
2016-04-03 16:13:12 +00:00
RAnalFunction *fcn;
const char *fcn_name = NULL;
2016-04-03 16:13:12 +00:00
ut64 pcv = ds->analop.jump;
if (pcv == UT64_MAX) {
2016-04-03 16:41:50 +00:00
pcv = ds->analop.ptr; // call [reloc-addr] // windows style
2016-04-03 16:13:12 +00:00
if (pcv == UT64_MAX) {
2016-04-03 16:41:50 +00:00
pcv = r_reg_getv (core->anal->reg, pc);
2016-04-03 16:13:12 +00:00
}
}
2016-04-03 16:13:12 +00:00
fcn = r_anal_get_fcn_at (core->anal, pcv, 0);
if (fcn) {
fcn_name = fcn->name;
} else {
RFlagItem *item = r_flag_get_i (core->flags, pcv);
2016-09-23 14:28:48 +00:00
if (item) {
fcn_name = item->name;
2016-09-23 14:28:48 +00:00
}
}
if (fcn_name) {
char * key = resolve_fcn_name (core->anal, fcn_name);
if (key) {
const char *sp = r_reg_get_name (core->anal->reg, R_REG_NAME_SP);
const char *fcn_type = r_anal_type_func_ret (core->anal, key);
const char * cc;
nargs = r_anal_type_func_args_count (core->anal, key);
// HACK: remove other comments
delete_last_comment (ds);
if (ds->show_color) {
r_cons_strcat (ds->pal_comment);
}
ds_align_comment (ds);
r_cons_printf ("; %s%s%s(", fcn_type, fcn_type[strlen (fcn_type) - 1] == '*' ? "": " ", key);
if (nargs == 0) {
r_cons_printf ("void);");
break;
}
cc = r_anal_type_func_cc (core->anal, key);
if (!cc) {
// unsupported calling convention
break;
}
ut64 spv = r_reg_getv (core->anal->reg, sp);
ut64 s_width = (core->anal->bits == 64)? 8: 4;
spv += s_width;
ut64 arg_addr = UT64_MAX;
for (i = 0; i < nargs; i++) {
const char *arg_name, *fmt, *cc_source;
char *arg_orig_c_type, *arg_c_type;
ut64 arg_size;
int on_stack=0, warning=0;
get_fcn_args_info (core->anal, key, i, cc, &arg_name, &arg_orig_c_type, &arg_c_type, &fmt, &arg_size, &cc_source);
if (!strcmp (cc_source, "stack_rev")) {
int j;
free (arg_orig_c_type);
on_stack = 1;
for (j = nargs-1; j >= i; j--) {
warning = 0;
get_fcn_args_info (core->anal, key, j, cc, &arg_name, &arg_orig_c_type, &arg_c_type, &fmt, &arg_size, &cc_source);
arg_addr = spv;
if (arg_size == 0) {
r_cons_printf ("%s: unk_size", arg_c_type);
warning = 1;
arg_size = s_width;
}
spv += arg_size;
if (!fmt) {
if (!warning) {
r_cons_printf ("%s : unk_format", arg_c_type);
} else {
r_cons_printf ("_format");
}
r_cons_printf (j!=i?", ":");");
free (arg_orig_c_type);
continue;
}
if (fmt) {
print_fcn_arg (core, arg_orig_c_type, arg_name, fmt, arg_addr, on_stack);
r_cons_printf (j!=i?", ":");");
}
free (arg_orig_c_type);
}
break;
}
if (!strncmp (cc_source, "stack", 5)) {
arg_addr = spv;
if (arg_size == 0) {
r_cons_printf ("%s: unk_size", arg_c_type);
warning = 1;
arg_size = s_width;
}
spv += arg_size;
on_stack = 1;
} else {
arg_addr = r_reg_getv (core->anal->reg, cc_source);
}
if (!fmt) {
if (!warning) {
r_cons_printf ("%s : unk_format", arg_c_type);
} else {
r_cons_printf ("_format");
}
r_cons_printf (i!=(nargs-1)?", ":");");
free (arg_orig_c_type);
continue;
}
if (fmt) {
print_fcn_arg (core, arg_orig_c_type, arg_name, fmt, arg_addr, on_stack);
r_cons_printf (i!=(nargs-1)?", ":");");
}
free (arg_orig_c_type);
}
free (key);
} else {
// function not in sdb
goto callfallback;
}
} else {
// function name not resolved
callfallback:
nargs = DEFAULT_NARGS;
if (fcn) {
nargs = fcn->nargs;
}
r_cons_printf ("; CALL: ");
for (i = 0; i < nargs; i++) {
ut64 v = r_debug_arg_get (core->dbg, R_ANAL_CC_TYPE_STDCALL, i);
r_cons_printf ("%s0x%"PFMT64x, i?", ":"", v);
}
}
}
break;
}
r_config_set_i (core->config, "io.cache", ioc);
beach:
if (ds->show_spacy) {
switch (ds->analop.type) {
case R_ANAL_OP_TYPE_CALL:
case R_ANAL_OP_TYPE_MJMP:
case R_ANAL_OP_TYPE_UJMP:
case R_ANAL_OP_TYPE_IJMP:
case R_ANAL_OP_TYPE_RJMP:
case R_ANAL_OP_TYPE_IRJMP:
case R_ANAL_OP_TYPE_CJMP:
case R_ANAL_OP_TYPE_JMP:
case R_ANAL_OP_TYPE_RET:
ds_print_spacy (ds, 1);
break;
}
}
}
2016-09-21 09:00:52 +00:00
static void ds_print_calls_hints(RDisasmState *ds) {
int emu = r_config_get_i (ds->core->config, "asm.emu");
int emuwrite = r_config_get_i (ds->core->config, "asm.emuwrite");
if (emu && emuwrite) {
// this is done by ESIL
return;
}
RAnal *anal = ds->core->anal;
RAnalFunction *fcn = r_anal_get_fcn_in (anal, ds->analop.jump, -1);
char *name;
if (!fcn) {
return;
}
if (r_anal_type_func_exist (anal, fcn->name)) {
name = strdup (fcn->name);
} else if (!(name = r_anal_type_func_guess (anal, fcn->name))) {
return;
}
if (ds->show_color) {
r_cons_strcat (ds->pal_comment);
}
ds_align_comment (ds);
const char *fcn_type = r_anal_type_func_ret (anal, name);
r_cons_printf ("; %s%s%s(", fcn_type, fcn_type[strlen (fcn_type) - 1] == '*' ? "": " ", name);
int i, arg_max = r_anal_type_func_args_count (anal, name);
2016-09-23 14:28:48 +00:00
if (!arg_max) {
r_cons_printf ("void);");
} else {
for (i = 0; i < arg_max; i++) {
char *type = r_anal_type_func_args_type (anal, name, i);
r_cons_printf ("%s%s%s%s%s", i == 0 ? "": " ", type,
type[strlen (type) -1] == '*' ? "": " ",
r_anal_type_func_args_name (anal, name, i),
i == arg_max - 1 ? ");": ",");
free (type);
}
}
free (name);
}
2016-09-21 09:00:52 +00:00
2016-05-30 10:35:39 +00:00
static void ds_print_comments_right(RDisasmState *ds) {
char *desc = NULL;
2016-05-30 10:35:39 +00:00
RCore *core = ds->core;
ds_print_relocs (ds);
if (ds->asm_describe && !ds->has_description) {
char *op, *locase = strdup (ds->asmop.buf_asm);
if (!locase) {
return;
}
op = strchr (locase, ' ');
if (op) *op = 0;
2015-07-15 12:55:00 +00:00
r_str_case (locase, 0);
desc = r_asm_describe (core->assembler, locase);
free (locase);
}
if (ds->show_comments) {
if (desc && *desc) {
2016-05-30 10:35:39 +00:00
ds_align_comment (ds);
if (ds->show_color) {
r_cons_strcat (ds->color_comment);
}
r_cons_strcat (" ; ");
r_cons_strcat (desc);
}
if (ds->show_comment_right && ds->comment) {
char *comment = r_str_chop (ds->comment);
if (*comment) {
if (!desc) {
ds_align_comment (ds);
}
if (ds->show_color) {
r_cons_strcat (ds->color_comment);
}
r_cons_printf (" ; %s", comment);
}
// r_cons_strcat_justify (comment, strlen (ds->refline) + 5, ';');
if (ds->show_color) {
2016-05-30 10:35:39 +00:00
ds_print_color_reset (ds);
}
2016-05-30 10:35:39 +00:00
R_FREE (ds->comment);
}
}
free (desc);
if (ds->analop.type == R_ANAL_OP_TYPE_CALL && ds->show_calls) {
ds_print_calls_hints (ds);
}
}
2014-11-10 12:26:03 +00:00
#if 0
static void handle_print_refptr_meta_infos(RCore *core, RDisasmState *ds, ut64 word8 ) {
RAnalMetaItem *mi2 = r_meta_find (core->anal, word8,
R_META_TYPE_ANY, R_META_WHERE_HERE);
if (mi2) {
switch (mi2->type) {
case R_META_TYPE_STRING:
{ char *str = r_str_escape (mi2->str);
r_cons_printf (" (at=0x%08"PFMT64x") (len=%"PFMT64d
") \"%s\" ", word8, mi2->size, str);
free (str);
}
break;
case 'd':
r_cons_printf (" (data)");
break;
default:
2014-07-22 23:34:28 +00:00
r_cons_printf (" (%c) %s", mi2->type, mi2->str);
break;
2014-05-04 15:21:05 +00:00
}
} else {
2014-01-23 02:47:20 +00:00
mi2 = r_meta_find (core->anal, (ut64)ds->analop.ptr,
R_META_TYPE_ANY, R_META_WHERE_HERE);
if (mi2) {
char *str = r_str_escape (mi2->str);
r_cons_printf (" \"%s\" @ 0x%08"PFMT64x":%"PFMT64d,
2014-01-20 00:42:16 +00:00
str, ds->analop.ptr, mi2->size);
free (str);
} else r_cons_printf (" ; 0x%08x [0x%"PFMT64x"]",
2014-01-20 00:42:16 +00:00
word8, ds->analop.ptr);
}
}
2014-11-10 12:26:03 +00:00
#endif
2014-01-20 00:42:16 +00:00
2016-05-30 10:35:39 +00:00
static void ds_print_as_string(RDisasmState *ds) {
char *str = r_num_as_string (NULL, ds->analop.ptr, true);
if (str) {
2016-05-30 10:35:39 +00:00
ds_align_comment (ds);
r_cons_printf (" %s; \"%s\"%s", COLOR (ds, pal_comment),
str, COLOR_RESET (ds));
}
free (str);
}
2014-11-10 12:26:03 +00:00
#if 0
static void handle_print_refptr(RCore *core, RDisasmState *ds) {
ut64 word8 = 0;
ut32 word4 = 0;
int ret;
2014-01-20 00:42:16 +00:00
ret = handle_read_refptr (core, ds, &word8, &word4);
if (ret) {
2014-01-20 00:42:16 +00:00
handle_print_refptr_meta_infos (core, ds, word8);
} else {
st64 sref = ds->analop.ptr; // todo. use .refptr?
if (sref>0) {
RFlagItem *f = r_flag_get_i (core->flags, ds->analop.ptr);
if (f) {
r_cons_printf (" ; %s", f->name);
} else {
r_cons_printf (" ; 0x%08"PFMT64x, ds->analop.ptr);
}
}
}
}
2014-11-10 12:26:03 +00:00
#endif
2014-01-20 00:42:16 +00:00
// int l is for lines
R_API int r_core_print_disasm(RPrint *p, RCore *core, ut64 addr, ut8 *buf, int len, int l, int invbreak, int cbytes) {
int continueoninvbreak = (len == l) && invbreak;
RAnalFunction *of = NULL;
RAnalFunction *f = NULL;
2016-02-22 22:45:36 +00:00
int ret, i, inc, skip_bytes = 0, idx = 0;
int dorepeat = 1;
ut8 *nbuf = NULL;
2014-01-20 00:42:16 +00:00
RDisasmState *ds;
2014-01-20 00:42:16 +00:00
// TODO: All those ds must be print flags
2016-05-30 10:35:39 +00:00
ds = ds_init (core);
2014-01-20 00:42:16 +00:00
ds->cbytes = cbytes;
2016-05-30 10:35:39 +00:00
ds->print = p;
2014-01-20 00:42:16 +00:00
ds->l = l;
ds->buf = buf;
ds->len = len;
ds->addr = addr;
2015-09-28 09:21:23 +00:00
ds->hint = NULL;
//r_cons_printf ("len =%d l=%d ib=%d limit=%d\n", len, l, invbreak, p->limit);
// TODO: import values from debugger is possible
// TODO: allow to get those register snapshots from traces
// TODO: per-function register state trace
// XXX - is there a better way to reset a the analysis counter so that
// when code is disassembled, it can actually find the correct offsets
2016-06-10 14:14:07 +00:00
{ /* used by asm.emu */
r_reg_arena_push (core->anal->reg);
}
if (core->anal->cur && core->anal->cur->reset_counter) {
core->anal->cur->reset_counter (core->anal, addr);
}
2016-05-30 10:35:39 +00:00
ds_reflines_init (ds);
core->inc = 0;
/* reset jmp table if not asked to keep it */
if (!core->keep_asmqjmps) { // hack
core->asmqjmps_count = 0;
core->asmqjmps_size = R_CORE_ASMQJMPS_NUM;
core->asmqjmps = realloc (core->asmqjmps, core->asmqjmps_size * sizeof (ut64));
if (core->asmqjmps) {
for (i = 0; i < R_CORE_ASMQJMPS_NUM; i++) {
core->asmqjmps[i] = UT64_MAX;
}
}
}
toro:
// uhm... is this necesary? imho can be removed
2016-09-22 16:06:10 +00:00
r_asm_set_pc (core->assembler, ds->addr + idx);
core->cons->vline = r_config_get_i (core->config, "scr.utf8") ? r_vline_u : r_vline_a;
if (core->print->cur_enabled) {
// TODO: support in-the-middle-of-instruction too
2016-04-03 22:52:45 +00:00
r_anal_op_fini (&ds->analop);
if (r_anal_op (core->anal, &ds->analop, core->offset + core->print->cur,
buf + core->print->cur, (int)(len - core->print->cur))) {
2014-01-20 00:42:16 +00:00
// TODO: check for ds->analop.type and ret
ds->dest = ds->analop.jump;
}
} else {
/* highlight eip */
const char *pc = core->anal->reg->name[R_REG_NAME_PC];
RFlagItem *item = r_flag_get (core->flags, pc);
if (item) {
ds->dest = item->offset;
}
}
2016-05-30 10:35:39 +00:00
ds_print_esil_anal_init (ds);
r_cons_break (NULL, NULL);
2016-02-22 22:45:36 +00:00
inc = 0;
if (!ds->l) {
len = ds->l = core->blocksize;
2016-02-22 22:45:36 +00:00
}
r_anal_build_range_on_hints (core->anal);
2016-09-22 16:06:10 +00:00
for (i = idx = ret = 0; idx < len && ds->lines < ds->l; idx += inc, i++, ds->index += inc, ds->lines++) {
2014-01-20 00:42:16 +00:00
ds->at = ds->addr + idx;
if (core->cons && core->cons->breaked) {
dorepeat = 0;
return 0; //break;
}
2014-01-20 00:42:16 +00:00
r_core_seek_archbits (core, ds->at); // slow but safe
ds->has_description = false;
2014-01-20 00:42:16 +00:00
ds->hint = r_core_hint_begin (core, ds->hint, ds->at);
r_asm_set_pc (core->assembler, ds->at);
2016-05-30 10:35:39 +00:00
ds_update_ref_lines (ds);
f = r_anal_get_fcn_in (core->anal, ds->at, R_ANAL_FCN_TYPE_NULL);
ds->fcn = f;
if (f && f->folded && r_anal_fcn_is_in_offset (f, ds->at)) {
int delta = (ds->at <= f->addr)? (ds->at - f->addr + r_anal_fcn_size (f)): 0;
if (of != f) {
char cmt[32];
2016-09-21 09:00:52 +00:00
get_bits_comment (core, f, cmt, sizeof (cmt));
2016-05-30 10:35:39 +00:00
ds_show_comments_right (ds);
r_cons_printf ("%s%s%s (fcn) %s%s%s\n",
2016-10-20 23:24:40 +00:00
COLOR (ds, color_fline), core->cons->vline[CORNER_TL],
COLOR (ds, color_fname), f->name, cmt, COLOR_RESET (ds));
2016-05-30 10:35:39 +00:00
ds_setup_print_pre (ds, true, false);
ds_print_lines_left (ds);
ds_print_offset (ds);
r_cons_printf ("(%d byte folded function)\n", r_anal_fcn_size (f));
//r_cons_printf ("%s%s%s\n", COLOR (ds, color_fline), core->cons->vline[RDWN_CORNER], COLOR_RESET (ds));
if (delta < 0) {
delta = -delta;
}
ds->addr += delta + idx;
r_io_read_at (core->io, ds->addr, buf, len);
inc = 0; //delta;
idx = 0;
of = f;
if (len == l) {
2015-12-16 14:30:13 +00:00
break;
}
continue;
} else {
ds->lines--;
ds->addr += 1;
r_io_read_at (core->io, ds->addr, buf, len);
inc = 0; //delta;
idx = 0;
// r_cons_printf ("delta %d fsize %d\n", delta, f->size);
// inc = 1;
continue;
}
}
2014-01-20 00:42:16 +00:00
if (!ds->hint || !ds->hint->bits) {
if (f) {
if (f->bits) {
if (!ds->oldbits) {
2014-01-20 00:42:16 +00:00
ds->oldbits = r_config_get_i (core->config, "asm.bits");
}
2014-01-20 00:42:16 +00:00
if (ds->oldbits != f->bits) {
r_config_set_i (core->config, "asm.bits", f->bits);
}
} else {
2014-01-20 00:42:16 +00:00
if (ds->oldbits) {
r_config_set_i (core->config, "asm.bits", ds->oldbits);
ds->oldbits = 0;
}
}
} else {
2014-01-20 00:42:16 +00:00
if (ds->oldbits) {
r_config_set_i (core->config, "asm.bits", ds->oldbits);
ds->oldbits = 0;
}
}
}
2016-05-30 10:35:39 +00:00
ds_show_comments_right (ds);
//TRY adding here
char *link_key = sdb_fmt (-1, "link.%08"PFMT64x, ds->addr + idx);
const char *link_type = sdb_const_get (core->anal->sdb_types, link_key, 0);
if (link_type) {
char *fmt = r_anal_type_format (core->anal, link_type);
if (fmt) {
r_cons_printf ("(%s)\n", link_type);
r_core_cmdf (core, "pf %s @ 0x%08"PFMT64x"\n", fmt, ds->addr + idx);
inc += r_anal_type_get_size (core->anal, link_type) / 8;
free (fmt);
continue;
}
} else {
ret = ds_disassemble (ds, buf + idx, len - idx);
if (ret == -31337) {
inc = ds->oplen;
continue;
}
}
2014-01-20 00:42:16 +00:00
if (ds->retry) {
ds->retry = 0;
goto retry;
}
2016-05-30 10:35:39 +00:00
ds_atabs_option (ds);
// TODO: store previous oplen in core->dec
2016-09-22 16:06:10 +00:00
if (!core->inc) {
2014-01-20 00:42:16 +00:00
core->inc = ds->oplen;
}
2016-04-03 23:03:31 +00:00
if (ds->analop.mnemonic || !ds->lastfail) {
r_anal_op_fini (&ds->analop);
}
if (!ds->lastfail) {
2016-10-20 23:24:40 +00:00
r_anal_op (core->anal, &ds->analop, ds->at, buf+idx, (int)(len - idx));
}
if (ret < 1) {
2014-01-20 00:42:16 +00:00
r_strbuf_init (&ds->analop.esil);
ds->analop.type = R_ANAL_OP_TYPE_ILL;
}
2014-01-20 00:42:16 +00:00
if (ds->hint) {
if (ds->hint->size) {
ds->analop.size = ds->hint->size;
}
if (ds->hint->ptr) {
ds->analop.ptr = ds->hint->ptr;
}
}
2016-05-30 10:35:39 +00:00
ds_print_bbline (ds);
2016-04-03 23:59:30 +00:00
if (ds->at >= addr) {
r_print_set_rowoff (core->print, ds->lines, ds->at - addr);
}
2015-12-17 19:18:50 +00:00
if (ds->midflags) {
skip_bytes = handleMidFlags (core, ds, true);
2016-06-13 23:52:46 +00:00
if (skip_bytes && ds->midflags == R_MIDFLAGS_SHOW) {
2015-12-17 19:18:50 +00:00
ds->at += skip_bytes;
2016-06-13 23:52:46 +00:00
}
2015-12-17 19:18:50 +00:00
}
2016-05-30 10:35:39 +00:00
ds_show_flags (ds);
if (skip_bytes && ds->midflags == R_MIDFLAGS_SHOW) {
2015-12-17 19:18:50 +00:00
ds->at -= skip_bytes;
}
2016-05-30 10:35:39 +00:00
ds_instruction_mov_lea (ds, idx);
ds_control_flow_comments (ds);
ds_adistrick_comments (ds);
/* XXX: This is really cpu consuming.. need to be fixed */
2016-05-30 10:35:39 +00:00
ds_show_functions (ds);
ds_show_xrefs (ds);
ds_setup_print_pre (ds, false, false);
ds_print_lines_left (ds);
2016-01-27 02:33:52 +00:00
if (ds->show_comments && !ds->show_comment_right) {
if (ds->show_emu) {
2016-05-30 10:35:39 +00:00
ds_print_esil_anal (ds);
2016-01-27 02:33:52 +00:00
r_cons_newline ();
2016-05-30 10:35:39 +00:00
ds_setup_print_pre (ds, false, false);
ds_print_lines_left (ds);
2016-01-27 02:33:52 +00:00
}
2016-01-27 01:35:45 +00:00
}
f = r_anal_get_fcn_in (core->anal, ds->addr, 0);
2016-05-30 10:35:39 +00:00
if (ds_print_labels (ds, f)) {
ds_show_functions (ds);
ds_show_xrefs (ds);
ds_setup_print_pre (ds, false, false);
ds_print_lines_left (ds);
}
ds_print_offset (ds);
ds_print_op_size (ds);
ds_print_trace (ds);
ds_print_cycles (ds);
ds_print_family (ds);
ds_print_stackptr (ds);
ret = ds_print_meta_infos (ds, buf, len, idx);
if (!ds->mi_found) {
/* show cursor */
2016-05-30 10:35:39 +00:00
ds_print_show_cursor (ds);
ds_print_show_bytes (ds);
ds_print_lines_right (ds);
ds_build_op_str (ds);
ds_print_opstr (ds);
ds_print_fcn_name (ds);
ds_print_color_reset (ds);
ds_print_dwarf (ds);
ret = ds_print_middle (ds, ret);
ds_print_asmop_payload (ds);
if (core->assembler->syntax != R_ASM_SYNTAX_INTEL) {
RAsmOp ao; /* disassemble for the vm .. */
int os = core->assembler->syntax;
r_asm_set_syntax (core->assembler, R_ASM_SYNTAX_INTEL);
2016-10-20 23:24:40 +00:00
r_asm_disassemble (core->assembler, &ao, buf+idx, len-idx + 5);
r_asm_set_syntax (core->assembler, os);
}
2016-05-30 10:35:39 +00:00
ds_print_core_vmode (ds);
//ds_print_cc_update (ds);
} else {
ds->mi_found = 0;
}
2016-05-30 10:35:39 +00:00
ds_print_op_push_info (ds);
ds_print_ptr (ds, len + 256, idx);
Add asm.hints and handle CDOV deoptimization CDIV deoptimization =================== This patch implements hints in the disassembler that aim to assist the user in reading compiler-optimized divisions by analysing the involved magic number. Background ========== Since integer divisions are usually very expensive on most architectures, compilers try very hard to substitute them with cheaper operations. One of the more advanced substitutions is described in the book __Hacker's Delight__, chapter 10. An actual implementation of the described algorithm in LLVM can be found in the functions: `TargetLowering::BuildSDIV()` and `APInt::magic()`. The optimization approximately transforms e.g. ```asm xor edx, edx idiv 39 ``` into ```asm mov eax, edi mov edx, 0xd20d20d3 imul edx lea eax, [rdx + rdi] sar edi, 0x1f sar eax, 5 sub eax, edi ``` Reading the optimized version and __seeing__ the constant 39 seems difficult. Therefore I try to provide a small hint to the user. Limitations =========== * The current implementation only takes the magic number into account, therefore it may result in false positives. * Due to the nature of the optimization, the given hint may be off by a power of two. Fixing this would require to analyse the following shift instructions. * The hint is only shown in the line containing the magic number. The user still has to know which of the following instructions belong to the optimization. TODO ==== * Implement the corresponding analysis for unsigned integers * Implement the corresponding analysis for 64-bit integers. * Improve the heuristic by also looking at the next few instructions. ( I don't really know how to iterate over the instructions in the disassember in a non-deprecated way. Maybe someone can drop me a hint? ) * Implement an exact analysis using the actual dataflow in radeco and use it to revert the optimization. ( I suppose this is outside the scope of radare )
2016-06-15 13:18:04 +00:00
ds_cdiv_optimization (ds);
2016-05-30 10:35:39 +00:00
ds_print_comments_right (ds);
ds_show_refs (ds);
if (!(ds->show_comments && ds->show_comment_right && ds->comment)) {
2016-05-30 10:35:39 +00:00
ds_print_esil_anal (ds);
2016-01-27 01:49:40 +00:00
r_cons_newline ();
}
2014-01-20 00:42:16 +00:00
if (ds->line) {
if (ds->show_lines_ret && ds->analop.type == R_ANAL_OP_TYPE_RET) {
if (strchr (ds->line, '>')) {
2014-01-20 00:42:16 +00:00
memset (ds->line, ' ', r_str_len_utf8 (ds->line));
2015-09-02 08:01:53 +00:00
}
r_cons_printf ("%s%s%s%s; --------------------------------------\n",
ds->pre, COLOR (ds, color_flow), ds->line, COLOR_RESET (ds));
}
2016-04-03 22:52:45 +00:00
R_FREE (ds->line);
R_FREE (ds->refline);
R_FREE (ds->refline2);
}
R_FREE (ds->opstr);
inc = ds->oplen;
2016-06-13 23:52:46 +00:00
if (ds->midflags == R_MIDFLAGS_REALIGN && skip_bytes) {
2015-12-17 19:18:50 +00:00
inc = skip_bytes;
2016-06-13 23:52:46 +00:00
}
if (inc < 1) {
2016-02-07 20:44:35 +00:00
inc = 1;
2016-06-13 23:52:46 +00:00
}
}
if (nbuf == buf) {
2016-06-13 23:52:46 +00:00
R_FREE (buf);
}
r_cons_break_end ();
#if HASRETRY
2016-09-22 16:06:10 +00:00
if (!ds->cbytes && ds->lines < ds->l && dorepeat) {
ds->addr = ds->at + inc;
retry:
if (len < 4) {
len = 4;
}
buf = nbuf = malloc (len);
if (ds->tries > 0) {
2014-01-20 00:42:16 +00:00
if (r_core_read_at (core, ds->addr, buf, len) ) {
goto toro;
}
}
if (ds->lines < ds->l) {
//ds->addr += idx;
2014-01-20 00:42:16 +00:00
if (r_core_read_at (core, ds->addr, buf, len) != len) {
//ds->tries = -1;
}
goto toro;
}
2016-06-10 14:14:07 +00:00
if (continueoninvbreak) {
goto toro;
2016-06-10 14:14:07 +00:00
}
}
#endif
2014-01-20 00:42:16 +00:00
if (ds->oldbits) {
r_config_set_i (core->config, "asm.bits", ds->oldbits);
ds->oldbits = 0;
2013-08-11 13:38:42 +00:00
}
r_print_set_rowoff (core->print, ds->lines, ds->at - addr);
r_print_set_rowoff (core->print, ds->lines + 1, UT32_MAX);
2015-09-12 17:12:57 +00:00
// TODO: this too (must review)
2016-05-30 10:35:39 +00:00
ds_print_esil_anal_fini (ds);
ds_reflines_fini (ds);
ds_free (ds);
/* used by asm.emu */
r_reg_arena_pop (core->anal->reg);
2014-01-20 00:42:16 +00:00
return idx; //-ds->lastfail;
2013-08-11 13:38:42 +00:00
}
/* Disassemble either `nb_opcodes` instructions, or
* `nb_bytes` bytes; both can be negative.
* Set to 0 the parameter you don't use */
R_API int r_core_print_disasm_instructions(RCore *core, int nb_bytes, int nb_opcodes) {
2014-01-22 22:58:23 +00:00
RDisasmState *ds = NULL;
2016-06-06 08:36:09 +00:00
int i, j, ret, len = 0;
RAnalFunction *f;
2014-01-20 00:42:16 +00:00
char *tmpopstr;
const ut64 old_offset = core->offset;
bool hasanal = false;
r_reg_arena_push (core->anal->reg);
if (!nb_bytes) {
nb_bytes = core->blocksize;
if (nb_opcodes < 0) {
/* Backward disassembly or nb_opcodes opcodes
* - We compute the new starting offset
* - Read at the new offset */
nb_opcodes = -nb_opcodes;
r_core_asm_bwdis_len (core, &nb_bytes, &core->offset, nb_opcodes);
r_core_read_at (core, core->offset, core->block, nb_bytes);
}
} else {
if (nb_bytes < 0) { // Disassemble backward `nb_bytes` bytes
nb_bytes = -nb_bytes;
core->offset -= nb_bytes;
r_core_read_at (core, core->offset, core->block, nb_bytes);
}
}
// XXX - is there a better way to reset a the analysis counter so that
// when code is disassembled, it can actually find the correct offsets
if (core->anal->cur && core->anal->cur->reset_counter) {
core->anal->cur->reset_counter (core->anal, core->offset);
}
2016-05-30 10:35:39 +00:00
ds = ds_init (core);
ds->l = nb_opcodes;
2015-10-20 22:26:32 +00:00
ds->len = nb_opcodes * 8;
2015-10-20 23:51:34 +00:00
if (ds->len > core->blocksize) {
if (core->fixedblock) {
nb_bytes = ds->len = core->blocksize;
} else {
r_core_block_size (core, ds->len);
r_core_block_read (core);
2015-10-20 23:51:34 +00:00
}
}
if (!ds->l) {
ds->l = ds->len;
}
r_cons_break (NULL, NULL);
//build ranges to map addr with bits
r_anal_build_range_on_hints (core->anal);
2015-10-20 22:26:32 +00:00
#define isTheEnd (nb_opcodes? j<nb_opcodes: i<nb_bytes)
for (i = j = 0; isTheEnd; i += ret, j++) {
2014-01-20 00:42:16 +00:00
ds->at = core->offset +i;
hasanal = false;
2014-01-20 00:42:16 +00:00
r_core_seek_archbits (core, ds->at);
if (r_cons_singleton ()->breaked) {
break;
}
2014-01-20 00:42:16 +00:00
ds->hint = r_core_hint_begin (core, ds->hint, ds->at);
ds->has_description = false;
2014-01-20 00:42:16 +00:00
r_asm_set_pc (core->assembler, ds->at);
// XXX copypasta from main disassembler function
f = r_anal_get_fcn_in (core->anal, ds->at, R_ANAL_FCN_TYPE_NULL);
2014-01-20 00:42:16 +00:00
if (!ds->hint || !ds->hint->bits) {
if (f) {
if (f->bits) {
if (!ds->oldbits) {
2014-01-20 00:42:16 +00:00
ds->oldbits = r_config_get_i (core->config, "asm.bits");
}
2014-01-20 00:42:16 +00:00
if (ds->oldbits != f->bits) {
r_config_set_i (core->config, "asm.bits", f->bits);
}
2013-09-30 10:56:00 +00:00
} else {
2014-01-20 00:42:16 +00:00
if (ds->oldbits != 0) {
r_config_set_i (core->config, "asm.bits", ds->oldbits);
ds->oldbits = 0;
}
2013-09-30 10:56:00 +00:00
}
} else {
2014-01-20 00:42:16 +00:00
if (ds->oldbits) {
r_config_set_i (core->config, "asm.bits", ds->oldbits);
ds->oldbits = 0;
}
}
}
ret = r_asm_disassemble (core->assembler, &ds->asmop, core->block+i, core->blocksize-i);
2016-04-03 22:17:57 +00:00
r_anal_op_fini (&ds->analop);
2015-06-04 11:05:02 +00:00
if (ds->show_color && !hasanal) {
r_anal_op (core->anal, &ds->analop, ds->at, core->block + i, core->blocksize - i);
hasanal = true;
2015-06-04 11:05:02 +00:00
}
//r_cons_printf ("0x%08"PFMT64x" ", core->offset+i);
if (ds->hint && ds->hint->size) {
2014-01-20 00:42:16 +00:00
ret = ds->hint->size;
ds->oplen = ret;
ds->analop.size = ret;
ds->asmop.size = ret;
}
2016-06-06 08:36:09 +00:00
len += R_MAX (0, ret);
2014-01-20 00:42:16 +00:00
if (ds->hint && ds->hint->opcode) {
free (ds->opstr);
2014-01-20 00:42:16 +00:00
ds->opstr = strdup (ds->hint->opcode);
} else {
2014-01-20 00:42:16 +00:00
if (ds->use_esil) {
2015-06-04 11:05:02 +00:00
if (!hasanal) {
r_anal_op (core->anal, &ds->analop,
ds->at, core->block+i,
core->blocksize-i);
hasanal = true;
2015-06-04 11:05:02 +00:00
}
2014-01-20 00:42:16 +00:00
if (*R_STRBUF_SAFEGET (&ds->analop.esil)) {
free (ds->opstr);
2014-01-20 00:42:16 +00:00
ds->opstr = strdup (R_STRBUF_SAFEGET (&ds->analop.esil));
}
} else if (ds->filter) {
2015-10-20 21:37:20 +00:00
char *asm_str;
int ofs = core->parser->flagspace;
int fs = ds->flagspace_ports;
if (ds->analop.type == R_ANAL_OP_TYPE_IO) {
core->parser->notin_flagspace = -1;
core->parser->flagspace = fs;
} else {
if (fs != -1) {
core->parser->notin_flagspace = fs;
core->parser->flagspace = fs;
} else {
core->parser->notin_flagspace = -1;
core->parser->flagspace = -1;
}
}
2015-10-20 21:37:20 +00:00
core->parser->hint = ds->hint;
r_parse_filter (core->parser, core->flags,
ds->asmop.buf_asm, ds->str, sizeof (ds->str), core->print->big_endian);
2015-10-20 21:37:20 +00:00
ds->opstr = strdup (ds->str);
asm_str = colorize_asm_string (core, ds);
core->parser->flagspace = ofs;
free (ds->opstr);
2015-10-20 21:37:20 +00:00
ds->opstr = asm_str;
core->parser->flagspace = ofs; // ???
2015-10-20 21:37:20 +00:00
} else {
ds->opstr = strdup (ds->asmop.buf_asm);
}
if (ds->decode) {
free (ds->opstr);
2015-06-04 11:05:02 +00:00
if (!hasanal) {
r_anal_op (core->anal, &ds->analop, ds->at, core->block+i, core->blocksize-i);
hasanal = true;
2015-06-04 11:05:02 +00:00
}
2014-01-20 00:42:16 +00:00
tmpopstr = r_anal_op_to_string (core->anal, &ds->analop);
ds->opstr = (tmpopstr)? tmpopstr: strdup (ds->asmop.buf_asm);
}
}
2015-11-02 17:57:01 +00:00
{
2015-06-04 11:05:02 +00:00
const char *opcolor = NULL;
if (ds->show_color) {
opcolor = r_print_color_op_type (core->print, ds->analop.type);
r_cons_printf ("%s%s" Color_RESET "\n", opcolor, ds->opstr);
} else {
r_cons_println (ds->opstr);
2015-06-04 11:05:02 +00:00
}
2016-05-30 10:35:39 +00:00
R_FREE (ds->opstr);
}
if (ds->hint) {
r_anal_hint_free (ds->hint);
ds->hint = NULL;
}
}
r_cons_break_end ();
2014-01-20 00:42:16 +00:00
if (ds->oldbits) {
r_config_set_i (core->config, "asm.bits", ds->oldbits);
ds->oldbits = 0;
}
2016-05-30 10:35:39 +00:00
ds_free (ds);
core->offset = old_offset;
2016-06-06 08:36:09 +00:00
r_reg_arena_pop (core->anal->reg);
return len;
}
R_API int r_core_print_disasm_json(RCore *core, ut64 addr, ut8 *buf, int nb_bytes, int nb_opcodes) {
RAsmOp asmop;
RDisasmState *ds;
RAnalFunction *f;
int i, j, k, oplen, ret, line;
ut64 old_offset = core->offset;
ut64 at;
int dis_opcodes = 0;
r_cons_printf ("[");
2015-04-08 08:41:42 +00:00
int limit_by = 'b';
2015-04-08 08:41:42 +00:00
if (nb_opcodes != 0) {
limit_by = 'o';
}
2015-02-16 23:54:55 +00:00
if (nb_opcodes) { // Disassemble `nb_opcodes` opcodes.
if (nb_opcodes < 0) {
2015-02-16 23:54:55 +00:00
int count, nbytes = 0;
/* Backward disassembly of `nb_opcodes` opcodes:
* - We compute the new starting offset
* - Read at the new offset */
nb_opcodes = -nb_opcodes;
if (nb_opcodes > 0xffff) {
eprintf ("Too many backward instructions\n");
return 0;
}
if (r_core_prevop_addr (core, core->offset, nb_opcodes, &addr)) {
nbytes = core->offset - addr;
} else if (!r_core_asm_bwdis_len (core, &nbytes, &addr, nb_opcodes)) {
/* workaround to avoid empty arrays */
#define BWRETRY 0
#if BWRETRY
nb_opcodes ++;
if (!r_core_asm_bwdis_len (core, &nbytes, &addr, nb_opcodes)) {
#endif
r_cons_printf ("]");
2015-09-14 10:35:38 +00:00
return false;
#if BWRETRY
}
#endif
nb_opcodes --;
2014-12-19 19:44:44 +00:00
}
2015-02-16 23:54:55 +00:00
count = R_MIN (nb_bytes, nbytes);
if (count > 0) {
2015-02-16 23:54:55 +00:00
r_core_read_at (core, addr, buf, count);
r_core_read_at (core, addr+count, buf+count, nb_bytes-count);
} else {
if (nb_bytes > 0) {
memset (buf, 0xff, nb_bytes);
}
2015-02-16 23:54:55 +00:00
}
} else {
// If we are disassembling a positive number of lines, enable dis_opcodes
// to be used to finish the loop
// If we are disasembling a negative number of lines, we just calculate
// the equivalent addr and nb_size and scan a positive number of BYTES
// so keep dis_opcodes = 0;
dis_opcodes = 1;
r_core_read_at (core, addr, buf, nb_bytes);
}
2016-02-16 20:48:07 +00:00
} else { // Disassemble `nb_bytes` bytes
if (nb_bytes < 0) {
//Backward disassembly of `nb_bytes` bytes
nb_bytes = -nb_bytes;
addr -= nb_bytes;
r_core_read_at (core, addr, buf, nb_bytes);
}
}
core->offset = addr;
// XXX - is there a better way to reset a the analysis counter so that
// when code is disassembled, it can actually find the correct offsets
if (core->anal && core->anal->cur && core->anal->cur->reset_counter) {
core->anal->cur->reset_counter (core->anal, addr);
}
// TODO: add support for anal hints
// If using #bytes i = j
// If using #opcodes, j is the offset from start address. i is the
// offset in current disassembly buffer (256 by default)
i = k = j = line = 0;
2015-04-09 23:57:17 +00:00
// i = number of bytes
// j = number of instructions
// k = delta from addr
2016-09-28 14:47:16 +00:00
ds = ds_init (core);
for (;;) {
bool end_nbopcodes, end_nbbytes;
at = addr + k;
r_asm_set_pc (core->assembler, at);
// 32 is the biggest opcode length in intel
// Make sure we have room for it
if (dis_opcodes == 1 && i >= nb_bytes - 32) {
// Read another nb_bytes bytes into buf from current offset
r_core_read_at (core, at, buf, nb_bytes);
i = 0;
}
2015-04-08 08:41:42 +00:00
if (limit_by == 'o') {
if (j >= nb_opcodes) {
2015-04-08 08:41:42 +00:00
break;
}
} else if (i >= nb_bytes) {
break;
2015-04-08 01:20:11 +00:00
}
ret = r_asm_disassemble (core->assembler, &asmop, buf + i, nb_bytes - i);
if (ret < 1) {
r_cons_printf (j > 0 ? ",{" : "{");
r_cons_printf ("\"offset\":%"PFMT64d, at);
r_cons_printf (",\"size\":1,\"type\":\"invalid\"}");
i++;
k++;
j++;
continue;
}
ds->has_description = false;
r_anal_op_fini (&ds->analop);
r_anal_op (core->anal, &ds->analop, at, buf + i, nb_bytes - i);
2016-08-02 23:17:27 +00:00
if (ds->pseudo) {
r_parse_parse (core->parser, asmop.buf_asm, asmop.buf_asm);
}
f = r_anal_get_fcn_in (core->anal, at, R_ANAL_FCN_TYPE_FCN | R_ANAL_FCN_TYPE_SYM);
if (ds->varsub && f) {
core->parser->varlist = r_anal_var_list_dynamic;
2015-11-19 22:12:08 +00:00
r_parse_varsub (core->parser, f, at, ds->analop.size,
asmop.buf_asm, asmop.buf_asm, sizeof (asmop.buf_asm));
}
oplen = r_asm_op_get_size (&asmop);
2016-08-02 23:17:27 +00:00
r_cons_printf (j > 0 ? ",{" : "{");
r_cons_printf ("\"offset\":%"PFMT64d, at);
if (f) {
r_cons_printf (",\"fcn_addr\":%"PFMT64d, f->addr);
r_cons_printf (",\"fcn_last\":%"PFMT64d, f->addr + r_anal_fcn_size (f) - oplen);
} else {
r_cons_printf (",\"fcn_addr\":0");
r_cons_printf (",\"fcn_last\":0");
}
r_cons_printf (",\"size\":%d", oplen);
2014-12-19 16:49:42 +00:00
{
char *escaped_str = r_str_escape (asmop.buf_asm);
r_cons_printf (",\"opcode\":\"%s\"", escaped_str);
free (escaped_str);
}
if (ds->use_esil) {
const char * esil = R_STRBUF_SAFEGET (&ds->analop.esil);
r_cons_printf (",\"esil\":\"%s\"", esil);
2014-12-19 16:49:42 +00:00
}
r_cons_printf (",\"bytes\":\"%s\"", asmop.buf_hex);
2015-10-08 15:02:22 +00:00
r_cons_printf (",\"family\":\"%s\"",
r_anal_op_family_to_string (ds->analop.family));
r_cons_printf (",\"type\":\"%s\"", r_anal_optype_to_string (ds->analop.type));
// wanted the numerical values of the type information
r_cons_printf (",\"type_num\":%"PFMT64d, ds->analop.type);
r_cons_printf (",\"type2_num\":%"PFMT64d, ds->analop.type2);
// handle switch statements
if (ds->analop.switch_op && r_list_length (ds->analop.switch_op->cases) > 0) {
// XXX - the java caseop will still be reported in the assembly,
// this is an artifact to make ensure the disassembly is properly
// represented during the analysis
RListIter *iter;
RAnalCaseOp *caseop;
int cnt = r_list_length (ds->analop.switch_op->cases);
r_cons_printf (", \"switch\":[");
r_list_foreach (ds->analop.switch_op->cases, iter, caseop ) {
cnt--;
r_cons_printf ("{");
r_cons_printf ("\"addr\":%"PFMT64d, caseop->addr);
r_cons_printf (", \"value\":%"PFMT64d, (st64) caseop->value);
r_cons_printf (", \"jump\":%"PFMT64d, caseop->jump);
r_cons_printf ("}");
if (cnt > 0) r_cons_printf (",");
}
r_cons_printf ("]");
}
if (ds->analop.jump != UT64_MAX ) {
r_cons_printf (",\"jump\":%"PFMT64d, ds->analop.jump);
if (ds->analop.fail != UT64_MAX) {
r_cons_printf (",\"fail\":%"PFMT64d, ds->analop.fail);
}
}
/* add flags */
{
const RList *flags = r_flag_get_list (core->flags, at);
RFlagItem *flag;
RListIter *iter;
if (flags && !r_list_empty (flags)) {
r_cons_printf (",\"flags\":[");
r_list_foreach (flags, iter, flag) {
r_cons_printf ("%s\"%s\"", iter->p?",":"",flag->name);
}
r_cons_printf ("]");
}
}
/* add comments */
{
// TODO: slow because we are decoding and encoding b64
char *comment = r_meta_get_string (core->anal, R_META_TYPE_COMMENT, at);
if (comment) {
char *b64comment = sdb_encode ((const ut8*)comment, -1);
r_cons_printf (",\"comment\":\"%s\"", b64comment);
free (comment);
free (b64comment);
}
}
/* add xrefs */
{
RAnalRef *ref;
RListIter *iter;
RList *xrefs = r_anal_xref_get (core->anal, at);
if (xrefs && !r_list_empty (xrefs)) {
r_cons_printf (",\"xrefs\":[");
r_list_foreach (xrefs, iter, ref) {
r_cons_printf ("%s{\"addr\":%"PFMT64d",\"type\":\"%s\"}",
iter->p?",":"", ref->addr,
r_anal_xrefs_type_tostring (ref->type));
}
r_cons_printf ("]");
}
2015-01-15 23:56:54 +00:00
r_list_free (xrefs);
}
r_cons_printf ("}");
2015-04-09 23:57:17 +00:00
i += oplen; // bytes
k += oplen; // delta from addr
j++; // instructions
2014-08-21 22:39:31 +00:00
line++;
end_nbopcodes = dis_opcodes == 1 && nb_opcodes > 0 && line>=nb_opcodes;
end_nbbytes = dis_opcodes == 0 && nb_bytes > 0 && i>=nb_bytes;
2016-09-28 14:47:16 +00:00
if (end_nbopcodes || end_nbbytes) {
break;
}
}
r_cons_printf ("]");
core->offset = old_offset;
r_anal_op_fini (&ds->analop);
2015-09-14 10:35:38 +00:00
return true;
}
R_API int r_core_print_disasm_all(RCore *core, ut64 addr, int l, int len, int mode) {
const bool scr_color = r_config_get_i (core->config, "scr.color");
int i, ret, err = 0, count = 0;
ut8 *buf = core->block;
char str[128];
RAsmOp asmop;
if (l < 1) {
l = len;
}
if (l > core->blocksize || addr != core->offset) {
buf = malloc (l + 1);
r_core_read_at (core, addr, buf, l);
}
if (mode == 'j') {
r_cons_printf ("[");
}
r_cons_break (NULL, NULL);
for (i = 0; i < l; i++) {
r_asm_set_pc (core->assembler, addr + i);
if (r_cons_singleton ()->breaked) {
break;
}
ret = r_asm_disassemble (core->assembler, &asmop, buf + i, l - i);
if (ret < 1) {
ret = err = 1;
switch (mode) {
case 'j':
case '=':
break;
case 'i':
r_cons_printf ("???\n");
break;
default:
r_cons_printf ("0x%08"PFMT64x" ???\n", addr + i);
break;
}
} else {
count ++;
switch (mode) {
case 'i':
r_parse_filter (core->parser, core->flags, asmop.buf_asm,
str, sizeof (str), core->print->big_endian);
if (scr_color) {
char *buf_asm;
RAnalOp aop;
r_anal_op (core->anal, &aop, addr, buf+i, l-i);
buf_asm = r_print_colorize_opcode (str,
core->cons->pal.reg, core->cons->pal.num);
r_cons_printf ("%s%s\n",
r_print_color_op_type (core->print, aop.type),
buf_asm);
free (buf_asm);
} else {
r_cons_println (asmop.buf_asm);
}
break;
case '=':
if (i < 28) {
char *str = r_str_newf ("0x%08"PFMT64x" %60s %s\n",
addr + i, "", asmop.buf_asm);
char *sp = strchr (str, ' ');
if (sp) {
char *end = sp + 60 + 1;
const char *src = asmop.buf_hex;
char *dst = sp + 1 + (i * 2);
int len = strlen (src);
if (dst < end) {
if (dst + len >= end) {
len = end - dst;
dst[len] = '.';
}
memcpy (dst, src, len);
}
}
r_cons_strcat (str);
free (str);
}
break;
case 'j':
r_cons_printf ("{\"addr\":%08"PFMT64d",\"bytes\":\"%s\",\"inst\":\"%s\"}%s",
addr + i, asmop.buf_hex, asmop.buf_asm, ",");
break;
default:
r_cons_printf ("0x%08"PFMT64x" %20s %s\n",
addr + i, asmop.buf_hex, asmop.buf_asm);
}
}
}
r_cons_break_end ();
if (buf != core->block) {
free (buf);
}
if (mode == 'j') {
r_cons_printf ("{}]\n");
}
return count;
}
R_API int r_core_print_fcn_disasm(RPrint *p, RCore *core, ut64 addr, int l, int invbreak, int cbytes) {
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, addr, R_ANAL_FCN_TYPE_NULL);
2015-04-22 22:46:28 +00:00
ut32 cur_buf_sz = 0;
ut8 *buf = NULL;
ut32 len = 0;
int ret, idx = 0, i;
RListIter *bb_iter;
RAnalBlock *bb = NULL;
RDisasmState *ds;
2015-04-22 22:46:28 +00:00
RList *bb_list = NULL;
2016-09-22 16:06:10 +00:00
if (!fcn) {
2015-04-22 22:46:28 +00:00
return -1;
2016-09-22 16:06:10 +00:00
}
2015-04-22 22:46:28 +00:00
cur_buf_sz = r_anal_fcn_size (fcn) + 1;
2015-04-22 22:46:28 +00:00
buf = malloc (cur_buf_sz);
2016-09-22 16:06:10 +00:00
if (!buf) {
return -1;
}
len = r_anal_fcn_size (fcn);
2015-04-22 22:46:28 +00:00
bb_list = r_list_new();
2016-05-24 20:22:15 +00:00
if (!bb_list) {
free (buf);
return -1;
}
//r_cons_printf ("len =%d l=%d ib=%d limit=%d\n", len, l, invbreak, p->limit);
// TODO: import values from debugger is possible
// TODO: allow to get those register snapshots from traces
// TODO: per-function register state trace
idx = 0;
memset (buf, 0, cur_buf_sz);
// XXX - is there a better way to reset a the analysis counter so that
// when code is disassembled, it can actually find the correct offsets
2014-04-09 02:53:34 +00:00
if (core->anal->cur && core->anal->cur->reset_counter) {
core->anal->cur->reset_counter (core->anal, addr);
}
// TODO: All those ds must be print flags
2016-05-30 10:35:39 +00:00
ds = ds_init (core);
ds->cbytes = cbytes;
2016-05-30 10:35:39 +00:00
ds->print = p;
ds->l = l;
ds->buf = buf;
ds->len = r_anal_fcn_size (fcn);
ds->addr = fcn->addr;
ds->fcn = fcn;
r_list_foreach (fcn->bbs, bb_iter, bb) {
r_list_add_sorted (bb_list, bb, cmpaddr);
}
// Premptively read the bb data locs for ref lines
r_list_foreach (bb_list, bb_iter, bb) {
2016-09-22 16:06:10 +00:00
if (idx >= cur_buf_sz) {
break;
}
r_core_read_at (core, bb->addr, buf+idx, bb->size);
//ret = r_asm_disassemble (core->assembler, &ds->asmop, buf+idx, bb->size);
//if (ret > 0) eprintf ("%s\n",ds->asmop.buf_asm);
idx += bb->size;
}
2016-05-30 10:35:39 +00:00
ds_reflines_fcn_init (ds, fcn, buf);
core->inc = 0;
2016-09-22 16:06:10 +00:00
core->cons->vline = r_config_get_i (core->config, "scr.utf8")? r_vline_u: r_vline_a;
i = idx = 0;
r_cons_break (NULL, NULL);
2016-05-30 10:35:39 +00:00
ds_print_esil_anal_init (ds);
2016-09-22 16:06:10 +00:00
if (core->io && core->io->debug) {
r_debug_map_sync (core->dbg);
2016-09-22 16:06:10 +00:00
}
r_list_foreach (bb_list, bb_iter, bb) {
ut32 bb_size_consumed = 0;
// internal loop to consume bb that contain case-like operations
ds->at = bb->addr;
ds->addr = bb->addr;
len = bb->size;
if (len > cur_buf_sz) {
free (buf);
cur_buf_sz = len;
buf = malloc (cur_buf_sz);
ds->buf = buf;
}
do {
// XXX - why is it necessary to set this everytime?
r_asm_set_pc (core->assembler, ds->at);
if (ds->lines >= ds->l) break;
if (r_cons_singleton ()->breaked) break;
2016-05-30 10:35:39 +00:00
ds_update_ref_lines (ds);
/* show type links */
r_core_cmdf (core, "tf 0x%08"PFMT64x, ds->at);
2016-05-30 10:35:39 +00:00
ds_show_comments_right (ds);
ret = ds_disassemble (ds, buf+idx, len - bb_size_consumed);
ds_atabs_option (ds);
// TODO: store previous oplen in core->dec
if (core->inc == 0) {
core->inc = ds->oplen;
}
r_anal_op_fini (&ds->analop);
if (!ds->lastfail)
2014-02-20 02:08:12 +00:00
r_anal_op (core->anal, &ds->analop,
ds->at+bb_size_consumed, buf+idx,
len-bb_size_consumed);
if (ret < 1) {
r_strbuf_init (&ds->analop.esil);
ds->analop.type = R_ANAL_OP_TYPE_ILL;
}
2016-05-30 10:35:39 +00:00
ds_instruction_mov_lea (ds, idx);
ds_control_flow_comments (ds);
ds_adistrick_comments (ds);
/* XXX: This is really cpu consuming.. need to be fixed */
2016-05-30 10:35:39 +00:00
ds_show_functions (ds);
if (ds_print_labels (ds, fcn)) {
ds_show_functions (ds);
}
ds_show_xrefs (ds);
ds_show_flags (ds);
ds_setup_print_pre (ds, false, false);
ds_print_lines_left (ds);
ds_print_offset (ds);
ds_print_op_size (ds);
ds_print_trace (ds);
ds_print_cycles (ds);
ds_print_family (ds);
ds_print_stackptr (ds);
ret = ds_print_meta_infos (ds, buf, len, idx);
if (ds->mi_found) {
ds->mi_found = 0;
2014-09-23 09:55:11 +00:00
continue;
}
/* show cursor */
2016-05-30 10:35:39 +00:00
ds_print_show_cursor (ds);
ds_print_show_bytes (ds);
ds_print_lines_right (ds);
ds_build_op_str (ds);
ds_print_opstr (ds);
ds_print_fcn_name (ds);
ds_print_import_name (ds);
ds_print_color_reset (ds);
ds_print_dwarf (ds);
ret = ds_print_middle (ds, ret);
ds_print_asmop_payload (ds);
if (core->assembler->syntax != R_ASM_SYNTAX_INTEL) {
RAsmOp ao; /* disassemble for the vm .. */
int os = core->assembler->syntax;
2014-02-20 02:08:12 +00:00
r_asm_set_syntax (core->assembler,
R_ASM_SYNTAX_INTEL);
r_asm_disassemble (core->assembler, &ao,
buf+idx, len-bb_size_consumed);
r_asm_set_syntax (core->assembler, os);
}
2016-05-30 10:35:39 +00:00
ds_print_core_vmode (ds);
//ds_print_cc_update (ds);
2016-05-30 10:35:39 +00:00
ds_print_op_push_info (ds);
/*if (ds->analop.refptr) {
handle_print_refptr (core, ds);
} else {
handle_print_ptr (core, ds, len, idx);
}*/
2016-05-30 10:35:39 +00:00
ds_print_ptr (ds, len, idx);
Add asm.hints and handle CDOV deoptimization CDIV deoptimization =================== This patch implements hints in the disassembler that aim to assist the user in reading compiler-optimized divisions by analysing the involved magic number. Background ========== Since integer divisions are usually very expensive on most architectures, compilers try very hard to substitute them with cheaper operations. One of the more advanced substitutions is described in the book __Hacker's Delight__, chapter 10. An actual implementation of the described algorithm in LLVM can be found in the functions: `TargetLowering::BuildSDIV()` and `APInt::magic()`. The optimization approximately transforms e.g. ```asm xor edx, edx idiv 39 ``` into ```asm mov eax, edi mov edx, 0xd20d20d3 imul edx lea eax, [rdx + rdi] sar edi, 0x1f sar eax, 5 sub eax, edi ``` Reading the optimized version and __seeing__ the constant 39 seems difficult. Therefore I try to provide a small hint to the user. Limitations =========== * The current implementation only takes the magic number into account, therefore it may result in false positives. * Due to the nature of the optimization, the given hint may be off by a power of two. Fixing this would require to analyse the following shift instructions. * The hint is only shown in the line containing the magic number. The user still has to know which of the following instructions belong to the optimization. TODO ==== * Implement the corresponding analysis for unsigned integers * Implement the corresponding analysis for 64-bit integers. * Improve the heuristic by also looking at the next few instructions. ( I don't really know how to iterate over the instructions in the disassember in a non-deprecated way. Maybe someone can drop me a hint? ) * Implement an exact analysis using the actual dataflow in radeco and use it to revert the optimization. ( I suppose this is outside the scope of radare )
2016-06-15 13:18:04 +00:00
ds_cdiv_optimization (ds);
2016-05-30 10:35:39 +00:00
ds_print_comments_right (ds);
ds_show_refs (ds);
2016-05-30 10:35:39 +00:00
ds_print_esil_anal (ds);
if ( !(ds->show_comments && ds->show_comment_right && ds->comment)) {
r_cons_newline ();
}
if (ds->line) {
2016-05-30 10:35:39 +00:00
R_FREE (ds->line);
R_FREE (ds->refline);
R_FREE (ds->refline2);
}
2016-05-30 10:35:39 +00:00
ds_print_bbline (ds);
bb_size_consumed += ds->oplen;
ds->index += ds->oplen;
idx += ds->oplen;
ds->at += ds->oplen;
ds->addr += ds->oplen;
ds->lines++;
2016-05-30 10:35:39 +00:00
R_FREE (ds->opstr);
} while (bb_size_consumed < len);
i++;
}
free (buf);
r_cons_break_end ();
2016-05-30 10:35:39 +00:00
ds_print_esil_anal_fini (ds);
if (ds->oldbits) {
2014-02-20 02:08:12 +00:00
r_config_set_i (core->config, "asm.bits", ds->oldbits);
ds->oldbits = 0;
}
2016-05-30 10:35:39 +00:00
ds_free (ds);
r_list_free (bb_list);
return idx;
}