radare2/libr/bin/demangle.c
Jonathan Neuschäfer ecf6792318 Fix #2927 and random code cleanups
- asm_dcpu16: remove an obsolete comment
  It was obsoleted in 5285d1bdea.
- Indentation fixes
- fix a few typos
- remove "#define NEW_ESIL"
- move comment about r_bin_filter_name to the right place
- README.md: Add V810 to the list of supported architectures
- Also, de-duplicate LH5801
- Add attribution to randomart.c, fixes #2927
2015-07-12 19:20:36 +02:00

364 lines
8.5 KiB
C

/* radare - LGPL - Copyright 2011-2015 - pancake */
#include <r_bin.h>
#include <cxx/demangle.h>
//TODO: mangler_branch: remove?
#include "mangling/demangler.h"
R_API void r_bin_demangle_list(RBin *bin) {
const char *langs[] = { "cxx", "java", "objc", "swift", "dlang", "msvc", NULL };
RBinPlugin *plugin;
RListIter *it;
int i;
if (!bin) return;
for (i=0; langs[i]; i++) {
eprintf ("%s\n", langs[i]);
}
r_list_foreach (bin->plugins, it, plugin) {
if (plugin->demangle) {
eprintf ("%s\n", plugin->name);
}
}
}
R_API char *r_bin_demangle_plugin(RBin *bin, const char *name, const char *str) {
RBinPlugin *plugin;
RListIter *it;
if (!bin || !name || !str) return NULL;
r_list_foreach (bin->plugins, it, plugin) {
if (plugin->demangle) {
return plugin->demangle (str);
}
}
return NULL;
}
// http://code.google.com/p/smali/wiki/TypesMethodsAndFields
R_API char *r_bin_demangle_java(const char *str) {
const char *w = NULL;
int is_array = 0;
const char *ptr;
int is_ret = 0;
int wlen = 0;
RBuffer *buf;
int n = 0;
char *ret;
ptr = strchr (str, '(');
if (!ptr)
return NULL;
buf = r_buf_new ();
if (!buf) return NULL;
r_buf_append_bytes (buf, (const ut8*)str, (int)(size_t)(ptr-str));
r_buf_append_bytes (buf, (const ut8*)" (", 2);
while (*str) {
switch (*str) {
case ')':
is_ret = 1;
break;
case '[':
is_array = 1;
break;
case 'L':
str++;
ptr = strchr (str, ';');
if (ptr) {
w = str;
wlen = (int)(size_t)(ptr-str);
}
str = ptr;
break;
case 'I': w = "int"; wlen = 3; break;
case 'C': w = "char"; wlen = 4; break;
case 'B': w = "byte"; wlen = 4; break;
case 'V': w = "void"; wlen = 4; break;
case 'J': w = "long"; wlen = 4; break;
case 'F': w = "float"; wlen = 5; break;
case 'S': w = "short"; wlen = 5; break;
case 'D': w = "double"; wlen = 6; break;
case 'Z': w = "boolean"; wlen = 7; break;
}
if (w) {
if (is_ret) {
r_buf_prepend_bytes (buf, (const ut8*)" ", 1);
r_buf_prepend_bytes (buf, (const ut8*)w, wlen);
r_buf_append_bytes (buf, (const ut8*)")", 1);
break;
} else {
if (n++>0)
r_buf_append_bytes (buf, (const ut8*)", ", 2);
r_buf_append_bytes (buf, (const ut8*)w, wlen);
}
if (is_array) {
r_buf_append_bytes (buf, (const ut8*)"[]", 2);
is_array = 0;
}
}
w = NULL;
if (!str) break;
str++;
}
ret = r_buf_to_string (buf);
r_buf_free (buf);
return ret;
}
R_API char *r_bin_demangle_msvc(const char *str)
{
char *out = NULL;
SDemangler *mangler = 0;
create_demangler(&mangler);
if (init_demangler(mangler, (char *)str) == eDemanglerErrOK) {
mangler->demangle(mangler, &out/*demangled_name*/);
}
free_demangler(mangler);
return out;
}
R_API char *r_bin_demangle_cxx(const char *str) {
char *out;
// DMGL_TYPES | DMGL_PARAMS | DMGL_ANSI | DMGL_VERBOSE
// | DMGL_RET_POSTFIX | DMGL_TYPES;
int i;
#if WITH_GPL
int flags = DMGL_NO_OPTS;
#endif
const char *prefixes[] = {
"__symbol_stub1_",
"reloc.",
"sym.imp.",
"imp.",
NULL
};
if (str[0]==str[1] && *str=='_') {
str++;
} {
for (i=0; prefixes[i]; i++) {
int plen = strlen (prefixes[i]);
if (!strncmp (str, prefixes[i], plen)) {
str += plen;
break;
}
}
}
#if WITH_GPL
out = cplus_demangle_v3 (str, flags);
#else
/* TODO: implement a non-gpl alternative to c++v3 demangler */
out = NULL;
#endif
if (out) {
r_str_replace_char (out, ' ', 0);
}
return out;
}
R_API char *r_bin_demangle_objc(RBinFile *binfile, const char *sym) {
char *ret = NULL;
char *clas = NULL;
char *name = NULL;
char *args = NULL;
int i, nargs = 0;
const char *type = NULL;
/* classes */
if (!strncmp (sym, "_OBJC_Class_", 12)) {
ret = malloc (10+strlen (sym));
sprintf (ret, "class %s", sym+12);
if (binfile) r_bin_class_new (binfile, sym+12, NULL, R_BIN_CLASS_PUBLIC);
return ret;
} else
if (!strncmp (sym, "_OBJC_CLASS_$_", 14)) {
ret = malloc (10+strlen (sym));
sprintf (ret, "class %s", sym+14);
if (binfile) r_bin_class_new (binfile, sym+14, NULL, R_BIN_CLASS_PUBLIC);
return ret;
} else
/* fields */
if (!strncmp (sym, "_OBJC_IVAR_$_", 13)) {
char *p;
clas = strdup (sym+13);
p = strchr (clas, '.');
type = "field";
if (p) {
*p = 0;
name = strdup (p+1);
} else name = NULL;
if (binfile) r_bin_class_add_field (binfile, clas, name);
} else
/* methods */
if (sym[1] == '[') { // apple style
if (sym[0] == '+') type = "static";
else if (sym[0] == '-') type = "public";
if (type) {
clas = strdup (sym+2);
name = strchr (clas, ' ');
if (name) {
*name++ = 0;
name = strdup (name);
if (!name){
free (clas);
return NULL;
}
for (i=0; name[i]; i++) {
if (name[i]==']') {
name[i] = 0;
} else
if (name[i]==':') {
nargs++;
name[i] = 0;
}
}
}
}
} else
if (sym[0]=='_' && sym[2]=='_') { // gnu style
clas = strdup (sym+3);
args = strstr (clas, "__");
if (!args) {
free (clas);
return NULL;
}
*args = 0;
name = strdup (args+2);
if (!name){
free (args);
free (clas);
return NULL;
}
args = NULL;
for (i=0; name[i]; i++) {
if (name[i]=='_') {
name[i] = 0;
nargs++;
}
}
if (sym[1] == 'i') type = "public";
else if (sym[1] == 'c') type = "static";
}
if (type) {
if (!strcmp (type, "field")) {
int namelen = name?strlen (name):0;
ret = malloc (strlen (clas)+namelen+32);
if (ret) sprintf (ret, "field int %s::%s", clas, name);
} else {
if (nargs) {
const char *arg = "int";
args = malloc (((strlen (arg)+4) * nargs)+1);
args[0] = 0;
for(i=0;i<nargs; i++) {
strcat (args, arg);
if (i+1<nargs)
strcat (args, ", ");
}
} else args = strdup ("");
if (type && name && *name) {
ret = malloc (strlen (type)+strlen (name)+
strlen(clas)+strlen(args)+15);
sprintf (ret, "%s int %s::%s(%s)", type, clas, name, args);
if (binfile) r_bin_class_add_method (binfile, clas, name, nargs);
}
}
}
free (clas);
free (args);
free (name);
return ret;
}
R_API int r_bin_demangle_type (const char *str) {
if (!str || !*str)
return R_BIN_NM_NONE;
if (!strcmp (str, "swift"))
return R_BIN_NM_SWIFT;
if (!strcmp (str, "java"))
return R_BIN_NM_JAVA;
if (!strcmp (str, "objc"))
return R_BIN_NM_OBJC;
if (!strcmp (str, "cxx"))
return R_BIN_NM_CXX;
if (!strcmp (str, "dlang"))
return R_BIN_NM_DLANG;
if (!strcmp (str, "msvc"))
return R_BIN_NM_MSVC;
return R_BIN_NM_NONE;
}
R_API int r_bin_lang_rust(RBinFile *binfile) {
RBinObject *o = binfile ? binfile->o : NULL;
RBinInfo *info = o ? o->info : NULL;
RBinSymbol *sym;
RListIter *iter;
int haslang = R_FALSE;
if (!info)
return R_FALSE;
r_list_foreach (o->symbols, iter, sym) {
if (strstr (sym->name, "rust_stack_exhausted")) {
haslang = R_TRUE;
info->lang = "rust";
break;
}
}
// NOTE: if the rust binary is stripped we can check
// if the strings contain 'rust', but this can be too
// time consuming and spawn some false positives and,
// as long as lang detection is only useful for demangling
// there's no utility on catching this case.
return haslang;
}
R_API int r_bin_lang_type(RBinFile *binfile, const char *def) {
int type = 0;
RBinPlugin *plugin;
if (def && *def) {
type = r_bin_demangle_type (def);
if (type != R_BIN_NM_NONE)
return type;
}
plugin = r_bin_file_cur_plugin (binfile);
if (plugin && plugin->demangle_type)
type = plugin->demangle_type (def);
else {
if (binfile->o && binfile->o->info) {
type = r_bin_demangle_type (binfile->o->info->lang);
}
}
if (type == R_BIN_NM_NONE)
type = r_bin_demangle_type (def);
return type;
}
R_API char *r_bin_demangle (RBinFile *binfile, const char *def, const char *str) {
RBin *bin = binfile->rbin;
int type = r_bin_lang_type (binfile, def);
switch (type) {
case R_BIN_NM_JAVA: return r_bin_demangle_java (str);
/* rust uses the same mangling as c++ and appends a uniqueid */
case R_BIN_NM_RUST: return r_bin_demangle_cxx (str);
case R_BIN_NM_CXX: return r_bin_demangle_cxx (str);
case R_BIN_NM_OBJC: return r_bin_demangle_objc (NULL, str);
case R_BIN_NM_SWIFT: return r_bin_demangle_swift (str);
case R_BIN_NM_DLANG: return r_bin_demangle_plugin (bin, "dlang", str);
}
return NULL;
}
#ifdef TEST
main() {
char *out, str[128];
strncpy (str, "_Z1hic", sizeof (str)-1);
strncpy (str, "main(Ljava/lang/String;I)V", sizeof (str)-1);
strncpy (str, "main([Ljava/lang/String;)V", sizeof (str)-1);
strncpy (str, "foo([III)Ljava/lang/Integer;", sizeof (str)-1);
//out = cplus_demangle_v3 (str, flags);
out = r_bin_demangle_java (str); //, flags);
printf ("INPUT (%s)\n", str);
printf ("OUTPUT (%s)\n", out);
}
#endif