#include #include #include #include #include #include #include "parse.h" #include "pagemap.h" static struct maps_list *alloc_maplist(void) { struct maps_list *map; map = malloc(sizeof *map); if (map == NULL) goto err; memset(map, 0, sizeof(*map)); INIT_LIST_HEAD(&map->list); err: return map; } static struct maps *alloc_map(void) { struct maps *map; map = malloc(sizeof *map); if (map == NULL) goto err; memset(map, 0, sizeof(*map)); INIT_LIST_HEAD(&map->list); err: return map; } static struct maps *parse_maps(FILE *file, int pid) { struct maps *the_map = NULL; char line[1024]; int ret; while(fgets(line, sizeof(line), file)) { struct maps *map = alloc_map(); unsigned long start, end; char name[1024]; if (map == NULL) return 0; if (the_map == NULL) the_map = map; ret = sscanf(line, "%lx-%lx %*s %*s %*s %*s %s", &start, &end, name); printf("%x, start %lx, end %lx, str: %s\n", ret, start, end, ret >= 3 ? name : ""); if (ret < 2) { printf("Error reading input: %s\n", line); break; } map->start = start; map->end = end; map->size = end - start; map->pid = pid; if (ret >= 3) strncpy(map->name, name, sizeof(map->name)); list_add_tail(&map->list, &the_map->list); } return the_map; } static void clear_pageframe(struct pageframe *pf) { memset(pf, 0, sizeof(*pf)); } static struct pageframe *alloc_pageframe(void) { struct pageframe *pageframe; pageframe = malloc(sizeof *pageframe); if (pageframe == NULL) goto err; clear_pageframe(pageframe); err: return pageframe; } #define BITRANGE(first, last) (((2ll << (last - first)) - 1) << first) static void pageframe_to_struct(unsigned long long p, struct pageframe *pf) { pf->page_present = !!(BITRANGE(63, 63) & p); pf->page_swapped = !!(BITRANGE(62, 62) & p); pf->page_shift = (BITRANGE(55, 60) & p) >> 55; pf->pfn = (BITRANGE(0, 54) & p); pf->swap_type = (BITRANGE(0, 4) & p); pf->swap_offset = (BITRANGE(5, 54) & p) >> 5; #if 0 printf("pfn: %lx shift: %d present: %d swapped %d\n", pf->pfn, pf->page_shift, pf->page_present, pf->page_swapped); #endif } static int compare_pageframe(struct bintree *at, struct bintree *bt) { struct pageframe *a, *b; a = tree_to_pageframe(at); b = tree_to_pageframe(bt); return a->pfn - b->pfn; } struct bintree_ops pageframe_ops = { .compare = compare_pageframe, }; /* Read data from the /proc/pid/pagemap file */ static int parse_pageframe(FILE *file, struct pageframe *pf_tree, struct maps *maps, int add_to_tree) { struct maps *map; struct maps_list *tmp; struct pageframe *match, *pageframe = NULL; long start, len, i; unsigned long long pf; int ret, error; /* Go through the list of allocated memory areas */ list_for_each_entry(map, &maps->list, list) { start = map->start >> (PAGE_SHIFT - 3); len = map->size >> (PAGE_SHIFT - 3); printf("start: %lx len %lx: name: %s\n", start, len, map->name); ret = fseek(file, start, SEEK_SET); if (ret) { error = errno; fprintf(stderr, "Error seeking to %lx: %s\n", start, strerror(error)); continue; return -1; } for (i = 0; i < len; i++) { ret = fread(&pf, 1, sizeof(pf), file); if (ret != sizeof(pf)) { error = errno; fprintf(stderr, "Error reading %ld bytes, got %d: %s\n", sizeof(pf), ret, strerror(errno)); continue; return -1; } if (!pageframe) pageframe = alloc_pageframe(); pageframe_to_struct(pf, pageframe); if (add_to_tree) { match = tree_to_pageframe( bintree_add(&pf_tree->tree, &pageframe->tree, &pageframe_ops)); } else { match = tree_to_pageframe( bintree_find(&pf_tree->tree, &pageframe->tree, &pageframe_ops)); } if (match == NULL) continue; if (match == pageframe) pageframe = NULL; match->refcount++; /* * Add a link from the physical page to this * process's page map */ if (!match->ml) { match->ml = alloc_maplist(); match->ml->map = map; } else { tmp = alloc_maplist(); tmp->map = map; list_add(&match->ml->list, &tmp->list); } } } return 0; } void read_pageframe(int pid, struct pageframe *pageframe, int add_to_tree) { struct maps *maps; FILE *file; int error; char path[512]; snprintf(path, sizeof(path), "/proc/%d/maps", pid); file = fopen(path, "rb"); if (!file) goto err_out; maps = parse_maps(file, pid); snprintf(path, sizeof(path), "/proc/%d/pagemap", pid); file = fopen(path, "rb"); if (!file) goto err_out; parse_pageframe(file, pageframe, maps, add_to_tree); return; err_out: error = errno; fprintf(stderr, "Failed to open file %s: %s\n", path, strerror(error)); return; } static int get_next_pid(void) { static DIR *dir = NULL; struct dirent *dirent; int error; if (!dir) { dir = opendir("/proc"); if (!dir) { error = errno; printf("Failed to open /proc directory: %s\n", strerror(error)); return -1; } } restart: dirent = readdir(dir); if (!dirent) { if (errno == 0) { closedir(dir); dir = NULL; return 0; } error = errno; printf("Failed to read directory: %s\n", strerror(error)); return -1; } printf("%s\n", dirent->d_name); if (dirent->d_name[0] < '0' || dirent->d_name[0] > '9') goto restart; return atoi(dirent->d_name); } void scan_all_pids(struct pageframe *pf, int interesting_pid) { int pid; read_pageframe(interesting_pid, pf, 1); while(1) { pid = get_next_pid(); if (pid <= 0) break; read_pageframe(pid, pf, 0); } }