// SPDX-License-Identifier: GPL-2.0-only#include <ctype.h>#include <elf.h>#ifndef EF_CSKY_ABIMASK#define EF_CSKY_ABIMASK 0XF0000000#endif#include <errno.h>#include <fcntl.h>#include <inttypes.h>#include <libgen.h>#include <regex.h>#include <stdlib.h>#include <unistd.h> #include <linux/string.h>#include <linux/zalloc.h>#include <subcmd/run-command.h> #include "annotate.h"#include "annotate-data.h"#include "build-id.h"#include "capstone.h"#include "debug.h"#include "disasm.h"#include "dso.h"#include "dwarf-regs.h"#include "env.h"#include "evsel.h"#include "libbfd.h"#include "llvm.h"#include "map.h"#include "maps.h"#include "namespaces.h"#include "srcline.h"#include "symbol.h"#include "thread.h"#include "util.h" static regex_t file_lineno; /* These can be referred from the arch-dependent code */const struct ins_ops call_ops;const struct ins_ops dec_ops;const struct ins_ops jump_ops;const struct ins_ops mov_ops;const struct ins_ops nop_ops;const struct ins_ops lock_ops;const struct ins_ops ret_ops;const struct ins_ops load_store_ops;const struct ins_ops arithmetic_ops; static void ins__sort(struct arch *arch);static int disasm_line__parse(char *line, const char **namep, char **rawp);static int disasm_line__parse_powerpc(struct disasm_line *dl, struct annotate_args *args); static __attribute__((constructor)) void symbol__init_regexpr(void){ regcomp(&file_lineno, "^/[^:]+:([0-9]+)", REG_EXTENDED);} 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((void *)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 * sizeof(struct ins)); goto out_update_instructions;} int arch__associate_ins_ops(struct arch *arch, const char *name, const struct ins_ops *ops){ struct ins *ins; if (arch->nr_instructions == arch->nr_instructions_allocated && arch__grow_instructions(arch)) return -1; ins = (struct 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;} static int e_machine_and_eflags__cmp(const struct e_machine_and_e_flags *val1, const struct e_machine_and_e_flags *val2){ if (val1->e_machine == val2->e_machine) { if (val1->e_machine != EM_CSKY) return 0; if ((val1->e_flags & EF_CSKY_ABIMASK) < (val2->e_flags & EF_CSKY_ABIMASK)) return -1; return (val1->e_flags & EF_CSKY_ABIMASK) > (val2->e_flags & EF_CSKY_ABIMASK); } return val1->e_machine < val2->e_machine ? -1 : 1;} static int arch__key_cmp(const void *key, const void *archp){ const struct arch *const *arch = archp; return e_machine_and_eflags__cmp(key, &(*arch)->id);} static int arch__cmp(const void *a, const void *b){ const struct arch *const *aa = a; const struct arch *const *ab = b; return e_machine_and_eflags__cmp(&(*aa)->id, &(*ab)->id);} const struct arch *arch__find(uint16_t e_machine, uint32_t e_flags, const char *cpuid){ static const struct arch *(*const arch_new_fn[])(const struct e_machine_and_e_flags *id, const char *cpuid) = { [EM_386] = arch__new_x86, [EM_ARC] = arch__new_arc, [EM_ARM] = arch__new_arm, [EM_AARCH64] = arch__new_arm64, [EM_CSKY] = arch__new_csky, [EM_LOONGARCH] = arch__new_loongarch, [EM_MIPS] = arch__new_mips, [EM_PPC64] = arch__new_powerpc, [EM_PPC] = arch__new_powerpc, [EM_RISCV] = arch__new_riscv64, [EM_S390] = arch__new_s390, [EM_SPARC] = arch__new_sparc, [EM_SPARCV9] = arch__new_sparc, [EM_X86_64] = arch__new_x86, }; static const struct arch **archs; static size_t num_archs; struct e_machine_and_e_flags key = { .e_machine = e_machine, .e_flags = e_flags, }; const struct arch *result = NULL, **tmp; if (num_archs > 0) { tmp = bsearch(&key, archs, num_archs, sizeof(*archs), arch__key_cmp); if (tmp) result = *tmp; } if (result) return result; if (e_machine >= ARRAY_SIZE(arch_new_fn) || arch_new_fn[e_machine] == NULL) { errno = ENOTSUP; return NULL; } tmp = reallocarray(archs, num_archs + 1, sizeof(*archs)); if (!tmp) return NULL; archs = tmp; result = arch_new_fn[e_machine](&key, cpuid); if (!result) { pr_err("%s: failed to initialize %u arch priv area\n", __func__, e_machine); return NULL; } archs[num_archs++] = result; qsort(archs, num_archs, sizeof(*archs), arch__cmp); return result;} bool arch__is_x86(const struct arch *arch){ return arch->id.e_machine == EM_386 || arch->id.e_machine == EM_X86_64;} bool arch__is_powerpc(const struct arch *arch){ return arch->id.e_machine == EM_PPC || arch->id.e_machine == EM_PPC64;} static void ins_ops__delete(struct ins_operands *ops){ if (ops == NULL) return; zfree(&ops->source.raw); zfree(&ops->source.name); zfree(&ops->target.raw); zfree(&ops->target.name);} int ins__raw_scnprintf(const struct ins *ins, char *bf, size_t size, struct ins_operands *ops, int max_ins_name){ return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->raw);} int ins__scnprintf(const struct ins *ins, char *bf, size_t size, struct ins_operands *ops, int max_ins_name){ if (ins->ops->scnprintf) return ins->ops->scnprintf(ins, bf, size, ops, max_ins_name); return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name);} bool ins__is_fused(const struct arch *arch, const char *ins1, const char *ins2){ if (!arch || !arch->ins_is_fused) return false; return arch->ins_is_fused(arch, ins1, ins2);} static int call__parse(const struct arch *arch, struct ins_operands *ops, struct map_symbol *ms, struct disasm_line *dl __maybe_unused){ char *endptr, *tok, *name; struct map *map = ms->map; struct addr_map_symbol target; ops->target.addr = strtoull(ops->raw, &endptr, 16); name = strchr(endptr, '<'); if (name == NULL) goto indirect_call; name++; if (arch->objdump.skip_functions_char && strchr(name, arch->objdump.skip_functions_char)) return -1; tok = strchr(name, '>'); if (tok == NULL) return -1; *tok = '\0'; ops->target.name = strdup(name); *tok = '>'; if (ops->target.name == NULL) return -1;find_target: target = (struct addr_map_symbol) { .ms = { .map = map__get(map), }, .addr = map__objdump_2mem(map, ops->target.addr), }; if (maps__find_ams(thread__maps(ms->thread), &target) == 0 && map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr) ops->target.sym = target.ms.sym; addr_map_symbol__exit(&target); return 0; indirect_call: tok = strchr(endptr, '*'); if (tok != NULL) { endptr++; /* Indirect call can use a non-rip register and offset: callq *0x8(%rbx). * Do not parse such instruction. */ if (strstr(endptr, "(%r") == NULL) ops->target.addr = strtoull(endptr, NULL, 16); } goto find_target;} int call__scnprintf(const struct ins *ins, char *bf, size_t size, struct ins_operands *ops, int max_ins_name){ if (ops->target.sym) return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.sym->name); if (ops->target.addr == 0) return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); if (ops->target.name) return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.name); return scnprintf(bf, size, "%-*s *%" PRIx64, max_ins_name, ins->name, ops->target.addr);} const struct ins_ops call_ops = { .parse = call__parse, .scnprintf = call__scnprintf, .is_call = true,}; bool ins__is_call(const struct ins *ins){ return ins->ops && ins->ops->is_call;} /* * Prevents from matching commas in the comment section, e.g.: * ffff200008446e70: b.cs ffff2000084470f4 <generic_exec_single+0x314> // b.hs, b.nlast * * and skip comma as part of function arguments, e.g.: * 1d8b4ac <linemap_lookup(line_maps const*, unsigned int)+0xcc> */static inline const char *validate_comma(const char *c, struct ins_operands *ops){ if (ops->jump.raw_comment && c > ops->jump.raw_comment) return NULL; if (ops->jump.raw_func_start && c > ops->jump.raw_func_start) return NULL; return c;} static int jump__parse(const struct arch *arch, struct ins_operands *ops, struct map_symbol *ms, struct disasm_line *dl __maybe_unused){ struct map *map = ms->map; struct symbol *sym = ms->sym; struct addr_map_symbol target = { .ms = { .map = map__get(map), }, }; const char *c = strchr(ops->raw, ','); u64 start, end; ops->jump.raw_comment = strchr(ops->raw, arch->objdump.comment_char); ops->jump.raw_func_start = strchr(ops->raw, '<'); c = validate_comma(c, ops); /* * Examples of lines to parse for the _cpp_lex_token@@Base * function: * * 1159e6c: jne 115aa32 <_cpp_lex_token@@Base+0xf92> * 1159e8b: jne c469be <cpp_named_operator2name@@Base+0xa72> * * 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 <security_file_permission+0xd0> */ if (c != NULL) { c++; ops->target.addr = strtoull(c, NULL, 16); if (!ops->target.addr) { c = strchr(c, ','); c = validate_comma(c, ops); if (c != NULL) { c++; ops->target.addr = strtoull(c, NULL, 16); } } } else { 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 (maps__find_ams(thread__maps(ms->thread), &target) == 0 && map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr) ops->target.sym = target.ms.sym; if (!ops->target.outside) { ops->target.offset = target.addr - start; ops->target.offset_avail = true; } else { ops->target.offset_avail = false; } addr_map_symbol__exit(&target); return 0;} int jump__scnprintf(const struct ins *ins, char *bf, size_t size, struct ins_operands *ops, int max_ins_name){ const char *c; if (!ops->target.addr || ops->target.offset < 0) return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); if (ops->target.outside && ops->target.sym != NULL) return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.sym->name); c = strchr(ops->raw, ','); c = validate_comma(c, ops); if (c != NULL) { const char *c2 = strchr(c + 1, ','); c2 = validate_comma(c2, ops); /* check for 3-op insn */ if (c2 != NULL) c = c2; c++; /* mirror arch objdump's space-after-comma style */ if (*c == ' ') c++; } return scnprintf(bf, size, "%-*s %.*s%" PRIx64, max_ins_name, ins->name, c ? c - ops->raw : 0, ops->raw, ops->target.offset);} void jump__delete(struct ins_operands *ops __maybe_unused){ /* * The ops->jump.raw_comment and ops->jump.raw_func_start belong to the * raw string, don't free them. */} const struct ins_ops jump_ops = { .free = jump__delete, .parse = jump__parse, .scnprintf = jump__scnprintf, .is_jump = true,}; bool ins__is_jump(const struct ins *ins){ return ins->ops && ins->ops->is_jump;} static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep){ char *endptr, *name, *t; if (strstr(raw, "(%rip)") == NULL) return 0; *addrp = strtoull(comment, &endptr, 16); if (endptr == comment) return 0; name = strchr(endptr, '<'); if (name == NULL) return -1; name++; t = strchr(name, '>'); if (t == NULL) return 0; *t = '\0'; *namep = strdup(name); *t = '>'; return 0;}Lines 1–500 of 1648. Load more
// SPDX-License-Identifier: GPL-2.0-only #include <ctype.h> #include <elf.h> #ifndef EF_CSKY_ABIMASK #define EF_CSKY_ABIMASK 0XF0000000 #endif #include <errno.h> #include <fcntl.h> #include <inttypes.h> #include <libgen.h> #include <regex.h> #include <stdlib.h> #include <unistd.h> #include <linux/string.h> #include <linux/zalloc.h> #include <subcmd/run-command.h> #include "annotate.h" #include "annotate-data.h" #include "build-id.h" #include "capstone.h" #include "debug.h" #include "disasm.h" #include "dso.h" #include "dwarf-regs.h" #include "env.h" #include "evsel.h" #include "libbfd.h" #include "llvm.h" #include "map.h" #include "maps.h" #include "namespaces.h" #include "srcline.h" #include "symbol.h" #include "thread.h" #include "util.h" static regex_t file_lineno; /* These can be referred from the arch-dependent code */ const struct ins_ops call_ops; const struct ins_ops dec_ops; const struct ins_ops jump_ops; const struct ins_ops mov_ops; const struct ins_ops nop_ops; const struct ins_ops lock_ops; const struct ins_ops ret_ops; const struct ins_ops load_store_ops; const struct ins_ops arithmetic_ops; static void ins__sort(struct arch *arch); static int disasm_line__parse(char *line, const char **namep, char **rawp); static int disasm_line__parse_powerpc(struct disasm_line *dl, struct annotate_args *args); static __attribute__((constructor)) void symbol__init_regexpr(void) { regcomp(&file_lineno, "^/[^:]+:([0-9]+)", REG_EXTENDED); } 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((void *)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 * sizeof(struct ins)); goto out_update_instructions; } int arch__associate_ins_ops(struct arch *arch, const char *name, const struct ins_ops *ops) { struct ins *ins; if (arch->nr_instructions == arch->nr_instructions_allocated && arch__grow_instructions(arch)) return -1; ins = (struct 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; } static int e_machine_and_eflags__cmp(const struct e_machine_and_e_flags *val1, const struct e_machine_and_e_flags *val2) { if (val1->e_machine == val2->e_machine) { if (val1->e_machine != EM_CSKY) return 0; if ((val1->e_flags & EF_CSKY_ABIMASK) < (val2->e_flags & EF_CSKY_ABIMASK)) return -1; return (val1->e_flags & EF_CSKY_ABIMASK) > (val2->e_flags & EF_CSKY_ABIMASK); } return val1->e_machine < val2->e_machine ? -1 : 1; } static int arch__key_cmp(const void *key, const void *archp) { const struct arch *const *arch = archp; return e_machine_and_eflags__cmp(key, &(*arch)->id); } static int arch__cmp(const void *a, const void *b) { const struct arch *const *aa = a; const struct arch *const *ab = b; return e_machine_and_eflags__cmp(&(*aa)->id, &(*ab)->id); } const struct arch *arch__find(uint16_t e_machine, uint32_t e_flags, const char *cpuid) { static const struct arch *(*const arch_new_fn[])(const struct e_machine_and_e_flags *id, const char *cpuid) = { [EM_386] = arch__new_x86, [EM_ARC] = arch__new_arc, [EM_ARM] = arch__new_arm, [EM_AARCH64] = arch__new_arm64, [EM_CSKY] = arch__new_csky, [EM_LOONGARCH] = arch__new_loongarch, [EM_MIPS] = arch__new_mips, [EM_PPC64] = arch__new_powerpc, [EM_PPC] = arch__new_powerpc, [EM_RISCV] = arch__new_riscv64, [EM_S390] = arch__new_s390, [EM_SPARC] = arch__new_sparc, [EM_SPARCV9] = arch__new_sparc, [EM_X86_64] = arch__new_x86, }; static const struct arch **archs; static size_t num_archs; struct e_machine_and_e_flags key = { .e_machine = e_machine, .e_flags = e_flags, }; const struct arch *result = NULL, **tmp; if (num_archs > 0) { tmp = bsearch(&key, archs, num_archs, sizeof(*archs), arch__key_cmp); if (tmp) result = *tmp; } if (result) return result; if (e_machine >= ARRAY_SIZE(arch_new_fn) || arch_new_fn[e_machine] == NULL) { errno = ENOTSUP; return NULL; } tmp = reallocarray(archs, num_archs + 1, sizeof(*archs)); if (!tmp) return NULL; archs = tmp; result = arch_new_fn[e_machine](&key, cpuid); if (!result) { pr_err("%s: failed to initialize %u arch priv area\n", __func__, e_machine); return NULL; } archs[num_archs++] = result; qsort(archs, num_archs, sizeof(*archs), arch__cmp); return result; } bool arch__is_x86(const struct arch *arch) { return arch->id.e_machine == EM_386 || arch->id.e_machine == EM_X86_64; } bool arch__is_powerpc(const struct arch *arch) { return arch->id.e_machine == EM_PPC || arch->id.e_machine == EM_PPC64; } static void ins_ops__delete(struct ins_operands *ops) { if (ops == NULL) return; zfree(&ops->source.raw); zfree(&ops->source.name); zfree(&ops->target.raw); zfree(&ops->target.name); } int ins__raw_scnprintf(const struct ins *ins, char *bf, size_t size, struct ins_operands *ops, int max_ins_name) { return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->raw); } int ins__scnprintf(const struct ins *ins, char *bf, size_t size, struct ins_operands *ops, int max_ins_name) { if (ins->ops->scnprintf) return ins->ops->scnprintf(ins, bf, size, ops, max_ins_name); return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); } bool ins__is_fused(const struct arch *arch, const char *ins1, const char *ins2) { if (!arch || !arch->ins_is_fused) return false; return arch->ins_is_fused(arch, ins1, ins2); } static int call__parse(const struct arch *arch, struct ins_operands *ops, struct map_symbol *ms, struct disasm_line *dl __maybe_unused) { char *endptr, *tok, *name; struct map *map = ms->map; struct addr_map_symbol target; ops->target.addr = strtoull(ops->raw, &endptr, 16); name = strchr(endptr, '<'); if (name == NULL) goto indirect_call; name++; if (arch->objdump.skip_functions_char && strchr(name, arch->objdump.skip_functions_char)) return -1; tok = strchr(name, '>'); if (tok == NULL) return -1; *tok = '\0'; ops->target.name = strdup(name); *tok = '>'; if (ops->target.name == NULL) return -1; find_target: target = (struct addr_map_symbol) { .ms = { .map = map__get(map), }, .addr = map__objdump_2mem(map, ops->target.addr), }; if (maps__find_ams(thread__maps(ms->thread), &target) == 0 && map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr) ops->target.sym = target.ms.sym; addr_map_symbol__exit(&target); return 0; indirect_call: tok = strchr(endptr, '*'); if (tok != NULL) { endptr++; /* Indirect call can use a non-rip register and offset: callq *0x8(%rbx). * Do not parse such instruction. */ if (strstr(endptr, "(%r") == NULL) ops->target.addr = strtoull(endptr, NULL, 16); } goto find_target; } int call__scnprintf(const struct ins *ins, char *bf, size_t size, struct ins_operands *ops, int max_ins_name) { if (ops->target.sym) return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.sym->name); if (ops->target.addr == 0) return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); if (ops->target.name) return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.name); return scnprintf(bf, size, "%-*s *%" PRIx64, max_ins_name, ins->name, ops->target.addr); } const struct ins_ops call_ops = { .parse = call__parse, .scnprintf = call__scnprintf, .is_call = true, }; bool ins__is_call(const struct ins *ins) { return ins->ops && ins->ops->is_call; } /* * Prevents from matching commas in the comment section, e.g.: * ffff200008446e70: b.cs ffff2000084470f4 <generic_exec_single+0x314> // b.hs, b.nlast * * and skip comma as part of function arguments, e.g.: * 1d8b4ac <linemap_lookup(line_maps const*, unsigned int)+0xcc> */ static inline const char *validate_comma(const char *c, struct ins_operands *ops) { if (ops->jump.raw_comment && c > ops->jump.raw_comment) return NULL; if (ops->jump.raw_func_start && c > ops->jump.raw_func_start) return NULL; return c; } static int jump__parse(const struct arch *arch, struct ins_operands *ops, struct map_symbol *ms, struct disasm_line *dl __maybe_unused) { struct map *map = ms->map; struct symbol *sym = ms->sym; struct addr_map_symbol target = { .ms = { .map = map__get(map), }, }; const char *c = strchr(ops->raw, ','); u64 start, end; ops->jump.raw_comment = strchr(ops->raw, arch->objdump.comment_char); ops->jump.raw_func_start = strchr(ops->raw, '<'); c = validate_comma(c, ops); /* * Examples of lines to parse for the _cpp_lex_token@@Base * function: * * 1159e6c: jne 115aa32 <_cpp_lex_token@@Base+0xf92> * 1159e8b: jne c469be <cpp_named_operator2name@@Base+0xa72> * * 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 <security_file_permission+0xd0> */ if (c != NULL) { c++; ops->target.addr = strtoull(c, NULL, 16); if (!ops->target.addr) { c = strchr(c, ','); c = validate_comma(c, ops); if (c != NULL) { c++; ops->target.addr = strtoull(c, NULL, 16); } } } else { 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 (maps__find_ams(thread__maps(ms->thread), &target) == 0 && map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr) ops->target.sym = target.ms.sym; if (!ops->target.outside) { ops->target.offset = target.addr - start; ops->target.offset_avail = true; } else { ops->target.offset_avail = false; } addr_map_symbol__exit(&target); return 0; } int jump__scnprintf(const struct ins *ins, char *bf, size_t size, struct ins_operands *ops, int max_ins_name) { const char *c; if (!ops->target.addr || ops->target.offset < 0) return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); if (ops->target.outside && ops->target.sym != NULL) return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.sym->name); c = strchr(ops->raw, ','); c = validate_comma(c, ops); if (c != NULL) { const char *c2 = strchr(c + 1, ','); c2 = validate_comma(c2, ops); /* check for 3-op insn */ if (c2 != NULL) c = c2; c++; /* mirror arch objdump's space-after-comma style */ if (*c == ' ') c++; } return scnprintf(bf, size, "%-*s %.*s%" PRIx64, max_ins_name, ins->name, c ? c - ops->raw : 0, ops->raw, ops->target.offset); } void jump__delete(struct ins_operands *ops __maybe_unused) { /* * The ops->jump.raw_comment and ops->jump.raw_func_start belong to the * raw string, don't free them. */ } const struct ins_ops jump_ops = { .free = jump__delete, .parse = jump__parse, .scnprintf = jump__scnprintf, .is_jump = true, }; bool ins__is_jump(const struct ins *ins) { return ins->ops && ins->ops->is_jump; } static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep) { char *endptr, *name, *t; if (strstr(raw, "(%rip)") == NULL) return 0; *addrp = strtoull(comment, &endptr, 16); if (endptr == comment) return 0; name = strchr(endptr, '<'); if (name == NULL) return -1; name++; t = strchr(name, '>'); if (t == NULL) return 0; *t = '\0'; *namep = strdup(name); *t = '>'; return 0; }