From 57cda9236ef6a360e659af08a4b95e5e6b715507 Mon Sep 17 00:00:00 2001 From: pancake Date: Tue, 25 Aug 2026 16:13:22 +0200 Subject: [PATCH] Add typed IL2CPP method metadata --- doc/r2unity.md | 12 ++-- doc/todo.md | 2 +- src/lib/lib.c | 125 ++++++++++++++++++++++++++++++++++++++++++ src/lib/lib.h | 9 +++ src/r2/bin_r2unity.c | 105 +++++++++++++++++++++++++++++++++-- src/r2/core_r2unity.c | 72 +++++++++++++++--------- 6 files changed, 289 insertions(+), 36 deletions(-) diff --git a/doc/r2unity.md b/doc/r2unity.md index 6d26bab..3c2e9e0 100644 --- a/doc/r2unity.md +++ b/doc/r2unity.md @@ -355,10 +355,14 @@ int32_t customAttributeIndex; /* removed at v24.1 */ int32_t typeIndex; /* -> MetadataRegistration.types */ ``` -Not decoded by r2unity today. Without it, every dumped method -degrades to `Method()` with no parameter types or names. Combined -with `parameterDefaultValues` (§2.4) this is what reconstructs real -C# signatures like `Foo(string name, int count = 0)`. +r2unity decodes this table and exposes parameter tokens, names, and +type indices in `r2unity-sj`; it also emits a canonical signature such +as `Namespace.Type.Foo(this;string:name,int:count):void`. Type indices +that refer directly to a type definition are resolved to source names. +Pointer, array, and constructed-generic indices still require the native +`MetadataRegistration.types` table and use `type_index.N` until that +table is available. `parameterDefaultValues` (§2.4) remains necessary +to reconstruct optional values such as `int count = 0`. ### 2.4 Default values: `fieldDefaultValues`, `parameterDefaultValues`, `fieldAndParameterDefaultValueData` diff --git a/doc/todo.md b/doc/todo.md index d116e87..6cbeda3 100644 --- a/doc/todo.md +++ b/doc/todo.md @@ -119,7 +119,7 @@ Still missing: Add or improve decoding for: - - parameters and full method signatures + - generic method/type substitutions in signatures - default values for fields and parameters - properties and events - nested types diff --git a/src/lib/lib.c b/src/lib/lib.c index 4acd0db..5226424 100644 --- a/src/lib/lib.c +++ b/src/lib/lib.c @@ -295,6 +295,12 @@ static ut64 field_definition_entry_size(R2UnityMetadata *meta) { return 4 + type_index_size + 4; } +static ut64 parameter_definition_entry_size(R2UnityMetadata *meta) { + const bool compact_indices = (meta->version >= 35); + const int type_index_size = compact_indices? meta->typeIndexSize: 4; + return 4 + 4 + type_index_size; +} + /* Detect v24.0 vs v24.1+ (both land on disk as version==24). * * At v24.1 the ImageDefinition row grew by 8 bytes (added @@ -507,6 +513,8 @@ R_API ut64 r2unity_metadata_section_entry_size(R2UnityMetadata *meta, R2UMetadat return method_definition_entry_size (meta); case R2U_SEC_FIELDS: return field_definition_entry_size (meta); + case R2U_SEC_PARAMETERS: + return parameter_definition_entry_size (meta); case R2U_SEC_TYPE_DEFINITIONS: return type_definition_entry_size (meta); case R2U_SEC_IMAGES: @@ -820,6 +828,123 @@ R_API Il2CppFieldDefinition *r2unity_get_field_definitions(R2UnityMetadata *meta return fields; } +R_API Il2CppParameterDefinition *r2unity_get_parameter_definitions(R2UnityMetadata *meta, size_t *count) { + R_RETURN_VAL_IF_FAIL (meta && count, NULL); + const bool compact_indices = (meta->version >= 35); + const int type_index_size = compact_indices? meta->typeIndexSize: 4; + const ut64 entry = parameter_definition_entry_size (meta); + ut8 *buf = read_metadata_table (meta, R2U_SEC_PARAMETERS, entry, count); + if (!buf) { + return NULL; + } + Il2CppParameterDefinition *parameters = R_NEWS (Il2CppParameterDefinition, *count); + if (!parameters) { + R_FREE (buf); + return NULL; + } + for (size_t i = 0; i < *count; i++) { + const ut8 *p = buf + i * entry; + parameters[i].nameIndex = read_u32p (&p); + parameters[i].token = read_u32p (&p); + parameters[i].typeIndex = read_indexp (&p, type_index_size); + } + R_FREE (buf); + return parameters; +} + +static const char *csharp_type_alias(const char *name) { + static const struct { + const char *fullname; + const char *alias; + } aliases[] = { + { "System.Void", "void" }, + { "System.Boolean", "bool" }, + { "System.Byte", "byte" }, + { "System.SByte", "sbyte" }, + { "System.Char", "char" }, + { "System.Decimal", "decimal" }, + { "System.Double", "double" }, + { "System.Single", "float" }, + { "System.Int16", "short" }, + { "System.UInt16", "ushort" }, + { "System.Int32", "int" }, + { "System.UInt32", "uint" }, + { "System.Int64", "long" }, + { "System.UInt64", "ulong" }, + { "System.IntPtr", "nint" }, + { "System.UIntPtr", "nuint" }, + { "System.Object", "object" }, + { "System.String", "string" }, + }; + for (size_t i = 0; i < R_ARRAY_SIZE (aliases); i++) { + if (!strcmp (name, aliases[i].fullname)) { + return aliases[i].alias; + } + } + return NULL; +} + +R_API char *r2unity_type_name_from_index(R2UnityMetadata *meta, const Il2CppTypeDefinition *types, size_t type_count, int32_t type_index, bool fallback) { + R_RETURN_VAL_IF_FAIL (meta, NULL); + if (type_index >= 0) { + for (size_t i = 0; types && i < type_count; i++) { + if (types[i].byvalTypeIndex != type_index) { + continue; + } + char *name = r2unity_type_fullname (meta, &types[i], i, R2U_NAME_FALLBACK_TYPE); + if (name) { + const char *alias = csharp_type_alias (name); + if (alias) { + free (name); + return strdup (alias); + } + } + return name; + } + } + return fallback? r_str_newf ("type_index.%d", type_index): NULL; +} + +R_API char *r2unity_method_signature(R2UnityMetadata *meta, const Il2CppMethodDefinition *method, const Il2CppTypeDefinition *owner, size_t owner_index, const Il2CppTypeDefinition *types, size_t type_count, const Il2CppParameterDefinition *parameters, size_t parameter_count, bool fallback) { + R_RETURN_VAL_IF_FAIL (meta && method, NULL); + char *return_type = r2unity_type_name_from_index (meta, types, type_count, method->returnType, fallback); + char *method_name = r2unity_method_fullname (meta, method, owner, owner_index, + fallback? R2U_NAME_FALLBACK_TYPE: 0); + if (!method_name) { + free (return_type); + return NULL; + } + RStrBuf *sb = r_strbuf_new (method_name); + r_strbuf_append (sb, "("); + bool is_instance = !(method->flags & 0x0010); + if (is_instance) { + r_strbuf_append (sb, "this;"); + } + for (size_t i = 0; i < method->parameterCount; i++) { + st64 pi = (st64)method->parameterStart + (st64)i; + const Il2CppParameterDefinition *parameter = parameters + && pi >= 0 && (ut64)pi < parameter_count + ? ¶meters[pi]: NULL; + char *type_name = parameter + ? r2unity_type_name_from_index (meta, types, type_count, parameter->typeIndex, fallback) + : NULL; + char *parameter_name = parameter? r2unity_get_string (meta, parameter->nameIndex): NULL; + r_strbuf_appendf (sb, "%s%s", i? ",": "", + type_name? type_name: "unknown"); + if (R_STR_ISNOTEMPTY (parameter_name)) { + r_strbuf_appendf (sb, ":%s", parameter_name); + } else { + r_strbuf_appendf (sb, ":arg%zu", i); + } + free (parameter_name); + free (type_name); + } + r_strbuf_appendf (sb, "):%s", return_type? return_type: "unknown"); + free (method_name); + free (return_type); + return r_strbuf_drain (sb); +} + R_API int32_t *r2unity_get_type_index_table(R2UnityMetadata *meta, R2UMetadataSectionId id, size_t *count) { R_RETURN_VAL_IF_FAIL (meta && count, NULL); const bool compact_indices = (meta->version >= 35); diff --git a/src/lib/lib.h b/src/lib/lib.h index 6c69a51..b41b2cb 100644 --- a/src/lib/lib.h +++ b/src/lib/lib.h @@ -130,6 +130,12 @@ typedef struct { uint32_t token; } Il2CppFieldDefinition; +typedef struct { + uint32_t nameIndex; + uint32_t token; + int32_t typeIndex; +} Il2CppParameterDefinition; + typedef struct { uint32_t nameIndex; int32_t assemblyIndex; @@ -264,6 +270,9 @@ R_API bool r2unity_read_string_literal(R2UnityMetadata *meta, const Il2CppString R_API Il2CppTypeDefinition *r2unity_get_type_definitions(R2UnityMetadata *meta, size_t *count); R_API Il2CppMethodDefinition *r2unity_get_method_definitions(R2UnityMetadata *meta, size_t *count); R_API Il2CppFieldDefinition *r2unity_get_field_definitions(R2UnityMetadata *meta, size_t *count); +R_API Il2CppParameterDefinition *r2unity_get_parameter_definitions(R2UnityMetadata *meta, size_t *count); +R_API char *r2unity_type_name_from_index(R2UnityMetadata *meta, const Il2CppTypeDefinition *types, size_t type_count, int32_t type_index, bool fallback); +R_API char *r2unity_method_signature(R2UnityMetadata *meta, const Il2CppMethodDefinition *method, const Il2CppTypeDefinition *owner, size_t owner_index, const Il2CppTypeDefinition *types, size_t type_count, const Il2CppParameterDefinition *parameters, size_t parameter_count, bool fallback); R_API int32_t *r2unity_get_type_index_table(R2UnityMetadata *meta, R2UMetadataSectionId id, size_t *count); R_API Il2CppImageDefinition *r2unity_get_images(R2UnityMetadata *meta, size_t *count); R_API int *r2unity_build_type_image_map(const Il2CppImageDefinition *images, size_t image_count, size_t type_count); diff --git a/src/r2/bin_r2unity.c b/src/r2/bin_r2unity.c index 35d0365..653758b 100644 --- a/src/r2/bin_r2unity.c +++ b/src/r2/bin_r2unity.c @@ -835,17 +835,32 @@ static RBinSymbol *new_symbol(const char *name, ut64 paddr, ut64 size, const cha if (!sym) { return NULL; } +#if R2_ABIVERSION >= 138 + sym->attr.size = (ut32)R_MIN (size, UT32_MAX); + sym->attr.flags = attr; + sym->attr.lang = R_BIN_LANG_NONE; +#else sym->size = (ut32)R_MIN (size, UT32_MAX); - sym->type = type; sym->attr = attr; - sym->ordinal = ordinal; sym->lang = R_BIN_LANG_NONE; +#endif + sym->type = type; + sym->ordinal = ordinal; if (classname) { sym->classname = strdup (classname); } return sym; } +static void set_symbol_signature(RBinSymbol *sym, const char *name, const char *signature) { + if (!sym || !sym->name || !name || !signature) { + return; + } + free (sym->name->name); + sym->name->name = strdup (name); + r_bin_name_update (sym->name, signature); +} + #if R2UNITY_BIN_VEC_ABI typedef RVecRBinSymbol R2UnitySymbolSink; @@ -1016,6 +1031,8 @@ static bool symbols_fill(RBinFile *bf, R2UnitySymbolSink *ret) { size_t method_count = 0; Il2CppMethodDefinition *methods = r2unity_get_method_definitions (meta, &method_count); + size_t parameter_count = 0; + Il2CppParameterDefinition *parameters = r2unity_get_parameter_definitions (meta, ¶meter_count); ut64 method_entry = r2unity_metadata_section_entry_size (meta, R2U_SEC_METHODS); Il2CppMetadataSection method_sec; r2unity_metadata_section (meta, R2U_SEC_METHODS, &method_sec); @@ -1036,12 +1053,29 @@ static bool symbols_fill(RBinFile *bf, R2UnitySymbolSink *ret) { classname = r2unity_type_fullname (meta, td, type_idx, R2U_NAME_FALLBACK_TYPE); } RBinSymbol *sym = new_symbol (name, method_sec.offset + i * method_entry, method_entry, R_BIN_TYPE_METH_STR, method_attr (methods[i].flags, mn), classname, ordinal++); + if (sym) { + char *signature = r2unity_method_signature (meta, &methods[i], td, type_idx, + types, type_count, parameters, parameter_count, true); + set_symbol_signature (sym, name, signature); + free (signature); + sym->rtype = r2unity_type_name_from_index (meta, types, type_count, + methods[i].returnType, true); +#if R2_ABIVERSION >= 138 + sym->attr.lang = R_BIN_LANG_CIL; + sym->arg_count = methods[i].parameterCount + + ((methods[i].flags & 0x0010)? 0: 1); + sym->cc_arg_count = sym->arg_count; + sym->ret_count = sym->rtype && !strcmp (sym->rtype, "void")? 0: 1; + sym->arg_prefix = "a"; +#endif + } append_symbol (ret, sym); free (classname); free (mn); free (name); } + R_FREE (parameters); R_FREE (methods); R_FREE (types); R_FREE (asms); @@ -1087,7 +1121,11 @@ static RList *classes(RBinFile *bf) { if (klass) { klass->index = (int)i; klass->addr = type->offset; +#if R2_ABIVERSION >= 138 + klass->attr.lang = R_BIN_LANG_NONE; +#else klass->lang = R_BIN_LANG_NONE; +#endif r_list_append (ret, klass); } free (name); @@ -1100,7 +1138,11 @@ static RList *classes(RBinFile *bf) { RBinClass *klass = r_bin_class_new (name, NULL, R_BIN_ATTR_NONE); klass->index = (int)i; klass->addr = obj->bgdb->tables[i].offset; +#if R2_ABIVERSION >= 138 + klass->attr.lang = R_BIN_LANG_NONE; +#else klass->lang = R_BIN_LANG_NONE; +#endif r_list_append (ret, klass); free (name); } @@ -1115,6 +1157,10 @@ static RList *classes(RBinFile *bf) { Il2CppTypeDefinition *types = r2unity_get_type_definitions (meta, &type_count); size_t method_count = 0; Il2CppMethodDefinition *methods = r2unity_get_method_definitions (meta, &method_count); + size_t parameter_count = 0; + Il2CppParameterDefinition *parameters = r2unity_get_parameter_definitions (meta, ¶meter_count); + size_t field_count = 0; + Il2CppFieldDefinition *fields = r2unity_get_field_definitions (meta, &field_count); Il2CppMetadataSection type_sec; Il2CppMetadataSection method_sec; r2unity_metadata_section (meta, R2U_SEC_TYPE_DEFINITIONS, &type_sec); @@ -1125,16 +1171,48 @@ static RList *classes(RBinFile *bf) { for (size_t i = 0; types && i < type_count; i++) { char *ns = get_string (obj, types[i].namespaceIndex); char *tn = get_string (obj, types[i].nameIndex); + char *base = r2unity_type_name_from_index (meta, types, type_count, + types[i].parentIndex, false); char *fallback = NULL; if (!tn || !*tn) { fallback = r_str_newf ("type.%zu", i); } - RBinClass *klass = r_bin_class_new ((tn && *tn)? tn: fallback, NULL, type_attr (types[i].flags)); + RBinClass *klass = r_bin_class_new ((tn && *tn)? tn: fallback, base, type_attr (types[i].flags)); klass->index = (int)i; klass->addr = type_sec.offset + i * type_entry; - klass->lang = R_BIN_LANG_NONE; +#if R2_ABIVERSION >= 138 + klass->attr.lang = R_BIN_LANG_CIL; +#else + klass->lang = R_BIN_LANG_CIL; +#endif if (ns && *ns) { +#if R2_ABIVERSION >= 138 + klass->attr.ns = strdup (ns); +#else klass->ns = strdup (ns); +#endif + } + int field_start = types[i].fieldStart; + int fields_in_type = types[i].field_count; + for (int k = 0; fields && k < fields_in_type && field_start >= 0 + && (size_t)(field_start + k) < field_count; k++) { + size_t fi = (size_t)(field_start + k); + char *field_name = get_string (obj, fields[fi].nameIndex); + char *field_type = r2unity_type_name_from_index (meta, types, type_count, + fields[fi].typeIndex, true); +#if R2UNITY_BIN_VEC_ABI + RBinField *field = RVecRBinField_emplace_back (&klass->fields); + if (field) { + field->name = r_bin_name_new (R_STR_ISNOTEMPTY (field_name)? field_name: "field"); + field->type = r_bin_name_new (R_STR_ISNOTEMPTY (field_type)? field_type: "unknown"); +#if R2_ABIVERSION >= 138 + field->attr.kind = R_BIN_FIELD_KIND_FIELD; + field->attr.lang = R_BIN_LANG_CIL; +#endif + } +#endif + free (field_type); + free (field_name); } int start = types[i].methodStart; int count = types[i].method_count; @@ -1149,16 +1227,35 @@ static RList *classes(RBinFile *bf) { char *mname = r2unity_method_fullname (meta, &methods[mi], td, type_idx, R2U_NAME_WITH_PARAMS | R2U_NAME_FALLBACK_TYPE); char *raw = get_string (obj, methods[mi].nameIndex); RBinSymbol *sym = new_symbol (mname? mname: raw, method_sec.offset + mi * method_entry, method_entry, R_BIN_TYPE_METH_STR, method_attr (methods[mi].flags, raw), NULL, (int)mi); + if (sym) { + char *signature = r2unity_method_signature (meta, &methods[mi], td, type_idx, + types, type_count, parameters, parameter_count, true); + set_symbol_signature (sym, mname? mname: raw, signature); + free (signature); + sym->rtype = r2unity_type_name_from_index (meta, types, type_count, + methods[mi].returnType, true); +#if R2_ABIVERSION >= 138 + sym->attr.lang = R_BIN_LANG_CIL; + sym->arg_count = methods[mi].parameterCount + + ((methods[mi].flags & 0x0010)? 0: 1); + sym->cc_arg_count = sym->arg_count; + sym->ret_count = sym->rtype && !strcmp (sym->rtype, "void")? 0: 1; + sym->arg_prefix = "a"; +#endif + } append_class_method (klass, sym); free (raw); free (mname); } r_list_append (ret, klass); + free (base); free (fallback); free (tn); free (ns); } + R_FREE (fields); + R_FREE (parameters); R_FREE (methods); R_FREE (types); return ret; diff --git a/src/r2/core_r2unity.c b/src/r2/core_r2unity.c index dc6339d..5ce7a5e 100644 --- a/src/r2/core_r2unity.c +++ b/src/r2/core_r2unity.c @@ -441,26 +441,8 @@ static bool enrich_reverse_pinvokes_native(RCore *core, R2UnityMetadata *meta, c return path && *path && r2unity_enrich_reverse_pinvokes_native (meta, path, &opts, items, count); } -static int type_definition_for_type_index(const Il2CppTypeDefinition *types, size_t type_count, int32_t type_index) { - if (type_index >= 0) { - for (size_t i = 0; i < type_count; i++) { - if (types[i].byvalTypeIndex == type_index) { - return (int)i; - } - } - } - return -1; -} - static char *type_name_from_index(R2UnityMetadata *meta, const Il2CppTypeDefinition *types, size_t type_count, int32_t type_index, bool fallback) { - int idx = type_definition_for_type_index (types, type_count, type_index); - if (idx >= 0) { - return r2unity_type_fullname (meta, &types[idx], (size_t)idx, R2U_NAME_FALLBACK_TYPE); - } - if (fallback && type_index >= 0) { - return r_str_newf ("type_index.%d", type_index); - } - return NULL; + return r2unity_type_name_from_index (meta, types, type_count, type_index, fallback); } static char *field_name_or_fallback(R2UnityMetadata *meta, const Il2CppFieldDefinition *field, size_t index) { @@ -832,6 +814,8 @@ static int cmd_symbols(RCore *core, char mode) { Il2CppTypeDefinition *types = r2unity_get_type_definitions (meta, &type_count); size_t method_count = 0; Il2CppMethodDefinition *methods = r2unity_get_method_definitions (meta, &method_count); + size_t parameter_count = 0; + Il2CppParameterDefinition *parameters = r2unity_get_parameter_definitions (meta, ¶meter_count); size_t img_count = 0; Il2CppImageDefinition *images = r2unity_get_images (meta, &img_count); @@ -876,12 +860,16 @@ static int cmd_symbols(RCore *core, char mode) { if (!fullname) { continue; } + char *signature = r2unity_method_signature (meta, m, td, type_idx, + types, type_count, parameters, parameter_count, true); + char *return_type = r2unity_type_name_from_index (meta, types, type_count, + m->returnType, true); char *imgname = img? r2unity_get_string (meta, img->nameIndex): NULL; char flag_buf[1024]; if (imgname && *imgname) { - snprintf (flag_buf, sizeof (flag_buf), "sym.unity.%s.%s", imgname, fullname); + snprintf (flag_buf, sizeof (flag_buf), "sym.unity.%s.%s.%zu", imgname, fullname, j); } else { - snprintf (flag_buf, sizeof (flag_buf), "sym.unity.%s", fullname); + snprintf (flag_buf, sizeof (flag_buf), "sym.unity.%s.%zu", fullname, j); } r_name_filter (flag_buf, -1); @@ -890,6 +878,33 @@ static int cmd_symbols(RCore *core, char mode) { if (mode == 'j') { pj_o (pj); pj_ks (pj, "name", fullname); + pj_kn (pj, "index", (ut64)j); + pj_hex (pj, "token", m->token, 8); + pj_string_or_null (pj, "signature", signature); + pj_string_or_null (pj, "return_type", return_type); + pj_kb (pj, "static", (m->flags & 0x0010) != 0); + pj_ka (pj, "parameters"); + for (size_t k = 0; k < m->parameterCount; k++) { + st64 pi = (st64)m->parameterStart + (st64)k; + const Il2CppParameterDefinition *parameter = pi >= 0 && (ut64)pi < parameter_count + ? ¶meters[pi]: NULL; + char *parameter_name = parameter? r2unity_get_string (meta, parameter->nameIndex): NULL; + char *parameter_type = parameter + ? r2unity_type_name_from_index (meta, types, type_count, parameter->typeIndex, true) + : NULL; + pj_o (pj); + pj_kn (pj, "index", k); + if (parameter) { + pj_ki (pj, "type_index", parameter->typeIndex); + pj_hex (pj, "token", parameter->token, 8); + } + pj_string_or_null (pj, "name", parameter_name); + pj_string_or_null (pj, "type", parameter_type); + pj_end (pj); + free (parameter_type); + free (parameter_name); + } + pj_end (pj); pj_ks (pj, "flag", flag_buf); if (imgname) { pj_ks (pj, "image", imgname); @@ -903,11 +918,11 @@ static int cmd_symbols(RCore *core, char mode) { if (addr > 0x1000) { r_cons_printf (core->cons, "'@0x%" PFMT64x "'f %s\n", addr, flag_buf); if (imgname && *imgname) { - r_cons_printf (core->cons, "'@0x%" PFMT64x "'CCu Method: [%s]%s%s %s\n", addr, imgname, *attrs? " ": "", attrs, fullname); + r_cons_printf (core->cons, "'@0x%" PFMT64x "'CCu Method: [%s]%s%s %s\n", addr, imgname, *attrs? " ": "", attrs, signature? signature: fullname); } else if (*attrs) { - r_cons_printf (core->cons, "'@0x%" PFMT64x "'CCu Method: %s %s\n", addr, attrs, fullname); + r_cons_printf (core->cons, "'@0x%" PFMT64x "'CCu Method: %s %s\n", addr, attrs, signature? signature: fullname); } else { - r_cons_printf (core->cons, "'@0x%" PFMT64x "'CCu Method: %s\n", addr, fullname); + r_cons_printf (core->cons, "'@0x%" PFMT64x "'CCu Method: %s\n", addr, signature? signature: fullname); } listed++; } @@ -921,11 +936,11 @@ static int cmd_symbols(RCore *core, char mode) { imgname, *attrs? " ": "", attrs, - fullname); + signature? signature: fullname); } else if (*attrs) { - comment = r_str_newf ("Method: %s %s", attrs, fullname); + comment = r_str_newf ("Method: %s %s", attrs, signature? signature: fullname); } else { - comment = r_str_newf ("Method: %s", fullname); + comment = r_str_newf ("Method: %s", signature? signature: fullname); } if (comment) { r_meta_set_string (core->anal, R_META_TYPE_COMMENT, addr, comment); @@ -937,6 +952,8 @@ static int cmd_symbols(RCore *core, char mode) { free (attrs); free (imgname); + free (return_type); + free (signature); free (fullname); } @@ -956,6 +973,7 @@ static int cmd_symbols(RCore *core, char mode) { r2unity_native_result_fini (&native_result); R_FREE (type2img); R_FREE (images); + R_FREE (parameters); R_FREE (methods); R_FREE (types); close_metadata (meta, buf);