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
|
diff --git a/server/patch_server.py b/server/patch_server.py
index 6667e12..5e20671 100644
--- a/server/patch_server.py
+++ b/server/patch_server.py
@@ -1900,7 +1900,7 @@ def _idatui_lit_extent(plain, x):
return (lo, hi)
-def _idatui_pc_nums(cf, sl):
+def _idatui_pc_nums(cf, sl, plain=None):
"""Every number literal on one pseudocode line, as
[{x0, x1, ea, opnum, value, nbytes, fmt}].
@@ -1912,16 +1912,26 @@ def _idatui_pc_nums(cf, sl):
import ida_lines
import idaapi
- plain = ida_lines.tag_remove(sl.line)
+ # ``plain`` is the untagged line; callers that already have it pass it in
+ # rather than making tag_remove run twice over every line of the function.
+ if plain is None:
+ plain = ida_lines.tag_remove(sl.line)
out = []
x = 0
+ # One ctree_item_t for the whole line, and no head/tail at all. They are
+ # SWIG allocations in the innermost loop of a scan that probes every
+ # literal-looking character -- and 'a' to 'f' are hex digits, so `a1`, `v6`
+ # and `sub_1F4C0` all qualify and most columns of a line get probed. head
+ # and tail were never read. (Same three costs as decomp_map's sweep.)
+ item = ida_hexrays.ctree_item_t()
+ line = sl.line
+ get_line_item = cf.get_line_item
while x < len(plain):
ch = plain[x]
if ch not in _IDATUI_LIT_CHARS and ch != "'":
x += 1
continue
- head, item, tail = (ida_hexrays.ctree_item_t() for _ in range(3))
- if not cf.get_line_item(sl.line, x, True, head, item, tail):
+ if not get_line_item(line, x, True, None, item, None):
x += 1
continue
if item.citype != ida_hexrays.VDI_EXPR:
@@ -1997,7 +2007,7 @@ def pc_nums(
for i in range(len(sv)):
plain = ida_lines.tag_remove(sv[i].line)
compact = _idatui_compact(plain)
- for rec in _idatui_pc_nums(cf, sv[i]):
+ for rec in _idatui_pc_nums(cf, sv[i], plain):
out.append({
"line": i,
"x0": _idatui_compact_col(plain, compact, rec["x0"]),
|