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