This patch introduces a --map-anon-mem argument to perf report to deal
with anon-executable-memory symbol parsing.
Sometimes, we mmap() executable memory area, and copy some '.so' or '.o'
files to the area, and then do the relocation and code fixing to make the
code work well. However, perf could not parse symbol info in those files,
since the memory area is not file-backended.
The problem was first discussed in :
https://lkml.org/lkml/2015/4/1/203
In this discussion, we finally preferred to something like 'perf inject'
to inject fake mmap events into perf.data. However, for embeded system
whose space is limited, it's not so wise to make another big perf.data
by 'perf inject'. So we still adopt the previous solution: introduce
'--map-anon-mem' argument and let user directly hint perf-report about
the private mapping info.
The content of this patch:
1) A new field mapping_strlist is introduced to struct report, in order
to store --map-anon-mem string for afterwards parsing.
2) A new field maps_anon is introduced to struct map_groups. maps_anon is used
to store the maps user defines directly for anon-mapping. when searching maps
in map_groups, we prefer to the maps stored in maps_anon.
3) The main part of this patch resides in builtin-report.c and session.c.
the part in builtin-report.c is charge of storing --map-anon-mem string,
while the part in session.c parses the string, create maps, and store maps
in map_groups->maps_anon.
Here is an example:
$ perf report --map-anon-mem=./libtesta.o@257,0x7f864c0000,0x60,0 \
--map-anon-mem=./libtestb.o@257,0x7f864c0060,0x1000,0
Where 257 is the pid and 0x76864c0000 is private map area got through:
mmap(NULL, 4096 * 4, PROT_EXEC|PROT_WRITE|PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE, \
-1, 0);
and libtesta.o is copied to [0x7f864c0000,0x7f864c0060),
libtestb.o is copied to [0x7f864c0060,0x7f864c1060).
Signed-off-by: Wang Nan <wangnan0@xxxxxxxxxx>[SNIP]
Signed-off-by: Hou Pengyang <houpengyang@xxxxxxxxxx>
---
tools/perf/Documentation/perf-report.txt | 8 +++
tools/perf/builtin-report.c | 39 +++++++++++
tools/perf/util/map.c | 3 +-
tools/perf/util/map.h | 10 ++-
tools/perf/util/session.c | 117 +++++++++++++++++++++++++++++++
tools/perf/util/session.h | 4 ++
6 files changed, 178 insertions(+), 3 deletions(-)
+[SNIP]
int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
{
struct perf_session *session;
@@ -728,6 +755,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts",
"Instruction Tracing options",
itrace_parse_synth_opts),
+ OPT_CALLBACK_OPTARG(0, "map-anon-mem", &report.mapping_strlist, NULL,
+ "objfile@pid,start,length[,offset]",
+ "Provide map adjustment hinting",
+ append_to_strlist),
OPT_END()
};
struct perf_data_file file = {
@@ -767,6 +798,14 @@ repeat:
if (session == NULL)
return -1;
+ if (perf_session__map_anon(session,
+ report.mapping_strlist)) {
+ parse_options_usage(report_usage, options,
+ "map-anon-mem", 0);
+ goto error;
+ }
+
+
if (report.queue_size) {
ordered_events__set_alloc_size(&session->ordered_events,
report.queue_size);
+static int
+__perf_session__map_anon(struct perf_session *session, int pid,
+ char *path, u64 addr, u64 length,
+ u64 offset)
+{
+ struct thread *thread;
+ struct map *map;
+ int err = -1;
+
+ thread = perf_session__findnew(session, pid);
+ if (!thread)
+ return -1;
+[SNIP]
+ map = map__new(&session->machines.host, addr, length, offset,
+ pid, 0, 0, 0, 0, PROT_READ | PROT_EXEC, 0, path,
+ MAP__FUNCTION, thread);
+ if (!map)
+ goto out;
+
+ maps__fixup_overlappings(&thread->mg->maps_anon, map, stderr);
+ maps__insert(&thread->mg->maps_anon, map);
+ map->groups = thread->mg;
+
+ err = 0;
+out:
+ thread__put(thread);
+ return err;
+}
+
+int perf_session__map_anon(struct perf_session *session,
+ struct strlist *slist)
+{
+ struct str_node *node;
+ int err;
+
+ if (!slist)
+ return 0;
+
+ strlist__for_each(node, slist) {
+ int pid;
+ u64 addr, length, offset;
+ const char *map_anon_cmd = node->s;
+ char path[PATH_MAX];
+
+ if (parse_map_anon_mem(map_anon_cmd, path,
+ &pid, &addr, &length, &offset))
+ return -1;
+
+ err = __perf_session__map_anon(session,
+ pid, path, addr,
+ length, offset);
+ if (err)
+ return -1;
+ }
+
+ return 0;
+}