# Lifting Bits Patchestry Patchestry

> patchir-inspect: Structuring Verification & Test Generation Tool

- Skill: `tomevault-io/lifting-bits-patchestry-patchestry` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add tomevault-io/lifting-bits-patchestry-patchestry`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tomevault-io/lifting-bits-patchestry-patchestry/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: tomevault-io (https://skillmd.com/u/tomevault-io)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tomevault-io/lifting-bits-patchestry-patchestry

---


# patchir-inspect: Structuring Verification & Test Generation Tool

Two modes for the patchir-decomp pipeline:

- **`--debug`**: verify the default structuring pipeline produces
  functionally equivalent C output compared to the goto-based baseline
  (emitted via the hidden `--emit-flat-baseline` flag), and audit both
  outputs against the input P-Code JSON for emission bugs.
- **`--test-gen`**: extract P-Code from a binary function via Ghidra
  headless and generate a complete LIT test with FileCheck patterns.

## Arguments

```
--debug <fixture.json>                        # equivalence checks (default)
--debug --batch                               # run on ALL fixtures in test/patchir-decomp/
--test-gen --binary <path> --function <name>  # generate LIT test from binary
```

When no mode flag is present, default to `--debug`.

## Mode Dispatch

Each mode runs inside its own isolated `general-purpose` subagent via the
Task tool. This keeps the main context clean — raw decomp outputs, batch
tables, and Docker logs never reach the parent conversation.

- `--debug` → spawn the **Debug Agent** (Task prompt defined below)
- `--test-gen` → spawn the **Test-Gen Agent** (Task prompt defined below)

After the subagent returns, relay its verdict and any findings back to
the user. Do not re-run the checks in the parent context.

---

## Debug Agent

When dispatched, spawn a `general-purpose` subagent using the Task tool
with the prompt template below. Substitute `<FIXTURE>` with the target
JSON (or the literal string `--batch` when batch mode is requested).

```
You are running the patchir-inspect debug-mode workflow against <FIXTURE>.

Project root: <cwd>
Binary: builds/*/tools/patchir-decomp/*/patchir-decomp
Strip script: test/scripts/strip-json-comments.sh
Reference methodology: .claude/skills/patchir-inspect/references/structuring-diff-checks.md

Workflow:

1. For each input fixture (one file or every JSON in test/patchir-decomp/
   when --batch), strip // comments with the strip script and run
   patchir-decomp twice — once with --emit-flat-baseline (goto baseline)
   and once without it (default structured output). Capture stderr.

2. Run the Step 2 functional equivalence checks on both .c outputs:
   - 2.5 Condition preservation (if/while/switch counts, &&/|| merge
     triage)
   - 2.6 Duplicate and cross-scope overwrite detection
   - 2.7 Structuring-introduced dead code
   - 2.8 Fallthrough into goto-only labels
   Full check definitions are in references/structuring-diff-checks.md.

3. Run the Step 3 JSON ground-truth audit on the input P-Code JSON
   vs both C outputs: CALL coverage, CBRANCH/condition, STORE/
   assignment, RETURN, globals, per-block reachability, duplicate
   assignment. Flag definitions are in the reference file.

4. For --batch, emit the summary table with columns Fixture, Status,
   G(goto), G(struct), Elim%, Conds, Fall, JSON, Flags. Aggregate
   stats: total, pass, flag, skip, fully-structured count, goto
   elimination %, condition losses, fallthrough count.

5. Classify findings:
   - Critical: CALL_LOST, missing switch cases, crash, lost conditions,
     Fall>0, 2.6b cross-scope overwrite
   - Bug: DUP_ASSIGN, lost assignments, structuring-introduced dead code
   - Flag: COND_DEFICIT, STORE_DEFICIT, BLOCK_LOST
   - Warning: remaining gotos, dead labels, redundant breaks

6. End with a single VERDICT line:
   - VERDICT: PASS — no Critical/Bug, no unresolved Flags
   - VERDICT: FLAG — Flags present, need triage
   - VERDICT: FAIL — Critical or Bug present

Report concisely. For --batch, include the full table but limit per-
fixture triage narrative to fixtures flagged as non-PASS. For a single
fixture, include any Critical/Bug findings with file:line references.
```

---

## Test-Gen Agent

When dispatched, spawn a `general-purpose` subagent using the Task tool
with the prompt template below. Substitute `<BINARY>` and `<FUNCTION>`
with the user-provided values.

```
You are running the patchir-inspect test-gen workflow for function
"<FUNCTION>" from binary "<BINARY>".

Project root: <cwd>
Decomp binary: builds/*/tools/patchir-decomp/*/patchir-decomp
Ghidra wrapper: scripts/ghidra/decompile-headless.sh
Docker build: scripts/ghidra/build-headless-docker.sh
Call-check generator: scripts/gen-call-checks.py

Workflow:

1. Ensure the Ghidra Docker image exists:
      docker image inspect trailofbits/patchestry-decompilation:latest
   If missing, run scripts/ghidra/build-headless-docker.sh and report
   "Building Ghidra headless Docker image (one-time setup)...". Stop
   on build failure and report stderr.

2. Extract P-Code JSON:
      bash scripts/ghidra/decompile-headless.sh \
        --input <BINARY> \
        --function <FUNCTION> \
        --output /tmp/patchdbg_testgen/<FUNCTION>.json
   Stop on extraction failure and report stderr.

3. Generate baseline outputs from the extracted JSON:
      <decomp> -input <extracted> \
        -emit-cir -emit-llvm -print-tu -output <baseline>

4. Build FileCheck patterns from the baseline:
   - Function signature: grep `cir.func @<FUNCTION>(` from the .cir
     output and emit it as the FN check line.
   - Call targets: run
       python3 scripts/gen-call-checks.py <extracted.json>
     to produce `// CALL-CHECK-DAG: cir.call @<target>(` lines.

5. Assemble test/patchir-decomp/<FUNCTION>.json with this header,
   followed by the raw extracted JSON as-is:
       // RUN: bash %strip-json-comments %s > %t.json
       // RUN: %patchir-decomp -input %t.json -emit-cir -emit-llvm -print-tu -output %t >> /dev/null 2>&1
       // RUN: %file-check -vv -check-prefix=FN %s --input-file %t.cir
       // FN: cir.func @<FUNCTION>(
       // RUN: %gen-call-checks %t.json > %t.call.checks
       // RUN: %file-check -check-prefix=CALL-CHECK %t.call.checks --input-file %t.cir
   Follow the pattern in existing fixtures like bloodview__parse_cli.json
   and bool_ops.json.

6. Validate the generated test:
      lit builds/default/test/patchir-decomp/<FUNCTION>.json \
          -D BUILD_TYPE=Debug -v
   On LIT failure, report the output and leave the file in place.

7. Report:
       Generated: test/patchir-decomp/<FUNCTION>.json
         Source:  <BINARY> :: <FUNCTION>
         Blocks:  N basic blocks, M operations
         Checks:  FN (signature), CALL-CHECK (K call targets)
         LIT:     PASS
```

---

## Additional Resources

### Reference Files

- **`references/structuring-diff-checks.md`** — full methodology for
  checks 2.1–2.10 and 3.1–3.7, flag definitions, triage rules, concrete
  bug examples
- **`references/usage-plan.md`** — development workflow recipes for
  pre-commit gating, regression checking, and test generation

---
> Source: [lifting-bits/patchestry](https://github.com/lifting-bits/patchestry) — distributed by [TomeVault](https://tomevault.io).
<!-- tomevault:4.0:skill_md:2026-06-24 -->

