The xserver local service is reachable from a payload, but a connect made inside the rdebug process is accepted at the service layer and then never dequeued: the server's accept callback runs (3F34EC50), but no 12-byte X11 setup read follows and Xlib waits in select. create_process(entry,name,stack,1,arg) from a new process fixes it. xlaunch creates the child; the server reads the setup (READ12 ret 0x0C), writes the reply (8 + 0x90), and xhello creates/maps/syncs a 400x200 window. The payload also had to keep Display* in a11 (callee-saved) instead of reloading it from a RAM cell, and re-run SETF after each Xlib call. Final breakpoint-free frame: dwt/gui/evidence/xhello_window_frame2838.png. ROM untouched (b46a3e442ccb86134d2356bd70d22fd2).
23 KiB
How the VT1200's GUI apps are built — and what a payload can do with that
Status: static architecture DONE; injection verdict measured, not assumed.
A payload can call ROM routines with the firmware calling convention (proved
live: strlen("0::0") returned 4), but XOpenDisplay from the injected process
never completes: the run stays at stage 2, the display pointer stays 0, the
X server's client watermark does not move, and the rdebug service stops answering.
Creating a new X window from a payload is therefore hard, not medium.
All work is static (Ghidra on vt1200_v22.bin) plus one live experiment on a
private NVRAM/cfg under the documented VT1200_SKIP_LEVEL1=1 divergence. ROM
untouched (md5 b46a3e442ccb86134d2356bd70d22fd2), no driver edits.
Address convention used here: Ghidra byte address and firmware bit address
(= Ghidra × 8). Ghidra address = 0x7E40000 + ROM file offset.
1. The model in one paragraph
The terminal runs a small process-per-application OS on one TMS34010. RAM is
shared and unprotected; processes are contexts (a PCB from create_process, a
stack, a private file table at *(0x1B3900)+0x100). The graphics system is a
real X11 server in ROM (dix, the DEC/Athena server: strings
Hello, this is the X server, CreateWellKnownSockets,
Internal error in ConfigureWindow, BadWindow - parameter not a Window). The
GUI applications are X clients built on Xlib, which is also in ROM
(XConnectDisplay, Xlib: sequence lost, XCreateCursor-class request
builders). There is no separate DWT window API: the "DWT Window Manager" is
an ordinary X client that speaks the X11 WM protocol plus DECwindows atoms
(DEC_WM_HINTS, WM_MOVED, DEC_WM_ICON_STATE, DEC_WM_TAKE_FOCUS).
Because RAM is shared, app state (the Messages list, window ids, cursors) is
global and a routine in one process can update another app's data — that is why
rdebug opcode 8 can write the Terminal Manager's Messages box without a
connection of its own. The X protocol traffic, however, is done by each app's
own process through its own connection (Display * in a global: TM @0xB78E0,
WM @0x27AA80).
2. Function table
2.1 Processes / app lifecycle
| what | Ghidra | bits | notes |
|---|---|---|---|
create_process(entry,name,stack,1,arg) |
0x07EE0D48 |
0x3F706A40 |
mallocs a 0x39-byte PCB, copies the name, allocates the stack, links it at @0x1B3860 |
| current-process pointer | — | 0x1B3900 |
+0x100 = user area (fd table) |
| process list head | — | 0x1B3860 |
|
Main Program (creates SERVER + SESSIONMGR) |
0x07E69B6A…0x07E69C1A |
0x3F34DB50 |
itself a created process (name Main Program) |
| X server entry SERVER | 0x07E6C522 |
0x3F362910 |
dix main; prints Hello, this is the X server |
| Session Manager / Terminal Manager SESSIONMGR_PROC | 0x07E5CDBC |
0x3F2E6DE0 |
is the Terminal Manager (see §3) |
| Window Manager WM | 0x07F5702C |
0x3FAB8160 |
DWT WM; prints DWT Window Manager is here to stay |
| terminal emulator VTE | 0x07E9B60A |
0x3F4DB050 |
DECterm/VTE |
create_process argument order (from the pushes at 0x7E69B72): the first
argument is the entry point (bit address), the second the name string,
the third the stack size, the fourth a constant 1, the fifth a pointer/arg.
Example (main, 0x07E69BE2):
07E69BC8 MOVK 0x1,A9 ; arg3 = 1
07E69BCC MOVI 0x4E20,A9 ; arg2 = 0x4E20 stack
07E69BD2 MOVI 0x3F34E2E0,A8 ; arg1 = "SESSIONMGR_PROC"
07E69BDA MOVI 0x3F2E6DE0,A9 ; arg0 = entry
07E69BE2 CALLA 0x07EE0D48 ; create_process
2.2 Xlib (client side, all in ROM)
The request-builder opcode is visible in each function (MOVB 0xNN into the
request buffer), which is how these were named; the DB26 XDrawString and DB25
XCreateSimpleWindow shapes were then checked against their argument blocks.
| Xlib function | Ghidra | bits | shape seen |
|---|---|---|---|
XOpenDisplay(name) |
0x07F384AE |
0x3F9C2570 |
mallocs 0x4D8, parses the name, connects |
XParseDisplay / service lookup |
0x07FA7538 |
0x3FD3A9C0 |
splits host:display.screen, resolves "xserver" |
XCreateSimpleWindow(d,p,x,y,w,h,bw,border,bg) |
0x07FA8372 |
0x3FD41B90 |
opcode 1, 9 args |
XMapWindow(d,w) |
0x07FAC8B6 |
0x3FD645B0 |
opcode 8, 2 args |
XMapSubwindows(d,w) |
0x07FAC97E |
0x3FD64BF0 |
opcode 9 |
XSelectInput(d,w,mask) |
0x07FB2FAA |
0x3FD97D50 |
ChangeWindowAttributes, mask 0x800 |
XChangeWindowAttributes |
0x07FA70EE |
0x3FD38770 |
opcode 2 |
XConfigureWindow |
0x07FA74A2 |
0x3FD3A510 |
opcode 12 |
XInternAtom(d,name,only_if_exists) |
0x07FABC84 |
0x3FD5E420 |
opcode 16 |
XChangeProperty |
0x07FA6E66 |
0x3FD37330 |
opcode 18 |
XCreateGC(d,drawable,mask,values) |
0x07F32E00 |
0x3F997000 |
opcode 55; template copied from ROM 0x2317D0 |
XChangeGC |
0x07F333F0 |
0x3F999F80 |
opcode 56 |
XSetForeground(d,gc,pixel) |
0x07FB334C |
0x3FD99A60 |
caches in GC, marks dirty |
XSync(d,discard) |
0x07FB3ED6 |
0x3FD9F6B0 |
sends GetInputFocus (43), waits |
XDrawString(d,drawable,gc,x,y,s,n) |
0x07FB4000 |
0x3FDA0000 |
opcode 74 (PolyText8) |
XLoadFont(d,name) |
0x07FA95D0 |
0x3FD4AE80 |
opcode 45 (OpenFont) |
XCopyArea |
0x07FA7C44 |
0x3FD3E220 |
opcode 62 |
| internal PolyFillRectangle fast path | 0x07F33D1E |
0x3F99E8F0 |
opcode 70; not a public entry point |
strlen |
0x07F68B1A |
0x3FB458D0 |
used as the ABI check |
2.3 X server internals that matter
| what | Ghidra | bits |
|---|---|---|
| connection setup / accept entry | 0x07EB1700 |
0x3F58B800 |
auth reject logger (0x07E7E8D0) |
0x07E7E8D0 |
0x3F3F4680 |
| client table (32 × 0x80) | RAM | 0x1B6600 |
| client watermark | RAM | 0x1B8620 |
| client bitmap (32 bits) | RAM | 0x1B86A0 |
| well-known socket / service name | ROM "xserver" |
0x3F591F08 |
The server's connection path reads the 12-byte X11 setup (0xEBB1CE(conn,12,buf)),
checks the byte-order byte, then reads the auth name/data and looks the peer up
in the user/node table. Failure goes to a routine that logs
Client is not authorized to access server and closes.
3. Terminal Manager: what it is and how it starts
The Terminal Manager is not a separate application. It is the UI half of the
process main() creates as SESSIONMGR_PROC (entry 0x3F2E6DE0). The single
function that begins at 0x7E5CDBC runs straight through the display setup
(0x7E5D0F0), the TM window creation (0x7E5D2D0), the WM launch
(0x7E5D760) and the VTE launch (0x7E5E676). This is continuous code: the
disassembly has no return between 0x7E5CDBC and 0x7E5F7xx.
Startup, quoted:
07E5D1FA MOVI 0x3F30DC00,A8 ; "0::0" at ROM 0x7E61B80
07E5D204 CALLA 0x07F384AE ; XOpenDisplay("0::0")
07E5D20A MOVE A8,@0xB78E0 ; TM's Display * (global)
07E5D212 JRNE 0x07E5D228
07E5D216 MOVI 0x3F30DC28,A8 ; "DWTM Failed to open display\n"
07E5D21E CALLA 0x07F6683C ; printf
The title string Terminal Manager V2.2 is at ROM 0x7E61D8B
(bit 0x3F30EC58) and is referenced from the same function (0x7E5E928).
Terminal Manager XIO error... restarting... (0x7E61B53) confirms the TM is an
XIO/Xlib client, not a private drawing API.
The TM's first window is a 1×1 "WM protocol" window; the visible TM box is built
with the widget toolkit (the code at 0x7E7F24A, 0x7E8465A, 0x7E873FE,
0x7E94880, … that calls XCreateSimpleWindow + XMapWindow).
Launched from: main(), not a menu or an init list. A menu does exist for
secondary apps — the Create menu (Terminal Window on Host Port, TELNET Terminal Window…, PRINT) calls create_process at 0x7E91BA0/0x7E91C26.
4. Minimum "hello window" call sequence
From the TM's own code (0x7E5D2B4–0x7E5D2D0) and the WM's
(0x7F57044–0x7F5704E). The calling convention is not "push on SP": the
caller reserves one slot with MOVE A14,-*SP,1, pushes arguments upward
with MOVE arg,*A14+,1 (last argument first), and the callee restores A14/SP.
; root = *(*(display+0x480)+0x40) (TM 0x7E5D290..0x7E5D2AA)
MOVE @0xB78E0,A11 ; display
MOVE @0xB7F80,A9 ; default screen number
SLL 0x9,A9 / SLL 0x7,A7 / ADD A7,A9 ; * 0x280 (screen struct)
MOVE *A11(0x480),A7 / ADD A9,A7 ; screens[]
MOVE *A7(0x40),A9 / MOVE A9,@0xB7960 ; root window
; window = XCreateSimpleWindow(display, root, 0,0, 1,1, 0, 0, 1)
MOVE A14,-*SP,1
MOVK 1,A7 / MOVE A7,*A14+,1 ; background = 1
SUB A7,A7 / MOVE A7,*A14+,1 ; border
MOVE A7,*A14+,1 ; border width
MOVK 1,A7 / MOVE A7,*A14+,1 ; height
MOVE A7,*A14+,1 ; width
SUB A7,A7 / MOVE A7,*A14+,1 ; y
MOVE A7,*A14+,1 ; x
MOVE A9,*A14+,1 ; parent = root
MOVE A11,*A14+,1 ; display
CALLA 0x07FA8372 ; -> window id
The full minimum is 4 Xlib calls:
XOpenDisplay("0::0")—0x3F9C2570XCreateSimpleWindow(d, root, x, y, w, h, bw, border, background)—0x3FD41B90XMapWindow(d, win)—0x3FD645B0XSync(d, 0)—0x3FD9F6B0(flush + round trip)
To draw text add XLoadFont(d,"fixed") (0x3FD4AE80), XCreateGC
(0x3F997000) with GCFont=0x4000, XSetForeground (0x3FD99A60) and
XDrawString (0x3FDA0000). No event loop is needed for a static window; the
server keeps it after the client goes idle.
Globals: only the Display * is per-app. There is no global "current
display" to initialise; XOpenDisplay allocates and returns it. Window ids,
GCs and fonts are server-side resources and are valid for any client.
5. The injection experiment (run) and the verdict
Payload: dwt/gui/xhello.asm → dwt/gui/build/xhello.bin (390 B), linked at bit
0x01840000, built with the TI SDK flow (dwt/gui/build.sh). It first calls
strlen("0::0") as an ABI check (must return 4; if not it returns without
touching Xlib), then XOpenDisplay, root lookup, XCreateSimpleWindow,
XMapWindow, XSync, storing a stage counter at bit 0x01850140 and the
display/window at 0x01850100/0x01850120.
Run: VT1200_SKIP_LEVEL1=1, private -nvram_directory/-cfg_directory,
-networkprovider taptun, BOOTP/TFTP from harness/serve.py --bootp,
-nothrottle; frame/marker probe dwt/gui/probe2.lua. Injected with
dwt/visual/inject.py (poke + jump, challenge answered by
dwt/challenge.respond). The terminal booted to the Terminal Manager, answered
rdebug, and the payload was poked and jumped with no breakpoints.
Result:
strlen = 4 <- the firmware calling convention works
stage = 2 <- reached the XOpenDisplay call
display = 0 <- never returned
window = 0
xclient watermark = 1 (unchanged: no new client slot was taken)
jump: NO RETURN within 20 s; the same connection then times out
The machine stays alive (frames advance, the TM keeps running) but the
remote-debug process sits in Xlib's select wrapper (0x3FD969F0, waiting on
the display fd) and the rdebug service stops answering. No window appeared in
the frame dump (dwt/gui/run/gui_frame15571.png is the normal TM).
Verdict: HARD for "a payload creates its own window through XOpenDisplay".
The window API is ordinary Xlib — the missing piece is the local transport
handshake: a connection opened from the injected process is never accepted by
the server (client watermark does not move), so Xlib waits forever. The one
thing that decides it is whether the "xserver" service connection can be
established from a process other than the boot-time clients; that is not an API
question and is not answered by the ROM alone.
MEDIUM for a narrower goal: influencing an existing window. The shared-RAM
UI path is proven — rdebug opcode 8 calls the TM's append routine
0x3F309350 and the text appears in the Messages pane with no connection of its
own. Any payload can call the same TK/UI routines, but they mutate the owning
app's data structures so that the owner does the X drawing.
6. Internal IPC to the X server
Both boot-time clients open the display with the literal string "0::0"
(TM at ROM 0x7E61B80, bit 0x3F30DC00; WM at 0x7F59D29, bit 0x3FACE948).
XParseDisplay (0x7FA7538) does not build a TCP address. It resolves a
named local service:
07FA766C CALLA 0x07F65C68 ; kernel_lock (per-process critical flag)
07FA7672 MOVI 0x3FD3DCA0,A8 ; "xserver"
07FA767C CALLA 0x07EE160C ; service attach by name
07FA7688 JREQ ... ; null -> unlock, sleep 100 ms, retry
0x7EE160C is a service-table lookup/attach; the lookup itself
(0x7EE1B70) scans a 32-entry table at 0x1E8D70 (4-byte entries) with
strcmp against the name. The X server registers the same name on its side
("xserver" appears next to CreateWellKnownSockets at 0x7E6A4B0, and next to
the TCP accept X Server's TCP Port at 0x7E591F08).
So the internal route is: named local service xserver, reached by
XOpenDisplay("0::0"), not TCP and not a Unix socket path. TCP port 6000 is a
separate listener; it is gated by the user/node authorisation list
(Connection request from user %s on node %s rejected, auth check
0x7E7E8D0), which is why an external xdpyinfo gets
Client is not authorized to access server while the local service clients do
not.
7. App inventory
GUI (X clients):
| process | entry (bits) | role |
|---|---|---|
SERVER |
0x3F362910 |
X11 dix server, well-known socket xserver + TCP 6000 |
SESSIONMGR_PROC |
0x3F2E6DE0 |
Session Manager and Terminal Manager UI (Messages, Ethernet/IP/LAT, memory bar, Customize/Print Screen panels) |
WM |
0x3FAB8160 |
DWT Window Manager: frames, title bars, icon box, DEC WM atoms |
VTE |
0x3F4DB050 |
terminal emulator window (created on demand by the TM) |
PRINT |
0x3F3E2590 → 0x7E7C4B2 |
print manager, launched from the Print Screen/Create menu |
Non-GUI processes (same create_process mechanism, for completeness):
INETSERVER, LAT server (0x3F2BD3F0), MOP server (0x3FAED480), LANCE server
(0x3F9DB9A0), TCPIP_FONTS (0x3F95EB10), resolver (0x3F5B7EF0),
Telnet (0x3F6D2F90), Route (0x3F5BF380), rtvalidate (0x3F663360),
VTE_listen (0x3F50F6A0), VTE_listen_shr (0x3F50F860), Bootp
(0x3F57B710), Inetd (0x3F587C00), domain_name (0x3F5B9510),
remote debug (0x3F59F320), TCP_UP (0x3F22F940), Terminate_tcp
(0x3F22E7F0), Main Program (0x3F34DB50), DWTM/VTE helpers.
There is no file manager, editor, clock or cardfiler in this image; the only
GUI apps are the five above, plus the TM's own modal/panel code in the
0x7E7xxxx–0x7E9xxxx toolkit range.
8. The experiment that would settle the transport question
Run the same payload but instrument the server side: breakpoint the server
accept entry 0x3F58B800 and the auth check 0x3F3F4680, log hits to a file
from a Lua frame hook (MAME's printf action did not reach stdout with
-debugger none in this run, so use a wpset/bpset action that increments a
RAM counter, or a Lua hook that samples PC every frame), then inject
xhello.bin. Three outcomes:
- Accept never hit → the service connect from a non-boot process never reaches
the server; the next step is to call
0x7EE160C("xserver")by hand under the debugger and inspect its return value / the fd it installs. - Accept hit, auth rejects → authorise the injected client (the same user/node table the config UI edits), then the window should appear.
- Accept hit, auth passes, no reply → the setup packet is wrong; compare the bytes Xlib writes from the WM's connection with ours.
A second, independent route worth trying: create_process a fresh process whose
entry is the payload (create_process(0x01840000, "GUI", 0x2000, 1, 0)), so the
X connection is made by a normal new process rather than by the rdebug
dispatcher. That isolates "wrong process context" from "wrong transport".
Not run: the owner's MAME was not running, but the shared tap
(tap-mess-1000-0 / bridge vt1200) was used only after confirming no
mame0289/vt1200 process existed; a private NVRAM and cfg directory were used
and the run was stopped afterwards. No second MAME was started while another was
live.
9. Evidence files
| path | contents |
|---|---|
dwt/gui/xhello.asm |
the payload (ABI check + 4 Xlib calls) |
dwt/gui/build.sh |
TI SDK build wrapper, output under dwt/gui/ |
dwt/gui/build/xhello.bin, .lst, .map |
assembled payload, listing, map |
dwt/gui/probe.lua, probe2.lua, probe3.lua |
frame snapshots + marker/PC telemetry + accept breakpoint |
dwt/gui/run/mame.log |
boot, markers (strlen=4, stage=2, disp=0, xclients=1) |
dwt/gui/run/gui_frame15571.png |
post-injection frame: normal Terminal Manager, no new window |
10. Transport settled: a create_process child opens a window
Verdict: H3 holds, with one payload bug on top. A process created by the
firmware's own create_process connects to the "xserver" local service,
completes the X11 setup handshake, creates and maps a window. The final,
breakpoint-free run shows it at frame 2838:
dwt/gui/evidence/xhello_window_frame2838.png (black 400x200 window at 100,100
with the WM frame/title bar, over the Terminal Manager).
The ROM is untouched (md5 b46a3e442ccb86134d2356bd70d22fd2); no driver edits.
Run configuration is the documented VT1200_SKIP_LEVEL1=1 divergence, private
-cfg_directory/-nvram_directory, BOOTP from harness/serve.py --bootp.
10.1 H1: the connect does reach the server accept — even from rdebug
The old probe address 0x3F58B800 was wrong: it is the epilogue of the
function that creates the "remote debug" process (mmfm sp,a7,a9,a11,a13; rets),
not the X accept. The local-service path is:
| stage | bit address |
|---|---|
XOpenDisplay |
3F9C2570 |
XParseDisplay → service attach by name |
3FD3B3E0 |
| service attach / lookup | 3F70B060 / 3F70DB80 |
| server-side accept callback (registration arg 1) | 3F34EC50 |
| local accept worker, 12-byte setup read | 3F34F190 / 3F350170 |
| setup read implementation | 3F70C5C0 |
| TCP accept (separate, auth-guarded) | 3F58B830 |
Instrumentation of the old experiment (xhello called in the rdebug process) shows the connect is accepted, not rejected:
TR OPEN entry pc=3F9C2570 a14=01852020 ...
TR ATTACH entry pc=3F70B060 ... proc=003FFBD0
TR ATTACH ret a8=008D3050
TR SETUP-WRITE pre ...
TR ACCEPT-CB entry proc=00414F90 ; SERVER runs the service callback
TR REGISTER ret a8=007ADA30 ; re-registers for the next client
(no READ12)
proc=00414F90 is SERVER (confirmed from the process list). So the service
table lookup, the attach and the accept callback all succeed; the failure is
downstream of accept.
10.2 H2: no auth check on the local path
3F3F4680 (the "Client is not authorized" path) is never hit for a local
connect. The auth/user-node table belongs to the TCP listener (3F58B830,
X Server's TCP Port), not to the named service. Nothing rejects "0::0".
10.3 What the rdebug process does not get
After the accept callback, the server's local accept worker must dequeue the
connection and read the 12-byte X11 setup. In the rdebug-process run it never
does — there is no READ12 after the injected ACCEPT-CB; the client then sits
in Xlib's select (3FD969F0), which is the original observation. The server
side was alive (boot clients' own READ12 calls occur earlier in the same log).
A fresh create_process child is dequeued normally. Why the rdebug context is
not dequeued was not reduced to a single ROM check; what is measured is the
difference in outcome: same payload, same service, same server, only the
calling process differs.
10.4 H3: create_process makes it work
dwt/gui/xlaunch.asm (128 B, bit 01860000) is the launcher. Its call shape is
the Telnet handler's (0x3F6D4340–0x3F6D4440):
create_process(entry, name, stack, 1, arg) ; entry = 01840000, stack = 6000
It is invoked by the real rdebug jump; create_process returns PCB
003FFBD0 and the child's xhello runs. The trace then shows the full
handshake:
TR CREATE_PROC entry entryarg=003F30DC ... proc=004043D0
TR OPEN entry ... (child) TR ATTACH ret a8=008D3050
TR ACCEPT-CB entry proc=00414F90
TR READ12 ret a8=0000000C ; server read the 12-byte setup
TR SRV-WRITE ret a8=00000008 ; setup reply header
TR SRV-WRITE ret a8=00000090 ; vendor + screen list
TR XREAD ret a8=00000008 expect=00000008 ; client read both
TR XREAD ret a8=00000090 expect=00000090
TR CreateSimpleWindow
TR MapWindow
TR XSync
Raw excerpt: dwt/gui/evidence/transport_evidence.txt; full trace:
dwt/gui/run12/debug.log (instrumented) and dwt/gui/run13/mame.log
(breakpoint-free).
10.5 The second bug: do not reload Display * from the marker cell
With H3 alone the child still crashed in XCreateSimpleWindow. The cause is in
xhello, not in the transport: XOpenDisplay really returns 0x7C7290
(DISP-RET2 a8=007C7290), but the value read back from the old RAM marker cell
was 0x006B7290. The root lookup then dereferenced the wrong block (all 0x5555
fill) and produced garbage; the call went wild.
The fix, in dwt/gui/xhello.asm, is to keep the Display in a11 and the
window in a10 — both are callee-saved by every Xlib entry point
(mmtm sp,a5,a7,a9,a10,a11,a13) — instead of reloading it from RAM, and to
re-run setf 16,0,0; setf 32,0,1 after every Xlib call because Xlib changes the
CPU's field state. The markers are diagnostic only now.
10.6 Reproduce
./dwt/gui/build.sh dwt/gui/xhello.asm 01840000 # 390 B
./dwt/gui/build.sh dwt/gui/xlaunch.asm 01860000 # 128 B
# boot with the private cfg/nvram and the breakpoint-free probe
VT1200_SKIP_LEVEL1=1 MSG_TRIGGER=$PWD/trigger MSG_DIR=$PWD \
/home/arti/code/k-space/mame0289/vt1200 vt1200 \
-rompath harness/mame/roms -sound none -skip_gameinfo \
-networkprovider taptun -video none -nothrottle \
-cfg_directory $PWD/cfg -nvram_directory $PWD/nvram \
-autoboot_script $PWD/probe_win.lua -autoboot_delay 0
# after 192.168.99.2:771 answers (one rdebug connection per poke/jump)
python3 dwt/visual/inject.py --host 192.168.99.2 \
--poke-file 0x01840000 --file dwt/gui/build/xhello.bin
python3 dwt/visual/inject.py --host 192.168.99.2 \
--poke-file 0x01860000 --file dwt/gui/build/xlaunch.bin \
--jump 0x01860000 --jump-wait 8
probe_win.lua contains no bpset/wpset; the final frame is produced by the
payload alone. Stage markers: 01890140 reaches 6, 01890160 = 4.
10.7 Limits
- The demonstration depends on the
VT1200_SKIP_LEVEL1=1divergence (as did the original experiment); it is evidence about the OS/X server, not a real POST. - The window is an empty black
XCreateSimpleWindow(400x200, border 2) on the root window. The WM frames it; no text is drawn. Adding text needsXLoadFont/XCreateGC/XDrawStringon the same working connection. - The rdebug process's own connect remains unusable; use
create_process.