linux proc maps文件分析

Proc/pid/maps显示进程映射了的内存区域和访问权限。对应内核中的操作集为proc_pid_maps_op,具体的导出函数为show_map。内核中进程的一段地址空间用一个vm_area_struct结构体表示,所有地址空间存储在task->mm->mmap链表中。

一个文件可以映射到进程的一段内存区域中,映射的文件描述符保存在vm_area_struct->vm_file域中,这种内存区域叫做有名内存区域,相反,属于匿名映射内存区域。Vm_area_struct每项对应解析如下表所示:


内核每进程的vm_area_struct项


/proc/pid/maps中的项


含义


vm_start


“-”前一列,如00377000


此段虚拟地址空间起始地址


vm_end


“-”后一列,如00390000


此段虚拟地址空间结束地址


vm_flags


第三列,如r-xp


此段虚拟地址空间的属性。每种属性用一个字段表示,r表示可读,w表示可写,x表示可执行,p和s共用一个字段,互斥关系,p表示私有段,s表示共享段,如果没有相应权限,则用’-’代替


vm_pgoff


第四列,如00000000


对有名映射,表示此段虚拟内存起始地址在文件中以页为单位的偏移。对匿名映射,它等于0或者vm_start/PAGE_SIZE


vm_file->f_dentry->d_inode->i_sb->s_dev


第五列,如fd:00


映射文件所属设备号。对匿名映射来说,因为没有文件在磁盘上,所以没有设备号,始终为00:00。对有名映射来说,是映射的文件所在设备的设备号


vm_file->f_dentry->d_inode->i_ino


第六列,如9176473


映射文件所属节点号。对匿名映射来说,因为没有文件在磁盘上,所以没有节点号,始终为00:00。对有名映射来说,是映射的文件的节点号


第七列,如/lib/ld-2.5.so


对有名来说,是映射的文件名。对匿名映射来说,是此段虚拟内存在进程中的角色。[stack]表示在进程中作为栈使用,[heap]表示堆。其余情况则无显示

下面一起看下一个proc maps的例子。

cat /proc/19970/task/19970/maps

001f7000-00212000 r-xp 00000000 fd:00 2719760    /lib/ld-2.5.so

00212000-00213000 r-xp 0001a000 fd:00 2719760    /lib/ld-2.5.so

00213000-00214000 rwxp 0001b000 fd:00 2719760    /lib/ld-2.5.so

00214000-0036b000 r-xp 00000000 fd:00 2719767    /lib/libc-2.5.so

0036b000-0036d000 r-xp 00157000 fd:00 2719767    /lib/libc-2.5.so

0036d000-0036e000 rwxp 00159000 fd:00 2719767    /lib/libc-2.5.so

0036e000-00371000 rwxp 0036e000 00:00 0

0054f000-00565000 r-xp 00000000 fd:00 2719791    /lib/libpthread-2.5.so

00565000-00566000 r-xp 00015000 fd:00 2719791    /lib/libpthread-2.5.so

00566000-00567000 rwxp 00016000 fd:00 2719791    /lib/libpthread-2.5.so

00567000-00569000 rwxp 00567000 00:00 0

006f5000-006f6000 r-xp 006f5000 00:00 0          [vdso]

08048000-08049000 r-xp 00000000 fd:00 3145810    /home/lijz/code/pthread

08049000-0804a000 rw-p 00000000 fd:00 3145810    /home/lijz/code/pthread

08c50000-08c71000 rw-p 08c50000 00:00 0          [heap]

b75d7000-b75d8000 ---p b75d7000 00:00 0

b75d8000-b7fda000 rw-p b75d8000 00:00 0

b7fe4000-b7fe5000 rw-p b7fe4000 00:00 0

bf987000-bf99c000 rw-p bffea000 00:00 0          [stack]

进程的每段地址空间由struct vm_area_struct 描述。如上所示的每一行对应一个vm_area_struct结构体。一个文件可以映射到内存中,vm_area_struct的vm_file保存了文件描述符,这种映射称为有名映射,反之则为匿名映射。下面以第十四行为例,解释各例的内容。

第一列:08049000-0804a000-----本段内存映射的虚拟地址空间范围,对应vm_area_struct中的vm_start和vm_end。

第二列:rw-p----权限 r-读,w-写 x-可执行 p-私有,对应vm_flags。

第三列:00000000----针对有名映射,指本段映射地址在文件中的偏移,对应vm_pgoff。对匿名映射而言,为vm_area_struct->vm_start。

第四列:fd:00----所映射的文件所属设备的设备号,对应vm_file->f_dentry->d_inode->i_sb->s_dev。匿名映射为0。其中fd为主设备号,00为次设备号。

第五列:3145810----文件的索引节点号,对应vm_file->f_dentry->d_inode->i_ino,与ls –i显示的内容相符。匿名映射为0。

第六列:/home/lijz/code/pthread---所映射的文件名。对有名映射而言,是映射的文件名,对匿名映射来说,是此段内存在进程中的作用。[stack]表示本段内存作为栈来使用,[heap]作为堆来使用,其他情况则为无。

经过上面的分析,proc maps中的每一列代表的意思已经非常清晰了。接下来看下proc每maps中每一行的解析。各共享库的代码段,存放着二进制可执行的机器指令,由kernel把该库ELF文件的代码段map到虚存空间;各共享库的数据段,存放着程序执行所需的全局变量,由kernel把ELF文件的数据段map到虚存空间;用户代码段,存放着二进制形式的可执行的机器指令,由kernel把ELF文件的代码段map到虚存空间;用户数据段,存放着程序执行所需的全局变量,由kernel把ELF文件的数据段map到虚存空间;堆(heap),当且仅当malloc调用时存在,由kernel把匿名内存map到虚存空间,堆则在程序中没有调用malloc的情况下不存在;栈(stack),作为进程的临时数据区,由kernel把匿名内存map到虚存空间,栈空间的增长方向是从高地址到低地址。

pthread这个应用程序在maps中占用了两行,内容如下:

08048000-08049000 r-xp 00000000 fd:00 3145810    /home/lijz/code/pthread

08049000-0804a000 rw-p 00000000 fd:00 3145810    /home/lijz/code/pthread

其中第一行的权限是只读,并且可执行,说明第一行是应用程序的代码段,而第二行的权限是可读可写,但是没有执行权限,说明该段是pthread的数据段。

00c56000-00dad000 r-xp 00000000 fd:00 2719767    /lib/libc-2.5.so

00dad000-00daf000 r-xp 00157000 fd:00 2719767    /lib/libc-2.5.so

00daf000-00db0000 rwxp 00159000 fd:00 2719767    /lib/libc-2.5.so

以上是libc-2.5共享库在maps文件中的记录,每个共享库在maps文件中对应着三行,分别是数据段与代码段。

堆[heap]段。

08c64000-08c85000 rw-p 08c64000 00:00 0          [heap]

有些maps文件并不会出现该记录,这主要跟程序中有无使用malloc相关,如果主线程使用了malloc就会有该记录,否则就没有。在子线程中调用malloc,会产生另外的堆映射,但是并不会标记[heap]。例如,在子线程中动态分配1MB的内存空间,pthread2应用程序的执行结果如下所示:

tid addr 0xbfd818f0

child thread run

stackbase 0xb7f4f3c0

stackaddr =0x7754e008----malloc分配的地址

guardsize 4096

对应的maps文件:

08048000-08049000 r-xp 00000000 fd:00 3145811    /home/lijz/code/pthread2

08049000-0804a000 rw-p 00000000 fd:00 3145811    /home/lijz/code/pthread2

0945a000-0947b000 rw-p 0945a000 00:00 0          [heap]

7754e000-b754f000 rw-p 7754e000 00:00 0 -----------区间大小正是1MB

b754f000-b7550000 ---p b754f000 00:00 0

b7550000-b7f52000 rw-p b7550000 00:00 0

b7f5c000-b7f5d000 rw-p b7f5c000 00:00 0

bfd6e000-bfd83000 rw-p bffea000 00:00 0          [stack]

maps文件中红色标注的行,从内容上看,本段内存大小是1MB,权限为读写私有,偏移为本段内存的开始地址,设备号和文件索引节点为0。可以看出本段内存是进程通过mmap映射的一段空间,是匿名映射。在pthread2程序中,正好用malloc分配了一个1MB的内存,能够与这段内存对应。同时,malloc分配的地址0x7754e008正落在该区间,并且偏向区间低地址部分,说明该区间是个堆地址空间。说明了这段1M的内存确实是进程调用malloc分配的,其中malloc又调用mmap系统调用匿名映射。

栈段[stack],下面用几个例子来说明栈段。

bfd50000-bfd65000 rw-p bffea000 00:00 0          [stack]

对于单线程应用程序而言,只有一个[stack]段,对应多线程应用程序,[stack]段是主线程的栈空间,子线程的栈空间则用pthread库自动分配。

例1,将一个单线程的应用的局部变量的地址打印出来,执行的结果如下所示:

./pthread2

tid addr 0xbfc73600

对应的maps文件:

08048000-08049000 r-xp 00000000 fd:00 3145811    /home/lijz/code/pthread2

08049000-0804a000 rw-p 00000000 fd:00 3145811    /home/lijz/code/pthread2

b7f7e000-b7f80000 rw-p b7f7e000 00:00 0

b7f8a000-b7f8b000 rw-p b7f8a000 00:00 0

bfc5f000-bfc74000 rw-p bffea000 00:00 0          [stack]

局部变量的地址0xbfc73600在[stack]区间。

例2:将一个拥有一个子线程的应用局部变量打印出来,执行的结果如下所示:

tid addr 0xbfd64740---------主线程中打印的局部变量地址

child thread run

stackaddr   0xb7fc93c4--------子线程中打印的局部变量地址

guardsize 4096---------栈保护页大小

对应的maps文件如下:

08048000-08049000 r-xp 00000000 fd:00 3145811    /home/lijz/code/pthread2

08049000-0804a000 rw-p 00000000 fd:00 3145811    /home/lijz/code/pthread2

08c64000-08c85000 rw-p 08c64000 00:00 0          [heap]

b75c9000-b75ca000 ---p b75c9000 00:00 0---------pthread_create默认的栈溢出保护区

b75ca000-b7fcc000 rw-p b75ca000 00:000------------pthread_create创建的子线程的栈空间

b7fd6000-b7fd7000 rw-p b7fd6000 00:00 0------------------4KB应该也是通过mmap产生的匿名映射

bfd50000-bfd65000 rw-p bffea000 00:00 0          [stack]---------主进程的栈空间

由上执行结果显示,主线程中局部变量地址0xbfd64740落在[stack]区间,而子线程局部变量地址0xb7fc93c4则落在b75ca000-b7fcc000 rw-p b75ca00区间,并且局部变量的地址从高地址开始分配,说明该VMA正是子线程的栈地址空间。另外,对栈空间,pthread默认设置了一个4KB的栈保护页,对应的区间为:b75c9000-b75ca000---p b75c9000,该区间不可读,不可写,也不能执行,通过这些属性信息的设置,可以达到栈溢出保护的作用。

例3:在例2的基础上,多创建一个线程,pthread2程序的执行结果如下所示:

./pthread2

tid addr 0xbfc81610----------主线程局部变量地址

child thread run

stackaddr = 0xb7f183c0-------子线程1局部变量地址

guardsize 4096

child thread2 run

stackaddr =0xb75173c4 ----------子线程局部变量地址

guardsize 4096

对应的maps文件:

08048000-08049000 r-xp 00000000 fd:00 3145811    /home/lijz/code/pthread2

08049000-0804a000 rw-p 00000000 fd:00 3145811    /home/lijz/code/pthread2

092d6000-092f7000 rw-p 092d6000 00:00 0          [heap]

76b16000-b6b17000 rw-p 76b16000 00:00 0 ----------mallocmmap

b6b17000-b6b18000 ---p b6b17000 00:00 0

b6b18000-b7518000 rw-p b6b18000 00:000---------pthread thread2 stack space

b7518000-b7519000 ---p b7518000 00:00 0

b7519000-b7f1b000 rw-p b7519000 00:000----------pthread thread1 stack space

b7f25000-b7f26000 rw-p b7f25000 00:00 0

bfc6e000-bfc83000 rw-p bffea000 00:00 0          [stack]---main thread stack space

从maps文件记录上看,增加一个子线程,在maps文件中就增加了两条记录,分别是子线程的栈空间和栈保护页的记录。默认情况下,pthread为子线程预留的栈空间大小为1MB,栈保护页为4KB(这主要跟页大小相关)。

总之,proc maps文件可以查看进程的内存映射,每一段内存的权限属性等信息。

时间: 2024-08-27 15:43:18

linux proc maps文件分析的相关文章

linux /proc/meminfo 文件分析(转载)

cat /proc/meminfo    读出的内核信息进行解释, 下篇文章会简单对读出该信息的代码进行简单的分析. # cat /proc/meminfo MemTotal:     16438852 kB MemFree:      10980184 kB Buffers:         95884 kB Cached:         224108 kB SwapCached:          0 kB Active:        5161616 kB Inactive:      

/proc/cpuinfo 文件分析(查看CPU信息)

/proc/cpuinfo文件分析 根据以下内容,我们则可以很方便的知道当前系统关于CPU.CPU的核数.CPU是否启用超线程等信息. <1>查询系统具有多少个逻辑核:cat /proc/cpuinfo | grep "processor" | wc -l   //逻辑处理器的id(逻辑核数) <3>查询系统CPU的个数:cat /proc/cpuinfo | grep "physical id" | sort | uniq | wc -l 

linux /proc/stat 文件说明

/proc/stat 文件内容 # cat /proc/stat cpu 1411 1322 3070 1193539 2790 0 268 0 0 0 cpu0 472 658 787 297933 695 0 19 0 0 0 cpu1 314 157 728 299238 170 0 1 0 0 0 cpu2 322 441 1069 296914 1727 0 246 0 0 0 cpu3 302 66 485 299452 197 0 1 0 0 0 intr 299813 52 96

linux /proc/devices文件与/dev目录区别

关于标题内容的几点解释: 1.proc目录是一个虚拟文件系统,可以为linux用户空间和内核空间提供交互 它只存在于内存中,而不占实际的flash或硬盘空间 2./proc/devices/里的设备是加载驱动程序时生成的 3./dev/下的设备是通过创建设备节点生成的,用户通过此设备节点来访问内核里的驱动

linux /proc/cpuinfo 文件描写叙述

processor :系统中逻辑处理核的编号.对于单核处理器.则课觉得是其CPU编号,对于多核处理器则能够是物理核.或者使用超线程技术虚拟的逻辑核 vendor_id :CPU制造商 cpu family :CPU产品系列代号 model :CPU属于其系列中的哪一代的代号 model name:CPU属于的名字及其编号.标称主频 stepping :CPU属于制作更新版本号 cpu MHz :CPU的实际使用主频 cache size :CPU二级缓存大小 physical id :单个CPU

linux /proc/cpuinfo 文件描述

processor :系统中逻辑处理核的编号.对于单核处理器,则课认为是其CPU编号,对于多核处理器则可以是物理核.或者使用超线程技术虚拟的逻辑核 vendor_id :CPU制造商 cpu family :CPU产品系列代号 model :CPU属于其系列中的哪一代的代号 model name:CPU属于的名字及其编号.标称主频 stepping :CPU属于制作更新版本 cpu MHz :CPU的实际使用主频 cache size :CPU二级缓存大小 physical id :单个CPU的

进程内存分配和/proc/xxx/maps简单分析

参考:http://blog.163.com/tao198352__4232/blog/static/8502064520105611157897/ :http://blog.chinaunix.net/uid-9543173-id-3571436.html 下面是一个Linux进程的标准的内存段布局: maps文件内容输出: [[email protected] src]# cat -n /proc/10800/maps     1  00400000-0040a000 r-xp 000000

Linux内核源代码情景分析-特殊文件系统/proc-对/proc/self/cwd的访问

继上篇文章Linux内核源代码情景分析-特殊文件系统/proc,我们对/proc/loadavg访问后,这篇文章是对/proc/self/cwd的访问. int __user_walk(const char *name, unsigned flags, struct nameidata *nd) { char *tmp; int err; tmp = getname(name);//在系统空间分配一个页面,并从用户空间把文件名复制到这个页面 err = PTR_ERR(tmp); if (!IS

Linux内核源代码情景分析-特殊文件系统/proc

由于proc文件系统并不物理地存在于任何设备上,它的安装过程是特殊的.对proc文件系统不能直接通过mount()来安装,而要先由系统内核在内核初始化时自动地通过一个函数kern_mount()安装一次,然后再由处理系统初始化的进程通过mount()安装,实际上是"重安装". 一.在内核初始化时调用init_proc_fs(),代码如下: static DECLARE_FSTYPE(proc_fs_type, "proc", proc_read_super, FS_