• 首页
  • 加入
  • RSS
  • xtrace

    Saturday, November 4, 2023
    deepin 社区官方博客 #deepin-community:deepin.org


    介绍

    xtrace是一个用于跟踪分析X11图形协议通信的工具,它可以监控和记录X11服务器上的各种场景,以帮助开发人员诊断和调试与图形界面相关的问题。作为一款强大的工具,xtrace可用于逆向工程、调试分析、性能分析等领域。在Linux X11系统中,xtrace能够记录一个程序在运行时所发起的X11协议请求和XServer发送给程序的事件,以及这些调用的参数。这对于在不阅读源码情况排查程序中的问题、理解程序行为、分析性能瓶颈以及进行协议审计都非常有用。笔者在工作过程中使用该工具深度剖析过腾讯会议、simplescreenrecorder等应用程序的实现,在没有阅读代码的前提下可以获得软件录屏的工作流程,配合阅读常规的X11录屏代码,可分析出其部分工功能异常原因,这些经验在xwayland适配X11应用程序截图录屏项目中通过实战解决了一系列问题。

    本文主要介绍的是X11协议的监视工具,希望您在读完本篇文章后可以对如何监控X11协议有比较深刻的认知,在工作中经常会碰到一些X11应用程序运行时功能异常,在没有应用程序源码的情况下通过xtrace进行调试是一个不错的选择,希望在阅读完这篇文章后,能丰富您的调试技巧。祝您阅读愉快!

    xtrace的安装和使用非常简单,打开终端像如下输入命令即可启动工具:

    // UOS上安装xtrace,deepin上没有可以在http://snapshot.debian.org/上下载
    sudo apt install xtrace
    
    // 运行之后协议电报内容会存储在/tmp/dde-calendar.xtrace中
    xtrace -n -o /tmp/dde-calendar.xtrace dde-calendar	
    
    命令行选项含义或用途
    –display, -d用于ssh远程调试,例如:xtrace -d :0 dde-calendar
    –outfile, -o用于将通信内容转存到磁盘,例如:xtrace -o /tmp/x.log dde-calendar
    –stopwhendone, -s进程退出后停止xtrace,例如:xtrace -s dde-calendar

    工作原理

    如图1所示,X11其主要有两种通信方式,在同一个计算机内主要使用unix domain socket进行通信;在不同计算机之间使用TCP/IP通信。只需要“截获”通信消息,将其转为易于读取的格式输出即可达到监控目的。这是xtrace工作的基本原理。

    图1. 不同客户端使用同一个XServer显示器框架图

    如下图2是X11窗口创建的基本流程,因为篇幅限制,图中只绘制了基础的请求和事件,但X11协议远比图中绘制的复杂,笔者在此只介绍一下基础的协议交互模型,方便在读者在查看xtrace追踪日志时有基础的认知。

    图2. X11协议交互流程

    总之xtrace是Xorg X Server自带的一个工具,通过分析xtrace的输出,你可以了解X Server是如何处理客户端应用程序的请求,以及可能的问题所在。xtrace 工具的作用:

    X11在文件系统中暴露了通信用的socket套接字文件,这使得第三方应用程序可以监控套接字文件从而“窥视"X11客户端和服务端之间的通信,这一技术点是xtrace工作的主要基础。

    // X11 socket套接字文件在文件系统中的位置
    ls /tmp/.X11-unix
    X0  X9
    

    如下日志所示xtrace工作的本质就是不断地获取wrote和received的数据然后将其解析为易于阅读的描述语言打印出来。

    // 全量日志
    001:>:received 32 bytes
    001:>:09dc:32: Reply to InternAtom: atom=0x250("_NET_KDE_COMPOSITE_TOGGLING")
    001:>:wrote 32 bytes
    001:>:received 32 bytes
    001:>:09dc: Event XKEYBOARD-XkbEvent(85) type=2 time=0x018d8071 device=0x03 not-yet-supported=0x10,0x00,0x00,0x10,0x01,0x00,0x00,0x00,0x00,0x01,0x90,0x10,0x10,0x10,0x90,0x00,0x01,0x90,0x11,0x00,0x00,0x87,0x05;
    001:>:wrote 32 bytes
    001:>:received 32 bytes
    001:>:09dc: Event XKEYBOARD-XkbEvent(85) type=2 time=0x018d8072 device=0x03 not-yet-supported=0x10,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x00,0x01,0x90,0x11,0x00,0x00,0x87,0x05;
    001:>:wrote 32 bytes
    001:>:received 32 bytes
    001:>:09dc: Event XKEYBOARD-XkbEvent(85) type=2 time=0x018d8073 device=0x03 not-yet-supported=0x10,0x00,0x00,0x10,0x01,0x00,0x00,0x00,0x00,0x01,0x90,0x10,0x10,0x10,0x90,0x00,0x01,0x90,0x11,0x00,0x00,0x87,0x05;
    

    其工作流程大致如下:

    相关的代码调用堆栈如下:

    Breakpoint 1, startline (c=0x4f8270, d=TO_SERVER, format=0x417a71 "%04x:%3u: Request(%hhu): %s ") at parse.c:52
    52              if( (print_timestamps || print_reltimestamps)
    (gdb) bt
    #0  startline (c=0x4f8270, d=TO_SERVER, format=0x417a71 "%04x:%3u: Request(%hhu): %s ") at parse.c:52
    #1  0x000000000040b5f5 in print_client_request (c=0x4f8270, bigrequest=false) at parse.c:1692
    #2  0x000000000040cc2d in parse_client (c=0x4f8270) at parse.c:1996
    #3  0x0000000000403b4a in mainqueue (listener=4) at main.c:406
    #4  0x00000000004045d4 in main (argc=4, argv=0x7fffffffdef8) at main.c:706
    (gdb) c
    Continuing.
    
    Breakpoint 1, startline (c=0x4f8270, d=TO_CLIENT, format=0x417b32 "%04x:%u: Reply to %s: ") at parse.c:52
    52              if( (print_timestamps || print_reltimestamps)
    (gdb) bt
    #0  startline (c=0x4f8270, d=TO_CLIENT, format=0x417b32 "%04x:%u: Reply to %s: ") at parse.c:52
    #1  0x000000000040c1f3 in print_server_reply (c=0x4f8270) at parse.c:1859
    #2  0x000000000040d0e5 in parse_server (c=0x4f8270) at parse.c:2064
    #3  0x00000000004035ed in mainqueue (listener=4) at main.c:336
    #4  0x00000000004045d4 in main (argc=4, argv=0x7fffffffdef8) at main.c:706
    
    // connect socket
    Breakpoint 2, generateSocketName (addr=0x7fffffffdd30, display=9) at x11common.c:114
    114             snprintf(addr->sun_path,sizeof(addr->sun_path),"/tmp/.X11-unix/X%d",display);
    (gdb) p display 
    $5 = 9
    (gdb) c
    Continuing.
    [Detaching after fork from child process 7682]
    Got connection from unknown(local)
    
    Breakpoint 2, generateSocketName (addr=0x7fffffffd9d0, display=0) at x11common.c:114
    114             snprintf(addr->sun_path,sizeof(addr->sun_path),"/tmp/.X11-unix/X%d",display);
    (gdb) p display 
    $6 = 0
    (gdb) bt
    #0  generateSocketName (addr=0x7fffffffd9d0, display=0) at x11common.c:114
    #1  0x0000000000404c92 in connectToServer (displayname=0x7fffffffe363 ":0", family=1, hostname=0x0, display=0) at x11client.c:77
    #2  0x0000000000402766 in acceptConnection (listener=3) at main.c:95
    #3  0x0000000000403edd in mainqueue (listener=3) at main.c:452
    #4  0x00000000004045d4 in main (argc=2, argv=0x7fffffffdf18) at main.c:706
    (gdb) 
    

    协议分析

    xtrace通过拦截X11协议通信来进行分析。它捕获传输到X服务器的请求以及服务器对这些请求的响应,将他们解析化以日志输出的形式打印出来。所以本质来说协议分析指的是X11协议交互分析,需要对 X11相关的协议做到非常了解,即每个协议有什么功能,在xcb中是如何处理,在xserver中又是如何处理。受限于篇幅,笔者在此不会阐述所有的协议分析,而是拿我们平时常用的一些软件做一些分析和介绍。

    日志流关键字含义或用途
    Present-Request(148,1)客户端用于GLX等送显
    Request(1): CreateWindow请求创建X窗口,shm、glx都有
    GLX-Request(152,3): glXCreateContext请求创建GLX上下文,可以用来判断客户端是否GLX应用
    MIT-SHM-Request(130,3): PutImageX11 shm客户端请求更新图像
    Event XKEYBOARD-XkbEvent(85)xserver键盘事件传递给X客户端
    Event Generic(35) XInputExtension鼠标事件,后面带着ButtonPress、ButtonRelease、Motion等
    Request(36): GrabServergrab请求
    Request(37): UngrabServer解除grab请求
    DeleteProperty请求删除X11窗口的一些属性
    ChangeProperty改变X11窗口的一些属性
    PropertyNotify窗口属性改变发送事件通知客户端
    MIT-SHM-Request(130,4): GetImageshm方式获取屏幕图像
    Request(62): CopyArea复制屏幕一部分区域图像(离屏)
    Request(53): CreatePixmap创建图像(离屏)

    上述表格中只是介绍了常见部分的协议,X协议非常的丰富,完整的模块如下所示:

    总结

    总体来说xtrace是一个有用的工具,对于笔者来说经常会接触生态软件的图形显示问题,对于少部分软件开发商不愿意提供代码和问题复现最小demo,此时其软件对于笔者来说是一个黑盒,当问题边界靠近X相关的技术时,笔者会使用xtrace去详细分析该软件的详细功能,往往这可以在底层剖析软件的显示工作方式,配合系统上相关的组建库代码,可以方便地处理客户的紧急问题。 笔者编写这篇文档是希望可以鼓励更多的同事使用xtrace,这个工具可以帮助你熟悉X11的工具原理,同时也可以理解像qt、gtk等UI库的底层实现,在定位系统复制粘贴、图形显示、拖拽、窗口相关的问题时可以提供更加底层的日志,方便更加精准地定位问题根因!

    参考资料