3.3. 记录应用程序交互

应用程序的可执行代码与操作系统和共享库的代码交互。记录这些交互的活动日志可以有足够的了解应用程序的行为,而无需调试实际的应用程序代码。另外,分析应用程序的交互可帮助识别错误清单的条件。

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

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

strace

strace 工具主要启用由应用程序使用的系统调用(内核功能)。

  • strace 工具可以提供关于调用的详细输出,因为 strace 会解释参数以及了解底层内核代码的结果。将数字转换为相应的常量名称,位组合标志扩展至标志列表,指向字符数组的指针以提供实际字符串等。可能缺少对更多最新内核功能的支持。
  • 您可以过滤 traced 调用来减少捕获的数据量。
  • 除了设置日志过滤器外,使用 strace 不需要任何特定的设置。
  • 使用 strace 跟踪应用程序代码会导致应用程序的执行速度显著慢。因此,strace 不适用于许多生产部署。作为替代方案,请考虑使用 ltrace 或 SystemTap。
  • Red Hat Developer Toolset 中提供的 strace 版本也可以执行系统调用修改。此功能可用于调试。
ltrace

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

  • ltrace 工具允许对任何库进行追踪调用。
  • 您可以过滤 traced 调用来减少捕获的数据量。
  • 除了设置日志过滤器外,使用 ltrace 不需要任何特定的设置。
  • ltrace 工具非常轻便且快速,提供 strace 的替代选择:可以跟踪库中相应的接口,如 glibc,使用 ltrace 而不是使用 strace 跟踪内核功能。
  • 因为 ltrace 不会象 strace 一样处理一组已知的调用,所以不会试图解释传递给库函数的值。ltrace 输出仅包含原始数字和指针。ltrace 输出的解释需要咨询输出中存在库的实际接口声明。
注意

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

SystemTap

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

  • 与使用 straceltrace 进行比较,使用脚本进行日志处理意味着在初始设置阶段有更多工作。但是,脚本功能除生成日志外,扩展 SystemTap 的有用性。
  • SystemTap 通过创建和插入内核模块来工作。SystemTap 的使用效率更高,且不会自行创建系统或应用程序的执行速度。
  • SystemTap 附带一组用法示例。
GDB

GNU Debugger(GDB)主要用于调试,而不是处理日志记录。但是,它的某些功能在应用程序交互是值得关注的主要活动的情况中发挥用处。

  • 使用 GDB,可以方便地将交互事件的捕获与后续执行路径的立即调试。
  • 在其他工具的初始识别问题后,GDBDB 最适合分析响应不常或分散事件。在任何带有频繁事件的情况中使用 GDB 变得效率不低甚至不可能。

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

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

先决条件

  • 必须在系统中安装了 strace

步骤

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

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

      $ 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 工具会退出。

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

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

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

最好查看输出并将其保存到文件中。使用 tee 命令实现这一目的:

$ strace ... |& tee your_log_file.log

其他资源

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

ltrace 工具可监控应用程序对库中可用函数的调用(共享对象)。

注意

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

先决条件

  • 在系统中必须安装 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 选项过滤输出:

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

      如需更多信息,请参阅 ltrace(1)_ manual page。

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

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

  4. 当程序退出时,ltrace 会退出。

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

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

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

最好查看输出并将其保存到文件中。使用 tee 命令实现这一目的:

$ ltrace ... |& tee your_log_file.log

其他资源

  • ltrace(1) 手册页:

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

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

SystemTap 工具为内核事件注册自定义事件处理程序。与 strace 工具相比,使用它较复杂,但它的效率更高,并可以启用更复杂的处理逻辑。名为 strace.stp 的 SystemTap 脚本与 SystemTap 一起安装,并可实现使用 SystemTap 的 strace 大致相同的功能。

先决条件

  • 必须在系统中安装 SystemTap 和相关的内核软件包。

步骤

  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 时,该脚本会退出。

3.3.5. 使用 GDB 截获应用程序系统调用

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

先决条件

  • 您必须了解 GDB 断点的使用。
  • GDB 必须附加到程序。

步骤

  1. 设置 catchpoint:

    (gdb) catch syscall syscall-name

    命令 catch syscall 设置了一个特殊的断点,它会在程序执行系统调用时停止执行。

    syscall-name 选项指定调用的名称。您可以为各种系统调用指定多个追踪点。使用 syscall-name 选项会使 GDB 在任意系统调用中停止。

  2. 开始执行程序。

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

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

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

其他资源

3.3.6. 使用 GDB 截获应用程序处理信号

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

先决条件

  • 您必须了解 GDB 断点的使用。
  • GDB 必须附加到程序。

步骤

  1. 设置 catchpoint:

    (gdb) catch signal signal-type

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

  2. 让程序运行。

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

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

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

其他资源