]> git.itanic.dy.fi Git - scan-pagemap/blob - parse.c
parser: Store the per mapping statistics in the maps structure
[scan-pagemap] / parse.c
1 #include <sys/types.h>
2 #include <dirent.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <errno.h>
7
8 #include "parse.h"
9 #include "pagemap.h"
10
11 static struct maps_list *alloc_maplist(void)
12 {
13         struct maps_list *map;
14
15         map = malloc(sizeof *map);
16         if (map == NULL)
17                 goto err;
18
19         memset(map, 0, sizeof(*map));
20         INIT_LIST_HEAD(&map->list);
21 err:
22         return map;
23 }
24
25 static struct maps *alloc_map(void)
26 {
27         struct maps *map;
28
29         map = malloc(sizeof *map);
30         if (map == NULL)
31                 goto err;
32
33         memset(map, 0, sizeof(*map));
34         INIT_LIST_HEAD(&map->list);
35 err:
36         return map;
37 }
38
39 static struct maps *parse_maps(FILE *file, int pid)
40 {
41         struct maps *the_map = NULL;
42         char line[1024];
43         int ret;
44
45         while(fgets(line, sizeof(line), file)) {
46                 struct maps *map = alloc_map();
47                 unsigned long start, end;
48                 char name[1024];
49
50                 if (map == NULL)
51                         return 0;
52
53                 if (the_map == NULL)
54                         the_map = map;
55
56                 ret = sscanf(line, "%lx-%lx %*s %*s %*s %*s %s",
57                              &start, &end, name);
58
59                 if (ret < 2) {
60                         printf("Error reading input: %s\n", line);
61                         break;
62                 }
63
64                 map->start = start;
65                 map->end = end;
66                 map->size = end - start;
67                 map->pid = pid;
68
69                 if (ret >= 3)
70                         strncpy(map->name, name, sizeof(map->name));
71
72                 list_add_tail(&map->list, &the_map->list);
73         }
74
75         return the_map;
76 }
77
78 static void clear_pageframe(struct pageframe *pf)
79 {
80         memset(pf, 0, sizeof(*pf));
81 }
82
83 static struct pageframe *alloc_pageframe(void)
84 {
85         struct pageframe *pageframe;
86
87         pageframe = malloc(sizeof *pageframe);
88         if (pageframe == NULL)
89                 goto err;
90
91         clear_pageframe(pageframe);
92 err:
93         return pageframe;
94 }
95
96 #define BITRANGE(first, last) (((2ll << (last - first)) - 1) << first)
97
98 static void pageframe_to_struct(unsigned long long p, struct pageframe *pf)
99 {
100         pf->page_present = !!(BITRANGE(63, 63) & p);
101         pf->page_swapped = !!(BITRANGE(62, 62) & p);
102         pf->page_shift   =   (BITRANGE(55, 60) & p) >> 55;
103         pf->pfn          =   (BITRANGE(0, 54) & p);
104         pf->swap_type    =   (BITRANGE(0, 4) & p);
105         pf->swap_offset  =   (BITRANGE(5, 54) & p) >> 5;
106 #if 0
107         printf("pfn: %lx shift: %d present: %d swapped %d\n",
108                 pf->pfn, pf->page_shift, pf->page_present, pf->page_swapped);
109 #endif
110 }
111
112 static int compare_pageframe(struct bintree *at, struct bintree *bt)
113 {
114         struct pageframe *a, *b;
115         a = tree_to_pageframe(at);
116         b = tree_to_pageframe(bt);
117
118         return a->pfn - b->pfn;
119 }
120
121 struct bintree_ops pageframe_ops = {
122         .compare = compare_pageframe,
123 };
124
125 /* Read data from the /proc/pid/pagemap file */
126 static int parse_pageframe(FILE *file, struct pageframe *pf_tree,
127                         struct maps *maps, int add_to_tree)
128 {
129         struct maps *map;
130         struct maps_list *tmp;
131         struct pageframe *match, *pageframe = NULL;
132         long start, len, i;
133         unsigned long long pf;
134         int ret, error;
135
136         /* Go through the list of allocated memory areas */
137         list_for_each_entry(map, &maps->list, list) {
138                 start = map->start >> (PAGE_SHIFT - 3);
139                 len = map->size >> (PAGE_SHIFT - 3);
140
141                 ret = fseek(file, start, SEEK_SET);
142                 if (ret) {
143                         error = errno;
144                         fprintf(stderr, "Error seeking to %lx: %s\n", start,
145                                 strerror(error));
146                         continue;
147                 }
148
149                 for (i = 0; i < len; i++) {
150                         ret = fread(&pf, 1, sizeof(pf), file);
151                         if (ret != sizeof(pf)) {
152                                 error = errno;
153                                 continue;
154                         }
155                         if (!pageframe)
156                                 pageframe = alloc_pageframe();
157
158                         pageframe_to_struct(pf, pageframe);
159
160                         if (add_to_tree) {
161                                 match = tree_to_pageframe(
162                                         bintree_add(&pf_tree->tree,
163                                                 &pageframe->tree,
164                                                 &pageframe_ops));
165                         } else {
166                                 match = tree_to_pageframe(
167                                         bintree_find(&pf_tree->tree,
168                                                 &pageframe->tree,
169                                                 &pageframe_ops));
170                         }
171
172                         if (match == NULL)
173                                 continue;
174
175                         if (match == pageframe)
176                                 pageframe = NULL;
177
178                         match->refcount++;
179                         /*
180                          * Add a link from the physical page to this
181                          * process's page map
182                          */
183                         if (!match->ml) {
184                                 match->ml = alloc_maplist();
185                                 match->ml->map = map;
186                         } else {
187                                 tmp = alloc_maplist();
188                                 tmp->map = map;
189                                 list_add(&match->ml->list, &tmp->list);
190                         }
191
192                         if (match->page_present) {
193                                 map->pages_present++;
194                         } else if (match->page_swapped) {
195                                 map->pages_swapped++;
196                         }
197                 }
198         }
199
200         return 0;
201 }
202
203 void read_pageframe(int pid, struct pageframe *pageframe, int add_to_tree)
204 {
205         struct maps *maps;
206         FILE *file;
207         char path[512];
208
209         snprintf(path, sizeof(path), "/proc/%d/maps", pid);
210         file = fopen(path, "rb");
211
212         if (!file)
213                 return;
214
215         maps = parse_maps(file, pid);
216         fclose(file);
217
218         snprintf(path, sizeof(path), "/proc/%d/pagemap", pid);
219         file = fopen(path, "rb");
220
221         if (!file)
222                 return;
223
224         parse_pageframe(file, pageframe, maps, add_to_tree);
225         fclose(file);
226
227         return;
228 }
229
230 static int get_next_pid(void)
231 {
232         static DIR *dir = NULL;
233         struct dirent *dirent;
234         int error;
235
236         if (!dir) {
237                 dir = opendir("/proc");
238                 if (!dir) {
239                         error = errno;
240                         printf("Failed to open /proc directory: %s\n",
241                                 strerror(error));
242                         return -1;
243                 }
244         }
245
246 restart:
247         dirent = readdir(dir);
248         if (!dirent) {
249                 if (errno == 0) {
250                         closedir(dir);
251                         dir = NULL;
252                         return 0;
253                 }
254                 error = errno;
255                 printf("Failed to read /proc directory: %s\n", strerror(error));
256                 return -1;
257         }
258
259         printf("%s\n", dirent->d_name);
260         if (dirent->d_name[0] < '0' || dirent->d_name[0] > '9')
261                 goto restart;
262
263         return atoi(dirent->d_name);
264 }
265
266 void scan_all_pids(struct pageframe *pf, int interesting_pid)
267 {
268         int pid;
269
270         read_pageframe(interesting_pid, pf, 1);
271
272         while(1) {
273                 pid = get_next_pid();
274                 if (pid <= 0)
275                         break;
276                 read_pageframe(pid, pf, 0);
277         }
278 }