xtrace
Description
Xtrace fakes an X server and forwards all connections to
a real X server, displaying the communication between the clients
and the server in an (well, thoretically) human readable form.
For further reference take a look at the manpage (current version).
Examples
xtrace -D:9 -d:0 -k
starts xtrace as server :9, forwarding to server :0 and not terminating after
a client exited.
Then connect with some client (in some other terminal) to the new server, for
example with
xclock -display :9
and see the trace of the connection showing up. Let's take an easier example first,
the output for xlsfonts -display :9 -fn fixed
is
Got connection from unknown(local)
000:<: am lsb-first want 11:0 authorising with 'MIT-MAGIC-COOKIE-1' of length 16
000:>: Success, version is 11:0-60897.
First xtrace tells it got a connection via a local UNIX socket. The client wants
the protocoll to be little endian, an X11 server and authorized with a MIT-MAGIC-COOKIE-1
token. The server sucessfully replies. (It actually sends a lot more of information
but that is not printed here). Then it is time for the the client to send requests:
000:<:0001: 20: Request(55): CreateGC cid=0x01600000 drawable=0x00000131 values={background=0x00ffffff}
000:<:0002: 20: Request(98): QueryExtension name='BIG-REQUESTS'
000:<:0003: 24: Request(20): GetProperty delete=false(0x00) window=0x00000131 property=0x17("RESOURCE_MANAGER") type=0x1f("STRING") long-offset=0x00000000 long-length=0x05f5e100
Note that the reply for request two only comes after request 3 was sent. This is because
the X protocoll is asynchronous and typical Xlibs do not even sent out requests before
enough piled up or the application asks to flush them out. Also note that request 1 did
not get any reply, only some requests get replies, and the type of the request
specified whether it will get a reply:
000:>:0x0002:32: Reply to QueryExtension: present=true(0x01) major-opcode=131 first-event=0 first-error=0
000:>:0x0003:1528: Reply to GetProperty: type=0x1f("STRING") bytes-after=0x00000000 data='*Keyboard.keyboard:\tPC105DE\n*XYZ*Foreground:\tyellow\n*XYZ*Tek4014.Translations:\t#override <Key>F1: string("bla")\n*customization:\t-color\n*reverseVideo:\ton\n*scrollKey:\tTrue\n*scrollTtyOutput:\tFalse\nScrollbar.JumpCursor:\tTrue\nXBuffy*Background:\tdarkblue\nXBuffy*Bordercolor:\tgreen\nXBuffy*Foreground:\tyellow\nXBuffy*background:\tdarkblue\nXBuffy*bordercolor:\tdarkgreen\nXDvi.urlBase:\tfile://localhost/\nXDvi.wwwBrowser:\tmozilla-firefox\nXLess*Background:\tlightgray\nXLess*Foreground:\tblack\nXLock*dpmsstandby:\t-1\nXLock*dpmssuspend:\t-1\nXLock*logoutButton:\t15\nXLock*mode:\troll\nXLock*modelist:\troll\nXTerm*Background:\tdarkblue\nXTerm*Bordercolor:\tyellow\nXTerm*Foreground:\tyellow\nXTerm*Tek4014.Translations:\t#override <Key>F1: string("bla") string(0x0d)\nXTerm*VT100*colorBD:\twhite\nXTerm*VT100*colorBDMode:\ton\nXTerm*VT100*colorUL:\tmagenta\nXTerm*highlightSelection:\ttrue\nXTerm*saveLines:\t5000\nXTerm*scrollBar:\ttrue\nXTerm.VT100*colorULMode:\ton\nXTerm.VT100*dynamicColors:\ton\nXTerm.VT100*underLine:\toff\nXTerm.VT100.titeInhibit:\ttrue\nXclock*Hands:\tyellow\nXfm*Background:\tdarkgray\nXfm*Foreground:\tblack\nXfm*SimpleMenu.Translations:\t#override <Btn2Down>: notify() unhighlight() popdown() \nXfm*defaultEditor:\tnedit\nXpdf*reverseVideo:\toff\nemacs*Background:\tDarkSlateGray\nemacs*Foreground:\tWheat\nemacs*bitmapIcon:\ton\nemacs*cursorColor:\tOrchid\nemacs*font:\tfixed\nemacs*pointerColor:\tOrchid\nemacs.geometry:\t80x25\nmaxima*Foreground:\tblack\nxdvi*Background:\twhite\nxdvi*Foreground:\tblack\nxpdf*reverseVideo:\toff\nxterm*reverseWrap:\ttrue\n'
000:<:0004: 4: BIG-REQUESTSRequest(131): BigReqEnable
Now the client sent a special request, that is not in the basic set. For that it asked
before if that extension exists and what number it has, which xtrace also parsed so it
now knows that it is a request to allow big requests, whcih the server answers with
the new maximum size of requests allowed:
000:>:0x0004:32: Reply to BigReqEnable: maximum-request-length=1048575
000:<:0005: 20: Request(98): QueryExtension name='XKEYBOARD'
000:>:0x0005:32: Reply to QueryExtension: present=true(0x01) major-opcode=152 first-event=111 first-error=178
000:<:0006: 8: Request(152): unknown
As xtrace does not yet know the XKEYBOARD extension, it does not know which request this
is, so it calls it "unknown" and cannot show what fields it contains.
(xtrace has a --denyextensions option to modify the answer to every query for
a extension, so the client thinks those do not exist and thus hopefully uses replacements
within the known set.)
It also does not know if that request will
get a reply. But as it does not know what the reply means, it assused it has no reply
and thus complains when it gets one:
000:>:0006:32: unexpected reply
000:<:0007: 16: Request(49): ListFonts max-names=0x03e8 pattern='fixed'
000:>:0x0007:104: Reply to ListFonts: names={ s='fixed'},{ s='-misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-iso8859-1'};
Finally the actual request (everything else is just a artefact of xlib being used,
to only list the known fonts none of them would have been needed) is sent out
and got a reply. (If you are using a version of xtrace up to 0.5 you wll only see the
number of replies with this reply instead of the list, as that was overlooked before).
Getting xtrace
Further Reading
The best description for the X protocol easily found are the X Specifications, for
example found as
/usr/share/doc/xspecs/proto.html on your Debian host if xspecs is installed.
Why the name is stupid
xtrace is actually a stupid name for this program, as so much other things call itself
xtrace. But as none of those other things have anything todo with X, I think I will
keep that name. (So it better fit into the scheme started by strace and ltrace).
Or perhaps I will rename it to x11trace...