1e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/* 2e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> 3e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * 4e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Parts came from builtin-annotate.c, see those files for further 5e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * copyright notes. 6e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * 7e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Released under the GPL v2. (and only v2, not any later version) 8e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 9e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 10e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "util.h" 11e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "build-id.h" 12e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "color.h" 13e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "cache.h" 14e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "symbol.h" 15e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "debug.h" 16e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "annotate.h" 17e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "evsel.h" 18e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <pthread.h> 19e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <linux/bitops.h> 20e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 21e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengconst char *disassembler_style; 22e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengconst char *objdump_path; 23e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 24e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic struct ins *ins__find(const char *name); 25e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int disasm_line__parse(char *line, char **namep, char **rawp); 26e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 27e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void ins__delete(struct ins_operands *ops) 28e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 29e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng free(ops->source.raw); 30e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng free(ops->source.name); 31e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng free(ops->target.raw); 32e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng free(ops->target.name); 33e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 34e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 35e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, 36e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct ins_operands *ops) 37e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 38e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->raw); 39e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 40e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 41e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengint ins__scnprintf(struct ins *ins, char *bf, size_t size, 42e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct ins_operands *ops) 43e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 44e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (ins->ops->scnprintf) 45e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return ins->ops->scnprintf(ins, bf, size, ops); 46e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 47e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return ins__raw_scnprintf(ins, bf, size, ops); 48e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 49e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 50e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int call__parse(struct ins_operands *ops) 51e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 52e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng char *endptr, *tok, *name; 53e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 54e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ops->target.addr = strtoull(ops->raw, &endptr, 16); 55e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 56e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng name = strchr(endptr, '<'); 57e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (name == NULL) 58e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto indirect_call; 59e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 60e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng name++; 61e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 62e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng tok = strchr(name, '>'); 63e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (tok == NULL) 64e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -1; 65e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 66e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *tok = '\0'; 67e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ops->target.name = strdup(name); 68e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *tok = '>'; 69e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 70e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return ops->target.name == NULL ? -1 : 0; 71e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 72e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengindirect_call: 73e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng tok = strchr(endptr, '('); 74e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (tok != NULL) { 75e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ops->target.addr = 0; 76e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 77e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 78e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 79e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng tok = strchr(endptr, '*'); 80e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (tok == NULL) 81e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -1; 82e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 83e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ops->target.addr = strtoull(tok + 1, NULL, 16); 84e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 85e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 86e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 87e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int call__scnprintf(struct ins *ins, char *bf, size_t size, 88e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct ins_operands *ops) 89e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 90e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (ops->target.name) 91e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target.name); 92e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 93e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (ops->target.addr == 0) 94e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return ins__raw_scnprintf(ins, bf, size, ops); 95e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 96e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return scnprintf(bf, size, "%-6.6s *%" PRIx64, ins->name, ops->target.addr); 97e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 98e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 99e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic struct ins_ops call_ops = { 100e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng .parse = call__parse, 101e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng .scnprintf = call__scnprintf, 102e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}; 103e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 104e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengbool ins__is_call(const struct ins *ins) 105e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 106e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return ins->ops == &call_ops; 107e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 108e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 109e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int jump__parse(struct ins_operands *ops) 110e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 111e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const char *s = strchr(ops->raw, '+'); 112e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 113e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ops->target.addr = strtoull(ops->raw, NULL, 16); 114e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 115e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (s++ != NULL) 116e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ops->target.offset = strtoull(s, NULL, 16); 117e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng else 118e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ops->target.offset = UINT64_MAX; 119e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 120e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 121e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 122e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 123e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int jump__scnprintf(struct ins *ins, char *bf, size_t size, 124e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct ins_operands *ops) 125e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 126e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target.offset); 127e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 128e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 129e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic struct ins_ops jump_ops = { 130e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng .parse = jump__parse, 131e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng .scnprintf = jump__scnprintf, 132e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}; 133e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 134e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengbool ins__is_jump(const struct ins *ins) 135e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 136e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return ins->ops == &jump_ops; 137e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 138e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 139e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep) 140e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 141e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng char *endptr, *name, *t; 142e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 143e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (strstr(raw, "(%rip)") == NULL) 144e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 145e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 146e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *addrp = strtoull(comment, &endptr, 16); 147e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng name = strchr(endptr, '<'); 148e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (name == NULL) 149e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -1; 150e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 151e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng name++; 152e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 153e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng t = strchr(name, '>'); 154e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (t == NULL) 155e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 156e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 157e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *t = '\0'; 158e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *namep = strdup(name); 159e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *t = '>'; 160e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 161e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 162e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 163e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 164e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int lock__parse(struct ins_operands *ops) 165e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 166e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng char *name; 167e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 168e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ops->locked.ops = zalloc(sizeof(*ops->locked.ops)); 169e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (ops->locked.ops == NULL) 170e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 171e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 172e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0) 173e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_free_ops; 174e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 175e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ops->locked.ins = ins__find(name); 176e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (ops->locked.ins == NULL) 177e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_free_ops; 178e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 179e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!ops->locked.ins->ops) 180e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 181e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 182e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (ops->locked.ins->ops->parse) 183e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ops->locked.ins->ops->parse(ops->locked.ops); 184e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 185e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 186e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 187e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout_free_ops: 188e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng free(ops->locked.ops); 189e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ops->locked.ops = NULL; 190e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 191e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 192e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 193e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int lock__scnprintf(struct ins *ins, char *bf, size_t size, 194e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct ins_operands *ops) 195e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 196e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int printed; 197e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 198e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (ops->locked.ins == NULL) 199e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return ins__raw_scnprintf(ins, bf, size, ops); 200e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 201e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng printed = scnprintf(bf, size, "%-6.6s ", ins->name); 202e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return printed + ins__scnprintf(ops->locked.ins, bf + printed, 203e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng size - printed, ops->locked.ops); 204e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 205e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 206e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void lock__delete(struct ins_operands *ops) 207e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 208e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng free(ops->locked.ops); 209e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng free(ops->target.raw); 210e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng free(ops->target.name); 211e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 212e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 213e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic struct ins_ops lock_ops = { 214e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng .free = lock__delete, 215e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng .parse = lock__parse, 216e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng .scnprintf = lock__scnprintf, 217e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}; 218e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 219e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int mov__parse(struct ins_operands *ops) 220e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 221e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng char *s = strchr(ops->raw, ','), *target, *comment, prev; 222e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 223e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (s == NULL) 224e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -1; 225e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 226e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *s = '\0'; 227e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ops->source.raw = strdup(ops->raw); 228e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *s = ','; 229e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 230e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (ops->source.raw == NULL) 231e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -1; 232e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 233e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng target = ++s; 234e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 235e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng while (s[0] != '\0' && !isspace(s[0])) 236e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ++s; 237e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng prev = *s; 238e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *s = '\0'; 239e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 240e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ops->target.raw = strdup(target); 241e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *s = prev; 242e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 243e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (ops->target.raw == NULL) 244e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_free_source; 245e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 246e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng comment = strchr(s, '#'); 247e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (comment == NULL) 248e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 249e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 250e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng while (comment[0] != '\0' && isspace(comment[0])) 251e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ++comment; 252e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 253e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng comment__symbol(ops->source.raw, comment, &ops->source.addr, &ops->source.name); 254e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name); 255e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 256e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 257e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 258e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout_free_source: 259e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng free(ops->source.raw); 260e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ops->source.raw = NULL; 261e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -1; 262e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 263e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 264e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int mov__scnprintf(struct ins *ins, char *bf, size_t size, 265e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct ins_operands *ops) 266e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 267e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return scnprintf(bf, size, "%-6.6s %s,%s", ins->name, 268e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ops->source.name ?: ops->source.raw, 269e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ops->target.name ?: ops->target.raw); 270e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 271e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 272e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic struct ins_ops mov_ops = { 273e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng .parse = mov__parse, 274e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng .scnprintf = mov__scnprintf, 275e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}; 276e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 277e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int dec__parse(struct ins_operands *ops) 278e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 279e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng char *target, *comment, *s, prev; 280e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 281e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng target = s = ops->raw; 282e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 283e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng while (s[0] != '\0' && !isspace(s[0])) 284e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ++s; 285e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng prev = *s; 286e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *s = '\0'; 287e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 288e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ops->target.raw = strdup(target); 289e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *s = prev; 290e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 291e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (ops->target.raw == NULL) 292e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -1; 293e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 294e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng comment = strchr(s, '#'); 295e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (comment == NULL) 296e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 297e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 298e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng while (comment[0] != '\0' && isspace(comment[0])) 299e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ++comment; 300e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 301e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name); 302e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 303e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 304e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 305e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 306e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int dec__scnprintf(struct ins *ins, char *bf, size_t size, 307e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct ins_operands *ops) 308e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 309e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return scnprintf(bf, size, "%-6.6s %s", ins->name, 310e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ops->target.name ?: ops->target.raw); 311e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 312e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 313e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic struct ins_ops dec_ops = { 314e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng .parse = dec__parse, 315e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng .scnprintf = dec__scnprintf, 316e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}; 317e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 318e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int nop__scnprintf(struct ins *ins __maybe_unused, char *bf, size_t size, 319e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct ins_operands *ops __maybe_unused) 320e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 321e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return scnprintf(bf, size, "%-6.6s", "nop"); 322e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 323e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 324e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic struct ins_ops nop_ops = { 325e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng .scnprintf = nop__scnprintf, 326e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}; 327e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 328e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/* 329e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Must be sorted by name! 330e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 331e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic struct ins instructions[] = { 332e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "add", .ops = &mov_ops, }, 333e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "addl", .ops = &mov_ops, }, 334e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "addq", .ops = &mov_ops, }, 335e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "addw", .ops = &mov_ops, }, 336e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "and", .ops = &mov_ops, }, 337e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "bts", .ops = &mov_ops, }, 338e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "call", .ops = &call_ops, }, 339e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "callq", .ops = &call_ops, }, 340e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "cmp", .ops = &mov_ops, }, 341e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "cmpb", .ops = &mov_ops, }, 342e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "cmpl", .ops = &mov_ops, }, 343e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "cmpq", .ops = &mov_ops, }, 344e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "cmpw", .ops = &mov_ops, }, 345e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "cmpxch", .ops = &mov_ops, }, 346e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "dec", .ops = &dec_ops, }, 347e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "decl", .ops = &dec_ops, }, 348e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "imul", .ops = &mov_ops, }, 349e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "inc", .ops = &dec_ops, }, 350e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "incl", .ops = &dec_ops, }, 351e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "ja", .ops = &jump_ops, }, 352e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jae", .ops = &jump_ops, }, 353e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jb", .ops = &jump_ops, }, 354e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jbe", .ops = &jump_ops, }, 355e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jc", .ops = &jump_ops, }, 356e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jcxz", .ops = &jump_ops, }, 357e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "je", .ops = &jump_ops, }, 358e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jecxz", .ops = &jump_ops, }, 359e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jg", .ops = &jump_ops, }, 360e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jge", .ops = &jump_ops, }, 361e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jl", .ops = &jump_ops, }, 362e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jle", .ops = &jump_ops, }, 363e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jmp", .ops = &jump_ops, }, 364e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jmpq", .ops = &jump_ops, }, 365e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jna", .ops = &jump_ops, }, 366e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jnae", .ops = &jump_ops, }, 367e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jnb", .ops = &jump_ops, }, 368e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jnbe", .ops = &jump_ops, }, 369e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jnc", .ops = &jump_ops, }, 370e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jne", .ops = &jump_ops, }, 371e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jng", .ops = &jump_ops, }, 372e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jnge", .ops = &jump_ops, }, 373e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jnl", .ops = &jump_ops, }, 374e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jnle", .ops = &jump_ops, }, 375e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jno", .ops = &jump_ops, }, 376e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jnp", .ops = &jump_ops, }, 377e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jns", .ops = &jump_ops, }, 378e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jnz", .ops = &jump_ops, }, 379e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jo", .ops = &jump_ops, }, 380e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jp", .ops = &jump_ops, }, 381e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jpe", .ops = &jump_ops, }, 382e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jpo", .ops = &jump_ops, }, 383e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jrcxz", .ops = &jump_ops, }, 384e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "js", .ops = &jump_ops, }, 385e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "jz", .ops = &jump_ops, }, 386e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "lea", .ops = &mov_ops, }, 387e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "lock", .ops = &lock_ops, }, 388e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "mov", .ops = &mov_ops, }, 389e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "movb", .ops = &mov_ops, }, 390e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "movdqa",.ops = &mov_ops, }, 391e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "movl", .ops = &mov_ops, }, 392e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "movq", .ops = &mov_ops, }, 393e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "movslq", .ops = &mov_ops, }, 394e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "movzbl", .ops = &mov_ops, }, 395e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "movzwl", .ops = &mov_ops, }, 396e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "nop", .ops = &nop_ops, }, 397e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "nopl", .ops = &nop_ops, }, 398e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "nopw", .ops = &nop_ops, }, 399e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "or", .ops = &mov_ops, }, 400e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "orl", .ops = &mov_ops, }, 401e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "test", .ops = &mov_ops, }, 402e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "testb", .ops = &mov_ops, }, 403e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "testl", .ops = &mov_ops, }, 404e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "xadd", .ops = &mov_ops, }, 405e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "xbeginl", .ops = &jump_ops, }, 406e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng { .name = "xbeginq", .ops = &jump_ops, }, 407e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}; 408e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 409e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int ins__cmp(const void *name, const void *insp) 410e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 411e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const struct ins *ins = insp; 412e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 413e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return strcmp(name, ins->name); 414e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 415e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 416e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic struct ins *ins__find(const char *name) 417e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 418e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const int nmemb = ARRAY_SIZE(instructions); 419e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 420e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__cmp); 421e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 422e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 423e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengint symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym) 424e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 425e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct annotation *notes = symbol__annotation(sym); 426e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pthread_mutex_init(¬es->lock, NULL); 427e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 428e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 429e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 430e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengint symbol__alloc_hist(struct symbol *sym) 431e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 432e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct annotation *notes = symbol__annotation(sym); 433e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const size_t size = symbol__size(sym); 434e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng size_t sizeof_sym_hist; 435e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 436e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* Check for overflow when calculating sizeof_sym_hist */ 437e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (size > (SIZE_MAX - sizeof(struct sym_hist)) / sizeof(u64)) 438e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -1; 439e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 440e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64)); 441e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 442e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* Check for overflow in zalloc argument */ 443e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (sizeof_sym_hist > (SIZE_MAX - sizeof(*notes->src)) 444e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng / symbol_conf.nr_events) 445e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -1; 446e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 447e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist); 448e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (notes->src == NULL) 449e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -1; 450e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng notes->src->sizeof_sym_hist = sizeof_sym_hist; 451e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng notes->src->nr_histograms = symbol_conf.nr_events; 452e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng INIT_LIST_HEAD(¬es->src->source); 453e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 454e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 455e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 456e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengvoid symbol__annotate_zero_histograms(struct symbol *sym) 457e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 458e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct annotation *notes = symbol__annotation(sym); 459e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 460e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pthread_mutex_lock(¬es->lock); 461e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (notes->src != NULL) 462e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng memset(notes->src->histograms, 0, 463e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng notes->src->nr_histograms * notes->src->sizeof_sym_hist); 464e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pthread_mutex_unlock(¬es->lock); 465e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 466e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 467e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengint symbol__inc_addr_samples(struct symbol *sym, struct map *map, 468e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int evidx, u64 addr) 469e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 470e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unsigned offset; 471e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct annotation *notes; 472e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct sym_hist *h; 473e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 474e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng notes = symbol__annotation(sym); 475e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (notes->src == NULL) 476e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -ENOMEM; 477e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 478e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); 479e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 480e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (addr < sym->start || addr > sym->end) 481e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -ERANGE; 482e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 483e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng offset = addr - sym->start; 484e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng h = annotation__histogram(notes, evidx); 485e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng h->sum++; 486e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng h->addr[offset]++; 487e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 488e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64 489e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ", evidx=%d] => %" PRIu64 "\n", sym->start, sym->name, 490e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng addr, addr - sym->start, evidx, h->addr[offset]); 491e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 492e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 493e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 494e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void disasm_line__init_ins(struct disasm_line *dl) 495e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 496e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng dl->ins = ins__find(dl->name); 497e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 498e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (dl->ins == NULL) 499e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return; 500e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 501e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!dl->ins->ops) 502e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return; 503e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 504e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (dl->ins->ops->parse) 505e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng dl->ins->ops->parse(&dl->ops); 506e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 507e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 508e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int disasm_line__parse(char *line, char **namep, char **rawp) 509e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 510e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng char *name = line, tmp; 511e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 512e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng while (isspace(name[0])) 513e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ++name; 514e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 515e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (name[0] == '\0') 516e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -1; 517e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 518e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *rawp = name + 1; 519e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 520e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng while ((*rawp)[0] != '\0' && !isspace((*rawp)[0])) 521e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ++*rawp; 522e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 523e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng tmp = (*rawp)[0]; 524e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng (*rawp)[0] = '\0'; 525e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *namep = strdup(name); 526e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 527e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (*namep == NULL) 528e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_free_name; 529e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 530e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng (*rawp)[0] = tmp; 531e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 532e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if ((*rawp)[0] != '\0') { 533e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng (*rawp)++; 534e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng while (isspace((*rawp)[0])) 535e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ++(*rawp); 536e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 537e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 538e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 539e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 540e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout_free_name: 541e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng free(*namep); 542e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *namep = NULL; 543e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -1; 544e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 545e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 546e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize) 547e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 548e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct disasm_line *dl = zalloc(sizeof(*dl) + privsize); 549e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 550e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (dl != NULL) { 551e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng dl->offset = offset; 552e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng dl->line = strdup(line); 553e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (dl->line == NULL) 554e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_delete; 555e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 556e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (offset != -1) { 557e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (disasm_line__parse(dl->line, &dl->name, &dl->ops.raw) < 0) 558e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_free_line; 559e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 560e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng disasm_line__init_ins(dl); 561e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 562e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 563e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 564e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return dl; 565e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 566e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout_free_line: 567e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng free(dl->line); 568e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout_delete: 569e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng free(dl); 570e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return NULL; 571e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 572e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 573e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengvoid disasm_line__free(struct disasm_line *dl) 574e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 575e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng free(dl->line); 576e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng free(dl->name); 577e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (dl->ins && dl->ins->ops->free) 578e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng dl->ins->ops->free(&dl->ops); 579e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng else 580e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ins__delete(&dl->ops); 581e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng free(dl); 582e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 583e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 584e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengint disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw) 585e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 586e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (raw || !dl->ins) 587e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return scnprintf(bf, size, "%-6.6s %s", dl->name, dl->ops.raw); 588e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 589e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return ins__scnprintf(dl->ins, bf, size, &dl->ops); 590e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 591e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 592e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void disasm__add(struct list_head *head, struct disasm_line *line) 593e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 594e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng list_add_tail(&line->node, head); 595e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 596e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 597e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstruct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos) 598e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 599e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng list_for_each_entry_continue(pos, head, node) 600e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (pos->offset >= 0) 601e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return pos; 602e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 603e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return NULL; 604e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 605e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 606e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengdouble disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, 607e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng s64 end, const char **path) 608e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 609e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct source_line *src_line = notes->src->lines; 610e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng double percent = 0.0; 611e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 612e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (src_line) { 613e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng size_t sizeof_src_line = sizeof(*src_line) + 614e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sizeof(src_line->p) * (src_line->nr_pcnt - 1); 615e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 616e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng while (offset < end) { 617e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng src_line = (void *)notes->src->lines + 618e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng (sizeof_src_line * offset); 619e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 620e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (*path == NULL) 621e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *path = src_line->path; 622e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 623e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng percent += src_line->p[evidx].percent; 624e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng offset++; 625e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 626e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } else { 627e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct sym_hist *h = annotation__histogram(notes, evidx); 628e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng unsigned int hits = 0; 629e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 630e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng while (offset < end) 631e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng hits += h->addr[offset++]; 632e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 633e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (h->sum) 634e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng percent = 100.0 * hits / h->sum; 635e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 636e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 637e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return percent; 638e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 639e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 640e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start, 641e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct perf_evsel *evsel, u64 len, int min_pcnt, int printed, 642e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int max_lines, struct disasm_line *queue) 643e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 644e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng static const char *prev_line; 645e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng static const char *prev_color; 646e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 647e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (dl->offset != -1) { 648e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const char *path = NULL; 649e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng double percent, max_percent = 0.0; 650e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng double *ppercents = &percent; 651e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int i, nr_percent = 1; 652e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const char *color; 653e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct annotation *notes = symbol__annotation(sym); 654e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng s64 offset = dl->offset; 655e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const u64 addr = start + offset; 656e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct disasm_line *next; 657e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 658e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng next = disasm__get_next_ip_line(¬es->src->source, dl); 659e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 660e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (perf_evsel__is_group_event(evsel)) { 661e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng nr_percent = evsel->nr_members; 662e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ppercents = calloc(nr_percent, sizeof(double)); 663e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (ppercents == NULL) 664e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -1; 665e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 666e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 667e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng for (i = 0; i < nr_percent; i++) { 668e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng percent = disasm__calc_percent(notes, 669e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng notes->src->lines ? i : evsel->idx + i, 670e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng offset, 671e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng next ? next->offset : (s64) len, 672e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng &path); 673e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 674e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ppercents[i] = percent; 675e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (percent > max_percent) 676e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng max_percent = percent; 677e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 678e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 679e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (max_percent < min_pcnt) 680e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -1; 681e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 682e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (max_lines && printed >= max_lines) 683e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 1; 684e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 685e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (queue != NULL) { 686e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng list_for_each_entry_from(queue, ¬es->src->source, node) { 687e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (queue == dl) 688e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 689e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng disasm_line__print(queue, sym, start, evsel, len, 690e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 0, 0, 1, NULL); 691e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 692e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 693e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 694e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng color = get_percent_color(max_percent); 695e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 696e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* 697e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Also color the filename and line if needed, with 698e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * the same color than the percentage. Don't print it 699e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * twice for close colored addr with the same filename:line 700e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 701e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (path) { 702e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!prev_line || strcmp(prev_line, path) 703e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng || color != prev_color) { 704e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng color_fprintf(stdout, color, " %s", path); 705e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng prev_line = path; 706e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng prev_color = color; 707e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 708e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 709e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 710e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng for (i = 0; i < nr_percent; i++) { 711e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng percent = ppercents[i]; 712e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng color = get_percent_color(percent); 713e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng color_fprintf(stdout, color, " %7.2f", percent); 714e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 715e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 716e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng printf(" : "); 717e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng color_fprintf(stdout, PERF_COLOR_MAGENTA, " %" PRIx64 ":", addr); 718e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line); 719e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 720e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (ppercents != &percent) 721e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng free(ppercents); 722e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 723e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } else if (max_lines && printed >= max_lines) 724e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 1; 725e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng else { 726e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int width = 8; 727e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 728e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (queue) 729e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -1; 730e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 731e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (perf_evsel__is_group_event(evsel)) 732e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng width *= evsel->nr_members; 733e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 734e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!*dl->line) 735e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng printf(" %*s:\n", width, " "); 736e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng else 737e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng printf(" %*s: %s\n", width, " ", dl->line); 738e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 739e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 740e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 741e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 742e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 743e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/* 744e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * symbol__parse_objdump_line() parses objdump output (with -d --no-show-raw) 745e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * which looks like following 746e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * 747e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * 0000000000415500 <_init>: 748e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * 415500: sub $0x8,%rsp 749e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * 415504: mov 0x2f5ad5(%rip),%rax # 70afe0 <_DYNAMIC+0x2f8> 750e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * 41550b: test %rax,%rax 751e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * 41550e: je 415515 <_init+0x15> 752e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * 415510: callq 416e70 <__gmon_start__@plt> 753e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * 415515: add $0x8,%rsp 754e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * 415519: retq 755e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * 756e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * it will be parsed and saved into struct disasm_line as 757e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * <offset> <name> <ops.raw> 758e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * 759e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * The offset will be a relative offset from the start of the symbol and -1 760e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * means that it's not a disassembly line so should be treated differently. 761e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * The ops.raw part will be parsed further according to type of the instruction. 762e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 763e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int symbol__parse_objdump_line(struct symbol *sym, struct map *map, 764e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng FILE *file, size_t privsize) 765e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 766e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct annotation *notes = symbol__annotation(sym); 767e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct disasm_line *dl; 768e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng char *line = NULL, *parsed_line, *tmp, *tmp2, *c; 769e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng size_t line_len; 770e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng s64 line_ip, offset = -1; 771e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 772e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (getline(&line, &line_len, file) < 0) 773e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -1; 774e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 775e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!line) 776e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -1; 777e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 778e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng while (line_len != 0 && isspace(line[line_len - 1])) 779e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng line[--line_len] = '\0'; 780e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 781e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng c = strchr(line, '\n'); 782e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (c) 783e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *c = 0; 784e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 785e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng line_ip = -1; 786e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng parsed_line = line; 787e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 788e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* 789e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Strip leading spaces: 790e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 791e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng tmp = line; 792e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng while (*tmp) { 793e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (*tmp != ' ') 794e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 795e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng tmp++; 796e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 797e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 798e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (*tmp) { 799e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* 800e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Parse hexa addresses followed by ':' 801e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 802e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng line_ip = strtoull(tmp, &tmp2, 16); 803e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0') 804e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng line_ip = -1; 805e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 806e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 807e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (line_ip != -1) { 808e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u64 start = map__rip_2objdump(map, sym->start), 809e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng end = map__rip_2objdump(map, sym->end); 810e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 811e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng offset = line_ip - start; 812e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if ((u64)line_ip < start || (u64)line_ip > end) 813e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng offset = -1; 814e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng else 815e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng parsed_line = tmp2 + 1; 816e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 817e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 818e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng dl = disasm_line__new(offset, parsed_line, privsize); 819e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng free(line); 820e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 821e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (dl == NULL) 822e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -1; 823e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 824e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (dl->ops.target.offset == UINT64_MAX) 825e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng dl->ops.target.offset = dl->ops.target.addr - 826e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng map__rip_2objdump(map, sym->start); 827e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 828e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* 829e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * kcore has no symbols, so add the call target name if it is on the 830e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * same map. 831e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 832e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (dl->ins && ins__is_call(dl->ins) && !dl->ops.target.name) { 833e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct symbol *s; 834e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u64 ip = dl->ops.target.addr; 835e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 836e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (ip >= map->start && ip <= map->end) { 837e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ip = map->map_ip(map, ip); 838e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng s = map__find_symbol(map, ip, NULL); 839e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (s && s->start == ip) 840e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng dl->ops.target.name = strdup(s->name); 841e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 842e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 843e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 844e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng disasm__add(¬es->src->source, dl); 845e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 846e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 847e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 848e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 849e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void delete_last_nop(struct symbol *sym) 850e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 851e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct annotation *notes = symbol__annotation(sym); 852e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct list_head *list = ¬es->src->source; 853e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct disasm_line *dl; 854e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 855e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng while (!list_empty(list)) { 856e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng dl = list_entry(list->prev, struct disasm_line, node); 857e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 858e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (dl->ins && dl->ins->ops) { 859e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (dl->ins->ops != &nop_ops) 860e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return; 861e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } else { 862e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!strstr(dl->line, " nop ") && 863e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng !strstr(dl->line, " nopl ") && 864e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng !strstr(dl->line, " nopw ")) 865e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return; 866e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 867e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 868e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng list_del(&dl->node); 869e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng disasm_line__free(dl); 870e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 871e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 872e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 873e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengint symbol__annotate(struct symbol *sym, struct map *map, size_t privsize) 874e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 875e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct dso *dso = map->dso; 876e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng char *filename = dso__build_id_filename(dso, NULL, 0); 877e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng bool free_filename = true; 878e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng char command[PATH_MAX * 2]; 879e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng FILE *file; 880e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int err = 0; 881e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng char symfs_filename[PATH_MAX]; 882e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 883e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (filename) { 884e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng snprintf(symfs_filename, sizeof(symfs_filename), "%s%s", 885e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng symbol_conf.symfs, filename); 886e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 887e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 888e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (filename == NULL) { 889e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (dso->has_build_id) { 890e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_err("Can't annotate %s: not enough memory\n", 891e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sym->name); 892e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -ENOMEM; 893e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 894e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto fallback; 895e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } else if (readlink(symfs_filename, command, sizeof(command)) < 0 || 896e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng strstr(command, "[kernel.kallsyms]") || 897e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng access(symfs_filename, R_OK)) { 898e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng free(filename); 899e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengfallback: 900e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* 901e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * If we don't have build-ids or the build-id file isn't in the 902e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * cache, or is just a kallsyms file, well, lets hope that this 903e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * DSO is the same as when 'perf record' ran. 904e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 905e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng filename = dso->long_name; 906e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng snprintf(symfs_filename, sizeof(symfs_filename), "%s%s", 907e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng symbol_conf.symfs, filename); 908e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng free_filename = false; 909e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 910e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 911e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && 912e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng !dso__is_kcore(dso)) { 913e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng char bf[BUILD_ID_SIZE * 2 + 16] = " with build id "; 914e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng char *build_id_msg = NULL; 915e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 916e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (dso->annotate_warned) 917e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_free_filename; 918e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 919e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (dso->has_build_id) { 920e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng build_id__sprintf(dso->build_id, 921e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sizeof(dso->build_id), bf + 15); 922e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng build_id_msg = bf; 923e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 924e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng err = -ENOENT; 925e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng dso->annotate_warned = 1; 926e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_err("Can't annotate %s:\n\n" 927e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng "No vmlinux file%s\nwas found in the path.\n\n" 928e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng "Please use:\n\n" 929e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng " perf buildid-cache -vu vmlinux\n\n" 930e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng "or:\n\n" 931e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng " --vmlinux vmlinux\n", 932e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sym->name, build_id_msg ?: ""); 933e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_free_filename; 934e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 935e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 936e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__, 937e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng filename, sym->name, map->unmap_ip(map, sym->start), 938e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng map->unmap_ip(map, sym->end)); 939e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 940e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_debug("annotating [%p] %30s : [%p] %30s\n", 941e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng dso, dso->long_name, sym, sym->name); 942e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 943e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng snprintf(command, sizeof(command), 944e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng "%s %s%s --start-address=0x%016" PRIx64 945e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng " --stop-address=0x%016" PRIx64 946e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng " -d %s %s -C %s 2>/dev/null|grep -v %s|expand", 947e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng objdump_path ? objdump_path : "objdump", 948e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng disassembler_style ? "-M " : "", 949e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng disassembler_style ? disassembler_style : "", 950e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng map__rip_2objdump(map, sym->start), 951e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng map__rip_2objdump(map, sym->end+1), 952e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng symbol_conf.annotate_asm_raw ? "" : "--no-show-raw", 953e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng symbol_conf.annotate_src ? "-S" : "", 954e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng symfs_filename, filename); 955e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 956e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_debug("Executing: %s\n", command); 957e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 958e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng file = popen(command, "r"); 959e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!file) 960e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_free_filename; 961e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 962e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng while (!feof(file)) 963e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (symbol__parse_objdump_line(sym, map, file, privsize) < 0) 964e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 965e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 966e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* 967e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * kallsyms does not have symbol sizes so there may a nop at the end. 968e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Remove it. 969e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 970e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (dso__is_kcore(dso)) 971e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng delete_last_nop(sym); 972e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 973e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pclose(file); 974e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout_free_filename: 975e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (free_filename) 976e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng free(filename); 977e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return err; 978e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 979e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 980e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void insert_source_line(struct rb_root *root, struct source_line *src_line) 981e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 982e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct source_line *iter; 983e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct rb_node **p = &root->rb_node; 984e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct rb_node *parent = NULL; 985e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int i, ret; 986e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 987e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng while (*p != NULL) { 988e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng parent = *p; 989e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng iter = rb_entry(parent, struct source_line, node); 990e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 991e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ret = strcmp(iter->path, src_line->path); 992e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (ret == 0) { 993e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng for (i = 0; i < src_line->nr_pcnt; i++) 994e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng iter->p[i].percent_sum += src_line->p[i].percent; 995e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return; 996e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 997e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 998e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (ret < 0) 999e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng p = &(*p)->rb_left; 1000e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng else 1001e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng p = &(*p)->rb_right; 1002e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 1003e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1004e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng for (i = 0; i < src_line->nr_pcnt; i++) 1005e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng src_line->p[i].percent_sum = src_line->p[i].percent; 1006e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1007e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng rb_link_node(&src_line->node, parent, p); 1008e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng rb_insert_color(&src_line->node, root); 1009e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 1010e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1011e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int cmp_source_line(struct source_line *a, struct source_line *b) 1012e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 1013e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int i; 1014e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1015e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng for (i = 0; i < a->nr_pcnt; i++) { 1016e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (a->p[i].percent_sum == b->p[i].percent_sum) 1017e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng continue; 1018e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return a->p[i].percent_sum > b->p[i].percent_sum; 1019e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 1020e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1021e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 1022e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 1023e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1024e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void __resort_source_line(struct rb_root *root, struct source_line *src_line) 1025e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 1026e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct source_line *iter; 1027e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct rb_node **p = &root->rb_node; 1028e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct rb_node *parent = NULL; 1029e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1030e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng while (*p != NULL) { 1031e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng parent = *p; 1032e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng iter = rb_entry(parent, struct source_line, node); 1033e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1034e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (cmp_source_line(src_line, iter)) 1035e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng p = &(*p)->rb_left; 1036e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng else 1037e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng p = &(*p)->rb_right; 1038e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 1039e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1040e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng rb_link_node(&src_line->node, parent, p); 1041e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng rb_insert_color(&src_line->node, root); 1042e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 1043e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1044e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void resort_source_line(struct rb_root *dest_root, struct rb_root *src_root) 1045e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 1046e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct source_line *src_line; 1047e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct rb_node *node; 1048e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1049e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng node = rb_first(src_root); 1050e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng while (node) { 1051e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct rb_node *next; 1052e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1053e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng src_line = rb_entry(node, struct source_line, node); 1054e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng next = rb_next(node); 1055e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng rb_erase(node, src_root); 1056e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1057e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng __resort_source_line(dest_root, src_line); 1058e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng node = next; 1059e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 1060e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 1061e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1062e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void symbol__free_source_line(struct symbol *sym, int len) 1063e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 1064e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct annotation *notes = symbol__annotation(sym); 1065e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct source_line *src_line = notes->src->lines; 1066e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng size_t sizeof_src_line; 1067e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int i; 1068e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1069e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sizeof_src_line = sizeof(*src_line) + 1070e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng (sizeof(src_line->p) * (src_line->nr_pcnt - 1)); 1071e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1072e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng for (i = 0; i < len; i++) { 1073e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng free(src_line->path); 1074e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng src_line = (void *)src_line + sizeof_src_line; 1075e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 1076e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1077e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng free(notes->src->lines); 1078e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng notes->src->lines = NULL; 1079e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 1080e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1081e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/* Get the filename:line for the colored entries */ 1082e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int symbol__get_source_line(struct symbol *sym, struct map *map, 1083e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct perf_evsel *evsel, 1084e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct rb_root *root, int len, 1085e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const char *filename) 1086e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 1087e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u64 start; 1088e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int i, k; 1089e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int evidx = evsel->idx; 1090e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng char cmd[PATH_MAX * 2]; 1091e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct source_line *src_line; 1092e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct annotation *notes = symbol__annotation(sym); 1093e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct sym_hist *h = annotation__histogram(notes, evidx); 1094e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct rb_root tmp_root = RB_ROOT; 1095e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int nr_pcnt = 1; 1096e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u64 h_sum = h->sum; 1097e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng size_t sizeof_src_line = sizeof(struct source_line); 1098e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1099e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (perf_evsel__is_group_event(evsel)) { 1100e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng for (i = 1; i < evsel->nr_members; i++) { 1101e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng h = annotation__histogram(notes, evidx + i); 1102e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng h_sum += h->sum; 1103e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 1104e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng nr_pcnt = evsel->nr_members; 1105e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sizeof_src_line += (nr_pcnt - 1) * sizeof(src_line->p); 1106e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 1107e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1108e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!h_sum) 1109e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 1110e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1111e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng src_line = notes->src->lines = calloc(len, sizeof_src_line); 1112e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!notes->src->lines) 1113e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -1; 1114e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1115e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng start = map__rip_2objdump(map, sym->start); 1116e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1117e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng for (i = 0; i < len; i++) { 1118e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng char *path = NULL; 1119e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng size_t line_len; 1120e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u64 offset; 1121e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng FILE *fp; 1122e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng double percent_max = 0.0; 1123e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1124e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng src_line->nr_pcnt = nr_pcnt; 1125e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1126e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng for (k = 0; k < nr_pcnt; k++) { 1127e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng h = annotation__histogram(notes, evidx + k); 1128e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng src_line->p[k].percent = 100.0 * h->addr[i] / h->sum; 1129e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1130e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (src_line->p[k].percent > percent_max) 1131e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng percent_max = src_line->p[k].percent; 1132e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 1133e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1134e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (percent_max <= 0.5) 1135e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto next; 1136e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1137e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng offset = start + i; 1138e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset); 1139e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng fp = popen(cmd, "r"); 1140e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!fp) 1141e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto next; 1142e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1143e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (getline(&path, &line_len, fp) < 0 || !line_len) 1144e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto next_close; 1145e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1146e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng src_line->path = malloc(sizeof(char) * line_len + 1); 1147e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!src_line->path) 1148e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto next_close; 1149e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1150e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng strcpy(src_line->path, path); 1151e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng insert_source_line(&tmp_root, src_line); 1152e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1153e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng next_close: 1154e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pclose(fp); 1155e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng next: 1156e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng src_line = (void *)src_line + sizeof_src_line; 1157e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 1158e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1159e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng resort_source_line(root, &tmp_root); 1160e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 1161e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 1162e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1163e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void print_summary(struct rb_root *root, const char *filename) 1164e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 1165e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct source_line *src_line; 1166e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct rb_node *node; 1167e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1168e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng printf("\nSorted summary for file %s\n", filename); 1169e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng printf("----------------------------------------------\n\n"); 1170e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1171e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (RB_EMPTY_ROOT(root)) { 1172e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng printf(" Nothing higher than %1.1f%%\n", MIN_GREEN); 1173e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return; 1174e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 1175e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1176e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng node = rb_first(root); 1177e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng while (node) { 1178e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng double percent, percent_max = 0.0; 1179e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const char *color; 1180e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng char *path; 1181e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int i; 1182e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1183e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng src_line = rb_entry(node, struct source_line, node); 1184e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng for (i = 0; i < src_line->nr_pcnt; i++) { 1185e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng percent = src_line->p[i].percent_sum; 1186e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng color = get_percent_color(percent); 1187e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng color_fprintf(stdout, color, " %7.2f", percent); 1188e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1189e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (percent > percent_max) 1190e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng percent_max = percent; 1191e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 1192e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1193e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng path = src_line->path; 1194e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng color = get_percent_color(percent_max); 1195e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng color_fprintf(stdout, color, " %s", path); 1196e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1197e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng node = rb_next(node); 1198e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 1199e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 1200e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1201e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void symbol__annotate_hits(struct symbol *sym, struct perf_evsel *evsel) 1202e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 1203e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct annotation *notes = symbol__annotation(sym); 1204e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct sym_hist *h = annotation__histogram(notes, evsel->idx); 1205e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u64 len = symbol__size(sym), offset; 1206e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1207e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng for (offset = 0; offset < len; ++offset) 1208e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (h->addr[offset] != 0) 1209e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2, 1210e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sym->start + offset, h->addr[offset]); 1211e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum); 1212e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 1213e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1214e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengint symbol__annotate_printf(struct symbol *sym, struct map *map, 1215e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct perf_evsel *evsel, bool full_paths, 1216e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int min_pcnt, int max_lines, int context) 1217e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 1218e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct dso *dso = map->dso; 1219e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng char *filename; 1220e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const char *d_filename; 1221e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct annotation *notes = symbol__annotation(sym); 1222e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct disasm_line *pos, *queue = NULL; 1223e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u64 start = map__rip_2objdump(map, sym->start); 1224e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int printed = 2, queue_len = 0; 1225e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int more = 0; 1226e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u64 len; 1227e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int width = 8; 1228e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int namelen; 1229e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1230e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng filename = strdup(dso->long_name); 1231e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!filename) 1232e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -ENOMEM; 1233e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1234e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (full_paths) 1235e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng d_filename = filename; 1236e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng else 1237e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng d_filename = basename(filename); 1238e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1239e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng len = symbol__size(sym); 1240e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng namelen = strlen(d_filename); 1241e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1242e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (perf_evsel__is_group_event(evsel)) 1243e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng width *= evsel->nr_members; 1244e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1245e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng printf(" %-*.*s| Source code & Disassembly of %s\n", 1246e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng width, width, "Percent", d_filename); 1247e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng printf("-%-*.*s-------------------------------------\n", 1248e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng width+namelen, width+namelen, graph_dotted_line); 1249e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1250e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (verbose) 1251e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng symbol__annotate_hits(sym, evsel); 1252e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1253e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng list_for_each_entry(pos, ¬es->src->source, node) { 1254e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (context && queue == NULL) { 1255e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng queue = pos; 1256e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng queue_len = 0; 1257e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 1258e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1259e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng switch (disasm_line__print(pos, sym, start, evsel, len, 1260e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng min_pcnt, printed, max_lines, 1261e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng queue)) { 1262e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng case 0: 1263e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ++printed; 1264e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (context) { 1265e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng printed += queue_len; 1266e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng queue = NULL; 1267e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng queue_len = 0; 1268e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 1269e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 1270e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng case 1: 1271e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* filtered by max_lines */ 1272e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ++more; 1273e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 1274e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng case -1: 1275e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng default: 1276e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* 1277e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Filtered by min_pcnt or non IP lines when 1278e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * context != 0 1279e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 1280e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!context) 1281e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 1282e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (queue_len == context) 1283e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng queue = list_entry(queue->node.next, typeof(*queue), node); 1284e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng else 1285e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ++queue_len; 1286e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 1287e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 1288e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 1289e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1290e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng free(filename); 1291e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1292e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return more; 1293e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 1294e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1295e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengvoid symbol__annotate_zero_histogram(struct symbol *sym, int evidx) 1296e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 1297e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct annotation *notes = symbol__annotation(sym); 1298e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct sym_hist *h = annotation__histogram(notes, evidx); 1299e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1300e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng memset(h, 0, notes->src->sizeof_sym_hist); 1301e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 1302e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1303e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengvoid symbol__annotate_decay_histogram(struct symbol *sym, int evidx) 1304e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 1305e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct annotation *notes = symbol__annotation(sym); 1306e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct sym_hist *h = annotation__histogram(notes, evidx); 1307e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int len = symbol__size(sym), offset; 1308e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1309e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng h->sum = 0; 1310e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng for (offset = 0; offset < len; ++offset) { 1311e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng h->addr[offset] = h->addr[offset] * 7 / 8; 1312e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng h->sum += h->addr[offset]; 1313e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 1314e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 1315e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1316e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengvoid disasm__purge(struct list_head *head) 1317e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 1318e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct disasm_line *pos, *n; 1319e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1320e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng list_for_each_entry_safe(pos, n, head, node) { 1321e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng list_del(&pos->node); 1322e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng disasm_line__free(pos); 1323e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 1324e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 1325e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1326e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp) 1327e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 1328e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng size_t printed; 1329e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1330e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (dl->offset == -1) 1331e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return fprintf(fp, "%s\n", dl->line); 1332e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1333e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng printed = fprintf(fp, "%#" PRIx64 " %s", dl->offset, dl->name); 1334e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1335e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (dl->ops.raw[0] != '\0') { 1336e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ", 1337e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng dl->ops.raw); 1338e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 1339e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1340e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return printed + fprintf(fp, "\n"); 1341e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 1342e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1343e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengsize_t disasm__fprintf(struct list_head *head, FILE *fp) 1344e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 1345e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct disasm_line *pos; 1346e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng size_t printed = 0; 1347e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1348e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng list_for_each_entry(pos, head, node) 1349e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng printed += disasm_line__fprintf(pos, fp); 1350e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1351e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return printed; 1352e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 1353e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1354e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengint symbol__tty_annotate(struct symbol *sym, struct map *map, 1355e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct perf_evsel *evsel, bool print_lines, 1356e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng bool full_paths, int min_pcnt, int max_lines) 1357e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 1358e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct dso *dso = map->dso; 1359e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const char *filename = dso->long_name; 1360e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct rb_root source_line = RB_ROOT; 1361e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u64 len; 1362e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1363e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (symbol__annotate(sym, map, 0) < 0) 1364e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -1; 1365e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1366e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng len = symbol__size(sym); 1367e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1368e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (print_lines) { 1369e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng symbol__get_source_line(sym, map, evsel, &source_line, 1370e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng len, filename); 1371e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng print_summary(&source_line, filename); 1372e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 1373e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1374e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng symbol__annotate_printf(sym, map, evsel, full_paths, 1375e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng min_pcnt, max_lines, 0); 1376e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (print_lines) 1377e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng symbol__free_source_line(sym, len); 1378e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1379e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng disasm__purge(&symbol__annotation(sym)->src->source); 1380e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1381e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 1382e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 1383