virt_to_phys_user

This commit is contained in:
Ciro Santilli
2017-07-30 23:31:22 +01:00
parent 7d6449d47b
commit 25f9913e0c
5 changed files with 155 additions and 67 deletions

View File

@@ -3,7 +3,8 @@ Only tested in x86_64.
Adapted from: https://github.com/dwks/pagemap/blob/8a25747bc79d6080c8b94eac80807a4dceeda57a/pagemap2.c
https://stackoverflow.com/questions/17021214/how-to-decode-proc-pid-pagemap-entries-in-linux/45126141#45126141
- https://stackoverflow.com/questions/17021214/how-to-decode-proc-pid-pagemap-entries-in-linux/45126141#45126141
- https://stackoverflow.com/questions/5748492/is-there-any-api-for-determining-the-physical-address-from-virtual-address-in-li
Dump the page map of a given process PID.
@@ -13,106 +14,79 @@ Data sources: /proc/PIC/{map,pagemap}
#define _POSIX_C_SOURCE 200809L
#include <errno.h>
#include <fcntl.h>
#include <stdint>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
typedef struct {
uint64_t phys : 54;
int soft_dirty : 1;
int padding : 4;
int padding : 1;
* Bit 61 page is file-page or shared-anon (since 3.5)
* Bit 62 page swapped
* Bit 63 page present
} PagemapEntry;
int parse_pagemap(PagemapEntry &entry, int fd, size_t offset)
{
if (pread(pagemap, &data, ) != sizeof(data)) {
perror("pread");
break;
}
data & 0x7fffffffffffff,
(data >> 55) & 1,
(data >> 61) & 1,
(data >> 62) & 1,
(data >> 63) & 1,
}
#include "common.h" /* pagemap_get_entry */
int main(int argc, char **argv) {
char buffer[BUFSIZ];
char maps_file[BUFSIZ];
char pagemap_file[BUFSIZ];
int maps;
int maps_fd;
int offset = 0;
int pagemap;
long page_size;
int pagemap_fd;
pid_t pid;
if (argc < 2) {
printf("Usage: %s pid\n", argv[0]);
return EXIT_FAILURE;
}
pid_t pid = (pid_t)strtoul(argv[1], NULL, 0);
snprintf(maps_file, sizeof(maps_file), "/proc/%lu/maps", (unsigned long)pid);
snprintf(pagemap_file, sizeof(pagemap_file), "/proc/%lu/pagemap", (unsigned long)pid);
maps = open(maps_file, O_RDONLY);
if (maps < 0) {
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 = open(pagemap_file, O_RDONLY);
if (pagemap < 0) {
pagemap_fd = open(pagemap_file, O_RDONLY);
if (pagemap_fd < 0) {
perror("open pagemap");
return EXIT_FAILURE;
}
page_size = sysconf(_SC_PAGE_SIZE);
printf("addr pfn soft-dirty file/shared swapped present library\n");
for (;;) {
ssize_t length = read(maps, buffer + offset, sizeof buffer - offset);
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++) {
unsigned long low = 0, high = 0;
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 --;
while (x && buffer[x] != '\n') x--;
if (buffer[x] == '\n') x++;
size_t beginning = x;
while(buffer[x] != '-' && x < sizeof buffer) {
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') {
} else if (c >= 'a' && c <= 'f') {
low += c - 'a' + 10;
} else {
break;
}
}
while(buffer[x] != '-' && x < sizeof buffer) x++;
while (buffer[x] != '-' && x < sizeof buffer) x++;
if (buffer[x] == '-') x++;
while(buffer[x] != ' ' && x < sizeof buffer) {
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') {
} else if (c >= 'a' && c <= 'f') {
high += c - 'a' + 10;
} else {
break;
}
else break;
}
lib_name = 0;
for (int field = 0; field < 4; field++) {
@@ -127,27 +101,27 @@ int main(int argc, char **argv) {
}
/* Get info about all pages in this page range with pagemap. */
{
unsigned long data;
PagemapEntry entry;
for (unsigned long i = low; i < high; i += page_size) {
unsigned long index = (i / page_size) * sizeof(data);
parse_pagemap(&entry, pagemap, sizeof(data) * index);
printf("%lx %lx %d %d %d %d %s\n",
i,
data & 0x7fffffffffffff,
(data >> 55) & 1,
(data >> 61) & 1,
(data >> 62) & 1,
(data >> 63) & 1,
lib_name
);
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);
close(pagemap);
return 0;
close(maps_fd);
close(pagemap_fd);
return EXIT_SUCCESS;
}