diff options
Diffstat (limited to 'elfutils/libdwfl/linux-kernel-modules.c')
-rw-r--r-- | elfutils/libdwfl/linux-kernel-modules.c | 59 |
1 files changed, 49 insertions, 10 deletions
diff --git a/elfutils/libdwfl/linux-kernel-modules.c b/elfutils/libdwfl/linux-kernel-modules.c index 5bbb384a..e07073cd 100644 --- a/elfutils/libdwfl/linux-kernel-modules.c +++ b/elfutils/libdwfl/linux-kernel-modules.c @@ -1,5 +1,5 @@ /* Standard libdwfl callbacks for debugging the running Linux kernel. - Copyright (C) 2005, 2006, 2007, 2008 Red Hat, Inc. + Copyright (C) 2005-2009 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -254,6 +254,29 @@ report_kernel_archive (Dwfl *dwfl, const char **release, return result; } +static size_t +check_suffix (const FTSENT *f, size_t namelen) +{ +#define TRY(sfx) \ + if ((namelen ? f->fts_namelen == namelen + sizeof sfx - 1 \ + : f->fts_namelen >= sizeof sfx) \ + && !memcmp (f->fts_name + f->fts_namelen - (sizeof sfx - 1), \ + sfx, sizeof sfx)) \ + return sizeof sfx - 1 + + TRY (".ko"); +#if USE_ZLIB + TRY (".ko.gz"); +#endif +#if USE_BZLIB + TRY (".ko.bz2"); +#endif + + return 0; + +#undef TRY +} + /* Report a kernel and all its modules found on disk, for offline use. If RELEASE starts with '/', it names a directory to look in; if not, it names a directory to find under /lib/modules/; @@ -296,14 +319,23 @@ dwfl_linux_kernel_report_offline (Dwfl *dwfl, const char *release, FTSENT *f; while ((f = fts_read (fts)) != NULL) { + /* Skip a "source" subtree, which tends to be large. + This insane hard-coding of names is what depmod does too. */ + if (f->fts_namelen == sizeof "source" - 1 + && !strcmp (f->fts_name, "source")) + { + fts_set (fts, f, FTS_SKIP); + continue; + } + switch (f->fts_info) { case FTS_F: case FTS_SL: - case FTS_NSOK: + case FTS_NSOK:; /* See if this file name matches "*.ko". */ - if (f->fts_namelen > 3 - && !memcmp (f->fts_name + f->fts_namelen - 3, ".ko", 4)) + const size_t suffix = check_suffix (f, 0); + if (suffix) { /* We have a .ko file to report. Following the algorithm by which the kernel makefiles set KBUILD_MODNAME, we @@ -313,13 +345,13 @@ dwfl_linux_kernel_report_offline (Dwfl *dwfl, const char *release, names. To handle that, we would have to look at the __this_module.name contents in the module's text. */ - char name[f->fts_namelen - 3 + 1]; + char name[f->fts_namelen - suffix + 1]; for (size_t i = 0; i < f->fts_namelen - 3U; ++i) if (f->fts_name[i] == '-' || f->fts_name[i] == ',') name[i] = '_'; else name[i] = f->fts_name[i]; - name[f->fts_namelen - 3] = '\0'; + name[f->fts_namelen - suffix] = '\0'; if (predicate != NULL) { @@ -334,8 +366,7 @@ dwfl_linux_kernel_report_offline (Dwfl *dwfl, const char *release, continue; } - if (dwfl_report_offline (dwfl, name, - f->fts_path, -1) == NULL) + if (dwfl_report_offline (dwfl, name, f->fts_path, -1) == NULL) { result = -1; break; @@ -660,6 +691,15 @@ dwfl_linux_kernel_find_elf (Dwfl_Module *mod, int error = ENOENT; while ((f = fts_read (fts)) != NULL) { + /* Skip a "source" subtree, which tends to be large. + This insane hard-coding of names is what depmod does too. */ + if (f->fts_namelen == sizeof "source" - 1 + && !strcmp (f->fts_name, "source")) + { + fts_set (fts, f, FTS_SKIP); + continue; + } + error = ENOENT; switch (f->fts_info) { @@ -667,8 +707,7 @@ dwfl_linux_kernel_find_elf (Dwfl_Module *mod, case FTS_SL: case FTS_NSOK: /* See if this file name is "MODULE_NAME.ko". */ - if (f->fts_namelen == namelen + 3 - && !memcmp (f->fts_name + namelen, ".ko", 4) + if (check_suffix (f, namelen) && (!memcmp (f->fts_name, module_name, namelen) || !memcmp (f->fts_name, alternate_name, namelen))) { |