23l: DR exec-watch verified working end-to-end by micro-test on this kernel (SIGTRAP+DR6 correct); contradiction isolated to process/thread targeting in tracer, single remaining hypothesis documented with debug protocol

This commit is contained in:
2026-08-24 02:22:55 +03:00
parent baafbb6dc6
commit 56edd3c0f4
2 changed files with 28 additions and 3 deletions
+14
View File
@@ -2461,3 +2461,17 @@ resweep-CONT чурн); (в) по хиту — дамп rcx(bands)/rdx(scratch)
(г) если рендер опять не стартовал — просто перезапустить (флак ~50%).
После дампа bands[] в момент param-change: сравнить с R-кривой, восстановить
G, декодировать потребителя через backtrace ([rsp]) из того же хита.
### 23l (короткое): DR-механизм верифицирован микротестом; расхождение локализовано
Микротест /tmp/opencode/dtest.py на fork+exec ребёнке: DR0 exec-watch срабатывает
(SIGTRAP, rip==target, DR6 bit0) — ядро/CPU полностью поддерживают аппаратные
ловушки через POKEUSER 0x350/0x388. При этом fnexec с ранним армированием
(до создания экземпляра, наследование через TRACECLONE + армирование при
рождении каждого треда) даёт 0 попаданий на {529fe0, loop-head, design×2,
dispatcher, bidir} при подтверждённых рендерах и 8–12/8–12 армированных тредов.
Одновременно: disp32-скан показывает, что ВЕСЬ доступ к scratch/FIR идёт только
из декодированного цикла 52bxxx. Прямое противоречие ⇒ остался ровно один
неисключённый вариант: **трассируется не тот процесс/треды умирают до арма**.
Следующий шаг: в fnexec логировать КАЖДЫЙ stop (rip,dr6,pid) без фильтра +
счётчик всех SIGTRAP; если трапов нет вообще на тредах, которые заведомо
выполняют модульный код — сравнивать /proc/pid/task состав до/после.
+14 -3
View File
@@ -89,7 +89,9 @@ def main():
time.sleep(0.001)
pt(PTRACE_POKEUSER, host, DR_BASE + 0, 0x1802A24C0)
pt(PTRACE_POKEUSER, host, DR_BASE + 8, 0x1802FA420)
pt(PTRACE_POKEUSER, host, DR7_OFF, 0x3)
pt(PTRACE_POKEUSER, host, DR_BASE + 16, 0x180535A70)
pt(PTRACE_POKEUSER, host, DR_BASE + 24, 0x18052D650)
pt(PTRACE_POKEUSER, host, DR7_OFF, 0xF)
ok0 = pt(PTRACE_PEEKUSER, host, DR7_OFF)
print('early arm dr7=%#x' % (ok0 or 0), flush=True)
pt(PTRACE_CONT, host, 0, 0)
@@ -168,7 +170,12 @@ def main():
if pt(PTRACE_GETREGS, pid, 0, ctypes.addressof(regs)) is None:
continue
rip = regs.rip - (1 if False else 0)
if rip not in (0x180529FE0, 0x18052B550, 0x1802A24C0, 0x1802FA420):
if pid not in armed:
seized.add(pid)
if arm(pid):
armed.add(pid)
# re-read regs after arming? DR change does not touch GPRs
if rip not in (0x180529FE0, 0x18052B550, 0x1802A24C0, 0x1802FA420, 0x180535A70, 0x18052D650):
pt(PTRACE_CONT, pid, 0, 0)
continue
if rip == 0x180529FE0:
@@ -176,7 +183,7 @@ def main():
elif rip == 0x18052B550:
n1 += 1
rec = dict(which='design' if rip in (0x1802A24C0, 0x1802FA420)
else ('529fe0' if hit529 else 'loop'),
else ('529fe0' if rip == 0x180529FE0 else 'loop'),
rip=rip, rcx=regs.rcx, rdx=regs.rdx,
cnt=regs.r8 & 0xffffffff,
t=round(time.time() - t0, 3), tid=pid)
@@ -202,6 +209,10 @@ def main():
pt(PTRACE_SETREGS, pid, 0, ctypes.addressof(regs))
pt(PTRACE_CONT, pid, 0, 0)
elif os.WIFSTOPPED(pid):
if pid not in armed and sig == signal.SIGTRAP:
seized.add(pid)
if arm(pid):
armed.add(pid)
pt(PTRACE_CONT, pid, 0, sig if 0 < sig < 32 else 0)
if fresh_t is None and os.path.exists(wav) and os.path.getmtime(wav) > wt0:
fresh_t = time.time() - t0