Skip to content

Commit b129962

Browse files
committed
Preserve and prefer exact DWARF function types ##analysis
1 parent b2ff269 commit b129962

2 files changed

Lines changed: 296 additions & 27 deletions

File tree

libr/anal/dwarf_process.c

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <ctype.h>
44
#include <r_anal.h>
5+
#include <r_anal_priv.h>
56
#include <r_bin_dwarf.h>
67

78
typedef struct dwarf_parse_context_t {
@@ -13,6 +14,7 @@ typedef struct dwarf_parse_context_t {
1314
HtUP/*<offset, RBinDwarfLocList*>*/ *locations;
1415
const char *lang; // for demangling
1516
RArena *arena;
17+
Sdb *pass_sdb;
1618
} Context;
1719

1820
typedef struct dwarf_function_t {
@@ -1614,14 +1616,18 @@ static bool dwarf_function_type_matches(Sdb *types, const char *name, const char
16141616
return true;
16151617
}
16161618

1617-
static char *dwarf_function_type_name(Context *ctx, const char *sname, const Function *dwarf_fcn, const char *ret_type, RList/*<Variable*>*/ *variables, bool has_unspecified_parameters) {
1619+
static char *dwarf_function_type_name(Context *ctx, const char *sname, const Function *dwarf_fcn, const char *ret_type, RList/*<Variable*>*/ *variables, bool has_unspecified_parameters, bool seen_in_pass) {
16181620
R_RETURN_VAL_IF_FAIL (ctx && ctx->anal && sname && dwarf_fcn && ret_type && variables, NULL);
16191621
Sdb *types = ctx->anal->sdb_types;
16201622
const char *previous_name = sdb_const_getf (ctx->sdb, NULL, "fcn.%s.name", sname);
16211623
const char *previous = sdb_const_getf (ctx->sdb, NULL, "fcn.%s.typed_name", sname);
16221624
const ut64 previous_addr = sdb_num_getf (ctx->sdb, NULL, "fcn.%s.addr", sname);
16231625
if (previous_name && !strcmp (previous_name, dwarf_fcn->name)
1624-
&& previous && previous_addr == dwarf_fcn->addr) {
1626+
&& previous && previous_addr == dwarf_fcn->addr
1627+
&& (!seen_in_pass
1628+
|| dwarf_function_type_matches (types, previous, ret_type,
1629+
variables, has_unspecified_parameters)
1630+
|| sdb_const_getf (ctx->pass_sdb, NULL, "type.%s.quality", previous))) {
16251631
return strdup (previous);
16261632
}
16271633
char *name = sanitize_c_identifier (dwarf_fcn->name);
@@ -1731,6 +1737,8 @@ static void import_dwarf_function_type(Context *ctx, const char *sname, const ch
17311737
sdb_setf (ctx->sdb, csig, 0, "fcn.%s.csig", sname);
17321738
r_strbuf_fini (&args_buf);
17331739

1740+
const char *pass_quality = sdb_const_getf (ctx->pass_sdb, NULL,
1741+
"type.%s.quality", typed_name);
17341742
const bool type_existed = !!sdb_const_get (anal->sdb_types, typed_name, 0);
17351743
if (!type_existed) {
17361744
/* Only attempt C parsing for C-like languages. Non-C languages
@@ -1759,21 +1767,28 @@ static void import_dwarf_function_type(Context *ctx, const char *sname, const ch
17591767
if (!r_type_func_exist (anal->sdb_types, typed_name)) {
17601768
(void)import_dwarf_function_fallback (anal, typed_name, ret_type, variables, has_unspecified_parameters);
17611769
}
1770+
if (r_type_func_exist (anal->sdb_types, typed_name)) {
1771+
sdb_setf (ctx->pass_sdb, dwarf_fcn->prototype_complete? "complete": "incomplete", 0,
1772+
"type.%s.quality", typed_name);
1773+
}
1774+
} else if (pass_quality && !strcmp (pass_quality, "incomplete")
1775+
&& dwarf_fcn->prototype_complete
1776+
&& !dwarf_function_type_matches (anal->sdb_types, typed_name,
1777+
ret_type, variables, has_unspecified_parameters)) {
1778+
/* Only a function record created by an inferior DIE in this pass is
1779+
replaceable. Registered and prior-pass types remain untouched. */
1780+
(void)r_anal_function_del_signature (anal, typed_name);
1781+
(void)import_dwarf_function_fallback (anal, typed_name, ret_type, variables, has_unspecified_parameters);
1782+
sdb_setf (ctx->pass_sdb, "complete", 0, "type.%s.quality", typed_name);
1783+
} else if (pass_quality && dwarf_fcn->prototype_complete) {
1784+
sdb_setf (ctx->pass_sdb, "complete", 0, "type.%s.quality", typed_name);
17621785
}
17631786
const bool type_matches = dwarf_fcn->prototype_complete
17641787
&& dwarf_function_type_matches (anal->sdb_types, typed_name,
17651788
ret_type, variables, has_unspecified_parameters);
1766-
const char *linked = sdb_const_getf (anal->sdb_types, NULL,
1767-
"fcnlink.%08" PFMT64x, dwarf_fcn->addr);
17681789
if (type_matches) {
17691790
sdb_setf (anal->sdb_types, typed_name, 0,
17701791
"fcnlink.%08" PFMT64x, dwarf_fcn->addr);
1771-
} else if (linked && !strcmp (linked, typed_name)) {
1772-
char *link_key = r_str_newf ("fcnlink.%08" PFMT64x, dwarf_fcn->addr);
1773-
if (link_key) {
1774-
sdb_unset (anal->sdb_types, link_key, 0);
1775-
}
1776-
free (link_key);
17771792
}
17781793
free (csig);
17791794
}
@@ -1787,8 +1802,25 @@ static void sdb_save_dwarf_function(Context *ctx, Function *dwarf_fcn, const cha
17871802
free (real_name);
17881803
return;
17891804
}
1805+
const char *pass_name = sdb_const_getf (ctx->pass_sdb, NULL,
1806+
"fcn.%08" PFMT64x ".%s.name", dwarf_fcn->addr, sname);
1807+
const bool seen_in_pass = pass_name && !strcmp (pass_name, real_name);
1808+
const char *pass_quality = seen_in_pass
1809+
? sdb_const_getf (ctx->pass_sdb, NULL,
1810+
"fcn.%08" PFMT64x ".%s.quality", dwarf_fcn->addr, sname)
1811+
: NULL;
1812+
if (pass_quality && (!strcmp (pass_quality, "complete")
1813+
|| !dwarf_fcn->prototype_complete)) {
1814+
free (real_name);
1815+
free (sname);
1816+
return;
1817+
}
1818+
sdb_setf (ctx->pass_sdb, real_name, 0,
1819+
"fcn.%08" PFMT64x ".%s.name", dwarf_fcn->addr, sname);
1820+
sdb_setf (ctx->pass_sdb, dwarf_fcn->prototype_complete? "complete": "incomplete", 0,
1821+
"fcn.%08" PFMT64x ".%s.quality", dwarf_fcn->addr, sname);
17901822
char *typed_name = dwarf_function_type_name (ctx, sname, dwarf_fcn,
1791-
ret_type, variables, has_unspecified_parameters);
1823+
ret_type, variables, has_unspecified_parameters, seen_in_pass);
17921824
sdb_set (sdb, sname, "fcn", 0);
17931825

17941826
char *addr_val = r_str_newf ("0x%" PFMT64x, dwarf_fcn->addr);
@@ -2105,8 +2137,13 @@ static void parse_type_entry(Context *ctx, ut64 idx) {
21052137
*/
21062138
R_API void r_anal_dwarf_process_info(const RAnal *anal, RAnalDwarfContext *ctx) {
21072139
R_RETURN_IF_FAIL (ctx && anal);
2140+
r_anal_types_ensure_loaded ((RAnal *)anal);
21082141
Sdb *dwarf_sdb = sdb_ns (anal->sdb, "dwarf", 1);
21092142
sdb_unset_like (anal->sdb_types, "fcnlink.*");
2143+
Sdb *pass_sdb = sdb_new0 ();
2144+
if (!pass_sdb) {
2145+
return;
2146+
}
21102147

21112148
const RBinDwarfDebugInfo *info = ctx->info;
21122149
const RBinDwarfCompUnit *unit;
@@ -2120,13 +2157,15 @@ R_API void r_anal_dwarf_process_info(const RAnal *anal, RAnalDwarfContext *ctx)
21202157
.sdb = dwarf_sdb,
21212158
.locations = ctx->loc,
21222159
.lang = NULL,
2123-
.arena = arena
2160+
.arena = arena,
2161+
.pass_sdb = pass_sdb
21242162
};
21252163
R_VEC_FOREACH_I (unit->dies, j) {
21262164
parse_type_entry (&dw_context, j);
21272165
}
21282166
}
21292167
r_arena_free (arena);
2168+
sdb_free (pass_sdb);
21302169
}
21312170

21322171
bool filter_sdb_function_names(void *user, const char *k, const char *v) {

0 commit comments

Comments
 (0)