Skip to content

Commit

Permalink
perf symbols: Preparation for compressed kernel module support
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Namhyung Kim authored and Arnaldo Carvalho de Melo committed Nov 4, 2014
1 parent 758008b commit c00c48f
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 3 deletions.
75 changes: 75 additions & 0 deletions tools/perf/util/dso.c
Original file line number Diff line number Diff line change
Expand Up @@ -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',
};

Expand Down Expand Up @@ -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;

Expand All @@ -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.
*/
Expand Down
7 changes: 7 additions & 0 deletions tools/perf/util/dso.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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:
Expand Down
19 changes: 18 additions & 1 deletion tools/perf/util/machine.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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, '-', '_');
Expand Down
35 changes: 34 additions & 1 deletion tools/perf/util/symbol-elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand Down
8 changes: 7 additions & 1 deletion tools/perf/util/symbol.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -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().
Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit c00c48f

Please sign in to comment.