#!/usr/bin/env python3 """fnsample.py — active RIP sampling of all threads via PTRACE_INTERRUPT during the offline-render burst. Finds which code ACTUALLY executes.""" import ctypes import glob import os import signal import struct import subprocess import sys import time MOD_LO, MOD_HI = 0x180001000, 0x181baa000 DUR = float(os.environ.get('SAMP_DUR', '2.5')) PTRACE_CONT = 7 PTRACE_GETREGS = 12 PTRACE_INTERRUPT = 0x4207 PTRACE_SEIZE = 0x4206 PTRACE_O_TRACECLONE = 2 libc = ctypes.CDLL('libc.so.6', use_errno=True) class UserRegs(ctypes.Structure): _fields_ = [(n, ctypes.c_ulonglong) for n in ( 'r15', 'r14', 'r13', 'r12', 'rbp', 'rbx', 'r11', 'r10', 'r9', 'r8', 'rax', 'rcx', 'rdx', 'rsi', 'rdi', 'orig_rax', 'rip', 'cs', 'eflags', 'rsp', 'ss', 'fs_base', 'gs_base', 'ds', 'es', 'fs', 'gs')] def pt(req, pid, addr=0, data=0): libc.ptrace.restype = ctypes.c_long r = libc.ptrace(req, pid, ctypes.c_void_p(addr), ctypes.c_void_p(data)) return None if r == -1 else r def find_host(): for p in glob.glob('/proc/[0-9]*'): pid = int(os.path.basename(p)) try: cmd = open(f'/proc/{pid}/cmdline', 'rb').read().replace(b'\0', b' ').decode('utf8', 'replace') maps = open(f'/proc/{pid}/maps').read() except Exception: continue if 'soothe2' in maps and 'reaper' not in cmd: return pid return None def main(): subprocess.run("pkill -9 -x reaper; pkill -9 -f '[y]abridge'; sleep 1", shell=True) proc = subprocess.Popen(['/usr/bin/reaper', '-nosplash', '-ignoreerrors', '-renderproject', '/home/m/soothe-bt/dual_b1q_0.5.rpp'], stdout=open('/dev/null', 'w'), stderr=subprocess.STDOUT) host = None t0 = time.time() while time.time() - t0 < 30 and not host: host = find_host() time.sleep(0.002) if not host: print('NO HOST') return 1 print('host %d at %.3fs' % (host, time.time() - t0), flush=True) seized = {host} pt(PTRACE_SEIZE, host, 0, PTRACE_O_TRACECLONE) pt(PTRACE_CONT, host, 0, 0) ips = {} t_end = time.time() + DUR t_start = None nsamp = 0 while time.time() < t_end: # resweep tids occasionally for tid_s in glob.glob(f'/proc/{host}/task/*'): tid = int(os.path.basename(tid_s)) if tid not in seized: if pt(PTRACE_SEIZE, tid, 0, PTRACE_O_TRACECLONE) is not None: seized.add(tid) for tid in list(seized): if pt(PTRACE_INTERRUPT, tid) is None: continue got = False for _ in range(20): try: pid, status = os.waitpid(tid, os.WUNTRACED | os.WNOHANG) except ChildProcessError: break if pid == tid: got = True break time.sleep(0.0002) if got: regs = UserRegs() if pt(PTRACE_GETREGS, tid, 0, ctypes.addressof(regs)) is not None: nsamp += 1 if t_start is None: t_start = time.time() if MOD_LO <= regs.rip < MOD_HI: b = regs.rip >> 4 << 4 ips[b] = ips.get(b, 0) + 1 pt(PTRACE_CONT, tid, 0, 0) print('samples=%d in-module=%d unique64=%d window=%.2fs..%.2fs' % (nsamp, sum(ips.values()), len(ips), (t_start or t0) - t0, time.time() - t0)) core = {a: c for a, c in ips.items() if 0x180520000 <= a < 0x180560000} for a, c in sorted(core.items(), key=lambda x: -x[1])[:18]: print('CORE %#x %d' % (a, c)) for b, c in sorted(ips.items(), key=lambda x: -x[1])[:6]: print('%#x %d' % (b, c)) proc.kill() return 0 if __name__ == '__main__': sys.exit(main())