162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <linux/compiler.h> 362306a36Sopenharmony_ci#include <sys/types.h> 462306a36Sopenharmony_ci#include <regex.h> 562306a36Sopenharmony_ci#include <stdlib.h> 662306a36Sopenharmony_ci 762306a36Sopenharmony_cistruct arm64_annotate { 862306a36Sopenharmony_ci regex_t call_insn, 962306a36Sopenharmony_ci jump_insn; 1062306a36Sopenharmony_ci}; 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cistatic int arm64_mov__parse(struct arch *arch __maybe_unused, 1362306a36Sopenharmony_ci struct ins_operands *ops, 1462306a36Sopenharmony_ci struct map_symbol *ms __maybe_unused) 1562306a36Sopenharmony_ci{ 1662306a36Sopenharmony_ci char *s = strchr(ops->raw, ','), *target, *endptr; 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci if (s == NULL) 1962306a36Sopenharmony_ci return -1; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci *s = '\0'; 2262306a36Sopenharmony_ci ops->source.raw = strdup(ops->raw); 2362306a36Sopenharmony_ci *s = ','; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci if (ops->source.raw == NULL) 2662306a36Sopenharmony_ci return -1; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci target = ++s; 2962306a36Sopenharmony_ci ops->target.raw = strdup(target); 3062306a36Sopenharmony_ci if (ops->target.raw == NULL) 3162306a36Sopenharmony_ci goto out_free_source; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci ops->target.addr = strtoull(target, &endptr, 16); 3462306a36Sopenharmony_ci if (endptr == target) 3562306a36Sopenharmony_ci goto out_free_target; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci s = strchr(endptr, '<'); 3862306a36Sopenharmony_ci if (s == NULL) 3962306a36Sopenharmony_ci goto out_free_target; 4062306a36Sopenharmony_ci endptr = strchr(s + 1, '>'); 4162306a36Sopenharmony_ci if (endptr == NULL) 4262306a36Sopenharmony_ci goto out_free_target; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci *endptr = '\0'; 4562306a36Sopenharmony_ci *s = ' '; 4662306a36Sopenharmony_ci ops->target.name = strdup(s); 4762306a36Sopenharmony_ci *s = '<'; 4862306a36Sopenharmony_ci *endptr = '>'; 4962306a36Sopenharmony_ci if (ops->target.name == NULL) 5062306a36Sopenharmony_ci goto out_free_target; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci return 0; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ciout_free_target: 5562306a36Sopenharmony_ci zfree(&ops->target.raw); 5662306a36Sopenharmony_ciout_free_source: 5762306a36Sopenharmony_ci zfree(&ops->source.raw); 5862306a36Sopenharmony_ci return -1; 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic int mov__scnprintf(struct ins *ins, char *bf, size_t size, 6262306a36Sopenharmony_ci struct ins_operands *ops, int max_ins_name); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic struct ins_ops arm64_mov_ops = { 6562306a36Sopenharmony_ci .parse = arm64_mov__parse, 6662306a36Sopenharmony_ci .scnprintf = mov__scnprintf, 6762306a36Sopenharmony_ci}; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic struct ins_ops *arm64__associate_instruction_ops(struct arch *arch, const char *name) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci struct arm64_annotate *arm = arch->priv; 7262306a36Sopenharmony_ci struct ins_ops *ops; 7362306a36Sopenharmony_ci regmatch_t match[2]; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci if (!regexec(&arm->jump_insn, name, 2, match, 0)) 7662306a36Sopenharmony_ci ops = &jump_ops; 7762306a36Sopenharmony_ci else if (!regexec(&arm->call_insn, name, 2, match, 0)) 7862306a36Sopenharmony_ci ops = &call_ops; 7962306a36Sopenharmony_ci else if (!strcmp(name, "ret")) 8062306a36Sopenharmony_ci ops = &ret_ops; 8162306a36Sopenharmony_ci else 8262306a36Sopenharmony_ci ops = &arm64_mov_ops; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci arch__associate_ins_ops(arch, name, ops); 8562306a36Sopenharmony_ci return ops; 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic int arm64__annotate_init(struct arch *arch, char *cpuid __maybe_unused) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci struct arm64_annotate *arm; 9162306a36Sopenharmony_ci int err; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (arch->initialized) 9462306a36Sopenharmony_ci return 0; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci arm = zalloc(sizeof(*arm)); 9762306a36Sopenharmony_ci if (!arm) 9862306a36Sopenharmony_ci return ENOMEM; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci /* bl, blr */ 10162306a36Sopenharmony_ci err = regcomp(&arm->call_insn, "^blr?$", REG_EXTENDED); 10262306a36Sopenharmony_ci if (err) 10362306a36Sopenharmony_ci goto out_free_arm; 10462306a36Sopenharmony_ci /* b, b.cond, br, cbz/cbnz, tbz/tbnz */ 10562306a36Sopenharmony_ci err = regcomp(&arm->jump_insn, "^[ct]?br?\\.?(cc|cs|eq|ge|gt|hi|hs|le|lo|ls|lt|mi|ne|pl|vc|vs)?n?z?$", 10662306a36Sopenharmony_ci REG_EXTENDED); 10762306a36Sopenharmony_ci if (err) 10862306a36Sopenharmony_ci goto out_free_call; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci arch->initialized = true; 11162306a36Sopenharmony_ci arch->priv = arm; 11262306a36Sopenharmony_ci arch->associate_instruction_ops = arm64__associate_instruction_ops; 11362306a36Sopenharmony_ci arch->objdump.comment_char = '/'; 11462306a36Sopenharmony_ci arch->objdump.skip_functions_char = '+'; 11562306a36Sopenharmony_ci return 0; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ciout_free_call: 11862306a36Sopenharmony_ci regfree(&arm->call_insn); 11962306a36Sopenharmony_ciout_free_arm: 12062306a36Sopenharmony_ci free(arm); 12162306a36Sopenharmony_ci return SYMBOL_ANNOTATE_ERRNO__ARCH_INIT_REGEXP; 12262306a36Sopenharmony_ci} 123