linux查看页表的方法

🧩 一、背景知识:Linux 页表结构

Linux 2.6 内核(特别是 x86/x86_64 架构)中,页表(page table)是把虚拟地址映射到物理地址的多级结构。

常见结构(x86 架构):

级别名称每级条目数量功能
PGDPage Global Directory1024顶级目录
PUDPage Upper Directory(2.6 中可选)一般未启用
PMDPage Middle Directory1024中间层
PTEPage Table Entry1024实际页映射项

在 32 位系统上通常是 2 或 3 级页表,在 64 位系统上是 4 级页表



🧰 二、在用户态查看页表(普通用户能做的)

1. 查看虚拟内存布局

cat /proc/self/maps

或者针对某个进程:

cat /proc/<pid>/maps

这会列出:

地址范围 权限 偏移 设备 inode 文件名

例如:

00400000-00452000 r-xp 00000000 08:01 12345 /bin/bash

虽然这不是直接的页表,但能反映出虚拟内存段分布。



2. 查看页表条目(较低层)

cat /proc/<pid>/pagemap

这是 Linux 2.6.25 之后引入的接口,用于查看每个虚拟页对应的物理页号(PFN)。

使用工具查看:

sudo grep -A 4 "Vm" /proc/<pid>/status

或者使用更方便的命令:

sudo pmap -x <pid>

输出每段虚拟内存对应的页数和物理占用。

⚠️ 注意:老版本(2.6.20 之前)的内核没有 /proc/pid/pagemap,只能通过内核模块或调试器查看页表。


🧩 三、在内核态查看页表(开发或内核调试)

1. 使用 crash 工具(基于 kdump)

如果你有系统的 vmcore(内核转储):

crash /usr/lib/debug/vmlinux vmcore

在 crash shell 中:

crash> vtop <PID> <虚拟地址>

这会解析出页表层级(PGD→PMD→PTE)和对应的物理页号。



2. 使用内核调试器 gdb + vmlinux

例如在 qemu/gdb 调试内核时:

(gdb) p *pgd_offset(current->mm, 0x8048000)

可以直接打印出 PGD/PTE 的内容。



3. 内核模块方式(示例)

自己写一个简单的内核模块来遍历页表:

#include <linux/mm.h>
#include <linux/module.h>

static int __init show_page_table_init(void)
{
    struct mm_struct *mm = current->mm;
    pgd_t *pgd = pgd_offset(mm, 0x8048000);
    printk(KERN_INFO "PGD: %lx\n", pgd_val(*pgd));
    return 0;
}

static void __exit show_page_table_exit(void) { }

module_init(show_page_table_init);
module_exit(show_page_table_exit);
MODULE_LICENSE("GPL");

编译加载后,你可以在 dmesg 中看到页表项信息。

⚠️ 必须在 root 下执行,并且非常小心不要误操作内核内存。


🔍 四、页表调试辅助工具

工具功能
pmap显示进程的内存映射
cat /proc/pid/pagemap显示虚拟→物理页号映射
gdb / crash内核级调试
自写内核模块打印页表层级内容


💡 总结

需求推荐方法
普通查看cat /proc/<pid>/maps
查看物理映射/proc/<pid>/pagemap(2.6.25+)
深入调试页表结构crash 或 GDB 调试内核
代码层查看内核模块遍历页表(pgd_offsetpmd_offsetpte_offset_map



文章标签:

评论(0)