命令字:!lsof

基本功能:获取所有或指定进程所打开文件的文件描述符或详细信息。
基本用法:!ndx.lsof

1.用法描述:

在调试代码的过程中,有时我们可能会想要知道某个进程在创建与执行时调用了哪些文件,就可以使用!ndx.lsof命令,该命令会将所有或指定进程所打开的文件的文件描述符列出(部分进程由于权限原因,文件描述符没有或不能访问,用户空间的进程基本正常)。

ts_addr为该进程的地址,fd_addr为该进程文件描述符表的第一个文件描述符的地址,指向一个file结构体。

后面加上 -P <进程地址>可以显示指定地址。

后面加上 -v 可以显示详细信息。

2.开发过程:

1.寻找切入口

要读取进程相关的东西那自然是要从进程结构体入手。我们第一步是要获取linux中的进程描述符的地址,也就是init_task。

在task_struct进程结构体中有一个字段叫做files,如下图

可以看到,其为一个指向files_struct的指针。

获取到该结构体之后,我们就该寻找该进程的文件描述符了。

上图为该结构体的结构,我们需要读取的是偏移为28的fdtab字段,其类型为fdtable结构体(其实在偏移a0的fd_array字段的file指针数组就是我们需要找的文件描述符表,但是我们先要获取一些其他数据)


上图为fdtabl的结构图,箭头所指的即为我们需要读取的数据的,其中max_fds为文件描述符表的最大长度,而fd字段为一个指针,指向上面提到的fd_array数组。


其实图中的这些数字就是这些文件在文件描述符表中的下标,我们只需要打印出该信息即可。

2.如何打印详细信息

要获取详细信息,我们还需要读取表中存放的file结构体中的字段。

上图为file结构体的详细信息,上面有各种字段,如f_pos表示文件当前的偏移量。f_fllags用于储存有关文件的标志,信息,如读写模式,打开方式等。

我们并没有读取很多数据,只是打印了部分关键数据。

上图就是我们所打印的一些数据,最后一个为文件的名称,名称前面的数字为文件描述符,i_ino为该文件的inode号,用于标识和索引该文件的元数据信息,如文件大小,权限等。那么我们是怎么读取到该文件名的呢?

3.读取文件名

在file中有一个f_path的字段,是一个path的结构体,

上图为path结构体,我们需要的文件名在dentry当中


进到dentry结构体当中,如上图,我们需要找d_!name字段,
该字段为一个字符数组,存放的即为文件名。

4.如何读取路径?

本文件的文件名读好了,可是我们还想要看到他的路径,那该怎么办呢?
仔细观察,我们可以发现,在dentry结构体中还有一个d_parent字段,该字段为一个指针指向其父类,知道这个知识,我们就可以很轻松的读取到他的父文件名了。


当然,你也可以用d_subdirs字段,其为一个双向链表,方分别指向他的上位和下位文件的dentry。

匿名文件怎么办?

但并非所有文件都有路径。

这是11.7的改版,可以看到,类似于anon_inode:[eventfd]这种文件还是无路径。

其实这种文件是匿名文件,不真实存在在磁盘当中。前半部分的anon_inode:其实是该文件的一个挂载点,后面的是该文件的名字。所以这类文件我们选择去打印他的挂载点。

作者:施国瑞  创建时间:2023-11-06 11:29
最后编辑:施国瑞  更新时间:2024-08-07 16:18