aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorblasty <blasty@local>2026-07-23 22:01:21 +0200
committerblasty <blasty@local>2026-07-23 22:01:21 +0200
commit4a3cf34f845e1865b2c1e663b2369ddbc490f5e6 (patch)
tree1910467ac5161e5a03e3fd801244713c2497e529
parentfix: don't let a late navigation steal focus from an open prompt (diff)
downloadida-tui-4a3cf34f845e1865b2c1e663b2369ddbc490f5e6.tar.gz
ida-tui-4a3cf34f845e1865b2c1e663b2369ddbc490f5e6.tar.xz
ida-tui-4a3cf34f845e1865b2c1e663b2369ddbc490f5e6.zip
fix: follow/double-click a label lands on the label, not the function entry
resolve(name) went through lookup_funcs, which for a mid-function label (loc_/locret_) does get_name_ea -> label ea, then get_function(ea) and reports the CONTAINING function's entry address. So double-clicking (or following) a label jumped to the top of the function instead of the label's own address. Add a server tool resolve_names that returns the address a name actually denotes via idaapi.get_name_ea (functions, labels and data alike), and route Program.resolve() through it, keeping lookup_funcs only as a fallback for the "did you mean ..." suggestion on an unknown name. Verified: resolve('loc_2040') -> 0x2040 (was the function entry); double-click follow on a label row lands on the label ea. Regression sweep follow_xrefs/xref_labels/rename/rename_history/decomp_follow_self/search/ listing_view/disasm_nav/mouse 50/0. Needs a supervisor restart (new tool).
-rw-r--r--idatui/domain.py16
-rw-r--r--server/patch_server.py19
2 files changed, 33 insertions, 2 deletions
diff --git a/idatui/domain.py b/idatui/domain.py
index e8e2996..2a3fc2b 100644
--- a/idatui/domain.py
+++ b/idatui/domain.py
@@ -1274,8 +1274,20 @@ class Program:
return int(s, 16)
if re.fullmatch(r"[0-9a-fA-F]+", s):
return int(s, 16)
- # Symbol name -> ask the server. lookup_funcs takes an array of strings
- # and returns [{"query":..., "fn": {addr,name,size} | null, "error":...}].
+ # Symbol name -> resolve to the address the NAME denotes (get_name_ea via
+ # resolve_names). This handles functions, data AND mid-function labels
+ # (loc_/locret_): lookup_funcs would map a label to its *containing*
+ # function's entry, so double-clicking a label jumped to the wrong place.
+ try:
+ payload = self.client.call("resolve_names", queries=[s])
+ res = payload.get("result", []) if isinstance(payload, dict) else []
+ ea = res[0].get("ea") if res and isinstance(res[0], dict) else None
+ if ea:
+ return _as_int(ea)
+ except IDAToolError:
+ pass # older server without resolve_names -> fall back below
+ # Fall back to function-name resolution (also drives the 'did you mean'
+ # suggestion when the name is unknown).
try:
payload = self.client.call("lookup_funcs", queries=[s])
except IDAToolError as e:
diff --git a/server/patch_server.py b/server/patch_server.py
index 7ee490a..ff14a09 100644
--- a/server/patch_server.py
+++ b/server/patch_server.py
@@ -42,6 +42,25 @@ def _idatui_lv_get(x):
@tool
@idasync
+def resolve_names(
+ queries: Annotated[list, "Symbol name(s) to resolve to their OWN address"],
+) -> list:
+ """Resolve named locations (functions, labels like loc_/locret_, data) to the
+ exact address the NAME denotes, via get_name_ea. Unlike lookup_funcs, a
+ mid-function label resolves to the label's address, not the containing
+ function's entry."""
+ import idaapi
+ qs = queries if isinstance(queries, list) else [queries]
+ out = []
+ for q in qs:
+ q = str(q).strip()
+ ea = idaapi.get_name_ea(idaapi.BADADDR, q)
+ out.append({"query": q, "ea": (hex(ea) if ea != idaapi.BADADDR else None)})
+ return out
+
+
+@tool
+@idasync
def del_type(
name: Annotated[str, "Local type name to delete (struct/union/enum/typedef)"],
) -> dict: