chore: commit G3.2+G3.3 deploy binaries + debug scripts; ignore debug run artifacts
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
# waitscan for gui_probe bridge_exact11 (PASS case): dump threads while the
|
||||
# probe is attached, to compare against the hung bridge.
|
||||
import ctypes, ctypes.wintypes as w, struct, subprocess, sys, os, time
|
||||
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
|
||||
LOG = os.path.join(os.path.dirname(os.path.abspath(__file__)), "waitscan_probe.log")
|
||||
PROBE = r"C:\Users\locpham\SonicForgeStudio\native_bridge\build\Release\gui_probe.exe"
|
||||
PATH = r"C:\Program Files\Common Files\VST3\Nexus.vst3"
|
||||
def wait_log(pattern, timeout):
|
||||
end = time.time() + timeout
|
||||
while time.time() < end:
|
||||
try:
|
||||
with open(LOG, 'r', encoding='utf-8', errors='replace') as f:
|
||||
if pattern in f.read():
|
||||
return True
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
time.sleep(0.2)
|
||||
return False
|
||||
proc = subprocess.Popen([PROBE, PATH, "bridge_exact11", "60"],
|
||||
stdout=open(LOG, 'wb'), stderr=subprocess.STDOUT)
|
||||
pid = proc.pid
|
||||
print("pid", pid)
|
||||
if not wait_log("isPlatformTypeSupported=0", 120):
|
||||
print("TIMEOUT"); sys.exit(1)
|
||||
time.sleep(3)
|
||||
k32 = ctypes.windll.kernel32
|
||||
PROCESS_QUERY_INFORMATION = 0x0400
|
||||
PROCESS_VM_READ = 0x0010
|
||||
PROCESS_DUP_HANDLE = 0x0040
|
||||
TH32CS_SNAPTHREAD = 0x4
|
||||
THREAD_GET_CONTEXT = 0x0008
|
||||
THREAD_QUERY_INFORMATION = 0x0040
|
||||
THREAD_SUSPEND_RESUME = 0x0002
|
||||
k32.OpenProcess.argtypes = [w.DWORD, w.BOOL, w.DWORD]
|
||||
k32.OpenProcess.restype = ctypes.c_void_p
|
||||
hProc = k32.OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_DUP_HANDLE, False, pid)
|
||||
if not hProc:
|
||||
print("OpenProcess failed", ctypes.get_last_error()); sys.exit(1)
|
||||
psapi = ctypes.windll.psapi
|
||||
class MODULEINFO(ctypes.Structure):
|
||||
_fields_ = [("lpBaseOfDll", ctypes.c_void_p), ("SizeOfImage", w.DWORD),
|
||||
("pad", w.DWORD), ("EntryPoint", ctypes.c_void_p)]
|
||||
psapi.EnumProcessModulesEx.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_void_p), w.DWORD, ctypes.POINTER(w.DWORD), w.DWORD]
|
||||
psapi.GetModuleInformation.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.POINTER(MODULEINFO), w.DWORD]
|
||||
psapi.GetModuleBaseNameA.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_char_p, w.DWORD]
|
||||
nmods = w.DWORD(0)
|
||||
psapi.EnumProcessModulesEx(hProc, None, 0, ctypes.byref(nmods), 3)
|
||||
arr = (ctypes.c_void_p * (nmods.value // 8))()
|
||||
psapi.EnumProcessModulesEx(hProc, arr, nmods.value, ctypes.byref(nmods), 3)
|
||||
mods = []
|
||||
for m in arr:
|
||||
if not m: continue
|
||||
mi = MODULEINFO()
|
||||
psapi.GetModuleInformation(hProc, m, ctypes.byref(mi), ctypes.sizeof(MODULEINFO))
|
||||
name = ctypes.create_string_buffer(260)
|
||||
psapi.GetModuleBaseNameA(hProc, m, name, 260)
|
||||
mods.append((mi.lpBaseOfDll, mi.SizeOfImage, name.value.decode('latin1')))
|
||||
def resolve(addr):
|
||||
for base, size, name in mods:
|
||||
if base <= addr < base + size:
|
||||
return f"{name}+0x{addr-base:x}"
|
||||
return f"0x{addr:x}"
|
||||
class THREADENTRY32(ctypes.Structure):
|
||||
_fields_ = [("dwSize", w.DWORD), ("cntUsage", w.DWORD), ("th32ThreadID", w.DWORD),
|
||||
("th32OwnerProcessID", w.DWORD), ("tpBasePri", w.LONG),
|
||||
("tpDeltaPri", w.LONG), ("dwFlags", w.DWORD)]
|
||||
te = THREADENTRY32()
|
||||
te.dwSize = ctypes.sizeof(THREADENTRY32)
|
||||
snap = k32.CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0)
|
||||
ok = k32.Thread32First(snap, ctypes.byref(te))
|
||||
threads = []
|
||||
while ok:
|
||||
if te.th32OwnerProcessID == pid:
|
||||
threads.append(te.th32ThreadID)
|
||||
ok = k32.Thread32Next(snap, ctypes.byref(te))
|
||||
k32.CloseHandle(snap)
|
||||
print(f"threads: {threads}")
|
||||
class CONTEXT(ctypes.Structure):
|
||||
_fields_ = [("raw", ctypes.c_ubyte * 0x4d0)]
|
||||
CONTEXT_AMD64 = 0x00100000
|
||||
CONTEXT_FULL = CONTEXT_AMD64 | 0x3
|
||||
def ctx_regs(ctx):
|
||||
b = bytes(ctx.raw)
|
||||
u = lambda o: struct.unpack_from('<Q', b, o)[0]
|
||||
return dict(rip=u(0xF8), rsp=u(0x98), rcx=u(0x80), rdx=u(0x88), r8=u(0xB8), r9=u(0xC0))
|
||||
k32.GetThreadContext.argtypes = [ctypes.c_void_p, ctypes.POINTER(CONTEXT)]
|
||||
k32.GetThreadContext.restype = w.BOOL
|
||||
k32.SuspendThread.argtypes = [ctypes.c_void_p]
|
||||
k32.ResumeThread.argtypes = [ctypes.c_void_p]
|
||||
k32.OpenThread.argtypes = [w.DWORD, w.BOOL, w.DWORD]
|
||||
k32.OpenThread.restype = ctypes.c_void_p
|
||||
k32.CloseHandle.argtypes = [ctypes.c_void_p]
|
||||
for tid in threads:
|
||||
ht = k32.OpenThread(THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SUSPEND_RESUME, False, tid)
|
||||
if not ht:
|
||||
print(f"tid {tid}: open fail"); continue
|
||||
k32.SuspendThread(ht)
|
||||
ctx = CONTEXT()
|
||||
struct.pack_into('<I', ctx.raw, 0x30, CONTEXT_FULL)
|
||||
if k32.GetThreadContext(ht, ctypes.byref(ctx)):
|
||||
r = ctx_regs(ctx)
|
||||
print(f"tid {tid}: rip={resolve(r['rip'])} rcx=0x{r['rcx']:x} r9=0x{r['r9']:x}")
|
||||
else:
|
||||
print(f"tid {tid}: GetThreadContext fail")
|
||||
k32.ResumeThread(ht)
|
||||
k32.CloseHandle(ht)
|
||||
proc.terminate()
|
||||
Reference in New Issue
Block a user