Skip to content

bloat: filter intra-function jump labels (<funcname+0xNN>) from references_to / called_by #484

Description

@zackees

Symptom

After #478 landed, fl::basic_string::materialize() shows 17+ entries in references_to that look like:

_ZN2fl12basic_string11materializeEv+0x15
_ZN2fl12basic_string11materializeEv+0x11
_ZN2fl12basic_string11materializeEv+0xc0
_ZN2fl12basic_string11materializeEv+0x5c
…

These aren't real callees — they're intra-function jump targets that objdump -d annotates as <funcname+0xNN> when a branch lands at a known offset inside another (or the same) function. The pattern is most common with:

  • bne / beq / unconditional b branches between basic blocks
  • Switch-table dispatch that jumps to multiple in-function labels
  • Loop back-edges

Root cause

callgraph::parse_call_target and callgraph::is_real_call_target in crates/fbuild-core/src/symbol_analysis/callgraph.rs strip:

  • ARM mapping symbols ($a / $d / $t)
  • PLT shims (@plt)
  • Pure hex addresses (<0x40123456>)

but the <funcname+0xNN> shape passes through unchanged. The downstream invert() pass then propagates the bogus name into called_by too — so heavy callees show inflated, partially-self-referential caller lists.

Fix

In is_real_call_target: drop tokens matching the regex ^.+\+0[xX][0-9a-fA-F]+$.

Equivalent prose:

  • If the inner annotation contains a +0x followed by hex through end of string, treat it as an intra-function label (not a call).

Don't merely strip the suffix — these aren't calls at all. Two bne branches both labeled <func+0x15> would otherwise collapse into one synthetic "call to func".

Acceptance

  • New test in callgraph::tests: intra_function_jump_labels_are_dropped — feeds a synthetic disasm with bne 400500 <foo+0x15> and asserts parse_disasm does not emit foo+0x15 as an edge.
  • Re-run fbuild bloat lookup --symbol "fl::basic_string::materialize()" on the FastLED esp32s3 ELF and confirm zero +0xNN entries in either references_to or called_by.
  • No change to the legitimate-call test corpus (Xtensa / RISC-V / ARM / AVR cases in callgraph::tests all stay green).

Out of scope

  • Inlining recovery (some +0xNN annotations point at the start of an inlined function the compiler didn't give a separate symbol to). That's a different problem; the conservative fix is still correct here.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status
    Triage

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions