简体   繁体   English

如何从Linux中的用户空间找到变量的物理地址?

[英]How to find the physical address of a variable from user-space in Linux?

I want to find the physical address of a variable defined in a user-space process?我想找到在用户空间进程中定义的变量的物理地址? Is there any way to do it using root privileges?有没有办法使用root权限来做到这一点?

As partially answered before, normal programs should not need to worry about physical addresses as they run in a virtual address space with all its conveniences.正如之前部分回答的那样,普通程序不需要担心物理地址,因为它们在虚拟地址空间中运行并具有所有便利性。 Furthermore, not every virtual address has a physical address, the may belong to mapped files or swapped pages.此外,并非每个虚拟地址都有物理地址,它们可能属于映射文件或交换页面。 However, sometimes it may be interesting to see this mapping, even in userland.然而,有时看到这个映射可能会很有趣,即使是在用户空间。

For this purpose, the Linux kernel exposes its mapping to userland through a set of files in the /proc .为此,Linux 内核通过/proc中的一组文件将其映射公开给用户空间。 The documentation can be found here .文档可以在这里找到。 Short summary:简短的摘要:

  1. /proc/$pid/maps provides a list of mappings of virtual addresses together with additional information, such as the corresponding file for mapped files. /proc/$pid/maps提供了虚拟地址的映射列表以及附加信息,例如映射文件的相应文件。
  2. /proc/$pid/pagemap provides more information about each mapped page, including the physical address if it exists. /proc/$pid/pagemap提供有关每个映射页面的更多信息,包括物理地址(如果存在)。

This website provides a C program that dumps the mappings of all running processes using this interface and an explanation of what it does. 这个网站提供了一个 C 程序,它使用这个接口转储所有正在运行的进程的映射,并解释它的作用。

#include "stdio.h"
#include "unistd.h"
#include "inttypes.h"

uintptr_t vtop(uintptr_t vaddr) {
    FILE *pagemap;
    intptr_t paddr = 0;
    int offset = (vaddr / sysconf(_SC_PAGESIZE)) * sizeof(uint64_t);
    uint64_t e;

    // https://www.kernel.org/doc/Documentation/vm/pagemap.txt
    if ((pagemap = fopen("/proc/self/pagemap", "r"))) {
        if (lseek(fileno(pagemap), offset, SEEK_SET) == offset) {
            if (fread(&e, sizeof(uint64_t), 1, pagemap)) {
                if (e & (1ULL << 63)) { // page present ?
                    paddr = e & ((1ULL << 54) - 1); // pfn mask
                    paddr = paddr * sysconf(_SC_PAGESIZE);
                    // add offset within page
                    paddr = paddr | (vaddr & (sysconf(_SC_PAGESIZE) - 1));
                }   
            }   
        }   
        fclose(pagemap);
    }   

    return paddr;
}   

First, why would you want to do this?首先,你为什么要这样做? The purpose of modern VM systems is to remove the application programmer from the complexity of physocal memory layout.现代 VM 系统的目的是将应用程序程序员从物理内存布局的复杂性中移除。 Gving them each their own uniform address space to make their life easyer.给他们每个人自己统一的地址空间,让他们的生活更轻松。

If you did want to do this you would almost certanly need to use a kernel module.如果您确实想这样做,您几乎肯定需要使用内核模块。 Get the virtual address of the variable in the normal way, use this to index into the processes page tables and read the value you find(the physical address of the frame).以正常方式获取变量的虚拟地址,使用它来索引进程页表并读取您找到的值(帧的物理地址)。 Then add the page offset to get the complete physical address.然后加上页偏移量,得到完整的物理地址。 Note you wont be able to use this address while paging is enabled.请注意,启用分页时您将无法使用此地址。

(If your lucky you may be able to get the frame address of a VM region from the /proc file system and thus wouldnt require to write a kernel module.) (如果幸运的话,您可以从 /proc 文件系统中获取 VM 区域的帧地址,因此不需要编写内核模块。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM