Skip to content

Function discovery finds only 44% of functions in one 32-bit MSVC PE (gap scanning contributes nothing) #247

Description

@danielplohmann

Summary

On one i686-pc-windows-msvc binary, SMDA reports 1167 functions where the companion PDB describes 2656 distinct function entry addresses (2296 S_[GL]PROC32 procedure records, 1790 publics).

The ratio is not the interesting part — the shape of the miss is:

SMDA functions                      : 1167
PDB entry addresses (procs+publics) : 2656  (procs 2296, publics 1790)
SMDA functions with a PDB entry     : 1167  (100.0%)
SMDA functions WITHOUT one          : 0
PDB entries SMDA did not find       : 1489

Every function SMDA found is one the debug info also describes, and it found none beyond that set. SMDA is not reading the PDB here — it names 1 function of 1167 — so this is not a naming effect. It means that on this binary, whatever normally recovers functions that are not reachable by direct call contributed nothing at all.

A binary where discovery is working normally has a substantial population of functions with no symbol at their entry (outlined exception funclets, cold chunks). Here that population is exactly empty, which is what makes it look like a discovery problem rather than an accounting one.

Versions

Reproduced identically on 4.4.4 and 4.4.7 (current release): 1167 functions in both. Python 3.12.13, lief 1.0.0.

Reproducer

Bundle attached separately (hyperfine.exe + hyperfine.pdb + two scripts, ~4 MB):

pip install smda lief
python3 repro.py hyperfine.exe hyperfine.pdb            # the counts
python3 entry_coverage.py hyperfine.exe hyperfine.pdb   # the diagnostic above

entry_coverage.py needs llvm-pdbutil on PATH for the PDB side.

Probably not the target triple

The same build recipe, toolchain and target applied to ripgrep 14.1.1 gives 15,370 functions, with the expected large population of unnamed-at-entry functions. So i686-pc-windows-msvc as such is fine; it is this binary that comes out empty.

One property that may matter

The binary is cross-compiled from Linux with rust-lld, against mingw-w64-derived import libraries and hand-written assembly stand-ins for the CRT symbols Rust's prebuilt std references — i.e. no Microsoft toolchain was involved, so the CRT/startup objects are stubs rather than the real thing. The Rust code itself is normal (it comes from the same prebuilt rust-std rlibs an MSVC-hosted build links), but if discovery seeds from entry-point/CRT structure, stubbed startup objects are a plausible place for it to lose its footing. Worth checking early; I have not diagnosed it.

Provenance is fully public and regenerable: hyperfine v1.19.0 (MIT/Apache-2.0), rustc 1.95.0, opt-level=3, lto="off", debug=2.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions