/* * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> * * Parts came from builtin-annotate.c, see those files for further * copyright notes. * * Released under the GPL v2. (and only v2, not any later version) */ #include "util.h"#include "build-id.h"#include "color.h"#include "cache.h"#include "symbol.h"#include "debug.h"#include "annotate.h"#include "evsel.h"#include <pthread.h>#include <linux/bitops.h> const char *disassembler_style;const char *objdump_path; static struct ins *ins__find(const char *name);static int disasm_line__parse(char *line, char **namep, char **rawp); static void ins__delete(struct ins_operands *ops){ free(ops->source.raw); free(ops->source.name); free(ops->target.raw); free(ops->target.name);} static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops){ return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->raw);} int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops){ if (ins->ops->scnprintf) return ins->ops->scnprintf(ins, bf, size, ops); return ins__raw_scnprintf(ins, bf, size, ops);} static int call__parse(struct ins_operands *ops){ char *endptr, *tok, *name; ops->target.addr = strtoull(ops->raw, &endptr, 16); name = strchr(endptr, '<'); if (name == NULL) goto indirect_call; name++; tok = strchr(name, '>'); if (tok == NULL) return -1; *tok = '\0'; ops->target.name = strdup(name); *tok = '>'; return ops->target.name == NULL ? -1 : 0; indirect_call: tok = strchr(endptr, '('); if (tok != NULL) { ops->target.addr = 0; return 0; } tok = strchr(endptr, '*'); if (tok == NULL) return -1; ops->target.addr = strtoull(tok + 1, NULL, 16); return 0;} static int call__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops){ if (ops->target.name) return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target.name); if (ops->target.addr == 0) return ins__raw_scnprintf(ins, bf, size, ops); return scnprintf(bf, size, "%-6.6s *%" PRIx64, ins->name, ops->target.addr);} static struct ins_ops call_ops = { .parse = call__parse, .scnprintf = call__scnprintf,}; bool ins__is_call(const struct ins *ins){ return ins->ops == &call_ops;} static int jump__parse(struct ins_operands *ops){ const char *s = strchr(ops->raw, '+'); ops->target.addr = strtoull(ops->raw, NULL, 16); if (s++ != NULL) ops->target.offset = strtoull(s, NULL, 16); else ops->target.offset = UINT64_MAX; return 0;} static int jump__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops){ return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target.offset);} static struct ins_ops jump_ops = { .parse = jump__parse, .scnprintf = jump__scnprintf,}; bool ins__is_jump(const struct ins *ins){ return ins->ops == &jump_ops;} 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); 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;} static int lock__parse(struct ins_operands *ops){ 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) goto out_free_ops; ops->locked.ins = ins__find(name); if (ops->locked.ins == NULL) goto out_free_ops; if (!ops->locked.ins->ops) return 0; if (ops->locked.ins->ops->parse) ops->locked.ins->ops->parse(ops->locked.ops); return 0; out_free_ops: free(ops->locked.ops); ops->locked.ops = NULL; return 0;} static int lock__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops){ int printed; if (ops->locked.ins == 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, size - printed, ops->locked.ops);} static void lock__delete(struct ins_operands *ops){ free(ops->locked.ops); free(ops->target.raw); free(ops->target.name);} static struct ins_ops lock_ops = { .free = lock__delete, .parse = lock__parse, .scnprintf = lock__scnprintf,}; static int mov__parse(struct ins_operands *ops){ char *s = strchr(ops->raw, ','), *target, *comment, prev; if (s == NULL) return -1; *s = '\0'; ops->source.raw = strdup(ops->raw); *s = ','; if (ops->source.raw == NULL) return -1; target = ++s; while (s[0] != '\0' && !isspace(s[0])) ++s; prev = *s; *s = '\0'; ops->target.raw = strdup(target); *s = prev; if (ops->target.raw == NULL) goto out_free_source; comment = strchr(s, '#'); if (comment == NULL) return 0; while (comment[0] != '\0' && isspace(comment[0])) ++comment; comment__symbol(ops->source.raw, comment, &ops->source.addr, &ops->source.name); comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name); return 0; out_free_source: free(ops->source.raw); ops->source.raw = NULL; return -1;} static int mov__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops){ return scnprintf(bf, size, "%-6.6s %s,%s", ins->name, ops->source.name ?: ops->source.raw, ops->target.name ?: ops->target.raw);} static struct ins_ops mov_ops = { .parse = mov__parse, .scnprintf = mov__scnprintf,}; static int dec__parse(struct ins_operands *ops){ char *target, *comment, *s, prev; target = s = ops->raw; while (s[0] != '\0' && !isspace(s[0])) ++s; prev = *s; *s = '\0'; ops->target.raw = strdup(target); *s = prev; if (ops->target.raw == NULL) return -1; comment = strchr(s, '#'); if (comment == NULL) return 0; while (comment[0] != '\0' && isspace(comment[0])) ++comment; comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name); return 0;} static int dec__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops){ return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target.name ?: ops->target.raw);} static struct ins_ops dec_ops = { .parse = dec__parse, .scnprintf = dec__scnprintf,}; static int nop__scnprintf(struct ins *ins __maybe_unused, char *bf, size_t size, struct ins_operands *ops __maybe_unused){ return scnprintf(bf, size, "%-6.6s", "nop");} static struct ins_ops nop_ops = { .scnprintf = nop__scnprintf,}; /* * Must be sorted by name! */static struct ins instructions[] = { { .name = "add", .ops = &mov_ops, }, { .name = "addl", .ops = &mov_ops, }, { .name = "addq", .ops = &mov_ops, }, { .name = "addw", .ops = &mov_ops, }, { .name = "and", .ops = &mov_ops, }, { .name = "bts", .ops = &mov_ops, }, { .name = "call", .ops = &call_ops, }, { .name = "callq", .ops = &call_ops, }, { .name = "cmp", .ops = &mov_ops, }, { .name = "cmpb", .ops = &mov_ops, }, { .name = "cmpl", .ops = &mov_ops, }, { .name = "cmpq", .ops = &mov_ops, }, { .name = "cmpw", .ops = &mov_ops, }, { .name = "cmpxch", .ops = &mov_ops, }, { .name = "dec", .ops = &dec_ops, }, { .name = "decl", .ops = &dec_ops, }, { .name = "imul", .ops = &mov_ops, }, { .name = "inc", .ops = &dec_ops, }, { .name = "incl", .ops = &dec_ops, }, { .name = "ja", .ops = &jump_ops, }, { .name = "jae", .ops = &jump_ops, }, { .name = "jb", .ops = &jump_ops, }, { .name = "jbe", .ops = &jump_ops, }, { .name = "jc", .ops = &jump_ops, }, { .name = "jcxz", .ops = &jump_ops, }, { .name = "je", .ops = &jump_ops, }, { .name = "jecxz", .ops = &jump_ops, }, { .name = "jg", .ops = &jump_ops, }, { .name = "jge", .ops = &jump_ops, }, { .name = "jl", .ops = &jump_ops, }, { .name = "jle", .ops = &jump_ops, }, { .name = "jmp", .ops = &jump_ops, }, { .name = "jmpq", .ops = &jump_ops, }, { .name = "jna", .ops = &jump_ops, }, { .name = "jnae", .ops = &jump_ops, }, { .name = "jnb", .ops = &jump_ops, }, { .name = "jnbe", .ops = &jump_ops, }, { .name = "jnc", .ops = &jump_ops, }, { .name = "jne", .ops = &jump_ops, }, { .name = "jng", .ops = &jump_ops, }, { .name = "jnge", .ops = &jump_ops, }, { .name = "jnl", .ops = &jump_ops, }, { .name = "jnle", .ops = &jump_ops, }, { .name = "jno", .ops = &jump_ops, }, { .name = "jnp", .ops = &jump_ops, }, { .name = "jns", .ops = &jump_ops, }, { .name = "jnz", .ops = &jump_ops, }, { .name = "jo", .ops = &jump_ops, }, { .name = "jp", .ops = &jump_ops, }, { .name = "jpe", .ops = &jump_ops, }, { .name = "jpo", .ops = &jump_ops, }, { .name = "jrcxz", .ops = &jump_ops, }, { .name = "js", .ops = &jump_ops, }, { .name = "jz", .ops = &jump_ops, }, { .name = "lea", .ops = &mov_ops, }, { .name = "lock", .ops = &lock_ops, }, { .name = "mov", .ops = &mov_ops, }, { .name = "movb", .ops = &mov_ops, }, { .name = "movdqa",.ops = &mov_ops, }, { .name = "movl", .ops = &mov_ops, }, { .name = "movq", .ops = &mov_ops, }, { .name = "movslq", .ops = &mov_ops, }, { .name = "movzbl", .ops = &mov_ops, }, { .name = "movzwl", .ops = &mov_ops, }, { .name = "nop", .ops = &nop_ops, }, { .name = "nopl", .ops = &nop_ops, }, { .name = "nopw", .ops = &nop_ops, }, { .name = "or", .ops = &mov_ops, }, { .name = "orl", .ops = &mov_ops, }, { .name = "test", .ops = &mov_ops, }, { .name = "testb", .ops = &mov_ops, }, { .name = "testl", .ops = &mov_ops, }, { .name = "xadd", .ops = &mov_ops, }, { .name = "xbeginl", .ops = &jump_ops, }, { .name = "xbeginq", .ops = &jump_ops, },}; static int ins__cmp(const void *name, const void *insp){ const struct ins *ins = insp; return strcmp(name, ins->name);} static struct ins *ins__find(const char *name){ const int nmemb = ARRAY_SIZE(instructions); return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__cmp);} int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym){ struct annotation *notes = symbol__annotation(sym); pthread_mutex_init(¬es->lock, NULL); return 0;} int symbol__alloc_hist(struct symbol *sym){ struct annotation *notes = symbol__annotation(sym); const size_t size = symbol__size(sym); size_t sizeof_sym_hist; /* Check for overflow when calculating sizeof_sym_hist */ if (size > (SIZE_MAX - sizeof(struct sym_hist)) / sizeof(u64)) return -1; sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64)); /* Check for overflow in zalloc argument */ if (sizeof_sym_hist > (SIZE_MAX - sizeof(*notes->src)) / symbol_conf.nr_events) return -1; notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist); if (notes->src == NULL) return -1; notes->src->sizeof_sym_hist = sizeof_sym_hist; notes->src->nr_histograms = symbol_conf.nr_events; INIT_LIST_HEAD(¬es->src->source); return 0;} void symbol__annotate_zero_histograms(struct symbol *sym){ struct annotation *notes = symbol__annotation(sym); pthread_mutex_lock(¬es->lock); if (notes->src != NULL) memset(notes->src->histograms, 0, notes->src->nr_histograms * notes->src->sizeof_sym_hist); pthread_mutex_unlock(¬es->lock);} int symbol__inc_addr_samples(struct symbol *sym, struct map *map, int evidx, u64 addr){ unsigned offset; struct annotation *notes; struct sym_hist *h; notes = symbol__annotation(sym); if (notes->src == NULL) return -ENOMEM; pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); if (addr < sym->start || addr > sym->end) return -ERANGE; offset = addr - sym->start; h = annotation__histogram(notes, evidx); h->sum++; h->addr[offset]++; pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64 ", evidx=%d] => %" PRIu64 "\n", sym->start, sym->name, addr, addr - sym->start, evidx, h->addr[offset]); return 0;} static void disasm_line__init_ins(struct disasm_line *dl){ dl->ins = ins__find(dl->name); if (dl->ins == NULL) return; Lines 1–500 of 1378. Load more
/* * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> * * Parts came from builtin-annotate.c, see those files for further * copyright notes. * * Released under the GPL v2. (and only v2, not any later version) */ #include "util.h" #include "build-id.h" #include "color.h" #include "cache.h" #include "symbol.h" #include "debug.h" #include "annotate.h" #include "evsel.h" #include <pthread.h> #include <linux/bitops.h> const char *disassembler_style; const char *objdump_path; static struct ins *ins__find(const char *name); static int disasm_line__parse(char *line, char **namep, char **rawp); static void ins__delete(struct ins_operands *ops) { free(ops->source.raw); free(ops->source.name); free(ops->target.raw); free(ops->target.name); } static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops) { return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->raw); } int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops) { if (ins->ops->scnprintf) return ins->ops->scnprintf(ins, bf, size, ops); return ins__raw_scnprintf(ins, bf, size, ops); } static int call__parse(struct ins_operands *ops) { char *endptr, *tok, *name; ops->target.addr = strtoull(ops->raw, &endptr, 16); name = strchr(endptr, '<'); if (name == NULL) goto indirect_call; name++; tok = strchr(name, '>'); if (tok == NULL) return -1; *tok = '\0'; ops->target.name = strdup(name); *tok = '>'; return ops->target.name == NULL ? -1 : 0; indirect_call: tok = strchr(endptr, '('); if (tok != NULL) { ops->target.addr = 0; return 0; } tok = strchr(endptr, '*'); if (tok == NULL) return -1; ops->target.addr = strtoull(tok + 1, NULL, 16); return 0; } static int call__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops) { if (ops->target.name) return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target.name); if (ops->target.addr == 0) return ins__raw_scnprintf(ins, bf, size, ops); return scnprintf(bf, size, "%-6.6s *%" PRIx64, ins->name, ops->target.addr); } static struct ins_ops call_ops = { .parse = call__parse, .scnprintf = call__scnprintf, }; bool ins__is_call(const struct ins *ins) { return ins->ops == &call_ops; } static int jump__parse(struct ins_operands *ops) { const char *s = strchr(ops->raw, '+'); ops->target.addr = strtoull(ops->raw, NULL, 16); if (s++ != NULL) ops->target.offset = strtoull(s, NULL, 16); else ops->target.offset = UINT64_MAX; return 0; } static int jump__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops) { return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target.offset); } static struct ins_ops jump_ops = { .parse = jump__parse, .scnprintf = jump__scnprintf, }; bool ins__is_jump(const struct ins *ins) { return ins->ops == &jump_ops; } 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); 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; } static int lock__parse(struct ins_operands *ops) { 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) goto out_free_ops; ops->locked.ins = ins__find(name); if (ops->locked.ins == NULL) goto out_free_ops; if (!ops->locked.ins->ops) return 0; if (ops->locked.ins->ops->parse) ops->locked.ins->ops->parse(ops->locked.ops); return 0; out_free_ops: free(ops->locked.ops); ops->locked.ops = NULL; return 0; } static int lock__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops) { int printed; if (ops->locked.ins == 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, size - printed, ops->locked.ops); } static void lock__delete(struct ins_operands *ops) { free(ops->locked.ops); free(ops->target.raw); free(ops->target.name); } static struct ins_ops lock_ops = { .free = lock__delete, .parse = lock__parse, .scnprintf = lock__scnprintf, }; static int mov__parse(struct ins_operands *ops) { char *s = strchr(ops->raw, ','), *target, *comment, prev; if (s == NULL) return -1; *s = '\0'; ops->source.raw = strdup(ops->raw); *s = ','; if (ops->source.raw == NULL) return -1; target = ++s; while (s[0] != '\0' && !isspace(s[0])) ++s; prev = *s; *s = '\0'; ops->target.raw = strdup(target); *s = prev; if (ops->target.raw == NULL) goto out_free_source; comment = strchr(s, '#'); if (comment == NULL) return 0; while (comment[0] != '\0' && isspace(comment[0])) ++comment; comment__symbol(ops->source.raw, comment, &ops->source.addr, &ops->source.name); comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name); return 0; out_free_source: free(ops->source.raw); ops->source.raw = NULL; return -1; } static int mov__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops) { return scnprintf(bf, size, "%-6.6s %s,%s", ins->name, ops->source.name ?: ops->source.raw, ops->target.name ?: ops->target.raw); } static struct ins_ops mov_ops = { .parse = mov__parse, .scnprintf = mov__scnprintf, }; static int dec__parse(struct ins_operands *ops) { char *target, *comment, *s, prev; target = s = ops->raw; while (s[0] != '\0' && !isspace(s[0])) ++s; prev = *s; *s = '\0'; ops->target.raw = strdup(target); *s = prev; if (ops->target.raw == NULL) return -1; comment = strchr(s, '#'); if (comment == NULL) return 0; while (comment[0] != '\0' && isspace(comment[0])) ++comment; comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name); return 0; } static int dec__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops) { return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target.name ?: ops->target.raw); } static struct ins_ops dec_ops = { .parse = dec__parse, .scnprintf = dec__scnprintf, }; static int nop__scnprintf(struct ins *ins __maybe_unused, char *bf, size_t size, struct ins_operands *ops __maybe_unused) { return scnprintf(bf, size, "%-6.6s", "nop"); } static struct ins_ops nop_ops = { .scnprintf = nop__scnprintf, }; /* * Must be sorted by name! */ static struct ins instructions[] = { { .name = "add", .ops = &mov_ops, }, { .name = "addl", .ops = &mov_ops, }, { .name = "addq", .ops = &mov_ops, }, { .name = "addw", .ops = &mov_ops, }, { .name = "and", .ops = &mov_ops, }, { .name = "bts", .ops = &mov_ops, }, { .name = "call", .ops = &call_ops, }, { .name = "callq", .ops = &call_ops, }, { .name = "cmp", .ops = &mov_ops, }, { .name = "cmpb", .ops = &mov_ops, }, { .name = "cmpl", .ops = &mov_ops, }, { .name = "cmpq", .ops = &mov_ops, }, { .name = "cmpw", .ops = &mov_ops, }, { .name = "cmpxch", .ops = &mov_ops, }, { .name = "dec", .ops = &dec_ops, }, { .name = "decl", .ops = &dec_ops, }, { .name = "imul", .ops = &mov_ops, }, { .name = "inc", .ops = &dec_ops, }, { .name = "incl", .ops = &dec_ops, }, { .name = "ja", .ops = &jump_ops, }, { .name = "jae", .ops = &jump_ops, }, { .name = "jb", .ops = &jump_ops, }, { .name = "jbe", .ops = &jump_ops, }, { .name = "jc", .ops = &jump_ops, }, { .name = "jcxz", .ops = &jump_ops, }, { .name = "je", .ops = &jump_ops, }, { .name = "jecxz", .ops = &jump_ops, }, { .name = "jg", .ops = &jump_ops, }, { .name = "jge", .ops = &jump_ops, }, { .name = "jl", .ops = &jump_ops, }, { .name = "jle", .ops = &jump_ops, }, { .name = "jmp", .ops = &jump_ops, }, { .name = "jmpq", .ops = &jump_ops, }, { .name = "jna", .ops = &jump_ops, }, { .name = "jnae", .ops = &jump_ops, }, { .name = "jnb", .ops = &jump_ops, }, { .name = "jnbe", .ops = &jump_ops, }, { .name = "jnc", .ops = &jump_ops, }, { .name = "jne", .ops = &jump_ops, }, { .name = "jng", .ops = &jump_ops, }, { .name = "jnge", .ops = &jump_ops, }, { .name = "jnl", .ops = &jump_ops, }, { .name = "jnle", .ops = &jump_ops, }, { .name = "jno", .ops = &jump_ops, }, { .name = "jnp", .ops = &jump_ops, }, { .name = "jns", .ops = &jump_ops, }, { .name = "jnz", .ops = &jump_ops, }, { .name = "jo", .ops = &jump_ops, }, { .name = "jp", .ops = &jump_ops, }, { .name = "jpe", .ops = &jump_ops, }, { .name = "jpo", .ops = &jump_ops, }, { .name = "jrcxz", .ops = &jump_ops, }, { .name = "js", .ops = &jump_ops, }, { .name = "jz", .ops = &jump_ops, }, { .name = "lea", .ops = &mov_ops, }, { .name = "lock", .ops = &lock_ops, }, { .name = "mov", .ops = &mov_ops, }, { .name = "movb", .ops = &mov_ops, }, { .name = "movdqa",.ops = &mov_ops, }, { .name = "movl", .ops = &mov_ops, }, { .name = "movq", .ops = &mov_ops, }, { .name = "movslq", .ops = &mov_ops, }, { .name = "movzbl", .ops = &mov_ops, }, { .name = "movzwl", .ops = &mov_ops, }, { .name = "nop", .ops = &nop_ops, }, { .name = "nopl", .ops = &nop_ops, }, { .name = "nopw", .ops = &nop_ops, }, { .name = "or", .ops = &mov_ops, }, { .name = "orl", .ops = &mov_ops, }, { .name = "test", .ops = &mov_ops, }, { .name = "testb", .ops = &mov_ops, }, { .name = "testl", .ops = &mov_ops, }, { .name = "xadd", .ops = &mov_ops, }, { .name = "xbeginl", .ops = &jump_ops, }, { .name = "xbeginq", .ops = &jump_ops, }, }; static int ins__cmp(const void *name, const void *insp) { const struct ins *ins = insp; return strcmp(name, ins->name); } static struct ins *ins__find(const char *name) { const int nmemb = ARRAY_SIZE(instructions); return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__cmp); } int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym) { struct annotation *notes = symbol__annotation(sym); pthread_mutex_init(¬es->lock, NULL); return 0; } int symbol__alloc_hist(struct symbol *sym) { struct annotation *notes = symbol__annotation(sym); const size_t size = symbol__size(sym); size_t sizeof_sym_hist; /* Check for overflow when calculating sizeof_sym_hist */ if (size > (SIZE_MAX - sizeof(struct sym_hist)) / sizeof(u64)) return -1; sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64)); /* Check for overflow in zalloc argument */ if (sizeof_sym_hist > (SIZE_MAX - sizeof(*notes->src)) / symbol_conf.nr_events) return -1; notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist); if (notes->src == NULL) return -1; notes->src->sizeof_sym_hist = sizeof_sym_hist; notes->src->nr_histograms = symbol_conf.nr_events; INIT_LIST_HEAD(¬es->src->source); return 0; } void symbol__annotate_zero_histograms(struct symbol *sym) { struct annotation *notes = symbol__annotation(sym); pthread_mutex_lock(¬es->lock); if (notes->src != NULL) memset(notes->src->histograms, 0, notes->src->nr_histograms * notes->src->sizeof_sym_hist); pthread_mutex_unlock(¬es->lock); } int symbol__inc_addr_samples(struct symbol *sym, struct map *map, int evidx, u64 addr) { unsigned offset; struct annotation *notes; struct sym_hist *h; notes = symbol__annotation(sym); if (notes->src == NULL) return -ENOMEM; pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); if (addr < sym->start || addr > sym->end) return -ERANGE; offset = addr - sym->start; h = annotation__histogram(notes, evidx); h->sum++; h->addr[offset]++; pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64 ", evidx=%d] => %" PRIu64 "\n", sym->start, sym->name, addr, addr - sym->start, evidx, h->addr[offset]); return 0; } static void disasm_line__init_ins(struct disasm_line *dl) { dl->ins = ins__find(dl->name); if (dl->ins == NULL) return;