xref: /linux/tools/perf/util/annotate-arch/annotate-s390.c (revision c7decec2f2d2ab0366567f9e30c0e1418cece43f)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <string.h>
3 #include <linux/compiler.h>
4 #include "../debug.h"
5 #include "../disasm.h"
6 #include "../map.h"
7 #include "../maps.h"
8 #include "../symbol.h"
9 #include "../thread.h"
10 #include "../annotate.h"
11 #include "../annotate-data.h"
12 
s390_call__parse(const struct arch * arch,struct ins_operands * ops,struct map_symbol * ms,struct disasm_line * dl __maybe_unused)13 static int s390_call__parse(const struct arch *arch, struct ins_operands *ops,
14 			    struct map_symbol *ms,
15 			    struct disasm_line *dl __maybe_unused)
16 {
17 	char *endptr, *tok, *name;
18 	struct map *map = ms->map;
19 	struct addr_map_symbol target;
20 
21 	tok = strchr(ops->raw, ',');
22 	if (!tok)
23 		return -1;
24 
25 	ops->target.addr = strtoull(tok + 1, &endptr, 16);
26 
27 	name = strchr(endptr, '<');
28 	if (name == NULL)
29 		return -1;
30 
31 	name++;
32 
33 	if (arch->objdump.skip_functions_char &&
34 	    strchr(name, arch->objdump.skip_functions_char))
35 		return -1;
36 
37 	tok = strchr(name, '>');
38 	if (tok == NULL)
39 		return -1;
40 
41 	*tok = '\0';
42 	ops->target.name = strdup(name);
43 	*tok = '>';
44 
45 	if (ops->target.name == NULL)
46 		return -1;
47 
48 	target = (struct addr_map_symbol) {
49 		.ms = { .map = map__get(map), },
50 		.addr = map__objdump_2mem(map, ops->target.addr),
51 	};
52 
53 	if (maps__find_ams(thread__maps(ms->thread), &target) == 0 &&
54 	    map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr)
55 		ops->target.sym = target.ms.sym;
56 
57 	addr_map_symbol__exit(&target);
58 	return 0;
59 }
60 
61 static const struct ins_ops s390_call_ops = {
62 	.parse	   = s390_call__parse,
63 	.scnprintf = call__scnprintf,
64 	.is_call   = true,
65 };
66 
s390_mov__parse(const struct arch * arch __maybe_unused,struct ins_operands * ops,struct map_symbol * ms __maybe_unused,struct disasm_line * dl __maybe_unused)67 static int s390_mov__parse(const struct arch *arch __maybe_unused,
68 			   struct ins_operands *ops,
69 			   struct map_symbol *ms __maybe_unused,
70 			   struct disasm_line *dl __maybe_unused)
71 {
72 	char *s = strchr(ops->raw, ','), *target, *endptr;
73 
74 	if (s == NULL)
75 		return -1;
76 
77 	*s = '\0';
78 	ops->source.raw = strdup(ops->raw);
79 	*s = ',';
80 
81 	if (ops->source.raw == NULL)
82 		return -1;
83 
84 	target = ++s;
85 	ops->target.raw = strdup(target);
86 	if (ops->target.raw == NULL)
87 		goto out_free_source;
88 
89 	ops->target.addr = strtoull(target, &endptr, 16);
90 	if (endptr == target)
91 		goto out_free_target;
92 
93 	s = strchr(endptr, '<');
94 	if (s == NULL)
95 		goto out_free_target;
96 	endptr = strchr(s + 1, '>');
97 	if (endptr == NULL)
98 		goto out_free_target;
99 
100 	*endptr = '\0';
101 	ops->target.name = strdup(s + 1);
102 	*endptr = '>';
103 	if (ops->target.name == NULL)
104 		goto out_free_target;
105 
106 	return 0;
107 
108 out_free_target:
109 	zfree(&ops->target.raw);
110 out_free_source:
111 	zfree(&ops->source.raw);
112 	return -1;
113 }
114 
115 
116 static const struct ins_ops s390_mov_ops = {
117 	.parse	   = s390_mov__parse,
118 	.scnprintf = mov__scnprintf,
119 };
120 
s390__associate_ins_ops(struct arch * arch,const char * name)121 static const struct ins_ops *s390__associate_ins_ops(struct arch *arch, const char *name)
122 {
123 	const struct ins_ops *ops = NULL;
124 
125 	/* catch all kind of jumps */
126 	if (strchr(name, 'j') ||
127 	    !strncmp(name, "bct", 3) ||
128 	    !strncmp(name, "br", 2))
129 		ops = &jump_ops;
130 	/* override call/returns */
131 	if (!strcmp(name, "bras") ||
132 	    !strcmp(name, "brasl") ||
133 	    !strcmp(name, "basr"))
134 		ops = &s390_call_ops;
135 	if (!strcmp(name, "br"))
136 		ops = &ret_ops;
137 	/* override load/store relative to PC */
138 	if (!strcmp(name, "lrl") ||
139 	    !strcmp(name, "lgrl") ||
140 	    !strcmp(name, "lgfrl") ||
141 	    !strcmp(name, "llgfrl") ||
142 	    !strcmp(name, "strl") ||
143 	    !strcmp(name, "stgrl"))
144 		ops = &s390_mov_ops;
145 
146 	if (ops)
147 		arch__associate_ins_ops(arch, name, ops);
148 	return ops;
149 }
150 
s390__cpuid_parse(struct arch * arch,const char * cpuid)151 static int s390__cpuid_parse(struct arch *arch, const char *cpuid)
152 {
153 	unsigned int family;
154 	char model[16], model_c[16], cpumf_v[16], cpumf_a[16];
155 	int ret;
156 
157 	/*
158 	 * cpuid string format:
159 	 * "IBM,family,model-capacity,model[,cpum_cf-version,cpum_cf-authorization]"
160 	 */
161 	ret = sscanf(cpuid, "%*[^,],%u,%[^,],%[^,],%[^,],%s", &family, model_c,
162 		     model, cpumf_v, cpumf_a);
163 	if (ret >= 2) {
164 		arch->family = family;
165 		arch->model = 0;
166 		return 0;
167 	}
168 
169 	return -1;
170 }
171 
arch__new_s390(const struct e_machine_and_e_flags * id,const char * cpuid)172 const struct arch *arch__new_s390(const struct e_machine_and_e_flags *id, const char *cpuid)
173 {
174 	struct arch *arch = zalloc(sizeof(*arch));
175 
176 	if (!arch)
177 		return NULL;
178 
179 	arch->name = "s390";
180 	arch->id = *id;
181 	arch->associate_instruction_ops = s390__associate_ins_ops;
182 	if (cpuid) {
183 		if (s390__cpuid_parse(arch, cpuid)) {
184 			errno = SYMBOL_ANNOTATE_ERRNO__ARCH_INIT_CPUID_PARSING;
185 			return NULL;
186 		}
187 	}
188 	arch->objdump.comment_char = '#';
189 	return arch;
190 }
191