angr / angr/cle

eh_frame function hints are only loaded when load_debug_info is set, so CFGFast's eh_frame seeding is inert by default

Aperta
#744 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub
Lingua principale
Python
Stelle
485
Fork
135
Merge medio
2g 2h
PR unite (30g)
15

Descrizione

THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS

`.eh_frame` function hints are only collected when the loader was asked for
debug information, which it is not by default. Every consumer of
`Backend.function_hints` therefore sees an empty list for an ordinary
`angr.Project(path)`, including `CFGFast`, whose `eh_frame=True` option is
documented as "Retrieve function starts (and maybe sizes later) from the
.eh_frame of ELF binaries" and is on by default.

```python
# cle/backends/elf/elf.py
if self.has_dwarf_info and self.loader._load_debug_info:
...
if dwarf.has_EH_CFI():
self._load_function_hints_from_fde(dwarf, FunctionHintSource.EH_FRAME)

# cle/loader.py
load_debug_info: bool = False,
```

`.eh_frame` is not debug information in the sense that flag guards. It is an
allocated section, present after stripping, mapped at run time, and reading its
FDE headers needs neither `.debug_info` nor `.debug_abbrev`. Requiring the
debug-info opt-in to see it means the common case — a stripped release binary,
where the FDE headers are the only remaining record of where functions start —
is exactly the case where the hints are unavailable, while a binary carrying
full DWARF, where the symbol table already answers the question, is the case
where they are loaded.

### What it costs

Adding the FDE-derived hints to `main_object.function_hints` after loading and
changing nothing else, then running `CFGFast(normalize=True,
data_references=False, resolve_indirect_jumps=True, force_complete_scan=False)`,
counting `.eh_frame` FDE `initial_location` values with no block starting on
them. All of these are stripped shared objects and executables from a corpus
sweep, none of them with a `.symtab`:

```
arch FDEs entries with no block, default with the hints
RISCV64 1068 22 0
RISCV64 390 19 1
SuperH 257 39 3
X86 1519 42 3
Loongarch 148 36 24
S390X 58 16 4
```

A six-FDE x86-64 shared object shows the shape: `function_hints` is empty by
default and the entries at `0x4014c0` and `0x402000` are not block starts; with
`load_debug_info=True` there are six hints and both become block starts. That
code — `endbr64; push %r15; ...` — is reached only through a registration table,
so nothing in the binary points at it and `.eh_frame` is the only place its
entry is written down.

It does not fix everything: on several ppc64, ppc32, s390x and x86 objects the
count does not move, because the linear scan has already claimed the entry as
part of a block that began in the preceding alignment padding. That is a
separate defect, filed against angr.

### The relocatable caveat

#597 records that hints derived this way are wrong for stripped relocatable
objects, whose FDE addresses are all zero before a linker assigns them. That
argues for excluding `ET_REL`, not for tying `.eh_frame` to `load_debug_info`.

Two directions, both a call for whoever owns the loader: read the FDE headers
unconditionally for non-relocatable ELFs and accept the parse cost on every
load, or keep them behind an opt-in but a separate one, so that
`CFGFast(eh_frame=True)` is not silently inert.

Guida per i contributori

Nessuna guida per i contributori indicizzata per questo repository

Valutazione

Questa issue non è ancora stata valutata.

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.