aboutsummaryrefslogtreecommitdiffstats
path: root/idatui/rpc.py
diff options
context:
space:
mode:
authorblasty <blasty@local>2026-08-07 00:33:12 +0200
committerblasty <blasty@local>2026-08-07 00:33:28 +0200
commit2b0ae8df463edb597007186688ee557c18f1ac18 (patch)
tree006045dd73f4049d98e20a8c0830406490445f08 /idatui/rpc.py
parentlaunch: the sweep could delete the file it was asked to open (diff)
downloadida-tui-2b0ae8df463edb597007186688ee557c18f1ac18.tar.gz
ida-tui-2b0ae8df463edb597007186688ee557c18f1ac18.tar.xz
ida-tui-2b0ae8df463edb597007186688ee557c18f1ac18.zip
diag: somewhere for swallowed errors to go
A TUI must not die because one background load failed, so this codebase catches broadly -- ~50 `except Exception` sites, two dozen resolving to `pass`. Right policy, one bad consequence: with 44 `@work(thread=True)` workers, a failure in a background load leaves no trace whatsoever. The view stays empty and there is nothing to read afterwards, because the app owns the screen. kittygfx already solved this for itself with $IDATUI_KITTY_LOG. idatui/diag.py is the same idea for everything else: $IDATUI_LOG writes every swallowed error plus its traceback to a file, and the last 50 are kept in memory regardless so a driver can ask a live app what went wrong. Unset, it costs an environ lookup. Wired in where losing the error changes a DECISION rather than just a pixel: * rename: a resolve() that throws renames as DATA instead of as a function. * name: a function_of() that throws means we never learn the address is a function start, so the index keeps the old name and every readback says the rename didn't happen. * retype: a resolve() that throws retypes the ENCLOSING function instead. * decompile: a failed full-body fetch silently returns CLIPPED pseudocode. * trail: a failed decomp_map stops the pseudocode being painted, silently. Deliberately NOT wired into the query_one guards -- a modal owning the screen is normal and constant, and logging it would bury the real entries in noise. New RPC verb `diag {n?, clear?}`, documented in docs/RPC.md: the answer to "the verb reported success and the pane shows nothing". Also a flake, same shape as the others: follow_xrefs waited on the nav depth but asserted on _cur, and a follow pushes the source entry BEFORE opening the target -- so the check could run in between and see the function it jumped from. About one run in ten. It waits on the postcondition it asserts now; three clean full runs since. 833 checks; --fast is 344 in 3.5s.
Diffstat (limited to 'idatui/rpc.py')
-rw-r--r--idatui/rpc.py11
1 files changed, 11 insertions, 0 deletions
diff --git a/idatui/rpc.py b/idatui/rpc.py
index b4ca80e..698e4cf 100644
--- a/idatui/rpc.py
+++ b/idatui/rpc.py
@@ -28,6 +28,7 @@ from typing import Any
from rich.console import Console
from ._sync import drain, settle
+from . import diag
from .app import DecompView, GraphView, HexView, ListingView, ViewMode
PROTO_VERSION = 1
@@ -889,6 +890,16 @@ class RpcServer:
return functions(app, params.get("filter"), int(params.get("limit", 50)))
# -- projects ------------------------------------------------------ #
+ if method == "diag":
+ # What has been swallowed lately. A driver that got "success" and a
+ # pane showing nothing has no other way to ask; inside a
+ # full-screen TUI there is nowhere for a traceback to go.
+ if params.get("clear"):
+ diag.clear()
+ return {"cleared": True}
+ return {"recent": diag.recent(int(params.get("n", 10))),
+ "log": os.environ.get("IDATUI_LOG") or None}
+
if method == "trace":
tc = app.trace_ctl
if tc.trace is None: