diff options
author | Ingo Molnar <mingo@kernel.org> | 2016-11-25 18:12:41 +0100 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-11-25 18:12:41 +0100 |
commit | 2471cece40d61b0035360338569d338f9dea6099 (patch) | |
tree | 809f1d14defbc82fc6a957597b8b0bcb6600faed /tools/perf/util/annotate.c | |
parent | 47414424c53a70eceb0fc6e0a35a31a2b763d5b2 (diff) | |
parent | 4708bbda5cb2f6cdc331744597527143f46394d5 (diff) |
Merge tag 'perf-core-for-mingo-20161125' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
New features:
- Improve ARM support in the annotation code, affecting 'perf annotate', 'perf
report' and live annotation in 'perf top' (Kim Phillips)
- Initial support for PowerPC in the annotation code (Ravi Bangoria)
- Skip repetitive scheduler function on the top of the stack in
'perf sched timehist' (Namhyung Kim)
Fixes:
- Fix maps resolution in libbpf (Eric Leblond)
- Get the kernel signature via /proc/version_signature, available on
Ubuntu systems, to make sure BPF proggies works, as the one provided
via 'uname -r' doesn't (Wang Nan)
- Fix segfault in 'perf record' when running with suid and kptr_restrict
is 1 (Wang Nan)
Infrastructure changes:
- Support per-arch instruction tables, kept via a static or dynamic table
(Arnaldo Carvalho de Melo)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/perf/util/annotate.c')
-rw-r--r-- | tools/perf/util/annotate.c | 157 |
1 files changed, 112 insertions, 45 deletions
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 095d90a9077f..3e34ee0fde28 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -28,14 +28,20 @@ const char *disassembler_style; const char *objdump_path; static regex_t file_lineno; -static struct ins *ins__find(struct arch *arch, const char *name); -static int disasm_line__parse(char *line, char **namep, char **rawp); +static struct ins_ops *ins__find(struct arch *arch, const char *name); +static void ins__sort(struct arch *arch); +static int disasm_line__parse(char *line, const char **namep, char **rawp); struct arch { const char *name; struct ins *instructions; size_t nr_instructions; + size_t nr_instructions_allocated; + struct ins_ops *(*associate_instruction_ops)(struct arch *arch, const char *name); bool sorted_instructions; + bool initialized; + void *priv; + int (*init)(struct arch *arch); struct { char comment_char; char skip_functions_char; @@ -50,18 +56,62 @@ static struct ins_ops nop_ops; static struct ins_ops lock_ops; static struct ins_ops ret_ops; +static int arch__grow_instructions(struct arch *arch) +{ + struct ins *new_instructions; + size_t new_nr_allocated; + + if (arch->nr_instructions_allocated == 0 && arch->instructions) + goto grow_from_non_allocated_table; + + new_nr_allocated = arch->nr_instructions_allocated + 128; + new_instructions = realloc(arch->instructions, new_nr_allocated * sizeof(struct ins)); + if (new_instructions == NULL) + return -1; + +out_update_instructions: + arch->instructions = new_instructions; + arch->nr_instructions_allocated = new_nr_allocated; + return 0; + +grow_from_non_allocated_table: + new_nr_allocated = arch->nr_instructions + 128; + new_instructions = calloc(new_nr_allocated, sizeof(struct ins)); + if (new_instructions == NULL) + return -1; + + memcpy(new_instructions, arch->instructions, arch->nr_instructions); + goto out_update_instructions; +} + +static int arch__associate_ins_ops(struct arch* arch, const char *name, struct ins_ops *ops) +{ + struct ins *ins; + + if (arch->nr_instructions == arch->nr_instructions_allocated && + arch__grow_instructions(arch)) + return -1; + + ins = &arch->instructions[arch->nr_instructions]; + ins->name = strdup(name); + if (!ins->name) + return -1; + + ins->ops = ops; + arch->nr_instructions++; + + ins__sort(arch); + return 0; +} + #include "arch/arm/annotate/instructions.c" #include "arch/x86/annotate/instructions.c" +#include "arch/powerpc/annotate/instructions.c" static struct arch architectures[] = { { .name = "arm", - .instructions = arm__instructions, - .nr_instructions = ARRAY_SIZE(arm__instructions), - .objdump = { - .comment_char = ';', - .skip_functions_char = '+', - }, + .init = arm__annotate_init, }, { .name = "x86", @@ -71,6 +121,10 @@ static struct arch architectures[] = { .comment_char = '#', }, }, + { + .name = "powerpc", + .init = powerpc__annotate_init, + }, }; static void ins__delete(struct ins_operands *ops) @@ -218,26 +272,20 @@ static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep) static int lock__parse(struct arch *arch, struct ins_operands *ops, struct map *map) { - char *name; - ops->locked.ops = zalloc(sizeof(*ops->locked.ops)); if (ops->locked.ops == NULL) return 0; - if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0) + if (disasm_line__parse(ops->raw, &ops->locked.ins.name, &ops->locked.ops->raw) < 0) goto out_free_ops; - ops->locked.ins = ins__find(arch, name); - free(name); + ops->locked.ins.ops = ins__find(arch, ops->locked.ins.name); - if (ops->locked.ins == NULL) + if (ops->locked.ins.ops == NULL) goto out_free_ops; - if (!ops->locked.ins->ops) - return 0; - - if (ops->locked.ins->ops->parse && - ops->locked.ins->ops->parse(arch, ops->locked.ops, map) < 0) + if (ops->locked.ins.ops->parse && + ops->locked.ins.ops->parse(arch, ops->locked.ops, map) < 0) goto out_free_ops; return 0; @@ -252,19 +300,19 @@ static int lock__scnprintf(struct ins *ins, char *bf, size_t size, { int printed; - if (ops->locked.ins == NULL) + if (ops->locked.ins.ops == NULL) return ins__raw_scnprintf(ins, bf, size, ops); printed = scnprintf(bf, size, "%-6.6s ", ins->name); - return printed + ins__scnprintf(ops->locked.ins, bf + printed, + return printed + ins__scnprintf(&ops->locked.ins, bf + printed, size - printed, ops->locked.ops); } static void lock__delete(struct ins_operands *ops) { - struct ins *ins = ops->locked.ins; + struct ins *ins = &ops->locked.ins; - if (ins && ins->ops->free) + if (ins->ops && ins->ops->free) ins->ops->free(ops->locked.ops); else ins__delete(ops->locked.ops); @@ -425,8 +473,9 @@ static void ins__sort(struct arch *arch) qsort(arch->instructions, nmemb, sizeof(struct ins), ins__cmp); } -static struct ins *ins__find(struct arch *arch, const char *name) +static struct ins_ops *__ins__find(struct arch *arch, const char *name) { + struct ins *ins; const int nmemb = arch->nr_instructions; if (!arch->sorted_instructions) { @@ -434,7 +483,18 @@ static struct ins *ins__find(struct arch *arch, const char *name) arch->sorted_instructions = true; } - return bsearch(name, arch->instructions, nmemb, sizeof(struct ins), ins__key_cmp); + ins = bsearch(name, arch->instructions, nmemb, sizeof(struct ins), ins__key_cmp); + return ins ? ins->ops : NULL; +} + +static struct ins_ops *ins__find(struct arch *arch, const char *name) +{ + struct ins_ops *ops = __ins__find(arch, name); + + if (!ops && arch->associate_instruction_ops) + ops = arch->associate_instruction_ops(arch, name); + + return ops; } static int arch__key_cmp(const void *name, const void *archp) @@ -691,19 +751,16 @@ int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip) static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, struct map *map) { - dl->ins = ins__find(arch, dl->name); + dl->ins.ops = ins__find(arch, dl->ins.name); - if (dl->ins == NULL) + if (!dl->ins.ops) return; - if (!dl->ins->ops) - return; - - if (dl->ins->ops->parse && dl->ins->ops->parse(arch, &dl->ops, map) < 0) - dl->ins = NULL; + if (dl->ins.ops->parse && dl->ins.ops->parse(arch, &dl->ops, map) < 0) + dl->ins.ops = NULL; } -static int disasm_line__parse(char *line, char **namep, char **rawp) +static int disasm_line__parse(char *line, const char **namep, char **rawp) { char *name = line, tmp; @@ -736,7 +793,8 @@ static int disasm_line__parse(char *line, char **namep, char **rawp) return 0; out_free_name: - zfree(namep); + free((void *)namep); + *namep = NULL; return -1; } @@ -755,7 +813,7 @@ static struct disasm_line *disasm_line__new(s64 offset, char *line, goto out_delete; if (offset != -1) { - if (disasm_line__parse(dl->line, &dl->name, &dl->ops.raw) < 0) + if (disasm_line__parse(dl->line, &dl->ins.name, &dl->ops.raw) < 0) goto out_free_line; disasm_line__init_ins(dl, arch, map); @@ -774,20 +832,21 @@ out_delete: void disasm_line__free(struct disasm_line *dl) { zfree(&dl->line); - zfree(&dl->name); - if (dl->ins && dl->ins->ops->free) - dl->ins->ops->free(&dl->ops); + if (dl->ins.ops && dl->ins.ops->free) + dl->ins.ops->free(&dl->ops); else ins__delete(&dl->ops); + free((void *)dl->ins.name); + dl->ins.name = NULL; free(dl); } int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw) { - if (raw || !dl->ins) - return scnprintf(bf, size, "%-6.6s %s", dl->name, dl->ops.raw); + if (raw || !dl->ins.ops) + return scnprintf(bf, size, "%-6.6s %s", dl->ins.name, dl->ops.raw); - return ins__scnprintf(dl->ins, bf, size, &dl->ops); + return ins__scnprintf(&dl->ins, bf, size, &dl->ops); } static void disasm__add(struct list_head *head, struct disasm_line *line) @@ -1143,7 +1202,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, map__rip_2objdump(map, sym->start); /* kcore has no symbols, so add the call target name */ - if (dl->ins && ins__is_call(dl->ins) && !dl->ops.target.name) { + if (dl->ins.ops && ins__is_call(&dl->ins) && !dl->ops.target.name) { struct addr_map_symbol target = { .map = map, .addr = dl->ops.target.addr, @@ -1173,8 +1232,8 @@ static void delete_last_nop(struct symbol *sym) while (!list_empty(list)) { dl = list_entry(list->prev, struct disasm_line, node); - if (dl->ins && dl->ins->ops) { - if (dl->ins->ops != &nop_ops) + if (dl->ins.ops) { + if (dl->ins.ops != &nop_ops) return; } else { if (!strstr(dl->line, " nop ") && @@ -1300,6 +1359,14 @@ int symbol__disassemble(struct symbol *sym, struct map *map, const char *arch_na if (arch == NULL) return -ENOTSUP; + if (arch->init) { + err = arch->init(arch); + if (err) { + pr_err("%s: failed to initialize %s arch priv area\n", __func__, arch->name); + return err; + } + } + pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__, symfs_filename, sym->name, map->unmap_ip(map, sym->start), map->unmap_ip(map, sym->end)); @@ -1767,7 +1834,7 @@ static size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp) if (dl->offset == -1) return fprintf(fp, "%s\n", dl->line); - printed = fprintf(fp, "%#" PRIx64 " %s", dl->offset, dl->name); + printed = fprintf(fp, "%#" PRIx64 " %s", dl->offset, dl->ins.name); if (dl->ops.raw[0] != '\0') { printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ", |