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