【问题标题】:Find the mapping from virtual pages to physical pages in Solaris在 Solaris 中查找从虚拟页面到物理页面的映射
【发布时间】:2011-07-23 22:29:21
【问题描述】:

我想访问虚拟页面到某个进程的物理页面的映射。操作系统为Solaris,具体版本可咨询https://stackoverflow.com/users/760807/metallicpriest

我想得到这样的列表:

virt_addrs            phys_addrs
0x000000-0x001000     0x537000-0x538000
0x001000-0x002000     0x832000-0x833000
...

cpu 是 x86 或 x86_64。页面大小为 4K;交换已关闭。我对由 FS(可执行映像)支持且进程未使用的页面不感兴趣。

【问题讨论】:

    标签: memory-management operating-system solaris mmu


    【解决方案1】:

    您可以使用 pmap 和内核调试器 (mdb -k) 来实现。

    Pmap 将首先显示进程使用了​​哪些(虚拟)内存区域,然后,在 mdb 下,您将获得进程结构(pid2proc)并显示其 p_as 字段(进程地址空间)。当将该值作为参数传递时,vtop 命令可以显示进程虚拟到物理地址的映射。

    例如:

    $ pmap -s 609
    609:    /usr/lib/utmpd
     Address    Bytes Pgsz Mode   Mapped File
    08046000       8K   4K rw---    [ stack ]
    08050000      12K   4K r-x--  /usr/lib/utmpd
    08063000       4K   4K rw---  /usr/lib/utmpd
    ...
    
    # mdb -k
    Loading modules: [ unix genunix specfs dtrace mac cpu.generic cpu_ms.AuthenticAMD.15 uppc pcplusmp scsi_vhci zfs ip hook neti arp usba sd sockfs stmf stmf_sbd s1394 fctl lofs random nfs sppp crypto cpc fcip ptm ufs logindmux ipc ]
    > 0t609::pid2proc | ::print proc_t p_as
    p_as = 0xffffff018cf38b00
    > 08046000::vtop -a 0xffffff018cf38b00
    virtual 8046000 mapped to physical a5c16000
    > 8047000::vtop -a 0xffffff018cf38b00
    virtual 8047000 mapped to physical a1267000
    ...
    

    【讨论】:

    • mdb使用哪个接口?我可以仅通过 proc 进行相同的翻译,还是需要直接 /dev/mem 访问?
    • kmdb 内置在内核中。我强烈怀疑您是否可以从用户空间中的任何内容中实现您正在寻找的东西。 /proc 和 /dev/mem 不提供映射信息。
    • /dev/mem 应该有这个信息,因为页表在内存中(典型情况,没有交换)。我想获取被 COW 编辑的页面列表(我有 2 个进程,父进程和子进程,并且想知道哪些页面在父进程或子进程中发生了更改)
    • 这些信息无疑在 /dev/mem 中,但如果没有内核本身的帮助,可能没有可靠的方法来找出 where
    • "mdb -k" 能够从内核中获取此信息,因此无需构建另一个内核模块。跟踪 mdb 如何与内核调试器交互可能会有所帮助。 cvs.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/cmd/mdb/…
    【解决方案2】:

    有点晚了,但在 Solaris 上做起来一点也不难。只需使用libkvm

    这是针对 Solaris 11 的:

    /* needed to get latest /proc structures */
    #define _STRUCTURED_PROC 1
    
    #include <stddef.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <strings.h>
    #include <string.h>
    #include <limits.h>
    #include <stdio.h>
    #include <fcntl.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <kvm.h>
    #include <sys/proc.h>
    #include <sys/procfs.h>
    
    void printVirtToPhysMappings( kvm_t *kvm, const char *pidStr );
    
    int main( int argc, char **argv )
    {
        kvm_t *kvm = kvm_open( NULL, NULL, NULL, O_RDONLY, argv[ 0 ] );
    
        for ( int ii = 1; ii < argc; ii++ )
        {
            printVirtToPhysMappings( kvm, argv[ ii ] );
        }
    
        kvm_close( kvm );
        return( 0 );
    }
    
    
    void printVirtToPhysMappings( kvm_t *kvm, const char *pidStr )
    {
        char mapFile[ PATH_MAX ];
        struct stat sb;
    
        sprintf( mapFile, "/proc/%s/xmap", pidStr );
        pid_t pid = strtol( pidStr, NULL, 0 );
        struct proc *procPtr = kvm_getproc( kvm, pid );
    
        int mapFD = open( mapFile, O_RDONLY );
        fstat( mapFD, &sb );
    
        size_t numMaps = sb.st_size / sizeof( prxmap_t );
        prxmap_t mapEntries[ numMaps ];
    
        pread( mapFD, mapEntries, sb.st_size, 0UL );
    
        for ( size_t ii = 0; ii < numMaps; ii++ )
        {
            /* use the actual page size - page sizes can vary */
            size_t pageSize = mapEntries[ ii ].pr_hatpagesize;
    
            /* if page size is 0, page isn't mapped - set default
               page size so we emit the output anyway */
            if ( 0 == pageSize ) pageSize = 4096;
    
            size_t numPages = mapEntries[ ii ].pr_size / pageSize;
            for ( size_t jj = 0; jj < numPages; jj++ )
            {
                uintptr_t virtAddr = mapEntries[ ii ].pr_vaddr + jj * pageSize;
    
                /* kvm_physaddr() is an undocumented feature of libkvm */
                void *physAddr = ( void * ) kvm_physaddr( kvm, procPtr->p_as, virtAddr );
                printf( "virtAddr: %p, page size: %ld, physAddr: %p\n", virtAddr, pageSize, physAddr );
            }
        }
    
        close( mapFD );
    
    }
    

    您需要是 root 才能运行它,而且根本没有错误检查。给它一个错误的 PID,它可能会是 SEGV。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-09
      • 1970-01-01
      • 1970-01-01
      • 2014-05-18
      • 2020-02-29
      • 2021-03-05
      • 2016-09-25
      • 1970-01-01
      相关资源
      最近更新 更多