linux查看页表的方法
已于 2025年10月04日 12:14 修改
访问次数:0
🧩 一、背景知识:Linux 页表结构
在 Linux 2.6 内核(特别是 x86/x86_64 架构)中,页表(page table)是把虚拟地址映射到物理地址的多级结构。
常见结构(x86 架构):
| 级别 | 名称 | 每级条目数量 | 功能 |
|---|---|---|---|
| PGD | Page Global Directory | 1024 | 顶级目录 |
| PUD | Page Upper Directory | (2.6 中可选) | 一般未启用 |
| PMD | Page Middle Directory | 1024 | 中间层 |
| PTE | Page Table Entry | 1024 | 实际页映射项 |
在 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_offset、pmd_offset、pte_offset_map) |
评论(0)