Add shared reverse-engineering lookups (re_disassemble, re_xrefs, re_bytes, re_lookup)
Read the project's flat image, facts.jsonl and annotations with the team's current names; exposed as MCP tools and as 'harbor re'. Configured by a [reverse] table in the project file.
This commit is contained in:
1 parent
dbc0c45ef2
commit
3f6df88f95
5 files changed
+410
-2
No files matched your search
+49
-1
@@ -33,7 +33,9 @@ review queue, presence and stop flags. Protocol:
|
||||
7. Put finished work in the review queue with submit(); do not announce commits in chat. A coordinator lands it.
|
||||
8. When you are waiting on someone, use wait_for_messages() instead of polling or sleeping.
|
||||
9. A correction is send(..., corrects=<id of your earlier message>).
|
||||
10. Before your session ends or your allowance runs out, write handoff(): finished, in flight, next."""
|
||||
10. Before your session ends or your allowance runs out, write handoff(): finished, in flight, next.
|
||||
11. To read the original machine code use re_disassemble, re_xrefs, re_bytes and re_lookup: they read the project's
|
||||
own image with the team's current names, so do not write your own disassembler or offset maths."""
|
||||
|
||||
KindName = Literal["note", "question", "answer", "request", "finding", "retraction", "decision", "status", "handoff"]
|
||||
Importance = Literal["normal", "high", "urgent"]
|
||||
@@ -436,6 +438,52 @@ def resume(target: str, relay_of: int | None = None, reason: str | None = None)
|
||||
return run(do)
|
||||
|
||||
|
||||
_reverse = {}
|
||||
|
||||
|
||||
def _re(fn):
|
||||
"""Run a reverse-engineering lookup against the project's [reverse] files (read-only, no Harbor lock needed)."""
|
||||
try:
|
||||
h = harbor()
|
||||
r = _reverse.get(h.project.name)
|
||||
if r is None:
|
||||
from .reverse import Reverse
|
||||
r = _reverse[h.project.name] = Reverse(h.project.reverse)
|
||||
return fn(r)
|
||||
except (HarborError, projects.ProjectError) as error:
|
||||
raise ToolError(str(error)) from None
|
||||
|
||||
|
||||
@mcp.tool
|
||||
def re_disassemble(target: str, max_bytes: int | None = None) -> str:
|
||||
"""Disassemble the whole function at an address or name (or max_bytes from the address), from the project's own
|
||||
image of the executable, with call targets, imports and known globals named from the team's annotations. Use
|
||||
this instead of writing your own disassembler script."""
|
||||
return _re(lambda r: r.disassemble(target, max_bytes))
|
||||
|
||||
|
||||
@mcp.tool
|
||||
def re_xrefs(target: str) -> dict:
|
||||
"""Callers and callees of the function at an address or name, plus the globals, imports and strings it uses,
|
||||
each with its current name."""
|
||||
return _re(lambda r: r.xrefs(target))
|
||||
|
||||
|
||||
@mcp.tool
|
||||
def re_bytes(target: str, count: int = 16, as_type: Literal["hex", "int32", "uint32", "float", "double",
|
||||
"string"] = "hex") -> dict:
|
||||
"""Bytes at an address or name, read as hex, int32, uint32, float, double or a C string (constants, tables,
|
||||
initial values of globals)."""
|
||||
return _re(lambda r: r.bytes_at(target, count, as_type))
|
||||
|
||||
|
||||
@mcp.tool
|
||||
def re_lookup(target: str) -> dict:
|
||||
"""What the team has recorded about an address or name: the names.csv, functions.csv and globals.csv rows, the
|
||||
prototype, the containing function, and the decompiled file with its status."""
|
||||
return _re(lambda r: r.lookup(target))
|
||||
|
||||
|
||||
def _report_in():
|
||||
"""Tell Harbor this agent's app has its tools running: at start, then every 5 minutes while the app keeps the
|
||||
server open (updates the connection only, not the agent's last-seen time)."""
|
||||
|
||||
Reference in new issue
Block a user