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