// SPDX-License-Identifier: GPL-2.0-only/* * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> * * Parts came from builtin-annotate.c, see those files for further * copyright notes. */ #include <errno.h>#include <inttypes.h>#include <libgen.h>#include <stdlib.h>#include <bpf/bpf.h>#include <bpf/btf.h>#include <bpf/libbpf.h>#include <linux/btf.h>#include "util.h" // hex_width()#include "ui/ui.h"#include "sort.h"#include "build-id.h"#include "color.h"#include "config.h"#include "dso.h"#include "env.h"#include "map.h"#include "maps.h"#include "symbol.h"#include "srcline.h"#include "units.h"#include "debug.h"#include "annotate.h"#include "evsel.h"#include "evlist.h"#include "bpf-event.h"#include "block-range.h"#include "string2.h"#include "util/event.h"#include "arch/common.h"#include <regex.h>#include <pthread.h>#include <linux/bitops.h>#include <linux/kernel.h>#include <linux/string.h>#include <subcmd/parse-options.h>#include <subcmd/run-command.h> /* FIXME: For the HE_COLORSET */#include "ui/browser.h" /* * FIXME: Using the same values as slang.h, * but that header may not be available everywhere */#define LARROW_CHAR ((unsigned char)',')#define RARROW_CHAR ((unsigned char)'+')#define DARROW_CHAR ((unsigned char)'.')#define UARROW_CHAR ((unsigned char)'-') #include <linux/ctype.h> struct annotation_options annotation__default_options = { .use_offset = true, .jump_arrows = true, .annotate_src = true, .offset_level = ANNOTATION__OFFSET_JUMP_TARGETS, .percent_type = PERCENT_PERIOD_LOCAL,}; static regex_t file_lineno; static struct ins_ops *ins__find(struct arch *arch, const char *name);static void ins__sort(struct arch *arch);static int disasm_line__parse(char *line, const char **namep, char **rawp); struct arch { const char *name; struct ins *instructions; size_t nr_instructions; size_t nr_instructions_allocated; struct ins_ops *(*associate_instruction_ops)(struct arch *arch, const char *name); bool sorted_instructions; bool initialized; void *priv; unsigned int model; unsigned int family; int (*init)(struct arch *arch, char *cpuid); bool (*ins_is_fused)(struct arch *arch, const char *ins1, const char *ins2); struct { char comment_char; char skip_functions_char; } objdump;}; static struct ins_ops call_ops;static struct ins_ops dec_ops;static struct ins_ops jump_ops;static struct ins_ops mov_ops;static struct ins_ops nop_ops;static struct ins_ops lock_ops;static struct ins_ops ret_ops; static int arch__grow_instructions(struct arch *arch){ struct ins *new_instructions; size_t new_nr_allocated; if (arch->nr_instructions_allocated == 0 && arch->instructions) goto grow_from_non_allocated_table; new_nr_allocated = arch->nr_instructions_allocated + 128; new_instructions = realloc(arch->instructions, new_nr_allocated * sizeof(struct ins)); if (new_instructions == NULL) return -1; out_update_instructions: arch->instructions = new_instructions; arch->nr_instructions_allocated = new_nr_allocated; return 0; grow_from_non_allocated_table: new_nr_allocated = arch->nr_instructions + 128; new_instructions = calloc(new_nr_allocated, sizeof(struct ins)); if (new_instructions == NULL) return -1; memcpy(new_instructions, arch->instructions, arch->nr_instructions); goto out_update_instructions;} static int arch__associate_ins_ops(struct arch* arch, const char *name, struct ins_ops *ops){ struct ins *ins; if (arch->nr_instructions == arch->nr_instructions_allocated && arch__grow_instructions(arch)) return -1; ins = &arch->instructions[arch->nr_instructions]; ins->name = strdup(name); if (!ins->name) return -1; ins->ops = ops; arch->nr_instructions++; ins__sort(arch); return 0;} #include "arch/arc/annotate/instructions.c"#include "arch/arm/annotate/instructions.c"#include "arch/arm64/annotate/instructions.c"#include "arch/csky/annotate/instructions.c"#include "arch/x86/annotate/instructions.c"#include "arch/powerpc/annotate/instructions.c"#include "arch/s390/annotate/instructions.c"#include "arch/sparc/annotate/instructions.c" static struct arch architectures[] = { { .name = "arc", .init = arc__annotate_init, }, { .name = "arm", .init = arm__annotate_init, }, { .name = "arm64", .init = arm64__annotate_init, }, { .name = "csky", .init = csky__annotate_init, }, { .name = "x86", .init = x86__annotate_init, .instructions = x86__instructions, .nr_instructions = ARRAY_SIZE(x86__instructions), .ins_is_fused = x86__ins_is_fused, .objdump = { .comment_char = '#', }, }, { .name = "powerpc", .init = powerpc__annotate_init, }, { .name = "s390", .init = s390__annotate_init, .objdump = { .comment_char = '#', }, }, { .name = "sparc", .init = sparc__annotate_init, .objdump = { .comment_char = '#', }, },}; static void ins__delete(struct ins_operands *ops){ if (ops == NULL) return; zfree(&ops->source.raw); zfree(&ops->source.name); zfree(&ops->target.raw); zfree(&ops->target.name);} static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops, int max_ins_name){ return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->raw);} int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops, int max_ins_name){ if (ins->ops->scnprintf) return ins->ops->scnprintf(ins, bf, size, ops, max_ins_name); return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name);} bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2){ if (!arch || !arch->ins_is_fused) return false; return arch->ins_is_fused(arch, ins1, ins2);} static int call__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms){ char *endptr, *tok, *name; struct map *map = ms->map; struct addr_map_symbol target = { .ms = { .map = map, }, }; ops->target.addr = strtoull(ops->raw, &endptr, 16); name = strchr(endptr, '<'); if (name == NULL) goto indirect_call; name++; if (arch->objdump.skip_functions_char && strchr(name, arch->objdump.skip_functions_char)) return -1; tok = strchr(name, '>'); if (tok == NULL) return -1; *tok = '\0'; ops->target.name = strdup(name); *tok = '>'; if (ops->target.name == NULL) return -1;find_target: target.addr = map__objdump_2mem(map, ops->target.addr); if (maps__find_ams(ms->maps, &target) == 0 && map__rip_2objdump(target.ms.map, map->map_ip(target.ms.map, target.addr)) == ops->target.addr) ops->target.sym = target.ms.sym; return 0; indirect_call: tok = strchr(endptr, '*'); if (tok != NULL) { endptr++; /* Indirect call can use a non-rip register and offset: callq *0x8(%rbx). * Do not parse such instruction. */ if (strstr(endptr, "(%r") == NULL) ops->target.addr = strtoull(endptr, NULL, 16); } goto find_target;} static int call__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops, int max_ins_name){ if (ops->target.sym) return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.sym->name); if (ops->target.addr == 0) return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); if (ops->target.name) return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.name); return scnprintf(bf, size, "%-*s *%" PRIx64, max_ins_name, ins->name, ops->target.addr);} static struct ins_ops call_ops = { .parse = call__parse, .scnprintf = call__scnprintf,}; bool ins__is_call(const struct ins *ins){ return ins->ops == &call_ops || ins->ops == &s390_call_ops;} /* * Prevents from matching commas in the comment section, e.g.: * ffff200008446e70: b.cs ffff2000084470f4 <generic_exec_single+0x314> // b.hs, b.nlast */static inline const char *validate_comma(const char *c, struct ins_operands *ops){ if (ops->raw_comment && c > ops->raw_comment) return NULL; return c;} static int jump__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms){ struct map *map = ms->map; struct symbol *sym = ms->sym; struct addr_map_symbol target = { .ms = { .map = map, }, }; const char *c = strchr(ops->raw, ','); u64 start, end; ops->raw_comment = strchr(ops->raw, arch->objdump.comment_char); c = validate_comma(c, ops); /* * Examples of lines to parse for the _cpp_lex_token@@Base * function: * * 1159e6c: jne 115aa32 <_cpp_lex_token@@Base+0xf92> * 1159e8b: jne c469be <cpp_named_operator2name@@Base+0xa72> * * The first is a jump to an offset inside the same function, * the second is to another function, i.e. that 0xa72 is an * offset in the cpp_named_operator2name@@base function. */ /* * skip over possible up to 2 operands to get to address, e.g.: * tbnz w0, #26, ffff0000083cd190 <security_file_permission+0xd0> */ if (c++ != NULL) { ops->target.addr = strtoull(c, NULL, 16); if (!ops->target.addr) { c = strchr(c, ','); c = validate_comma(c, ops); if (c++ != NULL) ops->target.addr = strtoull(c, NULL, 16); } } else { ops->target.addr = strtoull(ops->raw, NULL, 16); } target.addr = map__objdump_2mem(map, ops->target.addr); start = map->unmap_ip(map, sym->start), end = map->unmap_ip(map, sym->end); ops->target.outside = target.addr < start || target.addr > end; /* * FIXME: things like this in _cpp_lex_token (gcc's cc1 program): cpp_named_operator2name@@Base+0xa72 * Point to a place that is after the cpp_named_operator2name * boundaries, i.e. in the ELF symbol table for cc1 * cpp_named_operator2name is marked as being 32-bytes long, but it in * fact is much larger than that, so we seem to need a symbols__find() * routine that looks for >= current->start and < next_symbol->start, * possibly just for C++ objects? * * For now lets just make some progress by marking jumps to outside the * current function as call like. * * Actual navigation will come next, with further understanding of how * the symbol searching and disassembly should be done. */ if (maps__find_ams(ms->maps, &target) == 0 && map__rip_2objdump(target.ms.map, map->map_ip(target.ms.map, target.addr)) == ops->target.addr) ops->target.sym = target.ms.sym; if (!ops->target.outside) { ops->target.offset = target.addr - start; ops->target.offset_avail = true; } else { ops->target.offset_avail = false; } return 0;} static int jump__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops, int max_ins_name){ const char *c; if (!ops->target.addr || ops->target.offset < 0) return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); if (ops->target.outside && ops->target.sym != NULL) return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.sym->name); c = strchr(ops->raw, ','); c = validate_comma(c, ops); if (c != NULL) { const char *c2 = strchr(c + 1, ','); c2 = validate_comma(c2, ops); /* check for 3-op insn */ if (c2 != NULL) c = c2; c++; /* mirror arch objdump's space-after-comma style */ if (*c == ' ') c++; } return scnprintf(bf, size, "%-*s %.*s%" PRIx64, max_ins_name, ins->name, c ? c - ops->raw : 0, ops->raw, ops->target.offset);} static struct ins_ops jump_ops = { .parse = jump__parse, .scnprintf = jump__scnprintf,}; bool ins__is_jump(const struct ins *ins){ return ins->ops == &jump_ops;} static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep){ char *endptr, *name, *t; if (strstr(raw, "(%rip)") == NULL) return 0; *addrp = strtoull(comment, &endptr, 16); if (endptr == comment) return 0; name = strchr(endptr, '<'); if (name == NULL) return -1; name++; t = strchr(name, '>'); if (t == NULL) return 0; *t = '\0'; *namep = strdup(name); *t = '>'; return 0;} static int lock__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms){ ops->locked.ops = zalloc(sizeof(*ops->locked.ops)); if (ops->locked.ops == NULL) return 0; if (disasm_line__parse(ops->raw, &ops->locked.ins.name, &ops->locked.ops->raw) < 0) goto out_free_ops; ops->locked.ins.ops = ins__find(arch, ops->locked.ins.name); if (ops->locked.ins.ops == NULL) goto out_free_ops; if (ops->locked.ins.ops->parse && ops->locked.ins.ops->parse(arch, ops->locked.ops, ms) < 0) goto out_free_ops; return 0; out_free_ops: zfree(&ops->locked.ops); return 0;}Lines 1–500 of 3201. Load more
// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> * * Parts came from builtin-annotate.c, see those files for further * copyright notes. */ #include <errno.h> #include <inttypes.h> #include <libgen.h> #include <stdlib.h> #include <bpf/bpf.h> #include <bpf/btf.h> #include <bpf/libbpf.h> #include <linux/btf.h> #include "util.h" // hex_width() #include "ui/ui.h" #include "sort.h" #include "build-id.h" #include "color.h" #include "config.h" #include "dso.h" #include "env.h" #include "map.h" #include "maps.h" #include "symbol.h" #include "srcline.h" #include "units.h" #include "debug.h" #include "annotate.h" #include "evsel.h" #include "evlist.h" #include "bpf-event.h" #include "block-range.h" #include "string2.h" #include "util/event.h" #include "arch/common.h" #include <regex.h> #include <pthread.h> #include <linux/bitops.h> #include <linux/kernel.h> #include <linux/string.h> #include <subcmd/parse-options.h> #include <subcmd/run-command.h> /* FIXME: For the HE_COLORSET */ #include "ui/browser.h" /* * FIXME: Using the same values as slang.h, * but that header may not be available everywhere */ #define LARROW_CHAR ((unsigned char)',') #define RARROW_CHAR ((unsigned char)'+') #define DARROW_CHAR ((unsigned char)'.') #define UARROW_CHAR ((unsigned char)'-') #include <linux/ctype.h> struct annotation_options annotation__default_options = { .use_offset = true, .jump_arrows = true, .annotate_src = true, .offset_level = ANNOTATION__OFFSET_JUMP_TARGETS, .percent_type = PERCENT_PERIOD_LOCAL, }; static regex_t file_lineno; static struct ins_ops *ins__find(struct arch *arch, const char *name); static void ins__sort(struct arch *arch); static int disasm_line__parse(char *line, const char **namep, char **rawp); struct arch { const char *name; struct ins *instructions; size_t nr_instructions; size_t nr_instructions_allocated; struct ins_ops *(*associate_instruction_ops)(struct arch *arch, const char *name); bool sorted_instructions; bool initialized; void *priv; unsigned int model; unsigned int family; int (*init)(struct arch *arch, char *cpuid); bool (*ins_is_fused)(struct arch *arch, const char *ins1, const char *ins2); struct { char comment_char; char skip_functions_char; } objdump; }; static struct ins_ops call_ops; static struct ins_ops dec_ops; static struct ins_ops jump_ops; static struct ins_ops mov_ops; static struct ins_ops nop_ops; static struct ins_ops lock_ops; static struct ins_ops ret_ops; static int arch__grow_instructions(struct arch *arch) { struct ins *new_instructions; size_t new_nr_allocated; if (arch->nr_instructions_allocated == 0 && arch->instructions) goto grow_from_non_allocated_table; new_nr_allocated = arch->nr_instructions_allocated + 128; new_instructions = realloc(arch->instructions, new_nr_allocated * sizeof(struct ins)); if (new_instructions == NULL) return -1; out_update_instructions: arch->instructions = new_instructions; arch->nr_instructions_allocated = new_nr_allocated; return 0; grow_from_non_allocated_table: new_nr_allocated = arch->nr_instructions + 128; new_instructions = calloc(new_nr_allocated, sizeof(struct ins)); if (new_instructions == NULL) return -1; memcpy(new_instructions, arch->instructions, arch->nr_instructions); goto out_update_instructions; } static int arch__associate_ins_ops(struct arch* arch, const char *name, struct ins_ops *ops) { struct ins *ins; if (arch->nr_instructions == arch->nr_instructions_allocated && arch__grow_instructions(arch)) return -1; ins = &arch->instructions[arch->nr_instructions]; ins->name = strdup(name); if (!ins->name) return -1; ins->ops = ops; arch->nr_instructions++; ins__sort(arch); return 0; } #include "arch/arc/annotate/instructions.c" #include "arch/arm/annotate/instructions.c" #include "arch/arm64/annotate/instructions.c" #include "arch/csky/annotate/instructions.c" #include "arch/x86/annotate/instructions.c" #include "arch/powerpc/annotate/instructions.c" #include "arch/s390/annotate/instructions.c" #include "arch/sparc/annotate/instructions.c" static struct arch architectures[] = { { .name = "arc", .init = arc__annotate_init, }, { .name = "arm", .init = arm__annotate_init, }, { .name = "arm64", .init = arm64__annotate_init, }, { .name = "csky", .init = csky__annotate_init, }, { .name = "x86", .init = x86__annotate_init, .instructions = x86__instructions, .nr_instructions = ARRAY_SIZE(x86__instructions), .ins_is_fused = x86__ins_is_fused, .objdump = { .comment_char = '#', }, }, { .name = "powerpc", .init = powerpc__annotate_init, }, { .name = "s390", .init = s390__annotate_init, .objdump = { .comment_char = '#', }, }, { .name = "sparc", .init = sparc__annotate_init, .objdump = { .comment_char = '#', }, }, }; static void ins__delete(struct ins_operands *ops) { if (ops == NULL) return; zfree(&ops->source.raw); zfree(&ops->source.name); zfree(&ops->target.raw); zfree(&ops->target.name); } static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops, int max_ins_name) { return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->raw); } int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops, int max_ins_name) { if (ins->ops->scnprintf) return ins->ops->scnprintf(ins, bf, size, ops, max_ins_name); return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); } bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2) { if (!arch || !arch->ins_is_fused) return false; return arch->ins_is_fused(arch, ins1, ins2); } static int call__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms) { char *endptr, *tok, *name; struct map *map = ms->map; struct addr_map_symbol target = { .ms = { .map = map, }, }; ops->target.addr = strtoull(ops->raw, &endptr, 16); name = strchr(endptr, '<'); if (name == NULL) goto indirect_call; name++; if (arch->objdump.skip_functions_char && strchr(name, arch->objdump.skip_functions_char)) return -1; tok = strchr(name, '>'); if (tok == NULL) return -1; *tok = '\0'; ops->target.name = strdup(name); *tok = '>'; if (ops->target.name == NULL) return -1; find_target: target.addr = map__objdump_2mem(map, ops->target.addr); if (maps__find_ams(ms->maps, &target) == 0 && map__rip_2objdump(target.ms.map, map->map_ip(target.ms.map, target.addr)) == ops->target.addr) ops->target.sym = target.ms.sym; return 0; indirect_call: tok = strchr(endptr, '*'); if (tok != NULL) { endptr++; /* Indirect call can use a non-rip register and offset: callq *0x8(%rbx). * Do not parse such instruction. */ if (strstr(endptr, "(%r") == NULL) ops->target.addr = strtoull(endptr, NULL, 16); } goto find_target; } static int call__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops, int max_ins_name) { if (ops->target.sym) return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.sym->name); if (ops->target.addr == 0) return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); if (ops->target.name) return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.name); return scnprintf(bf, size, "%-*s *%" PRIx64, max_ins_name, ins->name, ops->target.addr); } static struct ins_ops call_ops = { .parse = call__parse, .scnprintf = call__scnprintf, }; bool ins__is_call(const struct ins *ins) { return ins->ops == &call_ops || ins->ops == &s390_call_ops; } /* * Prevents from matching commas in the comment section, e.g.: * ffff200008446e70: b.cs ffff2000084470f4 <generic_exec_single+0x314> // b.hs, b.nlast */ static inline const char *validate_comma(const char *c, struct ins_operands *ops) { if (ops->raw_comment && c > ops->raw_comment) return NULL; return c; } static int jump__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms) { struct map *map = ms->map; struct symbol *sym = ms->sym; struct addr_map_symbol target = { .ms = { .map = map, }, }; const char *c = strchr(ops->raw, ','); u64 start, end; ops->raw_comment = strchr(ops->raw, arch->objdump.comment_char); c = validate_comma(c, ops); /* * Examples of lines to parse for the _cpp_lex_token@@Base * function: * * 1159e6c: jne 115aa32 <_cpp_lex_token@@Base+0xf92> * 1159e8b: jne c469be <cpp_named_operator2name@@Base+0xa72> * * The first is a jump to an offset inside the same function, * the second is to another function, i.e. that 0xa72 is an * offset in the cpp_named_operator2name@@base function. */ /* * skip over possible up to 2 operands to get to address, e.g.: * tbnz w0, #26, ffff0000083cd190 <security_file_permission+0xd0> */ if (c++ != NULL) { ops->target.addr = strtoull(c, NULL, 16); if (!ops->target.addr) { c = strchr(c, ','); c = validate_comma(c, ops); if (c++ != NULL) ops->target.addr = strtoull(c, NULL, 16); } } else { ops->target.addr = strtoull(ops->raw, NULL, 16); } target.addr = map__objdump_2mem(map, ops->target.addr); start = map->unmap_ip(map, sym->start), end = map->unmap_ip(map, sym->end); ops->target.outside = target.addr < start || target.addr > end; /* * FIXME: things like this in _cpp_lex_token (gcc's cc1 program): cpp_named_operator2name@@Base+0xa72 * Point to a place that is after the cpp_named_operator2name * boundaries, i.e. in the ELF symbol table for cc1 * cpp_named_operator2name is marked as being 32-bytes long, but it in * fact is much larger than that, so we seem to need a symbols__find() * routine that looks for >= current->start and < next_symbol->start, * possibly just for C++ objects? * * For now lets just make some progress by marking jumps to outside the * current function as call like. * * Actual navigation will come next, with further understanding of how * the symbol searching and disassembly should be done. */ if (maps__find_ams(ms->maps, &target) == 0 && map__rip_2objdump(target.ms.map, map->map_ip(target.ms.map, target.addr)) == ops->target.addr) ops->target.sym = target.ms.sym; if (!ops->target.outside) { ops->target.offset = target.addr - start; ops->target.offset_avail = true; } else { ops->target.offset_avail = false; } return 0; } static int jump__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops, int max_ins_name) { const char *c; if (!ops->target.addr || ops->target.offset < 0) return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); if (ops->target.outside && ops->target.sym != NULL) return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.sym->name); c = strchr(ops->raw, ','); c = validate_comma(c, ops); if (c != NULL) { const char *c2 = strchr(c + 1, ','); c2 = validate_comma(c2, ops); /* check for 3-op insn */ if (c2 != NULL) c = c2; c++; /* mirror arch objdump's space-after-comma style */ if (*c == ' ') c++; } return scnprintf(bf, size, "%-*s %.*s%" PRIx64, max_ins_name, ins->name, c ? c - ops->raw : 0, ops->raw, ops->target.offset); } static struct ins_ops jump_ops = { .parse = jump__parse, .scnprintf = jump__scnprintf, }; bool ins__is_jump(const struct ins *ins) { return ins->ops == &jump_ops; } static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep) { char *endptr, *name, *t; if (strstr(raw, "(%rip)") == NULL) return 0; *addrp = strtoull(comment, &endptr, 16); if (endptr == comment) return 0; name = strchr(endptr, '<'); if (name == NULL) return -1; name++; t = strchr(name, '>'); if (t == NULL) return 0; *t = '\0'; *namep = strdup(name); *t = '>'; return 0; } static int lock__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms) { ops->locked.ops = zalloc(sizeof(*ops->locked.ops)); if (ops->locked.ops == NULL) return 0; if (disasm_line__parse(ops->raw, &ops->locked.ins.name, &ops->locked.ops->raw) < 0) goto out_free_ops; ops->locked.ins.ops = ins__find(arch, ops->locked.ins.name); if (ops->locked.ins.ops == NULL) goto out_free_ops; if (ops->locked.ins.ops->parse && ops->locked.ins.ops->parse(arch, ops->locked.ops, ms) < 0) goto out_free_ops; return 0; out_free_ops: zfree(&ops->locked.ops); return 0; }