1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2696e2457SJiri Olsa #include <linux/compiler.h>
30fcb1da4SKim Phillips #include <sys/types.h>
40fcb1da4SKim Phillips #include <regex.h>
5f2a39fe8SArnaldo Carvalho de Melo #include <stdlib.h>
60fcb1da4SKim Phillips
70fcb1da4SKim Phillips struct arm64_annotate {
80fcb1da4SKim Phillips regex_t call_insn,
90fcb1da4SKim Phillips jump_insn;
100fcb1da4SKim Phillips };
110fcb1da4SKim Phillips
arm64_mov__parse(struct arch * arch __maybe_unused,struct ins_operands * ops,struct map_symbol * ms __maybe_unused)1258094c48SKim Phillips static int arm64_mov__parse(struct arch *arch __maybe_unused,
1358094c48SKim Phillips struct ins_operands *ops,
1458094c48SKim Phillips struct map_symbol *ms __maybe_unused)
1558094c48SKim Phillips {
1658094c48SKim Phillips char *s = strchr(ops->raw, ','), *target, *endptr;
1758094c48SKim Phillips
1858094c48SKim Phillips if (s == NULL)
1958094c48SKim Phillips return -1;
2058094c48SKim Phillips
2158094c48SKim Phillips *s = '\0';
2258094c48SKim Phillips ops->source.raw = strdup(ops->raw);
2358094c48SKim Phillips *s = ',';
2458094c48SKim Phillips
2558094c48SKim Phillips if (ops->source.raw == NULL)
2658094c48SKim Phillips return -1;
2758094c48SKim Phillips
2858094c48SKim Phillips target = ++s;
2958094c48SKim Phillips ops->target.raw = strdup(target);
3058094c48SKim Phillips if (ops->target.raw == NULL)
3158094c48SKim Phillips goto out_free_source;
3258094c48SKim Phillips
3358094c48SKim Phillips ops->target.addr = strtoull(target, &endptr, 16);
3458094c48SKim Phillips if (endptr == target)
3558094c48SKim Phillips goto out_free_target;
3658094c48SKim Phillips
3758094c48SKim Phillips s = strchr(endptr, '<');
3858094c48SKim Phillips if (s == NULL)
3958094c48SKim Phillips goto out_free_target;
4058094c48SKim Phillips endptr = strchr(s + 1, '>');
4158094c48SKim Phillips if (endptr == NULL)
4258094c48SKim Phillips goto out_free_target;
4358094c48SKim Phillips
4458094c48SKim Phillips *endptr = '\0';
4558094c48SKim Phillips *s = ' ';
4658094c48SKim Phillips ops->target.name = strdup(s);
4758094c48SKim Phillips *s = '<';
4858094c48SKim Phillips *endptr = '>';
4958094c48SKim Phillips if (ops->target.name == NULL)
5058094c48SKim Phillips goto out_free_target;
5158094c48SKim Phillips
5258094c48SKim Phillips return 0;
5358094c48SKim Phillips
5458094c48SKim Phillips out_free_target:
5558094c48SKim Phillips zfree(&ops->target.raw);
5658094c48SKim Phillips out_free_source:
5758094c48SKim Phillips zfree(&ops->source.raw);
5858094c48SKim Phillips return -1;
5958094c48SKim Phillips }
6058094c48SKim Phillips
6158094c48SKim Phillips static int mov__scnprintf(struct ins *ins, char *bf, size_t size,
62bc3bb795SArnaldo Carvalho de Melo struct ins_operands *ops, int max_ins_name);
6358094c48SKim Phillips
6458094c48SKim Phillips static struct ins_ops arm64_mov_ops = {
6558094c48SKim Phillips .parse = arm64_mov__parse,
6658094c48SKim Phillips .scnprintf = mov__scnprintf,
6758094c48SKim Phillips };
6858094c48SKim Phillips
arm64__associate_instruction_ops(struct arch * arch,const char * name)690fcb1da4SKim Phillips static struct ins_ops *arm64__associate_instruction_ops(struct arch *arch, const char *name)
700fcb1da4SKim Phillips {
710fcb1da4SKim Phillips struct arm64_annotate *arm = arch->priv;
720fcb1da4SKim Phillips struct ins_ops *ops;
730fcb1da4SKim Phillips regmatch_t match[2];
740fcb1da4SKim Phillips
750fcb1da4SKim Phillips if (!regexec(&arm->jump_insn, name, 2, match, 0))
760fcb1da4SKim Phillips ops = &jump_ops;
770fcb1da4SKim Phillips else if (!regexec(&arm->call_insn, name, 2, match, 0))
780fcb1da4SKim Phillips ops = &call_ops;
790fcb1da4SKim Phillips else if (!strcmp(name, "ret"))
800fcb1da4SKim Phillips ops = &ret_ops;
810fcb1da4SKim Phillips else
8258094c48SKim Phillips ops = &arm64_mov_ops;
830fcb1da4SKim Phillips
840fcb1da4SKim Phillips arch__associate_ins_ops(arch, name, ops);
850fcb1da4SKim Phillips return ops;
860fcb1da4SKim Phillips }
870fcb1da4SKim Phillips
arm64__annotate_init(struct arch * arch,char * cpuid __maybe_unused)88696e2457SJiri Olsa static int arm64__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
890fcb1da4SKim Phillips {
900fcb1da4SKim Phillips struct arm64_annotate *arm;
910fcb1da4SKim Phillips int err;
920fcb1da4SKim Phillips
930fcb1da4SKim Phillips if (arch->initialized)
940fcb1da4SKim Phillips return 0;
950fcb1da4SKim Phillips
960fcb1da4SKim Phillips arm = zalloc(sizeof(*arm));
970fcb1da4SKim Phillips if (!arm)
9842d7a910SArnaldo Carvalho de Melo return ENOMEM;
990fcb1da4SKim Phillips
1000fcb1da4SKim Phillips /* bl, blr */
1010fcb1da4SKim Phillips err = regcomp(&arm->call_insn, "^blr?$", REG_EXTENDED);
1020fcb1da4SKim Phillips if (err)
1030fcb1da4SKim Phillips goto out_free_arm;
1040fcb1da4SKim Phillips /* b, b.cond, br, cbz/cbnz, tbz/tbnz */
105*531778b1SNamhyung Kim 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?$",
1060fcb1da4SKim Phillips REG_EXTENDED);
1070fcb1da4SKim Phillips if (err)
1080fcb1da4SKim Phillips goto out_free_call;
1090fcb1da4SKim Phillips
1100fcb1da4SKim Phillips arch->initialized = true;
1110fcb1da4SKim Phillips arch->priv = arm;
1120fcb1da4SKim Phillips arch->associate_instruction_ops = arm64__associate_instruction_ops;
113d1f7b023SKim Phillips arch->objdump.comment_char = '/';
1140fcb1da4SKim Phillips arch->objdump.skip_functions_char = '+';
1150fcb1da4SKim Phillips return 0;
1160fcb1da4SKim Phillips
1170fcb1da4SKim Phillips out_free_call:
1180fcb1da4SKim Phillips regfree(&arm->call_insn);
1190fcb1da4SKim Phillips out_free_arm:
1200fcb1da4SKim Phillips free(arm);
12142d7a910SArnaldo Carvalho de Melo return SYMBOL_ANNOTATE_ERRNO__ARCH_INIT_REGEXP;
1220fcb1da4SKim Phillips }
123