1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
"""Profile persistent ida-tui operations inside the IDA process.
The profiler itself is a typed ``RemoteModule`` function in ``remote_tools.py``;
this file contains no generated Python source or knowledge of remote module names.
Usage::
PYTHONPATH=. python experiments/profile_remote.py [BINARY]
PYTHONPATH=. python experiments/profile_remote.py --op decompile
"""
from __future__ import annotations
import argparse
import os
from idatui import remote_ops
from idatui.nexus_client import NexusClient
CALLS = {
"heads": ("heads", {"count": 500, "annotate": True}),
"heads_plain": ("heads", {"count": 500, "annotate": False}),
"heads_skeleton": (
"heads",
{"count": 500, "annotate": True, "text": False},
),
"decompile": ("decompile", {}),
}
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("binary", nargs="?", default="targets/bash")
parser.add_argument("--op", default="heads", choices=sorted(CALLS))
parser.add_argument("--reps", type=int, default=20)
parser.add_argument("--addr", default=None, help="default: the .text start")
args = parser.parse_args()
client = NexusClient(os.path.abspath(args.binary)).connect()
addr = args.addr
if addr is None:
regions = client.call(remote_ops.file_regions)
rows = regions.get("regions") or regions.get("result") or []
text = next(
(row for row in rows if ".text" in str(row.get("name", ""))),
None,
)
addr = (text or rows[0])["start"] if rows else "0x0"
operation, call_args = CALLS[args.op]
call_args = {"addr": addr, **call_args}
print(
f"# {os.path.basename(args.binary)} op={args.op} "
f"addr={addr} reps={args.reps}"
)
# Install the persistent tool module and warm its caches before profiling.
client.call(remote_ops.heads, addr=addr, count=500, annotate=True)
out = client.call(
remote_ops.profile_remote,
operation=operation,
args=call_args,
reps=args.reps,
)
per = out["total"] / out["reps"] * 1000
print(f"# {out['total'] * 1000:.0f}ms total, {per:.1f}ms per call\n")
print(out["stats"])
client.close()
return 0
if __name__ == "__main__":
raise SystemExit(main())
|