arm64: Decode ARMv8.1-A LSE atomics and ARMv8.3-A LDAPR - #96
Conversation
This front end forked from Valgrind before ARMv8.1-A existed, so every LD<OP>, SWP, CAS, CASP and LDAPR encoding falls through dis_ARM64_load_store and the whole block comes back Ijk_NoDecode with size 0. Port the decode blocks upstream already carries: f1cf73455 with the swp and ldumax corrections of 6052ee66a for the atomic memory operations, 2281c8c86 for CAS, 9608e8019 for CASP and 41e2f95cf for LDAPR. The ported region is byte-identical to upstream master except for gen_SIGBUS_if_not_XX_aligned, which arrived after this fork's base and which the LDXR and LDAR blocks here still carry as a FIXME rather than as a check. ARMv8.4-A RCpc2 (LDAPUR, STLUR) is not included; upstream has no implementation of it either, only https://bugs.kde.org/show_bug.cgi?id=496477.
|
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS Validation record for head Provenance. Both arms are Fidelity to upstream. The ported region -- from A/B over the encoding space. 2,081,200 distinct 4-byte encodings, identical population in both arms: every distinct word in the executable sections of all 17 AArch64 ELF objects tracked in LDAPR predicate, exhaustively. The widened Assembled-encoding probe. 230 distinct encodings assembled by Consumer suite. Corpus measurement. The census that motivated this ran over Not covered. ARMv8.4-A RCpc2 ( session: sharpen |
|
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS One encoding per group, lifted with Before -- every one comes back as an empty block, so the caller gets no bytes and no address to resume from: vex at 875f7c9After -- the atomics become a barrier, a load, the operation, an vex with this change |
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS
Problem
The AArch64 front end decodes no ARMv8.1-A LSE atomic and no ARMv8.3-A
LDAPR, so a block containing one lifts to nothing at all:A corpus census over two multi-architecture collections found 307 objects carrying at least one declared function start that refuses this way, 3,789 such starts, and confirmed 4,549 of them
Ijk_NoDecodein context throughangr.Projectat the real load address -- 100% of what it re-checked. Because the refusal lands on the function's first instruction, the consumer gets no bytes and no address to resume from, and the function disappears from analysis rather than being truncated.Root cause
priv/guest_arm64_toIR.cforked from Valgrind before these instructions existed; its arm64 front end matches valgrind 3.15.0, andf1cf73455, which added LSE, landed on 2019-11-20, after 3.15.0 shipped.dis_ARM64_load_storetherefore falls through tofor every one of them, and
disInstr_ARM64turns that intodres.len = 0withIjk_NoDecode.Fix
Port the decode blocks upstream Valgrind already carries.
LDADD,LDCLR,LDEOR,LDSET,LDSMAX,LDSMIN,LDUMAX,LDUMINandSWPcome fromf1cf73455with theswp/ldumaxcorrections of6052ee66a;CASfrom2281c8c86;CASPfrom9608e8019;LDAPR/LDAPRB/LDAPRHfrom41e2f95cf. All four sizes and all four orderings decode. The ported region is byte-identical to upstream master apart fromgen_SIGBUS_if_not_XX_aligned, which arrived in2be719921after this fork's base and which the neighbouringLDXRandLDARblocks here still carry as aFIXMErather than as a check; adding it for the new blocks alone would leave the file inconsistent and would give every atomic a side exit on a jumpkind pyvex's consumers do not model.widenSto64comes along because the LSE block needs it, and theLDAPRdisassembly text saysldaprrather than reusing theldarspelling upstream left in place.The atomics lift the way upstream models them: a barrier for the acquire variants, a load, the operation, an
Ist_CAS, a barrier for the release variants, and anIjk_Boringexit back to the instruction when the CAS reported a stale value. That is the same shapeguest_amd64_toIR.calready emits for a lock-prefixed instruction.ARMv8.4-A RCpc2 --
LDAPUR,STLURand their sized forms -- is deliberately not included: upstream has no implementation either, only an open unpatched report at https://bugs.kde.org/show_bug.cgi?id=496477. It is 271 of the 3,789 refusing starts the census measured, so this change closes 92.8% of them.Testing
The regression lands with the consumer, angr/pyvex#579, which lifts every word of a compiled ARMv8.4-A fixture's
.textand asserts that the only words still refused are the RCpc2 group. On the merge base 97 of its words refuse; here 8 do. An A/B over 2,081,200 distinct AArch64 encodings -- the executable sections of every AArch64 ELF in angr/binaries, theLDAR/STLRblock's whole free-bit space exhaustively, and a fixed-seed uniform sample of the 32-bit space -- reports a difference on 2,480 encodings, every one of them previouslyIjk_NoDecode. Validation: #96 (comment)Merge order: this lands first, then angr/pyvex#579, whose
vexsubmodule is pinned to this head (846d111). Merging the pyvex half on its own leaves pyvex master's submodule pointing at a commit that is on no vex branch. Nothing in this repository reads async:line —.github/workflows/build.ymlis the only workflow and it is three build jobs — so the line below is a note to the reader.sync: angr/pyvex#579
session: sharpen