perf symbols: Preparation for compressed kernel module support
authorNamhyung Kim <namhyung@kernel.org>
Tue, 4 Nov 2014 01:14:27 +0000 (10:14 +0900)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Tue, 4 Nov 2014 13:15:53 +0000 (10:15 -0300)
This patch adds basic support to handle compressed kernel module as some
distro (such as Archlinux) carries on it now.  The actual work using
compression library will be added later.

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung.kim@lge.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1415063674-17206-2-git-send-email-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/dso.c
tools/perf/util/dso.h
tools/perf/util/machine.c
tools/perf/util/symbol-elf.c
tools/perf/util/symbol.c

index 0247acfdfaca807a1378631f19d6d38ddef67cf3..36a607cf8f508ad03f5868472283428cb11b839a 100644 (file)
@@ -21,8 +21,10 @@ char dso__symtab_origin(const struct dso *dso)
                [DSO_BINARY_TYPE__BUILDID_DEBUGINFO]            = 'b',
                [DSO_BINARY_TYPE__SYSTEM_PATH_DSO]              = 'd',
                [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE]          = 'K',
+               [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP]     = 'm',
                [DSO_BINARY_TYPE__GUEST_KALLSYMS]               = 'g',
                [DSO_BINARY_TYPE__GUEST_KMODULE]                = 'G',
+               [DSO_BINARY_TYPE__GUEST_KMODULE_COMP]           = 'M',
                [DSO_BINARY_TYPE__GUEST_VMLINUX]                = 'V',
        };
 
@@ -112,11 +114,13 @@ int dso__read_binary_type_filename(const struct dso *dso,
                break;
 
        case DSO_BINARY_TYPE__GUEST_KMODULE:
+       case DSO_BINARY_TYPE__GUEST_KMODULE_COMP:
                path__join3(filename, size, symbol_conf.symfs,
                            root_dir, dso->long_name);
                break;
 
        case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
+       case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP:
                __symbol__join_symfs(filename, size, dso->long_name);
                break;
 
@@ -137,6 +141,77 @@ int dso__read_binary_type_filename(const struct dso *dso,
        return ret;
 }
 
+static int decompress_dummy(const char *input __maybe_unused,
+                           int output __maybe_unused)
+{
+       return -1;
+}
+
+static const struct {
+       const char *fmt;
+       int (*decompress)(const char *input, int output);
+} compressions[] = {
+       { "gz", decompress_dummy },
+       { NULL, },
+};
+
+bool is_supported_compression(const char *ext)
+{
+       unsigned i;
+
+       for (i = 0; compressions[i].fmt; i++) {
+               if (!strcmp(ext, compressions[i].fmt))
+                       return true;
+       }
+       return false;
+}
+
+bool is_kmodule_extension(const char *ext)
+{
+       if (strncmp(ext, "ko", 2))
+               return false;
+
+       if (ext[2] == '\0' || (ext[2] == '.' && is_supported_compression(ext+3)))
+               return true;
+
+       return false;
+}
+
+bool is_kernel_module(const char *pathname, bool *compressed)
+{
+       const char *ext = strrchr(pathname, '.');
+
+       if (ext == NULL)
+               return false;
+
+       if (is_supported_compression(ext + 1)) {
+               if (compressed)
+                       *compressed = true;
+               ext -= 3;
+       } else if (compressed)
+               *compressed = false;
+
+       return is_kmodule_extension(ext + 1);
+}
+
+bool decompress_to_file(const char *ext, const char *filename, int output_fd)
+{
+       unsigned i;
+
+       for (i = 0; compressions[i].fmt; i++) {
+               if (!strcmp(ext, compressions[i].fmt))
+                       return !compressions[i].decompress(filename,
+                                                          output_fd);
+       }
+       return false;
+}
+
+bool dso__needs_decompress(struct dso *dso)
+{
+       return dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
+               dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
+}
+
 /*
  * Global list of open DSOs and the counter.
  */
index a316e4af321f0684a7cdde176d9b60009ba9412e..3782c82c6e44b579895dc0b48f034f856706c8d4 100644 (file)
@@ -22,7 +22,9 @@ enum dso_binary_type {
        DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
        DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
        DSO_BINARY_TYPE__GUEST_KMODULE,
+       DSO_BINARY_TYPE__GUEST_KMODULE_COMP,
        DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
+       DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP,
        DSO_BINARY_TYPE__KCORE,
        DSO_BINARY_TYPE__GUEST_KCORE,
        DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
@@ -185,6 +187,11 @@ int dso__kernel_module_get_build_id(struct dso *dso, const char *root_dir);
 char dso__symtab_origin(const struct dso *dso);
 int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type,
                                   char *root_dir, char *filename, size_t size);
+bool is_supported_compression(const char *ext);
+bool is_kmodule_extension(const char *ext);
+bool is_kernel_module(const char *pathname, bool *compressed);
+bool decompress_to_file(const char *ext, const char *filename, int output_fd);
+bool dso__needs_decompress(struct dso *dso);
 
 /*
  * The dso__data_* external interface provides following functions:
index 51a630301afa17f2c28ac118fe00d7da866067be..946c7d62cb6ed1e8b71193f817ca9b70b1f53037 100644 (file)
@@ -464,6 +464,7 @@ struct map *machine__new_module(struct machine *machine, u64 start,
 {
        struct map *map;
        struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename);
+       bool compressed;
 
        if (dso == NULL)
                return NULL;
@@ -476,6 +477,11 @@ struct map *machine__new_module(struct machine *machine, u64 start,
                dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
        else
                dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
+
+       /* _KMODULE_COMP should be next to _KMODULE */
+       if (is_kernel_module(filename, &compressed) && compressed)
+               dso->symtab_type++;
+
        map_groups__insert(&machine->kmaps, map);
        return map;
 }
@@ -861,8 +867,14 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg,
                        struct map *map;
                        char *long_name;
 
-                       if (dot == NULL || strcmp(dot, ".ko"))
+                       if (dot == NULL)
                                continue;
+
+                       /* On some system, modules are compressed like .ko.gz */
+                       if (is_supported_compression(dot + 1) &&
+                           is_kmodule_extension(dot - 2))
+                               dot -= 3;
+
                        snprintf(dso_name, sizeof(dso_name), "[%.*s]",
                                 (int)(dot - dent->d_name), dent->d_name);
 
@@ -1044,6 +1056,11 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
                        dot = strrchr(name, '.');
                        if (dot == NULL)
                                goto out_problem;
+                       /* On some system, modules are compressed like .ko.gz */
+                       if (is_supported_compression(dot + 1))
+                               dot -= 3;
+                       if (!is_kmodule_extension(dot + 1))
+                               goto out_problem;
                        snprintf(short_module_name, sizeof(short_module_name),
                                        "[%.*s]", (int)(dot - name), name);
                        strxfrchar(short_module_name, '-', '_');
index 1e23a5bfb044a4cf39f2a0dfbbb5bf26bbad4b4b..efc7eb6b8f0fa6bb8b78686a3a08600bdb7ddff8 100644 (file)
@@ -546,6 +546,35 @@ static int dso__swap_init(struct dso *dso, unsigned char eidata)
        return 0;
 }
 
+static int decompress_kmodule(struct dso *dso, const char *name,
+                             enum dso_binary_type type)
+{
+       int fd;
+       const char *ext = strrchr(name, '.');
+       char tmpbuf[] = "/tmp/perf-kmod-XXXXXX";
+
+       if ((type != DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP &&
+            type != DSO_BINARY_TYPE__GUEST_KMODULE_COMP) ||
+           type != dso->symtab_type)
+               return -1;
+
+       if (!ext || !is_supported_compression(ext + 1))
+               return -1;
+
+       fd = mkstemp(tmpbuf);
+       if (fd < 0)
+               return -1;
+
+       if (!decompress_to_file(ext + 1, name, fd)) {
+               close(fd);
+               fd = -1;
+       }
+
+       unlink(tmpbuf);
+
+       return fd;
+}
+
 bool symsrc__possibly_runtime(struct symsrc *ss)
 {
        return ss->dynsym || ss->opdsec;
@@ -571,7 +600,11 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
        Elf *elf;
        int fd;
 
-       fd = open(name, O_RDONLY);
+       if (dso__needs_decompress(dso))
+               fd = decompress_kmodule(dso, name, type);
+       else
+               fd = open(name, O_RDONLY);
+
        if (fd < 0)
                return -1;
 
index 078331140d8c6a5feec6f9aeda597b49f974cbda..c69915c9d5bc202b699793e6833860f172a75093 100644 (file)
@@ -51,7 +51,9 @@ static enum dso_binary_type binary_type_symtab[] = {
        DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
        DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
        DSO_BINARY_TYPE__GUEST_KMODULE,
+       DSO_BINARY_TYPE__GUEST_KMODULE_COMP,
        DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
+       DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP,
        DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
        DSO_BINARY_TYPE__NOT_FOUND,
 };
@@ -1300,7 +1302,9 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
                return dso->kernel == DSO_TYPE_GUEST_KERNEL;
 
        case DSO_BINARY_TYPE__GUEST_KMODULE:
+       case DSO_BINARY_TYPE__GUEST_KMODULE_COMP:
        case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
+       case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP:
                /*
                 * kernel modules know their symtab type - it's set when
                 * creating a module dso in machine__new_module().
@@ -1368,7 +1372,9 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
                return -1;
 
        kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
-               dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE;
+               dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
+               dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE ||
+               dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
 
        /*
         * Iterate over candidate debug images.