Merge branch 'timers-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / tools / perf / util / module.c
1 #include "util.h"
2 #include "../perf.h"
3 #include "string.h"
4 #include "module.h"
5
6 #include <libelf.h>
7 #include <gelf.h>
8 #include <elf.h>
9 #include <dirent.h>
10 #include <sys/utsname.h>
11
12 static unsigned int crc32(const char *p, unsigned int len)
13 {
14         int i;
15         unsigned int crc = 0;
16
17         while (len--) {
18                 crc ^= *p++;
19                 for (i = 0; i < 8; i++)
20                         crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
21         }
22         return crc;
23 }
24
25 /* module section methods */
26
27 struct sec_dso *sec_dso__new_dso(const char *name)
28 {
29         struct sec_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
30
31         if (self != NULL) {
32                 strcpy(self->name, name);
33                 self->secs = RB_ROOT;
34                 self->find_section = sec_dso__find_section;
35         }
36
37         return self;
38 }
39
40 static void sec_dso__delete_section(struct section *self)
41 {
42         free(((void *)self));
43 }
44
45 void sec_dso__delete_sections(struct sec_dso *self)
46 {
47         struct section *pos;
48         struct rb_node *next = rb_first(&self->secs);
49
50         while (next) {
51                 pos = rb_entry(next, struct section, rb_node);
52                 next = rb_next(&pos->rb_node);
53                 rb_erase(&pos->rb_node, &self->secs);
54                 sec_dso__delete_section(pos);
55         }
56 }
57
58 void sec_dso__delete_self(struct sec_dso *self)
59 {
60         sec_dso__delete_sections(self);
61         free(self);
62 }
63
64 static void sec_dso__insert_section(struct sec_dso *self, struct section *sec)
65 {
66         struct rb_node **p = &self->secs.rb_node;
67         struct rb_node *parent = NULL;
68         const u64 hash = sec->hash;
69         struct section *s;
70
71         while (*p != NULL) {
72                 parent = *p;
73                 s = rb_entry(parent, struct section, rb_node);
74                 if (hash < s->hash)
75                         p = &(*p)->rb_left;
76                 else
77                         p = &(*p)->rb_right;
78         }
79         rb_link_node(&sec->rb_node, parent, p);
80         rb_insert_color(&sec->rb_node, &self->secs);
81 }
82
83 struct section *sec_dso__find_section(struct sec_dso *self, const char *name)
84 {
85         struct rb_node *n;
86         u64 hash;
87         int len;
88
89         if (self == NULL)
90                 return NULL;
91
92         len = strlen(name);
93         hash = crc32(name, len);
94
95         n = self->secs.rb_node;
96
97         while (n) {
98                 struct section *s = rb_entry(n, struct section, rb_node);
99
100                 if (hash < s->hash)
101                         n = n->rb_left;
102                 else if (hash > s->hash)
103                         n = n->rb_right;
104                 else {
105                         if (!strcmp(name, s->name))
106                                 return s;
107                         else
108                                 n = rb_next(&s->rb_node);
109                 }
110         }
111
112         return NULL;
113 }
114
115 static size_t sec_dso__fprintf_section(struct section *self, FILE *fp)
116 {
117         return fprintf(fp, "name:%s vma:%llx path:%s\n",
118                        self->name, self->vma, self->path);
119 }
120
121 size_t sec_dso__fprintf(struct sec_dso *self, FILE *fp)
122 {
123         size_t ret = fprintf(fp, "dso: %s\n", self->name);
124
125         struct rb_node *nd;
126         for (nd = rb_first(&self->secs); nd; nd = rb_next(nd)) {
127                 struct section *pos = rb_entry(nd, struct section, rb_node);
128                 ret += sec_dso__fprintf_section(pos, fp);
129         }
130
131         return ret;
132 }
133
134 static struct section *section__new(const char *name, const char *path)
135 {
136         struct section *self = calloc(1, sizeof(*self));
137
138         if (!self)
139                 goto out_failure;
140
141         self->name = calloc(1, strlen(name) + 1);
142         if (!self->name)
143                 goto out_failure;
144
145         self->path = calloc(1, strlen(path) + 1);
146         if (!self->path)
147                 goto out_failure;
148
149         strcpy(self->name, name);
150         strcpy(self->path, path);
151         self->hash = crc32(self->name, strlen(name));
152
153         return self;
154
155 out_failure:
156         if (self) {
157                 if (self->name)
158                         free(self->name);
159                 if (self->path)
160                         free(self->path);
161                 free(self);
162         }
163
164         return NULL;
165 }
166
167 /* module methods */
168
169 struct mod_dso *mod_dso__new_dso(const char *name)
170 {
171         struct mod_dso *self = malloc(sizeof(*self) + strlen(name) + 1);
172
173         if (self != NULL) {
174                 strcpy(self->name, name);
175                 self->mods = RB_ROOT;
176                 self->find_module = mod_dso__find_module;
177         }
178
179         return self;
180 }
181
182 static void mod_dso__delete_module(struct module *self)
183 {
184         free(((void *)self));
185 }
186
187 void mod_dso__delete_modules(struct mod_dso *self)
188 {
189         struct module *pos;
190         struct rb_node *next = rb_first(&self->mods);
191
192         while (next) {
193                 pos = rb_entry(next, struct module, rb_node);
194                 next = rb_next(&pos->rb_node);
195                 rb_erase(&pos->rb_node, &self->mods);
196                 mod_dso__delete_module(pos);
197         }
198 }
199
200 void mod_dso__delete_self(struct mod_dso *self)
201 {
202         mod_dso__delete_modules(self);
203         free(self);
204 }
205
206 static void mod_dso__insert_module(struct mod_dso *self, struct module *mod)
207 {
208         struct rb_node **p = &self->mods.rb_node;
209         struct rb_node *parent = NULL;
210         const u64 hash = mod->hash;
211         struct module *m;
212
213         while (*p != NULL) {
214                 parent = *p;
215                 m = rb_entry(parent, struct module, rb_node);
216                 if (hash < m->hash)
217                         p = &(*p)->rb_left;
218                 else
219                         p = &(*p)->rb_right;
220         }
221         rb_link_node(&mod->rb_node, parent, p);
222         rb_insert_color(&mod->rb_node, &self->mods);
223 }
224
225 struct module *mod_dso__find_module(struct mod_dso *self, const char *name)
226 {
227         struct rb_node *n;
228         u64 hash;
229         int len;
230
231         if (self == NULL)
232                 return NULL;
233
234         len = strlen(name);
235         hash = crc32(name, len);
236
237         n = self->mods.rb_node;
238
239         while (n) {
240                 struct module *m = rb_entry(n, struct module, rb_node);
241
242                 if (hash < m->hash)
243                         n = n->rb_left;
244                 else if (hash > m->hash)
245                         n = n->rb_right;
246                 else {
247                         if (!strcmp(name, m->name))
248                                 return m;
249                         else
250                                 n = rb_next(&m->rb_node);
251                 }
252         }
253
254         return NULL;
255 }
256
257 static size_t mod_dso__fprintf_module(struct module *self, FILE *fp)
258 {
259         return fprintf(fp, "name:%s path:%s\n", self->name, self->path);
260 }
261
262 size_t mod_dso__fprintf(struct mod_dso *self, FILE *fp)
263 {
264         struct rb_node *nd;
265         size_t ret;
266
267         ret = fprintf(fp, "dso: %s\n", self->name);
268
269         for (nd = rb_first(&self->mods); nd; nd = rb_next(nd)) {
270                 struct module *pos = rb_entry(nd, struct module, rb_node);
271
272                 ret += mod_dso__fprintf_module(pos, fp);
273         }
274
275         return ret;
276 }
277
278 static struct module *module__new(const char *name, const char *path)
279 {
280         struct module *self = calloc(1, sizeof(*self));
281
282         if (!self)
283                 goto out_failure;
284
285         self->name = calloc(1, strlen(name) + 1);
286         if (!self->name)
287                 goto out_failure;
288
289         self->path = calloc(1, strlen(path) + 1);
290         if (!self->path)
291                 goto out_failure;
292
293         strcpy(self->name, name);
294         strcpy(self->path, path);
295         self->hash = crc32(self->name, strlen(name));
296
297         return self;
298
299 out_failure:
300         if (self) {
301                 if (self->name)
302                         free(self->name);
303                 if (self->path)
304                         free(self->path);
305                 free(self);
306         }
307
308         return NULL;
309 }
310
311 static int mod_dso__load_sections(struct module *mod)
312 {
313         int count = 0, path_len;
314         struct dirent *entry;
315         char *line = NULL;
316         char *dir_path;
317         DIR *dir;
318         size_t n;
319
320         path_len = strlen("/sys/module/");
321         path_len += strlen(mod->name);
322         path_len += strlen("/sections/");
323
324         dir_path = calloc(1, path_len + 1);
325         if (dir_path == NULL)
326                 goto out_failure;
327
328         strcat(dir_path, "/sys/module/");
329         strcat(dir_path, mod->name);
330         strcat(dir_path, "/sections/");
331
332         dir = opendir(dir_path);
333         if (dir == NULL)
334                 goto out_free;
335
336         while ((entry = readdir(dir))) {
337                 struct section *section;
338                 char *path, *vma;
339                 int line_len;
340                 FILE *file;
341
342                 if (!strcmp(".", entry->d_name) || !strcmp("..", entry->d_name))
343                         continue;
344
345                 path = calloc(1, path_len + strlen(entry->d_name) + 1);
346                 if (path == NULL)
347                         break;
348                 strcat(path, dir_path);
349                 strcat(path, entry->d_name);
350
351                 file = fopen(path, "r");
352                 if (file == NULL) {
353                         free(path);
354                         break;
355                 }
356
357                 line_len = getline(&line, &n, file);
358                 if (line_len < 0) {
359                         free(path);
360                         fclose(file);
361                         break;
362                 }
363
364                 if (!line) {
365                         free(path);
366                         fclose(file);
367                         break;
368                 }
369
370                 line[--line_len] = '\0'; /* \n */
371
372                 vma = strstr(line, "0x");
373                 if (!vma) {
374                         free(path);
375                         fclose(file);
376                         break;
377                 }
378                 vma += 2;
379
380                 section = section__new(entry->d_name, path);
381                 if (!section) {
382                         fprintf(stderr, "load_sections: allocation error\n");
383                         free(path);
384                         fclose(file);
385                         break;
386                 }
387
388                 hex2u64(vma, &section->vma);
389                 sec_dso__insert_section(mod->sections, section);
390
391                 free(path);
392                 fclose(file);
393                 count++;
394         }
395
396         closedir(dir);
397         free(line);
398         free(dir_path);
399
400         return count;
401
402 out_free:
403         free(dir_path);
404
405 out_failure:
406         return count;
407 }
408
409 static int mod_dso__load_module_paths(struct mod_dso *self)
410 {
411         struct utsname uts;
412         int count = 0, len;
413         char *line = NULL;
414         FILE *file;
415         char *path;
416         size_t n;
417
418         if (uname(&uts) < 0)
419                 goto out_failure;
420
421         len = strlen("/lib/modules/");
422         len += strlen(uts.release);
423         len += strlen("/modules.dep");
424
425         path = calloc(1, len);
426         if (path == NULL)
427                 goto out_failure;
428
429         strcat(path, "/lib/modules/");
430         strcat(path, uts.release);
431         strcat(path, "/modules.dep");
432
433         file = fopen(path, "r");
434         free(path);
435         if (file == NULL)
436                 goto out_failure;
437
438         while (!feof(file)) {
439                 char *name, *tmp;
440                 struct module *module;
441                 int line_len;
442
443                 line_len = getline(&line, &n, file);
444                 if (line_len < 0)
445                         break;
446
447                 if (!line)
448                         goto out_failure;
449
450                 line[--line_len] = '\0'; /* \n */
451
452                 path = strtok(line, ":");
453                 if (!path)
454                         goto out_failure;
455
456                 name = strdup(path);
457                 name = strtok(name, "/");
458
459                 tmp = name;
460
461                 while (tmp) {
462                         tmp = strtok(NULL, "/");
463                         if (tmp)
464                                 name = tmp;
465                 }
466                 name = strsep(&name, ".");
467
468                 /* Quirk: replace '-' with '_' in sound modules */
469                 for (len = strlen(name); len; len--) {
470                         if (*(name+len) == '-')
471                                 *(name+len) = '_';
472                 }
473
474                 module = module__new(name, path);
475                 if (!module) {
476                         fprintf(stderr, "load_module_paths: allocation error\n");
477                         goto out_failure;
478                 }
479                 mod_dso__insert_module(self, module);
480
481                 module->sections = sec_dso__new_dso("sections");
482                 if (!module->sections) {
483                         fprintf(stderr, "load_module_paths: allocation error\n");
484                         goto out_failure;
485                 }
486
487                 module->active = mod_dso__load_sections(module);
488
489                 if (module->active > 0)
490                         count++;
491         }
492
493         free(line);
494         fclose(file);
495
496         return count;
497
498 out_failure:
499         return -1;
500 }
501
502 int mod_dso__load_modules(struct mod_dso *dso)
503 {
504         int err;
505
506         err = mod_dso__load_module_paths(dso);
507
508         return err;
509 }