radare2/libr/core/cbin.c

3964 lines
112 KiB
C

/* radare - LGPL - Copyright 2011-2018 - earada, pancake */
#include <r_core.h>
#include <r_config.h>
#include "r_util.h"
#include "r_util/r_time.h"
#define is_in_range(at, from, sz) ((at) >= (from) && (at) < ((from) + (sz)))
#define VA_FALSE 0
#define VA_TRUE 1
#define VA_NOREBASE 2
#define LOAD_BSS_MALLOC 0
#define IS_MODE_SET(mode) ((mode) & R_MODE_SET)
#define IS_MODE_SIMPLE(mode) ((mode) & R_MODE_SIMPLE)
#define IS_MODE_SIMPLEST(mode) ((mode) & R_MODE_SIMPLEST)
#define IS_MODE_JSON(mode) ((mode) & R_MODE_JSON)
#define IS_MODE_RAD(mode) ((mode) & R_MODE_RADARE)
#define IS_MODE_EQUAL(mode) ((mode) & R_MODE_EQUAL)
#define IS_MODE_NORMAL(mode) (!(mode))
#define IS_MODE_CLASSDUMP(mode) ((mode) & R_MODE_CLASSDUMP)
// dup from cmd_info
#define PAIR_WIDTH 9
#define bprintf if (binfile && binfile->rbin && binfile->rbin->verbose) eprintf
static void pair(const char *key, const char *val, int mode, bool last) {
if (!val || !*val) {
return;
}
if (IS_MODE_JSON (mode)) {
const char *lst = last ? "" : ",";
r_cons_printf ("\"%s\":%s%s", key, val, lst);
} else {
char ws[16];
const int keyl = strlen (key);
const int wl = (keyl > PAIR_WIDTH) ? 0 : PAIR_WIDTH - keyl;
memset (ws, ' ', wl);
ws[wl] = 0;
r_cons_printf ("%s%s%s\n", key, ws, val);
}
}
static void pair_bool(const char *key, bool val, int mode, bool last) {
pair (key, r_str_bool (val), mode, last);
}
static void pair_int(const char *key, int val, int mode, bool last) {
pair (key, sdb_fmt ("%d", val), mode, last);
}
static void pair_ut64(const char *key, ut64 val, int mode, bool last) {
pair (key, sdb_fmt ("%"PFMT64d, val), mode, last);
}
static void pair_ut64x(const char *key, ut64 val, int mode, bool last) {
const char *str_val = IS_MODE_JSON (mode) ? sdb_fmt ("%"PFMT64d, val) : sdb_fmt ("0x%"PFMT64x, val);
pair (key, str_val, mode, last);
}
static void pair_str(const char *key, const char *val, int mode, int last) {
if (IS_MODE_JSON (mode)) {
if (!val) {
val = "";
}
char *encval = r_str_escape_utf8_for_json (val, -1);
if (encval) {
char *qs = r_str_newf ("\"%s\"", encval);
pair (key, qs, mode, last);
free (encval);
free (qs);
}
} else {
pair (key, val, mode, last);
}
}
#define STR(x) (x)? (x): ""
R_API int r_core_bin_set_cur(RCore *core, RBinFile *binfile);
static ut64 rva(RBin *bin, ut64 paddr, ut64 vaddr, int va) {
if (va == VA_TRUE) {
if (paddr != UT64_MAX) {
return r_bin_get_vaddr (bin, paddr, vaddr);
}
}
if (va == VA_NOREBASE) {
return vaddr;
}
return paddr;
}
R_API int r_core_bin_set_by_fd(RCore *core, ut64 bin_fd) {
if (r_bin_file_set_cur_by_fd (core->bin, bin_fd)) {
r_core_bin_set_cur (core, r_core_bin_cur (core));
return true;
}
return false;
}
R_API int r_core_bin_set_by_name(RCore *core, const char * name) {
if (r_bin_file_set_cur_by_name (core->bin, name)) {
r_core_bin_set_cur (core, r_core_bin_cur (core));
return true;
}
return false;
}
R_API int r_core_bin_set_env(RCore *r, RBinFile *binfile) {
r_return_val_if_fail (r, false);
RBinObject *binobj = binfile? binfile->o: NULL;
RBinInfo *info = binobj? binobj->info: NULL;
if (info) {
int va = info->has_va;
const char *arch = info->arch;
ut16 bits = info->bits;
ut64 baseaddr = r_bin_get_baddr (r->bin);
r_config_set_i (r->config, "bin.baddr", baseaddr);
sdb_num_add (r->sdb, "orig_baddr", baseaddr, 0);
r_config_set (r->config, "asm.arch", arch);
r_config_set_i (r->config, "asm.bits", bits);
r_config_set (r->config, "anal.arch", arch);
if (info->cpu && *info->cpu) {
r_config_set (r->config, "anal.cpu", info->cpu);
} else {
r_config_set (r->config, "anal.cpu", arch);
}
r_asm_use (r->assembler, arch);
r_core_bin_info (r, R_CORE_BIN_ACC_ALL, R_MODE_SET, va, NULL, NULL);
r_core_bin_set_cur (r, binfile);
return true;
}
return false;
}
R_API int r_core_bin_set_cur(RCore *core, RBinFile *binfile) {
if (!core->bin) {
return false;
}
if (!binfile) {
// Find first available binfile
ut32 fd = r_core_file_cur_fd (core);
binfile = fd != (ut32)-1
? r_bin_file_find_by_fd (core->bin, fd)
: NULL;
if (!binfile) {
return false;
}
}
r_bin_file_set_cur_binfile (core->bin, binfile);
return true;
}
R_API int r_core_bin_refresh_strings(RCore *r) {
return r_bin_reset_strings (r->bin)? true: false;
}
R_API RBinFile *r_core_bin_cur(RCore *core) {
return r_bin_cur (core->bin);
}
static void _print_strings(RCore *r, RList *list, int mode, int va) {
bool b64str = r_config_get_i (r->config, "bin.b64str");
int minstr = r_config_get_i (r->config, "bin.minstr");
int maxstr = r_config_get_i (r->config, "bin.maxstr");
RBin *bin = r->bin;
RBinObject *obj = r_bin_cur_object (bin);
RListIter *iter;
RListIter *last_processed = NULL;
RBinString *string;
RBinSection *section;
char *q;
bin->minstrlen = minstr;
bin->maxstrlen = maxstr;
if (IS_MODE_JSON (mode)) {
r_cons_printf ("[");
}
if (IS_MODE_RAD (mode)) {
r_cons_printf ("fs strings");
}
if (IS_MODE_SET (mode) && r_config_get_i (r->config, "bin.strings")) {
r_flag_space_set (r->flags, R_FLAGS_FS_STRINGS);
r_cons_break_push (NULL, NULL);
}
if (IS_MODE_NORMAL (mode)) {
r_cons_printf ("[Strings]\n");
r_cons_printf ("Num Paddr Vaddr Len Size Section Type String\n");
}
RBinString b64 = { 0 };
r_list_foreach (list, iter, string) {
const char *section_name, *type_string;
ut64 paddr, vaddr, addr;
paddr = string->paddr;
vaddr = string->vaddr; // r_bin_get_vaddr (bin, paddr, string->vaddr);
addr = va? string->vaddr: string->paddr;
if (!r_bin_string_filter (bin, string->string, addr)) {
continue;
}
if (string->length < minstr) {
continue;
}
if (maxstr && string->length > maxstr) {
continue;
}
section = obj? r_bin_get_section_at (obj, paddr, 0): NULL;
section_name = section ? section->name : "";
type_string = r_bin_string_type (string->type);
if (b64str) {
ut8 *s = r_base64_decode_dyn (string->string, -1);
if (s && *s && IS_PRINTABLE (*s)) {
// TODO: add more checks
free (b64.string);
memcpy (&b64, string, sizeof (b64));
b64.string = (char *)s;
b64.size = strlen (b64.string);
string = &b64;
}
}
if (IS_MODE_SET (mode)) {
char *f_name, *f_realname, *str;
if (r_cons_is_breaked ()) {
break;
}
r_meta_add (r->anal, R_META_TYPE_STRING, addr, addr + string->size, string->string);
f_name = strdup (string->string);
r_name_filter (f_name, -1);
if (r->bin->prefix) {
str = r_str_newf ("%s.str.%s", r->bin->prefix, f_name);
f_realname = r_str_newf ("%s.\"%s\"", r->bin->prefix, string->string);
} else {
str = r_str_newf ("str.%s", f_name);
f_realname = r_str_newf ("\"%s\"", string->string);
}
RFlagItem *flag = r_flag_set (r->flags, str, addr, string->size);
r_flag_item_set_realname (flag, f_realname);
free (str);
free (f_name);
free (f_realname);
} else if (IS_MODE_SIMPLE (mode)) {
r_cons_printf ("0x%"PFMT64x" %d %d %s\n", addr,
string->size, string->length, string->string);
} else if (IS_MODE_SIMPLEST (mode)) {
r_cons_println (string->string);
} else if (IS_MODE_JSON (mode)) {
int *block_list;
q = r_base64_encode_dyn (string->string, -1);
r_cons_printf ("%s{\"vaddr\":%"PFMT64u
",\"paddr\":%"PFMT64u",\"ordinal\":%d"
",\"size\":%d,\"length\":%d,\"section\":\"%s\","
"\"type\":\"%s\",\"string\":\"%s\"",
last_processed ? ",": "",
vaddr, paddr, string->ordinal, string->size,
string->length, section_name, type_string, q);
switch (string->type) {
case R_STRING_TYPE_UTF8:
case R_STRING_TYPE_WIDE:
case R_STRING_TYPE_WIDE32:
block_list = r_utf_block_list ((const ut8*)string->string, -1);
if (block_list) {
if (block_list[0] == 0 && block_list[1] == -1) {
/* Don't include block list if
just Basic Latin (0x00 - 0x7F) */
R_FREE (block_list);
break;
}
int *block_ptr = block_list;
r_cons_printf (",\"blocks\":[");
for (; *block_ptr != -1; block_ptr++) {
if (block_ptr != block_list) {
r_cons_printf (",");
}
const char *utfName = r_utf_block_name (*block_ptr);
r_cons_printf ("\"%s\"", utfName? utfName: "");
}
r_cons_printf ("]");
R_FREE (block_list);
}
}
r_cons_printf ("}");
free (q);
} else if (IS_MODE_RAD (mode)) {
char *f_name = strdup (string->string);
r_name_filter (f_name, R_FLAG_NAME_SIZE);
char *str = (r->bin->prefix)
? r_str_newf ("%s.str.%s", r->bin->prefix, f_name)
: r_str_newf ("str.%s", f_name);
r_cons_printf ("f %s %"PFMT64d" 0x%08"PFMT64x"\n"
"Cs %"PFMT64d" @ 0x%08"PFMT64x"\n",
str, string->size, addr,
string->size, addr);
free (str);
free (f_name);
} else {
int *block_list;
char *str = string->string;
char *no_dbl_bslash_str = NULL;
if (!r->print->esc_bslash) {
char *ptr;
for (ptr = str; *ptr; ptr++) {
if (*ptr != '\\') {
continue;
}
if (*(ptr + 1) == '\\') {
if (!no_dbl_bslash_str) {
no_dbl_bslash_str = strdup (str);
if (!no_dbl_bslash_str) {
break;
}
ptr = no_dbl_bslash_str + (ptr - str);
}
memmove (ptr + 1, ptr + 2, strlen (ptr + 2) + 1);
}
}
if (no_dbl_bslash_str) {
str = no_dbl_bslash_str;
}
}
r_cons_printf ("%03u 0x%08" PFMT64x " 0x%08" PFMT64x " %3u %3u (%s) %5s %s",
string->ordinal, paddr, vaddr,
string->length, string->size,
section_name, type_string, str);
if (str == no_dbl_bslash_str) {
R_FREE (str);
}
switch (string->type) {
case R_STRING_TYPE_UTF8:
case R_STRING_TYPE_WIDE:
case R_STRING_TYPE_WIDE32:
block_list = r_utf_block_list ((const ut8*)string->string, -1);
if (block_list) {
if (block_list[0] == 0 && block_list[1] == -1) {
/* Don't show block list if
just Basic Latin (0x00 - 0x7F) */
break;
}
int *block_ptr = block_list;
r_cons_printf (" blocks=");
for (; *block_ptr != -1; block_ptr++) {
if (block_ptr != block_list) {
r_cons_printf (",");
}
const char *name = r_utf_block_name (*block_ptr);
r_cons_printf ("%s", name? name: "");
}
free (block_list);
}
break;
}
r_cons_printf ("\n");
}
last_processed = iter;
}
R_FREE (b64.string);
if (IS_MODE_JSON (mode)) {
r_cons_printf ("]");
}
if (IS_MODE_SET (mode)) {
r_cons_break_pop ();
}
}
static bool bin_raw_strings(RCore *r, int mode, int va) {
RBinFile *bf = r_bin_cur (r->bin);
bool new_bf = false;
if (bf && strstr (bf->file, "malloc://")) {
//sync bf->buf to search string on it
r_io_read_at (r->io, 0, bf->buf->buf, bf->size);
}
if (!r->file) {
eprintf ("Core file not open\n");
if (IS_MODE_JSON (mode)) {
r_cons_print ("[]");
}
return false;
}
if (!bf) {
bf = R_NEW0 (RBinFile);
if (!bf) {
return false;
}
RIODesc *desc = r_io_desc_get (r->io, r->file->fd);
if (!desc) {
free (bf);
return false;
}
bf->file = strdup (desc->name);
bf->size = r_io_desc_size (desc);
if (bf->size == UT64_MAX) {
free (bf);
return false;
}
bf->buf = r_buf_new_with_io (&r->bin->iob, r->file->fd);
bf->o = NULL;
bf->rbin = r->bin;
new_bf = true;
va = false;
}
RList *l = r_bin_raw_strings (bf, 0);
_print_strings (r, l, mode, va);
if (new_bf) {
r_buf_free (bf->buf);
bf->buf = NULL;
bf->id = -1;
r_bin_file_free (bf);
}
return true;
}
static bool bin_strings(RCore *r, int mode, int va) {
RList *list;
RBinFile *binfile = r_core_bin_cur (r);
RBinPlugin *plugin = r_bin_file_cur_plugin (binfile);
int rawstr = r_config_get_i (r->config, "bin.rawstr");
if (!binfile) {
return false;
}
if (!r_config_get_i (r->config, "bin.strings")) {
return false;
}
if (!plugin) {
return false;
}
if (plugin->info && plugin->name) {
if (strcmp (plugin->name, "any") == 0 && !rawstr) {
if (IS_MODE_JSON (mode)) {
r_cons_print("[]");
}
return false;
}
}
if (!(list = r_bin_get_strings (r->bin))) {
return false;
}
_print_strings (r, list, mode, va);
return true;
}
static const char* get_compile_time(Sdb *binFileSdb) {
Sdb *info_ns = sdb_ns (binFileSdb, "info", false);
const char *timeDateStamp_string = sdb_const_get (info_ns,
"image_file_header.TimeDateStamp_string", 0);
return timeDateStamp_string;
}
static bool is_executable(RBinObject *obj) {
RListIter *it;
RBinSection* sec;
r_return_val_if_fail (obj, false);
if (obj->info && obj->info->arch) {
return true;
}
r_list_foreach (obj->sections, it, sec) {
if (sec->perm & R_PERM_X) {
return true;
}
}
return false;
}
static void sdb_concat_by_path(Sdb *s, const char *path) {
Sdb *db = sdb_new (0, path, 0);
sdb_merge (s, db);
sdb_close (db);
sdb_free (db);
}
R_API void r_core_anal_type_init(RCore *core) {
r_return_if_fail (core && core->anal);
const char *dir_prefix = r_config_get (core->config, "dir.prefix");
int bits = core->assembler->bits;
Sdb *types = core->anal->sdb_types;
// make sure they are empty this is initializing
sdb_reset (types);
const char *anal_arch = r_config_get (core->config, "anal.arch");
const char *os = r_config_get (core->config, "asm.os");
// spaguetti ahead
const char *dbpath = sdb_fmt (R_JOIN_3_PATHS ("%s", R2_SDB_FCNSIGN, "types.sdb"), dir_prefix);
if (r_file_exists (dbpath)) {
sdb_concat_by_path (types, dbpath);
}
dbpath = sdb_fmt (R_JOIN_3_PATHS ("%s", R2_SDB_FCNSIGN, "types-%s.sdb"),
dir_prefix, anal_arch);
if (r_file_exists (dbpath)) {
sdb_concat_by_path (types, dbpath);
}
dbpath = sdb_fmt (R_JOIN_3_PATHS ("%s", R2_SDB_FCNSIGN, "types-%s.sdb"),
dir_prefix, os);
if (r_file_exists (dbpath)) {
sdb_concat_by_path (types, dbpath);
}
dbpath = sdb_fmt (R_JOIN_3_PATHS ("%s", R2_SDB_FCNSIGN, "types-%d.sdb"),
dir_prefix, bits);
if (r_file_exists (dbpath)) {
sdb_concat_by_path (types, dbpath);
}
dbpath = sdb_fmt (R_JOIN_3_PATHS ("%s", R2_SDB_FCNSIGN, "types-%s-%d.sdb"),
dir_prefix, os, bits);
if (r_file_exists (dbpath)) {
sdb_concat_by_path (types, dbpath);
}
dbpath = sdb_fmt (R_JOIN_3_PATHS ("%s", R2_SDB_FCNSIGN, "types-%s-%d.sdb"),
dir_prefix, anal_arch, bits);
if (r_file_exists (dbpath)) {
sdb_concat_by_path (types, dbpath);
}
dbpath = sdb_fmt (R_JOIN_3_PATHS ("%s", R2_SDB_FCNSIGN, "types-%s-%s.sdb"),
dir_prefix, anal_arch, os);
if (r_file_exists (dbpath)) {
sdb_concat_by_path (types, dbpath);
}
dbpath = sdb_fmt (R_JOIN_3_PATHS ("%s", R2_SDB_FCNSIGN, "types-%s-%s-%d.sdb"),
dir_prefix, anal_arch, os, bits);
if (r_file_exists (dbpath)) {
sdb_concat_by_path (types, dbpath);
}
}
static int save_ptr(void *p, const char *k, const char *v) {
Sdb *sdbs[2];
sdbs[0] = ((Sdb**) p)[0];
sdbs[1] = ((Sdb**) p)[1];
if (!strncmp (v, "cc", strlen ("cc") + 1)) {
const char *x = sdb_const_get (sdbs[1], sdb_fmt ("cc.%s.name", k), 0);
char *tmp = sdb_fmt ("%p", x);
sdb_set (sdbs[0], tmp, x, 0);
}
return 1;
}
R_API void r_core_anal_cc_init(RCore *core) {
Sdb *sdbs[2] = {
sdb_new0 (),
core->anal->sdb_cc
};
const char *dir_prefix = r_config_get (core->config, "dir.prefix");
//save pointers and values stored inside them
//to recover from freeing heeps
const char *defaultcc = sdb_const_get (sdbs[1], "default.cc", 0);
sdb_set (sdbs[0], sdb_fmt ("0x%08"PFMT64x, r_num_get (NULL, defaultcc)), defaultcc, 0);
sdb_foreach (core->anal->sdb_cc, save_ptr, sdbs);
sdb_reset ( core->anal->sdb_cc);
const char *anal_arch = r_config_get (core->config, "anal.arch");
int bits = core->anal->bits;
if (bits == 16 && !strcmp (anal_arch, "arm")) {
bits = 32;
}
char *dbpath = sdb_fmt ("%s/"R2_SDB_FCNSIGN"/cc-%s-%d.sdb", dir_prefix, anal_arch, bits);
if (r_file_exists (dbpath)) {
sdb_concat_by_path (core->anal->sdb_cc, dbpath);
}
//restore all freed CC or replace with new default cc
RListIter *it;
RAnalFunction *fcn;
r_list_foreach (core->anal->fcns, it, fcn) {
char *ptr = sdb_fmt ("%p", fcn->cc);
const char *cc = sdb_const_get (sdbs[0], ptr, 0);
if (cc) {
fcn->cc = r_anal_cc_to_constant (core->anal, (char *)cc);
}
if (!fcn->cc) {
fcn->cc = r_anal_cc_default (core->anal);
}
fcn->cc = r_str_const (fcn->cc);
}
sdb_close (sdbs[0]);
sdb_free (sdbs[0]);
}
static int bin_info(RCore *r, int mode, ut64 laddr) {
int i, j, v;
char str[R_FLAG_NAME_SIZE];
RBinInfo *info = r_bin_get_info (r->bin);
RBinFile *binfile = r_core_bin_cur (r);
RBinObject *obj = r_bin_cur_object (r->bin);
const char *compiled = NULL;
bool havecode;
if (!binfile || !info || !obj) {
if (mode & R_MODE_JSON) {
r_cons_printf ("{}");
}
return false;
}
havecode = is_executable (obj) | (obj->entries != NULL);
compiled = get_compile_time (binfile->sdb);
if (IS_MODE_SET (mode)) {
r_config_set (r->config, "file.type", info->rclass);
r_config_set (r->config, "cfg.bigendian",
info->big_endian ? "true" : "false");
if (info->rclass && !strcmp (info->rclass, "fs")) {
// r_config_set (r->config, "asm.arch", info->arch);
// r_core_seek (r, 0, 1);
// eprintf ("m /root %s 0", info->arch);
// r_core_cmdf (r, "m /root hfs @ 0", info->arch);
} else {
if (info->lang) {
r_config_set (r->config, "bin.lang", info->lang);
}
r_config_set (r->config, "asm.os", info->os);
if (info->rclass && !strcmp (info->rclass, "pe")) {
r_config_set (r->config, "anal.cpp.abi", "msvc");
} else {
r_config_set (r->config, "anal.cpp.abi", "itanium");
}
r_config_set (r->config, "asm.arch", info->arch);
if (info->cpu && *info->cpu) {
r_config_set (r->config, "asm.cpu", info->cpu);
}
r_config_set (r->config, "anal.arch", info->arch);
snprintf (str, R_FLAG_NAME_SIZE, "%i", info->bits);
r_config_set (r->config, "asm.bits", str);
r_config_set (r->config, "asm.dwarf",
(R_BIN_DBG_STRIPPED & info->dbg_info) ? "false" : "true");
v = r_anal_archinfo (r->anal, R_ANAL_ARCHINFO_ALIGN);
if (v != -1) {
r_config_set_i (r->config, "asm.pcalign", v);
}
}
r_core_anal_type_init (r);
r_core_anal_cc_init (r);
} else if (IS_MODE_SIMPLE (mode)) {
r_cons_printf ("arch %s\n", info->arch);
if (info->cpu && *info->cpu) {
r_cons_printf ("cpu %s\n", info->cpu);
}
r_cons_printf ("bits %d\n", info->bits);
r_cons_printf ("os %s\n", info->os);
r_cons_printf ("endian %s\n", info->big_endian? "big": "little");
v = r_anal_archinfo (r->anal, R_ANAL_ARCHINFO_MIN_OP_SIZE);
if (v != -1) {
r_cons_printf ("minopsz %d\n", v);
}
v = r_anal_archinfo (r->anal, R_ANAL_ARCHINFO_MAX_OP_SIZE);
if (v != -1) {
r_cons_printf ("maxopsz %d\n", v);
}
v = r_anal_archinfo (r->anal, R_ANAL_ARCHINFO_ALIGN);
if (v != -1) {
r_cons_printf ("pcalign %d\n", v);
}
} else if (IS_MODE_RAD (mode)) {
if (info->type && !strcmp (info->type, "fs")) {
r_cons_printf ("e file.type=fs\n");
r_cons_printf ("m /root %s 0\n", info->arch);
} else {
r_cons_printf ("e cfg.bigendian=%s\n"
"e asm.bits=%i\n"
"e asm.dwarf=%s\n",
r_str_bool (info->big_endian),
info->bits,
r_str_bool (R_BIN_DBG_STRIPPED &info->dbg_info));
if (info->lang && *info->lang) {
r_cons_printf ("e bin.lang=%s\n", info->lang);
}
if (info->rclass && *info->rclass) {
r_cons_printf ("e file.type=%s\n",
info->rclass);
}
if (info->os) {
r_cons_printf ("e asm.os=%s\n", info->os);
}
if (info->arch) {
r_cons_printf ("e asm.arch=%s\n", info->arch);
}
if (info->cpu && *info->cpu) {
r_cons_printf ("e asm.cpu=%s\n", info->cpu);
}
v = r_anal_archinfo (r->anal, R_ANAL_ARCHINFO_ALIGN);
if (v != -1) {
r_cons_printf ("e asm.pcalign=%d\n", v);
}
}
} else {
// XXX: if type is 'fs' show something different?
char *tmp_buf;
if (IS_MODE_JSON (mode)) {
r_cons_printf ("{");
}
pair_str ("arch", info->arch, mode, false);
if (info->cpu && *info->cpu) {
pair_str ("cpu", info->cpu, mode, false);
}
pair_ut64x ("baddr", r_bin_get_baddr (r->bin), mode, false);
pair_ut64 ("binsz", r_bin_get_size (r->bin), mode, false);
pair_str ("bintype", info->rclass, mode, false);
pair_int ("bits", info->bits, mode, false);
pair_bool ("canary", info->has_canary, mode, false);
if (info->has_retguard != -1) {
pair_bool ("retguard", info->has_retguard, mode, false);
}
pair_bool ("sanitiz", info->has_sanitizers, mode, false);
pair_str ("class", info->bclass, mode, false);
if (info->actual_checksum) {
/* computed checksum */
pair_str ("cmp.csum", info->actual_checksum, mode, false);
}
pair_str ("compiled", compiled, mode, false);
pair_bool ("crypto", info->has_crypto, mode, false);
pair_str ("dbg_file", info->debug_file_name, mode, false);
pair_str ("endian", info->big_endian ? "big" : "little", mode, false);
if (info->rclass && !strcmp (info->rclass, "mdmp")) {
tmp_buf = sdb_get (binfile->sdb, "mdmp.flags", 0);
if (tmp_buf) {
pair_str ("flags", tmp_buf, mode, false);
free (tmp_buf);
}
}
pair_bool ("havecode", havecode, mode, false);
if (info->claimed_checksum) {
/* checksum specified in header */
pair_str ("hdr.csum", info->claimed_checksum, mode, false);
}
pair_str ("guid", info->guid, mode, false);
pair_str ("intrp", info->intrp, mode, false);
pair_ut64x ("laddr", laddr, mode, false);
pair_str ("lang", info->lang, mode, false);
pair_bool ("linenum", R_BIN_DBG_LINENUMS & info->dbg_info, mode, false);
pair_bool ("lsyms", R_BIN_DBG_SYMS & info->dbg_info, mode, false);
pair_str ("machine", info->machine, mode, false);
v = r_anal_archinfo (r->anal, R_ANAL_ARCHINFO_MAX_OP_SIZE);
if (v != -1) {
pair_int ("maxopsz", v, mode, false);
}
v = r_anal_archinfo (r->anal, R_ANAL_ARCHINFO_MIN_OP_SIZE);
if (v != -1) {
pair_int ("minopsz", v, mode, false);
}
pair_bool ("nx", info->has_nx, mode, false);
pair_str ("os", info->os, mode, false);
if (info->rclass && !strcmp (info->rclass, "pe")) {
pair_bool ("overlay", info->pe_overlay, mode, false);
}
v = r_anal_archinfo (r->anal, R_ANAL_ARCHINFO_ALIGN);
if (v != -1) {
pair_int ("pcalign", v, mode, false);
}
pair_bool ("pic", info->has_pi, mode, false);
pair_bool ("relocs", R_BIN_DBG_RELOCS & info->dbg_info, mode, false);
tmp_buf = sdb_get (obj->kv, "elf.relro", 0);
if (tmp_buf) {
pair_str ("relro", tmp_buf, mode, false);
free (tmp_buf);
}
pair_str ("rpath", info->rpath, mode, false);
if (info->rclass && !strcmp (info->rclass, "pe")) {
//this should be moved if added to mach0 (or others)
pair_bool ("signed", info->signature, mode, false);
}
pair_bool ("static", r_bin_is_static (r->bin), mode, false);
if (info->rclass && !strcmp (info->rclass, "mdmp")) {
v = sdb_num_get (binfile->sdb, "mdmp.streams", 0);
if (v != -1) {
pair_int ("streams", v, mode, false);
}
}
pair_bool ("stripped", R_BIN_DBG_STRIPPED & info->dbg_info, mode, false);
pair_str ("subsys", info->subsystem, mode, false);
pair_bool ("va", info->has_va, mode, true);
if (IS_MODE_JSON (mode)) {
r_cons_printf (",\"checksums\":{");
for (i = 0; info->sum[i].type; i++) {
RBinHash *h = &info->sum[i];
ut64 hash = r_hash_name_to_bits (h->type);
RHash *rh = r_hash_new (true, hash);
int len = r_hash_calculate (rh, hash, (const ut8*)
binfile->buf->buf+h->from, h->to);
if (len < 1) {
eprintf ("Invaild checksum length\n");
}
r_hash_free (rh);
r_cons_printf ("%s\"%s\":{\"hex\":\"", i?",": "", h->type);
// r_cons_printf ("%s\t%d-%dc\t", h->type, h->from, h->to+h->from);
for (j = 0; j < h->len; j++) {
r_cons_printf ("%02x", h->buf[j]);
}
r_cons_printf ("\"}");
}
r_cons_printf ("}");
} else {
for (i = 0; info->sum[i].type; i++) {
RBinHash *h = &info->sum[i];
ut64 hash = r_hash_name_to_bits (h->type);
RHash *rh = r_hash_new (true, hash);
int len = r_hash_calculate (rh, hash, (const ut8*)
binfile->buf->buf+h->from, h->to);
if (len < 1) {
eprintf ("Invalid wtf\n");
}
r_hash_free (rh);
r_cons_printf ("%s %d-%dc ", h->type, h->from, h->to+h->from);
for (j = 0; j < h->len; j++) {
r_cons_printf ("%02x", h->buf[j]);
}
r_cons_newline ();
}
}
if (IS_MODE_JSON (mode)) {
r_cons_printf ("}");
}
}
const char *dir_prefix = r_config_get (r->config, "dir.prefix");
char *spath = sdb_fmt ("%s/"R2_SDB_FCNSIGN"/spec.sdb", dir_prefix);
if (r_file_exists (spath)) {
sdb_concat_by_path (r->anal->sdb_fmts, spath);
}
return true;
}
static int bin_dwarf(RCore *core, int mode) {
RBinDwarfRow *row;
RListIter *iter;
RList *list = NULL;
if (!r_config_get_i (core->config, "bin.dbginfo")) {
return false;
}
RBinFile *binfile = r_core_bin_cur (core);
RBinPlugin * plugin = r_bin_file_cur_plugin (binfile);
if (!binfile) {
return false;
}
if (plugin && plugin->lines) {
list = plugin->lines (binfile);
} else if (core->bin) {
// TODO: complete and speed-up support for dwarf
RBinDwarfDebugAbbrev *da = NULL;
da = r_bin_dwarf_parse_abbrev (core->bin, mode);
r_bin_dwarf_parse_info (da, core->bin, mode);
r_bin_dwarf_parse_aranges (core->bin, mode);
list = r_bin_dwarf_parse_line (core->bin, mode);
r_bin_dwarf_free_debug_abbrev (da);
free (da);
}
if (!list) {
return false;
}
r_cons_break_push (NULL, NULL);
/* cache file:line contents */
const char *lastFile = NULL;
int *lastFileLines = NULL;
char *lastFileContents = NULL;
int lastFileLinesCount = 0;
/* ugly dupe for speedup */
const char *lastFile2 = NULL;
int *lastFileLines2 = NULL;
char *lastFileContents2 = NULL;
int lastFileLinesCount2 = 0;
const char *lf = NULL;
int *lfl = NULL;
char *lfc = NULL;
int lflc = 0;
//TODO we should need to store all this in sdb, or do a filecontentscache in libr/util
//XXX this whole thing has leaks
r_list_foreach (list, iter, row) {
if (r_cons_is_breaked ()) {
break;
}
if (mode) {
// TODO: use 'Cl' instead of CC
const char *path = row->file;
if (!lastFile || strcmp (path, lastFile)) {
if (lastFile && lastFile2 && !strcmp (path, lastFile2)) {
lf = lastFile;
lfl = lastFileLines;
lfc = lastFileContents;
lflc = lastFileLinesCount;
lastFile = lastFile2;
lastFileLines = lastFileLines2;
lastFileContents = lastFileContents2;
lastFileLinesCount = lastFileLinesCount2;
lastFile2 = lf;
lastFileLines2 = lfl;
lastFileContents2 = lfc;
lastFileLinesCount2 = lflc;
} else {
lastFile2 = lastFile;
lastFileLines2 = lastFileLines;
lastFileContents2 = lastFileContents;
lastFileLinesCount2 = lastFileLinesCount;
lastFile = path;
lastFileContents = r_file_slurp (path, NULL);
if (lastFileContents) {
lastFileLines = r_str_split_lines (lastFileContents, &lastFileLinesCount);
}
}
}
char *line = NULL;
//r_file_slurp_line (path, row->line - 1, 0);
if (lastFileLines && lastFileContents) {
int nl = row->line - 1;
if (nl >= 0 && nl < lastFileLinesCount) {
line = strdup (lastFileContents + lastFileLines[nl]);
}
} else {
line = NULL;
}
if (line) {
r_str_filter (line, strlen (line));
line = r_str_replace (line, "\"", "\\\"", 1);
line = r_str_replace (line, "\\\\", "\\", 1);
}
bool chopPath = !r_config_get_i (core->config, "dir.dwarf.abspath");
char *file = strdup (row->file);
if (chopPath) {
const char *slash = r_str_lchr (file, '/');
if (slash) {
memmove (file, slash + 1, strlen (slash));
}
}
// TODO: implement internal : if ((mode & R_MODE_SET))
if ((mode & R_MODE_SET)) {
// TODO: use CL here.. but its not necessary.. so better not do anything imho
// r_core_cmdf (core, "CL %s:%d 0x%08"PFMT64x, file, (int)row->line, row->address);
#if 0
char *cmt = r_str_newf ("%s:%d %s", file, (int)row->line, line? line: "");
r_meta_set_string (core->anal, R_META_TYPE_COMMENT, row->address, cmt);
free (cmt);
#endif
} else {
r_cons_printf ("CL %s:%d 0x%08" PFMT64x "\n",
file, (int)row->line,
row->address);
r_cons_printf ("\"CC %s:%d %s\"@0x%" PFMT64x
"\n",
file, row->line,
line ? line : "", row->address);
}
free (file);
free (line);
} else {
r_cons_printf ("0x%08" PFMT64x "\t%s\t%d\n",
row->address, row->file, row->line);
}
}
r_cons_break_pop ();
R_FREE (lastFileContents);
R_FREE (lastFileContents2);
// this list is owned by rbin, not us, we shouldnt free it
// r_list_free (list);
free (lastFileLines);
return true;
}
R_API int r_core_pdb_info(RCore *core, const char *file, ut64 baddr, int mode) {
R_PDB pdb = R_EMPTY;
pdb.cb_printf = r_cons_printf;
if (!init_pdb_parser (&pdb, file)) {
return false;
}
if (!pdb.pdb_parse (&pdb)) {
eprintf ("pdb was not parsed\n");
pdb.finish_pdb_parse (&pdb);
return false;
}
if (mode == R_MODE_JSON) {
r_cons_printf ("[");
}
switch (mode) {
case R_MODE_SET:
mode = 's';
r_core_cmd0 (core, ".iP*");
return true;
case R_MODE_JSON:
mode = 'j';
break;
case '*':
case 1:
mode = 'r';
break;
default:
mode = 'd'; // default
break;
}
pdb.print_types (&pdb, mode);
if (mode == 'j') {
r_cons_printf (",");
}
pdb.print_gvars (&pdb, baddr, mode);
if (mode == 'j') {
r_cons_printf ("]");
}
pdb.finish_pdb_parse (&pdb);
return true;
}
static int bin_pdb(RCore *core, int mode) {
ut64 baddr = r_bin_get_baddr (core->bin);
return r_core_pdb_info (core, core->bin->file, baddr, mode);
}
static int srclineCmp(const void *a, const void *b) {
return r_str_cmp (a, b, -1);
}
static int bin_source(RCore *r, int mode) {
RList *final_list = r_list_new ();
RBinFile * binfile = r->bin->cur;
if (!binfile) {
bprintf ("[Error bin file]\n");
r_list_free (final_list);
return false;
}
SdbListIter *iter;
RListIter *iter2;
char* srcline;
SdbKv *kv;
SdbList *ls = sdb_foreach_list (binfile->sdb_addrinfo, false);
ls_foreach (ls, iter, kv) {
char *v = sdbkv_value (kv);
RList *list = r_str_split_list (v, "|");
srcline = r_list_get_bottom (list);
if (srcline) {
if (!strstr (srcline, "0x")){
r_list_append (final_list, srcline);
}
}
r_list_free (list);
}
r_cons_printf ("[Source file]\n");
RList *uniqlist = r_list_uniq (final_list, srclineCmp);
r_list_foreach (uniqlist, iter2, srcline) {
r_cons_printf ("%s\n", srcline);
}
r_list_free (uniqlist);
r_list_free (final_list);
return true;
}
static int bin_main(RCore *r, int mode, int va) {
RBinAddr *binmain = r_bin_get_sym (r->bin, R_BIN_SYM_MAIN);
ut64 addr;
if (!binmain) {
return false;
}
addr = va ? r_bin_a2b (r->bin, binmain->vaddr) : binmain->paddr;
if (IS_MODE_SET (mode)) {
r_flag_space_set (r->flags, R_FLAGS_FS_SYMBOLS);
r_flag_set (r->flags, "main", addr, r->blocksize);
} else if (IS_MODE_SIMPLE (mode)) {
r_cons_printf ("%"PFMT64d, addr);
} else if (IS_MODE_RAD (mode)) {
r_cons_printf ("fs symbols\n");
r_cons_printf ("f main @ 0x%08"PFMT64x"\n", addr);
} else if (IS_MODE_JSON (mode)) {
r_cons_printf ("{\"vaddr\":%" PFMT64d
",\"paddr\":%" PFMT64d "}", addr, binmain->paddr);
} else {
r_cons_printf ("[Main]\n");
r_cons_printf ("vaddr=0x%08"PFMT64x" paddr=0x%08"PFMT64x"\n",
addr, binmain->paddr);
}
return true;
}
static inline bool is_initfini(RBinAddr *entry) {
switch (entry->type) {
case R_BIN_ENTRY_TYPE_INIT:
case R_BIN_ENTRY_TYPE_FINI:
case R_BIN_ENTRY_TYPE_PREINIT:
return true;
default:
return false;
}
}
static int bin_entry(RCore *r, int mode, ut64 laddr, int va, bool inifin) {
char str[R_FLAG_NAME_SIZE];
RList *entries = r_bin_get_entries (r->bin);
RListIter *iter;
RListIter *last_processed = NULL;
RBinAddr *entry = NULL;
int i = 0, init_i = 0, fini_i = 0, preinit_i = 0;
ut64 baddr = r_bin_get_baddr (r->bin);
if (IS_MODE_RAD (mode)) {
r_cons_printf ("fs symbols\n");
} else if (IS_MODE_JSON (mode)) {
r_cons_printf ("[");
} else if (IS_MODE_NORMAL (mode)) {
if (inifin) {
r_cons_printf ("[Constructors]\n");
} else {
r_cons_printf ("[Entrypoints]\n");
}
}
r_list_foreach (entries, iter, entry) {
ut64 paddr = entry->paddr;
ut64 hpaddr = UT64_MAX;
ut64 hvaddr = UT64_MAX;
if (mode != R_MODE_SET) {
if (inifin) {
if (entry->type == R_BIN_ENTRY_TYPE_PROGRAM) {
continue;
}
} else {
if (entry->type != R_BIN_ENTRY_TYPE_PROGRAM) {
continue;
}
}
}
if (entry->hpaddr) {
hpaddr = entry->hpaddr;
if (entry->hvaddr) {
hvaddr = rva (r->bin, hpaddr, entry->hvaddr, va);
}
}
ut64 at = rva (r->bin, paddr, entry->vaddr, va);
const char *type = r_bin_entry_type_string (entry->type);
if (!type) {
type = "unknown";
}
const char *hpaddr_key = (entry->type == R_BIN_ENTRY_TYPE_PROGRAM)
? "haddr" : "hpaddr";
if (IS_MODE_SET (mode)) {
r_flag_space_set (r->flags, R_FLAGS_FS_SYMBOLS);
if (entry->type == R_BIN_ENTRY_TYPE_INIT) {
snprintf (str, R_FLAG_NAME_SIZE, "entry.init%i", init_i);
} else if (entry->type == R_BIN_ENTRY_TYPE_FINI) {
snprintf (str, R_FLAG_NAME_SIZE, "entry.fini%i", fini_i);
} else if (entry->type == R_BIN_ENTRY_TYPE_PREINIT) {
snprintf (str, R_FLAG_NAME_SIZE, "entry.preinit%i", preinit_i);
} else {
snprintf (str, R_FLAG_NAME_SIZE, "entry%i", i);
}
r_flag_set (r->flags, str, at, 1);
if (is_initfini (entry) && hvaddr != UT64_MAX) {
r_meta_add (r->anal, R_META_TYPE_DATA, hvaddr,
hvaddr + entry->bits / 8, NULL);
}
} else if (IS_MODE_SIMPLE (mode)) {
r_cons_printf ("0x%08"PFMT64x"\n", at);
} else if (IS_MODE_JSON (mode)) {
r_cons_printf ("%s{\"vaddr\":%" PFMT64u ","
"\"paddr\":%" PFMT64u ","
"\"baddr\":%" PFMT64u ","
"\"laddr\":%" PFMT64u ",",
last_processed ? "," : "", at, paddr, baddr, laddr);
if (hvaddr != UT64_MAX) {
r_cons_printf ("\"hvaddr\":%" PFMT64u ",", hvaddr);
}
r_cons_printf ("\"%s\":%" PFMT64u ","
"\"type\":\"%s\"}",
hpaddr_key, hpaddr, type);
} else if (IS_MODE_RAD (mode)) {
char *name = NULL;
if (entry->type == R_BIN_ENTRY_TYPE_INIT) {
name = r_str_newf ("entry.init%i", init_i);
} else if (entry->type == R_BIN_ENTRY_TYPE_FINI) {
name = r_str_newf ("entry.fini%i", fini_i);
} else if (entry->type == R_BIN_ENTRY_TYPE_PREINIT) {
name = r_str_newf ("entry.preinit%i", preinit_i);
} else {
name = r_str_newf ("entry%i", i);
}
r_cons_printf ("f %s 1 @ 0x%08"PFMT64x"\n", name, at);
r_cons_printf ("f %s_%s 1 @ 0x%08"PFMT64x"\n", name, hpaddr_key, hpaddr);
r_cons_printf ("s %s\n", name);
free (name);
} else {
r_cons_printf ("vaddr=0x%08"PFMT64x" paddr=0x%08"PFMT64x, at, paddr);
if (is_initfini (entry) && hvaddr != UT64_MAX) {
r_cons_printf (" hvaddr=0x%08"PFMT64x, hvaddr);
}
r_cons_printf (" %s=", hpaddr_key);
if (hpaddr == UT64_MAX) {
r_cons_printf ("%"PFMT64d, hpaddr);
} else {
r_cons_printf ("0x%08"PFMT64x, hpaddr);
}
if (entry->type == R_BIN_ENTRY_TYPE_PROGRAM && hvaddr != UT64_MAX) {
r_cons_printf (" hvaddr=0x%08"PFMT64x, hvaddr);
}
r_cons_printf (" type=%s\n", type);
}
if (entry->type == R_BIN_ENTRY_TYPE_INIT) {
init_i++;
} else if (entry->type == R_BIN_ENTRY_TYPE_FINI) {
fini_i++;
} else if (entry->type == R_BIN_ENTRY_TYPE_PREINIT) {
preinit_i++;
} else {
i++;
}
last_processed = iter;
}
if (IS_MODE_SET (mode)) {
if (entry) {
ut64 at = rva (r->bin, entry->paddr, entry->vaddr, va);
r_core_seek (r, at, 0);
}
} else if (IS_MODE_JSON (mode)) {
r_cons_printf ("]");
r_cons_newline ();
} else if (IS_MODE_NORMAL (mode)) {
r_cons_printf ("\n%i entrypoints\n", init_i + fini_i + preinit_i + i);
}
return true;
}
static const char *bin_reloc_type_name(RBinReloc *reloc) {
#define CASE(T) case R_BIN_RELOC_ ## T: return reloc->additive ? "ADD_" #T : "SET_" #T
switch (reloc->type) {
CASE(8);
CASE(16);
CASE(32);
CASE(64);
}
return "UNKNOWN";
#undef CASE
}
static ut8 bin_reloc_size(RBinReloc *reloc) {
#define CASE(T) case R_BIN_RELOC_ ## T: return (T) / 8
switch (reloc->type) {
CASE(8);
CASE(16);
CASE(32);
CASE(64);
}
return 0;
#undef CASE
}
static char *resolveModuleOrdinal(Sdb *sdb, const char *module, int ordinal) {
Sdb *db = sdb;
char *foo = sdb_get (db, sdb_fmt ("%d", ordinal), 0);
return (foo && *foo) ? foo : NULL;
}
static char *get_reloc_name(RCore *r, RBinReloc *reloc, ut64 addr) {
char *reloc_name = NULL;
char *demangled_name = NULL;
const char *lang = r_config_get (r->config, "bin.lang");
int bin_demangle = r_config_get_i (r->config, "bin.demangle");
if (reloc->import && reloc->import->name) {
if (bin_demangle) {
demangled_name = r_bin_demangle (r->bin->cur, lang, reloc->import->name, addr);
}
reloc_name = sdb_fmt ("reloc.%s_%d", demangled_name ? demangled_name : reloc->import->name,
(int)(addr & 0xff));
if (!reloc_name) {
free (demangled_name);
return NULL;
}
r_str_replace_char (reloc_name, '$', '_');
} else if (reloc->symbol && reloc->symbol->name) {
if (bin_demangle) {
demangled_name = r_bin_demangle (r->bin->cur, lang, reloc->symbol->name, addr);
}
reloc_name = sdb_fmt ("reloc.%s_%d", demangled_name ? demangled_name : reloc->symbol->name,
(int)(addr & 0xff));
if (!reloc_name) {
free (demangled_name);
return NULL;
}
r_str_replace_char (reloc_name, '$', '_');
} else if (reloc->is_ifunc) {
// addend is the function pointer for the resolving ifunc
reloc_name = sdb_fmt ("reloc.ifunc_%"PFMT64x, reloc->addend);
} else {
// TODO(eddyb) implement constant relocs.
}
free (demangled_name);
return reloc_name;
}
static void set_bin_relocs(RCore *r, RBinReloc *reloc, ut64 addr, Sdb **db, char **sdb_module) {
int bin_demangle = r_config_get_i (r->config, "bin.demangle");
const char *lang = r_config_get (r->config, "bin.lang");
char *reloc_name, *demname = NULL;
bool is_pe = true;
int is_sandbox = r_sandbox_enable (0);
if (reloc->import && reloc->import->name[0]) {
char str[R_FLAG_NAME_SIZE];
RFlagItem *fi;
if (is_pe && !is_sandbox && strstr (reloc->import->name, "Ordinal")) {
const char *TOKEN = ".dll_Ordinal_";
char *module = strdup (reloc->import->name);
char *import = strstr (module, TOKEN);
r_str_case (module, false);
if (import) {
char *filename = NULL;
int ordinal;
*import = 0;
import += strlen (TOKEN);
ordinal = atoi (import);
if (!*sdb_module || strcmp (module, *sdb_module)) {
sdb_free (*db);
*db = NULL;
free (*sdb_module);
*sdb_module = strdup (module);
/* always lowercase */
filename = sdb_fmt ("%s.sdb", module);
r_str_case (filename, false);
if (r_file_exists (filename)) {
*db = sdb_new (NULL, filename, 0);
} else {
const char *dirPrefix = r_sys_prefix (NULL);
filename = sdb_fmt (R_JOIN_4_PATHS ("%s", R2_SDB_FORMAT, "dll", "%s.sdb"),
dirPrefix, module);
if (r_file_exists (filename)) {
*db = sdb_new (NULL, filename, 0);
}
}
}
if (*db) {
// ordinal-1 because we enumerate starting at 0
char *symname = resolveModuleOrdinal (*db, module, ordinal - 1); // uses sdb_get
if (symname) {
if (r->bin->prefix) {
reloc->import->name = r_str_newf
("%s.%s.%s", r->bin->prefix, module, symname);
} else {
reloc->import->name = r_str_newf
("%s.%s", module, symname);
}
R_FREE (symname);
}
}
}
free (module);
r_anal_hint_set_size (r->anal, reloc->vaddr, 4);
r_meta_add (r->anal, R_META_TYPE_DATA, reloc->vaddr, reloc->vaddr+4, NULL);
}
reloc_name = reloc->import->name;
if (r->bin->prefix) {
snprintf (str, R_FLAG_NAME_SIZE, "%s.reloc.%s", r->bin->prefix, reloc_name);
} else {
snprintf (str, R_FLAG_NAME_SIZE, "reloc.%s", reloc_name);
}
if (bin_demangle) {
demname = r_bin_demangle (r->bin->cur, lang, str, addr);
}
r_name_filter (str, 0);
fi = r_flag_set (r->flags, str, addr, bin_reloc_size (reloc));
if (demname) {
char *realname;
if (r->bin->prefix) {
realname = sdb_fmt ("%s.reloc.%s", r->bin->prefix, demname);
} else {
realname = sdb_fmt ("reloc.%s", demname);
}
r_flag_item_set_realname (fi, realname);
}
} else {
char *reloc_name = get_reloc_name (r, reloc, addr);
if (reloc_name) {
r_flag_set (r->flags, reloc_name, addr, bin_reloc_size (reloc));
} else {
// eprintf ("Cannot find a name for 0x%08"PFMT64x"\n", addr);
}
}
}
/* Define new data at relocation address if it's not in an executable section */
static void add_metadata(RCore *r, RBinReloc *reloc, ut64 addr, int mode) {
RBinFile * binfile = r->bin->cur;
RBinObject *binobj = binfile ? binfile->o: NULL;
RBinInfo *info = binobj ? binobj->info: NULL;
int cdsz;
cdsz = info? (info->bits == 64? 8: info->bits == 32? 4: info->bits == 16 ? 4: 0): 0;
if (cdsz == 0) {
return;
}
RIOMap *map = r_io_map_get (r->io, addr);
if (!map || map ->perm & R_PERM_X) {
return;
}
if (IS_MODE_SET (mode)) {
r_meta_add (r->anal, R_META_TYPE_DATA, reloc->vaddr, reloc->vaddr + cdsz, NULL);
} else if (IS_MODE_RAD (mode)) {
r_cons_printf ("f Cd %d @ 0x%08" PFMT64x "\n", cdsz, addr);
}
}
static bool is_section_symbol(RBinSymbol *s) {
/* workaround for some bin plugs (e.g. ELF) */
if (!s || *s->name) {
return false;
}
return (s->type && !strcmp (s->type, R_BIN_TYPE_SECTION_STR));
}
static bool is_section_reloc(RBinReloc *r) {
return is_section_symbol (r->symbol);
}
static bool is_file_symbol(RBinSymbol *s) {
/* workaround for some bin plugs (e.g. ELF) */
return (s && s->type && !strcmp (s->type, R_BIN_TYPE_FILE_STR));
}
static bool is_file_reloc(RBinReloc *r) {
return is_file_symbol (r->symbol);
}
static int bin_relocs(RCore *r, int mode, int va) {
bool bin_demangle = r_config_get_i (r->config, "bin.demangle");
const char *lang = r_config_get (r->config, "bin.lang");
RBIter iter;
RBinReloc *reloc = NULL;
Sdb *db = NULL;
PJ *pj = NULL;
char *sdb_module = NULL;
int i = 0;
R_TIME_BEGIN;
va = VA_TRUE; // XXX relocs always vaddr?
//this has been created for reloc object files
RBNode *relocs = r_bin_patch_relocs (r->bin);
if (!relocs) {
relocs = r_bin_get_relocs (r->bin);
}
if (IS_MODE_RAD (mode)) {
r_cons_println ("fs relocs");
} else if (IS_MODE_NORMAL (mode)) {
r_cons_println ("[Relocations]");
} else if (IS_MODE_JSON (mode)) {
// start a new JSON object
pj = pj_new ();
if (pj) {
pj_a (pj);
}
} else if (IS_MODE_SET (mode)) {
r_flag_space_set (r->flags, R_FLAGS_FS_RELOCS);
}
r_rbtree_foreach (relocs, iter, reloc, RBinReloc, vrb) {
ut64 addr = rva (r->bin, reloc->paddr, reloc->vaddr, va);
if (IS_MODE_SET (mode) && (is_section_reloc (reloc) || is_file_reloc (reloc))) {
/*
* Skip section reloc because they will have their own flag.
* Skip also file reloc because not useful for now.
*/
} else if (IS_MODE_SET (mode)) {
set_bin_relocs (r, reloc, addr, &db, &sdb_module);
add_metadata (r, reloc, addr, mode);
} else if (IS_MODE_SIMPLE (mode)) {
r_cons_printf ("0x%08"PFMT64x" %s\n", addr, reloc->import ? reloc->import->name : "");
} else if (IS_MODE_RAD (mode)) {
char *name = reloc->import
? strdup (reloc->import->name)
: (reloc->symbol ? strdup (reloc->symbol->name) : NULL);
if (name && bin_demangle) {
char *mn = r_bin_demangle (r->bin->cur, NULL, name, addr);
if (mn) {
free (name);
name = mn;
}
}
if (name) {
r_cons_printf ("f %s%s%s @ 0x%08"PFMT64x"\n",
r->bin->prefix ? r->bin->prefix : "reloc.",
r->bin->prefix ? "." : "", name, addr);
add_metadata (r, reloc, addr, mode);
free (name);
}
} else if (IS_MODE_JSON (mode)) {
if (pj) {
pj_o (pj);
char *mn = NULL;
char *relname = NULL;
// take care with very long symbol names! do not use sdb_fmt or similar
if (reloc->import) {
mn = r_bin_demangle (r->bin->cur, lang, reloc->import->name, addr);
relname = strdup (reloc->import->name);
} else if (reloc->symbol) {
mn = r_bin_demangle (r->bin->cur, lang, reloc->symbol->name, addr);
relname = strdup (reloc->symbol->name);
}
// check if name is available
pj_ks (pj, "name", (relname && strcmp (relname, "")) ? relname : "N/A");
pj_ks (pj, "demname", mn ? mn : "");
pj_ks (pj, "type",bin_reloc_type_name (reloc));
pj_kn (pj, "vaddr", reloc->vaddr);
pj_kn (pj, "paddr", reloc->paddr);
if (reloc->symbol) {
pj_kn (pj, "sym_va", reloc->symbol->vaddr);
}
pj_kb (pj, "is_ifunc", reloc->is_ifunc);
// end reloc item
pj_end (pj);
free (mn);
if (relname) {
free (relname);
}
}
} else if (IS_MODE_NORMAL (mode)) {
char *name = reloc->import
? strdup (reloc->import->name)
: reloc->symbol
? strdup (reloc->symbol->name)
: strdup ("null");
if (bin_demangle) {
char *mn = r_bin_demangle (r->bin->cur, NULL, name, addr);
if (mn && *mn) {
free (name);
name = mn;
}
}
r_cons_printf ("vaddr=0x%08"PFMT64x" paddr=0x%08"PFMT64x" type=%s",
addr, reloc->paddr, bin_reloc_type_name (reloc));
if (reloc->import && reloc->import->name[0]) {
r_cons_printf (" %s", name);
} else if (reloc->symbol && name && name[0]) {
r_cons_printf (" %s", name);
}
free (name);
if (reloc->addend) {
if (reloc->import && reloc->addend > 0) {
r_cons_printf (" +");
}
if (reloc->addend < 0) {
r_cons_printf (" - 0x%08"PFMT64x, -reloc->addend);
} else {
r_cons_printf (" 0x%08"PFMT64x, reloc->addend);
}
}
if (reloc->is_ifunc) {
r_cons_print (" (ifunc)");
}
r_cons_newline ();
}
i++;
}
if (IS_MODE_JSON (mode)) {
// close Json output
pj_end (pj);
r_cons_println (pj_string (pj));
}
if (IS_MODE_NORMAL (mode)) {
r_cons_printf ("\n%i relocations\n", i);
}
// free PJ object if used
if (pj) {
pj_free (pj);
}
R_FREE (sdb_module);
sdb_free (db);
db = NULL;
R_TIME_END;
return relocs != NULL;
}
#define MYDB 1
/* this is a hacky workaround that needs proper refactoring in Rbin to use Sdb */
#if MYDB
static Sdb *mydb = NULL;
static RList *osymbols = NULL;
static RBinSymbol *get_symbol(RBin *bin, RList *symbols, const char *name, ut64 addr) {
RBinSymbol *symbol, *res = NULL;
RListIter *iter;
if (mydb && symbols && symbols != osymbols) {
sdb_free (mydb);
mydb = NULL;
osymbols = symbols;
}
if (mydb) {
if (name) {
res = (RBinSymbol*)(void*)(size_t)
sdb_num_get (mydb, sdb_fmt ("%x", sdb_hash (name)), NULL);
} else {
res = (RBinSymbol*)(void*)(size_t)
sdb_num_get (mydb, sdb_fmt ("0x"PFMT64x, addr), NULL);
}
} else {
mydb = sdb_new0 ();
r_list_foreach (symbols, iter, symbol) {
if (!symbol->name) {
continue;
}
/* ${name}=${ptrToSymbol} */
if (!sdb_num_add (mydb, sdb_fmt ("%x", sdb_hash (symbol->name)), (ut64)(size_t)symbol, 0)) {
// eprintf ("DUP (%s)\n", symbol->name);
}
/* 0x${vaddr}=${ptrToSymbol} */
if (!sdb_num_add (mydb, sdb_fmt ("0x"PFMT64x, symbol->vaddr), (ut64)(size_t)symbol, 0)) {
// eprintf ("DUP (%s)\n", symbol->name);
}
if (name) {
if (!res && !strcmp (symbol->name, name)) {
res = symbol;
}
} else {
if (symbol->vaddr == addr) {
res = symbol;
}
}
}
osymbols = symbols;
}
return res;
}
#else
static RList *osymbols = NULL;
static RBinSymbol *get_symbol(RBin *bin, RList *symbols, const char *name, ut64 addr) {
RBinSymbol *symbol;
RListIter *iter;
// XXX this is slow, we should use a hashtable here
r_list_foreach (symbols, iter, symbol) {
if (name) {
if (!strcmp (symbol->name, name))
return symbol;
} else {
if (symbol->vaddr == addr) {
return symbol;
}
}
}
return NULL;
}
#endif
/* XXX: This is a hack to get PLT references in rabin2 -i */
/* imp. is a prefix that can be rewritten by the symbol table */
R_API ut64 r_core_bin_impaddr(RBin *bin, int va, const char *name) {
RList *symbols;
if (!name || !*name) {
return false;
}
if (!(symbols = r_bin_get_symbols (bin))) {
return false;
}
char *impname = r_str_newf ("imp.%s", name);
RBinSymbol *s = get_symbol (bin, symbols, impname, 0LL);
// maybe ut64_MAX to indicate import not found?
ut64 addr = 0LL;
if (s) {
if (va) {
if (s->paddr == UT64_MAX) {
addr = s->vaddr;
} else {
addr = r_bin_get_vaddr (bin, s->paddr, s->vaddr);
}
} else {
addr = s->paddr;
}
}
free (impname);
return addr;
}
static int bin_imports(RCore *r, int mode, int va, const char *name) {
RBinInfo *info = r_bin_get_info (r->bin);
int bin_demangle = r_config_get_i (r->config, "bin.demangle");
RBinImport *import;
RListIter *iter;
bool lit = info ? info->has_lit: false;
char *str;
int i = 0;
RList *imports = r_bin_get_imports (r->bin);
int cdsz = info? (info->bits == 64? 8: info->bits == 32? 4: info->bits == 16 ? 4: 0): 0;
if (IS_MODE_JSON (mode)) {
r_cons_print ("[");
} else if (IS_MODE_RAD (mode)) {
r_cons_println ("fs imports");
} else if (IS_MODE_NORMAL (mode)) {
r_cons_println ("[Imports]");
r_cons_println ("Num Vaddr Bind Type Name");
}
r_list_foreach (imports, iter, import) {
if (name && strcmp (import->name, name)) {
continue;
}
char *symname = strdup (import->name);
ut64 addr = lit ? r_core_bin_impaddr (r->bin, va, symname): 0;
if (bin_demangle) {
char *dname = r_bin_demangle (r->bin->cur, NULL, symname, addr);
if (dname) {
free (symname);
symname = r_str_newf ("sym.imp.%s", dname);
free (dname);
}
}
if (r->bin->prefix) {
char *prname = r_str_newf ("%s.%s", r->bin->prefix, symname);
free (symname);
symname = prname;
}
if (IS_MODE_SET (mode)) {
// TODO(eddyb) symbols that are imports.
// Add a dword/qword for PE imports
if (strstr (symname, ".dll_") && cdsz) {
r_meta_add (r->anal, R_META_TYPE_DATA, addr, addr + cdsz, NULL);
}
} else if (IS_MODE_SIMPLE (mode)) {
r_cons_println (symname);
} else if (IS_MODE_JSON (mode)) {
str = r_str_escape_utf8_for_json (symname, -1);
str = r_str_replace (str, "\"", "\\\"", 1);
r_cons_printf ("%s{\"ordinal\":%d,"
"\"bind\":\"%s\","
"\"type\":\"%s\",",
iter->p ? "," : "",
import->ordinal,
import->bind,
import->type);
if (import->classname && import->classname[0]) {
r_cons_printf ("\"classname\":\"%s\","
"\"descriptor\":\"%s\",",
import->classname,
import->descriptor);
}
r_cons_printf ("\"name\":\"%s\",\"plt\":%"PFMT64d"}",
str, addr);
free (str);
} else if (IS_MODE_RAD (mode)) {
// TODO(eddyb) symbols that are imports.
} else {
const char *bind = r_str_get (import->bind);
const char *type = r_str_get (import->type);
#if 0
r_cons_printf ("ordinal=%03d plt=0x%08"PFMT64x" bind=%s type=%s",
import->ordinal, addr, bind, type);
if (import->classname && import->classname[0]) {
r_cons_printf (" classname=%s", import->classname);
}
r_cons_printf (" name=%s", symname);
if (import->descriptor && import->descriptor[0]) {
r_cons_printf (" descriptor=%s", import->descriptor);
}
r_cons_newline ();
#else
r_cons_printf ("%4d 0x%08"PFMT64x" %7s %7s ",
import->ordinal, addr, bind, type);
if (import->classname && import->classname[0]) {
r_cons_printf ("%s.", import->classname);
}
r_cons_printf ("%s", symname);
if (import->descriptor && import->descriptor[0]) {
// Uh?
r_cons_printf (" descriptor=%s", import->descriptor);
}
r_cons_newline ();
#endif
}
R_FREE (symname);
i++;
}
if (IS_MODE_JSON (mode)) {
r_cons_print ("]");
} else if (IS_MODE_NORMAL (mode)) {
// r_cons_printf ("# %i imports\n", i);
}
#if MYDB
// NOTE: if we comment out this, it will leak.. but it will be faster
// because it will keep the cache across multiple RBin calls
osymbols = NULL;
sdb_free (mydb);
mydb = NULL;
#endif
return true;
}
static const char *getPrefixFor(const char *s) {
if (s) {
// workaround for ELF
if (!strcmp (s, R_BIN_TYPE_NOTYPE_STR)) {
return "loc";
}
if (!strcmp (s, R_BIN_TYPE_OBJECT_STR)) {
return "obj";
}
}
return "sym";
}
typedef struct {
const char *pfx; // prefix for flags
char *name; // raw symbol name
char *nameflag; // flag name for symbol
char *demname; // demangled raw symbol name
char *demflag; // flag name for demangled symbol
char *classname; // classname
char *classflag; // flag for classname
char *methname; // methods [class]::[method]
char *methflag; // methods flag sym.[class].[method]
} SymName;
static void snInit(RCore *r, SymName *sn, RBinSymbol *sym, const char *lang) {
#define MAXFLAG_LEN 128
int bin_demangle = lang != NULL;
const char *pfx;
if (!r || !sym || !sym->name) {
return;
}
pfx = getPrefixFor (sym->type);
sn->name = strdup (sym->name);
if (sym->dup_count) {
sn->nameflag = r_str_newf ("%s.%s_%d", pfx, sym->name, sym->dup_count);
} else {
sn->nameflag = r_str_newf ("%s.%s", pfx, sym->name);
}
r_name_filter (sn->nameflag, MAXFLAG_LEN);
if (sym->classname && sym->classname[0]) {
sn->classname = strdup (sym->classname);
sn->classflag = r_str_newf ("sym.%s.%s", sn->classname, sn->name);
r_name_filter (sn->classflag, MAXFLAG_LEN);
const char *name = sym->dname? sym->dname: sym->name;
sn->methname = r_str_newf ("%s::%s", sn->classname, name);
sn->methflag = r_str_newf ("sym.%s.%s", sn->classname, name);
r_name_filter (sn->methflag, strlen (sn->methflag));
} else {
sn->classname = NULL;
sn->classflag = NULL;
sn->methname = NULL;
sn->methflag = NULL;
}
sn->demname = NULL;
sn->demflag = NULL;
if (bin_demangle && sym->paddr) {
sn->demname = r_bin_demangle (r->bin->cur, lang, sn->name, sym->vaddr);
if (sn->demname) {
sn->demflag = r_str_newf ("%s.%s", pfx, sn->demname);
r_name_filter (sn->demflag, -1);
}
}
}
static void snFini(SymName *sn) {
R_FREE (sn->name);
R_FREE (sn->nameflag);
R_FREE (sn->demname);
R_FREE (sn->demflag);
R_FREE (sn->classname);
R_FREE (sn->classflag);
R_FREE (sn->methname);
R_FREE (sn->methflag);
}
static bool isAnExport(RBinSymbol *s) {
/* workaround for some bin plugs */
if (!strncmp (s->name, "imp.", 4)) {
return false;
}
return (s->bind && !strcmp (s->bind, R_BIN_BIND_GLOBAL_STR));
}
static int bin_symbols(RCore *r, int mode, ut64 laddr, int va, ut64 at, const char *name, bool exponly, const char *args) {
RBinInfo *info = r_bin_get_info (r->bin);
RList *entries = r_bin_get_entries (r->bin);
RBinSymbol *symbol;
RBinAddr *entry;
RListIter *iter;
bool firstexp = true;
bool printHere = false;
int i = 0, lastfs = 's';
bool bin_demangle = r_config_get_i (r->config, "bin.demangle");
if (!info) {
return 0;
}
if (args && *args == '.') {
printHere = true;
}
bool is_arm = info && info->arch && !strncmp (info->arch, "arm", 3);
const char *lang = bin_demangle ? r_config_get (r->config, "bin.lang") : NULL;
RList *symbols = r_bin_get_symbols (r->bin);
r_spaces_push (&r->anal->meta_spaces, "bin");
if (IS_MODE_JSON (mode) && !printHere) {
r_cons_printf ("[");
} else if (IS_MODE_SET (mode)) {
r_flag_space_set (r->flags, R_FLAGS_FS_SYMBOLS);
} else if (!at && exponly) {
if (IS_MODE_RAD (mode)) {
r_cons_printf ("fs exports\n");
} else if (IS_MODE_NORMAL (mode)) {
r_cons_printf (printHere ? "" : "[Exports]\n");
}
} else if (!at && !exponly) {
if (IS_MODE_RAD (mode)) {
r_cons_printf ("fs symbols\n");
} else if (IS_MODE_NORMAL (mode)) {
r_cons_printf (printHere ? "" : "[Symbols]\n");
}
}
if (IS_MODE_NORMAL (mode)) {
r_cons_printf ("Num Paddr Vaddr Bind Type Size Name\n");
}
r_list_foreach (symbols, iter, symbol) {
if (!symbol->name) {
continue;
}
char *r_symbol_name = r_str_escape_utf8 (symbol->name, false, true);
ut64 addr = symbol->paddr == UT64_MAX ? symbol->vaddr : rva (r->bin, symbol->paddr, symbol->vaddr, va);
int len = symbol->size ? symbol->size : 32;
SymName sn = {0};
if (exponly && !isAnExport (symbol)) {
free (r_symbol_name);
continue;
}
if (name && strcmp (r_symbol_name, name)) {
free (r_symbol_name);
continue;
}
if (at && (!symbol->size || !is_in_range (at, addr, symbol->size))) {
free (r_symbol_name);
continue;
}
if ((printHere && !is_in_range (r->offset, symbol->paddr, len))
&& (printHere && !is_in_range (r->offset, addr, len))) {
free (r_symbol_name);
continue;
}
snInit (r, &sn, symbol, lang);
if (IS_MODE_SET (mode) && (is_section_symbol (symbol) || is_file_symbol (symbol))) {
/*
* Skip section symbols because they will have their own flag.
* Skip also file symbols because not useful for now.
*/
} else if (IS_MODE_SET (mode)) {
if (is_arm && info->bits < 33) { // 16 or 32
int force_bits = 0;
if (symbol->paddr & 1 || symbol->bits == 16) {
force_bits = 16;
} else if (info->bits == 16 && symbol->bits == 32) {
force_bits = 32;
} else if (!(symbol->paddr & 1) && symbol->bits == 32) {
force_bits = 32;
}
if (force_bits) {
r_anal_hint_set_bits (r->anal, addr, force_bits);
}
}
if (!strncmp (r_symbol_name, "imp.", 4)) {
if (lastfs != 'i') {
r_flag_space_set (r->flags, R_FLAGS_FS_IMPORTS);
}
lastfs = 'i';
} else {
if (lastfs != 's') {
r_flag_space_set (r->flags, R_FLAGS_FS_SYMBOLS);
}
lastfs = 's';
}
/* If that's a Classed symbol (method or so) */
if (sn.classname) {
RFlagItem *fi = r_flag_get (r->flags, sn.methflag);
if (r->bin->prefix) {
char *prname = r_str_newf ("%s.%s", r->bin->prefix, sn.methflag);
r_name_filter (sn.methflag, -1);
free (sn.methflag);
sn.methflag = prname;
}
if (fi) {
r_flag_item_set_realname (fi, sn.methname);
if ((fi->offset - r->flags->base) == addr) {
// char *comment = fi->comment ? strdup (fi->comment) : NULL;
r_flag_unset (r->flags, fi);
}
} else {
fi = r_flag_set (r->flags, sn.methflag, addr, symbol->size);
char *comment = fi->comment ? strdup (fi->comment) : NULL;
if (comment) {
r_flag_item_set_comment (fi, comment);
R_FREE (comment);
}
}
} else {
const char *n = sn.demname ? sn.demname : sn.name;
const char *fn = sn.demflag ? sn.demflag : sn.nameflag;
char *fnp = (r->bin->prefix) ?
r_str_newf ("%s.%s", r->bin->prefix, fn):
strdup (fn);
RFlagItem *fi = r_flag_set (r->flags, fnp, addr, symbol->size);
if (fi) {
r_flag_item_set_realname (fi, n);
} else {
if (fn) {
eprintf ("[Warning] Can't find flag (%s)\n", fn);
}
}
free (fnp);
}
if (sn.demname) {
r_meta_add (r->anal, R_META_TYPE_COMMENT,
addr, symbol->size, sn.demname);
}
} else if (IS_MODE_JSON (mode)) {
char *str = r_str_escape_utf8_for_json (r_symbol_name, -1);
// str = r_str_replace (str, "\"", "\\\"", 1);
r_cons_printf ("%s{\"name\":\"%s\","
"\"demname\":\"%s\","
"\"flagname\":\"%s\","
"\"ordinal\":%d,"
"\"bind\":\"%s\","
"\"size\":%d,"
"\"type\":\"%s\","
"\"vaddr\":%"PFMT64d","
"\"paddr\":%"PFMT64d"}",
((exponly && firstexp) || printHere) ? "" : (iter->p ? "," : ""),
str,
sn.demname? sn.demname: "",
sn.nameflag,
symbol->ordinal,
symbol->bind,
(int)symbol->size,
symbol->type,
(ut64)addr, (ut64)symbol->paddr);
free (str);
} else if (IS_MODE_SIMPLE (mode)) {
const char *name = sn.demname? sn.demname: r_symbol_name;
r_cons_printf ("0x%08"PFMT64x" %d %s\n",
addr, (int)symbol->size, name);
} else if (IS_MODE_SIMPLEST (mode)) {
const char *name = sn.demname? sn.demname: r_symbol_name;
r_cons_printf ("%s\n", name);
} else if (IS_MODE_RAD (mode)) {
RBinFile *binfile;
RBinPlugin *plugin;
char *name = strdup (sn.demname? sn.demname: r_symbol_name);
r_name_filter (name, -1);
if (!strncmp (name, "imp.", 4)) {
if (lastfs != 'i') {
r_cons_printf ("fs imports\n");
}
lastfs = 'i';
} else {
if (lastfs != 's') {
r_cons_printf ("fs %s\n",
exponly? "exports": "symbols");
}
lastfs = 's';
}
if (r->bin->prefix) {
if (symbol->dup_count) {
r_cons_printf ("f %s.sym.%s_%d %u 0x%08"PFMT64x"\n",
r->bin->prefix, name, symbol->dup_count, symbol->size, addr);
} else {
r_cons_printf ("f %s.sym.%s %u 0x%08"PFMT64x"\n",
r->bin->prefix, name, symbol->size, addr);
}
} else {
if (*name) {
if (symbol->dup_count) {
r_cons_printf ("f sym.%s_%d %u 0x%08"PFMT64x"\n",
name, symbol->dup_count, symbol->size, addr);
} else {
r_cons_printf ("f sym.%s %u 0x%08"PFMT64x"\n",
name, symbol->size, addr);
}
} else {
// we dont want unnamed symbol flags
}
}
binfile = r_core_bin_cur (r);
plugin = r_bin_file_cur_plugin (binfile);
if (plugin && plugin->name) {
if (!strncmp (plugin->name, "pe", 2)) {
char *p, *module = strdup (r_symbol_name);
p = strstr (module, ".dll_");
if (p) {
const char *symname = p + 5;
*p = 0;
if (r->bin->prefix) {
r_cons_printf ("k bin/pe/%s/%d=%s.%s\n",
module, symbol->ordinal, r->bin->prefix, symname);
} else {
r_cons_printf ("k bin/pe/%s/%d=%s\n",
module, symbol->ordinal, symname);
}
}
free (module);
}
}
} else {
const char *bind = symbol->bind? symbol->bind: "NONE";
const char *type = symbol->type? symbol->type: "NONE";
const char *name = r_str_get (sn.demname? sn.demname: r_symbol_name);
// const char *fwd = r_str_get (symbol->forwarder);
r_cons_printf ("%03u", symbol->ordinal);
if (symbol->paddr == UT64_MAX) {
r_cons_printf (" ----------");
} else {
r_cons_printf (" 0x%08"PFMT64x, symbol->paddr);
}
r_cons_printf (" 0x%08"PFMT64x" %6s %6s %4d%s%s\n",
addr, bind, type, symbol->size, *name? " ": "", name);
}
snFini (&sn);
i++;
free (r_symbol_name);
if (exponly && firstexp) {
firstexp = false;
}
if (printHere) {
break;
}
}
//handle thumb and arm for entry point since they are not present in symbols
if (is_arm) {
r_list_foreach (entries, iter, entry) {
if (IS_MODE_SET (mode)) {
if (info->bits < 33) { // 16 or 32
int force_bits = 0;
ut64 addr = rva (r->bin, entry->paddr, entry->vaddr, va);
if (entry->paddr & 1 || entry->bits == 16) {
force_bits = 16;
} else if (info->bits == 16 && entry->bits == 32) {
force_bits = 32;
} else if (!(entry->paddr & 1)) {
force_bits = 32;
}
if (force_bits) {
r_anal_hint_set_bits (r->anal, addr, force_bits);
}
}
}
}
}
if (IS_MODE_JSON (mode) && !printHere) {
r_cons_printf ("]");
}
r_spaces_pop (&r->anal->meta_spaces);
return true;
}
static char *build_hash_string(int mode, const char *chksum, ut8 *data, ut32 datalen) {
char *chkstr = NULL, *aux, *ret = NULL;
const char *ptr = chksum;
char tmp[128];
int i;
do {
for (i = 0; *ptr && *ptr != ',' && i < sizeof (tmp) -1; i++) {
tmp[i] = *ptr++;
}
tmp[i] = '\0';
r_str_trim_head_tail (tmp);
chkstr = r_hash_to_string (NULL, tmp, data, datalen);
if (!chkstr) {
if (*ptr && *ptr == ',') {
ptr++;
}
continue;
}
if (IS_MODE_SIMPLE (mode)) {
aux = r_str_newf ("%s ", chkstr);
} else if (IS_MODE_JSON (mode)) {
aux = r_str_newf ("\"%s\":\"%s\",", tmp, chkstr);
} else {
aux = r_str_newf ("%s=%s ", tmp, chkstr);
}
ret = r_str_append (ret, aux);
free (chkstr);
free (aux);
if (*ptr && *ptr == ',') {
ptr++;
}
} while (*ptr);
return ret;
}
#define PRINT_CURRENT_SEEK \
if (i > 0 && len != 0) { \
if (seek == UT64_MAX) seek = 0; \
io->cb_printf ("=> 0x%08"PFMT64x" |", seek); \
for (j = 0; j < width; j++) { \
io->cb_printf ( \
((j*mul) + min >= seek && \
(j*mul) + min <= seek + len) \
? "^" : "-"); \
} \
io->cb_printf ("| 0x%08"PFMT64x"\n", seek+len); \
}
static void list_section_visual(RIO *io, RList *sections, ut64 seek, ut64 len, int use_color, int cols) {
ut64 mul, min = -1, max = -1;
RListIter *iter;
RBinSection *s;
int j, i = 0;
int width = cols - 70;
if (width < 1) {
width = 30;
}
ls_foreach (sections, iter, s) {
if (min == -1 || s->paddr < min) {
min = s->paddr;
}
if (max == -1 || s->paddr+s->size > max) {
max = s->paddr + s->size;
}
}
mul = (max-min) / width;
if (min != -1 && mul != 0) {
const char * color = "", *color_end = "";
char humansz[8];
i = 0;
ls_foreach (sections, iter, s) {
char *r_sname = r_str_escape (s->name);
r_num_units (humansz, sizeof (humansz), s->size);
if (use_color) {
color_end = Color_RESET;
if ((s->perm & R_PERM_X) && (s->perm & R_PERM_W)) { // exec & write bits
color = r_cons_singleton()->context->pal.widget_sel;
} else if (s->perm & R_PERM_X) { // exec bit
color = r_cons_singleton()->context->pal.graph_true;
} else if (s->perm & R_PERM_W) { // write bit
color = r_cons_singleton()->context->pal.graph_false;
} else {
color = "";
color_end = "";
}
} else {
color = "";
color_end = "";
}
if (io->va) {
io->cb_printf ("%02d%c %s0x%08"PFMT64x"%s |", i,
(seek >= s->vaddr && seek < s->vaddr + s->vsize) ? '*' : ' ',
color, s->vaddr, color_end);
} else {
io->cb_printf ("%02d%c %s0x%08"PFMT64x"%s |", i,
(seek >= s->paddr && seek < s->paddr + s->size) ? '*' : ' ',
color, s->paddr, color_end);
}
for (j = 0; j < width; j++) {
ut64 pos = min + (j * mul);
ut64 npos = min + ((j + 1) * mul);
if (s->paddr < npos && (s->paddr + s->size) > pos)
io->cb_printf ("#");
else io->cb_printf ("-");
}
if (io->va) {
io->cb_printf ("| %s0x%08"PFMT64x"%s %5s %s %04s\n",
color, s->vaddr + s->vsize, color_end, humansz,
r_str_rwx_i (s->perm), r_sname);
} else {
io->cb_printf ("| %s0x%08"PFMT64x"%s %5s %s %04s\n",
color, s->paddr+s->size, color_end, humansz,
r_str_rwx_i (s->perm), r_sname);
}
i++;
free (r_sname);
}
PRINT_CURRENT_SEEK;
}
}
typedef struct {
const char *uri;
int perm;
RIODesc *desc;
} FindFile;
static bool findFile(void *user, void *data, ut32 id) {
FindFile *res = (FindFile*)user;
RIODesc *desc = (RIODesc*)data;
if (desc->perm && res->perm && !strcmp (desc->uri, res->uri)) {
res->desc = desc;
return false;
}
return true;
}
static RIODesc *findReusableFile(RIO *io, const char *uri, int perm) {
FindFile arg = {
.uri = uri,
.perm = perm,
.desc = NULL,
};
r_id_storage_foreach (io->files, findFile, &arg);
return arg.desc;
}
static bool io_create_mem_map(RIO *io, RBinSection *sec, ut64 at) {
r_return_val_if_fail (io && sec, false);
bool reused = false;
ut64 gap = sec->vsize - sec->size;
char *uri = r_str_newf ("null://%"PFMT64u, gap);
RIODesc *desc = findReusableFile (io, uri, sec->perm);
if (desc) {
RIOMap *map = r_io_map_get (io, at);
if (!map) {
r_io_map_add_batch (io, desc->fd, desc->perm, 0LL, at, gap);
}
reused = true;
}
if (!desc) {
desc = r_io_open_at (io, uri, sec->perm, 0664, at);
}
free (uri);
if (!desc) {
return false;
}
// this works, because new maps are always born on the top
RIOMap *map = r_io_map_get (io, at);
// check if the mapping failed
if (!map) {
if (!reused) {
r_io_desc_close (desc);
}
return false;
}
// let the section refere to the map as a memory-map
map->name = r_str_newf ("mmap.%s", sec->name);
return true;
}
static void add_section(RCore *core, RBinSection *sec, ut64 addr, int fd) {
if (!r_io_desc_get (core->io, fd) || UT64_ADD_OVFCHK (sec->size, sec->paddr) ||
UT64_ADD_OVFCHK (sec->size, addr) || !sec->vsize) {
return;
}
ut64 size = sec->vsize;
// if there is some part of the section that needs to be zeroed by the loader
// we add a null map that takes care of it
if (sec->vsize > sec->size) {
if (!io_create_mem_map (core->io, sec, addr + sec->size)) {
return;
}
size = sec->size;
}
// then we map the part of the section that comes from the physical file
char *map_name = r_str_newf ("fmap.%s", sec->name);
if (!map_name) {
return;
}
int perm = sec->perm;
// workaround to force exec bit in text section
if (sec->name && strstr (sec->name, "text")) {
perm |= R_PERM_X;
}
RIOMap *map = r_io_map_add_batch (core->io, fd, perm, sec->paddr, addr, size);
if (!map) {
free (map_name);
return;
}
map->name = map_name;
return;
}
struct io_bin_section_info_t {
RBinSection *sec;
ut64 addr;
int fd;
};
static int bin_sections(RCore *r, int mode, ut64 laddr, int va, ut64 at, const char *name, const char *chksum, bool print_segments) {
char *str = NULL;
RBinSection *section;
RBinInfo *info = NULL;
RList *sections;
RListIter *iter;
RListIter *last_processed = NULL;
int i = 0;
int fd = -1;
bool printHere = false;
sections = r_bin_get_sections (r->bin);
#if LOAD_BSS_MALLOC
bool inDebugger = r_config_get_i (r->config, "cfg.debug");
#endif
HtPP *dup_chk_ht = ht_pp_new0 ();
bool ret = false;
const char *type = print_segments ? "segment" : "section";
bool segments_only = true;
RList *io_section_info = NULL;
if (!dup_chk_ht) {
return false;
}
if (chksum && *chksum == '.') {
printHere = true;
}
if (IS_MODE_EQUAL (mode)) {
int cols = r_cons_get_size (NULL);
list_section_visual (r->io, sections, r->offset, -1, r->print->flags & R_PRINT_FLAGS_COLOR, cols);
goto out;
}
if (IS_MODE_JSON (mode) && !printHere) {
r_cons_printf ("[");
} else if (IS_MODE_RAD (mode) && !at) {
r_cons_printf ("fs %ss\n", type);
} else if (IS_MODE_NORMAL (mode) && !at && !printHere) {
r_cons_printf ("[%s]\n", print_segments ? "Segments" : "Sections");
} else if (IS_MODE_NORMAL (mode) && printHere) {
r_cons_printf ("Current section\n");
} else if (IS_MODE_SET (mode)) {
fd = r_core_file_cur_fd (r);
r_flag_space_set (r->flags, print_segments? R_FLAGS_FS_SEGMENTS: R_FLAGS_FS_SECTIONS);
}
if (IS_MODE_NORMAL (mode)) {
r_cons_printf ("Nm Paddr Size Vaddr Memsz Perms %sName\n",
chksum ? "Checksum " : "");
}
if (IS_MODE_SET (mode)) {
r_list_foreach (sections, iter, section) {
if (!section->is_segment) {
segments_only = false;
break;
}
}
io_section_info = r_list_newf ((RListFree)free);
}
r_list_foreach (sections, iter, section) {
char perms[] = "----";
int va_sect = va;
ut64 addr;
if (va && !(section->perm & R_PERM_R)) {
va_sect = VA_NOREBASE;
}
addr = rva (r->bin, section->paddr, section->vaddr, va_sect);
if (name && strcmp (section->name, name)) {
continue;
}
if ((printHere && !(section->paddr <= r->offset && r->offset < (section->paddr + section->size)))
&& (printHere && !(addr <= r->offset && r->offset < (addr + section->size)))) {
continue;
}
r_name_filter (section->name, strlen (section->name) + 1);
if (at && (!section->size || !is_in_range (at, addr, section->size))) {
continue;
}
if (section->is_segment != print_segments) {
continue;
}
if (section->perm & R_PERM_SHAR) {
perms[0] = 's';
}
if (section->perm & R_PERM_R) {
perms[1] = 'r';
}
if (section->perm & R_PERM_W) {
perms[2] = 'w';
}
if (section->perm & R_PERM_X) {
perms[3] = 'x';
}
const char *arch = NULL;
int bits = 0;
if (section->arch || section->bits) {
arch = section->arch;
bits = section->bits;
}
if (info) {
if (!arch) {
arch = info->arch;
}
if (!bits) {
bits = info->bits;
}
}
if (!arch) {
arch = r_config_get (r->config, "asm.arch");
}
if (!bits) {
bits = R_SYS_BITS;
}
if (IS_MODE_SET (mode)) {
#if LOAD_BSS_MALLOC
if (!strcmp (section->name, ".bss")) {
// check if there's already a file opened there
int loaded = 0;
RListIter *iter;
RIOMap *m;
r_list_foreach (r->io->maps, iter, m) {
if (m->from == addr) {
loaded = 1;
}
}
if (!loaded && !inDebugger) {
r_core_cmdf (r, "on malloc://%d 0x%"PFMT64x" # bss\n",
section->vsize, addr);
}
}
#endif
if (section->format) {
// This is damn slow if section vsize is HUGE
if (section->vsize < 1024 * 1024 * 2) {
r_core_cmdf (r, "%s @ 0x%"PFMT64x, section->format, section->vaddr);
}
}
if (r->bin->prefix) {
str = r_str_newf ("%s.%s.%s", r->bin->prefix, type, section->name);
} else {
str = r_str_newf ("%s.%s", type, section->name);
}
ut64 size = r->io->va? section->vsize: section->size;
r_flag_set (r->flags, str, addr, size);
R_FREE (str);
if (!section->is_segment || segments_only) {
char *pfx = r->bin->prefix;
str = r_str_newf ("[%02d] %s %s size %" PFMT64d" named %s%s%s",
i, perms, type, size,
pfx? pfx: "", pfx? ".": "", section->name);
r_meta_add (r->anal, R_META_TYPE_COMMENT, addr, addr, str);
R_FREE (str);
}
if (section->add) {
bool found;
str = r_str_newf ("%"PFMT64x".%"PFMT64x".%"PFMT64x".%"PFMT64x".%"PFMT32u".%s.%"PFMT32u".%d",
section->paddr, addr, section->size, section->vsize, section->perm, section->name, r->bin->cur->id, fd);
ht_pp_find (dup_chk_ht, str, &found);
if (!found) {
// can't directly add maps because they
// need to be reversed, otherwise for
// the way IO works maps would be shown
// in reverse order
struct io_bin_section_info_t *ibs = R_NEW (struct io_bin_section_info_t);
if (!ibs) {
eprintf ("Could not allocate memory\n");
goto out;
}
ibs->sec = section;
ibs->addr = addr;
ibs->fd = fd;
r_list_append (io_section_info, ibs);
ht_pp_insert (dup_chk_ht, str, NULL);
}
R_FREE (str);
}
} else if (IS_MODE_SIMPLE (mode)) {
char *hashstr = NULL;
if (chksum) {
ut8 *data = malloc (section->size);
if (!data) {
goto out;
}
ut32 datalen = section->size;
r_io_pread_at (r->io, section->paddr, data, datalen);
hashstr = build_hash_string (mode, chksum,
data, datalen);
free (data);
}
r_cons_printf ("0x%"PFMT64x" 0x%"PFMT64x" %s %s%s%s\n",
addr, addr + section->size,
perms,
hashstr ? hashstr : "", hashstr ? " " : "",
section->name
);
free (hashstr);
} else if (IS_MODE_JSON (mode)) {
char *hashstr = NULL;
if (chksum && section->size > 0) {
ut8 *data = malloc (section->size);
if (!data) {
goto out;
}
ut32 datalen = section->size;
r_io_pread_at (r->io, section->paddr, data, datalen);
hashstr = build_hash_string (mode, chksum,
data, datalen);
free (data);
}
r_cons_printf ("%s{\"name\":\"%s\","
"\"size\":%"PFMT64d","
"\"vsize\":%"PFMT64d","
"\"perm\":\"%s\","
"%s"
"\"paddr\":%"PFMT64d","
"\"vaddr\":%"PFMT64d"}",
(last_processed && !printHere) ? "," : "",
section->name,
section->size,
section->vsize,
perms,
hashstr ? hashstr : "",
section->paddr,
addr);
free (hashstr);
} else {
char *hashstr = NULL, str[128];
if (chksum) {
ut8 *data = malloc (section->size);
if (!data) {
goto out;
}
ut32 datalen = section->size;
// VA READ IS BROKEN?
if (datalen > 0) {
r_io_pread_at (r->io, section->paddr, data, datalen);
}
hashstr = build_hash_string (mode, chksum, data, datalen);
free (data);
}
if (section->arch || section->bits) {
snprintf (str, sizeof (str), "arch=%s bits=%d ",
r_str_get2 (arch), bits);
} else {
str[0] = 0;
}
if (r->bin->prefix) {
r_cons_printf ("%02i 0x%08"PFMT64x" %5"PFMT64d" 0x%08"PFMT64x" %5"PFMT64d" "
"%s %s%s%s.%s\n",
i, section->paddr, section->size, addr, section->vsize,
perms, str, hashstr ?hashstr : "", r->bin->prefix, section->name);
} else {
r_cons_printf ("%02i 0x%08"PFMT64x" %5"PFMT64d" 0x%08"PFMT64x" %5"PFMT64d" "
"%s %s%s%s\n",
i, section->paddr, (ut64)section->size, addr, (ut64)section->vsize,
perms, str, hashstr ?hashstr : "", section->name);
}
free (hashstr);
}
i++;
last_processed = iter;
if (printHere) {
break;
}
}
if (IS_MODE_SET (mode) && !r_io_desc_is_dbg (r->io->desc)) {
RListIter *it;
struct io_bin_section_info_t *ibs;
r_list_foreach_prev (io_section_info, it, ibs) {
add_section (r, ibs->sec, ibs->addr, ibs->fd);
}
r_io_update (r->io);
r_list_free (io_section_info);
io_section_info = NULL;
}
if (IS_MODE_JSON (mode) && !printHere) {
r_cons_println ("]");
} else if (IS_MODE_NORMAL (mode) && !at && !printHere) {
// r_cons_printf ("\n%i sections\n", i);
}
ret = true;
out:
ht_pp_free (dup_chk_ht);
return ret;
}
static int bin_fields(RCore *r, int mode, int va) {
RList *fields;
RListIter *iter;
RBinField *field;
int i = 0;
RBin *bin = r->bin;
// RBinFile *binfile = r_core_bin_cur (r);
if (!(fields = r_bin_get_fields (bin))) {
return false;
}
if (IS_MODE_JSON (mode)) {
r_cons_print ("[");
} else if (IS_MODE_RAD (mode)) {
r_cons_println ("fs header");
} else if (IS_MODE_NORMAL (mode)) {
r_cons_println ("[Header fields]");
}
r_list_foreach (fields, iter, field) {
ut64 addr = rva (bin, field->paddr, field->vaddr, va);
if (IS_MODE_RAD (mode)) {
r_name_filter (field->name, -1);
r_cons_printf ("f header.%s @ 0x%08"PFMT64x"\n", field->name, addr);
if (field->comment && *field->comment) {
r_cons_printf ("CC %s @ 0x%"PFMT64x"\n", field->comment, addr);
}
if (field->format && *field->format) {
r_cons_printf ("pf.%s %s\n", field->name, field->format);
}
} else if (IS_MODE_JSON (mode)) {
r_cons_printf ("%s{\"name\":\"%s\","
"\"vaddr\":%"PFMT64d","
"\"paddr\":%"PFMT64d,
iter->p? ",": "",
field->name,
field->vaddr,
field->paddr
);
if (field->comment && *field->comment) {
// TODO: filter comment before json
r_cons_printf (",\"comment\":\"%s\"", field->comment);
}
if (field->format && *field->format) {
// TODO: filter comment before json
r_cons_printf (",\"format\":\"%s\"", field->format);
}
r_cons_printf ("}");
} else if (IS_MODE_NORMAL (mode)) {
const bool haveComment = (field->comment && *field->comment);
r_cons_printf ("0x%08"PFMT64x" 0x%08"PFMT64x" %s%s%s\n",
field->vaddr, field->paddr, field->name,
haveComment? "; ": "",
haveComment? field->comment: "");
}
i++;
}
if (IS_MODE_JSON (mode)) {
r_cons_printf ("]");
} else if (IS_MODE_NORMAL (mode)) {
r_cons_printf ("\n%i fields\n", i);
}
return true;
}
static char *get_rp(const char *rtype) {
char *rp = NULL;
switch (rtype[0]) {
case 'v':
rp = strdup ("void");
break;
case 'c':
rp = strdup ("char");
break;
case 'i':
rp = strdup ("int");
break;
case 's':
rp = strdup ("short");
break;
case 'l':
rp = strdup ("long");
break;
case 'q':
rp = strdup ("long long");
break;
case 'C':
rp = strdup ("unsigned char");
break;
case 'I':
rp = strdup ("unsigned int");
break;
case 'S':
rp = strdup ("unsigned short");
break;
case 'L':
rp = strdup ("unsigned long");
break;
case 'Q':
rp = strdup ("unsigned long long");
break;
case 'f':
rp = strdup ("float");
break;
case 'd':
rp = strdup ("double");
break;
case 'D':
rp = strdup ("long double");
break;
case 'B':
rp = strdup ("bool");
break;
case '#':
rp = strdup ("CLASS");
break;
default:
rp = strdup ("unknown");
break;
}
return rp;
}
static int bin_classes(RCore *r, int mode) {
RListIter *iter, *iter2, *iter3;
RBinSymbol *sym;
RBinClass *c;
RBinField *f;
char *name;
RList *cs = r_bin_get_classes (r->bin);
if (!cs) {
if (IS_MODE_JSON (mode)) {
r_cons_print("[]");
}
return false;
}
// XXX: support for classes is broken and needs more love
if (IS_MODE_JSON (mode)) {
r_cons_print ("[");
} else if (IS_MODE_SET (mode)) {
if (!r_config_get_i (r->config, "bin.classes")) {
return false;
}
r_flag_space_set (r->flags, R_FLAGS_FS_CLASSES);
} else if (IS_MODE_RAD (mode)) {
r_cons_println ("fs classes");
}
r_list_foreach (cs, iter, c) {
if (!c || !c->name || !c->name[0]) {
continue;
}
name = strdup (c->name);
r_name_filter (name, 0);
ut64 at_min = UT64_MAX;
ut64 at_max = 0LL;
r_list_foreach (c->methods, iter2, sym) {
if (sym->vaddr) {
if (sym->vaddr < at_min) {
at_min = sym->vaddr;
}
if (sym->vaddr + sym->size > at_max) {
at_max = sym->vaddr + sym->size;
}
}
}
if (at_min == UT64_MAX) {
at_min = c->addr;
at_max = c->addr; // XXX + size?
}
if (IS_MODE_SET (mode)) {
const char *classname = sdb_fmt ("class.%s", name);
r_flag_set (r->flags, classname, c->addr, 1);
r_list_foreach (c->methods, iter2, sym) {
char *mflags = r_core_bin_method_flags_str (sym->method_flags, mode);
char *method = sdb_fmt ("method%s.%s.%s",
mflags, c->name, sym->name);
R_FREE (mflags);
r_name_filter (method, -1);
r_flag_set (r->flags, method, sym->vaddr, 1);
}
} else if (IS_MODE_SIMPLE (mode)) {
r_cons_printf ("0x%08"PFMT64x" [0x%08"PFMT64x" - 0x%08"PFMT64x"] %s%s%s\n",
c->addr, at_min, at_max, c->name, c->super ? " " : "",
c->super ? c->super : "");
} else if (IS_MODE_RAD (mode)) {
r_cons_printf ("\"f class.%s = 0x%"PFMT64x"\"\n",
name, at_min);
if (c->super) {
r_cons_printf ("\"f super.%s.%s = %d\"\n",
c->name, c->super, c->index);
}
r_list_foreach (c->methods, iter2, sym) {
char *mflags = r_core_bin_method_flags_str (sym->method_flags, mode);
char *cmd = r_str_newf ("\"f method%s.%s.%s = 0x%"PFMT64x"\"\n", mflags, c->name, sym->name, sym->vaddr);
r_str_replace_char (cmd, '\n', 0);
r_cons_printf ("%s\n", cmd);
R_FREE (mflags);
free (cmd);
}
} else if (IS_MODE_JSON (mode)) {
if (c->super) {
r_cons_printf ("%s{\"classname\":\"%s\",\"addr\":%"PFMT64d",\"index\":%d,\"super\":\"%s\",\"methods\":[",
iter->p ? "," : "", c->name, c->addr,
c->index, c->super);
} else {
r_cons_printf ("%s{\"classname\":\"%s\",\"addr\":%"PFMT64d",\"index\":%d,\"methods\":[",
iter->p ? "," : "", c->name, c->addr,
c->index);
}
r_list_foreach (c->methods, iter2, sym) {
if (sym->method_flags) {
char *mflags = r_core_bin_method_flags_str (sym->method_flags, mode);
r_cons_printf ("%s{\"name\":\"%s\",\"flags\":%s,\"addr\":%"PFMT64d"}",
iter2->p? ",": "", sym->name, mflags, sym->vaddr);
R_FREE (mflags);
} else {
r_cons_printf ("%s{\"name\":\"%s\",\"addr\":%"PFMT64d"}",
iter2->p? ",": "", sym->name, sym->vaddr);
}
}
r_cons_printf ("], \"fields\":[");
r_list_foreach (c->fields, iter3, f) {
if (f->flags) {
char *mflags = r_core_bin_method_flags_str (f->flags, mode);
r_cons_printf ("%s{\"name\":\"%s\",\"flags\":%s,\"addr\":%"PFMT64d"}",
iter3->p? ",": "", f->name, mflags, f->vaddr);
R_FREE (mflags);
} else {
r_cons_printf ("%s{\"name\":\"%s\",\"addr\":%"PFMT64d"}",
iter3->p? ",": "", f->name, f->vaddr);
}
}
r_cons_printf ("]}");
} else if (IS_MODE_CLASSDUMP (mode)) {
char *rp = NULL;
if (c) {
//TODO -> Print Superclass
r_cons_printf ("@interface %s : \n{\n", c->name);
r_list_foreach (c->fields, iter2, f) {
if (f->name && r_regex_match ("ivar","e", f->name)) {
r_cons_printf (" %s %s\n", f->type, f->name);
}
}
r_cons_printf ("}\n");
r_list_foreach (c->methods, iter3, sym) {
if (sym->rtype && sym->rtype[0] != '@') {
rp = get_rp (sym->rtype);
r_cons_printf ("%s (%s) %s\n",
strncmp (sym->type, R_BIN_TYPE_METH_STR, 4)? "+": "-",
rp, sym->dname? sym->dname: sym->name);
}
}
r_cons_printf ("@end\n");
}
} else {
int m = 0;
r_cons_printf ("0x%08"PFMT64x" [0x%08"PFMT64x" - 0x%08"PFMT64x"] (sz %"PFMT64d") class %d %s",
c->addr, at_min, at_max, (at_max - at_min), c->index, c->name);
if (c->super) {
r_cons_printf (" super: %s\n", c->super);
} else {
r_cons_newline ();
}
r_list_foreach (c->methods, iter2, sym) {
char *mflags = r_core_bin_method_flags_str (sym->method_flags, mode);
r_cons_printf ("0x%08"PFMT64x" method %d %s %s\n",
sym->vaddr, m, mflags, sym->dname? sym->dname: sym->name);
R_FREE (mflags);
m++;
}
}
free (name);
}
if (IS_MODE_JSON (mode)) {
r_cons_print ("]");
}
return true;
}
static int bin_size(RCore *r, int mode) {
ut64 size = r_bin_get_size (r->bin);
if (IS_MODE_SIMPLE (mode) || IS_MODE_JSON (mode)) {
r_cons_printf ("%"PFMT64u"\n", size);
} else if (IS_MODE_RAD (mode)) {
r_cons_printf ("f bin_size @ %"PFMT64u"\n", size);
} else if (IS_MODE_SET (mode)) {
r_core_cmdf (r, "f bin_size @ %"PFMT64u"\n", size);
} else {
r_cons_printf ("%"PFMT64u"\n", size);
}
return true;
}
static int bin_libs(RCore *r, int mode) {
RList *libs;
RListIter *iter;
char* lib;
int i = 0;
if (!(libs = r_bin_get_libs (r->bin))) {
return false;
}
if (IS_MODE_JSON (mode)) {
r_cons_print ("[");
} else if (IS_MODE_NORMAL (mode)) {
r_cons_println ("[Linked libraries]");
}
r_list_foreach (libs, iter, lib) {
if (IS_MODE_SET (mode)) {
// Nothing to set.
// TODO: load libraries with iomaps?
} else if (IS_MODE_RAD (mode)) {
r_cons_printf ("CCa entry0 %s\n", lib);
} else if (IS_MODE_JSON (mode)) {
r_cons_printf ("%s\"%s\"", iter->p ? "," : "", lib);
} else {
// simple and normal print mode
r_cons_println (lib);
}
i++;
}
if (IS_MODE_JSON (mode)) {
r_cons_print ("]");
} else if (IS_MODE_NORMAL (mode)) {
if (i == 1) {
r_cons_printf ("\n%i library\n", i);
} else {
r_cons_printf ("\n%i libraries\n", i);
}
}
return true;
}
static void bin_mem_print(RList *mems, int perms, int depth, int mode) {
RBinMem *mem;
RListIter *iter;
if (!mems) {
return;
}
r_list_foreach (mems, iter, mem) {
if (IS_MODE_JSON (mode)) {
r_cons_printf ("{\"name\":\"%s\",\"size\":%d,\"address\":%d,"
"\"flags\":\"%s\"}", mem->name, mem->size,
mem->addr, r_str_rwx_i (mem->perms & perms));
} else if (IS_MODE_SIMPLE (mode)) {
r_cons_printf ("0x%08"PFMT64x"\n", mem->addr);
} else {
r_cons_printf ("0x%08"PFMT64x" +0x%04x %s %*s%-*s\n",
mem->addr, mem->size, r_str_rwx_i (mem->perms & perms),
depth, "", 20-depth, mem->name);
}
if (mem->mirrors) {
if (IS_MODE_JSON (mode)) {
r_cons_printf (",");
}
bin_mem_print (mem->mirrors, mem->perms & perms, depth + 1, mode);
}
if (IS_MODE_JSON (mode)) {
if (iter->n) {
r_cons_printf (",");
}
}
}
}
static int bin_mem(RCore *r, int mode) {
RList *mem = NULL;
if (!r) {
return false;
}
if (!IS_MODE_JSON (mode)) {
if (!(IS_MODE_RAD (mode) || IS_MODE_SET (mode))) {
r_cons_println ("[Memory]\n");
}
}
if (!(mem = r_bin_get_mem (r->bin))) {
if (IS_MODE_JSON (mode)) {
r_cons_print("[]");
}
return false;
}
if (IS_MODE_JSON (mode)) {
r_cons_print ("[");
bin_mem_print (mem, 7, 0, R_MODE_JSON);
r_cons_println ("]");
return true;
} else if (!(IS_MODE_RAD (mode) || IS_MODE_SET (mode))) {
bin_mem_print (mem, 7, 0, mode);
}
return true;
}
static void bin_pe_versioninfo(RCore *r, int mode) {
Sdb *sdb = NULL;
int num_version = 0;
int num_stringtable = 0;
int num_string = 0;
const char *format_version = "bin/cur/info/vs_version_info/VS_VERSIONINFO%d";
const char *format_stringtable = "%s/string_file_info/stringtable%d";
const char *format_string = "%s/string%d";
if (!IS_MODE_JSON (mode)) {
r_cons_printf ("=== VS_VERSIONINFO ===\n\n");
}
bool firstit_dowhile = true;
do {
char *path_version = sdb_fmt (format_version, num_version);
if (!(sdb = sdb_ns_path (r->sdb, path_version, 0))) {
break;
}
if (!firstit_dowhile && IS_MODE_JSON (mode)) {
r_cons_printf (",");
}
if (IS_MODE_JSON (mode)) {
r_cons_printf ("{\"VS_FIXEDFILEINFO\":{");
} else {
r_cons_printf ("# VS_FIXEDFILEINFO\n\n");
}
const char *path_fixedfileinfo = sdb_fmt ("%s/fixed_file_info", path_version);
if (!(sdb = sdb_ns_path (r->sdb, path_fixedfileinfo, 0))) {
r_cons_printf ("}");
break;
}
if (IS_MODE_JSON (mode)) {
r_cons_printf ("\"Signature\":%"PFMT64u",", sdb_num_get (sdb, "Signature", 0));
r_cons_printf ("\"StrucVersion\":%"PFMT64u",", sdb_num_get (sdb, "StrucVersion", 0));
r_cons_printf ("\"FileVersion\":\"%"PFMT64d".%"PFMT64d".%"PFMT64d".%"PFMT64d"\",",
sdb_num_get (sdb, "FileVersionMS", 0) >> 16,
sdb_num_get (sdb, "FileVersionMS", 0) & 0xFFFF,
sdb_num_get (sdb, "FileVersionLS", 0) >> 16,
sdb_num_get (sdb, "FileVersionLS", 0) & 0xFFFF);
r_cons_printf ("\"ProductVersion\":\"%"PFMT64d".%"PFMT64d".%"PFMT64d".%"PFMT64d"\",",
sdb_num_get (sdb, "ProductVersionMS", 0) >> 16,
sdb_num_get (sdb, "ProductVersionMS", 0) & 0xFFFF,
sdb_num_get (sdb, "ProductVersionLS", 0) >> 16,
sdb_num_get (sdb, "ProductVersionLS", 0) & 0xFFFF);
r_cons_printf ("\"FileFlagsMask\":%"PFMT64u",", sdb_num_get (sdb, "FileFlagsMask", 0));
r_cons_printf ("\"FileFlags\":%"PFMT64u",", sdb_num_get (sdb, "FileFlags", 0));
r_cons_printf ("\"FileOS\":%"PFMT64u",", sdb_num_get (sdb, "FileOS", 0));
r_cons_printf ("\"FileType\":%"PFMT64u",", sdb_num_get (sdb, "FileType", 0));
r_cons_printf ("\"FileSubType\":%"PFMT64u, sdb_num_get (sdb, "FileSubType", 0));
r_cons_printf ("},");
} else {
r_cons_printf (" Signature: 0x%"PFMT64x"\n", sdb_num_get (sdb, "Signature", 0));
r_cons_printf (" StrucVersion: 0x%"PFMT64x"\n", sdb_num_get (sdb, "StrucVersion", 0));
r_cons_printf (" FileVersion: %"PFMT64d".%"PFMT64d".%"PFMT64d".%"PFMT64d"\n",
sdb_num_get (sdb, "FileVersionMS", 0) >> 16,
sdb_num_get (sdb, "FileVersionMS", 0) & 0xFFFF,
sdb_num_get (sdb, "FileVersionLS", 0) >> 16,
sdb_num_get (sdb, "FileVersionLS", 0) & 0xFFFF);
r_cons_printf (" ProductVersion: %"PFMT64d".%"PFMT64d".%"PFMT64d".%"PFMT64d"\n",
sdb_num_get (sdb, "ProductVersionMS", 0) >> 16,
sdb_num_get (sdb, "ProductVersionMS", 0) & 0xFFFF,
sdb_num_get (sdb, "ProductVersionLS", 0) >> 16,
sdb_num_get (sdb, "ProductVersionLS", 0) & 0xFFFF);
r_cons_printf (" FileFlagsMask: 0x%"PFMT64x"\n", sdb_num_get (sdb, "FileFlagsMask", 0));
r_cons_printf (" FileFlags: 0x%"PFMT64x"\n", sdb_num_get (sdb, "FileFlags", 0));
r_cons_printf (" FileOS: 0x%"PFMT64x"\n", sdb_num_get (sdb, "FileOS", 0));
r_cons_printf (" FileType: 0x%"PFMT64x"\n", sdb_num_get (sdb, "FileType", 0));
r_cons_printf (" FileSubType: 0x%"PFMT64x"\n", sdb_num_get (sdb, "FileSubType", 0));
r_cons_newline ();
}
#if 0
r_cons_printf (" FileDate: %d.%d.%d.%d\n",
sdb_num_get (sdb, "FileDateMS", 0) >> 16,
sdb_num_get (sdb, "FileDateMS", 0) & 0xFFFF,
sdb_num_get (sdb, "FileDateLS", 0) >> 16,
sdb_num_get (sdb, "FileDateLS", 0) & 0xFFFF);
#endif
if (IS_MODE_JSON (mode)) {
r_cons_printf ("\"StringTable\":{");
} else {
r_cons_printf ("# StringTable\n\n");
}
for (num_stringtable = 0; sdb; num_stringtable++) {
char *path_stringtable = r_str_newf (format_stringtable, path_version, num_stringtable);
sdb = sdb_ns_path (r->sdb, path_stringtable, 0);
bool firstit_for = true;
for (num_string = 0; sdb; num_string++) {
char *path_string = r_str_newf (format_string, path_stringtable, num_string);
sdb = sdb_ns_path (r->sdb, path_string, 0);
if (sdb) {
if (!firstit_for && IS_MODE_JSON (mode)) { r_cons_printf (","); }
int lenkey = 0;
int lenval = 0;
ut8 *key_utf16 = sdb_decode (sdb_const_get (sdb, "key", 0), &lenkey);
ut8 *val_utf16 = sdb_decode (sdb_const_get (sdb, "value", 0), &lenval);
ut8 *key_utf8 = calloc (lenkey * 2, 1);
ut8 *val_utf8 = calloc (lenval * 2, 1);
if (r_str_utf16_to_utf8 (key_utf8, lenkey * 2, key_utf16, lenkey, true) < 0
|| r_str_utf16_to_utf8 (val_utf8, lenval * 2, val_utf16, lenval, true) < 0) {
eprintf ("Warning: Cannot decode utf16 to utf8\n");
} else if (IS_MODE_JSON (mode)) {
char *escaped_key_utf8 = r_str_escape ((char*)key_utf8);
char *escaped_val_utf8 = r_str_escape ((char*)val_utf8);
r_cons_printf ("\"%s\":\"%s\"", escaped_key_utf8, escaped_val_utf8);
free (escaped_key_utf8);
free (escaped_val_utf8);
} else {
r_cons_printf (" %s: %s\n", (char*)key_utf8, (char*)val_utf8);
}
free (key_utf8);
free (val_utf8);
free (key_utf16);
free (val_utf16);
}
firstit_for = false;
free (path_string);
}
free (path_stringtable);
}
if (IS_MODE_JSON (mode)) {
r_cons_printf ("}}");
}
num_version++;
firstit_dowhile = false;
} while (sdb);
}
static void bin_elf_versioninfo(RCore *r, int mode) {
const char *format = "bin/cur/info/versioninfo/%s%d";
int num_versym;
int num_verneed = 0;
int num_version = 0;
Sdb *sdb = NULL;
const char *oValue = NULL;
bool firstit_for_versym = true;
if (IS_MODE_JSON (mode)) {
r_cons_printf ("{\"versym\":[");
}
for (num_versym = 0;; num_versym++) {
const char *versym_path = sdb_fmt (format, "versym", num_versym);
if (!(sdb = sdb_ns_path (r->sdb, versym_path, 0))) {
break;
}
ut64 addr = sdb_num_get (sdb, "addr", 0);
ut64 offset = sdb_num_get (sdb, "offset", 0);
ut64 link = sdb_num_get (sdb, "link", 0);
ut64 num_entries = sdb_num_get (sdb, "num_entries", 0);
const char *section_name = sdb_const_get (sdb, "section_name", 0);
const char *link_section_name = sdb_const_get (sdb, "link_section_name", 0);
if (IS_MODE_JSON (mode)) {
if (!firstit_for_versym) { r_cons_printf (","); }
r_cons_printf ("{\"section_name\":\"%s\",\"address\":%"PFMT64u",\"offset\":%"PFMT64u",",
section_name, (ut64)addr, (ut64)offset);
r_cons_printf ("\"link\":%"PFMT64u",\"link_section_name\":\"%s\",\"entries\":[",
(ut32)link, link_section_name);
} else {
r_cons_printf ("Version symbols section '%s' contains %"PFMT64u" entries:\n", section_name, num_entries);
r_cons_printf (" Addr: 0x%08"PFMT64x" Offset: 0x%08"PFMT64x" Link: %x (%s)\n",
(ut64)addr, (ut64)offset, (ut32)link, link_section_name);
}
int i;
for (i = 0; i < num_entries; i++) {
const char *key = sdb_fmt ("entry%d", i);
const char *value = sdb_const_get (sdb, key, 0);
if (value) {
if (oValue && !strcmp (value, oValue)) {
continue;
}
if (IS_MODE_JSON (mode)) {
if (i > 0) { r_cons_printf (","); }
char *escaped_value = r_str_escape (value);
r_cons_printf ("{\"idx\":%"PFMT64u",\"value\":\"%s\"}",
(ut64) i, escaped_value);
free (escaped_value);
} else {
r_cons_printf (" 0x%08"PFMT64x": ", (ut64) i);
r_cons_printf ("%s\n", value);
}
oValue = value;
}
}
if (IS_MODE_JSON (mode)) {
r_cons_printf ("]}");
} else {
r_cons_printf ("\n\n");
}
firstit_for_versym = false;
}
if (IS_MODE_JSON (mode)) {
r_cons_printf ("],\"verneed\":[");
}
bool firstit_dowhile_verneed = true;
do {
char *verneed_path = r_str_newf (format, "verneed", num_verneed++);
if (!(sdb = sdb_ns_path (r->sdb, verneed_path, 0))) {
break;
}
if (IS_MODE_JSON (mode)) {
if (!firstit_dowhile_verneed) {
r_cons_printf (",");
}
r_cons_printf ("{\"section_name\":\"%s\",\"address\":%"PFMT64u",\"offset\":%"PFMT64u",",
sdb_const_get (sdb, "section_name", 0), sdb_num_get (sdb, "addr", 0), sdb_num_get (sdb, "offset", 0));
r_cons_printf ("\"link\":%"PFMT64u",\"link_section_name\":\"%s\",\"entries\":[",
sdb_num_get (sdb, "link", 0), sdb_const_get (sdb, "link_section_name", 0));
} else {
r_cons_printf ("Version need section '%s' contains %d entries:\n",
sdb_const_get (sdb, "section_name", 0), (int)sdb_num_get (sdb, "num_entries", 0));
r_cons_printf (" Addr: 0x%08"PFMT64x, sdb_num_get (sdb, "addr", 0));
r_cons_printf (" Offset: 0x%08"PFMT64x" Link to section: %"PFMT64d" (%s)\n",
sdb_num_get (sdb, "offset", 0), sdb_num_get (sdb, "link", 0),
sdb_const_get (sdb, "link_section_name", 0));
}
bool firstit_for_verneed = true;
for (num_version = 0;; num_version++) {
const char *filename = NULL;
int num_vernaux = 0;
char *path_version = sdb_fmt ("%s/version%d", verneed_path, num_version);
if (!(sdb = sdb_ns_path (r->sdb, path_version, 0))) {
break;
}
if (IS_MODE_JSON (mode)) {
if (!firstit_for_verneed) { r_cons_printf (","); }
r_cons_printf ("{\"idx\":%"PFMT64u",\"vn_version\":%d,",
sdb_num_get (sdb, "idx", 0), (int)sdb_num_get (sdb, "vn_version", 0));
} else {
r_cons_printf (" 0x%08"PFMT64x": Version: %d",
sdb_num_get (sdb, "idx", 0), (int)sdb_num_get (sdb, "vn_version", 0));
}
if ((filename = sdb_const_get (sdb, "file_name", 0))) {
if (IS_MODE_JSON (mode)) {
char *escaped_filename = r_str_escape (filename);
r_cons_printf ("\"file_name\":\"%s\",", escaped_filename);
free (escaped_filename);
} else {
r_cons_printf (" File: %s", filename);
}
}
if (IS_MODE_JSON (mode)) {
r_cons_printf ("\"cnt\":%d,", (int)sdb_num_get (sdb, "cnt", 0));
} else {
r_cons_printf (" Cnt: %d\n", (int)sdb_num_get (sdb, "cnt", 0));
}
if (IS_MODE_JSON (mode)) {
r_cons_printf ("\"vernaux\":[");
}
bool firstit_dowhile_vernaux = true;
do {
const char *path_vernaux = sdb_fmt ("%s/vernaux%d", path_version, num_vernaux++);
if (!(sdb = sdb_ns_path (r->sdb, path_vernaux, 0))) {
break;
}
if (IS_MODE_JSON (mode)) {
if (!firstit_dowhile_vernaux) { r_cons_printf (","); }
r_cons_printf ("{\"idx\":%"PFMT64u",\"name\":\"%s\",",
sdb_num_get (sdb, "idx", 0), sdb_const_get (sdb, "name", 0));
r_cons_printf ("\"flags\":\"%s\",\"version\":%d}",
sdb_const_get (sdb, "flags", 0), (int)sdb_num_get (sdb, "version", 0));
} else {
r_cons_printf (" 0x%08"PFMT64x": Name: %s",
sdb_num_get (sdb, "idx", 0), sdb_const_get (sdb, "name", 0));
r_cons_printf (" Flags: %s Version: %d\n",
sdb_const_get (sdb, "flags", 0), (int)sdb_num_get (sdb, "version", 0));
}
firstit_dowhile_vernaux = false;
} while (sdb);
if (IS_MODE_JSON (mode)) {
r_cons_printf ("]}");
}
firstit_for_verneed = false;
}
if (IS_MODE_JSON (mode)) {
r_cons_printf ("]}");
}
firstit_dowhile_verneed = false;
free (verneed_path);
} while (sdb);
if (IS_MODE_JSON (mode)) {
r_cons_printf ("]}");
}
}
static void bin_mach0_versioninfo(RCore *r) {
/* TODO */
}
static void bin_pe_resources(RCore *r, int mode) {
Sdb *sdb = NULL;
int index = 0;
PJ *pj = NULL;
const char *pe_path = "bin/cur/info/pe_resource";
if (!(sdb = sdb_ns_path (r->sdb, pe_path, 0))) {
return;
}
if (IS_MODE_SET (mode)) {
r_flag_space_set (r->flags, R_FLAGS_FS_RESOURCES);
} else if (IS_MODE_RAD (mode)) {
r_cons_printf ("fs resources\n");
} else if (IS_MODE_JSON (mode)) {
pj = pj_new ();
pj_a (pj);
}
while (true) {
const char *timestrKey = sdb_fmt ("resource.%d.timestr", index);
const char *vaddrKey = sdb_fmt ("resource.%d.vaddr", index);
const char *sizeKey = sdb_fmt ("resource.%d.size", index);
const char *typeKey = sdb_fmt ("resource.%d.type", index);
const char *languageKey = sdb_fmt ("resource.%d.language", index);
const char *nameKey = sdb_fmt ("resource.%d.name", index);
char *timestr = sdb_get (sdb, timestrKey, 0);
if (!timestr) {
break;
}
ut64 vaddr = sdb_num_get (sdb, vaddrKey, 0);
int size = (int)sdb_num_get (sdb, sizeKey, 0);
char *name = sdb_get (sdb, nameKey, 0);
char *type = sdb_get (sdb, typeKey, 0);
char *lang = sdb_get (sdb, languageKey, 0);
if (IS_MODE_SET (mode)) {
const char *name = sdb_fmt ("resource.%d", index);
r_flag_set (r->flags, name, vaddr, size);
} else if (IS_MODE_RAD (mode)) {
r_cons_printf ("f resource.%d %d 0x%08"PFMT32x"\n", index, size, vaddr);
} else if (IS_MODE_JSON (mode)) {
pj_o (pj);
pj_ks (pj, "name", name);
pj_ki (pj, "index", index);
pj_ks (pj, "type", type);
pj_kn (pj, "vaddr", vaddr);
pj_ki (pj, "size", size);
pj_ks (pj, "lang", lang);
pj_ks (pj, "timestamp", timestr);
pj_end (pj);
} else {
char humansz[8];
r_num_units (humansz, sizeof (humansz), size);
r_cons_printf ("Resource %d\n", index);
r_cons_printf (" name: %s\n", name);
r_cons_printf (" timestamp: %s\n", timestr);
r_cons_printf (" vaddr: 0x%08"PFMT64x"\n", vaddr);
r_cons_printf (" size: %s\n", humansz);
r_cons_printf (" type: %s\n", type);
r_cons_printf (" language: %s\n", lang);
}
R_FREE (timestr);
R_FREE (name);
R_FREE (type);
R_FREE (lang)
index++;
}
if (IS_MODE_JSON (mode)) {
pj_end (pj);
r_cons_printf ("%s\n", pj_string (pj));
pj_free (pj);
} else if (IS_MODE_RAD (mode)) {
r_cons_printf ("fs *");
}
}
static void bin_no_resources(RCore *r, int mode) {
if (IS_MODE_JSON (mode)) {
r_cons_printf ("[]");
}
}
static int bin_resources(RCore *r, int mode) {
const RBinInfo *info = r_bin_get_info (r->bin);
if (!info || !info->rclass) {
return false;
}
if (!strncmp ("pe", info->rclass, 2)) {
bin_pe_resources (r, mode);
} else {
bin_no_resources (r, mode);
}
return true;
}
static int bin_versioninfo(RCore *r, int mode) {
const RBinInfo *info = r_bin_get_info (r->bin);
if (!info || !info->rclass) {
return false;
}
if (!strncmp ("pe", info->rclass, 2)) {
bin_pe_versioninfo (r, mode);
} else if (!strncmp ("elf", info->rclass, 3)) {
bin_elf_versioninfo (r, mode);
} else if (!strncmp ("mach0", info->rclass, 5)) {
bin_mach0_versioninfo (r);
} else {
r_cons_println ("Unknown format");
return false;
}
return true;
}
static int bin_signature(RCore *r, int mode) {
RBinFile *cur = r_bin_cur (r->bin);
RBinPlugin *plg = r_bin_file_cur_plugin (cur);
if (plg && plg->signature) {
const char *signature = plg->signature (cur, IS_MODE_JSON (mode));
r_cons_println (signature);
free ((char*) signature);
return true;
}
return false;
}
R_API void r_core_bin_export_info_rad(RCore *core) {
Sdb *db = NULL;
char *flagname = NULL, *offset = NULL;
RBinFile *bf = r_core_bin_cur (core);
if (!bf) {
return;
}
db = sdb_ns (bf->sdb, "info", 0);;
if (db) {
SdbListIter *iter;
SdbKv *kv;
r_cons_printf ("fs format\n");
// iterate over all keys
SdbList *ls = sdb_foreach_list (db, false);
ls_foreach (ls, iter, kv) {
char *k = sdbkv_key (kv);
char *v = sdbkv_value (kv);
char *dup = strdup (k);
//printf ("?e (%s) (%s)\n", k, v);
if ((flagname = strstr (dup, ".offset"))) {
*flagname = 0;
flagname = dup;
r_cons_printf ("f %s @ %s\n", flagname, v);
free (offset);
offset = strdup (v);
}
if ((flagname = strstr (dup, ".cparse"))) {
r_cons_printf ("\"td %s\"\n", v);
}
free (dup);
}
R_FREE (offset);
ls_foreach (ls, iter, kv) {
char *k = sdbkv_key (kv);
char *v = sdbkv_value (kv);
char *dup = strdup (k);
if ((flagname = strstr (dup, ".format"))) {
*flagname = 0;
if (!offset) {
offset = strdup ("0");
}
flagname = dup;
r_cons_printf ("pf.%s %s\n", flagname, v);
}
free (dup);
}
ls_foreach (ls, iter, kv) {
char *k = sdbkv_key (kv);
char *v = sdbkv_value (kv);
char *dup = strdup (k);
if ((flagname = strstr (dup, ".format"))) {
*flagname = 0;
if (!offset) {
offset = strdup ("0");
}
flagname = dup;
int fmtsize = r_print_format_struct_size (v, core->print, 0, 0);
char *offset_key = r_str_newf ("%s.offset", flagname);
const char *off = sdb_const_get (db, offset_key, 0);
free (offset_key);
if (off) {
r_cons_printf ("Cf %d %s @ %s\n", fmtsize, v, off);
}
}
if ((flagname = strstr (dup, ".size"))) {
*flagname = 0;
flagname = dup;
r_cons_printf ("fl %s %s\n", flagname, v);
}
free (dup);
}
free (offset);
}
}
static int bin_header(RCore *r, int mode) {
RBinFile *cur = r_bin_cur (r->bin);
RBinPlugin *plg = r_bin_file_cur_plugin (cur);
if (plg && plg->header) {
plg->header (cur);
return true;
}
return false;
}
static int bin_hashes(RCore *r, int mode) {
ut64 lim = r_config_get_i (r->config, "cfg.hashlimit");
RIODesc *iod = r_io_desc_get (r->io, r->file->fd);
if (iod) {
// recompute again
r_bin_file_hash (r->bin, lim, iod->name);
char *hashes = r->bin->cur->o->info->hashes;
if (IS_MODE_JSON (mode)) {
PJ *pj = pj_new ();
if (!pj) {
eprintf ("bin_hashes: pj_new failed\n");
return false;
}
pj_o (pj);
pj_ks (pj, "values", hashes);
pj_end (pj);
r_cons_printf ("%s", pj_string (pj));
pj_free (pj);
} else {
r_cons_printf ("%s\n", hashes);
}
return true;
}
return false;
}
R_API int r_core_bin_info(RCore *core, int action, int mode, int va, RCoreBinFilter *filter, const char *chksum) {
int ret = true;
const char *name = NULL;
ut64 at = 0, loadaddr = r_bin_get_laddr (core->bin);
if (filter && filter->offset) {
at = filter->offset;
}
if (filter && filter->name) {
name = filter->name;
}
// use our internal values for va
va = va ? VA_TRUE : VA_FALSE;
#if 0
if (r_config_get_i (core->config, "anal.strings")) {
r_core_cmd0 (core, "aar");
}
#endif
if ((action & R_CORE_BIN_ACC_STRINGS)) {
ret &= bin_strings (core, mode, va);
}
if ((action & R_CORE_BIN_ACC_RAW_STRINGS)) {
ret &= bin_raw_strings (core, mode, va);
}
if ((action & R_CORE_BIN_ACC_INFO)) {
ret &= bin_info (core, mode, loadaddr);
}
if ((action & R_CORE_BIN_ACC_MAIN)) {
ret &= bin_main (core, mode, va);
}
if ((action & R_CORE_BIN_ACC_DWARF)) {
ret &= bin_dwarf (core, mode);
}
if ((action & R_CORE_BIN_ACC_PDB)) {
ret &= bin_pdb (core, mode);
}
if ((action & R_CORE_BIN_ACC_SOURCE)) {
ret &= bin_source (core, mode);
}
if ((action & R_CORE_BIN_ACC_ENTRIES)) {
ret &= bin_entry (core, mode, loadaddr, va, false);
}
if ((action & R_CORE_BIN_ACC_INITFINI)) {
ret &= bin_entry (core, mode, loadaddr, va, true);
}
if ((action & R_CORE_BIN_ACC_SECTIONS)) {
ret &= bin_sections (core, mode, loadaddr, va, at, name, chksum, false);
}
if ((action & R_CORE_BIN_ACC_SEGMENTS)) {
ret &= bin_sections (core, mode, loadaddr, va, at, name, chksum, true);
}
if (r_config_get_i (core->config, "bin.relocs")) {
if ((action & R_CORE_BIN_ACC_RELOCS)) {
ret &= bin_relocs (core, mode, va);
}
}
if ((action & R_CORE_BIN_ACC_LIBS)) {
ret &= bin_libs (core, mode);
}
if ((action & R_CORE_BIN_ACC_IMPORTS)) { // 5s
ret &= bin_imports (core, mode, va, name);
}
if ((action & R_CORE_BIN_ACC_EXPORTS)) {
ret &= bin_symbols (core, mode, loadaddr, va, at, name, true, chksum);
}
if ((action & R_CORE_BIN_ACC_SYMBOLS)) { // 6s
ret &= bin_symbols (core, mode, loadaddr, va, at, name, false, chksum);
}
if ((action & R_CORE_BIN_ACC_CLASSES)) { // 6s
ret &= bin_classes (core, mode);
}
if ((action & R_CORE_BIN_ACC_SIZE)) {
ret &= bin_size (core, mode);
}
if ((action & R_CORE_BIN_ACC_MEM)) {
ret &= bin_mem (core, mode);
}
if ((action & R_CORE_BIN_ACC_VERSIONINFO)) {
ret &= bin_versioninfo (core, mode);
}
if ((action & R_CORE_BIN_ACC_RESOURCES)) {
ret &= bin_resources (core, mode);
}
if ((action & R_CORE_BIN_ACC_SIGNATURE)) {
ret &= bin_signature (core, mode);
}
if ((action & R_CORE_BIN_ACC_FIELDS)) {
if (IS_MODE_SIMPLE (mode)) {
if ((action & R_CORE_BIN_ACC_HEADER) || action & R_CORE_BIN_ACC_FIELDS) {
/* ignore mode, just for quiet/simple here */
ret &= bin_fields (core, 0, va);
}
} else {
if (IS_MODE_NORMAL (mode)) {
ret &= bin_header (core, mode);
} else {
if ((action & R_CORE_BIN_ACC_HEADER) || action & R_CORE_BIN_ACC_FIELDS) {
ret &= bin_fields (core, mode, va);
}
}
}
}
if ((action & R_CORE_BIN_ACC_HASHES)) {
ret &= bin_hashes (core, mode);
}
return ret;
}
R_API int r_core_bin_set_arch_bits(RCore *r, const char *name, const char * arch, ut16 bits) {
int fd = r_io_fd_get_current (r->io);
RIODesc *desc = r_io_desc_get (r->io, fd);
RBinFile *curfile, *binfile = NULL;
if (!name) {
if (!desc || !desc->name) {
return false;
}
name = desc->name;
}
/* Check if the arch name is a valid name */
if (!r_asm_is_valid (r->assembler, arch)) {
return false;
}
/* Find a file with the requested name/arch/bits */
binfile = r_bin_file_find_by_arch_bits (r->bin, arch, bits);
if (!binfile) {
return false;
}
if (!r_bin_use_arch (r->bin, arch, bits, name)) {
return false;
}
curfile = r_bin_cur (r->bin);
//set env if the binfile changed or we are dealing with xtr
if (curfile != binfile || binfile->curxtr) {
r_core_bin_set_cur (r, binfile);
return r_core_bin_set_env (r, binfile);
}
return true;
}
R_API int r_core_bin_update_arch_bits(RCore *r) {
RBinFile *binfile = NULL;
const char *name = NULL, *arch = NULL;
ut16 bits = 0;
if (!r) {
return 0;
}
if (r->assembler) {
bits = r->assembler->bits;
if (r->assembler->cur) {
arch = r->assembler->cur->arch;
}
}
binfile = r_core_bin_cur (r);
name = binfile ? binfile->file : NULL;
if (binfile && binfile->curxtr) {
r_anal_hint_clear (r->anal);
}
return r_core_bin_set_arch_bits (r, name, arch, bits);
}
R_API int r_core_bin_raise(RCore *core, ut32 binfile_idx, ut32 binobj_idx) {
RBin *bin = core->bin;
RBinFile *binfile = NULL;
if (binfile_idx == UT32_MAX && binobj_idx == UT32_MAX) {
return false;
}
if (!r_bin_select_by_ids (bin, binfile_idx, binobj_idx)) {
return false;
}
binfile = r_core_bin_cur (core);
if (binfile) {
r_io_use_fd (core->io, binfile->fd);
}
// it should be 0 to use r_io_use_fd in r_core_block_read
core->switch_file_view = 0;
return binfile && r_core_bin_set_env (core, binfile) && r_core_block_read (core);
}
R_API bool r_core_bin_delete(RCore *core, ut32 binfile_idx, ut32 binobj_idx) {
if (binfile_idx == UT32_MAX && binobj_idx == UT32_MAX) {
return false;
}
if (!r_bin_object_delete (core->bin, binfile_idx, binobj_idx)) {
return false;
}
RBinFile *binfile = r_core_bin_cur (core);
if (binfile) {
r_io_use_fd (core->io, binfile->fd);
}
core->switch_file_view = 0;
return binfile && r_core_bin_set_env (core, binfile) && r_core_block_read (core);
}
static int r_core_bin_file_print(RCore *core, RBinFile *binfile, int mode) {
RListIter *iter;
RBinObject *obj;
const char *name = binfile ? binfile->file : NULL;
(void)r_bin_get_info (core->bin); // XXX is this necssary for proper iniitialization
ut32 id = binfile ? binfile->id : 0;
ut32 fd = binfile ? binfile->fd : 0;
ut32 bin_sz = binfile ? binfile->size : 0;
// TODO: handle mode to print in json and r2 commands
if (!binfile) {
return false;
}
switch (mode) {
case '*':
r_list_foreach (binfile->objs, iter, obj) {
r_cons_printf ("oba 0x%08"PFMT64x" %s # %d\n", obj->boffset, name, obj->id);
}
break;
case 'q':
r_list_foreach (binfile->objs, iter, obj) {
r_cons_printf ("%d\n", obj->id);
}
break;
case 'j':
r_cons_printf ("{\"name\":\"%s\",\"fd\":%d,\"id\":%d,\"size\":%d,\"objs\":[",
name, fd, id, bin_sz);
r_list_foreach (binfile->objs, iter, obj) {
RBinInfo *info = obj->info;
ut8 bits = info ? info->bits : 0;
const char *arch = info ? info->arch : "unknown";
r_cons_printf ("{\"objid\":%d,\"arch\":\"%s\",\"bits\":%d,\"binoffset\":%"
PFMT64d",\"objsize\":%"PFMT64d"}",
obj->id, arch, bits, obj->boffset, obj->obj_size);
if (iter->n) {
r_cons_print (",");
}
}
r_cons_print ("]}");
break;
default:
r_list_foreach (binfile->objs, iter, obj) {
RBinInfo *info = obj->info;
ut8 bits = info ? info->bits : 0;
const char *arch = info ? info->arch : "unknown";
if (!arch) {
arch = r_config_get (core->config, "asm.arch");
}
r_cons_printf ("%4d %s-%d at:0x%08"PFMT64x" sz:%"PFMT64d" ",
obj->id, arch, bits, obj->boffset, obj->obj_size );
r_cons_printf ("fd:%d %s\n", fd, name);
}
break;
}
return true;
}
R_API int r_core_bin_list(RCore *core, int mode) {
// list all binfiles and there objects and there archs
int count = 0;
RListIter *iter;
RBinFile *binfile = NULL; //, *cur_bf = r_core_bin_cur (core) ;
RBin *bin = core->bin;
const RList *binfiles = bin ? bin->binfiles: NULL;
if (!binfiles) {
return false;
}
if (mode == 'j') {
r_cons_print ("[");
}
r_list_foreach (binfiles, iter, binfile) {
r_core_bin_file_print (core, binfile, mode);
if (iter->n && mode == 'j') {
r_cons_print (",");
}
}
if (mode == 'j') {
r_cons_println ("]");
}
//r_core_file_set_by_file (core, cur_cf);
//r_core_bin_bind (core, cur_bf);
return count;
}
R_API char *r_core_bin_method_flags_str(ut64 flags, int mode) {
char *str;
RStrBuf *buf;
int i, len = 0;
buf = r_strbuf_new ("");
if (IS_MODE_SET (mode) || IS_MODE_RAD (mode)) {
if (!flags) {
goto out;
}
for (i = 0; i < 64; i++) {
ut64 flag = flags & (1ULL << i);
if (flag) {
const char *flag_string = r_bin_get_meth_flag_string (flag, false);
if (flag_string) {
r_strbuf_appendf (buf, ".%s", flag_string);
}
}
}
} else if (IS_MODE_JSON (mode)) {
if (!flags) {
r_strbuf_append (buf, "[]");
goto out;
}
r_strbuf_append (buf, "[");
for (i = 0; i < 64; i++) {
ut64 flag = flags & (1ULL << i);
if (flag) {
const char *flag_string = r_bin_get_meth_flag_string (flag, false);
if (len != 0) {
r_strbuf_append (buf, ",");
}
if (flag_string) {
r_strbuf_appendf (buf, "\"%s\"", flag_string);
} else {
r_strbuf_appendf (buf, "\"0x%08"PFMT64x"\"", flag);
}
len++;
}
}
r_strbuf_append (buf, "]");
} else {
int pad_len = 4; //TODO: move to a config variable
if (!flags) {
goto padding;
}
for (i = 0; i < 64; i++) {
ut64 flag = flags & (1ULL << i);
if (flag) {
const char *flag_string = r_bin_get_meth_flag_string (flag, true);
if (flag_string) {
r_strbuf_append (buf, flag_string);
} else {
r_strbuf_append (buf, "?");
}
len++;
}
}
padding:
for ( ; len < pad_len; len++) {
r_strbuf_append (buf, " ");
}
}
out:
str = strdup (r_strbuf_get (buf));
r_strbuf_free (buf);
return str;
}