xref: /openbmc/linux/tools/perf/arch/arm64/annotate/instructions.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
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