pagemap_dump!

This commit is contained in:
Ciro Santilli
2017-07-15 12:37:21 +01:00
parent d189b651ec
commit 105341b7ae
4 changed files with 202 additions and 4 deletions

View File

@@ -123,20 +123,30 @@ We have not managed to track this problem down yet, but the following workaround
This started happening when we switched to building QEMU through Buildroot, and has not been observed on later Ubuntu.
Using text mode is another workaround if you don't need GUI features.
## Filesystem persistency
The root filesystem is persistent across:
./runqemu
./runqemu
date >f
sync
However, when you do:
then:
./runqemu
cat f
This is particularly useful to re-run shell commands from the history of a previous session with `Ctrl + R`.
When you do:
./run
it gets overwritten by a fresh filesystem and you lose all changes.
the disk image gets overwritten by a fresh filesystem and you lose all changes.
Using text mode is another workaround if you don't need GUI features.
Remember that if you forcibly turn QEMU off without `sync` or `poweroff` from inside the VM, disk changes may not be saved.
## Text mode

View File

@@ -12,6 +12,8 @@ These programs can also be compiled and used on host.
1. [myinsmod](myinsmod.c)
1. [myrmmod](myrmmod.c)
1. [init_hello](init_hello.c)
1. [usermem](usermem.c)
1. [pagemap_dump](pagemap_dump.c)
1. Module tests
1. [anonymous_inode](anonymous_inode.c)
1. [poll](poll.c)

View File

@@ -0,0 +1,117 @@
/*
Only tested in x86_64.
Adapted from: https://github.com/dwks/pagemap/blob/8a25747bc79d6080c8b94eac80807a4dceeda57a/pagemap2.c
Dump the page map of a given process PID.
Data sources: /proc/PIC/{map,pagemap}
*/
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#define PAGE_SIZE 0x1000
int main(int argc, char *argv[]) {
char buffer[BUFSIZ];
char maps_file[BUFSIZ];
char pagemap_file[BUFSIZ];
int maps;
int offset = 0;
int pagemap;
if (argc < 2) {
printf("Usage: %s pid1\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) {
perror("open maps");
return EXIT_FAILURE;
}
pagemap = open(pagemap_file, O_RDONLY);
if (pagemap < 0) {
perror("open pagemap");
return EXIT_FAILURE;
}
printf("addr pfn soft-dirty file/shared swapped present library\n");
for (;;) {
ssize_t length = read(maps, 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;
if (buffer[i] == '\n' && i) {
size_t x = i - 1;
while(x && buffer[x] != '\n') x --;
if (buffer[x] == '\n') x++;
size_t beginning = 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;
}
const char *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++;
size_t y = x;
while (buffer[y] != '\n' && y < sizeof buffer) y++;
buffer[y] = 0;
lib_name = buffer + x;
{
unsigned long data;
for (unsigned long i = low; i < high; i += PAGE_SIZE) {
unsigned long index = (i / PAGE_SIZE) * sizeof(data);
if (pread(pagemap, &data, sizeof(data), index) != sizeof(data)) {
if (errno) perror("pread");
break;
}
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
);
}
}
}
}
}
close(maps);
close(pagemap);
return 0;
}

View File

@@ -0,0 +1,69 @@
/*
Only tested in x86_64.
Provide an allocated userland memory address for us to test out kernel memory APIs, including:
- /proc/pid/maps
- /proc/pid/pagemap
- /dev/mem
Usage:
/usermem.out &
Outputs address and pid, e.g.:
address 0x600800
pid 110
Now translate the virtual address to physical for the given PID:
/pagemap2.out 110 | grep 0x600000
where 0x600000 is the page that contains 0x600800.
This produces a line of type:
0x600000 0x7c7b 0 0 0 1 /pagemap_test.out
where 0x7c7b is the PFN. To get the physical address, just add three zeros back:
0x7c7b000
Examine the physical memory from the QEMU monitor: on host:
./qemumonitor
xp 0x7c7b800
Output:
0000000007c7b800: 0x12345678
Yes!!! We read the correct value from the physical address.
TODO: why does:
devmem2 0x7c7b800
fail on the mmap? CONFIG_STRICT_DEVMEM is not set.
*/
#define _XOPEN_SOURCE 700
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
enum { I0 = 0x12345678 };
static volatile uint32_t i = I0;
int main(void) {
printf("address %p\n", (void *)&i);
printf("pid %ju\n", (uintmax_t)getpid());
while (i == I0) {
sleep(1);
}
printf("i %jx\n", (uintmax_t)i);
return EXIT_SUCCESS;
}