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