import argparse
import ntoseye
def main() -> None:
ap = argparse.ArgumentParser(description=__doc__)
ap.add_argument("--backend", default="kd", choices=["gdb", "kd"])
ap.add_argument("--connect", default=None)
ap.add_argument("--process", default="lsass.exe")
ap.add_argument("--frames", type=int, default=4, help="frames to print per thread")
args = ap.parse_args()
dbg = ntoseye.attach(backend=args.backend, connect=args.connect)
dbg.interrupt()
try:
proc = next((p for p in dbg.processes() if p.ImageFileName == args.process), None)
if proc is None:
raise SystemExit(f"process {args.process!r} not found")
threads = proc.threads()
print(f"{args.process}: {len(threads)} threads\n")
for thread in threads:
vcpu = dbg.select_thread(thread.addr)
info = dbg.selected_thread()
where = f"on {vcpu}" if vcpu else "parked"
print(
f"tid {info.tid:>5} {info.state_name:<10} {info.wait_reason_name or '-':<14} {where}"
)
try:
for frame in dbg.backtrace(args.frames):
print(f" {frame.ip:#x} {frame.symbol}")
except ntoseye.NtoseyeError as exc:
print(f" (no stack: {exc})")
dbg.select_thread(None)
print("\nlive thread, frame 1 selected:")
frame = dbg.select_frame(1)
print(f" {frame.index}: ip={frame.ip:#x} sp={frame.sp:#x} ({dbg.closest_symbol(frame.ip)})")
print(f" rsp now reads {dbg.registers()['rsp']:#x}")
dbg.select_frame(None)
finally:
dbg.cont()
if __name__ == "__main__":
main()