diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 3ff829d89178..c299881c640a 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -273,11 +273,27 @@ bool ins__is_call(const struct ins *ins) return ins->ops == &call_ops || ins->ops == &s390_call_ops; } -static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map_symbol *ms __maybe_unused) +static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map_symbol *ms) { + struct map *map = ms->map; + struct symbol *sym = ms->sym; + struct addr_map_symbol target = { + .map = map, + }; const char *s = strchr(ops->raw, '+'); const char *c = strchr(ops->raw, ','); - + u64 start, end; + /* + * Examples of lines to parse for the _cpp_lex_token@@Base + * function: + * + * 1159e6c: jne 115aa32 <_cpp_lex_token@@Base+0xf92> + * 1159e8b: jne c469be + * + * The first is a jump to an offset inside the same function, + * the second is to another function, i.e. that 0xa72 is an + * offset in the cpp_named_operator2name@@base function. + */ /* * skip over possible up to 2 operands to get to address, e.g.: * tbnz w0, #26, ffff0000083cd190 @@ -293,6 +309,35 @@ static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *op ops->target.addr = strtoull(ops->raw, NULL, 16); } + target.addr = map__objdump_2mem(map, ops->target.addr); + start = map->unmap_ip(map, sym->start), + end = map->unmap_ip(map, sym->end); + + ops->target.outside = target.addr < start || target.addr > end; + + /* + * FIXME: things like this in _cpp_lex_token (gcc's cc1 program): + + cpp_named_operator2name@@Base+0xa72 + + * Point to a place that is after the cpp_named_operator2name + * boundaries, i.e. in the ELF symbol table for cc1 + * cpp_named_operator2name is marked as being 32-bytes long, but it in + * fact is much larger than that, so we seem to need a symbols__find() + * routine that looks for >= current->start and < next_symbol->start, + * possibly just for C++ objects? + * + * For now lets just make some progress by marking jumps to outside the + * current function as call like. + * + * Actual navigation will come next, with further understanding of how + * the symbol searching and disassembly should be done. + + if (map_groups__find_ams(&target) == 0 && + map__rip_2objdump(target.map, map->map_ip(target.map, target.addr)) == ops->target.addr) + ops->target.sym = target.sym; + */ + if (s++ != NULL) { ops->target.offset = strtoull(s, NULL, 16); ops->target.offset_avail = true; @@ -2355,11 +2400,15 @@ static void disasm_line__write(struct disasm_line *dl, struct annotation *notes, { if (dl->ins.ops && dl->ins.ops->scnprintf) { if (ins__is_jump(&dl->ins)) { - bool fwd = dl->ops.target.offset > dl->al.offset; + bool fwd; + if (dl->ops.target.outside) + goto call_like; + fwd = dl->ops.target.offset > dl->al.offset; obj__write_graph(obj, fwd ? DARROW_CHAR : UARROW_CHAR); obj__printf(obj, " "); } else if (ins__is_call(&dl->ins)) { +call_like: obj__write_graph(obj, RARROW_CHAR); obj__printf(obj, " "); } else if (ins__is_ret(&dl->ins)) { diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index c0bf0554a9ea..ad8baafaf9f9 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -28,6 +28,7 @@ struct ins_operands { u64 addr; s64 offset; bool offset_avail; + bool outside; } target; union { struct {