Linux /proc/kcore详解一


前言

环境:
Linux发行版:centos 7.6
linux内核版本: 3.10.0
硬件平台:intel x86_64

一、/proc/kcore

1.1 简介

/proc/kcore是一个动态的内核文件,包含了系统运行中内核的所有数据(内核当前状态的映像),即主内存的全部内容,并以 ELF core file 格式存储,与大多数/proc/目录下的文件不同的是:kcore显示了一个大小,该值以字节为单位。

它由内核在 fs/proc/kcore.c 中创建,并允许从用户空间读取所有内核虚拟内存空间,通过ls -l 展示它的大小是一个非常大数字,但是它根本不占用任何磁盘空间:与 /proc 中的所有其他文件一样,它的内容是由内核在读取文件时动态生成的,并且只能以root权限读取。

在这里插入图片描述


可以看出/proc/kcore显示一个非常大的数字:128T,2^47次方,也就是整个内核虚拟地址空间(x86_64的内核虚拟地址空间为128T:0xFFFF800000000000 ~ 0xFFFFFFFFFFFFFFFF)

在这里插入图片描述

1.2 x86_64内存空间布局

对于 intel x86_64 :
Complete virtual memory map with 4-level page tables(使用4级页表完成虚拟内存映射)

x86_64体系结构定义了一个 64 位的虚拟地址。 当前支持的是 48 位和 57 位虚拟地址。 位 63 到最高有效位是符号扩展的。如果您将它们解释为无符号,这会导致用户空间和内核地址之间出现空洞。
我当前的Intel x86_64机器支持的虚拟地址:48 位虚拟地址

在这里插入图片描述

对于 4-level page tables, Linux支持48 位虚拟地址(仅使用低48位,高16位做扩展),其支持的 2^48次方 = 256T,内核虚拟地址空间和用户虚拟地址空间各是128T。
用户虚拟地址空间:0x0000000000000000 ~ 0x00007FFFFFFFFFFF
内核虚拟地址空间:0xFFFF800000000000 ~ 0xFFFFFFFFFFFFFFFF
其余的都是unused space,hole。

/proc/kcore就是代表着这0xFFFF800000000000 ~ 0xFFFFFFFFFFFFFFFF。

====================================================
Complete virtual memory map with 4-level page tables
====================================================

========================================================================================================================
    Start addr    |   Offset   |     End addr     |  Size   | VM area description
========================================================================================================================
                  |            |                  |         |
 0000000000000000 |    0       | 00007fffffffffff |  128 TB | user-space virtual memory, different per mm
__________________|____________|__________________|_________|___________________________________________________________
                  |            |                  |         |
 0000800000000000 | +128    TB | ffff7fffffffffff | ~16M TB | ... huge, almost 64 bits wide hole of non-canonical
                  |            |                  |         |     virtual memory addresses up to the -128 TB
                  |            |                  |         |     starting offset of kernel mappings.
__________________|____________|__________________|_________|___________________________________________________________
                                                            |
                                                            | Kernel-space virtual memory, shared between all processes:
____________________________________________________________|___________________________________________________________
                  |            |                  |         |
 ffff800000000000 | -128    TB | ffff87ffffffffff |    8 TB | ... guard hole, also reserved for hypervisor
 ffff880000000000 | -120    TB | ffff887fffffffff |  0.5 TB | LDT remap for PTI
 ffff888000000000 | -119.5  TB | ffffc87fffffffff |   64 TB | direct mapping of all physical memory (page_offset_base)
 ffffc88000000000 |  -55.5  TB | ffffc8ffffffffff |  0.5 TB | ... unused hole
 ffffc90000000000 |  -55    TB | ffffe8ffffffffff |   32 TB | vmalloc/ioremap space (vmalloc_base)
 ffffe90000000000 |  -23    TB | ffffe9ffffffffff |    1 TB | ... unused hole
 ffffea0000000000 |  -22    TB | ffffeaffffffffff |    1 TB | virtual memory map (vmemmap_base)
 ffffeb0000000000 |  -21    TB | ffffebffffffffff |    1 TB | ... unused hole
 ffffec0000000000 |  -20    TB | fffffbffffffffff |   16 TB | KASAN shadow memory
__________________|____________|__________________|_________|____________________________________________________________
                                                            |
                                                            | Identical layout to the 56-bit one from here on:
____________________________________________________________|____________________________________________________________
                  |            |                  |         |
 fffffc0000000000 |   -4    TB | fffffdffffffffff |    2 TB | ... unused hole
                  |            |                  |         | vaddr_end for KASLR
 fffffe0000000000 |   -2    TB | fffffe7fffffffff |  0.5 TB | cpu_entry_area mapping
 fffffe8000000000 |   -1.5  TB | fffffeffffffffff |  0.5 TB | ... unused hole
 ffffff0000000000 |   -1    TB | ffffff7fffffffff |  0.5 TB | %esp fixup stacks
 ffffff8000000000 | -512    GB | ffffffeeffffffff |  444 GB | ... unused hole
 ffffffef00000000 |  -68    GB | fffffffeffffffff |   64 GB | EFI region mapping space
 ffffffff00000000 |   -4    GB | ffffffff7fffffff |    2 GB | ... unused hole
 ffffffff80000000 |   -2    GB | ffffffff9fffffff |  512 MB | kernel text mapping, mapped to physical address 0
 ffffffff80000000 |-2048    MB |                  |         |
 ffffffffa0000000 |-1536    MB | fffffffffeffffff | 1520 MB | module mapping space
 ffffffffff000000 |  -16    MB |                  |         |
    FIXADDR_START | ~-11    MB | ffffffffff5fffff | ~0.5 MB | kernel-internal fixmap range, variable size and offset
 ffffffffff600000 |  -10    MB | ffffffffff600fff |    4 kB | legacy vsyscall ABI
 ffffffffffe00000 |   -2    MB | ffffffffffffffff |    2 MB | ... unused hole
__________________|____________|__________________|_________|___________________________________________________________

1.3 elf core格式

在用file命令查看:

file /proc/kcore

在这里插入图片描述

它在内部具有 ELF 核心转储文件的格式(ELF 类型 4/ET_CORE)。 这意味着它与崩溃进程的核心文件具有相同的格式; 但它不是在崩溃时捕获单个进程的(静态)状态,而是提供整个系统状态的实时视图。

ELF 类型 4/ET_CORE:表示是elf文件格式的第四种类型。
其它三种格式: .o文件(ET_REL)、.so文件(ET_DYN)、exe文件(ET_EXEC)

ET_CORE:通过gdb 调试就能恢复到故障现场。
/proc/kcore 是把当前系统的内存模拟成一个 elf core 文件,可以使用gdb 对当前系统进行在线调试,来查看运行中系统的当前状态。

// include/uapi/linux/elf.h

/* These constants define the different elf file types */
#define ET_REL		1		/* Relocatable file */
#define ET_EXEC		2		/* Executable file */
#define ET_DYN		3		/* Shared object file */
#define ET_CORE		4		/* Core file */

elf core 文件格式简图:
elf core 文件是程序运行时的状态,只有 segment 信息,没有 section 信息。

在这里插入图片描述

1、PT_NOTE。这个是 elf core 中新增的 segment,记录了解析 memory 区域的关键信息。PT_NOTE segment 被分成了多个 elf_note结构,其中 NT_PRSTATUS 类型的记录了复位前 CPU 的寄存器信息,NT_TASKSTRUCT 记录了进程的 task_struct 信息。

/*
 * Notes used in ET_CORE. Architectures export some of the arch register sets
 * using the corresponding note types via the PTRACE_GETREGSET and
 * PTRACE_SETREGSET requests.
 */
#define NT_PRSTATUS		1
#define NT_PRFPREG		2
#define NT_PRPSINFO		3
#define NT_TASKSTRUCT	4
#define NT_AUXV			6

2、PT_LOAD。每个 segemnt 用来记录一段 memory 区域,并记录了这段 memory 对应的物理地址、虚拟地址和长度。

elf core 文件的大部分内容用 PT_LOAD segemnt 来记录 memeory 信息。

二、 readelf 读取/proc/kcore

readelf - Displays information about ELF files.

(1)

-h
--file-header

显示文件开头的 ELF header 中包含的信息:

readelf -h /proc/kcore

在这里插入图片描述

linux 内核中elf header数据结构如下:

// include/uapi/linux/elf.h

#define EI_NIDENT	16

typedef struct
{
  unsigned char	e_ident[EI_NIDENT];	/* Magic number and other info */
  Elf64_Half	e_type;				/* Object file type */
  Elf64_Half	e_machine;			/* Architecture */
  Elf64_Word	e_version;			/* Object file version */
  Elf64_Addr	e_entry;			/* Entry point virtual address */
  Elf64_Off		e_phoff;			/* Program header table file offset */
  Elf64_Off		e_shoff;			/* Section header table file offset */
  Elf64_Word	e_flags;			/* Processor-specific flags */
  Elf64_Half	e_ehsize;			/* ELF header size in bytes */
  Elf64_Half	e_phentsize;		/* Program header table entry size */
  Elf64_Half	e_phnum;			/* Program header table entry count */
  Elf64_Half	e_shentsize;		/* Section header table entry size */
  Elf64_Half	e_shnum;			/* Section header table entry count */
  Elf64_Half	e_shstrndx;			/* Section header string table index */
} Elf64_Ehdr;

(2)

-l
--program-headers
--segments

显示文件 segment headers 中包含的信息

readelf -l /proc/kcore

PT_NOTE 程序头包含附加信息,例如线程的寄存器、与每个 VMA 关联的文件等。
程序头中的 PT_LOAD 条目描述了进程的虚拟内存区域 (VMA)。

在这里插入图片描述


注意:
PT_NOTE segment 的 VirtAddr、PhysAddr和MemSiz都是0。
PT_LOAD segment 的 FileSiz、MemSiz 总是相等的,这也说明/proc/kcode是内存中文件,不存在于磁盘中。

linux 内核中程序头表数据结构如下:

typedef struct
{
  Elf64_Word	p_type;			/* Segment type */
  Elf64_Word	p_flags;		/* Segment flags */
  Elf64_Off		p_offset;		/* Segment file offset */
  Elf64_Addr	p_vaddr;		/* Segment virtual address */
  Elf64_Addr	p_paddr;		/* Segment physical address */
  Elf64_Xword	p_filesz;		/* Segment size in file */
  Elf64_Xword	p_memsz;		/* Segment size in memory */
  Elf64_Xword	p_align;		/* Segment alignment */
} Elf64_Phdr;

(3)

-n
--notes

如果有,则显示 NOTE段和/或节的内容(elf core显示NOTE段的内容):

readelf -n /proc/kcore

在这里插入图片描述

/*
 * Notes used in ET_CORE. Architectures export some of the arch register sets
 * using the corresponding note types via the PTRACE_GETREGSET and
 * PTRACE_SETREGSET requests.
 */
#define NT_PRSTATUS		1
#define NT_PRFPREG		2
#define NT_PRPSINFO		3
#define NT_TASKSTRUCT	4
#define NT_AUXV			6

三、 Linux 读取/proc/kcore

对 /proc/kcore 虚拟文件的每次读取访问都由 Linux 内核中的函数 read_kcore 处理。如果读访问包括ELF头、程序头或ELF notes,则会动态生成它们并返回给用户。否则,该函数将匹配要读取到虚拟内存地址的文件偏移量,并将内容复制过来。

//  fs/proc/kcore.c

/*
 * read from the ELF header and then kernel memory
 */
static ssize_t
read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
{
	......
}

static const struct file_operations proc_kcore_operations = {
	.read		= read_kcore,
	.open		= open_kcore,
	.llseek		= default_llseek,
};

四、/proc/iomem

我们常说的内存条和物理内存是不一样的,物理内存是指物理地址空间 ,内存条只是映射到这个地址空间的一部分,其余的还有各种PCI设备,IO端口。

在这里插入图片描述

/proc/iomem 文件显示每个物理设备的系统内存的当前映射,/proc/iomem 是一个虚拟文件,在 kernel/resource.c 中创建。 它列出了映射到物理地址空间的各种 I/O 内存区域,包括 RAM,即我们所说的内存条。

在这里插入图片描述


在 /proc/iomem 的输出中,所有 RAM 范围都被命名为“系统 RAM”。
System RAM:DDR物理内存,内存条。
System RAM 不一定位于物理地址空间的开头,也不总是在一个连续的块中。 为了确定物理地址空间的哪些部分是System RAM(相对于内存映射 I/O),我们通过 /proc/iomem来查找。

 cat /proc/iomem | grep "System RAM"

在这里插入图片描述

总结

这是/proc/kcore解析第一部分,主要是/proc/kcore简介以及readelf读取/proc/kcore文件的描述。

参考资料

https://blog.csdn.net/pwl999/article/details/118418242
https://www.kernel.org/doc/Documentation/x86/x86_64/mm.txt
https://schlafwandler.github.io/posts/dumping-/proc/kcore/
https://zhuanlan.zhihu.com/p/286088470
https://blog.csdn.net/dog250/article/details/102745181
https://freemandealer.github.io/2016/10/07/io-memory/
https://lief-project.github.io/doc/latest/tutorials/12_elf_coredump.html
https://man7.org/linux/man-pages/man5/proc.5.html

原文地址:https://blog.csdn.net/weixin_45030965

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


linux下开机自启: 在/etc/init.d目录下新建文件elasticsearch 并敲入shell脚本: 注意, 前两行必须填写,且要注释掉。 第一行为shell前行代码,目的告诉系统使用shell。 第二行分别代表运行级别、启动优先权、关闭优先权,且后面添加开机服务会用到。 shell脚本
1、因为在centos7中/etc/rc.d/rc.local的权限被降低了,所以需要赋予其可执行权 chmod +x /etc/rc.d/rc.local 2、赋予脚本可执行权限假设/usr/local/script/autostart.sh是你的脚本路径,给予执行权限 chmod +x /usr
最简单的查看方法可以使用ls -ll、ls-lh命令进行查看,当使用ls -ll,会显示成字节大小,而ls- lh会以KB、MB等为单位进行显示,这样比较直观一些。 通过命令du -h –max-depth=1 *,可以查看当前目录下各文件、文件夹的大小,这个比较实用。 查询当前目录总大小可以使用d
ASP.NET Core应用程序发布linux在shell中运行是正常的。可一但shell关闭网站也就关闭了,所以要配置守护进程, 用的是Supervisor,本文主要记录配置的过程和过程遇到的问题 安装Supervisor 1 yum install python-setuptools
设置时区(CentOS 7) 先执行命令timedatectl status|grep 'Time zone'查看当前时区,如果不是时区(Asia/Shanghai),则需要先设置为中国时区,否则时区不同会存在时差。 #已经是Asia/Shanghai,则无需设置 [root@xia
vim /etc/sysconfig/network-scripts/ifcfg-eth0 BOOTPROTO="static" ONBOOT=yes IPADDR=192.168.8.106 NETMASK=255.255.252.0 GATEWAY=192.168.
一、安装gcc依赖 由于 redis 是用 C 语言开发,安装之前必先确认是否安装 gcc 环境(gcc -v),如果没有安装,执行以下命令进行安装 [root@localhost local]# yum install -y gcc 二、下载并解压安装包 [root@localhost local
第一步 On CentOS/RHEL 6.*: $ sudo rpm -Uvh http://li.nux.ro/download/nux/dextop/el6/x86_64/nux-dextop-release-0-2.el6.nux.noarch.rpm On CentOS/RHEL 7: $
/// <summary> /// 取小写文件名后缀 /// </summary> /// <param name="name">文件名</param> /// <returns>返回小写后缀,不带“.”</ret
which nohup .bash_profile中并source加载 如果没有就安装吧 yum provides */nohup nohup npm run start & nohup ./kibana &
1.1 MySQL安装 1.1.1 下载wget命令 yum -y install wget 1.1.2 在线下载mysql安装包 wget https://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm 1.1.3 安装My
重启 reboot shutdown -r now init 6 关闭 init 0 shutdown -h now shutdown -h 20:25 #8点25关机查看内存 free CPU利用率 top 日期 date 设置时间 date 033017002015 #月日时间年 日历 cal
1、firewalld的基本使用 启动: systemctl start firewalld 关闭: systemctl stop firewalld 查看状态: systemctl status firewalld 开机禁用 : systemctl disable firewalld 开机启用 :
1 下载并安装MySQL官方的 Yum Repository wget -i -c http://dev.mysql.com/get/mysql57-community-release-el7-10.noarch.rpm 使用上面的命令就直接下载了安装用的Yum Repository,大概
CentOS6.x CentOS6中转用Upstrat代替以前的init.d/rcX.d的线性启动方式。 一、相关命令 通过initctl help可以查看相关命令 [root@localhost ~]# initctl help Job commands: start Start job. sto
1、使用命令:df -lk 找到已满磁盘 2、使用命令:du --max-depth=1 -h 查找大文件,删除
ifconfig:查看网卡信息 网卡配置文件位置: /etc/sysconfig/network-scripts/文件夹 nmtui:配置网卡 netstat -tlunp:查看端口信息 端口信息存储位置: /etc/services文件 route:查看路由信息 wget:下载网路文件,例如 wg
ps -ef:查看所有进程, ps -ef |grap firewalld 查看与firewalld相关的进程 which :查看进程:which firewalld kill 进程id:杀掉进程 kill 640,强制杀:kill -9 640 man:查看帮助,例如 man ps 查看
useradd:添加用户 useradd abc,默认添加一个abc组 vipw:查看系统中用户 groupadd:添加组groupadd ccna vigr:查看系统中的组 gpasswd:将用户abc添加到ccna组 gpasswd -a abc ccna groups abc:查看用户abc属