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"]),