diff options
| author | blasty <blasty@local> | 2026-07-25 12:15:45 +0200 |
|---|---|---|
| committer | blasty <blasty@local> | 2026-07-25 12:15:45 +0200 |
| commit | 7569141dc750cfd75347c14156773e3184a5b965 (patch) | |
| tree | e4bc4bbf17e33cf9778a4d95e4d3511694849409 /server/patch_server.py | |
| parent | ui: horizontally centre the splash logo in the loading dialog (diff) | |
| download | ida-tui-7569141dc750cfd75347c14156773e3184a5b965.tar.gz ida-tui-7569141dc750cfd75347c14156773e3184a5b965.tar.xz ida-tui-7569141dc750cfd75347c14156773e3184a5b965.zip | |
retype: 'y' now retypes globals too, not just prototypes and locals
In the decompiler, 'y' on a local variable already worked (func_types -> lvars ->
set_lvar_type), but a GLOBAL fell through every case and silently retyped the
ENCLOSING FUNCTION'S PROTOTYPE — worse than not working, since the prompt said
"prototype" while you thought you were typing a variable.
* server/patch_server.py: new data_type tool — {addr,name,type,size,is_func} for
a data item, so the prompt can prefill the current type and the caller can tell
a global from a function.
* domain: Program.data_type() + set_data_type() (set_type with kind="global").
* app: _prepare_retype gains the data case between "function" and the
current-function fallback, with a size-based prefill when the global is still
untyped; _do_retype routes kind="data" to set_data_type.
Classification verified on echo/main: 'v3' -> lvar (prefill 'char *'), 'stdout'
-> data (prefill 'FILE *'), 'main' -> func prototype, an unresolvable token ->
the enclosing prototype (unchanged fallback).
Also fixes a latent crash found while probing this: on_listing/decomp_view_
cursor_moved called self.query_one(ListingView), but App.query_one searches the
TOP screen — a cursor-moved message landing while any modal is up (loading
overlay, project switch) raised NoMatches out of a message handler and killed the
app. Both handlers now go through _try_view().
Pilot `retype` extended to 9 checks covering all three flavours, each asserting
the other targets are left alone. Two of the new checks needed settles: applying
a retype recompiles asynchronously, so scanning/indexing the pseudocode without
waiting reads text that's about to be replaced (this also cut the scenario from
30s to 2.6s of previously-wasted timeout). Full suite 174/2-flake.
Diffstat (limited to 'server/patch_server.py')
| -rw-r--r-- | server/patch_server.py | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/server/patch_server.py b/server/patch_server.py index 96c4689..09bca86 100644 --- a/server/patch_server.py +++ b/server/patch_server.py @@ -586,6 +586,35 @@ def xref_types( @tool @idasync +def data_type( + addr: Annotated[str, "Address or name of a data item / global"], +) -> dict: + """The current C type of a data item, for prefilling a retype prompt: + {addr, name, type, size, is_func}. ``type`` is empty when the item is + untyped; ``is_func`` distinguishes a global from a function so the caller + knows which flavour of set_type to use.""" + import idaapi + import ida_bytes + import ida_name + import idc + raw = str(addr).strip() + try: + ea = int(raw, 16) + except ValueError: + ea = idaapi.get_name_ea(idaapi.BADADDR, raw) + if ea == idaapi.BADADDR or not ida_bytes.is_mapped(ea): + return {"addr": raw, "error": f"not a mapped address: {raw}"} + return { + "addr": hex(ea), + "name": ida_name.get_name(ea) or "", + "type": idc.get_type(ea) or "", + "size": int(ida_bytes.get_item_size(ea) or 0), + "is_func": bool(idaapi.get_func(ea)), + } + + +@tool +@idasync def decomp_map( addr: Annotated[str, "Function address or name"], ) -> dict: |
