Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 182347
b: refs/heads/master
c: 56b03f3
h: refs/heads/master
i:
  182345: 3128e41
  182343: ba8eaf9
v: v3
  • Loading branch information
Arnaldo Carvalho de Melo authored and Ingo Molnar committed Jan 13, 2010
1 parent ff679be commit 4517745
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 6 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: b9a63b9b56d6910a25e3d4905525aef150420a9b
refs/heads/master: 56b03f3c4d641dbdbce2e52a2969712e85b0e030
7 changes: 7 additions & 0 deletions trunk/tools/perf/builtin-record.c
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,13 @@ static int __cmd_record(int argc, const char **argv)
return err;
}

err = event__synthesize_kernel_mmap(process_synthesized_event,
session, "_text");
if (err < 0) {
pr_err("Couldn't record kernel reference relocation symbol.\n");
return err;
}

if (!system_wide && profile_cpu == -1)
event__synthesize_thread(pid, process_synthesized_event,
session);
Expand Down
64 changes: 61 additions & 3 deletions trunk/tools/perf/util/event.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,50 @@ void event__synthesize_threads(int (*process)(event_t *event,
closedir(proc);
}

struct process_symbol_args {
const char *name;
u64 start;
};

static int find_symbol_cb(void *arg, const char *name, char type, u64 start)
{
struct process_symbol_args *args = arg;

if (!symbol_type__is_a(type, MAP__FUNCTION) || strcmp(name, args->name))
return 0;

args->start = start;
return 1;
}

int event__synthesize_kernel_mmap(int (*process)(event_t *event,
struct perf_session *session),
struct perf_session *session,
const char *symbol_name)
{
size_t size;
event_t ev = {
.header = { .type = PERF_RECORD_MMAP },
};
/*
* We should get this from /sys/kernel/sections/.text, but till that is
* available use this, and after it is use this as a fallback for older
* kernels.
*/
struct process_symbol_args args = { .name = symbol_name, };

if (kallsyms__parse(&args, find_symbol_cb) <= 0)
return -ENOENT;

size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename),
"[kernel.kallsyms.%s]", symbol_name) + 1;
size = ALIGN(size, sizeof(u64));
ev.mmap.header.size = (sizeof(ev.mmap) - (sizeof(ev.mmap.filename) - size));
ev.mmap.start = args.start;

return process(&ev, session);
}

static void thread__comm_adjust(struct thread *self)
{
char *comm = self->comm;
Expand Down Expand Up @@ -240,9 +284,9 @@ int event__process_lost(event_t *self, struct perf_session *session)

int event__process_mmap(event_t *self, struct perf_session *session)
{
struct thread *thread = perf_session__findnew(session, self->mmap.pid);
struct map *map = map__new(&self->mmap, MAP__FUNCTION,
session->cwd, session->cwdlen);
struct thread *thread;
struct map *map;
static const char kmmap_prefix[] = "[kernel.kallsyms.";

dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n",
self->mmap.pid, self->mmap.tid,
Expand All @@ -251,6 +295,20 @@ int event__process_mmap(event_t *self, struct perf_session *session)
(void *)(long)self->mmap.pgoff,
self->mmap.filename);

if (self->mmap.pid == 0 &&
memcmp(self->mmap.filename, kmmap_prefix,
sizeof(kmmap_prefix) - 1) == 0) {
const char *symbol_name = (self->mmap.filename +
sizeof(kmmap_prefix) - 1);
perf_session__set_kallsyms_ref_reloc_sym(session, symbol_name,
self->mmap.start);
return 0;
}

thread = perf_session__findnew(session, self->mmap.pid);
map = map__new(&self->mmap, MAP__FUNCTION,
session->cwd, session->cwdlen);

if (thread == NULL || map == NULL)
dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
else
Expand Down
4 changes: 4 additions & 0 deletions trunk/tools/perf/util/event.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ int event__synthesize_thread(pid_t pid,
void event__synthesize_threads(int (*process)(event_t *event,
struct perf_session *session),
struct perf_session *session);
int event__synthesize_kernel_mmap(int (*process)(event_t *event,
struct perf_session *session),
struct perf_session *session,
const char *symbol_name);

int event__process_comm(event_t *self, struct perf_session *session);
int event__process_lost(event_t *self, struct perf_session *session);
Expand Down
46 changes: 46 additions & 0 deletions trunk/tools/perf/util/session.c
Original file line number Diff line number Diff line change
Expand Up @@ -401,3 +401,49 @@ bool perf_session__has_traces(struct perf_session *self, const char *msg)

return true;
}

int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self,
const char *symbol_name,
u64 addr)
{
char *bracket;

self->ref_reloc_sym.name = strdup(symbol_name);
if (self->ref_reloc_sym.name == NULL)
return -ENOMEM;

bracket = strchr(self->ref_reloc_sym.name, ']');
if (bracket)
*bracket = '\0';

self->ref_reloc_sym.addr = addr;
return 0;
}

static u64 map__reloc_map_ip(struct map *map, u64 ip)
{
return ip + (s64)map->pgoff;
}

static u64 map__reloc_unmap_ip(struct map *map, u64 ip)
{
return ip - (s64)map->pgoff;
}

void perf_session__reloc_vmlinux_maps(struct perf_session *self,
u64 unrelocated_addr)
{
enum map_type type;
s64 reloc = unrelocated_addr - self->ref_reloc_sym.addr;

if (!reloc)
return;

for (type = 0; type < MAP__NR_TYPES; ++type) {
struct map *map = self->vmlinux_maps[type];

map->map_ip = map__reloc_map_ip;
map->unmap_ip = map__reloc_unmap_ip;
map->pgoff = reloc;
}
}
10 changes: 10 additions & 0 deletions trunk/tools/perf/util/session.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ struct perf_session {
unsigned long unknown_events;
struct rb_root hists;
u64 sample_type;
struct {
const char *name;
u64 addr;
} ref_reloc_sym;
int fd;
int cwdlen;
char *cwd;
Expand Down Expand Up @@ -59,4 +63,10 @@ bool perf_session__has_traces(struct perf_session *self, const char *msg);

int perf_header__read_build_ids(int input, u64 offset, u64 file_size);

int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self,
const char *symbol_name,
u64 addr);
void perf_session__reloc_vmlinux_maps(struct perf_session *self,
u64 unrelocated_addr);

#endif /* __PERF_SESSION_H */
7 changes: 5 additions & 2 deletions trunk/tools/perf/util/symbol.c
Original file line number Diff line number Diff line change
Expand Up @@ -956,11 +956,15 @@ static int dso__load_sym(struct dso *self, struct map *map,

elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
struct symbol *f;
const char *elf_name;
const char *elf_name = elf_sym__name(&sym, symstrs);
char *demangled = NULL;
int is_label = elf_sym__is_label(&sym);
const char *section_name;

if (kernel && session->ref_reloc_sym.name != NULL &&
strcmp(elf_name, session->ref_reloc_sym.name) == 0)
perf_session__reloc_vmlinux_maps(session, sym.st_value);

if (!is_label && !elf_sym__is_a(&sym, map->type))
continue;

Expand All @@ -973,7 +977,6 @@ static int dso__load_sym(struct dso *self, struct map *map,
if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
continue;

elf_name = elf_sym__name(&sym, symstrs);
section_name = elf_sec__name(&shdr, secstrs);

if (kernel || kmodule) {
Expand Down

0 comments on commit 4517745

Please sign in to comment.