2009-12-28 02:37:00 +03:00
|
|
|
#ifndef __PERF_MAP_H
|
|
|
|
#define __PERF_MAP_H
|
|
|
|
|
|
|
|
#include <linux/compiler.h>
|
|
|
|
#include <linux/list.h>
|
|
|
|
#include <linux/rbtree.h>
|
2010-03-26 01:58:58 +03:00
|
|
|
#include <stdio.h>
|
|
|
|
#include "types.h"
|
2009-12-28 02:37:00 +03:00
|
|
|
|
|
|
|
enum map_type {
|
|
|
|
MAP__FUNCTION = 0,
|
|
|
|
MAP__VARIABLE,
|
|
|
|
};
|
|
|
|
|
|
|
|
#define MAP__NR_TYPES (MAP__VARIABLE + 1)
|
|
|
|
|
2010-02-22 22:15:39 +03:00
|
|
|
extern const char *map_type__name[MAP__NR_TYPES];
|
|
|
|
|
2009-12-28 02:37:00 +03:00
|
|
|
struct dso;
|
2010-02-03 21:52:00 +03:00
|
|
|
struct ref_reloc_sym;
|
|
|
|
struct map_groups;
|
2009-12-28 02:37:00 +03:00
|
|
|
|
|
|
|
struct map {
|
|
|
|
union {
|
|
|
|
struct rb_node rb_node;
|
|
|
|
struct list_head node;
|
|
|
|
};
|
|
|
|
u64 start;
|
|
|
|
u64 end;
|
|
|
|
enum map_type type;
|
|
|
|
u64 pgoff;
|
perf annotate: Fix it for non-prelinked *.so
The problem was we were incorrectly calculating objdump
addresses for sym->start and sym->end, look:
For simple ET_DYN type DSO (*.so) with one function, objdump -dS
output is something like this:
000004ac <my_strlen>:
int my_strlen(const char *s)
4ac: 55 push %ebp
4ad: 89 e5 mov %esp,%ebp
4af: 83 ec 10 sub $0x10,%esp
{
i.e. we have relative-to-dso-mapping IPs (=RIP) there.
For ET_EXEC type and probably for prelinked libs as well (sorry
can't test - I don't use prelink) objdump outputs absolute IPs,
e.g.
08048604 <zz_strlen>:
extern "C"
int zz_strlen(const char *s)
8048604: 55 push %ebp
8048605: 89 e5 mov %esp,%ebp
8048607: 83 ec 10 sub $0x10,%esp
{
So, if sym->start is always relative to dso mapping(*), we'll
have to unmap it for ET_EXEC like cases, and leave as is for
ET_DYN cases.
(*) and it is - we've explicitely made it relative. Look for
adjust_symbols handling in dso__load_sym()
Previously we were always unmapping sym->start and for ET_DYN
dsos resulting addresses were wrong, and so objdump output was
empty.
The end result was that perf annotate output for symbols from
non-prelinked *.so had always 0.00% percents only, which is
wrong.
To fix it, let's introduce a helper for converting rip to
objdump address, and also let's document what map_ip() and
unmap_ip() do -- I had to study sources for several hours to
understand it.
Signed-off-by: Kirill Smelkov <kirr@landau.phys.spbu.ru>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Mike Galbraith <efault@gmx.de>
LKML-Reference: <1265223128-11786-8-git-send-email-acme@infradead.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-02-03 21:52:07 +03:00
|
|
|
|
|
|
|
/* ip -> dso rip */
|
2009-12-28 02:37:00 +03:00
|
|
|
u64 (*map_ip)(struct map *, u64);
|
perf annotate: Fix it for non-prelinked *.so
The problem was we were incorrectly calculating objdump
addresses for sym->start and sym->end, look:
For simple ET_DYN type DSO (*.so) with one function, objdump -dS
output is something like this:
000004ac <my_strlen>:
int my_strlen(const char *s)
4ac: 55 push %ebp
4ad: 89 e5 mov %esp,%ebp
4af: 83 ec 10 sub $0x10,%esp
{
i.e. we have relative-to-dso-mapping IPs (=RIP) there.
For ET_EXEC type and probably for prelinked libs as well (sorry
can't test - I don't use prelink) objdump outputs absolute IPs,
e.g.
08048604 <zz_strlen>:
extern "C"
int zz_strlen(const char *s)
8048604: 55 push %ebp
8048605: 89 e5 mov %esp,%ebp
8048607: 83 ec 10 sub $0x10,%esp
{
So, if sym->start is always relative to dso mapping(*), we'll
have to unmap it for ET_EXEC like cases, and leave as is for
ET_DYN cases.
(*) and it is - we've explicitely made it relative. Look for
adjust_symbols handling in dso__load_sym()
Previously we were always unmapping sym->start and for ET_DYN
dsos resulting addresses were wrong, and so objdump output was
empty.
The end result was that perf annotate output for symbols from
non-prelinked *.so had always 0.00% percents only, which is
wrong.
To fix it, let's introduce a helper for converting rip to
objdump address, and also let's document what map_ip() and
unmap_ip() do -- I had to study sources for several hours to
understand it.
Signed-off-by: Kirill Smelkov <kirr@landau.phys.spbu.ru>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Mike Galbraith <efault@gmx.de>
LKML-Reference: <1265223128-11786-8-git-send-email-acme@infradead.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-02-03 21:52:07 +03:00
|
|
|
/* dso rip -> ip */
|
2009-12-28 02:37:00 +03:00
|
|
|
u64 (*unmap_ip)(struct map *, u64);
|
perf annotate: Fix it for non-prelinked *.so
The problem was we were incorrectly calculating objdump
addresses for sym->start and sym->end, look:
For simple ET_DYN type DSO (*.so) with one function, objdump -dS
output is something like this:
000004ac <my_strlen>:
int my_strlen(const char *s)
4ac: 55 push %ebp
4ad: 89 e5 mov %esp,%ebp
4af: 83 ec 10 sub $0x10,%esp
{
i.e. we have relative-to-dso-mapping IPs (=RIP) there.
For ET_EXEC type and probably for prelinked libs as well (sorry
can't test - I don't use prelink) objdump outputs absolute IPs,
e.g.
08048604 <zz_strlen>:
extern "C"
int zz_strlen(const char *s)
8048604: 55 push %ebp
8048605: 89 e5 mov %esp,%ebp
8048607: 83 ec 10 sub $0x10,%esp
{
So, if sym->start is always relative to dso mapping(*), we'll
have to unmap it for ET_EXEC like cases, and leave as is for
ET_DYN cases.
(*) and it is - we've explicitely made it relative. Look for
adjust_symbols handling in dso__load_sym()
Previously we were always unmapping sym->start and for ET_DYN
dsos resulting addresses were wrong, and so objdump output was
empty.
The end result was that perf annotate output for symbols from
non-prelinked *.so had always 0.00% percents only, which is
wrong.
To fix it, let's introduce a helper for converting rip to
objdump address, and also let's document what map_ip() and
unmap_ip() do -- I had to study sources for several hours to
understand it.
Signed-off-by: Kirill Smelkov <kirr@landau.phys.spbu.ru>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Mike Galbraith <efault@gmx.de>
LKML-Reference: <1265223128-11786-8-git-send-email-acme@infradead.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-02-03 21:52:07 +03:00
|
|
|
|
2009-12-28 02:37:00 +03:00
|
|
|
struct dso *dso;
|
|
|
|
};
|
|
|
|
|
2010-02-03 21:52:00 +03:00
|
|
|
struct kmap {
|
|
|
|
struct ref_reloc_sym *ref_reloc_sym;
|
|
|
|
struct map_groups *kmaps;
|
|
|
|
};
|
|
|
|
|
|
|
|
static inline struct kmap *map__kmap(struct map *self)
|
|
|
|
{
|
|
|
|
return (struct kmap *)(self + 1);
|
|
|
|
}
|
|
|
|
|
2009-12-28 02:37:00 +03:00
|
|
|
static inline u64 map__map_ip(struct map *map, u64 ip)
|
|
|
|
{
|
|
|
|
return ip - map->start + map->pgoff;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u64 map__unmap_ip(struct map *map, u64 ip)
|
|
|
|
{
|
|
|
|
return ip + map->start - map->pgoff;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u64 identity__map_ip(struct map *map __used, u64 ip)
|
|
|
|
{
|
|
|
|
return ip;
|
|
|
|
}
|
|
|
|
|
perf annotate: Fix it for non-prelinked *.so
The problem was we were incorrectly calculating objdump
addresses for sym->start and sym->end, look:
For simple ET_DYN type DSO (*.so) with one function, objdump -dS
output is something like this:
000004ac <my_strlen>:
int my_strlen(const char *s)
4ac: 55 push %ebp
4ad: 89 e5 mov %esp,%ebp
4af: 83 ec 10 sub $0x10,%esp
{
i.e. we have relative-to-dso-mapping IPs (=RIP) there.
For ET_EXEC type and probably for prelinked libs as well (sorry
can't test - I don't use prelink) objdump outputs absolute IPs,
e.g.
08048604 <zz_strlen>:
extern "C"
int zz_strlen(const char *s)
8048604: 55 push %ebp
8048605: 89 e5 mov %esp,%ebp
8048607: 83 ec 10 sub $0x10,%esp
{
So, if sym->start is always relative to dso mapping(*), we'll
have to unmap it for ET_EXEC like cases, and leave as is for
ET_DYN cases.
(*) and it is - we've explicitely made it relative. Look for
adjust_symbols handling in dso__load_sym()
Previously we were always unmapping sym->start and for ET_DYN
dsos resulting addresses were wrong, and so objdump output was
empty.
The end result was that perf annotate output for symbols from
non-prelinked *.so had always 0.00% percents only, which is
wrong.
To fix it, let's introduce a helper for converting rip to
objdump address, and also let's document what map_ip() and
unmap_ip() do -- I had to study sources for several hours to
understand it.
Signed-off-by: Kirill Smelkov <kirr@landau.phys.spbu.ru>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Mike Galbraith <efault@gmx.de>
LKML-Reference: <1265223128-11786-8-git-send-email-acme@infradead.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-02-03 21:52:07 +03:00
|
|
|
|
perf top: Fix annotate for userspace
First, for programs and prelinked libraries, annotate code was
fooled by objdump output IPs (src->eip in the code) being
wrongly converted to absolute IPs. In such case there were no
conversion needed, but in
src->eip = strtoull(src->line, NULL, 16);
src->eip = map->unmap_ip(map, src->eip); // = eip + map->start - map->pgoff
we were reading absolute address from objdump (e.g. 8048604) and
then almost doubling it, because eip & map->start are
approximately close for small programs.
Needless to say, that later, in record_precise_ip() there was no
matching with real runtime IPs.
And second, like with `perf annotate` the problem with
non-prelinked *.so was that we were doing rip -> objdump address
conversion wrong.
Also, because unlike `perf annotate`, `perf top` code does
annotation based on absolute IPs for performance reasons(*), new
helper for mapping objdump addresse to IP is introduced.
(*) we get samples info in absolute IPs, and since we do lots of
hit-testing on absolute IPs at runtime in record_precise_ip(), it's
better to convert objdump addresses to IPs once and do no conversion
at runtime.
I also had to fix how objdump output is parsed (with hardcoded
8/16 characters format, which was inappropriate for ET_DYN dsos
with small addresses like '4ac')
Also note, that not all objdump output lines has associtated
IPs, e.g. look at source lines here:
000004ac <my_strlen>:
extern "C"
int my_strlen(const char *s)
4ac: 55 push %ebp
4ad: 89 e5 mov %esp,%ebp
4af: 83 ec 10 sub $0x10,%esp
{
int len = 0;
4b2: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%ebp)
4b9: eb 08 jmp 4c3 <my_strlen+0x17>
while (*s) {
++len;
4bb: 83 45 fc 01 addl $0x1,-0x4(%ebp)
++s;
4bf: 83 45 08 01 addl $0x1,0x8(%ebp)
So we mark them with eip=0, and ignore such lines in annotate
lookup code.
Signed-off-by: Kirill Smelkov <kirr@landau.phys.spbu.ru>
[ Note: one hunk of this patch was applied by Mike in 57d8188 ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Mike Galbraith <efault@gmx.de>
LKML-Reference: <1265550376-12665-1-git-send-email-acme@infradead.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-02-07 16:46:15 +03:00
|
|
|
/* rip/ip <-> addr suitable for passing to `objdump --start-address=` */
|
perf annotate: Fix it for non-prelinked *.so
The problem was we were incorrectly calculating objdump
addresses for sym->start and sym->end, look:
For simple ET_DYN type DSO (*.so) with one function, objdump -dS
output is something like this:
000004ac <my_strlen>:
int my_strlen(const char *s)
4ac: 55 push %ebp
4ad: 89 e5 mov %esp,%ebp
4af: 83 ec 10 sub $0x10,%esp
{
i.e. we have relative-to-dso-mapping IPs (=RIP) there.
For ET_EXEC type and probably for prelinked libs as well (sorry
can't test - I don't use prelink) objdump outputs absolute IPs,
e.g.
08048604 <zz_strlen>:
extern "C"
int zz_strlen(const char *s)
8048604: 55 push %ebp
8048605: 89 e5 mov %esp,%ebp
8048607: 83 ec 10 sub $0x10,%esp
{
So, if sym->start is always relative to dso mapping(*), we'll
have to unmap it for ET_EXEC like cases, and leave as is for
ET_DYN cases.
(*) and it is - we've explicitely made it relative. Look for
adjust_symbols handling in dso__load_sym()
Previously we were always unmapping sym->start and for ET_DYN
dsos resulting addresses were wrong, and so objdump output was
empty.
The end result was that perf annotate output for symbols from
non-prelinked *.so had always 0.00% percents only, which is
wrong.
To fix it, let's introduce a helper for converting rip to
objdump address, and also let's document what map_ip() and
unmap_ip() do -- I had to study sources for several hours to
understand it.
Signed-off-by: Kirill Smelkov <kirr@landau.phys.spbu.ru>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Mike Galbraith <efault@gmx.de>
LKML-Reference: <1265223128-11786-8-git-send-email-acme@infradead.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-02-03 21:52:07 +03:00
|
|
|
u64 map__rip_2objdump(struct map *map, u64 rip);
|
perf top: Fix annotate for userspace
First, for programs and prelinked libraries, annotate code was
fooled by objdump output IPs (src->eip in the code) being
wrongly converted to absolute IPs. In such case there were no
conversion needed, but in
src->eip = strtoull(src->line, NULL, 16);
src->eip = map->unmap_ip(map, src->eip); // = eip + map->start - map->pgoff
we were reading absolute address from objdump (e.g. 8048604) and
then almost doubling it, because eip & map->start are
approximately close for small programs.
Needless to say, that later, in record_precise_ip() there was no
matching with real runtime IPs.
And second, like with `perf annotate` the problem with
non-prelinked *.so was that we were doing rip -> objdump address
conversion wrong.
Also, because unlike `perf annotate`, `perf top` code does
annotation based on absolute IPs for performance reasons(*), new
helper for mapping objdump addresse to IP is introduced.
(*) we get samples info in absolute IPs, and since we do lots of
hit-testing on absolute IPs at runtime in record_precise_ip(), it's
better to convert objdump addresses to IPs once and do no conversion
at runtime.
I also had to fix how objdump output is parsed (with hardcoded
8/16 characters format, which was inappropriate for ET_DYN dsos
with small addresses like '4ac')
Also note, that not all objdump output lines has associtated
IPs, e.g. look at source lines here:
000004ac <my_strlen>:
extern "C"
int my_strlen(const char *s)
4ac: 55 push %ebp
4ad: 89 e5 mov %esp,%ebp
4af: 83 ec 10 sub $0x10,%esp
{
int len = 0;
4b2: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%ebp)
4b9: eb 08 jmp 4c3 <my_strlen+0x17>
while (*s) {
++len;
4bb: 83 45 fc 01 addl $0x1,-0x4(%ebp)
++s;
4bf: 83 45 08 01 addl $0x1,0x8(%ebp)
So we mark them with eip=0, and ignore such lines in annotate
lookup code.
Signed-off-by: Kirill Smelkov <kirr@landau.phys.spbu.ru>
[ Note: one hunk of this patch was applied by Mike in 57d8188 ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Mike Galbraith <efault@gmx.de>
LKML-Reference: <1265550376-12665-1-git-send-email-acme@infradead.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-02-07 16:46:15 +03:00
|
|
|
u64 map__objdump_2ip(struct map *map, u64 addr);
|
perf annotate: Fix it for non-prelinked *.so
The problem was we were incorrectly calculating objdump
addresses for sym->start and sym->end, look:
For simple ET_DYN type DSO (*.so) with one function, objdump -dS
output is something like this:
000004ac <my_strlen>:
int my_strlen(const char *s)
4ac: 55 push %ebp
4ad: 89 e5 mov %esp,%ebp
4af: 83 ec 10 sub $0x10,%esp
{
i.e. we have relative-to-dso-mapping IPs (=RIP) there.
For ET_EXEC type and probably for prelinked libs as well (sorry
can't test - I don't use prelink) objdump outputs absolute IPs,
e.g.
08048604 <zz_strlen>:
extern "C"
int zz_strlen(const char *s)
8048604: 55 push %ebp
8048605: 89 e5 mov %esp,%ebp
8048607: 83 ec 10 sub $0x10,%esp
{
So, if sym->start is always relative to dso mapping(*), we'll
have to unmap it for ET_EXEC like cases, and leave as is for
ET_DYN cases.
(*) and it is - we've explicitely made it relative. Look for
adjust_symbols handling in dso__load_sym()
Previously we were always unmapping sym->start and for ET_DYN
dsos resulting addresses were wrong, and so objdump output was
empty.
The end result was that perf annotate output for symbols from
non-prelinked *.so had always 0.00% percents only, which is
wrong.
To fix it, let's introduce a helper for converting rip to
objdump address, and also let's document what map_ip() and
unmap_ip() do -- I had to study sources for several hours to
understand it.
Signed-off-by: Kirill Smelkov <kirr@landau.phys.spbu.ru>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Mike Galbraith <efault@gmx.de>
LKML-Reference: <1265223128-11786-8-git-send-email-acme@infradead.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-02-03 21:52:07 +03:00
|
|
|
|
2009-12-28 02:37:00 +03:00
|
|
|
struct symbol;
|
|
|
|
|
|
|
|
typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
|
|
|
|
|
|
|
|
void map__init(struct map *self, enum map_type type,
|
|
|
|
u64 start, u64 end, u64 pgoff, struct dso *dso);
|
2010-03-26 01:58:57 +03:00
|
|
|
struct map *map__new(u64 start, u64 len, u64 pgoff, u32 pid, char *filename,
|
|
|
|
enum map_type type, char *cwd, int cwdlen);
|
2009-12-28 02:37:00 +03:00
|
|
|
void map__delete(struct map *self);
|
|
|
|
struct map *map__clone(struct map *self);
|
|
|
|
int map__overlap(struct map *l, struct map *r);
|
|
|
|
size_t map__fprintf(struct map *self, FILE *fp);
|
|
|
|
|
2010-02-03 21:52:00 +03:00
|
|
|
int map__load(struct map *self, symbol_filter_t filter);
|
|
|
|
struct symbol *map__find_symbol(struct map *self,
|
2009-12-28 02:37:00 +03:00
|
|
|
u64 addr, symbol_filter_t filter);
|
|
|
|
struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
|
|
|
|
symbol_filter_t filter);
|
|
|
|
void map__fixup_start(struct map *self);
|
|
|
|
void map__fixup_end(struct map *self);
|
|
|
|
|
2010-02-03 21:52:00 +03:00
|
|
|
void map__reloc_vmlinux(struct map *self);
|
|
|
|
|
2010-03-26 01:58:58 +03:00
|
|
|
struct map_groups {
|
|
|
|
struct rb_root maps[MAP__NR_TYPES];
|
|
|
|
struct list_head removed_maps[MAP__NR_TYPES];
|
|
|
|
};
|
|
|
|
|
|
|
|
size_t __map_groups__fprintf_maps(struct map_groups *self,
|
2010-03-26 18:11:06 +03:00
|
|
|
enum map_type type, int verbose, FILE *fp);
|
2010-03-26 01:58:58 +03:00
|
|
|
void maps__insert(struct rb_root *maps, struct map *map);
|
|
|
|
struct map *maps__find(struct rb_root *maps, u64 addr);
|
|
|
|
void map_groups__init(struct map_groups *self);
|
2010-03-26 18:11:06 +03:00
|
|
|
int map_groups__clone(struct map_groups *self,
|
|
|
|
struct map_groups *parent, enum map_type type);
|
|
|
|
size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp);
|
|
|
|
size_t map_groups__fprintf_maps(struct map_groups *self, int verbose, FILE *fp);
|
2010-03-26 01:58:58 +03:00
|
|
|
|
|
|
|
static inline void map_groups__insert(struct map_groups *self, struct map *map)
|
|
|
|
{
|
|
|
|
maps__insert(&self->maps[map->type], map);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline struct map *map_groups__find(struct map_groups *self,
|
|
|
|
enum map_type type, u64 addr)
|
|
|
|
{
|
|
|
|
return maps__find(&self->maps[type], addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct symbol *map_groups__find_symbol(struct map_groups *self,
|
|
|
|
enum map_type type, u64 addr,
|
|
|
|
symbol_filter_t filter);
|
|
|
|
|
|
|
|
static inline struct symbol *map_groups__find_function(struct map_groups *self,
|
|
|
|
u64 addr,
|
|
|
|
symbol_filter_t filter)
|
|
|
|
{
|
|
|
|
return map_groups__find_symbol(self, MAP__FUNCTION, addr, filter);
|
|
|
|
}
|
|
|
|
|
2010-03-26 18:11:06 +03:00
|
|
|
int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
|
|
|
|
int verbose, FILE *fp);
|
|
|
|
|
2010-03-26 01:58:58 +03:00
|
|
|
struct map *map_groups__find_by_name(struct map_groups *self,
|
|
|
|
enum map_type type, const char *name);
|
|
|
|
int __map_groups__create_kernel_maps(struct map_groups *self,
|
|
|
|
struct map *vmlinux_maps[MAP__NR_TYPES],
|
|
|
|
struct dso *kernel);
|
|
|
|
int map_groups__create_kernel_maps(struct map_groups *self,
|
|
|
|
struct map *vmlinux_maps[MAP__NR_TYPES]);
|
|
|
|
struct map *map_groups__new_module(struct map_groups *self, u64 start,
|
|
|
|
const char *filename);
|
2010-03-26 18:11:06 +03:00
|
|
|
void map_groups__flush(struct map_groups *self);
|
2010-03-26 01:58:58 +03:00
|
|
|
|
2009-12-28 02:37:00 +03:00
|
|
|
#endif /* __PERF_MAP_H */
|