注册挺久了,一直都是看没写过,今天就写简单的写第一篇,就叫s《trace学习》吧。
进入正题:
strace程序截取程序发出的系统调用并且显示它们以供查看。被跟踪的程序可以是从strace命令运行的,也可以是系统上已经运行的程序。如果有适当的权限,就可以研究现有的进程并且监视发出的系统调用。在调试程序时,他的价值是无法估量的。
下面我们通过一个简单的程序看一下systemcall.c:
-
.section .bss
-
.lcomm pid, 4
-
.lcomm uid, 4
-
.lcomm gid, 4
-
.section .text
-
.globl _start
-
_start:
-
movl $20, %eax # getpid的系统调用号为20
-
int $0x80 # 软中断,进入系统调用,返回值放在eax寄存器中
-
movl %eax, pid # 将返回值放到pid中
-
-
movl $24, %eax # getuid的系统调用号24
-
int $0x80
-
movl %eax, uid
-
-
movl $47, %eax # getgid的系统调用号为47
-
int $0x80
-
movl %eax, gid
-
不需要
-
end:
-
movl $1, %eax
-
movl $0, %ebx
-
int $0x80
编译,用strace命令执行: strace ./systemcall 得到如下信息:
-
execve("./systemcall", ["./systemcall"], [/* 37 vars */]) = 0
-
getpid() = 3744
-
getuid() = 1000
-
getgid() = 1000
-
_exit(0) = ?
上面显示了所有systemcall运行时的所有系统调用,按照应用程序执行顺序排列。左边的是系统调用名称,右边的是系统调用的返回值。系统调用execve显示操作系统shell如何运行这个程序,包括命令行中的参数和环境变量。
命令行加上一个"-c"参数后,程序运行结束,生成一个报告,概述所有系统调用,以及所有系统调用发生所用的时间。
点击(此处)折叠或打开
-
$ strace -c ./systemcalltest2
-
% time seconds usecs/call calls errors syscall
-
------ ----------- ----------- --------- --------- ----------------
-
-nan 0.000000 0 1 execve
-
-nan 0.000000 0 1 getpid
-
-nan 0.000000 0 1 getuid
-
-nan 0.000000 0 1 getgid
-
------ ----------- ----------- --------- --------- ----------------
-
100.00 0.000000 4 total
time显示的是时间,由于getpid, getuid, getgid都用时比较少,所以没能显示,但是我们可以看出总用时100usecs.
strace程序的基本操作产生很多的数据,可以使用命令行调整strace程序以便适合特定的应用程序。
点击(此处)折叠或打开
-
参数 描述
-
-c 统计每个系统调用的时间,调用和错误
-
-d 显示一些strace的调试输出
-
-e 指定输出的过滤表达式
-
-f 在创建子进程的时候跟踪他们
-
-ff 如果写入到输出文件,则把子进程写入到单独的文件中
-
-i 显示执行系统调用时的指令指针
-
-o 把输出写入到指定的文件
-
-p 附加到由PID指定的现有进程
-
-q 抑制关于附加和分离的消息
-
-r 对每个系统调用显示一个相对的时间戳
-
-t 把时间添加到没一行
-
-tt 把时间添加到没一行,包括微秒
-
-ttt 添加epoch形式的时间(从1970年1月1日的秒数),包括微秒
-
-T 显示每个系统调用花费的时间
-
-v 显示系统调用信息的不经省略的版本(详细的)
-
-x 以十六进制的形式显示所有非ASCII字符
-
-xx 以十六进制显示所有字符
举例:
点击(此处)折叠或打开
-
$ strace -e trace=getpid,getuid,getgid ./systemcalltest2
-
getpid() = 3740
-
getuid() = 1000
-
getgid() = 1000
注意: trace=call_list由于编程习惯的问题,习惯性的会在=/,之类的后面加上空格,这里不需要
我们可以用strace -o outfile ./systemcall把调试信息输入到outfile文件中,以便查看。
下面我们调试一个简单的C程序,经典的helloworld.c:
-
#include <stdio.h>
-
-
int main()
-
{
-
printf("hello world!\n");
-
return 0;
-
}
编译,用strace执行:
-
$ strace -c ./helloworld
-
hello world!
-
% time seconds usecs/call calls errors syscall
-
------ ----------- ----------- --------- --------- ----------------
-
-nan 0.000000 0 1 read
-
-nan 0.000000 0 1 write
-
-nan 0.000000 0 2 open
-
-nan 0.000000 0 2 close
-
-nan 0.000000 0 1 execve
-
-nan 0.000000 0 3 3 access
-
-nan 0.000000 0 1 brk
-
-nan 0.000000 0 1 munmap
-
-nan 0.000000 0 3 mprotect
-
-nan 0.000000 0 7 mmap2
-
-nan 0.000000 0 3 fstat64
-
-nan 0.000000 0 1 set_thread_area
-
------ ----------- ----------- --------- --------- ----------------
-
100.00 0.000000 26 3 total
我们发现access系统调用发生了3次错误,这时候我们可以用-e参数来查看。
-
$ strace -e trace=access ./helloworld
-
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
-
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
-
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
-
hello world!
这样我们就能轻松的发现错误原因,并能够方便的解决问题。
下面我们在做一个附加到正在运行的程序测试。
strace程序的另一个非常好的特性是监视已经运行在系统上程序的能力。-p参数可以把strace程序附加到一个PID并且捕获系统调用。
我们将helloworld.c程序稍作修改,让他循环打印hell oworld五次,中间间隔5秒。
-
#include <stdio.h>
-
-
int main()
-
{
-
int i;
-
for (i = 0; i < 10; i++)
-
{
-
printf("hello world!\n");
-
sleep(5);
-
}
-
return 0;
-
}
编译,运行./helloworld &(在后台运行),然后查看进程号。
-
$ ./helloworld &
-
[1] 3893
-
-
$ ps ax | grep helloworld
-
3893 pts/0 S 0:00 ./helloworld
下面我们执行strac -p 3893
-
$ strace -p 3893
Process 3897 attached - interrupt to quit
restart_syscall(<... resuming interrupted call ...>) = 0
write(1, "hello world!\n", 13) = 13
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
nanosleep({5, 0}, 0xbfc987d4) = 0
write(1, "hello world!\n", 13) = 13
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
nanosleep({5, 0},
这样我们就能查看进程3893的运行状态和系统调用过程。
好了,今天的strace学习就到这里,第一次写也没有经验,基本上是参考书上的例子,加上自己的一点点改动,当作学习笔记,也希望能帮助到一些朋友。
希望各位能多提些意见,谢谢
阅读(1438) | 评论(0) | 转发(0) |