Menu Close

Red Hat Training

A Red Hat training course is available for RHEL 8

第 9 章 记录应用程序互动

应用程序的可执行代码与操作系统代码和共享库交互。记录这些交互的活动日志可让您深入了解应用程序的行为,而无需调试实际应用程序代码。或者,分析应用程序的交互有助于找出错误清单的条件。

9.1. 用于记录应用程序交互的工具

Red Hat Enterprise Linux 提供多种工具来分析应用程序的交互。

strace

strace 工具主要启用应用程序所用系统调用(内核功能)的日志记录。

  • strace 工具可提供有关调用的详细输出,因为 strace 在了解底层内核代码的情况下解释参数和结果。数字被转换为对应的恒定名称,将位符合并到标志列表,指向字符数组来解引用,以提供实际字符串,等等。可能不支持较新的内核功能。
  • 您可以过滤追踪的调用来减少捕获的数据的数量。
  • 使用 strace 不需要任何特定的设置,除了设置日志过滤器外。
  • 使用 strace 追踪应用程序代码会导致应用程序的执行显著下降。因此, strace 不适合很多生产部署。作为替代,请考虑使用 ltrace 或者 SystemTap。
  • Red Hat Developer Toolset 中可用的 strace 版本也可以执行系统调用 tampering。这个功能对调试非常有用。
ltrace

ltrace 工具启用将应用程序的用户空间调用记录到共享对象(动态库)中。

  • ltrace 工具启用对任何库的追踪调用。
  • 您可以过滤追踪的调用来减少捕获的数据的数量。
  • 使用 ltrace 不需要任何特定的设置,除了设置日志过滤器外。
  • ltrace 工具是轻量级和快速的,提供了 strace 的替代方案:可以追踪库中的 glibc 中的对应接口,并使用 ltrace 来追踪使用 strace 的内核功能。
  • 因为 ltrace 没有处理类似 strace 的已知调用,所以它不会尝试解释传递给库功能的值。ltrace 输出只包含原始数字和指针。解释 ltrace 输出需要咨询输出中库的实际接口声明。
注意

在 Red Hat Enterprise Linux 8.0 中,一个已知问题会阻止 ltrace 追踪系统可执行文件。这个限制不适用于用户构建的可执行文件。

SystemTap

SystemTap 是一个工具平台,用于在 Linux 系统上模拟运行的进程和内核活动。SystemTap 使用自己的脚本语言来编程自定义事件处理程序。

  • 与使用 straceltrace 相比,脚本化日志记录意味着在初始设置阶段可以进行更多的工作。但是,脚本功能会扩展了 SystemTap 的功能,它超出了生成日志的范围。
  • SystemTap 通过创建和插入内核模块来实现。SystemTap 的使用效率高,不会对系统或应用程序本身造成显著下降。
  • SystemTap 附带一组使用示例。
GDB

GNU Debugger(GDB)主要用于调试,而不是记录。然而,在某些特性中,即使应用程序互动是关注的主要活动,也很有用。

  • 使用 GDB,可以方便地将交互事件的捕获与立即调试后续执行路径合并。
  • 在被其他工具初始发现有问题的情况后,GDB 最适合对罕见或单数事件进行分析。在出现频繁事件的任何场景中使用 GDB 将会变得效率低下甚至无法使用。

9.2. 使用 strace 监控应用程序的系统调用

strace 工具启用监控应用程序执行的系统(内核)调用。

流程

  1. 识别要监控的系统调用。
  2. 启动 strace 并将其附加到程序。

    • 如果您想要监控的程序没有运行,请启动 strace 并指定 程序:

      $ strace -fvttTyy -s 256 -e trace=call program
    • 如果程序已在运行,找到其进程 id(pid)并把 strace 附加到它:

      $ ps -C program
      (...)
      $ strace -fvttTyy -s 256 -e trace=call -ppid
    • 使用要显示的系统调用替换 call。您可以多次使用该 -e trace=call 选项。如果省略, strace 将显示所有系统调用类型。详情请查看 strace(1) 手册页。
    • 如果您不想追踪所有 fork 进程或线程,请保留 -f 选项。
  3. strace 工具显示应用程序的系统调用及其详情。

    在大多数情况下,如果没有为系统调用设置过滤,则应用程序及其库会发出大量调用, strace 输出会立即出现。

  4. strace 工具在程序退出时退出。

    要在追踪程序退出前终止监控, 按 Ctrl+C

    • 如果 strace 启动程序,该程序会与 strace 一起终止。
    • 如果您将 strace 附加到已在运行的程序,该程序会与 strace 一起终止。
  5. 分析应用程序的系统调用列表。

    • 日志中存在资源访问或可用性的问题,因为调用返回的错误。
    • 传递给系统调用和调用序列模式的值可让您了解应用程序行为的原因。
    • 如果应用程序崩溃,则可能需要在日志末尾获得重要信息。
    • 输出会包含大量不必要的信息。但是,您可以为系统调用构建一个更加精确的过滤器,并重复这个过程。
注意

查看输出并将其保存到文件中是很有好处的。使用 tee 命令达到此目的:

$ strace ... |& tee your_log_file.log

其它资源

9.3. 使用 ltrace 监控应用程序的库功能

ltrace 工具允许监控应用程序对库(共享对象)中可用功能的调用。

注意

在 Red Hat Enterprise Linux 8.0 中,一个已知问题会阻止 ltrace 追踪系统可执行文件。这个限制不适用于用户构建的可执行文件。

流程

  1. 若有可能,识别相关的库和功能。
  2. 启动 ltrace 并将其附加到程序。

    • 如果您想要监控的程序没有运行,请启动 ltrace 并指定 program:

      $ ltrace -f -l library -e function program
    • 如果程序已在运行,找到其进程 id(pid)并把 ltrace 附加到它:

      $ ps -C program
      (...)
      $ ltrace -f -l library -e function program -ppid
    • 使用 -e-f-l 选项过滤输出:

      • 提供要显示为功能的 功能 名称。-e function 选项可以多次使用。如果省略, ltrace 会显示对所有功能的调用。
      • 您可以使用 -l library 选项指定整个库,而不指定功能。这个选项的行为与 -e function 选项类似。
      • 如果您不想追踪所有 fork 进程或线程,请保留 -f 选项。

      如需更多信息,请参阅 ltrace(1)_ 手册页。

  3. ltrace 显示应用程序发出的库调用。

    在大多数情况下,如果没有设置过滤器,应用程序会发出大量调用, ltrace 输出会立即显示。

  4. ltrace 程序退出时退出。

    要在追踪程序退出前终止监控,按 ctrl+C

    • 如果 ltrace 启动程序,该程序会与 ltrace 一起终止。
    • 如果您将 ltrace 附加到已在运行的程序,该程序会与 ltrace 一起终止。
  5. 分析应用程序进行的库调用列表。

    • 如果应用程序崩溃,则可能需要在日志末尾获得重要信息。
    • 输出会包含大量不必要的信息。但是,您可以构造一个更精确的过滤器并重复这个步骤。
注意

查看输出并将其保存到文件中是很有好处的。使用 tee 命令达到此目的:

$ ltrace ... |& tee your_log_file.log

其它资源

  • ltrace(1) 手册页:

    $ man ltrace
  • Red Hat Developer Toolset User Guide - chapter ltrace

9.4. 使用 SystemTap 监控应用程序的系统调用

SystemTap 工具允许为内核事件注册自定义事件处理程序。与 strace 工具相比,更难以使用,但效率更高,并启用更复杂的处理逻辑。一个名为 strace.stp 的 SystemTap 脚本与 SystemTap 一起安装,并使用 SystemTap 提供 strace 功能的近似值。

流程

  1. 查找您要监控的进程 ID(pid):

    $ ps -aux
  2. 使用 strace.stp 脚本运行 SystemTap:

    # stap /usr/share/systemtap/examples/process/strace.stp -x pid

    pid 的值是进程 id。

    该脚本被编译到内核模块中,然后载入该模块。这在输入命令和获取输出之间引入了一些延迟。

  3. 当进程执行系统调用时,调用名称及其参数会输出到终端。
  4. 当进程终止或按 Ctrl+C 键时,该脚本会退出。

9.5. 使用 GDB 拦截应用程序系统调用

GNU Debugger(GDB)可让您在程序执行过程中的不同情况下停止执行。要在程序执行系统调用时停止执行,请使用 GDB 捕获点

流程

  1. 设置 catchpoint:

    (gdb) catch syscall syscall-name

    catch syscall 命令设置一种特殊的 breakpoint 类型,它会在程序执行系统调用时停止执行。

    syscall-name 选项指定调用的名称。您可以为各种系统调用指定多个捕获点。退出 syscall-name 选项会导致 GDB 在任何系统调用中停止。

  2. 开始执行程序。

    • 如果程序还没有启动执行,请启动它:

      (gdb) r
    • 如果停止了程序执行,恢复它:

      (gdb) c
  3. GDB 在执行程序执行任何指定的系统调用后停止执行。

9.6. 使用 GDB 截取应用程序对信号的处理

GNU Debugger(GDB)可让您在程序执行过程中的不同情况下停止执行。要在程序收到操作系统信号时停止执行,请使用 GDB 捕获点

流程

  1. 设置 catchpoint:

    (gdb) catch signal signal-type

    catch signal 命令设置一种特殊的 breakpoint 类型,它会在程序收到信号时停止执行。signal-type 选项指定信号的类型。使用特殊值 'all' 来捕获所有信号。

  2. 让程序运行。

    • 如果程序还没有启动执行,请启动它:

      (gdb) r
    • 如果停止了程序执行,恢复它:

      (gdb) c
  3. GDB 在程序接收任何指定的信号后停止执行。