perf_counter tools: Handle overlapping MMAP events
authorPeter Zijlstra <a.p.zijlstra@chello.nl>
Tue, 23 Jun 2009 09:23:07 +0000 (11:23 +0200)
committerIngo Molnar <mingo@elte.hu>
Tue, 23 Jun 2009 09:42:44 +0000 (11:42 +0200)
Martin Schwidefsky reported "perf report" symbol resolution
problems on S390.

Since we only report MMAP, not MUNMAP, we have to deal with
overlapping maps.

We used to simply throw out the old map on the assumption whole
maps got unmapped. This obviously doesn't deal with partial
unmaps. However it appears some dynamic linkers do fancy
partial unmaps (s390), so do something more elaborate and
truncate the old maps, only removing them when they've been
fully covered.

This resolves (part of) the S390 symbol resolution problems.

Reported-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Tested-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
tools/perf/builtin-report.c

index ec230a0146e9fb5dd991cd27036d5af0ecc91da7..b4e76f75ba87f41c06d5bc74b048d1b84d629b56 100644 (file)
@@ -400,9 +400,27 @@ static void thread__insert_map(struct thread *self, struct map *map)
 
        list_for_each_entry_safe(pos, tmp, &self->maps, node) {
                if (map__overlap(pos, map)) {
-                       list_del_init(&pos->node);
-                       /* XXX leaks dsos */
-                       free(pos);
+                       if (verbose >= 2) {
+                               printf("overlapping maps:\n");
+                               map__fprintf(map, stdout);
+                               map__fprintf(pos, stdout);
+                       }
+
+                       if (map->start <= pos->start && map->end > pos->start)
+                               pos->start = map->end;
+
+                       if (map->end >= pos->end && map->start < pos->end)
+                               pos->end = map->start;
+
+                       if (verbose >= 2) {
+                               printf("after collision:\n");
+                               map__fprintf(pos, stdout);
+                       }
+
+                       if (pos->start >= pos->end) {
+                               list_del_init(&pos->node);
+                               free(pos);
+                       }
                }
        }