linux进程内存结构&coredump filter

本文详细介绍了Linux进程的内存结构,包括text、data、bss、so、文件映射、匿名映射、heap和stack,并阐述了如何设置coredump,包括ulimit命令的使用和core_pattern的配置。同时,文章深入讲解了内核转储掩码,解释了不同掩码位对应的不同内存段,并通过实例分析了不同掩码下core文件的内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、进程的内存结构

一个进程的内存包含以下的部分:

text(代码段 ,可执行)
data (只读数据段)
bss(读写数据段(静态 或 全局变量))

以上从可执行文件中映射过来,分段映射


so(共享库的映射,和可执行文件一样,分段映射)
文件映射/匿名文件映射
heap
stack

结构如下:

这里写图片描述

地址从0x400000开始,不大于0xC0000000。

二、coredump

1、设定coredump

ulimit   -S -c unlimited(unlimited or core文件大小,单位为block(KB))

  • -H 设置硬件资源限制.
  • -S 设置软件资源限制.

sudo sh -c "echo '1' > /proc/sys/kernel/core_uses_pid"

sudo sh -c "echo '/home/wangxiumin/test/core-%e-%p-%t' > /proc/sys/kernel/core_pattern"

使用ulimit -a可以查看所有资源限制的设定值

也可以在 /etc/security/limits.conf 和环境变量中设定限制,这里不详述。

2、内核转储掩码:

程序崩溃 或 使用gcore工具 生成进程的core文件时,可以通过设定内核转储掩码来筛选需要dump的部分内存。

支持以下7种内存:

  - (bit 0) anonymous private memory(匿名私有内存段)

  - (bit 1) anonymous shared memory(匿名共享内存段)

  - (bit 2) file-backed private memory(file-backed 私有内存段):文件映射的内存

  - (bit 3) file-backed shared memory(file-bakced 共享内存段)

  - (bit 4) ELF header pages in file-backed private memory areas (it is

            effective only if the bit 2 is cleared)(ELF 文件映射,只有在bit 2 复位的时候才起作用)

  - (bit 5) hugetlb private memory(大页面私有内存) :mmap 映射的MAP_HUGETLB类型数据

  - (bit 6) hugetlb shared memory(大页面共享内存)

可以通过修改文件/proc/<pid>/coredump_filter来筛选需要dump的内存段。

/proc/<pid>/coredump_filter中的值为16进制,默认值为0x23,转化为二进制:00100011,从右向左看,bit 0、bit 1、bit 5 被置位,也就是说会转储所有的匿名内存段和大页面私有内存段。

 

三、例子分析

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/shm.h>

const int a = 10;                     //text
static  int c = 2;                    //data
static  int b;
int     d = 1;                   
int     e;                            //bss
int main(int argc, char *argv[])
{
        int len = 0;
        char *string = NULL;
        char *ptr1;
        char *ptr2;
        char *ptr3;
        char *ptr4;
        char *p_malloc = malloc(1024);   //heap

        char *shem = NULL;
        int  shmid  = 0;

        const int a1 = 10;
        static  int c1 = 2;
        static  int b1;
        int     d1 = 1;
        int     e1;

        
        int fd = open("111.txt",O_RDWR);
        char cmd[1024];
        sprintf(cmd,"echo '%s' > /proc/%d/coredump_filter",argv[1],getpid()); //设定coredump范围

        system(cmd);

        //filebackend 共享内存映射
        ptr1 = mmap(NULL, 4*1024 , PROT_READ|PROT_WRITE,MAP_SHARED , fd , 0);
        //filebackend 私有内存映射
        ptr2 = mmap(NULL, 4*1024 , PROT_READ|PROT_WRITE,MAP_PRIVATE  , fd , 0);
        //匿名私有内存 映射
        ptr3 = mmap(NULL, 4*1024 , PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1 , 0);
        //匿名共享内存 映射
        ptr4 = mmap(NULL, 4*1024 , PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_SHARED, -1 , 0);
 
        // systemV share 内存
        shmid = shmget(IPC_PRIVATE, 4*1024, IPC_CREAT|0600 );
        shem = shmat(shmid,NULL ,0);

        printf("p_malloc = 0x%x\n",p_malloc);

        printf("globle constant = 0x%x\n",&a);
        printf("globle static init address = 0x%x\n",&c);
        printf("globle static address = 0x%x\n",&b);
        printf("globle init address = 0x%x\n",&d);
        printf("globle address = 0x%x\n",&e);

        printf("local constant = 0x%x\n",&a1);
        printf("local static init address = 0x%x\n",&c1);
        printf("local static address = 0x%x\n",&b1);

        printf("stack address = 0x%x\n",&len);

        printf("fd shared ptr= 0x%x\n",ptr1);
        printf("fd private ptr = 0x%x\n",ptr2);
        printf("ANONYMOUS shared = 0x%x\n",ptr4);
        printf("ANONYMOUS private = 0x%x\n",ptr3);

        printf("shm id = 0x%x\n",shmid);
        printf("shm pointer = 0x%x\n",shem);

        // 使用pmap查看本进程的内存
        memset(cmd,0,1024);
        sprintf(cmd,"pmap -d %d",getpid());
        system(cmd);

        // gcore dump 出core
        memset(cmd,0,1024);
        sprintf(cmd,"gcore  %d",getpid());
        system(cmd);

        free(p_malloc);

        shmctl(shmid,IPC_RMID, NULL);

        munmap(ptr1,4*1024);
        munmap(ptr2,4*1024);
        munmap(ptr3,4*1024);
        munmap(ptr4,4*1024);
        close(fd);

        return 0;
}

程序的入参为内核转储掩码

./ r  0x7f  (dump 出所有的部分)

./r 0x7f
p_malloc = 0xeb1010
globle constant = 0x400d50
globle static init address = 0x60209c
globle static address = 0x6020ac
globle init address = 0x6020a0
globle address = 0x6020b4
local constant = 0x400d50
local static init address = 0x60209c
local static address = 0x6020ac
stack address = 0x7b34eee4
fd shared ptr= 0xee517000
fd private ptr = 0xee516000
ANONYMOUS shared = 0xee514000
ANONYMOUS private = 0xee515000
shm id = 0x2828018
shm pointer = 0xee513000
20987:   ./r 0x7f
Address           Kbytes Mode  Offset           Device    Mapping
0000000000400000       8 r-x-- 0000000000000000 000:00022 r             //代码段
0000000000601000       4 r---- 0000000000001000 000:00022 r             //只读数据段
0000000000602000       4 rw--- 0000000000002000 000:00022 r             // 读写数据段
0000000000eb1000     132 rw--- 0000000000000000 000:00000   [ anon ]    // malloc 堆
00007f31edf37000    1752 r-x-- 0000000000000000 0fd:00001 libc-2.17.so   //分段映射的so,属于file-backend 私有内存段。
00007f31ee0ed000    2048 ----- 00000000001b6000 0fd:00001 libc-2.17.so
00007f31ee2ed000      16 r---- 00000000001b6000 0fd:00001 libc-2.17.so
00007f31ee2f1000       8 rw--- 00000000001ba000 0fd:00001 libc-2.17.so
00007f31ee2f3000      20 rw--- 0000000000000000 000:00000   [ anon ]     //执行该so分配的内存
00007f31ee2f8000     132 r-x-- 0000000000000000 0fd:00001 ld-2.17.so
00007f31ee501000      12 rw--- 0000000000000000 000:00000   [ anon ]
00007f31ee512000       4 rw--- 0000000000000000 000:00000   [ anon ]
00007f31ee513000       4 rw-s- 0000000000000000 000:00004   [ shmid=0x2828018 ] systemV使用的shm
00007f31ee514000       4 rw-s- 0000000000000000 000:00004 zero (deleted)   //匿名共享内存
00007f31ee515000       4 rw--- 0000000000000000 000:00000   [ anon ]       //用户自己分配的匿名私有内存
00007f31ee516000       4 rw--- 0000000000000000 000:00022 111.txt          //file-backend 私有
00007f31ee517000       4 rw-s- 0000000000000000 000:00022 111.txt          //file-backend share
00007f31ee518000       4 rw--- 0000000000000000 000:00000   [ anon ]
00007f31ee519000       4 r---- 0000000000021000 0fd:00001 ld-2.17.so
00007f31ee51a000       4 rw--- 0000000000022000 0fd:00001 ld-2.17.so
00007f31ee51b000       4 rw--- 0000000000000000 000:00000   [ anon ]
00007fff7b32f000     132 rw--- 0000000000000000 000:00000   [ stack ]      // 栈
00007fff7b3f7000       8 r-x-- 0000000000000000 000:00000   [ anon ]
ffffffffff600000       4 r-x-- 0000000000000000 000:00000   [ anon ]
mapped: 4320K    writeable/private: 332K    shared: 12K
0x00007f31edff409c in waitpid () from /lib64/libc.so.6
warning: target file /proc/20987/cmdline contained unexpected null characters
warning: Memory read failed for corefile section, 1048576 bytes at 0x7f31ee0ed000. //相应部分没有权限所以报warning
Saved corefile core.20987

pmap结果中,每列的含义:

Address  :每个映射的起始虚拟地址
Kbytes :大小
Mode  :权限
Offset  :映射起始位置在文件中的偏移
Device  :设备名
Mapping:映像支持文件,已分配的内存

对与分配的没有明确的名字的内存,显示anon。

最后一行统计数据:

mapped: 总映射的大小

writeable/private:进程实际的私有内存(包含用户申请的file-backend部分,但不包含so的映射部分)

 shared: 共享内存的大小

pmap的数据来源于 /proc/<pid>/smaps & /proc/<pid>/maps

 

四、内核转储掩码试验:

传入不同的内核转储掩码,对core文件进行调试分析,确认dump出的具体内容:

1、./r 0x01

./r 0x01

gdb ./r core.2722
GNU gdb (GDB) 7.10.1
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-unknown-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./r...done.
[New LWP 2722]
Core was generated by `./r'.
#0  0x00007f3a7a56809c in waitpid () from /lib64/libc.so.6
(gdb) bt
#0  0x00007f3a7a56809c in waitpid () from /lib64/libc.so.6
#1  0x00007f3a7a4ed072 in do_system () from /lib64/libc.so.6
#2  0x0000000000400c48 in main (argc=2, argv=0x7fffb25a8f88) at test_ram.c:160
(gdb) f 2
#2  0x0000000000400c48 in main (argc=2, argv=0x7fffb25a8f88) at test_ram.c:160
160		system(cmd);
(gdb) p a
$1 = 10
(gdb) p c
$2 = 2
(gdb) p p_malloc
$3 = 0x7c6010 ""
(gdb) p ptr1
$4 = 0x7f3a7aa8b000 <error: Cannot access memory at address 0x7f3a7aa8b000>
(gdb) p ptr2
$5 = 0x7f3a7aa8a000 <error: Cannot access memory at address 0x7f3a7aa8a000>
(gdb) p ptr3
$6 = 0x7f3a7aa89000 ""
(gdb) p ptr4
$7 = 0x7f3a7aa88000 <error: Cannot access memory at address 0x7f3a7aa88000>
(gdb) p shmid
$8 = 43483160
(gdb) p shem
$9 = 0x7f3a7aa87000 <error: Cannot access memory at address 0x7f3a7aa87000>
(gdb) 

由结果可知,00000001代表的 匿名私有内存段,包含:可执行文件的 代码段,只读数据段,读写数据段,堆,栈,以及用户手动映射的私有内存段。

2、./r  0x2

gdb ./r core.2837
......
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./r...done.
[New LWP 2837]
Core was generated by `./r'.
#0  0x00007f3f473b309c in ?? ()

没有任何堆栈信息,要想正常调试core文件,匿名内存段必须dump出来

3、./r  0x3

Core was generated by `./r'.
#0  0x00007f41ef2f109c in waitpid () from /lib64/libc.so.6
(gdb) bt
#0  0x00007f41ef2f109c in waitpid () from /lib64/libc.so.6
#1  0x00007f41ef276072 in do_system () from /lib64/libc.so.6
#2  0x0000000000400c48 in main (argc=2, argv=0x7fffec040218) at test_ram.c:160
(gdb) f 2
#2  0x0000000000400c48 in main (argc=2, argv=0x7fffec040218) at test_ram.c:160
160		system(cmd);
(gdb) p ptr1
$1 = 0x7f41ef814000 <error: Cannot access memory at address 0x7f41ef814000>
(gdb) p ptr2
$2 = 0x7f41ef813000 <error: Cannot access memory at address 0x7f41ef813000>
(gdb) p ptr3
$3 = 0x7f41ef812000 ""
(gdb) p ptr4
$4 = 0x7f41ef811000 ""
(gdb) p shmid
$5 = 43614232
(gdb) p shem
$6 = 0x7f41ef810000 ""
(gdb) 

以上可知,00000010对应的匿名共享内存段包含 用户手动映射的 匿名共享内存段

其他情况不再一一试验。

转载于:https://my.oschina.net/ashnah/blog/1930407

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值