LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
From: Wang Nan <wangnan0@huawei.com>
To: <acme@kernel.org>, <jolsa@kernel.org>, <namhyung@kernel.org>
Cc: <mingo@redhat.com>, <lizefan@huawei.com>, <pi3orama@163.com>,
	<linux-kernel@vger.kernel.org>
Subject: [PATCH 4/4] perf tools: unwinding: try to read from map_adj for a unmapped address.
Date: Wed, 1 Apr 2015 10:33:15 +0000	[thread overview]
Message-ID: <1427884395-241111-5-git-send-email-wangnan0@huawei.com> (raw)
In-Reply-To: <1427884395-241111-1-git-send-email-wangnan0@huawei.com>

Previous patch allows users to use --map-adjustment to hint perf about
address ranges known to be shared object files backended. However, if
only parts of such object files are read, libunwind will fail to get
required information from unmapped area of those files.

This patch makes access_dso_mem() to try it best when when reading from
DSO. When it tried and fail the first time, it iterates over
map_adj_list to search a mapped DSO whcih contains such address and read
from it.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
---
 tools/perf/util/machine.c          | 55 ++++++++++++++++++++++++++++++++++++++
 tools/perf/util/machine.h          |  1 +
 tools/perf/util/unwind-libunwind.c | 18 +++++++++++--
 3 files changed, 72 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index dc9e91e..5176932 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1186,6 +1186,9 @@ struct map_adj {
 	u64 start;
 	u64 len;
 	u64 pgoff;
+	/* filled when first mapping */
+	bool mapped;
+	u64 map_start;
 	struct list_head list;
 	char filename[PATH_MAX];
 };
@@ -1304,6 +1307,7 @@ static int machine_add_map_adj(u32 pid, u64 start, u64 len,
 	new->start = start;
 	new->len = len;
 	new->pgoff = pgoff;
+	new->mapped = false;
 	strncpy(new->filename, filename, PATH_MAX);
 	list_add(&new->list, pos->list.prev);
 	return 0;
@@ -1351,6 +1355,11 @@ again:
 			map = map__new(machine, adj_start, adj_len, adj_pgoff,
 					pid, 0, 0, 0, 0, prot, flags,
 					pos->filename, type, thread);
+
+			if (!pos->mapped) {
+				pos->mapped = true;
+				pos->map_start = adj_start;
+			}
 		} else {
 			/*
 			 * |<----- tmp ----->|
@@ -1393,6 +1402,52 @@ error:
 	return -1;
 }
 
+/*
+ * Search map_adj according to pid and address and return an already
+ * mapped address. This function is used for dwarf unwinding. When
+ * libunwind tries to read from a DSO and fail because the area is not
+ * mapped, this function can help it to find cooresponding map_adj, and
+ * give it another chance to read from DSO.
+ *
+ * However, we are unable to ensure this searching always correct. See
+ * this:
+ *
+ *    |<--- liba.so --->|<-.. liba.so (unmapped) ..->|
+ *                      |<--- libb.so --->|<-.. libb.so (unmapped) ..->|
+ *    |<---     mmaped map_adj        --->|   ^
+ *
+ * Actually mapped area is assembled by part of liba.so and part of
+ * libb.so. When libunwind tries to read from ^ marked place, this
+ * searching returns liba.so, but in fact no one (expect libunwind
+ * itself) knows which map_adj is correct.
+ */
+int machine__search_map_adj(pid_t pid, u64 addr, u64 *map_start)
+{
+	struct map_adj *pos;
+
+	if (!map_start)
+		return -EINVAL;
+
+	list_for_each_entry(pos, &map_adj_list, list) {
+		if (pos->pid != (u32)(-1)) {
+			if (pos->pid < (u32)pid)
+				continue;
+			if (pos->pid > (u32)pid)
+				break;
+		}
+
+		if (!pos->mapped)
+			continue;
+
+		if ((pos->start <= addr) && (pos->start + pos->len > addr)) {
+			*map_start = pos->map_start;
+			return 0;
+		}
+	}
+
+	return -EEXIST;
+}
+
 int parse_map_adjustment(const struct option *opt __maybe_unused,
 		const char *arg, int unset __maybe_unused)
 {
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index 73b49e4..b0c66ce 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -224,5 +224,6 @@ int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid,
 			     pid_t tid);
 
 int parse_map_adjustment(const struct option *opt, const char *arg, int unset);
+int machine__search_map_adj(pid_t pid, u64 addr, u64 *map_start);
 
 #endif /* __PERF_MACHINE_H */
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index 78a32c7..a78c280 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -412,8 +412,22 @@ static int access_dso_mem(struct unwind_info *ui, unw_word_t addr,
 	thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
 			      MAP__FUNCTION, addr, &al);
 	if (!al.map) {
-		pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
-		return -1;
+		u64 map_start;
+
+		pr_debug("unwind: try find map from map_adj: %lx\n", (unsigned long)addr);
+		if (machine__search_map_adj(ui->thread->pid_, (u64)addr, &map_start)) {
+			pr_debug("unwind: no map for %lx even consider map adjustment\n",
+					(unsigned long)addr);
+			return -1;
+		}
+
+		thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
+				MAP__FUNCTION, map_start, &al);
+		if (!al.map) {
+			pr_debug("unwind: unable to find map for %lx (through %lx)\n",
+					(unsigned long)addr, (unsigned long)map_start);
+			return -1;
+		}
 	}
 
 	if (!al.map->dso)
-- 
1.8.3.4


      parent reply	other threads:[~2015-04-01 10:33 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-04-01 10:33 [PATCH 0/4] perf tools: introduce --map-adjustment Wang Nan
2015-04-01 10:33 ` [PATCH 1/4] perf tools: unwind: ensure unwind hooks return negative errorno Wang Nan
2015-04-01 12:12   ` Jiri Olsa
2015-04-01 12:41     ` Wang Nan
2015-04-07  8:30       ` Wang Nan
2015-04-01 10:33 ` [PATCH 2/4] perf tools: introduce machine_map_new to merge mmap/mmap2 processing code Wang Nan
2015-04-01 12:18   ` Jiri Olsa
2015-04-01 14:58     ` Arnaldo Carvalho de Melo
2015-04-01 10:33 ` [PATCH 3/4] perf tools: report: introduce --map-adjustment argument Wang Nan
2015-04-01 13:21   ` Jiri Olsa
2015-04-02  1:15     ` Wang Nan
2015-04-01 14:23   ` pi3orama
2015-04-01 10:33 ` Wang Nan [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1427884395-241111-5-git-send-email-wangnan0@huawei.com \
    --to=wangnan0@huawei.com \
    --cc=acme@kernel.org \
    --cc=jolsa@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lizefan@huawei.com \
    --cc=mingo@redhat.com \
    --cc=namhyung@kernel.org \
    --cc=pi3orama@163.com \
    --subject='Re: [PATCH 4/4] perf tools: unwinding: try to read from map_adj for a unmapped address.' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).