Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e7ee4047 authored by Wang Nan's avatar Wang Nan Committed by Arnaldo Carvalho de Melo
Browse files

perf symbols: Fix symbols searching for module in buildid-cache



Before this patch, if a sample is triggered inside a module not in
/lib/modules/`uname -r`/, even if the module is in buildid-cache, 'perf
report' will still be unable to find the correct symbol.  For example:

  # rm -rf ~/.debug/
  # perf buildid-cache -a ./mymodule.ko
  # perf probe -m ./mymodule.ko -a get_mymodule_val
  Added new event:
    probe:get_mymodule_val (on get_mymodule_val in mymodule)

  You can now use it in all perf tools, such as:

 	perf record -e probe:get_mymodule_val -aR sleep 1

  # perf record -e probe:get_mymodule_val cat /proc/mymodule
  mymodule:3
  [ perf record: Woken up 1 times to write data ]
  [ perf record: Captured and wrote 0.011 MB perf.data (1 samples) ]

  # perf report --stdio
  [SNIP]
  #
  # Overhead  Command  Shared Object     Symbol
  # ........  .......  ................  ......................
  #
    100.00%  cat      [mymodule]        [k] 0x0000000000000001

  # perf report -vvvv --stdio
  dso__load_sym: adjusting symbol: st_value: 0 sh_addr: 0 sh_offset: 0x70
  symbol__new: get_mymodule_val 0x70-0x8a
  [SNIP]

This is caused by dso__load() -> dso__load_sym(). In dso__load(), kmod
is true only when its file is found in some well know directories. All
files loaded from buildid-cache are treated as user programs. Following
dso__load_sym() set map->pgoff incorrectly.

This patch gives kernel modules in buildid-cache a chance to adjust
value of kmod. After dso__load() get the type of symbols, if it is
buildid, check the last 3 chars of original filename against '.ko', and
adjust the value of kmod if the file is a kernel module.

Signed-off-by: default avatarWang Nan <wangnan0@huawei.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Cody P Schafer <dev@codyps.com>
Cc: He Kuang <hekuang@huawei.com>
Cc: Jeremie Galarneau <jeremie.galarneau@efficios.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kirill Smelkov <kirr@nexedi.com>
Cc: Li Zefan <lizefan@huawei.com>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1454680939-24963-3-git-send-email-wangnan0@huawei.com


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent c7ac2417
Loading
Loading
Loading
Loading
+44 −0
Original line number Original line Diff line number Diff line
@@ -166,6 +166,50 @@ char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)
	return build_id__filename(build_id_hex, bf, size);
	return build_id__filename(build_id_hex, bf, size);
}
}


bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size)
{
	char *id_name, *ch;
	struct stat sb;

	id_name = dso__build_id_filename(dso, bf, size);
	if (!id_name)
		goto err;
	if (access(id_name, F_OK))
		goto err;
	if (lstat(id_name, &sb) == -1)
		goto err;
	if ((size_t)sb.st_size > size - 1)
		goto err;
	if (readlink(id_name, bf, size - 1) < 0)
		goto err;

	bf[sb.st_size] = '\0';

	/*
	 * link should be:
	 * ../../lib/modules/4.4.0-rc4/kernel/net/ipv4/netfilter/nf_nat_ipv4.ko/a09fe3eb3147dafa4e3b31dbd6257e4d696bdc92
	 */
	ch = strrchr(bf, '/');
	if (!ch)
		goto err;
	if (ch - 3 < bf)
		goto err;

	return strncmp(".ko", ch - 3, 3) == 0;
err:
	/*
	 * If dso__build_id_filename work, get id_name again,
	 * because id_name points to bf and is broken.
	 */
	if (id_name)
		id_name = dso__build_id_filename(dso, bf, size);
	pr_err("Invalid build id: %s\n", id_name ? :
					 dso->long_name ? :
					 dso->short_name ? :
					 "[unknown]");
	return false;
}

#define dsos__for_each_with_build_id(pos, head)	\
#define dsos__for_each_with_build_id(pos, head)	\
	list_for_each_entry(pos, head, node)	\
	list_for_each_entry(pos, head, node)	\
		if (!pos->has_build_id)		\
		if (!pos->has_build_id)		\
+1 −0
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@ int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id);
int filename__sprintf_build_id(const char *pathname, char *sbuild_id);
int filename__sprintf_build_id(const char *pathname, char *sbuild_id);


char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size);
char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size);
bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size);


int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event,
int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event,
			   struct perf_sample *sample, struct perf_evsel *evsel,
			   struct perf_sample *sample, struct perf_evsel *evsel,
+4 −0
Original line number Original line Diff line number Diff line
@@ -1529,6 +1529,10 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
	if (!runtime_ss && syms_ss)
	if (!runtime_ss && syms_ss)
		runtime_ss = syms_ss;
		runtime_ss = syms_ss;


	if (syms_ss && syms_ss->type == DSO_BINARY_TYPE__BUILD_ID_CACHE)
		if (dso__build_id_is_kmod(dso, name, PATH_MAX))
			kmod = true;

	if (syms_ss)
	if (syms_ss)
		ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, kmod);
		ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, kmod);
	else
	else