-
Notifications
You must be signed in to change notification settings - Fork 61
Add ccop_triggers test binaries for decompiler ccall rewriter tests #163
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
zardus
wants to merge
5
commits into
master
Choose a base branch
from
decompiler-ccop-handlers
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 1 commit
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
1affd06
Add ccop_triggers test binaries for decompiler ccall rewriter tests
zardus 03f05ee
Add ARM (armhf + aarch64) ccop_triggers test binaries and sources
zardus d591e5e
Add recompile-dataset: round-trip decompilation test corpus
zardus fc0553f
fix CI: simplify MSVC workflow CMD scripting
zardus 09ba960
ci: rebuild MSVC recompile-dataset binaries [skip ci]
github-actions[bot] File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,259 @@ | ||
| # ccop_triggers Test Suite — Status | ||
|
|
||
| ## What This Is | ||
|
|
||
| A set of C source files designed to trigger every VEX condition-code operation (ccop) type | ||
| handled by angr's decompiler ccall rewriters (`amd64_ccalls.py`, `x86_ccalls.py`). Each | ||
| function is `noinline`, uses a volatile sink to prevent dead-code elimination, and is compiled | ||
| with `-fno-if-conversion` to force real branches (not cmov). | ||
|
|
||
| Built binaries go into `bin/amd64/` and `bin/i386/` (gitignored). Run `bash build.sh` to | ||
| rebuild. | ||
|
|
||
| ## Current State: All 9 source files complete, all P0/P1 gaps filled | ||
|
|
||
| ### Complete — ~285 functions across 54 binaries (all build cleanly, all tests pass) | ||
|
|
||
| | File | Functions | Notes | | ||
| |------|-----------|-------| | ||
| | `ccop_sub.c` | 48 | SUB/CMP: CondZ/NZ/L/NL/LE/NLE/B/NB/BE/NBE/S/NS all at 8,16,32,64. Pure C comparisons. | | ||
| | `ccop_add.c` | 39 | ADD: CondZ/NZ/S/NS/O/NO/B (8,16,32,64), CondLE/NLE (8,16,32,64), CondBE (8,16,32). Uses `__builtin_add_overflow` for CondO; `asm goto` for CondLE/NLE/BE. 64-bit CondLE/NLE guarded by `__x86_64__`. | | ||
| | `ccop_logic.c` | 38 | LOGIC (test/and): CondZ/NZ/S/NS/L/NL (8,16,32,64), CondLE/NLE (8,16,32,64), CondB/BE (8,16,32 x86 only via `asm goto`). | | ||
| | `ccop_inc_dec.c` | 48 | INC: CondZ/NZ/S/NS (8,16,32,64), CondO/NO (8,16,32 via asm goto), CondLE/NLE (32 fallback). DEC: CondZ/NZ/S/NS/LE/NLE (8,16,32,64). All inline asm; built with `-mtune-ctrl=use_incdec`. | | ||
| | `ccop_shl_shr.c` | 32 | SHL: CondZ/NZ/S/NS (8,16,32,64). SHR: CondZ/NZ/S/NS (8,16,32,64). Pure C shifts; narrow widths use volatile + explicit casts. | | ||
| | `ccop_umul_smul.c` | 16 | UMUL/SMUL: CondO/NO (8,16,32,64). Uses `__builtin_*_overflow`. 64-bit UMUL CondNO guarded by `__x86_64__`. | | ||
| | `ccop_adc_sbb.c` | ~59 | ADC/SBB: comprehensive coverage. amd64 section (11 funcs via `__int128`), i386 section (48 funcs via pure C + asm goto). Covers CondZ/NZ/S/B/O/NO for ADC; CondZ/B/NB/BE/NBE/L/NL/S/O/NO for SBB at 8,16,32 widths. | | ||
| | `ccop_copy.c` | 4 | COPY: CondZ/NZ via `pushf`/`popf` + `asm goto`. amd64 uses `pushfq`/`popfq` (64-bit), i386 uses `pushfl`/`popfl` (32-bit). | | ||
| | `ccop_rflags_c.c` | 6 | rflags_c: carry flag extraction for ADD (32,64), SUB (32,64), DEC (32,64). amd64-only (`#ifdef __x86_64__`). Uses `adc $0` / `sbb $0` carry chains. | | ||
|
|
||
| ### Python Test Harness | ||
|
|
||
| `tests/analyses/decompiler/test_ccop_triggers.py` — parametrized pytest (54 test cases) | ||
| that decompiles every `ccop_*` function in every binary and asserts: | ||
|
|
||
| 1. Decompilation succeeds (codegen is not None) | ||
| 2. For rewriter-handled (op, cond, width) combos: no raw `calculate_condition` or | ||
| `calculate_rflags_c` in the output | ||
| 3. For fallback-only combos (no rewriter): just checks decompilation doesn't crash | ||
|
|
||
| Run: `python -m pytest tests/analyses/decompiler/test_ccop_triggers.py -v` | ||
|
|
||
| --- | ||
|
|
||
| ## Comprehensive Rewriter Coverage vs Test Coverage | ||
|
|
||
| The tables below map every (ccop, condition) combination handled by the rewriters against | ||
| what the test suite covers. This was generated by reading every code path in | ||
| `amd64_ccalls.py` and `x86_ccalls.py`. | ||
|
|
||
| ### Legend | ||
|
|
||
| - **A** = amd64 rewriter handles this (B/W/L/Q widths) | ||
| - **X** = x86 rewriter handles this (B/W/L widths) | ||
| - All listed conditions now have full width coverage | ||
|
|
||
| ### SUB — `ccop_sub.c` (48 functions) | ||
|
|
||
| | Condition | Rewriter | Tested Widths | | ||
| |-----------|----------|---------------| | ||
| | CondZ | A, X | 8, 16, 32, 64 | | ||
| | CondNZ | A, X | 8, 16, 32, 64 | | ||
| | CondL | A, X | 8, 16, 32, 64 | | ||
| | CondNL | A, X | 8, 16, 32, 64 | | ||
| | CondLE | A, X | 8, 16, 32, 64 | | ||
| | CondNLE | A, X | 8, 16, 32, 64 | | ||
| | CondB | A, X | 8, 16, 32, 64 | | ||
| | CondNB | A, X | 8, 16, 32, 64 | | ||
| | CondBE | A, X | 8, 16, 32, 64 | | ||
| | CondNBE | A, X | 8, 16, 32, 64 | | ||
| | CondS | A, X | 8, 16, 32, 64 | | ||
| | CondNS | A, X | 8, 16, 32, 64 | | ||
|
|
||
| ### ADD — `ccop_add.c` (39 functions) | ||
|
|
||
| | Condition | Rewriter | Tested Widths | | ||
| |-----------|----------|---------------| | ||
| | CondZ | A, X | 8, 16, 32, 64 | | ||
| | CondNZ | A, X | 8, 16, 32, 64 | | ||
| | CondS | A, X | 8, 16, 32, 64 | | ||
| | CondNS | A, X | 8, 16, 32, 64 | | ||
| | CondO | A, X | 8, 16, 32, 64 | | ||
| | CondNO | A, X | 8, 16, 32, 64 | | ||
| | CondB | A, X | 8, 16, 32, 64 | | ||
| | CondLE | X only | 8, 16, 32, 64 | | ||
| | CondNLE | X only | 8, 16, 32, 64 | | ||
| | CondBE | X only | 8, 16, 32 | | ||
|
|
||
| ### LOGIC — `ccop_logic.c` (38 functions) | ||
|
|
||
| | Condition | Rewriter | Tested Widths | | ||
| |-----------|----------|---------------| | ||
| | CondZ | A, X | 8, 16, 32, 64 | | ||
| | CondNZ | A, X | 8, 16, 32, 64 | | ||
| | CondS | A, X | 8, 16, 32, 64 | | ||
| | CondNS | A, X | 8, 16, 32, 64 | | ||
| | CondL | A, X | 8, 16, 32, 64 | | ||
| | CondNL | A, X | 8, 16, 32, 64 | | ||
| | CondLE | A, X | 8, 16, 32, 64 | | ||
| | CondNLE | A, X | 8, 16, 32, 64 | | ||
| | CondB | X only | 8, 16, 32 | | ||
| | CondBE | X only | 8, 16, 32 | | ||
|
|
||
| ### INC — `ccop_inc_dec.c` (24 INC functions) | ||
|
|
||
| | Condition | Rewriter | Tested Widths | | ||
| |-----------|----------|---------------| | ||
| | CondZ | A, X | 8, 16, 32, 64 | | ||
| | CondNZ | A, X | 8, 16, 32, 64 | | ||
| | CondS | A | 8, 16, 32, 64 | | ||
| | CondNS | A | 8, 16, 32, 64 | | ||
| | CondO | X only | 8, 16, 32 | | ||
| | CondNO | X only | 8, 16, 32 | | ||
|
|
||
| Note: INC CondLE/CondNLE (32) are in the test but neither rewriter handles this — those | ||
| test fallback behavior only. | ||
|
|
||
| ### DEC — `ccop_inc_dec.c` (24 DEC functions) | ||
|
|
||
| | Condition | Rewriter | Tested Widths | | ||
| |-----------|----------|---------------| | ||
| | CondZ | A, X | 8, 16, 32, 64 | | ||
| | CondNZ | A, X | 8, 16, 32, 64 | | ||
| | CondS | A | 8, 16, 32, 64 | | ||
| | CondNS | A | 8, 16, 32, 64 | | ||
| | CondLE | A, X | 8, 16, 32, 64 | | ||
| | CondNLE | A, X | 8, 16, 32, 64 | | ||
|
|
||
| ### SHL — `ccop_shl_shr.c` (16 SHL functions) | ||
|
|
||
| | Condition | Rewriter | Tested Widths | | ||
| |-----------|----------|---------------| | ||
| | CondZ | A, X | 8, 16, 32, 64 | | ||
| | CondNZ | A, X | 8, 16, 32, 64 | | ||
| | CondS | A, X | 8, 16, 32, 64 | | ||
| | CondNS | A, X | 8, 16, 32, 64 | | ||
|
|
||
| ### SHR — `ccop_shl_shr.c` (16 SHR functions) | ||
|
|
||
| | Condition | Rewriter | Tested Widths | | ||
| |-----------|----------|---------------| | ||
| | CondZ | A, X | 8, 16, 32, 64 | | ||
| | CondNZ | A, X | 8, 16, 32, 64 | | ||
| | CondS | A, X | 8, 16, 32, 64 | | ||
| | CondNS | A, X | 8, 16, 32, 64 | | ||
|
|
||
| ### UMUL — `ccop_umul_smul.c` (8 UMUL functions) | ||
|
|
||
| | Condition | Rewriter | Tested Widths | | ||
| |-----------|----------|---------------| | ||
| | CondO | A, X | 8, 16, 32, 64 | | ||
| | CondNO | A, X | 8, 16, 32, 64 | | ||
|
|
||
| ### SMUL — `ccop_umul_smul.c` (8 SMUL functions) | ||
|
|
||
| | Condition | Rewriter | Tested Widths | | ||
| |-----------|----------|---------------| | ||
| | CondO | A (B/W/L/Q), X (L only) | 8, 16, 32, 64 | | ||
| | CondNO | A (B/W/L/Q), X (L only) | 8, 16, 32, 64 | | ||
|
|
||
| ### ADC — `ccop_adc_sbb.c` | ||
|
|
||
| The AMD64 rewriter does NOT handle ADC at all. Only x86 handles ADC. | ||
|
|
||
| | Condition | Rewriter | Tested Widths | | ||
| |-----------|----------|---------------| | ||
| | CondO | X only | 8, 16, 32 | | ||
| | CondNO | X only | 8, 16, 32 | | ||
| | CondB | X only | 8, 16, 32 | | ||
|
|
||
| ADC CondZ/NZ/S are tested but NOT handled by any rewriter — they exercise fallback only. | ||
|
|
||
| ### SBB — `ccop_adc_sbb.c` | ||
|
|
||
| AMD64 rewriter only handles SBB+CondB. x86 handles more conditions. | ||
|
|
||
| | Condition | Rewriter | Tested Widths | | ||
| |-----------|----------|---------------| | ||
| | CondB | A, X | 8, 16, 32, 64 | | ||
| | CondBE | X only | 8, 16, 32 | | ||
| | CondNB | X only | 8, 16, 32 | | ||
| | CondNBE | X only | 8, 16, 32 | | ||
| | CondL | X only | 8, 16, 32 | | ||
| | CondNL | X only | 8, 16, 32 | | ||
| | CondO | X only | 8, 16, 32 | | ||
| | CondNO | X only | 8, 16, 32 | | ||
|
|
||
| SBB CondZ/S are tested but NOT handled by any rewriter — they exercise fallback only. | ||
|
|
||
| ### COPY — `ccop_copy.c` (4 functions) | ||
|
|
||
| | Condition | Rewriter | Tested Widths | | ||
| |-----------|----------|---------------| | ||
| | CondZ | A, X | 32, 64 | | ||
| | CondNZ | A, X | 32, 64 | | ||
|
|
||
| ### `amd64g_calculate_rflags_c` — `ccop_rflags_c.c` (6 functions, amd64-only) | ||
|
|
||
| | CCOP | Rewriter | Tested Widths | | ||
| |------|----------|---------------| | ||
| | ADD | A only | 32, 64 | | ||
| | SUB | A only | 32, 64 | | ||
| | DEC | A only | 32, 64 | | ||
|
|
||
| --- | ||
|
|
||
| ## Remaining Gaps (P2 — fallback-only, no rewriter exists) | ||
|
|
||
| These ccop+condition combos are NOT handled by either rewriter. Tests would only verify | ||
| the decompiler doesn't crash (produces a raw `_ccall`). Not urgent. | ||
|
|
||
| | Gap | Notes | | ||
| |-----|-------| | ||
| | ADC + CondZ/NZ/S | Tested already, no rewriter path exists | | ||
| | SBB + CondZ/S | Tested already, no rewriter path exists | | ||
| | INC + CondLE/NLE | Tested already, no rewriter path exists | | ||
| | CondP/CondNP (parity) | Not in any rewriter | | ||
| | ROL/ROR | Op types defined but no rewriter code | | ||
| | ANDN/BLSI/BLSMSK/BLSR | AMD64 BMI ops, no rewriter | | ||
| | ADCX/ADOX | AMD64 ADX ops, no rewriter | | ||
|
|
||
| --- | ||
|
|
||
| ## Build System | ||
|
|
||
| ``` | ||
| bash build.sh # builds 54 binaries (27 amd64, 27 i386) | ||
| ``` | ||
|
|
||
| Produces 3 optimization variants per source file x 2 arches: | ||
| - Standard sources: `-O1`, `-O2`, `-Os` | ||
| - INC/DEC: `-O1 -mtune-ctrl=use_incdec`, `-O2 -mtune=haswell`, `-Os -mtune-ctrl=use_incdec` | ||
| - ADC/SBB: same as standard | ||
|
|
||
| All with base flags: `-fno-if-conversion -fno-if-conversion2 -fno-tree-loop-if-convert -g` | ||
|
|
||
| Requires `gcc` and `gcc-multilib` (both installed on this system). | ||
|
|
||
| ## File Layout | ||
|
|
||
| ``` | ||
| ccop_triggers/ | ||
| ├── build.sh # Build script | ||
| ├── ccop_common.h # NOINLINE macro, volatile g_sink, sized typedefs | ||
| ├── ccop_sub.c # 48 funcs — SUB/CMP conditions | ||
| ├── ccop_add.c # 39 funcs — ADD conditions | ||
| ├── ccop_logic.c # 38 funcs — LOGIC (test/and) conditions | ||
| ├── ccop_inc_dec.c # 48 funcs — INC/DEC conditions (inline asm) | ||
| ├── ccop_shl_shr.c # 32 funcs — SHL/SHR conditions | ||
| ├── ccop_umul_smul.c # 16 funcs — multiply overflow | ||
| ├── ccop_adc_sbb.c # ~59 funcs — ADC/SBB multi-precision (inline asm) | ||
| ├── ccop_copy.c # 4 funcs — COPY (pushf/popf) | ||
| ├── ccop_rflags_c.c # 6 funcs — rflags_c carry extraction (amd64) | ||
| ├── .gitignore # Ignores bin/ | ||
| ├── STATUS.md # This file | ||
| └── bin/ # Compiled output (gitignored) | ||
| ├── amd64/ # 27 binaries | ||
| └── i386/ # 27 binaries | ||
|
|
||
| ../test_ccop_triggers.py # Pytest harness (54 parametrized test cases) | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| #!/bin/bash | ||
| # | ||
| # Build all ccop trigger binaries for amd64 and i386. | ||
| # Usage: cd tests/analyses/decompiler/ccop_triggers && bash build.sh | ||
| # | ||
| # Produces multiple variants per source file using different optimization | ||
| # levels, tuning targets, and feature flags to maximize the variety of | ||
| # ccop patterns the compiler emits. | ||
| # | ||
| # Requires: gcc, gcc-multilib (for -m32 builds) | ||
| # | ||
| set -e | ||
|
|
||
| SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" | ||
| cd "$SCRIPT_DIR" | ||
|
|
||
| # Base flags: suppress conditional moves so branches stay as branches, | ||
| # keep debug info for decompiler friendliness | ||
| BASE="-fno-if-conversion -fno-if-conversion2 -fno-tree-loop-if-convert -g" | ||
|
|
||
| # ─── Standard sources: work fine with default tuning ────────────── | ||
| STD_SRCS=( | ||
| ccop_sub | ||
| ccop_add | ||
| ccop_logic | ||
| ccop_shl_shr | ||
| ccop_umul_smul | ||
| ccop_copy | ||
| ccop_rflags_c | ||
| ) | ||
|
|
||
| # ─── INC/DEC source: needs -mtune-ctrl=use_incdec to emit inc/dec ─ | ||
| INCDEC_SRCS=( | ||
| ccop_inc_dec | ||
| ) | ||
|
|
||
| # ─── ADC/SBB source: needs wide types (__int128 on amd64, uint64_t | ||
| # on i386). Standard flags are fine; the code itself triggers it. | ||
| ADCSBB_SRCS=( | ||
| ccop_adc_sbb | ||
| ) | ||
|
|
||
| # Standard optimization variants | ||
| STD_VARIANTS=( | ||
| "O1::-O1" | ||
| "O2::-O2" | ||
| "Os::-Os" | ||
| ) | ||
|
|
||
| # INC/DEC variants: force inc/dec emission via tuning control | ||
| # -mtune-ctrl=use_incdec: explicit GCC override (works with any -mtune) | ||
| # -mtune=haswell: Haswell naturally enables inc/dec | ||
| INCDEC_VARIANTS=( | ||
| "O1_incdec::-O1 -mtune-ctrl=use_incdec" | ||
| "O2_haswell::-O2 -mtune=haswell" | ||
| "Os_incdec::-Os -mtune-ctrl=use_incdec" | ||
| ) | ||
|
|
||
| mkdir -p bin/amd64 bin/i386 | ||
|
|
||
| FAIL=0 | ||
| COUNT=0 | ||
|
|
||
| build_one() { | ||
| local src="$1" name="$2" arch_flag="$3" extra_flags="$4" outdir="$5" | ||
| if gcc $arch_flag $BASE $extra_flags -o "${outdir}/${name}" "${src}.c" 2>&1; then | ||
| COUNT=$((COUNT + 1)) | ||
| else | ||
| echo " FAILED: $name ($outdir)" | ||
| FAIL=1 | ||
| fi | ||
| } | ||
|
|
||
| # Build standard sources with standard variants | ||
| for src in "${STD_SRCS[@]}"; do | ||
| for variant in "${STD_VARIANTS[@]}"; do | ||
| IFS=':' read -r tag _ flags <<< "$variant" | ||
| name="${src}_${tag}" | ||
| echo "Building $name ..." | ||
| build_one "$src" "$name" "" "$flags" "bin/amd64" | ||
| build_one "$src" "$name" "-m32" "$flags" "bin/i386" | ||
| done | ||
| done | ||
|
|
||
| # Build INC/DEC sources with inc/dec-forcing variants | ||
| for src in "${INCDEC_SRCS[@]}"; do | ||
| for variant in "${INCDEC_VARIANTS[@]}"; do | ||
| IFS=':' read -r tag _ flags <<< "$variant" | ||
| name="${src}_${tag}" | ||
| echo "Building $name ..." | ||
| build_one "$src" "$name" "" "$flags" "bin/amd64" | ||
| build_one "$src" "$name" "-m32" "$flags" "bin/i386" | ||
| done | ||
| done | ||
|
|
||
| # Build ADC/SBB sources with standard variants | ||
| for src in "${ADCSBB_SRCS[@]}"; do | ||
| for variant in "${STD_VARIANTS[@]}"; do | ||
| IFS=':' read -r tag _ flags <<< "$variant" | ||
| name="${src}_${tag}" | ||
| echo "Building $name ..." | ||
| build_one "$src" "$name" "" "$flags" "bin/amd64" | ||
| build_one "$src" "$name" "-m32" "$flags" "bin/i386" | ||
| done | ||
| done | ||
|
|
||
| echo "" | ||
| if [ $FAIL -eq 0 ]; then | ||
| echo "Done. Built $COUNT binaries in bin/amd64/ and bin/i386/" | ||
| else | ||
| echo "Done with errors ($COUNT succeeded). Check output above." | ||
| exit 1 | ||
| fi | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The usage hint points to
tests/analyses/decompiler/ccop_triggers, but this script lives undertests_src/ccop_triggers. This is likely to mislead anyone trying to rebuild the binaries; update the usage line (and any other path references) to match the actual repo layout.