diff --git a/binr/rabin2/rabin2.c b/binr/rabin2/rabin2.c index f8f174de5a..3138e324f5 100644 --- a/binr/rabin2/rabin2.c +++ b/binr/rabin2/rabin2.c @@ -75,13 +75,14 @@ static int rabin_show_help(int v) { ); if (v) { printf ("Environment:\n" - " RABIN2_LANG: e bin.lang # assume lang for demangling\n" + " RABIN2_LANG: e bin.lang # assume lang for demangling\n" " RABIN2_NOPLUGINS: # do not load shared plugins (speedup loading)\n" - " RABIN2_DEMANGLE: e bin.demangle # show symbols demangled\n" - " RABIN2_MAXSTRBUF: e bin.maxstrbuf # specify maximum buffer size\n" - " RABIN2_STRFILTER: e bin.strfilter # r2 -qe bin.strfilter=? -c '' --\n" - " RABIN2_STRPURGE: e bin.strpurge # try to purge false positives\n" - " RABIN2_PREFIX: e bin.prefix # prefix symbols/sections/relocs with a specific string\n"); + " RABIN2_DEMANGLE=0:e bin.demangle # do not demangle symbols\n" + " RABIN2_MAXSTRBUF: e bin.maxstrbuf # specify maximum buffer size\n" + " RABIN2_STRFILTER: e bin.strfilter # r2 -qe bin.strfilter=? -c '' --\n" + " RABIN2_STRPURGE: e bin.strpurge # try to purge false positives\n" + " RABIN2_DMNGLRCMD: e bin.demanglercmd # try to purge false positives\n" + " RABIN2_PREFIX: e bin.prefix # prefix symbols/sections/relocs with a specific string\n"); } return 1; } @@ -418,7 +419,7 @@ static char *demangleAs(int type) { case R_BIN_NM_CXX: res = r_bin_demangle_cxx (file); break; case R_BIN_NM_JAVA: res = r_bin_demangle_java (file); break; case R_BIN_NM_OBJC: res = r_bin_demangle_objc (NULL, file); break; - case R_BIN_NM_SWIFT: res = r_bin_demangle_swift (file); break; + case R_BIN_NM_SWIFT: res = r_bin_demangle_swift (file, 0); break; // XX: use case R_BIN_NM_MSVC: res = r_bin_demangle_msvc(file); break; default: eprintf ("Unsupported demangler\n"); @@ -472,6 +473,10 @@ int main(int argc, char **argv) { } free (tmp); + if ((tmp = r_sys_getenv ("RABIN2_DMNGLRCMD"))) { + r_config_set (core.config, "bin.demanglecmd", tmp); + free (tmp); + } if ((tmp = r_sys_getenv ("RABIN2_LANG"))) { r_config_set (core.config, "bin.lang", tmp); free (tmp); diff --git a/libr/bin/demangle.c b/libr/bin/demangle.c index 71d2e57a58..958e9e48cd 100644 --- a/libr/bin/demangle.c +++ b/libr/bin/demangle.c @@ -343,7 +343,7 @@ R_API int r_bin_lang_type(RBinFile *binfile, const char *def, const char *sym) { return type; } -R_API char *r_bin_demangle (RBinFile *binfile, const char *def, const char *str) { +R_API char *r_bin_demangle(RBinFile *binfile, const char *def, const char *str) { int type = -1; RBin *bin; if (!binfile || !*str) return NULL; @@ -354,8 +354,12 @@ R_API char *r_bin_demangle (RBinFile *binfile, const char *def, const char *str) if (!strncmp (str, "imp.", 4)) str += 4; if (!strncmp (str, "__", 2)) { - type = R_BIN_NM_CXX; - str++; + if (str[2] == 'T') { + type = R_BIN_NM_SWIFT; + } else { + type = R_BIN_NM_CXX; + // str++; + } } // if str is sym. or imp. when str+=4 str points to the end so just return if (!*str) @@ -368,7 +372,7 @@ R_API char *r_bin_demangle (RBinFile *binfile, const char *def, const char *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_OBJC: return r_bin_demangle_objc (NULL, str); - case R_BIN_NM_SWIFT: return r_bin_demangle_swift (str); + case R_BIN_NM_SWIFT: return r_bin_demangle_swift (str, bin->demanglercmd); case R_BIN_NM_CXX: return r_bin_demangle_cxx (str); case R_BIN_NM_DLANG: return r_bin_demangle_plugin (bin, "dlang", str); } diff --git a/libr/bin/mangling/Makefile b/libr/bin/mangling/Makefile new file mode 100644 index 0000000000..30ea9d8a93 --- /dev/null +++ b/libr/bin/mangling/Makefile @@ -0,0 +1,3 @@ +all: + $(CC) -DHAS_MAIN=1 -I../../include swift-sd.c -L../../util -lr_util + ./a.out diff --git a/libr/bin/mangling/swift-sd.c b/libr/bin/mangling/swift-sd.c index 65a1ab1225..ade7deb7c9 100644 --- a/libr/bin/mangling/swift-sd.c +++ b/libr/bin/mangling/swift-sd.c @@ -1,11 +1,18 @@ -/* work-in-progress reverse engineered swift-demangler in C by pancake@nopcode.org */ +/* work-in-progress reverse engineered swift-demangler in C + * Copyright MIT 2015-2016 + * by pancake@nopcode.org */ #include #include #include #include +#include +#ifndef HAS_MAIN #define HAS_MAIN 0 +#endif + +#define IFDBG if(0) // $ echo "..." | xcrun swift-demangle @@ -22,13 +29,14 @@ static struct Type types[] = { { "Ss", "generic" }, // C_ARGC { "S_", "Generic" }, // C_ARGC { "Sa", "Array" }, - { "Si", "Int" }, + { "Si", "Swift.Int" }, { "Sf", "Float" }, { "Sb", "Bool" }, { "Su", "UInt" }, { "SQ", "ImplicitlyUnwrappedOptional" }, { "Sc", "UnicodeScalar" }, { "Sd", "Double" }, + { "SS", "String" }, // Swift.String /* builtin */ { "Bi1", "Builtin.Int1" }, { "Bp", "Builtin.RawPointer" }, @@ -41,6 +49,7 @@ static struct Type metas [] = { /* attributes */ { "FC", "ClassFunc" }, { "S0_FT", "?" }, + { "S0", "self" }, { "U__FQ_T_", "(A)" }, { "ToFC", "@objc class func" }, { "ToF", "@objc func" }, @@ -49,7 +58,7 @@ static struct Type metas [] = { }; static struct Type flags [] = { - { "f", "function" }, + //{ "f", "function" }, // this is not an accessor { "s", "setter" }, { "g", "getter" }, { "m", "method" }, // field? @@ -80,7 +89,7 @@ static const char *getstring(const char *s, int len) { return buf; } -static const char *resolve (struct Type *t, const char *foo, const char **bar) { +static const char *resolve(struct Type *t, const char *foo, const char **bar) { for (; t[0].code; t++) { int len = strlen (t[0].code); if (!strncmp (foo, t[0].code, len)) { @@ -93,31 +102,8 @@ static const char *resolve (struct Type *t, const char *foo, const char **bar) { static int have_swift_demangle = -1; -char *r_bin_demangle_swift(const char *s) { -#define STRCAT_BOUNDS(x) if ((x+2+strlen (out))>sizeof (out)) break; +static char *swift_demangle_cmd(const char *s) { static char *swift_demangle = NULL; - char out[8192]; - int i, len, is_generic = 0;; - int is_first = 1; - int is_last = 0; - int retmode = 0; - if (!strncmp (s, "__", 2)) s = s + 2; - if (!strncmp (s, "imp.", 4)) s = s + 4; - if (!strncmp (s, "reloc.", 6)) s = s + 6; -#if 0 - const char *element[] = { - "module", "class", "method", NULL - }; -#endif - const char *attr = NULL; - const char *attr2 = NULL; - const char *q, *p = s; - if (strncmp (s, "_T", 2)) { - return NULL; - } - if (strchr (s, '\'') || strchr (s, ' ')) - return NULL; - if (have_swift_demangle == -1) { if (!swift_demangle) { have_swift_demangle = 0; @@ -143,9 +129,100 @@ char *r_bin_demangle_swift(const char *s) { } return r_str_chop (res); } + return NULL; +} + +char *r_bin_demangle_swift(const char *s, int syscmd) { +#define STRCAT_BOUNDS(x) if ((x + 2 + strlen (out)) > sizeof (out)) break; + char out[1024]; + int i, len, is_generic = 0; + int is_first = 1; + int is_last = 0; + int retmode = 0; + if (!strncmp (s, "imp.", 4)) s = s + 4; + if (!strncmp (s, "__", 2)) s = s + 2; + if (!strncmp (s, "reloc.", 6)) s = s + 6; +#if 0 + const char *element[] = { + "module", "class", "method", NULL + }; +#endif + const char *attr = NULL; + const char *attr2 = NULL; + const char *q, *p = s; + + if (*s != 'T' && strncmp (s, "_T", 2)) { + return NULL; + } + if (strchr (s, '\'') || strchr (s, ' ')) { + return NULL; + } + if (syscmd) { + char *res = swift_demangle_cmd (s); + if (res) { + return res; + } + } + out[0] = 0; - p += 2; - if (*p == 'F' || *p == 'W') { + + const char *tail = NULL; + if (p[0]) { + switch (p[1]) { + case 'M': + switch (p[2]) { + case 'a': + tail = "..accessor.metadata"; + break; + case 'm': + tail = "..metaclass"; + break; + case 'L': + tail = "..lazy.metadata"; + break; + default: + tail = "..metadata"; + break; + } + break; + case 'I': // interfaces + eprintf ("Jkjfksaldf\n"); + break; + } + } + p += (tail? 1: 2); + + + int methlen; + q = getnum (p, &methlen); + if (q && methlen > 0) { + // + } + + if (IS_NUMBER (*p) || *p == 'v' || *p == 'o' || *p == 'V' || *p == 'M' || *p == 'C' || *p == 'F' || *p == 'W') { // _TF or __TW + if (!strncmp (p+1, "SS", 2)) { + strcat (out, "Swift.String.init ("); + p += 3; + } + if (!strncmp (p, "vdv", 3)) { + tail = "..field"; + p += 3; + } + if (!strncmp (p, "oFC", 3)) { + tail = "..init.witnesstable"; + p += 4; + } +#if 0 + if (!strncmp (p+1, "C", 2)) { + strcat (out, "class "); + p += 3; + } +#endif + q = getnum (q, &len); + if (len > 0) { + p = q; + } + q = numpos (p); //printf ("(%s)\n", getstring (p, (q-p))); for (i=0, len = 1; len; q += len, i++) { @@ -161,8 +238,7 @@ char *r_bin_demangle_swift(const char *s) { len, getstring (q, len)); #endif // push string - if (*out) - strcat (out, "."); + if (i && *out) strcat (out, "."); STRCAT_BOUNDS (len); strcat (out, getstring (q, len)); } @@ -176,6 +252,7 @@ char *r_bin_demangle_swift(const char *s) { } // return 0; } + /* parse accessors */ if (attr) { int len; const char *name; @@ -209,31 +286,50 @@ char *r_bin_demangle_swift(const char *s) { strcat (out, attr2); } } while (0); + if (q && *q == '_') { + strcat (out, " -> ()"); + } } else { /* parse function parameters here */ - // type len value + // type len value/ for (i=0; q; i++) { + if (*q == 'f') q++; switch (*q) { + case 'S': // "S0" + if (q[1] == '0') { + strcat (out, " (self) -> ()"); + if (attr) { + strcat (out, attr); + } + //p = q + 7; + q = p = q + 1; + attr = ""; + } else if (q[1] == 'S') { + // swift string + strcat (out, "__String"); + } + break; case 'B': case 'T': case 'I': + p = resolve (types, q + 0, &attr); // type + break; case 'F': - p = resolve (types, q+3, &attr); // type + strcat (out, " ()"); + p = resolve (types, q + 3, &attr); // type break; case 'G': q+=2; //printf ("GENERIC\n"); if (!strncmp (q, "_V", 2)) { - q+=2; + q += 2; } p = resolve (types, q, &attr); // type break; case 'V': - // printf ("VECTOR\n"); - p = resolve (types, q+1, &attr); // type + p = resolve (types, q + 1, &attr); // type break; case '_': - // it's return value time! p = resolve (types, q+1, &attr); // type //printf ("RETURN TYPE %s\n", attr); @@ -241,6 +337,7 @@ char *r_bin_demangle_swift(const char *s) { default: p = resolve (types, q, &attr); // type } + if (p) { q = p; q = getnum (p, &len); @@ -290,7 +387,6 @@ char *r_bin_demangle_swift(const char *s) { } q += len; } else { - //printf ("void\n"); q++; break; } @@ -300,6 +396,9 @@ char *r_bin_demangle_swift(const char *s) { //printf ("Unsupported type: %c\n", *p); } if (*out) { + if (tail) + strcat (out, tail); +#if 1 char *p, *outstr = strdup (out); p = outstr; for (;;) { @@ -311,6 +410,7 @@ char *r_bin_demangle_swift(const char *s) { } else break; } return outstr; +#endif } return NULL; } @@ -318,41 +418,116 @@ char *r_bin_demangle_swift(const char *s) { #if HAS_MAIN -const char *swift_tests[] = { - "_TFC10swifthello5Hellog5WorldSS" // getter -,"_TFC10swifthello5Hellom5WorldSS" // method -,"_TFC10swifthello5Hellos5WorldSS" // setter -// Swift.String.init (Swift.String.Type)(_builtinStringLiteral : Builtin.RawPointer, byteSize : Builtin.Word, isASCII : Builtin.Int1) -> Swift.String -,"_TFSSCfMSSFT21_builtinStringLiteralBp8byteSizeBw7isASCIIBi1__SS" -// FlappyBird.GameScene.resetScene (FlappyBird.GameScene)() -> () -,"_TFC10FlappyBird9GameScene10resetScenefS0_FT_T_" -// Swift.println (A) -> () -,"_TFSs7printlnU__FQ_T_" -// Swift.C_ARGV.mutableAddressor : Swift.UnsafeMutablePointer> -,"_TFSsa6C_ARGVGVSs20UnsafeMutablePointerGS_VSs4Int8__" -// Swift.C_ARGC.mutableAddressor : Swift.Int32 -,"_TFSsa6C_ARGCVSs5Int32" -//_swifthello.nor () -> Swift.Int -,"_TF10swifthello3norFT_Si" -,NULL -}; +typedef struct { + const char *sym; + const char *dem; +} Test; + +Test swift_tests[] = { +{ + "_TFSSCfT21_builtinStringLiteralBp8byteSizeBw7isASCIIBi1__SS" + ,"Swift.String.init (_builtinStringLiteral(Builtin.RawPointer byteSize__Builtin.Word isASCII__Builtin.Int1 _) -> String" + //, "Swift.String.init (Swift.String.Type) -> (_builtinStringLiteral : Builtin.RawPointer, byteSize : Builtin.Word, isASCII : Builtin.Int1) -> Swift.String +},{ + "_TFC10swifthello5Hellog5WorldSS" // getter + ,"swifthello.Hello.World.getter__String" + // swifthello.Hello.World.getter : Swift.String +},{ + "_TFC10swifthello5Hellom5WorldSS" // getter + ,"swifthello.Hello.World.method__String" +},{ + "_TFC10swifthello5Hellos5WorldSS" // getter + ,"swifthello.Hello.World.setter__String" +},{ + "_TFSSCfMSSFT21_builtinStringLiteralBp8byteSizeBw7isASCIIBi1__SS" + ,"Swift.String.init (_builtinStringLiteral(Builtin.RawPointer byteSize__Builtin.Word isASCII__Builtin.Int1 _) -> String" +},{ + "_TF10swifthello3norFT_Si" + ,"swifthello.nor () -> Swift.Int" +},{ + "_TFSs7printlnU__FQ_T_" + ,"println.(A) -> ()" +},{ + "_TFSsa6C_ARGVGVSs20UnsafeMutablePointerGS_VSs4Int8__" + ,"C_ARGV" +},{ + "_TFC10FlappyBird9GameScene10resetScenefS0_FT_T_" + ,"FlappyBird.GameScene.resetScene (self) -> (__ _) ()" // XXX this is not correct +},{ + "__TFC4main8BarClass8sayHellofT_T_" + ,"main.BarClass.sayHello" +},{ + "__TFC4main4TostCfT_S0_" + ,"main.Tost.allocator" +},{ + "__TFC4main4TostD" + ,"main.Tost.deallocator" +},{ + "__TFC4main4TostcfT_S0_" + ,"main.Tost.constructor" +},{ + "__TF4main4moinFT_Si" + ,"main.moin () -> Swift.Int" +},{ + "__TFC4main4Tostg3msgSS" + ,"main.Tost.msg.getter__String" +},{ + "__TMC4main4Tost" + ,"main.Tost..metadata" +},{ + "__TMLC4main4Tost" + ,"main.Tost..lazy.metadata" + +},{ + "__TMaC4main4Tost" + ,"main.Tost..accessor.metadata" + //,"_lazy cache variable for type metadata for main.Tost" +},{ + "__TMmC4main4Tost" + ,"main.Tost..metaclass" +},{ + "__TFV4main7Balanceg5widthSd" + ,"main.Balance.width.getter__Double" +},{ + "__TWoFC4main4TostCfT_S0_" + ,"Tost.allocator..init.witnesstable" +},{ + "__TWvdvC4main4Tost3msgSS" + ,"main.Tost.msg__String..field" +},{ + "__TIFC10Moscapsule10MQTTClient11unsubscribeFTSS17requestCompletionGSqFTOS_10MosqResultSi_T___T_A0_" + ,"Moscapsule.MQTTClient.unsubscribe ()" +////imp._TIFC10Moscapsule10MQTTClient11unsubscribeFTSS17requestCompletionGSqFTOS_10MosqResultSi_T___T_A0_ +},{ + // _direct field offset for main.Tost.msg : Swift.String + NULL, NULL +}}; int main(int argc, char **argv) { char *ret; - if (argc>1) { - ret = r_bin_demangle_swift (argv[1]); + if (argc > 1) { + ret = r_bin_demangle_swift (argv[1], 0); if (ret) { printf ("%s\n", ret); free (ret); } } else { int i = 0; - for (i=0; swift_tests[i]; i++) { - printf ("\n- %s\n", swift_tests[i]); - ret = r_bin_demangle_swift (swift_tests[i]); + for (i=0; swift_tests[i].sym; i++) { + Test *test = &swift_tests[i]; + printf ("[>>] %s\n", test->sym); + ret = r_bin_demangle_swift (test->sym, 0); if (ret) { - printf ("+ %s\n", ret); + if (!strcmp (ret, test->dem)) { + printf (Color_GREEN"[OK]"Color_RESET" %s\n", ret); + } else { + printf (Color_RED"[XX]"Color_RESET" %s\n", ret); + printf (Color_YELLOW"[MUSTBE]"Color_RESET" %s\n", test->dem); + } free (ret); + } else { + printf (Color_RED"[XX]"Color_RESET" \"(null)\"\n"); + printf (Color_YELLOW"[MUSTBE]"Color_RESET" %s\n", test->dem); } } } diff --git a/libr/core/bin.c b/libr/core/bin.c index 2ebade3191..fd58e50852 100644 --- a/libr/core/bin.c +++ b/libr/core/bin.c @@ -1190,6 +1190,10 @@ static void snInit(RCore *r, SymName *sn, RBinSymbol *sym, const char *lang) { r_name_filter (sn->demflag, -1); } } +if (strstr (sym->name, "4main4")) { + sn->demname = r_bin_demangle (r->bin->cur, "swift", sym->name); + eprintf ("%s = %s\n", sym->name, sn->demname); +} } static void snFini(SymName *sn) { diff --git a/libr/core/cmd_info.c b/libr/core/cmd_info.c index c087b5de66..2a16eda3b2 100644 --- a/libr/core/cmd_info.c +++ b/libr/core/cmd_info.c @@ -20,7 +20,7 @@ static bool demangle_internal(RCore *core, const char *lang, const char *s) { case R_BIN_NM_CXX: res = r_bin_demangle_cxx (s); break; case R_BIN_NM_JAVA: res = r_bin_demangle_java (s); break; case R_BIN_NM_OBJC: res = r_bin_demangle_objc (NULL, s); break; - case R_BIN_NM_SWIFT: res = r_bin_demangle_swift (s); break; + case R_BIN_NM_SWIFT: res = r_bin_demangle_swift (s, core->bin->demanglercmd); break; case R_BIN_NM_DLANG: res = r_bin_demangle_plugin (core->bin, "dlang", s); break; default: r_bin_demangle_list (core->bin); diff --git a/libr/core/config.c b/libr/core/config.c index f7daee93fc..071cd14bc8 100644 --- a/libr/core/config.c +++ b/libr/core/config.c @@ -410,6 +410,15 @@ static int cb_binfilter(void *user, void *data) { return true; } +/* BinDemangleCmd */ +static int cb_bdc(void *user, void *data) { + RCore *core = (RCore*) user; + RConfigNode *node = (RConfigNode*) data; + core->bin->demanglercmd = node->i_value; + return true; +} + + static int cb_strpurge(void *user, void *data) { RCore *core = (RCore*) user; RConfigNode *node = (RConfigNode*) data; @@ -1519,6 +1528,7 @@ R_API int r_core_config_init(RCore *core) { SETCB("bin.force", "", &cb_binforce, "Force that rbin plugin"); SETPREF("bin.lang", "", "Language for bin.demangle"); SETPREF("bin.demangle", "true", "Import demangled symbols from RBin"); + SETCB("bin.demanglecmd", "false", &cb_bdc, "run xcrun swift-demangle and similar if available (SLOW)"); /* bin */ SETI("bin.baddr", -1, "Base address of the binary"); diff --git a/libr/include/r_bin.h b/libr/include/r_bin.h index 894b0a0914..49a2f37e74 100644 --- a/libr/include/r_bin.h +++ b/libr/include/r_bin.h @@ -229,6 +229,7 @@ typedef struct r_bin_t { char *srcdir; // dir.source char *prefix; // bin.prefix ut64 filter_rules; + bool demanglercmd; } RBin; typedef int (*FREE_XTR)(void *xtr_obj); @@ -484,7 +485,7 @@ R_API int r_bin_demangle_type (const char *str); R_API char *r_bin_demangle_java(const char *str); R_API char *r_bin_demangle_cxx(const char *str); R_API char *r_bin_demangle_msvc(const char *str); -R_API char *r_bin_demangle_swift(const char *s); +R_API char *r_bin_demangle_swift(const char *s, bool syscmd); R_API char *r_bin_demangle_objc(RBinFile *binfile, const char *sym); R_API int r_bin_lang_type(RBinFile *binfile, const char *def, const char *sym); R_API bool r_bin_lang_objc(RBinFile *binfile);