]> git.itanic.dy.fi Git - scan-pagemap/blob - parse.c
pagemaps: Optimize memory usage
[scan-pagemap] / parse.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5
6 #include "parse.h"
7 #include "pagemap.h"
8
9 static struct maps_list *alloc_maplist(void)
10 {
11         struct maps_list *map;
12
13         map = malloc(sizeof *map);
14         if (map == NULL)
15                 goto err;
16
17         memset(map, 0, sizeof(*map));
18         INIT_LIST_HEAD(&map->list);
19 err:
20         return map;
21 }
22
23 static struct maps *alloc_map(void)
24 {
25         struct maps *map;
26
27         map = malloc(sizeof *map);
28         if (map == NULL)
29                 goto err;
30
31         memset(map, 0, sizeof(*map));
32         INIT_LIST_HEAD(&map->list);
33 err:
34         return map;
35 }
36
37 static struct maps *parse_maps(FILE *file, int pid)
38 {
39         struct maps *the_map = NULL;
40         char line[1024];
41         int ret;
42
43         while(fgets(line, sizeof(line), file)) {
44                 struct maps *map = alloc_map();
45                 unsigned long start, end;
46                 char name[1024];
47
48                 if (map == NULL)
49                         return 0;
50
51                 if (the_map == NULL)
52                         the_map = map;
53
54                 ret = sscanf(line, "%lx-%lx %*s %*s %*s %*s %s",
55                              &start, &end, name);
56
57                 printf("%x, start %lx, end %lx, str: %s\n",
58                         ret, start, end, ret >= 3 ? name : "");
59
60                 if (ret < 2) {
61                         printf("Error reading input: %s\n", line);
62                         break;
63                 }
64
65                 map->start = start;
66                 map->end = end;
67                 map->size = end - start;
68                 map->pid = pid;
69
70                 if (ret >= 3)
71                         strncpy(map->name, name, sizeof(map->name));
72
73                 list_add_tail(&map->list, &the_map->list);
74         }
75
76         return the_map;
77 }
78
79 static void clear_pageframe(struct pageframe *pf)
80 {
81         memset(pf, 0, sizeof(*pf));
82 }
83
84 static struct pageframe *alloc_pageframe(void)
85 {
86         struct pageframe *pageframe;
87
88         pageframe = malloc(sizeof *pageframe);
89         if (pageframe == NULL)
90                 goto err;
91
92         clear_pageframe(pageframe);
93 err:
94         return pageframe;
95 }
96
97 #define BITRANGE(first, last) (((2ll << (last - first)) - 1) << first)
98
99 static void pageframe_to_struct(unsigned long long p, struct pageframe *pf)
100 {
101         pf->page_present = !!(BITRANGE(63, 63) & p);
102         pf->page_swapped = !!(BITRANGE(62, 62) & p);
103         pf->page_shift   =   (BITRANGE(55, 60) & p) >> 55;
104         pf->pfn          =   (BITRANGE(0, 54) & p);
105         pf->swap_type    =   (BITRANGE(0, 4) & p);
106         pf->swap_offset  =   (BITRANGE(5, 54) & p) >> 5;
107 #if 0
108         printf("pfn: %lx shift: %d present: %d swapped %d\n",
109                 pf->pfn, pf->page_shift, pf->page_present, pf->page_swapped);
110 #endif
111 }
112
113 static int compare_pageframe(struct bintree *at, struct bintree *bt)
114 {
115         struct pageframe *a, *b;
116         a = tree_to_pageframe(at);
117         b = tree_to_pageframe(bt);
118
119         return a->pfn - b->pfn;
120 }
121
122 struct bintree_ops pageframe_ops = {
123         .compare = compare_pageframe,
124 };
125
126 /* Read data from the /proc/pid/pagemap file */
127 static int parse_pageframe(FILE *file, struct pageframe *pf_tree,
128                         struct maps *maps)
129 {
130         struct maps *map;
131         struct maps_list *tmp;
132         struct pageframe *match, *pageframe;
133         long start, len, i;
134         unsigned long long pf;
135         int ret, error;
136
137         /* Go through the list of allocated memory areas */
138         list_for_each_entry(map, &maps->list, list) {
139                 start = map->start >> (PAGE_SHIFT - 3);
140                 len = map->size >> (PAGE_SHIFT - 3);
141
142                 printf("start: %lx len %lx: name: %s\n",
143                         start, len, map->name);
144
145                 ret = fseek(file, start, SEEK_SET);
146                 if (ret) {
147                         error = errno;
148                         fprintf(stderr, "Error seeking to %lx: %s\n", start,
149                                 strerror(error));
150                         continue;
151                         return -1;
152                 }
153
154                 for (i = 0; i < len; i++) {
155                         ret = fread(&pf, 1, sizeof(pf), file);
156                         if (ret != sizeof(pf)) {
157                                 error = errno;
158                                 fprintf(stderr, 
159                                         "Error reading %ld bytes, got %d: %s\n",
160                                         sizeof(pf), ret, strerror(errno));
161                                 continue;
162                                 return -1;
163                         }
164                         pageframe = alloc_pageframe();
165                         pageframe_to_struct(pf, pageframe);
166                         match = tree_to_pageframe(
167                                 bintree_add(&pf_tree->tree,
168                                         &pageframe->tree, &pageframe_ops));
169
170                         if (match != pageframe)
171                                 free(pageframe);
172                         match->refcount++;
173                         /*
174                          * Add a link from the physical page to this
175                          * process's page map
176                          */
177                         if (!match->ml) {
178                                 match->ml = alloc_maplist();
179                                 match->ml->map = map;
180                         } else {
181                                 tmp = alloc_maplist();
182                                 tmp->map = map;
183                                 list_add(&match->ml->list, &tmp->list);
184                         }
185                 }
186         }
187
188         return 0;
189 }
190
191 void read_pageframe(int pid, struct pageframe *pageframe)
192 {
193         struct maps *maps;
194         FILE *file;
195         int error;
196         char path[512];
197
198         snprintf(path, sizeof(path), "/proc/%d/maps", pid);
199         file = fopen(path, "rb");
200
201         if (!file)
202                 goto err_out;
203
204         maps = parse_maps(file, pid);
205
206         snprintf(path, sizeof(path), "/proc/%d/pagemap", pid);
207         file = fopen(path, "rb");
208
209         if (!file)
210                 goto err_out;
211
212         parse_pageframe(file, pageframe, maps);
213
214         return;
215 err_out:
216         error = errno;
217         fprintf(stderr, "Failed to open file %s: %s\n", path, strerror(error));
218
219         return;
220 }