[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',
};
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;
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.
*/
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,
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:
{
struct map *map;
struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename);
+ bool compressed;
if (dso == NULL)
return NULL;
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;
}
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);
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, '-', '_');
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;
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;
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,
};
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().
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.