当前位置: 首页 > 工具软件 > strace > 使用案例 >

每天一个linux命令(68):strace 命令

贺文彬
2023-12-01

https://linux.die.net/man/1/strace

名称

strace - 跟踪系统调用和信号

概要

 

strace的 [ -dDffhiqrtttTvVxx ] [ -a  ] [ -e EXPR ] ... [ -o 文件 ] [ -p PID ] ... [ -s 了strsize] [ -u 用户名 ] [ -E VAR = VAL ] .. 。[- var ] ... [ 命令 [ arg ...]]

strace -c [ -D ] [ -e expr ] ... [ -O overhead ] [ -S sortby ] [ command [ arg ...]]

描述

在最简单的情况下,strace运行指定的命令直到它退出。它拦截并记录由进程调用的系统调用和进程接收的信号。每个系统调用的名称,其参数和返回值都打印在标准错误或使用-o选项指定的文件上。

strace是一种有用的诊断,指导和调试工具。系统管理员,诊断工作者和故障排除者会发现它对于解决源代码不易获得的程序的问题非常宝贵,因为它们不需要重新编译以便跟踪它们。学生,黑客和过于好奇的人会发现,通过跟踪普通程序,可以了解系统及其系统调用的大量信息。程序员会发现,由于系统调用和信号是在用户/内核接口发生的事件,因此仔细检查此边界对于错误隔离,健全性检查和尝试捕获竞争条件非常有用。

跟踪中的每一行都包含系统调用名称,后跟括号中的参数及其返回值。支持命令''cat / dev / null''的一个例子是:

<span style="color:#444444">open(“/ dev / null”,O_RDONLY)= 3</span>

错误(通常返回值为-1)具有附加的errno符号和错误字符串。

<span style="color:#444444">open(“/ foo / bar”,O_RDONLY)= -1 ENOENT(没有这样的文件或目录)</span>

信号被打印为信号符号和信号串。支撑和打断命令“睡眠666”的摘录是:

<span style="color:#444444">sigsuspend([] <未完成...>
--- SIGINT(中断)---
+++被SIGINT +++杀死</span>

如果正在执行系统调用,同时从另一个线程/进程调用另一个系统调用,则strace将尝试保留这些事件的顺序并将正在进行的调用标记为未完成。当呼叫返回时,它将被标记为已恢复

<span style="color:#444444">[pid 28772] select(4,[3],NULL,NULL,NULL <未完成...>
[pid 28779] clock_gettime(CLOCK_REALTIME,{1130322148,939977000})= 0
[pid 28772] <...选择恢复>)= 1(在[3]中)</span>

由于内核终止系统调用并且在信号处理程序完成后安排其立即重新执行,因此通过信号传递中断(可重新启动的)系统调用的处理方式也不同。

<span style="color:#444444">读(0,0x7ffff72cf5cf,1)=?ERESTARTSYS(待重启)
--- SIGALRM(闹钟)@ 0(0)---
<strong>rt_sigreturn</strong>(0xe)= 0
读(0,“”,...,1)= 0</span>

争论以象征性的形式印有激情。此示例显示了执行''>> xyzzy''输出重定向的shell:

<span style="color:#444444">打开(“xyzzy”,O_WRONLY | O_APPEND | O_CREAT,0666)= 3</span>

这里open的三个参数形式通过将flag参数分解为其三个按位OR成分并按照传统以八进制打印模式值来解码。在传统或本地使用不同于ANSI或POSIX的情况下,后一种形式是优选的。在某些情况下,strace输出已被证明比源更易读。

取消引用结构指针,并根据需要显示成员。在所有情况下,参数都以尽可能类似C的方式进行格式化。例如,命令''ls -l / dev / null''的本质被捕获为:

<span style="color:#444444">lstat(“/ dev / null”,{st_mode = S_IFCHR | 0666,st_rdev = makedev(1,3),...})= 0</span>

请注意如何取消引用'struct stat'参数以及如何以符号方式显示每个成员。特别是,观察如何将st_mode成员小心地解码为符号和数值的按位或。另请注意,在此示例中,lstat的第一个参数是系统调用的输入,第二个参数是输出。由于如果系统调用失败,则不会修改输出参数,因此可能无法始终取消引用参数。例如,使用不存在的文件重试''ls -l''示例会产生以下行:

<span style="color:#444444">lstat(“/ foo / bar”,0xb004)= -1 ENOENT(没有这样的文件或目录)</span>

在这种情况下,门廊灯亮,但没有人在家。

字符指针被取消引用并打印为C字符串。字符串中的非打印字符通常由普通的C转义码表示。只打印第一个strsize(默认为32个字节)字符串; 较长的字符串在结束引号后附加省略号。这是来自''ls -l''的一行,其中getpwuid库例程正在读取密码文件:

<span style="color:#444444">read(3,“root :: 0:0:System Administrator:/”...,1024)= 422</span>

虽然结构使用花括号进行注释,但简单的指针和数组使用方括号打印,并使用逗号分隔元素。以下是具有补充组ID的系统上的命令“id”的示例:

<span style="color:#444444">getgroups(32,[100,0])= 2</span>

另一方面,也使用方括号显示位集,但是设置元素仅由空格分隔。这是准备执行外部命令的shell:

<span style="color:#444444">sigprocmask(SIG_BLOCK,[CHLD TTOU],[])= 0</span>

这里的第二个参数是两个信号的位集,SIGCHLD和SIGTTOU。在某些情况下,位集非常丰富,打印出未设置的元素更有价值。在这种情况下,位集以前缀为前缀,如下所示:

<span style="color:#444444">sigprocmask(SIG_UNBLOCK,〜[],NULL)= 0</span>

这里第二个参数表示所有信号的完整集合。

选项

-C

计算每个系统调用的时间,调用和错误,并报告程序退出的摘要。在Linux上,这会尝试显示系统时间(在内核中运行的CPU时间),与挂钟时间无关。如果-c与-f或-F(下面)一起使用,则仅保留所有跟踪进程的聚合总计。

-D

(在SVR4和FreeBSD上不可用。)将跟踪器进程作为独立的孙子运行,而不是作为tracee的父级。这通过将tracee保持为调用进程的直接子进程来减少strace的可见效果 。

-d

在标准错误上显示strace本身的一些调试输出。

-F

跟踪由fork(2)系统调用导致的当前跟踪进程创建的子进程。

在非Linux平台上,只要知道其pid(通过父进程中fork(2)的返回值),就会附加新进程。这意味着这样的孩子可能会暂时不受控制地运行(特别是在vfork(2)的情况下),直到再次安排父母完成其(vfork(2)呼叫。在Linux上,孩子从第一条指令中被追踪到没有延迟。如果父进程决定等待(2)当前正在跟踪的子进程,则它将被暂停,直到适当的子进程终止或发出将导致其终止的信号(根据子进程的当前信号处理确定)。

在SunOS 4.x上,vfork的跟踪是通过一些动态链接技巧完成的。

-FF

如果-o filename选项生效,则每个进程跟踪都将写入filename.pid,其中pid是每个进程的数字进程ID。这与-c不兼容,因为不保留每进程计数。

-F

此选项现已过时,它具有与-f相同的功能。

-H

打印帮助摘要。

-一世

在系统调用时打印指令指针。

-q

禁止有关附加,分离等的消息。当输出重定向到文件并且命令直接运行而不是附加时,会自动发生这种情况。

-r

在进入每个系统调用时打印相对时间戳。这记录了连续系统调用开始之间的时间差。

-t

使用一天中的时间为跟踪的每一行添加前缀。

-tt

如果给出两次,则打印的时间将包括微秒。

-ttt

如果给定三次,则打印的时间将包括微秒,并且前导部分将被打印为自纪元以来的秒数。

-T

显示系统调用所花费的时间。这记录了每个系统调用的开始和结束之间的时间差。

-v

打印环境,stat,termios等呼叫的未缩写版本。这些结构在调用中非常常见,因此默认行为显示结构成员的合理子集。使用此选项可获得所有血腥细节。

-V

打印strace的版本号。

-X

以十六进制字符串格式打印所有非ASCII字符串。

-xx

以十六进制字符串格式打印所有字符串。

对齐特定列中的返回值(默认列40)。

-e expr

一个限定表达式,用于修改要跟踪的事件或如何跟踪它们。表达式的格式是:

qualifier = ] [ value1 [ value2 ] ......

其中限定符是一个跟踪缩写冗长信号,或是一个限定符依赖性符号或数字。默认限定符是trace。使用感叹号会取消该组值。例如,-eopen 表示字面意思-e trace = open,这意味着仅跟踪开放系统调用。相比之下,-etrace =!open表示跟踪除open之外的每个系统调用。另外,特殊值全部没有有明显的意义。

请注意,即使在引用的参数中,某些shell也会使用感叹号进行历史记录扩展。如果是这样,您必须使用反斜杠转义感叹号。

-e trace = set

仅跟踪指定的系统调用集。该-c选项用于确定哪些系统调用可能是跟踪有用有用。例如, trace = open,close,read,write意味着只跟踪那四个系统调用。如果仅监视系统调用的子集,则在推断用户/内核边界时要小心。默认值为trace = all

-e trace =文件

跟踪以文件名作为参数的所有系统调用。您可以将此视为-e trace = open,stat,chmod,unlink, ... 的缩写这对于查看进程引用的文件很有用。此外,使用缩写将确保您不会意外忘记在列表中包含类似lstat的调用。Betchya会忘记那一个。

-e trace = process

跟踪涉及流程管理的所有系统调用。这对于查看进程的fork,wait和exec步骤非常有用。

-e trace =网络

跟踪所有与网络相关的系统调用。

-e trace =信号

跟踪所有与信号相关的系统调用

-e trace = ipc

跟踪所有与IPC相关的系统调用。

-e trace = desc

跟踪所有文件描述符相关的系统调用

-e abbrev = set

缩写打印大型结构的每个成员的输出。默认值为abbrev = all。该-v选项的效果 缩写=无

-e verbose = set

指定系统调用集的解除引用结构。默认值为verbose = all

-e raw = set

为指定的系统调用集打印原始的,未解码的参数。此选项具有使所有参数以十六进制打印的效果。如果您不信任解码或者您需要知道参数的实际数值,这将非常有用。

-e signal = set

仅跟踪指定的信号子集。默认值为signal = all。例如,signal =!SIGIO(或signal =!io)会导致无法跟踪SIGIO信号。

-e read = set

对从指定集中列出的文件描述符读取的所有数据执行完整的十六进制和ASCII转储。例如,要查看文件描述符3和5上的所有输入活动,请使用-e read = 3,5。请注意,这与read(2)系统调用的正常跟踪无关,该调用由选项-e trace = read控制

-e write = set

对写入指定集中列出的文件描述符的所有数据执行完整的十六进制和ASCII转储。例如,要查看文件描述符3和5上的所有输出活动,请使用-e write = 3,5。请注意,这与write(2)系统调用的正常跟踪无关,该调用由选项-e trace = write控制

-o filename

将跟踪输出写入文件文件而不是stderr。如果使用-ff,请使用filename.pid。如果参数以“|”开头 或者用'!' 然后将参数的其余部分视为一个命令,并将所有输出传送给它。这样可以方便地将调试输出传递给程序,而不会影响已执行程序的重定向。

架空

将跟踪系统调用的开销设置为开销微秒。这对于覆盖默认启发式方法很有用,可以猜测在使用-c选项进行计时系统调用时仅花费多少时间。可以通过在没有跟踪的情况下对给定程序运行进行计时(使用时间(1))并将累积的系统调用时间与使用-c产生的总数进行比较来测量启发式的准确性。

-p pid

使用进程ID pid附加到进程并开始跟踪。可以通过键盘中断信号(CTRL -C)随时终止跟踪。strace会通过将自己从跟踪过程中分离出来而让它(它们)继续运行。除命令外,还可以使用多个 -p选项附加到最多32个进程(如果给出至少一个-p选项,则该选项是可选的)。

-s strsize

指定要打印的最大字符串大小(默认值为32)。请注意,文件名不被视为字符串,并且始终完整打印。

-S sortby

按指定条件对-c选项打印的直方图的输出进行排序。合法值是时间呼叫名称和 任何内容(默认时间)。

-u 用户名

使用用户ID,组ID和用户名的补充组运行命令。此选项仅在以root身份运行时有用,并且能够正确执行setuid和/或setgid二进制文件。除非使用此选项,否则setuid和setgid程序在没有有效权限的情况下执行。

-E var = val

在其环境变量列表中运行带有var = val的命令。

-E var

从继承的环境变量列表中删除var,然后将其传递给命令。

诊断

命令退出时,strace以相同的退出状态退出。如果命令由信号终止,则strace以相同的信号终止自身,因此strace可以用作对调用父进程透明的包装进程。

使用-p时,除非在执行跟踪时出现意外错误,否则strace的退出状态为零。

Setuid安装

如果将strace安装到root用户,那么调用用户将能够附加并跟踪任何用户拥有的进程。此外,setuid和setgid程序将以正确的有效权限执行和跟踪。由于只允许具有完全root权限的用户执行这些操作,因此只有当可以执行它的用户仅限于具有此信任的用户时,才能将strace作为setuid 安装到root。例如,是有意义的安装的一个特殊版本strace的与模式“rwsr-xr--”,用户和组迹线,其中的成员跟踪组是可信用户。如果您确实使用此功能,请记住为普通的lusers 安装一个非setuid版本的strace

也可以看看

ltrace(1), time(1), ptrace(2), proc(5)

笔记

遗憾的是,采用共享库的系统产生了如此多的跟踪混乱。

将系统调用输入和输出视为跨用户/内核边界的数据流是有益的。由于用户空间和内核空间是分离的并且受地址保护,因此有时可以使用输入和输出作为命题来对过程行为进行演绎推断。

在某些情况下,系统调用将与记录的行为不同或具有不同的名称。例如,在System V派生系统上,true time(2)系统调用不接受参数,stat函数称为xstat,并采用额外的前导参数。这些差异是系统调用接口的正常但特殊的特性,并由C库包装函数解释。

在某些平台上,使用-p选项对其应用系统调用跟踪的进程将接收SIGSTOP。此信号可能会中断不可重启的系统调用。如果进程不采取任何操作来重新启动系统调用,则可能会对进程产生不可预测的影响。

错误

使用setuid位的程序在跟踪时没有有效的用户ID权限。

除SVR4平台外,跟踪进程忽略SIGSTOP。

试图阻止SIGTRAP的跟踪进程将被发送SIGSTOP以试图强制继续跟踪。

跟踪过程运行缓慢。

命令下降的跟踪过程可以在中断信号(CTRL -C)之后保持运行。

在Linux上,尽管令人兴奋,但仍禁止跟踪init进程。

-i是弱支持的选项。

历史

strace原始的strace是由Paul Kranenburg为SunOS编写的,并且受到它的跟踪效用的启发。SunOS版本的strace 被移植到Linux并由Branko Lankester增强,后者也编写了Linux内核支持。尽管保罗发布strace的 1992年2.5,布兰科的工作是根据保罗的strace的 1.5从1991年发布在1993年,里克Sladkey合并strace的 2.5在SunOS和第二次发布strace的 Linux版,增加了很多的功能桁架(1)来自SVR4,并产生了在两个平台上都有效的strace。1994年里克移植了strace到SVR4和Solaris并编写了自动配置支持。1995年,他将strace移植到Irix并厌倦了以第三人称写自己。

错误

SIGTRAP信号由系统调用跟踪的内核实现在内部使用。当跟踪进程收到与跟踪无关的SIGTRAP信号时,strace将不会正确报告该信号。该信号通常不被程序使用,但可以通过硬编码中断指令或通过kill(2)。

问题

strace的问题应该通过Debian Bug Tracking System报告,或者通过< strace-devel@lists.sourceforge.net > 上的strace邮件列表报告

引用者

btkbdd(8), dstat(1), explain(1), explain_lca2010(1), htop(1), latrace(1),xxd(1)

 类似资料: