Skip to content

Instantly share code, notes, and snippets.

@hillu
Created March 10, 2021 17:33
Show Gist options
  • Save hillu/fb07ee4b23b7700873d80f71710b4203 to your computer and use it in GitHub Desktop.
Save hillu/fb07ee4b23b7700873d80f71710b4203 to your computer and use it in GitHub Desktop.
/*
dump-pagemap.c - Dump pagemap entries associated with mappings of a given process
Copyright 2021 Hilko Bengen <bengen@hilluzination.de>
License: GPL3 or later
Based on information from:
- linux/Documentation/filesystems/proc.txt
- linux/Documentation/admin-guide/mm/pagemap.rst
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
int main(int argc, char** argv) {
if (argc != 2) {
fprintf(stderr, "usage: %s <pid>\n pid = numeric PID or \"self\"\n", argv[0]);
exit(1);
}
char filebuf[256];
snprintf(filebuf, sizeof(filebuf), "/proc/%s/maps", argv[1]);
FILE* maps = fopen(filebuf, "r");
if (maps == NULL) {
fprintf(stderr, "open: %s: %s\n", filebuf, strerror(errno));
exit(1);
}
snprintf(filebuf, sizeof(filebuf), "/proc/%s/pagemap", argv[1]);
int pagemap = open(filebuf, O_RDONLY);
if (pagemap == -1) {
fprintf(stderr, "open: %s: %s\n", filebuf, strerror(errno));
exit(1);
}
uint64_t pagesize = sysconf(_SC_PAGE_SIZE);
char line[1024];
while (fgets(line, sizeof(line), maps)) {
uint64_t begin, end;
sscanf(line, "%" SCNx64 "-%" SCNx64, &begin, &end);
fputs(line, stdout);
printf("map: %"PRIx64"-%"PRIx64" (%"PRIx64")\n", begin, end, end-begin);
for (uint64_t pos = begin; pos < end; pos = pos + pagesize) {
uint64_t entry;
int sz = pread(pagemap, &entry, sizeof(entry), (pos / pagesize) * sizeof(entry));
if (sz != 8) {
fprintf(stderr, "pread\n");
exit(1);
}
// bit 61: present
// bit 62: file-backed
// bit 63: shared
fputc(".fsx:FSX"[entry >> 61], stdout);
}
fputc('\n', stdout);
}
fclose(maps);
close(pagemap);
}
@hillu
Copy link
Author

hillu commented Mar 11, 2021

Not quite. According to some tests I ran, the bit seems to be set even if the process only read from the page. This makes sense since the read would cause an exception that causes the kernel to map it. When an unmodified page is evicted again due to memory pressure, it can safely be discarded. A modified page would either need to stay in memory or be moved to swap.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment