linux proc pid maps,/proc/[pid]/pagemaps and /proc/[pid]/maps | linux

F**/proc//pagemap + /proc//maps dump example program**

Here is a pagemap example that converts virtual addresses to physical: Is there any API for determining the physical address from virtual address in Linux?

The following program uses both /proc//pagemap + /proc//maps to dump page table information to show how they can be used together. Usage:

sudo ./pagemap_dump.out

Sample output:

addr pfn soft-dirty file/shared swapped present library

400000 12845d 0 1 0 1 /bin/bash

401000 12845e 0 1 0 1 /bin/bash

402000 12845f 0 1 0 1 /bin/bash

This tells us for example that the virtual address 0x400000 maps to the physical address

0x12845d000.

Why sudo is required: https://unix.stackexchange.com/questions/345915/how-to-change-permission-of-proc-self-pagemap-file/383838#383838

This program works in two steps:

parse the human readable lines lines from /proc//maps. This files contains lines of form:

7ffff7b6d000-7ffff7bdd000 r-xp 00000000 fe:00 658 /lib/libuClibc-1.0.22.so

which gives us:

7f8af99f8000-7f8af99ff000: a virtual address range that belong to the process, possibly containing multiple pages.

/lib/libuClibc-1.0.22.so the name of the library that owns that memory.

loop over each page of each address range, and ask /proc//pagemap for more information about that page, including the physical address.

pagemap_dump.c

#define _XOPEN_SOURCE 700

#include

#include

#include

#include

#include

#include

#include

typedef struct {

uint64_t pfn : 55;

unsigned int soft_dirty : 1;

unsigned int file_page : 1;

unsigned int swapped : 1;

unsigned int present : 1;

} PagemapEntry;

/* Parse the pagemap entry for the given virtual address.

*

* @param[out] entry the parsed entry

* @param[in] pagemap_fd file descriptor to an open /proc/pid/pagemap file

* @param[in] vaddr virtual address to get entry for

* @return 0 for success, 1 for failure

*/

int pagemap_get_entry(PagemapEntry *entry, int pagemap_fd, uintptr_t vaddr)

{

size_t nread;

ssize_t ret;

uint64_t data;

nread = 0;

while (nread < sizeof(data)) {

ret = pread(pagemap_fd, ((uint8_t*)&data) + nread, sizeof(data) - nread,

(vaddr / sysconf(_SC_PAGE_SIZE)) * sizeof(data) + nread);

nread += ret;

if (ret <= 0) {

return 1;

}

}

entry->pfn = data & (((uint64_t)1 << 55) - 1);

entry->soft_dirty = (data >> 55) & 1;

entry->file_page = (data >> 61) & 1;

entry->swapped = (data >> 62) & 1;

entry->present = (data >> 63) & 1;

return 0;

}

/* Convert the given virtual address to physical using /proc/PID/pagemap.

*

* @param[out] paddr physical address

* @param[in] pid process to convert for

* @param[in] vaddr virtual address to get entry for

* @return 0 for success, 1 for failure

*/

int virt_to_phys_user(uintptr_t *paddr, pid_t pid, uintptr_t vaddr)

{

char pagemap_file[BUFSIZ];

int pagemap_fd;

snprintf(pagemap_file, sizeof(pagemap_file), "/proc/%ju/pagemap", (uintmax_t)pid);

pagemap_fd = open(pagemap_file, O_RDONLY);

if (pagemap_fd < 0) {

return 1;

}

PagemapEntry entry;

if (pagemap_get_entry(&entry, pagemap_fd, vaddr)) {

return 1;

}

close(pagemap_fd);

*paddr = (entry.pfn * sysconf(_SC_PAGE_SIZE)) + (vaddr % sysconf(_SC_PAGE_SIZE));

return 0;

}

int main(int argc, char **argv)

{

char buffer[BUFSIZ];

char maps_file[BUFSIZ];

char pagemap_file[BUFSIZ];

int maps_fd;

int offset = 0;

int pagemap_fd;

pid_t pid;

if (argc < 2) {

printf("Usage: %s pid\n", argv[0]);

return EXIT_FAILURE;

}

pid = strtoull(argv[1], NULL, 0);

snprintf(maps_file, sizeof(maps_file), "/proc/%ju/maps", (uintmax_t)pid);

snprintf(pagemap_file, sizeof(pagemap_file), "/proc/%ju/pagemap", (uintmax_t)pid);

maps_fd = open(maps_file, O_RDONLY);

if (maps_fd < 0) {

perror("open maps");

return EXIT_FAILURE;

}

pagemap_fd = open(pagemap_file, O_RDONLY);

if (pagemap_fd < 0) {

perror("open pagemap");

return EXIT_FAILURE;

}

printf("addr pfn soft-dirty file/shared swapped present library\n");

for (;;) {

ssize_t length = read(maps_fd, buffer + offset, sizeof buffer - offset);

if (length <= 0) break;

length += offset;

for (size_t i = offset; i < (size_t)length; i++) {

uintptr_t low = 0, high = 0;

if (buffer[i] == '\n' && i) {

const char *lib_name;

size_t y;

/* Parse a line from maps. Each line contains a range that contains many pages. */

{

size_t x = i - 1;

while (x && buffer[x] != '\n') x--;

if (buffer[x] == '\n') x++;

while (buffer[x] != '-' && x < sizeof buffer) {

char c = buffer[x++];

low *= 16;

if (c >= '0' && c <= '9') {

low += c - '0';

} else if (c >= 'a' && c <= 'f') {

low += c - 'a' + 10;

} else {

break;

}

}

while (buffer[x] != '-' && x < sizeof buffer) x++;

if (buffer[x] == '-') x++;

while (buffer[x] != ' ' && x < sizeof buffer) {

char c = buffer[x++];

high *= 16;

if (c >= '0' && c <= '9') {

high += c - '0';

} else if (c >= 'a' && c <= 'f') {

high += c - 'a' + 10;

} else {

break;

}

}

lib_name = 0;

for (int field = 0; field < 4; field++) {

x++;

while(buffer[x] != ' ' && x < sizeof buffer) x++;

}

while (buffer[x] == ' ' && x < sizeof buffer) x++;

y = x;

while (buffer[y] != '\n' && y < sizeof buffer) y++;

buffer[y] = 0;

lib_name = buffer + x;

}

/* Get info about all pages in this page range with pagemap. */

{

PagemapEntry entry;

for (uintptr_t addr = low; addr < high; addr += sysconf(_SC_PAGE_SIZE)) {

/* TODO always fails for the last page (vsyscall), why? pread returns 0. */

if (!pagemap_get_entry(&entry, pagemap_fd, addr)) {

printf("%jx %jx %u %u %u %u %s\n",

(uintmax_t)addr,

(uintmax_t)entry.pfn,

entry.soft_dirty,

entry.file_page,

entry.swapped,

entry.present,

lib_name

);

}

}

}

buffer[y] = '\n';

}

}

}

close(maps_fd);

close(pagemap_fd);

return EXIT_SUCCESS;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值