diff --git a/libr/bin/bfile.c b/libr/bin/bfile.c index 815c411260..4a4cf319a1 100644 --- a/libr/bin/bfile.c +++ b/libr/bin/bfile.c @@ -1051,7 +1051,10 @@ R_IPI RBinClass *r_bin_class_new(const char *name, const char *super, int view) RBinClass *c = R_NEW0 (RBinClass); if (c) { c->name = strdup (name); - c->super = super? strdup (super): NULL; + if (super) { + c->super = r_list_newf (free); + r_list_append (c->super, strdup (super)); + } c->methods = r_list_newf (r_bin_symbol_free); c->fields = r_list_newf (r_bin_field_free); c->visibility = view; @@ -1062,7 +1065,7 @@ R_IPI RBinClass *r_bin_class_new(const char *name, const char *super, int view) R_IPI void r_bin_class_free(RBinClass *k) { if (k) { free (k->name); - free (k->super); + r_list_free (k->super); free (k->visibility_str); r_list_free (k->methods); r_list_free (k->fields); @@ -1075,8 +1078,9 @@ R_API RBinClass *r_bin_file_add_class(RBinFile *bf, const char *name, const char RBinClass *c = __getClass (bf, name); if (c) { if (super) { - free (c->super); - c->super = strdup (super); + r_list_free (c->super); + c->super = r_list_newf (free); + r_list_append (c->super, strdup (super)); } return c; } diff --git a/libr/bin/format/objc/mach0_classes.c b/libr/bin/format/objc/mach0_classes.c index 2325412bec..5279194824 100644 --- a/libr/bin/format/objc/mach0_classes.c +++ b/libr/bin/format/objc/mach0_classes.c @@ -1189,7 +1189,8 @@ void MACH0_(get_class_t)(mach0_ut p, RBinFile *bf, RBinClass *klass, bool dupe, klass->addr = c.isa; if (c.superclass) { - klass->super = get_class_name (c.superclass, bf); + klass->super = r_list_newf (free); + r_list_append (klass->super, get_class_name (c.superclass, bf)); } else if (relocs) { struct reloc_t reloc_at_class_addr; reloc_at_class_addr.addr = p + sizeof (mach0_ut); @@ -1200,7 +1201,8 @@ void MACH0_(get_class_t)(mach0_ut p, RBinFile *bf, RBinClass *klass, bool dupe, char *target_class_name = (char*) ((struct reloc_t*) found->data)->name; if (r_str_startswith (target_class_name, _objc_class)) { target_class_name += _objc_class_len; - klass->super = strdup (target_class_name); + klass->super = r_list_newf (free); + r_list_append (klass->super, strdup (target_class_name)); } } } @@ -1208,7 +1210,7 @@ void MACH0_(get_class_t)(mach0_ut p, RBinFile *bf, RBinClass *klass, bool dupe, #if SWIFT_SUPPORT if (q (c.data + n_value) & 7) { - eprintf ("This is a Swift class\n"); + R_LOG_DEBUG ("This is a Swift class"); } #endif if (!is_meta_class && !dupe) { @@ -1616,9 +1618,10 @@ static RList *MACH0_(parse_categories)(RBinFile *bf, RSkipList *relocs, objc_cac if (cpar) { *cpar = 0; } + r_list_free (klass->super); + klass->super = r_list_newf (free); + r_list_append (klass->super, super); // char *name = strdup (super + idx); - free (klass->super); - klass->super = super; // free (klass->name); // klass->name = name; } diff --git a/libr/bin/p/bin_dex.c b/libr/bin/p/bin_dex.c index 25aa185bd0..02495503d6 100644 --- a/libr/bin/p/bin_dex.c +++ b/libr/bin/p/bin_dex.c @@ -1467,7 +1467,10 @@ static void parse_class(RBinFile *bf, RBinDexClass *c, int class_index, int *met cls->addr = dex->header.class_offset + (class_index * DEX_CLASS_SIZE); cls->methods = r_list_new (); const char *super = dex_class_super_name (dex, c); - cls->super = super? strdup (super): NULL; + if (super) { + cls->super = r_list_newf (free); + r_list_append (cls->super, strdup (super)); + } if (!cls->methods) { free (cls); goto beach; @@ -1484,7 +1487,15 @@ static void parse_class(RBinFile *bf, RBinDexClass *c, int class_index, int *met rbin->cb_printf (" Class descriptor : '%s;'\n", cls->name); rbin->cb_printf (" Access flags : 0x%04x (%s)\n", c->access_flags, r_str_get (cls->visibility_str)); - rbin->cb_printf (" Superclass : '%s'\n", cls->super); + if (cls->super) { + char *sk; + RListIter *iter; + rbin->cb_printf (" Superclass : '"); + r_list_foreach (cls->super, iter, sk) { + rbin->cb_printf ("%s%s", iter->n? ",": "", sk); + } + rbin->cb_printf ("'\n"); + } rbin->cb_printf (" Interfaces -\n"); } diff --git a/libr/core/cbin.c b/libr/core/cbin.c index 6433d9985b..93af340e90 100644 --- a/libr/core/cbin.c +++ b/libr/core/cbin.c @@ -3454,7 +3454,28 @@ static void classdump_c(RCore *r, RBinClass *c) { static void classdump_objc(RCore *r, RBinClass *c) { if (c->super) { - r_cons_printf ("@interface %s : %s\n{\n", c->name, c->super); + int n = 0; + r_cons_printf ("@interface %s :", c->name); + const char *sk; + RListIter *iter; + r_list_foreach (c->super, iter, sk) { + switch (n) { + case 0: + r_cons_printf (" %s", sk); + break; + case 1: + r_cons_printf ("< %s", sk); + break; + default: + r_cons_printf (", %s", sk); + break; + } + } + if (r_list_length (c->super) > 1) { + r_cons_printf (" >\n{\n"); + } else { + r_cons_printf ("\n{\n"); + } } else { r_cons_printf ("@interface %s\n{\n", c->name); } @@ -3586,9 +3607,11 @@ static int bin_classes(RCore *r, PJ *pj, int mode) { } else if (IS_MODE_SIMPLEST (mode)) { r_cons_printf ("%s\n", c->name); } else if (IS_MODE_SIMPLE (mode)) { + char *supers = r_str_list_join (c->super, ", "); r_cons_printf ("0x%08"PFMT64x" [0x%08"PFMT64x" - 0x%08"PFMT64x"] %s %s%s%s\n", c->addr, at_min, at_max, r_bin_lang_tostring (c->lang), c->name, c->super ? " " : "", - r_str_get (c->super)); + r_str_get (supers)); + free (supers); } else if (IS_MODE_CLASSDUMP (mode)) { if (c) { RBinFile *bf = r_bin_cur (r->bin); @@ -3607,14 +3630,17 @@ static int bin_classes(RCore *r, PJ *pj, int mode) { } else if (IS_MODE_RAD (mode)) { char *n = __filterShell (name); r_cons_printf ("\"f class.%s = 0x%"PFMT64x"\"\n", n, at_min); - free (n); if (c->super) { - char *cn = c->name; // __filterShell (c->name); - char *su = c->super; // __filterShell (c->super); - r_cons_printf ("\"f super.%s.%s = %d\"\n", - cn, su, c->index); - // free (cn); - // free (su); + char *cn = c->name; + RListIter *iter; + const char *sk; + r_list_foreach (c->super, iter, sk) { + char *fsk = strdup (sk); + r_name_filter (fsk, -1); + r_cons_printf ("\"f super.%s.%s = %d\"\n", + cn, fsk, c->index); + free (fsk); + } } r_list_foreach (c->methods, iter2, sym) { char *mflags = r_core_bin_method_flags_str (sym->method_flags, mode); @@ -3662,6 +3688,7 @@ static int bin_classes(RCore *r, PJ *pj, int mode) { } } r_cons_printf ("};\"\n"); + free (n); } else if (IS_MODE_JSON (mode)) { pj_o (pj); pj_ks (pj, "classname", c->name); @@ -3673,7 +3700,13 @@ static int bin_classes(RCore *r, PJ *pj, int mode) { pj_ki (pj, "index", c->index); if (c->super) { pj_ks (pj, "visibility", r_str_get (c->visibility_str)); - pj_ks (pj, "super", c->super); + RListIter *iter; + const char *sk; + pj_ka (pj, "super"); + r_list_foreach (c->super, iter, sk) { + pj_s (pj, sk); + } + pj_end (pj); } pj_ka (pj, "methods"); r_list_foreach (c->methods, iter2, sym) { @@ -3723,7 +3756,9 @@ static int bin_classes(RCore *r, PJ *pj, int mode) { r_cons_printf ("0x%08"PFMT64x" [0x%08"PFMT64x" - 0x%08"PFMT64x"] %6"PFMT64d" %s class %d %s", c->addr, at_min, at_max, (at_max - at_min), cl, c->index, c->name); if (c->super) { - r_cons_printf (" :: %s\n", c->super); + char *csv = r_str_list_join (c->super, ", "); + r_cons_printf (" :: %s\n", csv); + free (csv); } else { r_cons_newline (); } diff --git a/libr/core/cmd_info.c b/libr/core/cmd_info.c index 94007ebb38..9676bde2d3 100644 --- a/libr/core/cmd_info.c +++ b/libr/core/cmd_info.c @@ -1300,41 +1300,51 @@ static int cmd_info(void *data, const char *input) { } else if (input[1] == ',') { // "ic," // ic, cmd_ic_comma (core, input); - } else if (input[1] == 'g') { + } else if (input[1] == 'g') { // "icg" RBinClass *cls; - RListIter *iter; + RListIter *iter, *iter2; RBinObject *obj = r_bin_cur_object (core->bin); if (!obj) { break; } bool fullGraph = true; const char *match = r_str_trim_head_ro (input + 2); - if (*match) { + if (R_STR_ISNOTEMPTY (match)) { r_list_foreach (obj->classes, iter, cls) { - if (cls->super && strstr (cls->super, match)) { - r_cons_printf ("agn %s\n", cls->super); - r_cons_printf ("agn %s\n", cls->name); - r_cons_printf ("age %s %s\n", cls->super, cls->name); - } else if (strstr (cls->name, match)) { - r_cons_printf ("agn %s\n", cls->name); + char *sk; + if (!match || !strstr (cls->name, match)) { + continue; + } + r_cons_printf ("agn %s\n", cls->name); + if (cls->super) { + r_list_foreach (cls->super, iter2, sk) { + if (match && strstr (sk, match)) { + r_cons_printf ("agn %s\n", sk); + r_cons_printf ("age %s %s\n", sk, cls->name); + } + } } } } else if (fullGraph) { r_list_foreach (obj->classes, iter, cls) { - if (cls->super) { - r_cons_printf ("agn %s\n", cls->super); - r_cons_printf ("agn %s\n", cls->name); - r_cons_printf ("age %s %s\n", cls->super, cls->name); - } else { - r_cons_printf ("agn %s\n", cls->name); + const char *sk; + r_cons_printf ("agn %s\n", cls->name); + r_list_foreach (cls->super, iter2, sk) { + r_cons_printf ("agn %s\n", sk); + r_cons_printf ("age %s %s\n", sk, cls->name); } } } else { r_list_foreach (obj->classes, iter, cls) { - if (cls->super && !strstr (cls->super, "NSObject")) { - r_cons_printf ("agn %s\n", cls->super); + char *sk; + RListIter *iter; + r_list_foreach (cls->super, iter, sk) { + if (strstr (sk, "NSObject")) { + continue; + } + r_cons_printf ("agn %s\n", sk); r_cons_printf ("agn %s\n", cls->name); - r_cons_printf ("age %s %s\n", cls->super, cls->name); + r_cons_printf ("age %s %s\n", sk, cls->name); } } } diff --git a/libr/include/r_bin.h b/libr/include/r_bin.h index a130defaa8..73fa7da085 100644 --- a/libr/include/r_bin.h +++ b/libr/include/r_bin.h @@ -509,7 +509,7 @@ typedef struct r_bin_section_t { typedef struct r_bin_class_t { char *name; // TODO: char *module; - char *super; + RList *super; // list of char* char *visibility_str; // XXX only used by java int index; ut64 addr; diff --git a/shlr/java/class.c b/shlr/java/class.c index 6df1b56e10..b222ecbfd3 100644 --- a/shlr/java/class.c +++ b/shlr/java/class.c @@ -701,25 +701,25 @@ R_API void r_bin_java_get_import_json_definitions(RBinJavaObj *bin, PJ *pj) { R_API void r_bin_java_get_class_info_json(RBinJavaObj *bin, PJ *pj) { r_return_if_fail (bin && pj); RList *classes = r_bin_java_get_classes (bin); - RBinClass *class_ = r_list_get_n (classes, 0); + RBinClass *klass = r_list_get_n (classes, 0); // pj dict already opened - if (class_) { + if (klass) { int dummy = 0; RListIter *iter; - RBinClass *class_v = NULL; + RBinClass *klassv = NULL; // add access flags like in methods - bool is_public = ((class_->visibility & R_BIN_JAVA_CLASS_ACC_PUBLIC) != 0); - bool is_final = ((class_->visibility & R_BIN_JAVA_CLASS_ACC_FINAL) != 0); - bool is_super = ((class_->visibility & R_BIN_JAVA_CLASS_ACC_SUPER) != 0); - bool is_interface = ((class_->visibility & R_BIN_JAVA_CLASS_ACC_INTERFACE) != 0); - bool is_abstract = ((class_->visibility & R_BIN_JAVA_CLASS_ACC_ABSTRACT) != 0); - bool is_synthetic = ((class_->visibility & R_BIN_JAVA_CLASS_ACC_SYNTHETIC) != 0); - bool is_annotation = ((class_->visibility & R_BIN_JAVA_CLASS_ACC_ANNOTATION) != 0); - bool is_enum = ((class_->visibility & R_BIN_JAVA_CLASS_ACC_ENUM) != 0); + bool is_public = ((klass->visibility & R_BIN_JAVA_CLASS_ACC_PUBLIC) != 0); + bool is_final = ((klass->visibility & R_BIN_JAVA_CLASS_ACC_FINAL) != 0); + bool is_super = ((klass->visibility & R_BIN_JAVA_CLASS_ACC_SUPER) != 0); + bool is_interface = ((klass->visibility & R_BIN_JAVA_CLASS_ACC_INTERFACE) != 0); + bool is_abstract = ((klass->visibility & R_BIN_JAVA_CLASS_ACC_ABSTRACT) != 0); + bool is_synthetic = ((klass->visibility & R_BIN_JAVA_CLASS_ACC_SYNTHETIC) != 0); + bool is_annotation = ((klass->visibility & R_BIN_JAVA_CLASS_ACC_ANNOTATION) != 0); + bool is_enum = ((klass->visibility & R_BIN_JAVA_CLASS_ACC_ENUM) != 0); - pj_ki (pj, "access_flags", class_->visibility); + pj_ki (pj, "access_flags", klass->visibility); pj_ki (pj, "is_public", is_public); pj_ki (pj, "is_final", is_final); pj_ki (pj, "is_super", is_super); @@ -728,20 +728,26 @@ R_API void r_bin_java_get_class_info_json(RBinJavaObj *bin, PJ *pj) { pj_ki (pj, "is_synthetic", is_synthetic); pj_ki (pj, "is_annotation", is_annotation); pj_ki (pj, "is_enum", is_enum); - pj_ks (pj, "name", class_->name); - - pj_ks (pj, "super", r_str_get (class_->super)); + pj_ks (pj, "name", klass->name); + if (klass->super) { + const char *sk; + pj_ka (pj, "super"); + r_list_foreach (klass->super, iter, sk) { + pj_ks (pj, "super", sk); + } + pj_end (pj); + } pj_ka (pj, "interfaces"); - r_list_foreach (classes, iter, class_v) { + r_list_foreach (classes, iter, klassv) { if (!dummy) { dummy++; continue; } // enumerate all interface classes and append them to the interfaces - if ((class_v->visibility & R_BIN_JAVA_CLASS_ACC_INTERFACE) != 0) { - pj_s (pj, class_v->name); + if ((klassv->visibility & R_BIN_JAVA_CLASS_ACC_INTERFACE) != 0) { + pj_s (pj, klassv->name); } } @@ -2859,7 +2865,13 @@ R_API RList *r_bin_java_get_classes(RBinJavaObj *bin) { k->methods = r_bin_java_enum_class_methods (bin, bin->cf2.this_class); k->fields = r_bin_java_enum_class_fields (bin, bin->cf2.this_class); k->name = r_bin_java_get_this_class_name (bin); - k->super = r_bin_java_get_name_from_bin_cp_list (bin, bin->cf2.super_class); + char *n = r_bin_java_get_name_from_bin_cp_list (bin, bin->cf2.super_class); + if (R_STR_ISNOTEMPTY (n)) { + k->super = r_list_newf (free); + r_list_append (k->super, n); + } else { + free (n); + } k->index = (idx++); k->lang = R_BIN_LANG_JAVA; r_list_append (classes, k); diff --git a/test/db/anal/java b/test/db/anal/java index ea6ea5409b..9e80e5c7d5 100644 --- a/test/db/anal/java +++ b/test/db/anal/java @@ -2,7 +2,7 @@ NAME=java prototypes in json FILE=bins/java/jdwpexeccmd.class CMDS=java prototypes j EXPECT=<","fq_name":"java/lang/Object..()V","prototype":"public void ()"},{"access_flags":9,"is_method":1,"is_native":0,"is_synthetic":0,"is_private":0,"is_public":1,"is_static":1,"is_protected":0,"is_super":0,"addr":868,"offset":846,"class_name":"JDWPExecCmd","signature":"(Ljava/lang/String;)Ljava/lang/String;","name":"run","fq_name":"JDWPExecCmd.run.(Ljava/lang/String;)Ljava/lang/String;","prototype":"public static java.lang.String run (java.lang.String)"}],"fields":[],"imports":["java.lang.StringBuilder","java.io.BufferedReader","java.io.InputStreamReader","java.lang.Exception","JDWPExecCmd","java.lang.Object","java.lang.String","java.lang.Process","java.io.BufferedReader","java.lang.Exception","java.lang.Runtime","java.lang.Process","java.lang.String"]} +{"access_flags":33,"is_public":1,"is_final":0,"is_super":1,"is_interface":0,"is_abstract":0,"is_synthetic":0,"is_annotation":0,"is_enum":0,"name":"JDWPExecCmd","super":["super":"java/lang/Object"],"interfaces":[],"methods":[{"access_flags":1,"is_method":1,"is_native":0,"is_synthetic":0,"is_private":0,"is_public":1,"is_static":0,"is_protected":0,"is_super":0,"addr":825,"offset":803,"class_name":"java/lang/Object","signature":"()V","name":"","fq_name":"java/lang/Object..()V","prototype":"public void ()"},{"access_flags":9,"is_method":1,"is_native":0,"is_synthetic":0,"is_private":0,"is_public":1,"is_static":1,"is_protected":0,"is_super":0,"addr":868,"offset":846,"class_name":"JDWPExecCmd","signature":"(Ljava/lang/String;)Ljava/lang/String;","name":"run","fq_name":"JDWPExecCmd.run.(Ljava/lang/String;)Ljava/lang/String;","prototype":"public static java.lang.String run (java.lang.String)"}],"fields":[],"imports":["java.lang.StringBuilder","java.io.BufferedReader","java.io.InputStreamReader","java.lang.Exception","JDWPExecCmd","java.lang.Object","java.lang.String","java.lang.Process","java.io.BufferedReader","java.lang.Exception","java.lang.Runtime","java.lang.Process","java.lang.String"]} EOF RUN diff --git a/test/db/cmd/cmd_i b/test/db/cmd/cmd_i index 93871d16cd..16709edf78 100644 --- a/test/db/cmd/cmd_i +++ b/test/db/cmd/cmd_i @@ -4217,8 +4217,8 @@ icg Hello icg no_match EOF EXPECT=<