1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/compiler.h> 3 #include <sys/types.h> 4 #include <regex.h> 5 #include <stdlib.h> 6 7 struct arm64_annotate { 8 regex_t call_insn, 9 jump_insn; 10 }; 11 12 static int arm64_mov__parse(struct arch *arch __maybe_unused, 13 struct ins_operands *ops, 14 struct map_symbol *ms __maybe_unused) 15 { 16 char *s = strchr(ops->raw, ','), *target, *endptr; 17 18 if (s == NULL) 19 return -1; 20 21 *s = '\0'; 22 ops->source.raw = strdup(ops->raw); 23 *s = ','; 24 25 if (ops->source.raw == NULL) 26 return -1; 27 28 target = ++s; 29 ops->target.raw = strdup(target); 30 if (ops->target.raw == NULL) 31 goto out_free_source; 32 33 ops->target.addr = strtoull(target, &endptr, 16); 34 if (endptr == target) 35 goto out_free_target; 36 37 s = strchr(endptr, '<'); 38 if (s == NULL) 39 goto out_free_target; 40 endptr = strchr(s + 1, '>'); 41 if (endptr == NULL) 42 goto out_free_target; 43 44 *endptr = '\0'; 45 *s = ' '; 46 ops->target.name = strdup(s); 47 *s = '<'; 48 *endptr = '>'; 49 if (ops->target.name == NULL) 50 goto out_free_target; 51 52 return 0; 53 54 out_free_target: 55 zfree(&ops->target.raw); 56 out_free_source: 57 zfree(&ops->source.raw); 58 return -1; 59 } 60 61 static int mov__scnprintf(struct ins *ins, char *bf, size_t size, 62 struct ins_operands *ops, int max_ins_name); 63 64 static struct ins_ops arm64_mov_ops = { 65 .parse = arm64_mov__parse, 66 .scnprintf = mov__scnprintf, 67 }; 68 69 static struct ins_ops *arm64__associate_instruction_ops(struct arch *arch, const char *name) 70 { 71 struct arm64_annotate *arm = arch->priv; 72 struct ins_ops *ops; 73 regmatch_t match[2]; 74 75 if (!regexec(&arm->jump_insn, name, 2, match, 0)) 76 ops = &jump_ops; 77 else if (!regexec(&arm->call_insn, name, 2, match, 0)) 78 ops = &call_ops; 79 else if (!strcmp(name, "ret")) 80 ops = &ret_ops; 81 else 82 ops = &arm64_mov_ops; 83 84 arch__associate_ins_ops(arch, name, ops); 85 return ops; 86 } 87 88 static int arm64__annotate_init(struct arch *arch, char *cpuid __maybe_unused) 89 { 90 struct arm64_annotate *arm; 91 int err; 92 93 if (arch->initialized) 94 return 0; 95 96 arm = zalloc(sizeof(*arm)); 97 if (!arm) 98 return ENOMEM; 99 100 /* bl, blr */ 101 err = regcomp(&arm->call_insn, "^blr?$", REG_EXTENDED); 102 if (err) 103 goto out_free_arm; 104 /* b, b.cond, br, cbz/cbnz, tbz/tbnz */ 105 err = regcomp(&arm->jump_insn, "^[ct]?br?\\.?(cc|cs|eq|ge|gt|hi|le|ls|lt|mi|ne|pl)?n?z?$", 106 REG_EXTENDED); 107 if (err) 108 goto out_free_call; 109 110 arch->initialized = true; 111 arch->priv = arm; 112 arch->associate_instruction_ops = arm64__associate_instruction_ops; 113 arch->objdump.comment_char = '/'; 114 arch->objdump.skip_functions_char = '+'; 115 return 0; 116 117 out_free_call: 118 regfree(&arm->call_insn); 119 out_free_arm: 120 free(arm); 121 return SYMBOL_ANNOTATE_ERRNO__ARCH_INIT_REGEXP; 122 } 123