diff options
| author | user <user@clank> | 2026-08-07 08:32:31 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-08-07 08:32:31 +0200 |
| commit | 853d90c9866f3996a8ce66ac70f0559ccfad21c5 (patch) | |
| tree | b46febfe454fb7ad17da4c7f822ff949d53c1513 /server/patch_server.py | |
| parent | The page-freshness check carries the digest the client already holds (heads(e... (diff) | |
| download | ida-tui-853d90c9866f3996a8ce66ac70f0559ccfad21c5.tar.gz ida-tui-853d90c9866f3996a8ce66ac70f0559ccfad21c5.tar.xz ida-tui-853d90c9866f3996a8ce66ac70f0559ccfad21c5.zip | |
decomp_map: memoise obj_id -> ea for the whole function instead of only comparing against the previous column. dstr() was 79% of the tool (24us a call) and items interleave, so foo(a, b) flips call->arg->call and re-formatted an item already seen: 106594 calls for 15417 lines of bash. Also corrects run #30's claim that the duplicate ida_hexrays.decompile is what costs -- a warm decompile is 0.01ms.
Result: {"status":"keep","total_ms":24513.8,"lg_boot_ms":693.2,"lg_decomp_ms":2347.3,"lg_graph_ms":931.2,"lg_hex_ms":460.3,"lg_index_ms":69.1,"lg_listing_cold_ms":434.2,"lg_listing_warm_ms":462.4,"lg_nav_ms":6639.6,"lg_palette_ms":4.7,"lg_rename_ms":699.9,"lg_render_ms":219.7,"lg_search_ms":3441.1,"lg_split_ms":2218,"pure_graph_ms":216.5,"sm_boot_ms":436.9,"sm_decomp_ms":1264.9,"sm_graph_ms":758.2,"sm_hex_ms":437.9,"sm_index_ms":2.3,"sm_listing_cold_ms":256.8,"sm_listing_warm_ms":256,"sm_nav_ms":309.5,"sm_palette_ms":0.3,"sm_rename_ms":379.1,"sm_render_ms":249.5,"sm_search_ms":59.2,"sm_split_ms":1266,"fails":0}
Diffstat (limited to 'server/patch_server.py')
| -rw-r--r-- | server/patch_server.py | 42 |
1 files changed, 28 insertions, 14 deletions
diff --git a/server/patch_server.py b/server/patch_server.py index e860676..6667e12 100644 --- a/server/patch_server.py +++ b/server/patch_server.py @@ -983,13 +983,19 @@ def decomp_map( # read, so don't ask for them at all. # * sweep the TAGGED length. ``x`` is a screen column but ``sl.line`` still # carries IDA's colour tags, so a 23-column line was swept 124 times. - # * call dstr() per column. It formats a whole 'EA: description' string, and - # consecutive columns are nearly always the same ctree item -- so ask the - # item for its id first and only format when it changes. (The result is - # deduped by ``seen`` anyway, so skipping a repeat cannot change it.) + # * call dstr() per column. It formats a whole 'EA: description' string -- + # 24us a call, which is 79% of this tool. Comparing against the PREVIOUS + # column's item id is not enough: items interleave, so `foo(a, b)` flips + # call -> arg -> call -> arg and every flip re-formats an item already + # seen (106 594 calls for 15 417 lines of bash). Memoise id -> ea for the + # whole function instead: obj_id is unique within a cfunc, so the same id + # always yields the same string, and the result is deduped by ``seen`` + # anyway. Items with no ctree node (it is None) have no id to key on and + # still pay per occurrence. item = ida_hexrays.ctree_item_t() tag_remove = ida_lines.tag_remove get_line_item = cfunc.get_line_item + ea_of_id = {} lines = [] for sl in cfunc.get_pseudocode(): line = sl.line @@ -1004,21 +1010,29 @@ def decomp_map( if oid == prev_id: continue prev_id = oid + if oid in ea_of_id: + e = ea_of_id[oid] + if e is not None and e not in seen: + seen.add(e) + eas.append(hex(e)) + continue else: + oid = None prev_id = None # Match the /*ea*/ marker's source (decompile_function_safe): the # item's dstr() is 'EA: description'; get_ea() reports a different ea. + e = None dstr = item.dstr() - if not dstr: - continue - parts = dstr.split(": ", 1) - if len(parts) != 2: - continue - try: - e = int(parts[0], 16) - except ValueError: - continue - if e not in seen: + if dstr: + parts = dstr.split(": ", 1) + if len(parts) == 2: + try: + e = int(parts[0], 16) + except ValueError: + e = None + if oid is not None: + ea_of_id[oid] = e + if e is not None and e not in seen: seen.add(e) eas.append(hex(e)) lines.append({"ea": eas[0] if eas else None, "eas": eas}) |
