The 8 threads whose [rbx] did not resolve to a vtable were never in XObject::Wait. The backtrace grep matched WaitMultiple as a substring, and there %rbx is the XObject** array (mov %rsi,%rbx) with the count in %ebp, so [rbx] is objects[0] -- an object pointer, needing a second deref -- not a vtable. The unwind restored rbx correctly for all 18. freeze_waitobj.sh now takes the function and frame index from the backtrace and applies the matching read, and captures twice in one run (healthy and after the ~270s black-screen) so the comparison is within-run. waitobj_report.py tabulates both and diffs them, discarding any value info symbol cannot resolve.