Add annotate for bulk comments/renames, and say what to do about --raw - #225
Open
subwire wants to merge 1 commit into
Open
Add annotate for bulk comments/renames, and say what to do about --raw#225subwire wants to merge 1 commit into
annotate for bulk comments/renames, and say what to do about --raw#225subwire wants to merge 1 commit into
Conversation
Member
|
Fix conflicts plz. |
Two remaining gaps from a CTF where DecLib was the sole decompiler
interface.
**Bulk annotation.** Annotation is produced in bulk -- you read a binary,
build a mapping of address to label, then want to write it back. Applying
that one `comment set` at a time is N round-trips, so people drove the
Python client directly instead: one challenge passed
`renames={0x5440: 'detect_branch_trampoline', ...}` straight to
DecompilerClient, and another skipped DecLib entirely, opening the IDB
with idapro and calling ida_funcs.set_func_cmt in a loop.
decompiler annotate --file notes.json
echo '{"0x401000": "parses the header"}' | decompiler annotate
Accepts a list of {"addr", "comment"?, "name"?} records, or the shorthand
{addr: comment} object -- the shape people already build by hand. Backed
by `apply_annotations` on DecompilerInterface, which like decompile_many
defaults to an in-process loop and so collapses N round-trips into one for
every backend.
Renames are verified by read-back rather than assumed: a backend can
accept the write and quietly not apply it, and a silently miscounted
rename is worse than a reported failure. Per-item failures are returned to
the caller (address, field, reason) instead of only reaching the server
log, and one bad record no longer discards the batch.
Failure text is never blank. An exception raised without arguments has an
empty str(), which surfaced as "failed 0xdeadbe00 (name): " with no reason
at all -- the same class of bug as the propagate-server-error-text branch.
It now reads "KeyError (no message)".
**`--raw` inside `batch`.** The rejection is correct -- batch results are
structured, and raw text on stdout would corrupt them -- but "not allowed"
left the caller guessing, and we logged 7 hits on it. The message now
names the replacement: the text is already in results[].result.text.
Tests: bulk apply keeps going past a bad record, missing/empty records are
reported rather than raised, a blank exception cannot produce a blank
reason, and the --raw message names its replacement.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Collaborator
Author
|
Rebased onto current The conflicts were all against #222 landing ( |
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Problem
Two remaining gaps from D3CTF 2026, where we ran DecLib as the sole decompiler interface for a fleet of autonomous CTF agents.
Annotation is produced in bulk. You read a binary, build up a mapping of address to label, then want to write it back. Applying that one
comment setat a time is N round-trips — so people bypassed the CLI:renames={0x5440: 'detect_branch_trampoline', 0x5674: 'detect_any_hook', ...}straight toDecompilerClient.import idapro, open the.i64, loopida_funcs.set_func_cmt.--rawinsidebatchwas rejected with no hint about the alternative (7 hits in our logs).Change
Accepts either a list of records:
[{"addr": "0x401000", "comment": "parses the header", "name": "parse_hdr"}]…or the shorthand
{addr: comment}object — the shape people already build by hand.Backed by
apply_annotationsonDecompilerInterface, which (likedecompile_manyin #222) defaults to an in-process loop and so collapses N round-trips into one for every backend, with no per-backend code.Three deliberate robustness choices:
str(), which surfaced asfailed 0xdeadbe00 (name):with no reason — the same class of bug as Propagate server-side error text instead of dropping it #220. It now readsKeyError (no message).For
batch, the--rawrejection stays (raw text on stdout would corrupt structured results), but the message now names the replacement: the text is already inresults[].result.text.Verification
Against IDA on a real binary:
comments: 1, names: 1, failed: 0; both verified present afterwards{addr: comment}failed: 1, reasonKeyError (no message), exit 1Tests
Bulk apply keeps going past a bad record; missing-address and empty records are reported rather than raised; a blank exception cannot produce a blank reason; the
--rawmessage names its replacement.🤖 Generated with Claude Code