ilmanzo / ilmanzo/BinaryCoverage
Coverage undercounted when the debuginfo package installed doesn't match the .so's own owning package
- Dominant language
- C
- Stars
- 9
- Forks
- 6
- Avg merge
- 1h 32m
- Merged PRs (30d)
- 11
Description
## Summary
Several `pam_*.so` modules were reported with implausibly few functions in a
live openQA coverage run (see the aggregate report for job 6188711). This is
**not a bug in BinaryCoverage's enumeration logic** — it correctly and safely
falls back to a stripped library's own exported symbols when no matching
external debug symbols are available. The gap is upstream of that: **which
`-debuginfo` package gets installed before coverage runs.**
A single traced binary's PAM stack pulls in `.so` modules from several
different source packages (`pam`, `pam-extra`, `pam_pwquality`, `systemd`,
`lastlog2`, `wtmpdb`, ...). Installing `-debuginfo` for just
the package under test does not cover libraries that ship from a different,
split-off subpackage — so those modules enumerate as near-empty even though
they have real logic.
This is the same class of gap already noted in this repo's `plan.md` for
`tests/coverage/coverage_setup.pm` (os-autoinst-distri-opensuse) and the
python313/gdb case: `coverage_setup.pm`'s `push @packages, $pkg, $pkg .
'-debuginfo'` only ever requests debuginfo for the target package itself, not
for every package actually reachable via `ldd`/`dlopen` at runtime.
## Concrete example: `pam_limits.so`
`pam_limits.so` belongs to package `pam-extra`, not `pam`. With only
`pam-debuginfo` installed (matching the base `pam` package, which most other
PAM modules on the host belong to), `funkoverage enumerate --no-libs
/usr/lib64/security/pam_limits.so` finds only the two PAM entry points:
```
$ funkoverage enumerate --no-libs /usr/lib64/security/pam_limits.so
/usr/lib64/security/pam_limits.so pam_sm_close_session
/usr/lib64/security/pam_limits.so pam_sm_open_session
Total: 2 functions across 1 image(s)
```
After installing the correctly-matching `pam-extra-debuginfo` package, the
same library enumerates its real function set:
```
$ funkoverage enumerate --no-libs /usr/lib64/security/pam_limits.so
/usr/lib64/security/pam_limits.so _pam_parse
/usr/lib64/security/pam_limits.so base_name
/usr/lib64/security/pam_limits.so check_logins
/usr/lib64/security/pam_limits.so compare_filename
/usr/lib64/security/pam_limits.so init_limits
/usr/lib64/security/pam_limits.so pam_sm_close_session
/usr/lib64/security/pam_limits.so pam_sm_open_session
/usr/lib64/security/pam_limits.so pam_str_skip_prefix_len
/usr/lib64/security/pam_limits.so parse_config_file
/usr/lib64/security/pam_limits.so parse_kernel_limits
/usr/lib64/security/pam_limits.so parse_uid_range
/usr/lib64/security/pam_limits.so process_limit
/usr/lib64/security/pam_limits.so read_limits_dir
/usr/lib64/security/pam_limits.so rlimit2str
/usr/lib64/security/pam_limits.so set_if_null
/usr/lib64/security/pam_limits.so setup_limits
/usr/lib64/security/pam_limits.so split
/usr/lib64/security/pam_limits.so str2rlim_t
/usr/lib64/security/pam_limits.so str2rlimit
/usr/lib64/security/pam_limits.so trim
/usr/lib64/security/pam_limits.so value_from_file
Total: 21 functions across 1 image(s)
```
**2 vs 21 functions for the identical `.so` file** — same binary, same build,
the only difference is which debuginfo happens to be installed.
## Other affected modules on the same host
Surveyed every `pam_*.so` on a Tumbleweed test VM against `rpm -qf` and
whether a matching `-debuginfo` package was installed:
| module | owning package | matching debuginfo installed | functions enumerated |
|---|---|---|---|
| `pam_limits.so` | `pam-extra` | no (had `pam-debuginfo` instead) | 2 (real: 21) |
| `pam_pwquality.so` | `pam_pwquality` | no | 1 |
| `pam_systemd.so` | `systemd` | no | 2 |
| `pam_systemd_loadkey.so` | `systemd` | no | 2 |
| `pam_lastlog2.so` | `lastlog2` | no | 5 |
| `pam_wtmpdb.so` | `wtmpdb` | no | 5 |
Every other `pam_*.so` on the host belongs to plain `pam`, which did have
`pam-debuginfo` installed, and those all enumerate plausible function counts
(6–59).
## Where the actual fix belongs
Not in this repo. The fix is in whatever decides which debuginfo packages to
install before a coverage run — for the openQA case, that's
`tests/coverage/coverage_setup.pm` in `os-autoinst-distri-opensuse`, which
would need to resolve the real owning package of every library actually
reachable from the traced binary (via `rpm -qf` or equivalent, after an ldd
walk / dlopen discovery pass) and install debuginfo for each distinct package,
not just for the target binary's own package.
## Suggested follow-up here
BinaryCoverage's `funkoverage enumerate`/`install` could optionally surface
this more clearly at report time — e.g. a report footnote or a `--warn-thin`
mode flagging images whose function count looks suspiciously low relative to
their dynsym size, so a low count is visibly distinguishable from "this really
is a thin wrapper" (which is also a real, confirmed case — see `plan.md`'s
notes on `postfix`/`rpm`/`sestatus`). Filing this primarily so the two known
instances of the debuginfo-package-mismatch class (python313/gdb, now
pam-extra) are tracked in one place before deciding whether that's worth
building.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with plan.md and the coverage flow around funkoverage enumerate/install, then inspect tests/coverage/coverage_setup.pm in os-autoinst-distri-opensuse to understand the debuginfo selection gap. Done requires deciding whether this repository should add a thin-image warning or whether the issue remains an external openQA follow-up, with the decision and affected package-resolution behavior documented.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- testing, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100