C++ 一些调试中的小总结(六)

用strace了解程序的工作原理

问题:在进程内打开一个文件,都有唯一一个文件描述符(fd: file descriptor)与这个文件对应。如果已知一个fd,如何获取这个fd所对应文件的完整路径?不管是Linux、FreeBSD或其他Unix系统都没有提供这样的API,那怎么办呢?

我们换个角度思考:Unix下有没有什么命令可以获取进程打开了哪些文件?使用 lsof 命令即可以知道程序打开了哪些文件,也可以了解一个文件被哪个进程打开。(平时工作中很常用,例如,使用 lsof -p PID来查找某个进程存放的位置)

1.#include<stdio.h>  

2.#include<unistd.h>  

3.#include<sys/types.h>  

4.#include<sys/stat.h>  

5.#include<fcntl.h>  

6.  

7.int main()  

8.{  

9.    open("wcdj", O_CREAT|O_RDONLY);// open file foo  

10.    sleep(1200);// sleep 20 mins 方便调试  

11.  

12.    return 0;  

13.}  

14./* 

15.gcc -Wall -g -o testlsof testlsof.c  

16../testlsof &                                       

17.*/  

18.  

19.$ gcc -Wall -g -o testlsof testlsof.c            

20.$ ./testlsof &  

21.[1] 12371  

22.$ strace -o lsof.strace lsof -p 12371  

23.COMMAND    PID      USER   FD   TYPE DEVICE    SIZE    NODE NAME  

24.testlsof 12371 gerryyang  cwd    DIR    8,4    4096 2359314 /data/home/gerryyang/test/HACK  

25.testlsof 12371 gerryyang  rtd    DIR    8,1    4096       2 /  

26.testlsof 12371 gerryyang  txt    REG    8,4    7739 2359364 /data/home/gerryyang/test/HACK/testlsof  

27.testlsof 12371 gerryyang  mem    REG    8,1 1548470 1117263 /lib/libc-2.4.so  

28.testlsof 12371 gerryyang  mem    REG    8,1  129040 1117255 /lib/ld-2.4.so  

29.testlsof 12371 gerryyang  mem    REG    0,0               0 [stack] (stat: No such file or directory)  

30.testlsof 12371 gerryyang    0u   CHR  136,0               2 /dev/pts/0  

31.testlsof 12371 gerryyang    1u   CHR  136,0               2 /dev/pts/0  

32.testlsof 12371 gerryyang    2u   CHR  136,0               2 /dev/pts/0  

33.testlsof 12371 gerryyang    3r   REG    8,4       0 2359367 /data/home/gerryyang/test/HACK/wcdj  

34.$ grep "wcdj" lsof.strace   

35.readlink("/proc/12371/fd/3", "/data/home/gerryyang/test/HACK/wcdj", 4096) = 35  

36.$ cd /proc/12371/fd  

37.$ ls -l  

38.总计 4  

39.lrwx------ 1 gerryyang users 64 2012-03-23 14:14 0 -> /dev/pts/0  

40.lrwx------ 1 gerryyang users 64 2012-03-23 14:14 1 -> /dev/pts/0  

41.lrwx------ 1 gerryyang users 64 2012-03-23 14:14 2 -> /dev/pts/0  

42.lr-x------ 1 gerryyang users 64 2012-03-23 14:14 3 -> /data/home/gerryyang/test/HACK/wcdj  

用strace跟踪lsof的运行,输出结果保存在lsof.strace中。然后通过对lsof.strace内容的分析

从而了解到其实现原理是:

lsof利用了/proc/pid/fd目录。Linux内核会为每一个进程在/proc建立一个以其pid为名的目录用来保存进程的相关信息,而其子目录fd保存的是该进程打开的所有文件的fd。进入/proc/pid/fd目录下,发现每一个fd文件都是符号链接,而此链接就指向被该进程打开的一个文件。我们只要用readlink()系统调用就可以获取某个fd对应的文件了。

 

1.#include<stdio.h>  

2.#include<string.h>  

3.#include<sys/types.h>  

4.#include<unistd.h>// readlink  

5.#include<fcntl.h>  

6.#include<sys/stat.h>  

7.  

8.int get_pathname_from_fd(int fd, char pathname[], int n)  

9.{  

10.    char buf[1024];  

11.    pid_t pid;  

12.    bzero(buf, 1024);  

13.    pid = getpid();  

14.    snprintf(buf, 1024, "/proc/%i/fd/%i", pid, fd);// %i == %d  

15.  

16.    return readlink(buf, pathname, n);  

17.}  

18.  

19.int main()  

20.{  

21.    int fd;  

22.    char pathname[4096] = {0};  

23.    bzero(pathname, 4096);  

24.    fd = open("wcdj", O_RDONLY);                                  

25.      

26.    get_pathname_from_fd(fd, pathname, 4096);  

27.      

28.    printf("fd=%d; pathname=%s\n", fd, pathname);  

29.  

30.    return 0;  

31.}  

32./* 

33.gcc -Wall -g -o GetPathByFd GetPathByFd.c  

34.*/  

​​​​​​​ltrace的基本使用方法(针对前面的demo)

ltrace - A library call tracer

1.$ ltrace ./st1   

2.__libc_start_main(0x8048494, 1, 0xbfe4a204, 0x8048500, 0x80484f0 <unfinished ...>  

3.fopen("r", "r")                                                                                 = 0  

4.puts("r"Error!  

5.)                                                                                       = 7  

6.sleep(3)                                                                                        = 0  

7.fopen("r", "r")                                                                                 = 0  

8.puts("r"Error!  

9.)                                                                                       = 7  

10.sleep(3)                                                                                        = 0  

11.fopen("r", "r")                                                                                 = 0  

12.puts("r"Error!  

13.)                                                                                       = 7  

14.sleep(3 <unfinished ...>  

15.--- SIGINT (Interrupt) ---  

16.+++ killed by SIGINT +++ 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜鸟来了2022

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值