Re: [PATCH] handle munmap records in tools/perf was: Re: perf/jit doesn't cope well with mprotect() to jit containing pages
From: Stephane Eranian
Date: Fri Jan 27 2017 - 12:58:38 EST
On Fri, Jan 27, 2017 at 9:38 AM, Arnaldo Carvalho de Melo
<arnaldo.melo@xxxxxxxxx> wrote:
> Em Fri, Jan 27, 2017 at 12:43:05PM -0300, Arnaldo Carvalho de Melo escreveu:
>> Em Fri, Jan 27, 2017 at 02:07:02PM +0100, Peter Zijlstra escreveu:
>> > Something like the (compile tested only) below might be sufficient to
>> > disambiguate things. It would need a corresponding tools/perf patch of
>> > course, but I'm not too familiar with that code anymore.
>>
>> I'm working on patch to do feature test, fallback and handling of the
>> event, etc, will post later.
>
> Just compile tested, need to build a kernel with PeterZ's patch to test,
> feel free to go from there if in a hurry.
>
>
> The place where the map is yanked out of the thread's maps rbtree is at
>
> machine__process_munmap_event()
>
> The rest is making sure the tool works with older kernels, deals with
> endianness in the record in a perf.data file for cross platform
> analysis, hooking it to the various tools where handling this event
> makes sense.
>
At first glance this patch handles the munmap() well. But it will not solve
the case of Andres. Unless you're telling me that the kernel with Peterz's patch
will now generate munmap record because of the merging. If not, then the code
handling overlaps needs to change as well as I described in my other Email.
> [acme@jouet linux]$ diffstat /tmp/a.patch
> include/uapi/linux/perf_event.h | 14 +++++++++-
> perf/builtin-annotate.c | 1
> perf/builtin-c2c.c | 1
> perf/builtin-diff.c | 1
> perf/builtin-inject.c | 17 +++++++++++-
> perf/builtin-kmem.c | 1
> perf/builtin-mem.c | 1
> perf/builtin-record.c | 1
> perf/builtin-report.c | 1
> perf/builtin-script.c | 30 ++++++++++++++++++++++
> perf/builtin-trace.c | 1
> perf/util/data-convert-bt.c | 1
> perf/util/event.c | 18 +++++++++++++
> perf/util/event.h | 10 +++++++
> perf/util/evsel.c | 12 +++++++-
> perf/util/machine.c | 54 ++++++++++++++++++++++++++++++++++++++++
> perf/util/machine.h | 2 +
> perf/util/python.c | 1
> perf/util/session.c | 19 ++++++++++++++
> perf/util/tool.h | 1
> 20 files changed, 183 insertions(+), 4 deletions(-)
> [acme@jouet linux]$
>
> diff --git a/tools/include/uapi/linux/perf_event.h b/tools/include/uapi/linux/perf_event.h
> index c66a485a24ac..59c5cd5abbbf 100644
> --- a/tools/include/uapi/linux/perf_event.h
> +++ b/tools/include/uapi/linux/perf_event.h
> @@ -344,7 +344,8 @@ struct perf_event_attr {
> use_clockid : 1, /* use @clockid for time fields */
> context_switch : 1, /* context switch data */
> write_backward : 1, /* Write ring buffer from end to beginning */
> - __reserved_1 : 36;
> + munmap : 1, /* include munmap data */
> + __reserved_1 : 35;
>
> union {
> __u32 wakeup_events; /* wakeup every n events */
> @@ -862,6 +863,17 @@ enum perf_event_type {
> */
> PERF_RECORD_SWITCH_CPU_WIDE = 15,
>
> + /*
> + * struct {
> + * struct perf_event_header header;
> + *
> + * u64 addr;
> + * u64 len;
> + * struct sample_id sample_id;
> + * };
> + */
> + PERF_RECORD_MUNMAP = 16,
> +
> PERF_RECORD_MAX, /* non-ABI */
> };
>
> diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
> index ebb628332a6e..082b5f100ac5 100644
> --- a/tools/perf/builtin-annotate.c
> +++ b/tools/perf/builtin-annotate.c
> @@ -390,6 +390,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
> .sample = process_sample_event,
> .mmap = perf_event__process_mmap,
> .mmap2 = perf_event__process_mmap2,
> + .munmap = perf_event__process_munmap,
> .comm = perf_event__process_comm,
> .exit = perf_event__process_exit,
> .fork = perf_event__process_fork,
> diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c
> index e2b21723bbf8..3e1f1eba77e2 100644
> --- a/tools/perf/builtin-c2c.c
> +++ b/tools/perf/builtin-c2c.c
> @@ -313,6 +313,7 @@ static struct perf_c2c c2c = {
> .sample = process_sample_event,
> .mmap = perf_event__process_mmap,
> .mmap2 = perf_event__process_mmap2,
> + .munmap = perf_event__process_munmap,
> .comm = perf_event__process_comm,
> .exit = perf_event__process_exit,
> .fork = perf_event__process_fork,
> diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
> index 9ff0db4e2d0c..2c7856848887 100644
> --- a/tools/perf/builtin-diff.c
> +++ b/tools/perf/builtin-diff.c
> @@ -350,6 +350,7 @@ static struct perf_tool tool = {
> .sample = diff__process_sample_event,
> .mmap = perf_event__process_mmap,
> .mmap2 = perf_event__process_mmap2,
> + .munmap = perf_event__process_munmap,
> .comm = perf_event__process_comm,
> .exit = perf_event__process_exit,
> .fork = perf_event__process_fork,
> diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
> index b9bc7e39833a..4e6103d0c163 100644
> --- a/tools/perf/builtin-inject.c
> +++ b/tools/perf/builtin-inject.c
> @@ -282,6 +282,19 @@ static int perf_event__repipe_mmap2(struct perf_tool *tool,
> return err;
> }
>
> +static int perf_event__repipe_munmap(struct perf_tool *tool,
> + union perf_event *event,
> + struct perf_sample *sample,
> + struct machine *machine)
> +{
> + int err;
> +
> + err = perf_event__process_munmap(tool, event, sample, machine);
> + perf_event__repipe(tool, event, sample, machine);
> +
> + return err;
> +}
> +
> #ifdef HAVE_JITDUMP
> static int perf_event__jit_repipe_mmap2(struct perf_tool *tool,
> union perf_event *event,
> @@ -569,7 +582,7 @@ static void strip_init(struct perf_inject *inject)
> static bool has_tracking(struct perf_evsel *evsel)
> {
> return evsel->attr.mmap || evsel->attr.mmap2 || evsel->attr.comm ||
> - evsel->attr.task;
> + evsel->attr.task || evsel->attr.munmap;
> }
>
> #define COMPAT_MASK (PERF_SAMPLE_ID | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | \
> @@ -632,6 +645,7 @@ static int __cmd_inject(struct perf_inject *inject)
> inject->itrace_synth_opts.set) {
> inject->tool.mmap = perf_event__repipe_mmap;
> inject->tool.mmap2 = perf_event__repipe_mmap2;
> + inject->tool.munmap = perf_event__repipe_munmap;
> inject->tool.fork = perf_event__repipe_fork;
> inject->tool.tracing_data = perf_event__repipe_tracing_data;
> }
> @@ -732,6 +746,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
> .sample = perf_event__repipe_sample,
> .mmap = perf_event__repipe,
> .mmap2 = perf_event__repipe,
> + .munmap = perf_event__repipe,
> .comm = perf_event__repipe,
> .fork = perf_event__repipe,
> .exit = perf_event__repipe,
> diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
> index 29f4751a3574..eb59aa7a0f5b 100644
> --- a/tools/perf/builtin-kmem.c
> +++ b/tools/perf/builtin-kmem.c
> @@ -964,6 +964,7 @@ static struct perf_tool perf_kmem = {
> .comm = perf_event__process_comm,
> .mmap = perf_event__process_mmap,
> .mmap2 = perf_event__process_mmap2,
> + .munmap = perf_event__process_munmap,
> .ordered_events = true,
> };
>
> diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
> index cd7bc4d104e2..de026e9ef1be 100644
> --- a/tools/perf/builtin-mem.c
> +++ b/tools/perf/builtin-mem.c
> @@ -338,6 +338,7 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
> .sample = process_sample_event,
> .mmap = perf_event__process_mmap,
> .mmap2 = perf_event__process_mmap2,
> + .munmap = perf_event__process_munmap,
> .comm = perf_event__process_comm,
> .lost = perf_event__process_lost,
> .fork = perf_event__process_fork,
> diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
> index ffac8ca9fb01..f197fc196cd8 100644
> --- a/tools/perf/builtin-record.c
> +++ b/tools/perf/builtin-record.c
> @@ -1498,6 +1498,7 @@ static struct record record = {
> .comm = perf_event__process_comm,
> .mmap = perf_event__process_mmap,
> .mmap2 = perf_event__process_mmap2,
> + .munmap = perf_event__process_munmap,
> .ordered_events = true,
> },
> };
> diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
> index dbd7fa028861..96680fbeb664 100644
> --- a/tools/perf/builtin-report.c
> +++ b/tools/perf/builtin-report.c
> @@ -693,6 +693,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
> .sample = process_sample_event,
> .mmap = perf_event__process_mmap,
> .mmap2 = perf_event__process_mmap2,
> + .munmap = perf_event__process_munmap,
> .comm = perf_event__process_comm,
> .exit = perf_event__process_exit,
> .fork = perf_event__process_fork,
> diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
> index c0783b4f7b6c..27fcbcb15782 100644
> --- a/tools/perf/builtin-script.c
> +++ b/tools/perf/builtin-script.c
> @@ -1244,6 +1244,34 @@ static int process_mmap2_event(struct perf_tool *tool,
> return 0;
> }
>
> +static int process_munmap_event(struct perf_tool *tool, union perf_event *event,
> + struct perf_sample *sample, struct machine *machine)
> +{
> + struct thread *thread;
> + struct perf_script *script = container_of(tool, struct perf_script, tool);
> + struct perf_session *session = script->session;
> + struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, sample->id);
> +
> + if (perf_event__process_munmap(tool, event, sample, machine) < 0)
> + return -1;
> +
> + thread = machine__findnew_thread(machine, sample->pid, sample->tid);
> + if (thread == NULL) {
> + pr_debug("problem processing MUNMAP event, skipping it.\n");
> + return -1;
> + }
> +
> + if (!evsel->attr.sample_id_all) {
> + pr_debug("MUNMAP event requires attr.sample_id_all, skipping it.\n");
> + return -1;
> + }
> +
> + print_sample_start(sample, thread, evsel);
> + perf_event__fprintf(event, stdout);
> + thread__put(thread);
> + return 0;
> +}
> +
> static int process_switch_event(struct perf_tool *tool,
> union perf_event *event,
> struct perf_sample *sample,
> @@ -1290,6 +1318,7 @@ static int __cmd_script(struct perf_script *script)
> if (script->show_mmap_events) {
> script->tool.mmap = process_mmap_event;
> script->tool.mmap2 = process_mmap2_event;
> + script->tool.munmap = process_munmap_event;
> }
> if (script->show_switch_events)
> script->tool.context_switch = process_switch_event;
> @@ -2096,6 +2125,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
> .sample = process_sample_event,
> .mmap = perf_event__process_mmap,
> .mmap2 = perf_event__process_mmap2,
> + .munmap = perf_event__process_munmap,
> .comm = perf_event__process_comm,
> .exit = perf_event__process_exit,
> .fork = perf_event__process_fork,
> diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
> index 40ef9b293d1b..cfb7e9e2cd7d 100644
> --- a/tools/perf/builtin-trace.c
> +++ b/tools/perf/builtin-trace.c
> @@ -2411,6 +2411,7 @@ static int trace__replay(struct trace *trace)
> trace->tool.sample = trace__process_sample;
> trace->tool.mmap = perf_event__process_mmap;
> trace->tool.mmap2 = perf_event__process_mmap2;
> + trace->tool.munmap = perf_event__process_munmap;
> trace->tool.comm = perf_event__process_comm;
> trace->tool.exit = perf_event__process_exit;
> trace->tool.fork = perf_event__process_fork;
> diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c
> index 4e6cbc99f08e..8d1feb9fe82d 100644
> --- a/tools/perf/util/data-convert-bt.c
> +++ b/tools/perf/util/data-convert-bt.c
> @@ -1462,6 +1462,7 @@ int bt_convert__perf2ctf(const char *input, const char *path,
> .sample = process_sample_event,
> .mmap = perf_event__process_mmap,
> .mmap2 = perf_event__process_mmap2,
> + .munmap = perf_event__process_munmap,
> .comm = perf_event__process_comm,
> .exit = perf_event__process_exit,
> .fork = perf_event__process_fork,
> diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
> index 8ab0d7da956b..ffcba9c07c0d 100644
> --- a/tools/perf/util/event.c
> +++ b/tools/perf/util/event.c
> @@ -18,6 +18,7 @@ static const char *perf_event__names[] = {
> [0] = "TOTAL",
> [PERF_RECORD_MMAP] = "MMAP",
> [PERF_RECORD_MMAP2] = "MMAP2",
> + [PERF_RECORD_MUNMAP] = "MUNMAP",
> [PERF_RECORD_LOST] = "LOST",
> [PERF_RECORD_COMM] = "COMM",
> [PERF_RECORD_EXIT] = "EXIT",
> @@ -1080,6 +1081,12 @@ size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp)
> event->mmap2.filename);
> }
>
> +size_t perf_event__fprintf_munmap(union perf_event *event, FILE *fp)
> +{
> + return fprintf(fp, " [%#" PRIx64 ", %" PRIu64 "]\n",
> + event->munmap.start, event->munmap.len);
> +}
> +
> size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp)
> {
> struct thread_map *threads = thread_map__new_event(&event->thread_map);
> @@ -1128,6 +1135,14 @@ int perf_event__process_mmap2(struct perf_tool *tool __maybe_unused,
> return machine__process_mmap2_event(machine, event, sample);
> }
>
> +int perf_event__process_munmap(struct perf_tool *tool __maybe_unused,
> + union perf_event *event,
> + struct perf_sample *sample,
> + struct machine *machine)
> +{
> + return machine__process_munmap_event(machine, event, sample);
> +}
> +
> size_t perf_event__fprintf_task(union perf_event *event, FILE *fp)
> {
> return fprintf(fp, "(%d:%d):(%d:%d)\n",
> @@ -1199,6 +1214,9 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp)
> case PERF_RECORD_MMAP2:
> ret += perf_event__fprintf_mmap2(event, fp);
> break;
> + case PERF_RECORD_MUNMAP:
> + ret += perf_event__fprintf_munmap(event, fp);
> + break;
> case PERF_RECORD_AUX:
> ret += perf_event__fprintf_aux(event, fp);
> break;
> diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
> index c735c53a26f8..00942b6a9d48 100644
> --- a/tools/perf/util/event.h
> +++ b/tools/perf/util/event.h
> @@ -33,6 +33,12 @@ struct mmap2_event {
> char filename[PATH_MAX];
> };
>
> +struct munmap_event {
> + struct perf_event_header header;
> + u64 start;
> + u64 len;
> +};
> +
> struct comm_event {
> struct perf_event_header header;
> u32 pid, tid;
> @@ -484,6 +490,7 @@ union perf_event {
> struct perf_event_header header;
> struct mmap_event mmap;
> struct mmap2_event mmap2;
> + struct munmap_event munmap;
> struct comm_event comm;
> struct fork_event fork;
> struct lost_event lost;
> @@ -595,6 +602,8 @@ int perf_event__process_mmap2(struct perf_tool *tool,
> union perf_event *event,
> struct perf_sample *sample,
> struct machine *machine);
> +int perf_event__process_munmap(struct perf_tool *tool, union perf_event *event,
> + struct perf_sample *sample, struct machine *machine);
> int perf_event__process_fork(struct perf_tool *tool,
> union perf_event *event,
> struct perf_sample *sample,
> @@ -647,6 +656,7 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
> size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp);
> size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp);
> size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp);
> +size_t perf_event__fprintf_munmap(union perf_event *event, FILE *fp);
> size_t perf_event__fprintf_task(union perf_event *event, FILE *fp);
> size_t perf_event__fprintf_aux(union perf_event *event, FILE *fp);
> size_t perf_event__fprintf_itrace_start(union perf_event *event, FILE *fp);
> diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
> index 04e536ae4d88..c4b88e4f2422 100644
> --- a/tools/perf/util/evsel.c
> +++ b/tools/perf/util/evsel.c
> @@ -34,6 +34,7 @@ static struct {
> bool sample_id_all;
> bool exclude_guest;
> bool mmap2;
> + bool munmap;
> bool cloexec;
> bool clockid;
> bool clockid_wrong;
> @@ -930,6 +931,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts,
> attr->task = track;
> attr->mmap = track;
> attr->mmap2 = track && !perf_missing_features.mmap2;
> + attr->munmap = track && !perf_missing_features.munmap;
> attr->comm = track;
>
> if (opts->record_switch_events)
> @@ -1395,6 +1397,7 @@ int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr,
> PRINT_ATTRf(exclude_callchain_kernel, p_unsigned);
> PRINT_ATTRf(exclude_callchain_user, p_unsigned);
> PRINT_ATTRf(mmap2, p_unsigned);
> + PRINT_ATTRf(munmap, p_unsigned);
> PRINT_ATTRf(comm_exec, p_unsigned);
> PRINT_ATTRf(use_clockid, p_unsigned);
> PRINT_ATTRf(context_switch, p_unsigned);
> @@ -1474,6 +1477,8 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
> }
>
> fallback_missing_features:
> + if (perf_missing_features.munmap)
> + evsel->attr.munmap = 0;
> if (perf_missing_features.clockid_wrong)
> evsel->attr.clockid = CLOCK_MONOTONIC; /* should always work */
> if (perf_missing_features.clockid) {
> @@ -1603,10 +1608,13 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
> goto out_close;
>
> /*
> - * Must probe features in the order they were added to the
> + * Must probe features in the reverse order they were added to the
> * perf_event_attr interface.
> */
> - if (!perf_missing_features.write_backward && evsel->attr.write_backward) {
> + if (!perf_missing_features.munmap && evsel->attr.munmap) {
> + perf_missing_features.munmap = true;
> + goto fallback_missing_features;
> + } else if (!perf_missing_features.write_backward && evsel->attr.write_backward) {
> perf_missing_features.write_backward = true;
> goto out_close;
> } else if (!perf_missing_features.clockid_wrong && evsel->attr.use_clockid) {
> diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
> index 747a034d1ff3..24f2f309d70f 100644
> --- a/tools/perf/util/machine.c
> +++ b/tools/perf/util/machine.c
> @@ -1320,6 +1320,16 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
> return -1;
> }
>
> +static int machine__process_kernel_munmap_event(struct machine *machine __maybe_unused,
> + union perf_event *event __maybe_unused)
> +{
> + /*
> + * XXX: Fill this in as soon as we get munmap event for kernel
> + * "mmaps", aka module unload
> + */
> + return 0;
> +}
> +
> int machine__process_mmap2_event(struct machine *machine,
> union perf_event *event,
> struct perf_sample *sample)
> @@ -1379,6 +1389,48 @@ int machine__process_mmap2_event(struct machine *machine,
> return 0;
> }
>
> +int machine__process_munmap_event(struct machine *machine,
> + union perf_event *event,
> + struct perf_sample *sample)
> +{
> + struct thread *thread;
> + struct map *map;
> + enum map_type type = MAP__FUNCTION;
> + int ret = 0;
> +
> + if (dump_trace)
> + perf_event__fprintf_munmap(event, stdout);
> +
> + if (sample->cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
> + sample->cpumode == PERF_RECORD_MISC_KERNEL) {
> + ret = machine__process_kernel_munmap_event(machine, event);
> + if (ret < 0)
> + goto out_problem;
> + return 0;
> + }
> +
> + thread = machine__find_thread(machine, sample->pid, sample->tid);
> + if (thread == NULL)
> + goto out_problem;
> +
> + if (event->header.misc & PERF_RECORD_MISC_MMAP_DATA)
> + type = MAP__VARIABLE;
> +
> + map = map_groups__find(thread->mg, type, event->munmap.start);
> + if (map != NULL)
> + goto out_problem_map;
> +
> + map_groups__remove(thread->mg, map);
> + thread__put(thread);
> + return 0;
> +
> +out_problem_map:
> + thread__put(thread);
> +out_problem:
> + dump_printf("problem processing PERF_RECORD_MUNMAP, skipping event.\n");
> + return 0;
> +}
> +
> int machine__process_mmap_event(struct machine *machine, union perf_event *event,
> struct perf_sample *sample)
> {
> @@ -1540,6 +1592,8 @@ int machine__process_event(struct machine *machine, union perf_event *event,
> ret = machine__process_mmap_event(machine, event, sample); break;
> case PERF_RECORD_MMAP2:
> ret = machine__process_mmap2_event(machine, event, sample); break;
> + case PERF_RECORD_MUNMAP:
> + ret = machine__process_munmap_event(machine, event, sample); break;
> case PERF_RECORD_FORK:
> ret = machine__process_fork_event(machine, event, sample); break;
> case PERF_RECORD_EXIT:
> diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
> index a28305029711..eabc8b9d8d36 100644
> --- a/tools/perf/util/machine.h
> +++ b/tools/perf/util/machine.h
> @@ -101,6 +101,8 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
> struct perf_sample *sample);
> int machine__process_mmap2_event(struct machine *machine, union perf_event *event,
> struct perf_sample *sample);
> +int machine__process_munmap_event(struct machine *machine, union perf_event *event,
> + struct perf_sample *sample);
> int machine__process_event(struct machine *machine, union perf_event *event,
> struct perf_sample *sample);
>
> diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
> index a5fbc012e3df..047e004dc53f 100644
> --- a/tools/perf/util/python.c
> +++ b/tools/perf/util/python.c
> @@ -1155,6 +1155,7 @@ static struct {
> PERF_CONST(RECORD_READ),
> PERF_CONST(RECORD_SAMPLE),
> PERF_CONST(RECORD_MMAP2),
> + PERF_CONST(RECORD_MUNMAP),
> PERF_CONST(RECORD_AUX),
> PERF_CONST(RECORD_ITRACE_START),
> PERF_CONST(RECORD_LOST_SAMPLES),
> diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
> index 349c68144e55..42edd68ce0b8 100644
> --- a/tools/perf/util/session.c
> +++ b/tools/perf/util/session.c
> @@ -357,6 +357,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
> tool->mmap = process_event_stub;
> if (tool->mmap2 == NULL)
> tool->mmap2 = process_event_stub;
> + if (tool->munmap == NULL)
> + tool->munmap = process_event_stub;
> if (tool->comm == NULL)
> tool->comm = process_event_stub;
> if (tool->fork == NULL)
> @@ -480,6 +482,20 @@ static void perf_event__mmap2_swap(union perf_event *event,
> swap_sample_id_all(event, data);
> }
> }
> +
> +static void perf_event__munmap_swap(union perf_event *event, bool sample_id_all)
> +{
> + event->munmap.start = bswap_64(event->munmap.start);
> + event->munmap.len = bswap_64(event->munmap.len);
> +
> + if (sample_id_all) {
> + void *data = &event->munmap.len;
> +
> + data += sizeof(event->munmap.len);
> + swap_sample_id_all(event, data);
> + }
> +}
> +
> static void perf_event__task_swap(union perf_event *event, bool sample_id_all)
> {
> event->fork.pid = bswap_32(event->fork.pid);
> @@ -773,6 +789,7 @@ typedef void (*perf_event__swap_op)(union perf_event *event,
> static perf_event__swap_op perf_event__swap_ops[] = {
> [PERF_RECORD_MMAP] = perf_event__mmap_swap,
> [PERF_RECORD_MMAP2] = perf_event__mmap2_swap,
> + [PERF_RECORD_MUNMAP] = perf_event__munmap_swap,
> [PERF_RECORD_COMM] = perf_event__comm_swap,
> [PERF_RECORD_FORK] = perf_event__task_swap,
> [PERF_RECORD_EXIT] = perf_event__task_swap,
> @@ -1237,6 +1254,8 @@ static int machines__deliver_event(struct machines *machines,
> if (event->header.misc & PERF_RECORD_MISC_PROC_MAP_PARSE_TIMEOUT)
> ++evlist->stats.nr_proc_map_timeout;
> return tool->mmap2(tool, event, sample, machine);
> + case PERF_RECORD_MUNMAP:
> + return tool->munmap(tool, event, sample, machine);
> case PERF_RECORD_COMM:
> return tool->comm(tool, event, sample, machine);
> case PERF_RECORD_FORK:
> diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
> index ac2590a3de2d..66291063b8b2 100644
> --- a/tools/perf/util/tool.h
> +++ b/tools/perf/util/tool.h
> @@ -39,6 +39,7 @@ struct perf_tool {
> read;
> event_op mmap,
> mmap2,
> + munmap,
> comm,
> fork,
> exit,