在 Solaris 中查找从虚拟页到物理页的映射

发布于 2024-11-26 02:25:02 字数 404 浏览 3 评论 0原文

我想访问虚拟页面到某个进程的物理页面的映射。操作系统是Solaris,确切的版本可以从https://stackoverflow.com/users/760807/metalicpriest

询问想要获得如下列表:

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

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

I want to access a mapping of virtual pages to physical one of some process. The OS is Solaris, the exact version can be asked from https://stackoverflow.com/users/760807/metallicpriest

I want to get list like:

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

The cpu is x86 or x86_64. Page size is 4K; swap is turned off. I'm not interested in pages, that are backed by FS (executable image) and unused by process.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

半仙 2024-12-03 02:25:02

您可以使用 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
...

You can use pmap and the kernel debugger (mdb -k) to achieve that.

Pmap will first displays what (virtual) memory areas are used by the process, then, under mdb, you get the process structure (pid2proc) and display its p_as field (process address space). When passed that value as parameter, the vtop command can display the process virtual to physical address mapping.

eg:

$ 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
...
谈场末日恋爱 2024-12-03 02:25:02

虽然有点晚了,但在 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。

A bit late, but it's not hard to do at all on Solaris. Just use libkvm.

This is for 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 );

}

You'll need to be root to run that, and there's no error checking - at all. Give it a bad PID and it'll probably SEGV.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文