From ac388acdeba9713ae8381351d52fc8ac2be6ae9d Mon Sep 17 00:00:00 2001 From: NOT XVilka Date: Wed, 10 Jun 2026 11:55:21 +0800 Subject: [PATCH] Fix PDB virtual functions recognition in analysis (#6472) Co-authored-by: Anton Kochkov --- librz/arch/fcn.c | 6 ++++ librz/core/cpdb.c | 55 +++++++++++++++++++++++++++-- test/db/cmd/cmd_idp | 16 +++++++-- test/db/formats/dmp/dmp | 76 ++++++++++++++++++++--------------------- test/db/formats/pdb | 30 +++++----------- 5 files changed, 120 insertions(+), 63 deletions(-) diff --git a/librz/arch/fcn.c b/librz/arch/fcn.c index 55d00523b7..af3392ed46 100644 --- a/librz/arch/fcn.c +++ b/librz/arch/fcn.c @@ -563,6 +563,12 @@ static inline bool jumps_to_prelude(RzAnalysis *analysis, ut64 jmp_addr) { static inline bool jump_leaves_mapped_mem(RzAnalysis *analysis, ut64 insn_addr, ut64 jump_target) { rz_return_val_if_fail(analysis, false); RzIOMap *map = analysis->iob.map_get(analysis->iob.io, insn_addr); + if (!map) { + // The instruction itself is not part of any mapped region (e.g. analysis + // walked into a hole of a sparse address space such as a crash dump). + // Treat the jump as leaving mapped memory so we stop following it. + return true; + } return (jump_target < map->itv.addr || jump_target >= map->itv.addr + map->itv.size); } diff --git a/librz/core/cpdb.c b/librz/core/cpdb.c index ea7fcdcb47..6d8ad07cea 100644 --- a/librz/core/cpdb.c +++ b/librz/core/cpdb.c @@ -214,7 +214,7 @@ static void rz_core_bin_pdb_gvars_print(RzPdb *pdb, const ut64 baddr, RzCmdState } typedef struct { - const RzCore *core; + RzCore *core; const ut64 baddr; const char *file; } PDBLoadContext; @@ -287,8 +287,53 @@ static bool symbol_load(RzPdb *pdb, const PDBSymbol *symbol, void *u) { return true; } +/** + * \brief Second-pass callback that turns PDB public function symbols into + * analyzed functions. + * + * The PDB explicitly marks public symbols that are functions (cvpsfFunction). + * Some of these (e.g. virtual methods only reached through a vtable) are never + * discovered by call-following code analysis, so without this they would be + * present only as a flag and never show up as a function. This mirrors how + * \ref rz_core_analysis_all turns FUNC bin symbols into functions: it triggers + * analysis at the address and lets the already-set PDB flag name the function. + * + * This must run after all symbol flags have been set (see \ref pdb_symbols_load) + * so that functions reached by direct calls from here are also named correctly. + */ +static bool symbol_make_function(RzPdb *pdb, const PDBSymbol *symbol, void *u) { + if (!symbol || symbol->kind != PDB_Public) { + return true; + } + const PDBSPublic *public = symbol->data; + if (!public || !public->function || RZ_STR_ISEMPTY(public->name)) { + return true; + } + PDBLoadContext *ctx = u; + RzCore *core = ctx->core; + ut64 addr = rz_bin_pdb_to_rva(pdb, &public->offset); + if (addr == UT64_MAX) { + return true; + } + if (ctx->baddr != UT64_MAX) { + addr += ctx->baddr; + } + // Only create functions where executable code is actually mapped. This also + // keeps the symbol info (flags, types, globals) usable when no backing + // binary is loaded, since in that case no function will be created. + if (!rz_io_is_valid_offset(core->io, addr, RZ_PERM_X)) { + return true; + } + if (rz_analysis_get_function_at(core->analysis, addr)) { + return true; + } + int depth = rz_config_get_i(core->config, "analysis.depth"); + rz_core_analysis_fcn(core, addr, UT64_MAX, RZ_ANALYSIS_XREF_TYPE_NULL, depth); + return true; +} + static void pdb_symbols_load( - const RzCore *core, RzPdb *pdb, const char *pdbfile) { + RzCore *core, RzPdb *pdb, const char *pdbfile) { rz_return_if_fail(core && pdb); if (!(pdb->s_pe && pdb->s_gdata)) { return; @@ -309,6 +354,12 @@ static void pdb_symbols_load( rz_pdb_all_symbols_foreach(pdb, symbol_load, &ctx); rz_flag_space_pop(core->flags); + + // Create functions for public function symbols in a separate pass, after + // every symbol flag has been set, so each function (and any function it + // directly calls) is named from its PDB flag. + rz_pdb_all_symbols_foreach(pdb, symbol_make_function, &ctx); + free(file); } diff --git a/test/db/cmd/cmd_idp b/test/db/cmd/cmd_idp index 8eb6c29fd8..36147e11b2 100644 --- a/test/db/cmd/cmd_idp +++ b/test/db/cmd/cmd_idp @@ -7,8 +7,20 @@ fi 1 @ 0x00401010 EOF EXPECT=<