6 Commits
9 changed files with 838 additions and 238 deletions

No files matched your search

+1 -1
View File
@@ -1,7 +1,7 @@
project(
'r2unity',
'c',
version: '1.2.0',
version: '1.2.2',
default_options: [
'c_std=c99',
'warning_level=2',
+3 -1
View File
@@ -282,7 +282,9 @@ bool r2unity_find_method_pointers_elf(R2UnityMetadata *meta, const char *path, c
};
size_t section_count = 0;
R2UnityNativeSection *sections = elf_sections (&e, &section_count);
bool ok = r2unity_native_run_view (meta, &view, sections, section_count, options, result);
view.sections = sections;
view.section_count = section_count;
bool ok = r2unity_native_resolve (meta, &view, NULL, options, result);
R_FREE (sections);
elf_free (&e);
return ok;
+4 -1
View File
@@ -140,6 +140,7 @@ static R2UnityNativeSection *macho_sections(MachO *mo, size_t *count) {
for (size_t i = 0; i < mo->nsegs; i++) {
const MachSeg *s = &mo->segs[i];
ut64 vsize = s->vmsize? s->vmsize: s->filesize;
out[i].name = s->name;
out[i].vaddr = s->vmaddr;
out[i].vsize = vsize;
out[i].size = R_MIN (s->filesize, vsize);
@@ -169,7 +170,9 @@ bool r2unity_find_method_pointers_macho(R2UnityMetadata *meta, const char *path,
};
size_t section_count = 0;
R2UnityNativeSection *sections = macho_sections (&mo, &section_count);
bool ok = r2unity_native_run_view (meta, &view, sections, section_count, options, result);
view.sections = sections;
view.section_count = section_count;
bool ok = r2unity_native_resolve (meta, &view, NULL, options, result);
R_FREE (sections);
macho_free (&mo);
return ok;
+607 -190
View File
File diff suppressed because it is too large. Load diff
+5 -7
View File
@@ -14,9 +14,12 @@ typedef struct {
ut64 base_vaddr;
ut64 text_lo;
ut64 text_hi;
const struct r2unity_native_section_t *sections;
size_t section_count;
} R2UnityNativeView;
typedef struct {
typedef struct r2unity_native_section_t {
const char *name;
ut64 vaddr;
ut64 vsize;
ut64 size;
@@ -24,12 +27,7 @@ typedef struct {
bool is_data;
} R2UnityNativeSection;
bool r2unity_native_parse_code_registration(R2UnityMetadata *meta, R2UnityNativeView *view, ut64 code_registration_va, R2UnityNativeSource source, R2UnityNativeResult *result);
ut64 r2unity_native_resolve_override(const R2UnityNativeOptions *options, const char *const *names);
bool r2unity_native_result_has_ptrs(const R2UnityNativeResult *result);
void r2unity_native_take_heuristic_result(R2UnityNativeResult *result, ut64 *method_ptrs, int ptr_size);
bool r2unity_native_scan_sections(R2UnityMetadata *meta, R2UnityNativeView *view, const R2UnityNativeSection *sections, size_t section_count, R2UnityNativeResult *result);
bool r2unity_native_run_view(R2UnityMetadata *meta, R2UnityNativeView *view, const R2UnityNativeSection *sections, size_t section_count, const R2UnityNativeOptions *options, R2UnityNativeResult *result);
bool r2unity_native_resolve(R2UnityMetadata *meta, R2UnityNativeView *view, RBinFile *bf, const R2UnityNativeOptions *options, R2UnityNativeResult *result);
bool r2unity_find_method_pointers_elf(R2UnityMetadata *meta, const char *path, const R2UnityNativeOptions *options, R2UnityNativeResult *result);
bool r2unity_find_method_pointers_macho(R2UnityMetadata *meta, const char *path, const R2UnityNativeOptions *options, R2UnityNativeResult *result);
bool r2unity_find_method_pointers_pe(R2UnityMetadata *meta, const char *path, const R2UnityNativeOptions *options, R2UnityNativeResult *result);
+4 -1
View File
@@ -146,6 +146,7 @@ static R2UnityNativeSection *pe_sections(PeImg *pe, size_t *count) {
for (size_t i = 0; i < pe->nsecs; i++) {
const PeSec *s = &pe->secs[i];
ut64 vsize = s->vsize? s->vsize: s->filesize;
out[i].name = s->name;
out[i].vaddr = s->vaddr;
out[i].vsize = vsize;
out[i].size = R_MIN (s->filesize, vsize);
@@ -175,7 +176,9 @@ bool r2unity_find_method_pointers_pe(R2UnityMetadata *meta, const char *path, co
};
size_t section_count = 0;
R2UnityNativeSection *sections = pe_sections (&pe, &section_count);
bool ok = r2unity_native_run_view (meta, &view, sections, section_count, options, result);
view.sections = sections;
view.section_count = section_count;
bool ok = r2unity_native_resolve (meta, &view, NULL, options, result);
R_FREE (sections);
pe_free (&pe);
return ok;
+27 -5
View File
@@ -3,8 +3,10 @@
#include <r_util.h>
struct r_bin_t;
struct r_bin_file_t;
#if !defined(R2_BIN_H) && !defined(R2_BIN_DWARF_H)
typedef struct r_bin_t RBin;
typedef struct r_bin_file_t RBinFile;
#endif
#define IL2CPP_MAGIC 0xFAB11BAF
#define R2UNITY_METADATA_BASE_SECTION_COUNT 31
@@ -170,8 +172,7 @@ typedef struct {
enum {
R2U_INTEROP_PINVOKE = 1, /* managed -> native, [DllImport] */
R2U_INTEROP_REVERSE_PINVOKE = 2, /* native -> managed, [MonoPInvokeCallback] */
R2U_INTEROP_UNMANAGED_ONLY = 3, /* [UnmanagedCallersOnly] (.NET 5+) */
R2U_INTEROP_INTEROP_DATA = 4 /* Il2CppInteropData entry (opaque) */
R2U_INTEROP_UNMANAGED_ONLY = 3 /* [UnmanagedCallersOnly] (.NET 5+) */
};
/* A single P/Invoke or reverse-P/Invoke entry.
@@ -209,6 +210,24 @@ typedef enum {
R2U_NATIVE_SOURCE_HEURISTIC
} R2UnityNativeSource;
typedef enum {
R2U_NATIVE_TABLE_REVERSE_PINVOKE_WRAPPERS,
R2U_NATIVE_TABLE_GENERIC_METHOD_POINTERS,
R2U_NATIVE_TABLE_GENERIC_ADJUSTOR_THUNKS,
R2U_NATIVE_TABLE_INVOKER_POINTERS,
R2U_NATIVE_TABLE_UNRESOLVED_VIRTUAL_CALL_POINTERS,
R2U_NATIVE_TABLE_UNRESOLVED_INSTANCE_CALL_POINTERS,
R2U_NATIVE_TABLE_UNRESOLVED_STATIC_CALL_POINTERS,
R2U_NATIVE_TABLE_INTEROP_DATA,
R2U_NATIVE_TABLE_WINDOWS_RUNTIME_FACTORY_TABLE,
R2U_NATIVE_TABLE_COUNT
} R2UnityNativeTableId;
typedef struct {
ut64 va;
ut64 count;
} R2UnityNativeTable;
typedef struct {
const char *name;
ut64 va;
@@ -230,6 +249,7 @@ typedef struct {
ut64 metadata_registration_va;
ut64 method_pointers_va;
ut64 code_gen_modules_va;
R2UnityNativeTable tables[R2U_NATIVE_TABLE_COUNT];
int ptr_size;
} R2UnityNativeResult;
@@ -255,6 +275,7 @@ R_API R2UnityInterop *r2unity_enumerate_pinvokes(R2UnityMetadata *meta, size_t *
* Returns methods tagged with [MonoPInvokeCallback] or [UnmanagedCallersOnly].
* Pre-v29 metadata returns NULL (attribute ctor args live in generator stubs). */
R_API R2UnityInterop *r2unity_enumerate_reverse_pinvokes(R2UnityMetadata *meta, size_t *count);
R_API bool r2unity_enrich_reverse_pinvokes_native(R2UnityMetadata *meta, const char *path, const R2UnityNativeOptions *options, R2UnityInterop **items, size_t *count);
R_API void r2unity_free_interop(R2UnityInterop *items, size_t count);
R_API char *r2unity_sbom_tostring(R2UnityMetadata *meta, const char *exe_path, const char *metadata_path, R2UnitySbomFormat format);
R_API const char *r2unity_unity_range_from_wire(int wire);
@@ -264,12 +285,13 @@ R_API ut64 r2unity_metadata_section_entry_size(R2UnityMetadata *meta, R2UMetadat
R_API ut64 r2unity_metadata_section_count(R2UnityMetadata *meta, R2UMetadataSectionId id);
R_API ut64 r2unity_metadata_header_size(R2UnityMetadata *meta);
R_API const char *r2unity_native_source_name(R2UnityNativeSource source);
R_API const char *r2unity_native_table_name(R2UnityNativeTableId id);
R_API const char *const *r2unity_native_code_registration_names(void);
R_API const char *const *r2unity_native_metadata_registration_names(void);
R_API void r2unity_native_result_fini(R2UnityNativeResult *result);
R_API bool r2unity_find_method_pointers(R2UnityMetadata *meta, const char *path, const R2UnityNativeOptions *options, R2UnityNativeResult *result);
R_API bool r2unity_find_method_pointers_simple(R2UnityMetadata *meta, const char *path, const R2UnityNativeOptions *options, R2UnityNativeResult *result);
R_API bool r2unity_find_method_pointers_rbin(R2UnityMetadata *meta, struct r_bin_t *bin, struct r_bin_file_t *bf, const R2UnityNativeOptions *options, R2UnityNativeResult *result);
R_API bool r2unity_find_method_pointers_rbin(R2UnityMetadata *meta, RBin *bin, RBinFile *bf, const R2UnityNativeOptions *options, R2UnityNativeResult *result);
/* Companion-file discovery.
*
+61 -21
View File
@@ -150,6 +150,18 @@ static void pj_native_result(PJ *pj, const R2UnityNativeResult *native) {
pj_kn (pj, "metadata_registration", native? native->metadata_registration_va: 0);
pj_kn (pj, "method_pointers", native? native->method_pointers_va: 0);
pj_kn (pj, "code_gen_modules", native? native->code_gen_modules_va: 0);
pj_ko (pj, "native_tables");
for (R2UnityNativeTableId i = 0; i < R2U_NATIVE_TABLE_COUNT; i++) {
const R2UnityNativeTable *table = native? &native->tables[i]: NULL;
if (!table || !table->va) {
continue;
}
pj_ko (pj, r2unity_native_table_name (i));
pj_kn (pj, "count", table->count);
pj_kn (pj, "va", table->va);
pj_end (pj);
}
pj_end (pj);
}
static void print_native_comment(const R2UnityNativeResult *native) {
@@ -265,8 +277,36 @@ static int interop_cmp(const void *a, const void *b) {
return strcmp (xn, yn);
}
static int emit_pinvokes(R2UnityMetadata *meta, const char *exe_path, bool is_json, bool is_r2, bool quiet) {
(void)exe_path;
static char *interop_flag_name(const char *prefix, const R2UnityInterop *it) {
char *name = it->image_name && *it->image_name
? r_str_newf ("%s.%s.%s", prefix, it->image_name, it->name)
: r_str_newf ("%s.%s", prefix, it->name);
if (name) {
r_name_filter (name, -1);
if (!r_name_check (name)) {
R_FREE (name);
}
}
return name;
}
static void print_interop_wrapper_flag(const char *name, ut64 wrapper_va) {
if (wrapper_va && name) {
printf ("'@0x%" PFMT64x "'f %s\n", wrapper_va, name);
printf ("'@0x%" PFMT64x "'af+ $$ %s\n", wrapper_va, name);
}
}
static void json_interop_wrapper(FILE *f, const R2UnityInterop *it) {
if (it->wrapper_va) {
fprintf (f, ",\"wrapper_va\":\"0x%" PFMT64x "\"", it->wrapper_va);
}
if (it->wrapper_index != UINT32_MAX) {
fprintf (f, ",\"wrapper_index\":%u", it->wrapper_index);
}
}
static int emit_pinvokes(R2UnityMetadata *meta, bool is_json, bool is_r2, bool quiet) {
size_t n = 0;
R2UnityInterop *items = r2unity_enumerate_pinvokes (meta, &n);
if (items && n > 1) {
@@ -309,18 +349,16 @@ static int emit_pinvokes(R2UnityMetadata *meta, const char *exe_path, bool is_js
if (!it->name) {
continue;
}
char buf[1024];
if (it->image_name && *it->image_name) {
snprintf (buf, sizeof (buf), "sym.unity.%s.%s", it->image_name, it->name);
} else {
snprintf (buf, sizeof (buf), "sym.unity.%s", it->name);
char *name = interop_flag_name ("sym.unity", it);
if (!name) {
continue;
}
r_name_filter (buf, -1);
if (it->dll_name) {
printf ("# PInvoke %s -> %s!%s\n", buf, it->dll_name, it->entry_name? it->entry_name: it->name);
printf ("# PInvoke %s -> %s!%s\n", name, it->dll_name, it->entry_name? it->entry_name: it->name);
} else {
printf ("# PInvoke %s -> <unresolved>\n", buf);
printf ("# PInvoke %s -> <unresolved>\n", name);
}
free (name);
}
} else {
if (!quiet) {
@@ -356,10 +394,12 @@ static const char *interop_kind_label(uint8_t kind) {
}
}
static int emit_reverse_pinvokes(R2UnityMetadata *meta, const char *exe_path, bool is_json, bool is_r2, bool quiet) {
(void)exe_path;
static int emit_reverse_pinvokes(R2UnityMetadata *meta, const char *exe_path, const R2UnityNativeOptions *native, bool is_json, bool is_r2, bool quiet) {
size_t n = 0;
R2UnityInterop *items = r2unity_enumerate_reverse_pinvokes (meta, &n);
if (exe_path && *exe_path) {
r2unity_enrich_reverse_pinvokes_native (meta, exe_path, native, &items, &n);
}
if (items && n > 1) {
qsort (items, n, sizeof (R2UnityInterop), interop_cmp);
}
@@ -377,6 +417,7 @@ static int emit_reverse_pinvokes(R2UnityMetadata *meta, const char *exe_path, bo
fprintf (f, "\",\"method\":\"");
json_escape (f, it->name? it->name: "");
fprintf (f, "\",\"token\":\"0x%08x\",\"flags\":\"0x%04x\",\"iflags\":\"0x%04x\",\"attribute\":\"%s\",\"confidence\":%u", it->token, it->flags, it->iflags, interop_kind_label (it->kind), (unsigned)it->confidence);
json_interop_wrapper (f, it);
fputc ('}', f);
}
fprintf (f, "]}\n");
@@ -386,14 +427,13 @@ static int emit_reverse_pinvokes(R2UnityMetadata *meta, const char *exe_path, bo
if (!it->name) {
continue;
}
char buf[1024];
if (it->image_name && *it->image_name) {
snprintf (buf, sizeof (buf), "sym.unity.reverse.%s.%s", it->image_name, it->name);
} else {
snprintf (buf, sizeof (buf), "sym.unity.reverse.%s", it->name);
char *name = interop_flag_name ("sym.unity.reverse", it);
if (!name) {
continue;
}
r_name_filter (buf, -1);
printf ("# ReversePInvoke %s [%s]\n", buf, interop_kind_label (it->kind));
printf ("# ReversePInvoke %s [%s]\n", name, interop_kind_label (it->kind));
print_interop_wrapper_flag (name, it->wrapper_va);
free (name);
}
} else {
if (!quiet) {
@@ -1083,8 +1123,8 @@ int main(int argc, char *argv[]) {
return 1;
}
int rc = reverse_pinvokes
? emit_reverse_pinvokes (meta, exe_path, json_one_line, r2_script, quiet)
: emit_pinvokes (meta, exe_path, json_one_line, r2_script, quiet);
? emit_reverse_pinvokes (meta, exe_path, &native_options, json_one_line, r2_script, quiet)
: emit_pinvokes (meta, json_one_line, r2_script, quiet);
r2unity_free_metadata (meta);
r_unref (buf);
free_symbol_overrides (&symbol_overrides);
+126 -11
View File
@@ -6,6 +6,8 @@
#include <r_lib.h>
#include "../lib/lib.h"
#define R2UNITY_NATIVE_TARGET_LIMIT 0x10000
// clang-format off
static const char *g_help_msg[] = {
"Usage:", "r2unity[-subcmd]", " Unity IL2CPP analyzer",
@@ -14,7 +16,7 @@ static const char *g_help_msg[] = {
"r2unity-c", "[*j]", "enumerate classes, inheritance, methods, and fields",
"r2unity-D", "", "auto-detect companion files from current binary path",
"r2unity-i", "[j]", "summary (metadata version, type/method counts)",
"r2unity-s", "[*j]", "apply/list managed method symbols as flags + comments",
"r2unity-s", "[*j]", "apply/list managed/native symbols as flags + comments",
"r2unity-z", "[j]", "list managed string literals",
"r2unity-P", "[*j]", "list P/Invoke (managed -> native)",
"r2unity-R", "[*j]", "list reverse-P/Invoke (native -> managed)",
@@ -163,6 +165,18 @@ static void pj_native_result(PJ *pj, const R2UnityNativeResult *result) {
pj_kn (pj, "metadata_registration", result? result->metadata_registration_va: 0);
pj_kn (pj, "method_pointers", result? result->method_pointers_va: 0);
pj_kn (pj, "code_gen_modules", result? result->code_gen_modules_va: 0);
pj_ko (pj, "native_tables");
for (R2UnityNativeTableId i = 0; i < R2U_NATIVE_TABLE_COUNT; i++) {
const R2UnityNativeTable *table = result? &result->tables[i]: NULL;
if (!table || !table->va) {
continue;
}
pj_ko (pj, r2unity_native_table_name (i));
pj_kn (pj, "count", table->count);
pj_kn (pj, "va", table->va);
pj_end (pj);
}
pj_end (pj);
}
static void print_native_result(RCore *core, const R2UnityNativeResult *result) {
@@ -175,6 +189,54 @@ static void print_native_result(RCore *core, const R2UnityNativeResult *result)
result? result->code_gen_modules_va: 0);
}
static void native_flag(RCore *core, bool print, const char *name, ut64 addr, ut32 size) {
if (print) {
r_cons_printf (core->cons, "'@0x%08"PFMT64x"'f %s %u\n", addr, name, size);
} else {
r_flag_set (core->flags, name, addr, size);
}
}
static void apply_native_tables(RCore *core, const R2UnityNativeResult *result, bool print) {
int ptr_size = result->ptr_size == 4? 4: 8;
for (R2UnityNativeTableId i = 0; i < R2U_NATIVE_TABLE_COUNT; i++) {
const R2UnityNativeTable *table = &result->tables[i];
if (!table->va) {
continue;
}
const char *name = r2unity_native_table_name (i);
ut32 size = (ut32)R_MIN ((ut64)UT32_MAX, R_MAX ((ut64)1, table->count * ptr_size));
char flag[128];
snprintf (flag, sizeof (flag), "r2unity.table.%s", name);
native_flag (core, print, flag, table->va, size);
ut64 count = R_MIN (table->count, (ut64)R2UNITY_NATIVE_TARGET_LIMIT);
if (i >= R2U_NATIVE_TABLE_INTEROP_DATA || !count) {
continue;
}
int len = (int)(count * ptr_size);
ut8 *buf = malloc (len);
if (!buf || !r_io_read_at (core->io, table->va, buf, len)) {
free (buf);
continue;
}
for (ut64 j = 0; j < count; j++) {
const ut8 *p = buf + j * ptr_size;
ut64 addr = (ptr_size == 8? r_read_le64 (p): (ut64)r_read_le32 (p)) & ~(ut64)1;
if (addr <= 0x1000 || !r_io_is_valid_offset (core->io, addr, R_PERM_X)) {
continue;
}
snprintf (flag, sizeof (flag), "sym.r2unity.%s.%" PFMT64u, name, j);
native_flag (core, print, flag, addr, 1);
if (print) {
r_cons_printf (core->cons, "'@0x%08" PFMT64x "'af+ $$ %s\n", addr, flag);
} else if (core->anal && !r_anal_get_function_at (core->anal, addr)) {
r_anal_create_function (core->anal, flag, addr, R_ANAL_FCN_TYPE_FCN, NULL);
}
}
free (buf);
}
}
/* Resolve (and on first use, cache into the eval vars) the metadata path for
* the current session. Returns a pointer owned by the RConfig, or NULL. */
static const char *resolve_metadata_path(RCore *core) {
@@ -373,6 +435,12 @@ static bool find_method_pointers(RCore *core, R2UnityMetadata *meta, const char
return ok;
}
static bool enrich_reverse_pinvokes_native(RCore *core, R2UnityMetadata *meta, const char *path, R2UnityInterop **items, size_t *count) {
R2UnityNativeOptions opts = { 0 };
native_options_from_core (core, &opts);
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++) {
@@ -786,6 +854,9 @@ static int cmd_symbols(RCore *core, char mode) {
print_native_result (core, &native_result);
}
if (mode != 'j') {
apply_native_tables (core, &native_result, mode == '*');
}
ut64 applied = 0, listed = 0;
for (size_t j = 0; j < method_count; j++) {
Il2CppMethodDefinition *m = &methods[j];
@@ -982,6 +1053,35 @@ static const char *interop_kind_label(uint8_t kind) {
}
}
static void pj_interop_wrapper(PJ *pj, const R2UnityInterop *it) {
if (it->wrapper_va) {
pj_kn (pj, "wrapper_va", it->wrapper_va);
}
if (it->wrapper_index != UINT32_MAX) {
pj_kn (pj, "wrapper_index", it->wrapper_index);
}
}
static char *interop_flag_name(const char *prefix, const R2UnityInterop *it) {
char *name = it->image_name && *it->image_name
? r_str_newf ("%s.%s.%s", prefix, it->image_name, it->name)
: r_str_newf ("%s.%s", prefix, it->name);
if (name) {
r_name_filter (name, -1);
if (!r_name_check (name)) {
R_FREE (name);
}
}
return name;
}
static void print_interop_wrapper_flag(RCore *core, const char *name, ut64 wrapper_va) {
if (wrapper_va && name) {
r_cons_printf (core->cons, "'@0x%" PFMT64x "'f %s\n", wrapper_va, name);
r_cons_printf (core->cons, "'@0x%" PFMT64x "'af+ $$ %s\n", wrapper_va, name);
}
}
static int cmd_interop(RCore *core, bool reverse, char mode) {
RBuffer *buf = NULL;
R2UnityMetadata *meta = open_metadata (core, &buf);
@@ -992,6 +1092,12 @@ static int cmd_interop(RCore *core, bool reverse, char mode) {
R2UnityInterop *items = reverse
? r2unity_enumerate_reverse_pinvokes (meta, &n)
: r2unity_enumerate_pinvokes (meta, &n);
if (reverse) {
const char *lib = resolve_library_path (core);
if (lib) {
enrich_reverse_pinvokes_native (core, meta, lib, &items, &n);
}
}
if (items && n > 1) {
qsort (items, n, sizeof (R2UnityInterop), interop_cmp);
}
@@ -1022,6 +1128,7 @@ static int cmd_interop(RCore *core, bool reverse, char mode) {
pj_kn (pj, "flags", (ut64)it->flags);
pj_kn (pj, "iflags", (ut64)it->iflags);
pj_kn (pj, "confidence", (ut64)it->confidence);
pj_interop_wrapper (pj, it);
if (reverse) {
pj_ks (pj, "attribute", interop_kind_label (it->kind));
} else {
@@ -1039,27 +1146,35 @@ static int cmd_interop(RCore *core, bool reverse, char mode) {
pj_end (pj);
} else if (mode == '*') {
if (it->name) {
char flag_buf[1024];
const char *prefix = reverse? "sym.unity.reverse": "sym.unity";
if (it->image_name && *it->image_name) {
snprintf (flag_buf, sizeof (flag_buf), "%s.%s.%s", prefix, it->image_name, it->name);
} else {
snprintf (flag_buf, sizeof (flag_buf), "%s.%s", prefix, it->name);
char *name = interop_flag_name (prefix, it);
if (!name) {
free (attrs);
continue;
}
r_name_filter (flag_buf, -1);
if (reverse) {
r_cons_printf (core->cons, "# ReversePInvoke %s [%s]\n", flag_buf, interop_kind_label (it->kind));
r_cons_printf (core->cons, "# ReversePInvoke %s [%s]\n", name, interop_kind_label (it->kind));
} else if (it->dll_name) {
r_cons_printf (core->cons, "# PInvoke %s -> %s!%s\n", flag_buf, it->dll_name, it->entry_name? it->entry_name: it->name);
r_cons_printf (core->cons, "# PInvoke %s -> %s!%s\n", name, it->dll_name, it->entry_name? it->entry_name: it->name);
} else {
r_cons_printf (core->cons, "# PInvoke %s -> <unresolved>\n", flag_buf);
r_cons_printf (core->cons, "# PInvoke %s -> <unresolved>\n", name);
}
if (reverse) {
print_interop_wrapper_flag (core, name, it->wrapper_va);
}
free (name);
}
} else {
if (reverse) {
r_cons_printf (core->cons, "%s\t%s\t%s\t%s\t%u\n", it->image_name? it->image_name: "", it->name? it->name: "", interop_kind_label (it->kind), *attrs? attrs: "-", (unsigned)it->confidence);
} else {
r_cons_printf (core->cons, "%s\t%s\t%s\t%s\t%s\t%u\n", it->image_name? it->image_name: "", it->name? it->name: "", it->dll_name? it->dll_name: "<unresolved>", it->entry_name? it->entry_name: "<default>", *attrs? attrs: "-", (unsigned)it->confidence);
r_cons_printf (core->cons, "%s\t%s\t%s\t%s\t%s\t%u\n",
it->image_name? it->image_name: "",
it->name? it->name: "",
it->dll_name? it->dll_name: "<unresolved>",
it->entry_name? it->entry_name: "<default>",
*attrs? attrs: "-",
(unsigned)it->confidence);
}
}
free (attrs);