Chinaunix首页 | 论坛 | 博客
  • 博客访问: 14350
  • 博文数量: 2
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 30
  • 用 户 组: 普通用户
  • 注册时间: 2012-10-29 14:00
文章分类
文章存档

2014年(1)

2013年(1)

我的朋友

分类: LINUX

2013-10-15 01:20:40

        注册挺久了,一直都是看没写过,今天就写简单的写第一篇,就叫s《trace学习》吧。
进入正题:
        strace程序截取程序发出的系统调用并且显示它们以供查看。被跟踪的程序可以是从strace命令运行的,也可以是系统上已经运行的程序。如果有适当的权限,就可以研究现有的进程并且监视发出的系统调用。在调试程序时,他的价值是无法估量的。
        下面我们通过一个简单的程序看一下systemcall.c:

点击(此处)折叠或打开

  1. .section .bss
  2.     .lcomm pid, 4
  3.     .lcomm uid, 4
  4.     .lcomm gid, 4
  5. .section .text
  6. .globl _start
  7. _start:
  8.      movl $20, %eax # getpid的系统调用号为20
  9.      int $0x80 # 软中断,进入系统调用,返回值放在eax寄存器中
  10.      movl %eax, pid # 将返回值放到pid中

  11.     movl $24, %eax # getuid的系统调用号24
  12.     int $0x80
  13.     movl %eax, uid

  14.     movl $47, %eax # getgid的系统调用号为47
  15.     int $0x80
  16.     movl %eax, gid
  17. 不需要
  18. end:
  19.     movl $1, %eax
  20.     movl $0, %ebx
  21.     int $0x80
         编译,用strace命令执行: strace ./systemcall 得到如下信息:

点击(此处)折叠或打开

  1. execve("./systemcall", ["./systemcall"], [/* 37 vars */]) = 0
  2. getpid()                = 3744
  3. getuid()                = 1000
  4. getgid()                = 1000
  5. _exit(0)                = ?
        上面显示了所有systemcall运行时的所有系统调用,按照应用程序执行顺序排列。左边的是系统调用名称,右边的是系统调用的返回值。系统调用execve显示操作系统shell如何运行这个程序,包括命令行中的参数和环境变量。
命令行加上一个"-c"参数后,程序运行结束,生成一个报告,概述所有系统调用,以及所有系统调用发生所用的时间。
点击(此处)折叠或打开
  1. $ strace -c ./systemcalltest2
  2. % time seconds usecs/call calls errors syscall
  3. ------ ----------- ----------- --------- --------- ----------------
  4.   -nan 0.000000 0 1 execve
  5.   -nan 0.000000 0 1 getpid
  6.   -nan 0.000000 0 1 getuid
  7.   -nan 0.000000 0 1 getgid
  8. ------ ----------- ----------- --------- --------- ----------------
  9. 100.00 0.000000 4 total
        time显示的是时间,由于getpid, getuid, getgid都用时比较少,所以没能显示,但是我们可以看出总用时100usecs.
        strace程序的基本操作产生很多的数据,可以使用命令行调整strace程序以便适合特定的应用程序。
点击(此处)折叠或打开
  1. 参数                                            描述
  2. -c                                统计每个系统调用的时间,调用和错误
  3. -d                                显示一些strace的调试输出
  4. -e                                指定输出的过滤表达式
  5. -f                                在创建子进程的时候跟踪他们
  6. -ff                               如果写入到输出文件,则把子进程写入到单独的文件中
  7. -i                                显示执行系统调用时的指令指针
  8. -o                                把输出写入到指定的文件
  9. -p                                附加到由PID指定的现有进程
  10. -q                                抑制关于附加和分离的消息
  11. -r                                对每个系统调用显示一个相对的时间戳
  12. -t                                把时间添加到没一行
  13. -tt                               把时间添加到没一行,包括微秒
  14. -ttt                              添加epoch形式的时间(从1970年1月1日的秒数),包括微秒
  15. -T                                显示每个系统调用花费的时间
  16. -v                                显示系统调用信息的不经省略的版本(详细的)
  17. -x                                以十六进制的形式显示所有非ASCII字符
  18. -xx                               以十六进制显示所有字符


   举例:
点击(此处)折叠或打开
  1. $ strace -e trace=getpid,getuid,getgid ./systemcalltest2
  2. getpid() = 3740
  3. getuid() = 1000
  4. getgid() = 1000
    注意: trace=call_list由于编程习惯的问题,习惯性的会在=/,之类的后面加上空格,这里不需要
    我们可以用strace -o outfile ./systemcall把调试信息输入到outfile文件中,以便查看。
    下面我们调试一个简单的C程序,经典的helloworld.c:

点击(此处)折叠或打开

  1. #include <stdio.h>

  2. int main()
  3. {
  4.     printf("hello world!\n");
  5.     return 0;
  6. }
    编译,用strace执行:

点击(此处)折叠或打开

  1. $ strace -c ./helloworld
  2. hello world!
  3. % time seconds usecs/call calls errors syscall
  4. ------ ----------- ----------- --------- --------- ----------------
  5.   -nan 0.000000 0           1          read
  6.   -nan 0.000000 0           1          write
  7.   -nan 0.000000 0           2          open
  8.   -nan 0.000000 0           2          close
  9.   -nan 0.000000 0           1          execve
  10.   -nan 0.000000 0           3      3   access
  11.   -nan 0.000000 0           1          brk
  12.   -nan 0.000000 0           1          munmap
  13.   -nan 0.000000 0           3          mprotect
  14.   -nan 0.000000 0           7          mmap2
  15.   -nan 0.000000 0           3          fstat64
  16.   -nan 0.000000 0           1          set_thread_area
  17. ------ ----------- ----------- --------- --------- ----------------
  18. 100.00 0.000000 26 3 total
    我们发现access系统调用发生了3次错误,这时候我们可以用-e参数来查看。

点击(此处)折叠或打开

  1. $ strace -e trace=access ./helloworld
  2. access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
  3. access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
  4. access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
  5. hello world!
    这样我们就能轻松的发现错误原因,并能够方便的解决问题。


    下面我们在做一个附加到正在运行的程序测试。
    strace程序的另一个非常好的特性是监视已经运行在系统上程序的能力。-p参数可以把strace程序附加到一个PID并且捕获系统调用。
    我们将helloworld.c程序稍作修改,让他循环打印hell oworld五次,中间间隔5秒。

点击(此处)折叠或打开

  1. #include <stdio.h>

  2. int main()
  3. {
  4.     int i;
  5.     for (i = 0; i < 10; i++)
  6.     {
  7.         printf("hello world!\n");
  8.         sleep(5);
  9.     }
  10.     return 0;
  11. }
    编译,运行./helloworld &(在后台运行),然后查看进程号。

点击(此处)折叠或打开

  1. $ ./helloworld &
  2. [1] 3893
  3.  
  4. $ ps ax | grep helloworld
  5.  3893 pts/0 S 0:00 ./helloworld
    下面我们执行strac -p 3893

点击(此处)折叠或打开

  1.  $ 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学习就到这里,第一次写也没有经验,基本上是参考书上的例子,加上自己的一点点改动,当作学习笔记,也希望能帮助到一些朋友。
    希望各位能多提些意见,谢谢




阅读(1403) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:简单修改网卡名称

给主人留下些什么吧!~~