linux/tools/perf/util/module.c
<<
>>
Prefs
   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
  13static 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
  28struct 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
  41static void sec_dso__delete_section(struct section *self)
  42{
  43        free(((void *)self));
  44}
  45
  46void 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
  59void sec_dso__delete_self(struct sec_dso *self)
  60{
  61        sec_dso__delete_sections(self);
  62        free(self);
  63}
  64
  65static 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
  84struct 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
 116static 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
 122size_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
 135static 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
 156out_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
 170struct 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
 183static void mod_dso__delete_module(struct module *self)
 184{
 185        free(((void *)self));
 186}
 187
 188void 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
 201void mod_dso__delete_self(struct mod_dso *self)
 202{
 203        mod_dso__delete_modules(self);
 204        free(self);
 205}
 206
 207static 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
 226struct 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
 258static 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
 263size_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
 279static 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
 300out_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
 312static 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
 403out_free:
 404        free(dir_path);
 405
 406out_failure:
 407        return count;
 408}
 409
 410static 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
 527out_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
 538int 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}
 546