Skip to content

Add NuttX LL/SC decompiler fixture - #204

Open
zardus wants to merge 3 commits into
masterfrom
codex/nuttx-llsc-fixture
Open

Add NuttX LL/SC decompiler fixture#204
zardus wants to merge 3 commits into
masterfrom
codex/nuttx-llsc-fixture

Conversation

@zardus

@zardus zardus commented Aug 27, 2026

Copy link
Copy Markdown
Member

THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS

Problem

The LL/SC regression in the linked angr consumer needs the real ARM Thumb paths in the NuttX stm32f4discovery:nsh image entered at 0x08000189. The binaries baseline has no fixture that the consumer can load.

Root cause

The public DecBench ELF carries the required program and symbols, but also large .debug_* sections containing local build paths. Consumer tests cannot download the source artifact or manufacture a replacement at run time.

Fix

Add a debug-sanitized derivative that preserves the loaded program, symbols, entry point, and exercised regions while removing only .debug_*. Commit the pinned DecBench object, NuttX revision, Apache-2.0 license, hashes, and exact Binutils command.

Testing

GNU Binutils 2.46 arm-none-eabi-objcopy --remove-section=.debug_* reproduces the fixture byte-for-byte, and the focused consumer lift regression passes. The validation record contains exact artifact and content-identical rebase evidence.

Validation: #204 (comment)

sync: angr/angr#6679

session: sharpen

@zardus

zardus commented Aug 27, 2026

Copy link
Copy Markdown
Member Author

THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS

Validation record for head f602b77769dc72abbdd346678be038e495ab4116 against baseline a87538bc248531d2a1d22434143e8b9752459bac.

  • Exact PR shape: the own-merge-base/head scan verifies the added compiler-produced fixture and its load-bearing format/address shape: ARM Cortex-M ELF; LL/SC block 0x800d781 lies in read_pseudodir starting at 0x800d725.
  • Provenance/reproduction: ARM GNU Binutils 2.46 removal of .debug_* sections was rerun twice in separate fresh directories; both outputs byte-compare with each other and with the committed bytes.
  • Input/native identity: committed SHA-256 d30ea99781f9d0aa0d4db54d50a81b73adc5514d659c7059e55c54fd4a4c2bfb; the rustylib each consumer arm actually had mapped, read from that process's own /proc/self/maps and hashed there: baseline bf12e8d41861dfc6c074502f8875e00a4a961cb049a5f699052ca53aa7c14a1c, head d344c54e702d9b8b2984b2707f1c169f5970fb9b6d387aac8f1079f911a43406. The earlier figures in this row were isolated build artifacts of the superseded consumer pair and were not maps-derived; they are replaced rather than carried forward.
  • Real consumer: AIL: preserve LL/SC result definitions and effects angr#6679 at baseline a9ca247a5bcadf0ad8ecccb61be5f76dc4cd5050 and head 74af5caeb46d9b55532c624b579e07c512905392 loaded the committed fixture and produced the complete output published in that pull request's output record. The consumer was rebased after this record was first written; the pair it named before, baseline b0feae57a9e401292e03a6f9ffbd4b388d172bf5 and head 384c09457a97cfb229381d951b1ce228179de2f1, is superseded, and the branch patch is byte-identical across that rebase (stable patch id cdbc179a0a9ac09f187cec9bdf4a383f4999a25f).
  • Repeat/order control: A/B/B/A, a static structural/native capture whose determinism is established by separate same-arm processes; same-arm output is byte-identical and the cross-arm delta is nonempty.
  • Local scope: this recapture validates fixture bytes, fixture shape, and the actual consumer path only. It does not claim a fresh full-workspace gate.
  • Hosted status: fresh hosted dependency validation for this exact binaries head has not been observed in this recapture; it remains pending and no hosted success is claimed here.

@zardus
zardus force-pushed the codex/nuttx-llsc-fixture branch from e68a307 to 5ccff61 Compare August 28, 2026 13:05
@zardus

zardus commented Aug 28, 2026

Copy link
Copy Markdown
Member Author

THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS

Exact fixture-shape and consumer-output record for #204.

  • Fixture comparison: own merge base a87538bc248531d2a1d22434143e8b9752459bac versus exact head f602b77769dc72abbdd346678be038e495ab4116. The target path/shape is absent on the merge base and present on the head. ARM Cortex-M ELF; LL/SC block 0x800d781 lies in read_pseudodir starting at 0x800d725.
  • Fixture identity: SHA-256 d30ea99781f9d0aa0d4db54d50a81b73adc5514d659c7059e55c54fd4a4c2bfb; source provenance: DecBench revision e5eb576d66ee36793b800a4dd45e291e0add4472, O2-noinline/nuttx/nuttx. The complete readelf/objdump scan is retained with the exact script. The recorded recipe (ARM GNU Binutils 2.46 removal of .debug_* sections) was rerun twice in fresh directories; both runs are byte-identical to the committed fixture.
  • Actual consumer: AIL: preserve LL/SC result definitions and effects angr#6679, exact baseline b0feae57a9e401292e03a6f9ffbd4b388d172bf5 versus exact head 384c09457a97cfb229381d951b1ce228179de2f1; target LL/SC block and read_pseudodir; configuration scoped CFG plus full / SAILR. That consumer pair is superseded: AIL: preserve LL/SC result definitions and effects angr#6679 was rebased onto a9ca247a5bcadf0ad8ecccb61be5f76dc4cd5050 as head 74af5caeb46d9b55532c624b579e07c512905392, with a byte-identical branch patch (stable patch id cdbc179a0a9ac09f187cec9bdf4a383f4999a25f). The blocks below are the capture taken at the pair named above and are left as they were recorded; the capture at the current pair is that pull request's own output record.
  • Native identity: isolated built rustylib artifacts: base cda15fa73198006b09be899a089785c8105469b6d2b1d29272a5033f3328e59f, head 5eb00477859e754289d0083bac09a017fdcaf06f9019aef1619484e64d858eb6; the base exception arm did not retain /proc/self/maps, so neither is described as a maps-derived base/head pair.
  • Determinism: fresh A/B/B/A order, a static structural/native capture whose determinism is established by separate same-arm processes; each same-arm pair is byte-identical and every base/head comparison below is nonempty. Absolute checkout prefixes in tracebacks are normalized to <workspace> and the interpreter's store prefix to <python3.12> for publication; no line is removed or reordered, and raw output is retained unchanged.

Before — LL/SC block and read_pseudodir

Exact consumer baseline
Traceback (most recent call last):
  File "<workspace>/scratch/apply-latest-skills-pr-audit-20260828/fixture-output-recapture/capture-special.py", line 83, in <module>
    dec = proj.analyses[Decompiler].prep(fail_fast=True)(
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<python3.12>/contextlib.py", line 81, in inner
    return func(*args, **kwds)
           ^^^^^^^^^^^^^^^^^^^
  File "<workspace>/scratch/apply-latest-skills-pr-audit-20260828/output-regeneration-light/worktrees/6679-base/angr/analyses/analysis.py", line 249, in wrapper
    oself.__init__(*args, **kwargs)
  File "<workspace>/scratch/apply-latest-skills-pr-audit-20260828/output-regeneration-light/worktrees/6679-base/angr/analyses/decompiler/decompiler.py", line 241, in __init__
    self._decompile_with_cache()
  File "<workspace>/scratch/apply-latest-skills-pr-audit-20260828/output-regeneration-light/worktrees/6679-base/angr/analyses/decompiler/decompiler.py", line 287, in _decompile_with_cache
    self._decompile()
  File "<workspace>/scratch/apply-latest-skills-pr-audit-20260828/output-regeneration-light/worktrees/6679-base/angr/utils/timing.py", line 73, in timed_func
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "<workspace>/scratch/apply-latest-skills-pr-audit-20260828/output-regeneration-light/worktrees/6679-base/angr/analyses/decompiler/decompiler.py", line 412, in _decompile
    clinic = self.project.analyses.Clinic(
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<workspace>/scratch/apply-latest-skills-pr-audit-20260828/output-regeneration-light/worktrees/6679-base/angr/analyses/analysis.py", line 264, in __call__
    r = w(*args, **kwargs)
        ^^^^^^^^^^^^^^^^^^
  File "<python3.12>/contextlib.py", line 81, in inner
    return func(*args, **kwds)
           ^^^^^^^^^^^^^^^^^^^
  File "<workspace>/scratch/apply-latest-skills-pr-audit-20260828/output-regeneration-light/worktrees/6679-base/angr/analyses/analysis.py", line 249, in wrapper
    oself.__init__(*args, **kwargs)
  File "<workspace>/scratch/apply-latest-skills-pr-audit-20260828/output-regeneration-light/worktrees/6679-base/angr/analyses/decompiler/clinic.py", line 436, in __init__
    self._analyze_for_decompiling()
  File "<workspace>/scratch/apply-latest-skills-pr-audit-20260828/output-regeneration-light/worktrees/6679-base/angr/analyses/decompiler/clinic.py", line 500, in _analyze_for_decompiling
    ail_graph = self._decompilation_simplifications(ail_graph)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<workspace>/scratch/apply-latest-skills-pr-audit-20260828/output-regeneration-light/worktrees/6679-base/angr/analyses/decompiler/clinic.py", line 826, in _decompilation_simplifications
    stages[stage]()
  File "<workspace>/scratch/apply-latest-skills-pr-audit-20260828/output-regeneration-light/worktrees/6679-base/angr/analyses/decompiler/clinic.py", line 863, in _stage_constant_propagation
    self._simplify_function(
  File "<workspace>/scratch/apply-latest-skills-pr-audit-20260828/output-regeneration-light/worktrees/6679-base/angr/utils/timing.py", line 73, in timed_func
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "<workspace>/scratch/apply-latest-skills-pr-audit-20260828/output-regeneration-light/worktrees/6679-base/angr/analyses/decompiler/clinic.py", line 2026, in _simplify_function
    simplified = self._simplify_function_once(
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<workspace>/scratch/apply-latest-skills-pr-audit-20260828/output-regeneration-light/worktrees/6679-base/angr/utils/timing.py", line 73, in timed_func
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "<workspace>/scratch/apply-latest-skills-pr-audit-20260828/output-regeneration-light/worktrees/6679-base/angr/analyses/decompiler/clinic.py", line 2068, in _simplify_function_once
    simp = self.project.analyses[AILSimplifier].prep(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<python3.12>/contextlib.py", line 81, in inner
    return func(*args, **kwds)
           ^^^^^^^^^^^^^^^^^^^
  File "<workspace>/scratch/apply-latest-skills-pr-audit-20260828/output-regeneration-light/worktrees/6679-base/angr/analyses/analysis.py", line 249, in wrapper
    oself.__init__(*args, **kwargs)
  File "<workspace>/scratch/apply-latest-skills-pr-audit-20260828/output-regeneration-light/worktrees/6679-base/angr/analyses/decompiler/ail_simplifier.py", line 277, in __init__
    self._simplify()
  File "<workspace>/scratch/apply-latest-skills-pr-audit-20260828/output-regeneration-light/worktrees/6679-base/angr/analyses/decompiler/ail_simplifier.py", line 297, in _simplify
    folded_exprs = self._fold_exprs()
                   ^^^^^^^^^^^^^^^^^^
  File "<workspace>/scratch/apply-latest-skills-pr-audit-20260828/output-regeneration-light/worktrees/6679-base/angr/analyses/decompiler/ail_simplifier.py", line 951, in _fold_exprs
    propagator = self._compute_propagation()
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<workspace>/scratch/apply-latest-skills-pr-audit-20260828/output-regeneration-light/worktrees/6679-base/angr/utils/timing.py", line 73, in timed_func
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "<workspace>/scratch/apply-latest-skills-pr-audit-20260828/output-regeneration-light/worktrees/6679-base/angr/analyses/decompiler/ail_simplifier.py", line 419, in _compute_propagation
    prop = SPropagator(
           ^^^^^^^^^^^^
  File "<workspace>/scratch/apply-latest-skills-pr-audit-20260828/output-regeneration-light/worktrees/6679-base/angr/analyses/s_propagator.py", line 153, in __init__
    self._analyze()
  File "<workspace>/scratch/apply-latest-skills-pr-audit-20260828/output-regeneration-light/worktrees/6679-base/angr/analyses/s_propagator.py", line 498, in _analyze
    tmp_def_stmtidx = tmp_deflocs[block_loc][tmp_atom]
                      ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^
KeyError: <Tmp 2>

After — LL/SC block and read_pseudodir

Exact consumer head
BLOCK
IRSB {
   t0:Ity_I32 t1:Ity_I32 t2:Ity_I32 t3:Ity_I32 t4:Ity_I32 t5:Ity_I32 t6:Ity_I32 t7:Ity_I32 t8:Ity_I1 t9:Ity_I32 t10:Ity_I32 t11:Ity_I1 t12:Ity_I32 t13:Ity_I32 t14:Ity_I32 t15:Ity_I32 t16:Ity_I32 t17:Ity_I32 t18:Ity_I1 t19:Ity_I32 t20:Ity_I32 t21:Ity_I32 t22:Ity_I1 t23:Ity_I1 t24:Ity_I32 t25:Ity_I32 t26:Ity_I32 t27:Ity_I32 t28:Ity_I32 t29:Ity_I1 t30:Ity_I32 t31:Ity_I32 t32:Ity_I32 t33:Ity_I32 t34:Ity_I32 t35:Ity_I32 t36:Ity_I32 t37:Ity_I32 t38:Ity_I1 t39:Ity_I1 t40:Ity_I32 t41:Ity_I32 t42:Ity_I32 t43:Ity_I32 t44:Ity_I1 t45:Ity_I32 t46:Ity_I32 t47:Ity_I32 t48:Ity_I32 t49:Ity_I32 t50:Ity_I32 t51:Ity_I32 t52:Ity_I32 t53:Ity_I1 t54:Ity_I32 t55:Ity_I32 t56:Ity_I32 t57:Ity_I32 t58:Ity_I32 t59:Ity_I32 t60:Ity_I1 t61:Ity_I32 t62:Ity_I1 t63:Ity_I32 t64:Ity_I32 t65:Ity_I1 t66:Ity_I1

   00 | ------ IMark(0x800d780, 4, 1) ------
   01 | PUT(itstate) = 0x00000000
   02 | t25 = GET:I32(r3)
   03 | t2 = LDle-Linked(t25)
   04 | ------ IMark(0x800d784, 2, 1) ------
   05 | t28 = Add32(t2,0x00000001)
   06 | PUT(r1) = t28
   07 | PUT(cc_op) = 0x00000001
   08 | PUT(cc_dep1) = t2
   09 | PUT(cc_dep2) = 0x00000001
   10 | PUT(cc_ndep) = 0x00000000
   11 | PUT(pc) = 0x0800d787
   12 | ------ IMark(0x800d786, 4, 1) ------
   13 | PUT(itstate) = 0x00000000
   14 | t11 = ( STle-Cond(t25) = t28 )
   15 | t62 = Not1(t11)
   16 | t63 = 1Uto32(t62)
   17 | PUT(r2) = t63
   18 | ------ IMark(0x800d78a, 2, 1) ------
   19 | PUT(cc_op) = 0x00000002
   20 | PUT(cc_dep1) = t63
   21 | PUT(cc_dep2) = 0x00000000
   22 | PUT(cc_ndep) = 0x00000000
   23 | PUT(pc) = 0x0800d78d
   24 | ------ IMark(0x800d78c, 2, 1) ------
   25 | PUT(itstate) = 0x00000000
   26 | t66 = 32to1(t63)
   27 | if (t66) { PUT(pc) = 0x800d781; Ijk_Boring }
   NEXT: PUT(pc) = 0x0800d78f; Ijk_Boring
}
DECOMPILATION
typedef struct struct_0 {
    char padding_0[4];
    unsigned int field_4;
    unsigned int field_8;
    char padding_c[4];
    unsigned short field_10;
    char padding_12[2];
    unsigned int field_14;
    char padding_18[12];
    char field_24;
} struct_0;

typedef struct struct_1 {
    char padding_0[8];
    struct struct_0 *field_8;
} struct_1;


unsigned int read_pseudodir(struct_1 *idx, char *a1)
{
    struct_0 *v0;  // r2
    struct_0 *v1;  // r5
    unsigned int v2;  // r3
    unsigned int v3;  // r3
    unsigned int v4;  // 4098
    int v5;  // 4107

    if (!idx->field_8)
        return 0xfffffffe;
    strlcpy(a1 + 1, &idx->field_8->field_24, 33);
    *(a1) = 0;
    v0 = idx->field_8;
    if (v0->field_14)
    {
        switch (v0->field_10 & 15)
        {
        case 1:
            *(a1) = 2;
            v0 = idx->field_8;
            break;
        case 2:
            *(a1) = 6;
            v0 = idx->field_8;
            break;
        case 3:
            *(a1) = 4;
            v0 = idx->field_8;
            break;
        case 4:
            *(a1) = 3;
            v0 = idx->field_8;
            break;
        case 5:
            *(a1) = 5;
            v0 = idx->field_8;
            break;
        case 6:
            *(a1) = 7;
            v0 = idx->field_8;
            break;
        case 7:
            *(a1) = 9;
            v0 = idx->field_8;
            break;
        case 10:
            *(a1) = 1;
            v0 = idx->field_8;
            break;
        }
        if (!v0->field_8 && v0->field_14)
            inode_lock();
    }
    *(a1) = 4;
    inode_lock();
    v1 = idx->field_8;
    v2 = v1->field_4;
    idx->field_8 = v2;
    if (!v2)
    {
        inode_unlock();
        inode_release(v1);
        return 0;
    }
    /* unsupported instruction */
    v3 = v2 + 12;
    do
    {
        v4 = load_linked_le(vvar_221{r20|4b});
        v5 = (int)store_conditional_le(vvar_221{r20|4b}, (vvar_265 Add 1<32>));
    } while (!v5);
    /* unsupported instruction */
    inode_unlock();
    inode_release(v1);
    return 0;
}

@zardus
zardus force-pushed the codex/nuttx-llsc-fixture branch from 5ccff61 to f602b77 Compare August 28, 2026 16:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant