Register the STM32 backend so CLE can load Cortex-M flash images - #716
Conversation
cle/backends/stm32.py was never imported by cle.backends, so its
register_backend("stm32", ...) call never ran and the backend stayed out of
ALL_BACKENDS. Loading a raw Cortex-M flash image raised CLECompatibilityError
instead of selecting the backend.
Import and export it alongside the other backends, and repair the two things
that were wrong once it became reachable. is_compatible read from the stream's
current position, but Loader._static_backend probes every backend with one
shared stream and never rewinds it, so the vector table check ran against the
tail of the previous backend's read and never matched. The entry point was the
reset vector with its Thumb bit masked off, which makes angr lift the reset
handler as ARM; the ELF build of the same firmware reports the odd address.
Also drop VectorTable.get_irq_handler, which read a self._data attribute the
structure never had, and raise CLECompatibilityError rather than a bare
ValueError when an image requested as "stm32" is too short for a vector table.
|
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS Validation record for head
End-to-end effect on the angr path, with angr 9.3.3.dev0: import angr
TESTS = "binaries/tests/armel"
raw = angr.Project(f"{TESTS}/i2c_master_read-nucleol152re.bin", auto_load_libs=False)
elf = angr.Project(f"{TESTS}/i2c_master_read-nucleol152re.elf", auto_load_libs=False)
for p in (raw, elf):
print(hex(p.entry), p.factory.block(p.entry).thumb)On the baseline the first Caveats: the 9 skips are the pre-existing |
|
Corpus decompilation diffs can be found at angr/dec-snapshots@master...angr/cle_716 |
| """Reset handler address with Thumb bit cleared""" | ||
| return self.reset_handler & (~1) | ||
|
|
||
| def get_irq_handler(self, irq_num: int) -> int: |
There was a problem hiding this comment.
Don't make this unrelated change in this PR. This is perhaps a real bug, but address it in a separate discreet PR and keep this one focused
There was a problem hiding this comment.
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS
You are right, it is unrelated. Restored in 9cf81983c83846bdd15eb90a6e3faa82086a4ddc, so the diff is now only the registration, the is_compatible rewind and the Thumb bit.
For whoever picks it up: get_irq_handler reads self._data, which VectorTable never sets — from_bytes builds the structure with from_buffer_copy, so calling it raises AttributeError. It also could not work as written even with the attribute, because from_bytes copies only the first 64 bytes and every IRQ vector starts at offset 64. Nothing in the tree calls it.
There was a problem hiding this comment.
Can you fix it and add test cases?
There was a problem hiding this comment.
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS
Done, in #763 against master.
from_bytes now keeps the image it was given rather than only the 64 bytes the ctypes fields cover, which is what get_irq_handler needs to reach a peripheral vector at all, and a negative IRQ number raises instead of silently returning a system exception vector. Three tests cover it, reading the Nucleo-L152RE image's IRQ vectors and checking them against Default_Handler in the ELF build of the same firmware; all three fail on master with the original AttributeError.
It is broken -- it reads a self._data attribute the structure never sets -- but that is not this change's subject. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS
cle/backends/stm32.pywas never imported bycle.backends, so itsregister_backendcall never ran and the backend stayed out ofALL_BACKENDS. Loading a raw Cortex-M flash image raisedCLECompatibilityErrorinstead.Importing it exposed two more defects.
is_compatibleread from the stream's current position, butLoader._static_backendprobes every backend with one shared stream and never rewinds it. And the entry point had the reset vector's Thumb bit masked off, which makes angr lift the reset handler as ARM.The tests use the Nucleo-L152RE flash image already in
binariesand check the entry point against the ELF build of the same firmware.Validation: #716 (comment)