S.l.e!ep.¢%

像打了激速一样,以四倍的速度运转,开心的工作
简单、开放、平等的公司文化;尊重个性、自由与个人价值;
posts - 1098, comments - 335, trackbacks - 0, articles - 1
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

Linux调试工具lsof的深入分析

Posted on 2012-03-26 09:06 S.l.e!ep.¢% 阅读(2427) 评论(0)  编辑 收藏 引用 所属分类: gdb
1)查看对某个文件的使用情况
 
 
 
-------------------------------------------------------
 
root@troy:/# lsof -w /etc/passwd
 
 
 
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
 
python  2340 troy   10r   REG    8,1     1804 2886346 /etc/passwd
 
-------------------------------------------------------
 
注:-w参数表示不打印警告信息.
 
lsof程序会打开/proc/PID/fd/目录找到对映的文件句柄,再通过stat系统调用得到文件的详细信息.
 
同时还会利用fdinfo目录下的文件句柄得到打开文件时的状态.
 
例如:
 
 
 
1.1)创建程序test.c,本程序在/tmp/目录下以O_WRONLY(只写)和O_SYNC(同步)方式打开temp文件.
 
-------------------------------------------------------
 
root@troy:/tmp# more test.c
 
#include <unistd.h>
 
#include <sys/types.h>
 
#include <sys/stat.h>
 
#include <fcntl.h>
 
 
 
int main ()
 
{
 
        int fd;
 
        fd = open("/tmp/temp", O_WRONLY|O_SYNC);
 
        lseek(fd, 80L, SEEK_SET);
 
        sleep(100);
 
        close(fd);
 
 
 
        return 0;
 
}
 
 
 
root@troy:/tmp# gcc test.c -o testfd
 
root@troy:/tmp# ./testfd &
 
-------------------------------------------------------
 
 
 
1.2)观察testfd程序打开的文件/tmp/temp
 
-------------------------------------------------------
 
cat /proc/$(lsof -w /tmp/temp|awk '/testfd/{print $2}')/fdinfo/3
 
pos: 80
 
flags: 0110001
 
-------------------------------------------------------
 
我们看到程序输出pos和flags两组数据,pos字段表示被打开文件的当前读写位置,flags表示以文件方式打开该文件.
 
pos为80表示从文件起始位置移动80个字节的位置.
 
flags为0110001中的xxxxxx1表示以只写方式打开文件,如果是只读则为xxxxxx0,如果可读可写则为xxxxxx2,
 
其中的xx1xxxx表示以同步方式(O_SYNC)打开文件,如果改用以O_ASYNC方式打开文件,则为xx2xxxx,
 
如果同时指定了O_SYNC和O_ASYNC两种方式打开文件,结果则为xx3xxxx.
 
如果我们增加了O_APPEND方式打开文件,结果则为xxx2xxx.
 
如果我们增加了O_NONBLOCK方式打开文件,结果则为xxx4xxx.
 
如果同时指定了O_APPEND和NONBLOCK两种方式,结果则为xxx6xxx.
 
最后指明一下O_ASYNC用于打开终端和socket文件,默认产生SIGIO信号.
 
而O_NONBLOCK表示不阻塞打开的文件,只用于FIFO的管道文件中.
 
 
 
 
 
2)查看对某个目录的使用情况
 
 
 
我们先执行上个试验的程序.
 
 
 
-------------------------------------------------------
 
root@troy:~# /tmp/testfd &
 
[1] 17021
 
 
 
root@troy:~# lsof +d /tmp/
 
COMMAND   PID USER   FD   TYPE             DEVICE SIZE/OFF   NODE NAME
 
gedit    2531 troy    7u  unix 0xffff880029a49b00      0t0  17106 /tmp/gedit.troy.917415843
 
testfd  17021 root  txt    REG                8,1     8617 262475 /tmp/testfd
 
testfd  17021 root    3w   REG                8,1        0 262412 /tmp/temp
 
bash    3926  troy  cwd    DIR                8,1     4096 262149 /tmp
 
bash    4001  troy  cwd    DIR                8,1     4096 262149 /tmp
 
-------------------------------------------------------
 
 
 
如果不加参数+d呢?这里我们只看到了用户的当前使用目录,如下:
 
 
 
-------------------------------------------------------
 
root@troy:~# lsof -w /tmp
 
COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
 
bash    3926 troy  cwd    DIR    8,1     4096 262149 /tmp
 
bash    4001 troy  cwd    DIR    8,1     4096 262149 /tmp
 
-------------------------------------------------------
 
 
 
有什么区别吗?
 
加+d参数的情况下,lsof会遍列所有的进程,以及进程下所有的fd,fdinfo,cwd,root,exec,maps,以查找被程序占用中的目录.
 
而不加参数+d的情况下,lsof只会遍列所有进程的cwd,cwd是用户当前目录的软链接.如下:
 
 
 
-------------------------------------------------------
 
root@troy:~# ls -l /proc/3926/cwd
 
lrwxrwxrwx 1 troy troy 0 2011-02-09 19:23 /proc/3926/cwd -> /tmp
 
-------------------------------------------------------
 
 
 
 
 
 
 
3)查看某个进程的使用情况
 
-------------------------------------------------------
 
troy@troy:/proc/23294$ lsof -p 23294
 
COMMAND   PID USER   FD   TYPE  DEVICE SIZE/OFF    NODE NAME
 
ssh     23294 troy  cwd    DIR     8,1     4096  262149 /tmp
 
ssh     23294 troy  rtd    DIR     8,1     4096       2 /
 
ssh     23294 troy  txt    REG     8,1   339712 1058082 /usr/bin/ssh
 
ssh     23294 troy  mem    REG     8,1    51712  787472 /lib/libnss_files-2.11.1.so
 
ssh     23294 troy  mem    REG     8,1    43552  787456 /lib/libnss_nis-2.11.1.so
 
ssh     23294 troy  mem    REG     8,1    97256  787430 /lib/libnsl-2.11.1.so
 
ssh     23294 troy  mem    REG     8,1    35712  787454 /lib/libnss_compat-2.11.1.so
 
ssh     23294 troy  mem    REG     8,1   135745  787466 /lib/libpthread-2.11.1.so
 
ssh     23294 troy  mem    REG     8,1    10224  787804 /lib/libkeyutils-1.2.so
 
ssh     23294 troy  mem    REG     8,1    31168 1050775 /usr/lib/libkrb5support.so.0.1
 
ssh     23294 troy  mem    REG     8,1    14584  798518 /lib/libcom_err.so.2.1
 
ssh     23294 troy  mem    REG     8,1   154048 1050756 /usr/lib/libk5crypto.so.3.1
 
ssh     23294 troy  mem    REG     8,1   803192 1050769 /usr/lib/libkrb5.so.3.3
 
ssh     23294 troy  mem    REG     8,1    14696  795838 /lib/libdl-2.11.1.so
 
ssh     23294 troy  mem    REG     8,1  1572232  787469 /lib/libc-2.11.1.so
 
ssh     23294 troy  mem    REG     8,1   213784 1050761 /usr/lib/libgssapi_krb5.so.2.2
 
ssh     23294 troy  mem    REG     8,1    93000  787444 /lib/libresolv-2.11.1.so
 
ssh     23294 troy  mem    REG     8,1    92752  786985 /lib/libz.so.1.2.3.3
 
ssh     23294 troy  mem    REG     8,1  1622304  796093 /lib/libcrypto.so.0.9.8
 
ssh     23294 troy  mem    REG     8,1   136936  787431 /lib/ld-2.11.1.so
 
ssh     23294 troy    0u   CHR  136,20      0t0      23 /dev/pts/20
 
ssh     23294 troy    1u   CHR  136,20      0t0      23 /dev/pts/20
 
ssh     23294 troy    2u   CHR  136,20      0t0      23 /dev/pts/20
 
ssh     23294 troy    3u  IPv4 1603924      0t0     TCP troy.local:41879->10.1.1.7:ssh (ESTABLISHED)
 
ssh     23294 troy    4w  FIFO     0,8      0t0 1603904 pipe
 
ssh     23294 troy    5u   CHR  136,19      0t0      22 /dev/pts/19
 
ssh     23294 troy    6r   CHR     5,0      0t0    1129 /dev/tty
 
ssh     23294 troy    7u   CHR  136,21      0t0      24 /dev/pts/21
 
ssh     23294 troy    8u   CHR  136,20      0t0      23 /dev/pts/20
 
ssh     23294 troy    9u   CHR  136,20      0t0      23 /dev/pts/20
 
ssh     23294 troy   10u   CHR  136,20      0t0      23 /dev/pts/20
 
-------------------------------------------------------
 
 
 
lsof程序会跟据用户指定的PID,遍列/proc/目录找到该PID,在/proc/PID目录下依次打开stat,maps,fd,fdinfo.
 
stat文件包含了当前进程的信息.
 
当前进程的stat如下:
 
23294 (ssh) S 23291 23294 23294 34837 23294 4202496 836 0 0 0 8 10 0 0 20 0 1 0 29282141 39632896 658 18446744073709551615 140114439372800 140114439700540 140733214155456 140733214149016 140114423930835 0 0 4096 136331271 18446744071580239593 0 0 17 1 0 0 0 0 0
 
 
 
maps文件包含映像的文件:
 
当前进程的maps如下:
 
7f6eecf42000-7f6eecf4e000 r-xp 00000000 08:01 787472                     /lib/libnss_files-2.11.1.so
 
7f6eecf4e000-7f6eed14d000 ---p 0000c000 08:01 787472                     /lib/libnss_files-2.11.1.so
 
7f6eed14d000-7f6eed14e000 r--p 0000b000 08:01 787472                     /lib/libnss_files-2.11.1.so
 
7f6eed14e000-7f6eed14f000 rw-p 0000c000 08:01 787472                     /lib/libnss_files-2.11.1.so
 
7f6eed14f000-7f6eed159000 r-xp 00000000 08:01 787456                     /lib/libnss_nis-2.11.1.so
 
7f6eed159000-7f6eed358000 ---p 0000a000 08:01 787456                     /lib/libnss_nis-2.11.1.so
 
7f6eed358000-7f6eed359000 r--p 00009000 08:01 787456                     /lib/libnss_nis-2.11.1.so
 
7f6eed359000-7f6eed35a000 rw-p 0000a000 08:01 787456                     /lib/libnss_nis-2.11.1.so
 
7f6eed35a000-7f6eed371000 r-xp 00000000 08:01 787430                     /lib/libnsl-2.11.1.so
 
7f6eed371000-7f6eed570000 ---p 00017000 08:01 787430                     /lib/libnsl-2.11.1.so
 
7f6eed570000-7f6eed571000 r--p 00016000 08:01 787430                     /lib/libnsl-2.11.1.so
 
7f6eed571000-7f6eed572000 rw-p 00017000 08:01 787430                     /lib/libnsl-2.11.1.so
 
后省略.
 
这里用pmap 23294也可以找到加载的文件与虚拟地址的对映.
 
 
 
fd,fdinfo我们已经分析过了,当lsof找到/proc/23294/3时,发现是个socket文件,如下:
 
 
 
----------------------------------------------------
 
troy@troy:/proc/23294/fd$ ls -l
 
total 0
 
lrwx------ 1 troy troy 64 2011-02-11 02:47 0 -> /dev/pts/20
 
lrwx------ 1 troy troy 64 2011-02-11 02:47 1 -> /dev/pts/20
 
lrwx------ 1 troy troy 64 2011-02-11 02:47 10 -> /dev/pts/20
 
lrwx------ 1 troy troy 64 2011-02-11 01:07 2 -> /dev/pts/20
 
lrwx------ 1 troy troy 64 2011-02-11 02:47 3 -> socket:[1603924]
 
l-wx------ 1 troy troy 64 2011-02-11 02:47 4 -> pipe:[1603904]
 
lrwx------ 1 troy troy 64 2011-02-11 02:47 5 -> /dev/pts/19
 
lr-x------ 1 troy troy 64 2011-02-11 02:47 6 -> /dev/tty
 
lrwx------ 1 troy troy 64 2011-02-11 02:47 7 -> /dev/pts/21
 
lrwx------ 1 troy troy 64 2011-02-11 02:47 8 -> /dev/pts/20
 
lrwx------ 1 troy troy 64 2011-02-11 02:47 9 -> /dev/pts/20
 
----------------------------------------------------
 
 
 
此时会依次打开以下的文件,对网络套字接进行分析,各文件作用如下:
 
/proc/net/raw ---->原始套接字
 
/proc/net/unix ---->UNIX套接字
 
/proc/net/sockstat ---->当前套接字的使用情况
 
/proc/net/tcp ---->TCP套接字
 
/proc/net/udp ---->UDP套接字
 
/proc/net/udplite --->UDP无线通讯套接字
 
 
 
在/proc/net/tcp会找到对映的inode,socket:[1603924]的inode为1603924,而tcp中sl为12的一行正是这个socket服务.如下:
 
----------------------------------------------------
 
more /proc/net/tcp
 
  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode                                                   
 
   0: 00000000:0087 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 8984 1 ffff8800677d1380 300 0 0 2 -1                    
 
   1: 00000000:0369 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 8575 1 ffff8800677d0d00 300 0 0 2 -1                    
 
   2: 00000000:0050 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 8673 1 ffff880068c51a00 300 0 0 2 -1                    
 
   3: 00000000:1770 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 5350 1 ffff880068c50680 300 0 0 2 -1                    
 
   4: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 4315 1 ffff880068c50000 300 0 0 2 -1                    
 
   5: 0100007F:0277 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 25571 1 ffff88001a06c780 300 0 0 2 -1                   
 
   6: 00000000:0BB8 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 7881 1 ffff8800677d0680 300 0 0 2 -1                    
 
   7: 00000000:BD59 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 8986 1 ffff880068c52080 300 0 0 2 -1                    
 
   8: 0100007F:0019 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 6304 1 ffff880068c50d00 300 0 0 2 -1                    
 
   9: 4506010A:D6E9 0701010A:0016 01 00000000:00000000 02:00028405 00000000  1502        0 1603452 2 ffff880057896180 22 4 8 5 -1                  
 
  10: 4506010A:89A5 0701010A:0016 01 00000000:00000000 02:00091EFF 00000000  1502        0 1672803 2 ffff88001a068680 25 4 18 4 -1                  
 
  11: 4506010A:872E 0701010A:0016 01 00000000:00000000 02:0004B77C 00000000  1502        0 1177942 2 ffff880057893a80 125 4 0 3 2                  
 
  12: 4506010A:A397 0701010A:0016 01 00000000:00000000 02:0004D6A6 00000000  1502        0 1603924 2 ffff880057894e00 23 4 0 5 -1                  
 
  13: 4506010A:BD31 0701010A:0016 01 00000000:00000000 02:000139A5 00000000  1502        0 1345002 2 ffff880057897500 22 4 0 5 -1                  
 
  14: 4506010A:8F21 0701010A:0016 01 00000000:00000000 02:000192BE 00000000  1502        0 1351794 2 ffff880057896800 25 4 12 4 -1                 
 
  15: 4506010A:8AD1 0701010A:0016 01 00000000:00000000 02:00094915 00000000  1502        0 1447912 2 ffff880068c55b00 21 4 14 4 -1
 
----------------------------------------------------
 
其中local_address代表本地的IP和端口
 
4506010A(本地地址)的45转化为十进制是69,06转化为十制制是6,01转化为十进制是1,0A转化为十进制是10,倒过来也就是10.1.1.69,是本地地址.
 
A397(本地端口)转化为十进制是41879,也就是本地端口
 
rem_address代表远程IP和端口
 
0701010A(远程地址):10.1.1.7
 
0016(远程端口)22
 
其它参数都是内核调试时使用
 
uid就是用户的UID
 
 
 
 
 
 
 
4)显示所属user进程打开的文件
 
 
 
----------------------------------------------------
 
root@troy:/proc/2554# lsof -u test -w
 
COMMAND  PID USER   FD   TYPE             DEVICE SIZE/OFF    NODE NAME
 
su      2554 test  cwd    DIR                8,1     4096       2 /
 
su      2554 test  rtd    DIR                8,1     4096       2 /
 
su      2554 test  txt    REG                8,1    36864  262185 /bin/su
 
su      2554 test  mem    REG                8,1    27024  797476 /lib/libnss_lsass.so.2.0.0
 
su      2554 test  mem    REG                8,1    10272 1102794 /usr/lib/gconv/IBM850.so
 
su      2554 test  mem    REG                8,1    14392 1102782 /usr/lib/gconv/UTF-16.so
 
su      2554 test  mem    REG                8,1    43528  795516 /lib/security/pam_gnome_keyring.so
 
su      2554 test  mem    REG                8,1   256768  787477 /lib/libdbus-1.so.3.4.0
 
su      2554 test  mem    REG                8,1    14536 1052877 /usr/lib/libck-connector.so.0.0.0
 
su      2554 test  mem    REG                8,1    10360  795488 /lib/security/pam_ck_connector.so
 
su      2554 test  mem    REG                8,1    14344  787928 /lib/libgpg-error.so.0.4.0
 
su      2554 test  mem    REG                8,1   491000  787918 /lib/libgcrypt.so.11.5.2
 
su      2554 test  mem    REG                8,1    92752  786985 /lib/libz.so.1.2.3.3
 
su      2554 test  mem    REG                8,1    67896 1055840 /usr/lib/libtasn1.so.3.1.7
 
su      2554 test  mem    REG                8,1    10224  787804 /lib/libkeyutils-1.2.so
 
su      2554 test  mem    REG                8,1    31168 1050775 /usr/lib/libkrb5support.so.0.1
 
su      2554 test  mem    REG                8,1    14584  798518 /lib/libcom_err.so.2.1
 
以下略
 
----------------------------------------------------
 
 
 
通过strace,我们知道lsof通过stat系统调用得到这个进程的目录owner,正是我们要找的用户进程.
 
 
 
如下:
 
stat("/proc/2554/", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
 
open("/proc/2554/stat", O_RDONLY)       = 4
 
read(4, "2554 (su) S 2533 2554 2533 34817"..., 4096) = 241
 
 
 
最后lsof通过调用cwd,root,fd,fdinfo,maps以及网络套接字显示输出用户进程所使用的文件.
 
 
 
 
 
 
 
5)显示网络服务
 
 
 
----------------------------------------------------
 
root@troy:~# lsof -i
 
COMMAND    PID        USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
 
smbd       767        root   22u  IPv6   4410      0t0  TCP *:microsoft-ds (LISTEN)
 
smbd       767        root   23u  IPv6   4412      0t0  TCP *:netbios-ssn (LISTEN)
 
sshd       787        root    3u  IPv4   4227      0t0  TCP *:ssh (LISTEN)
 
sshd       787        root    4u  IPv6   4229      0t0  TCP *:ssh (LISTEN)
 
avahi-dae  809       avahi   13u  IPv4   4568      0t0  UDP *:mdns
 
avahi-dae  809       avahi   14u  IPv4   4569      0t0  UDP *:50511
 
dhclient   883        root    5u  IPv4   4530      0t0  UDP *:bootpc
 
Xorg       912        root    1u  IPv6   4705      0t0  TCP *:x11 (LISTEN)
 
Xorg       912        root    3u  IPv4   4706      0t0  TCP *:x11 (LISTEN)
 
dcerpcd   1132        root   15u  IPv4   8845      0t0  TCP *:loc-srv (LISTEN)
 
dcerpcd   1132        root   16u  IPv4   8846      0t0  UDP *:loc-srv
 
eventlogd 1261        root   14u  IPv4   8850      0t0  TCP *:55846 (LISTEN)
 
exim4     1563 Debian-exim    3u  IPv4   6359      0t0  TCP localhost:smtp (LISTEN)
 
以下略
 
----------------------------------------------------
 
 
 
lsof通过遍列所有进程的所有文件句柄,找到网络套接字,再通过/proc/net/下面的网络信息得到具体的套接字信息.

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理