xref: /linux/tools/perf/util/annotate-arch/annotate-s390.c (revision c7decec2f2d2ab0366567f9e30c0e1418cece43f)
107b972ffSIan Rogers // SPDX-License-Identifier: GPL-2.0
207b972ffSIan Rogers #include <string.h>
307b972ffSIan Rogers #include <linux/compiler.h>
407b972ffSIan Rogers #include "../debug.h"
507b972ffSIan Rogers #include "../disasm.h"
607b972ffSIan Rogers #include "../map.h"
707b972ffSIan Rogers #include "../maps.h"
807b972ffSIan Rogers #include "../symbol.h"
9c4e3a003SIan Rogers #include "../thread.h"
1007b972ffSIan Rogers #include "../annotate.h"
1107b972ffSIan Rogers #include "../annotate-data.h"
1207b972ffSIan Rogers 
s390_call__parse(const struct arch * arch,struct ins_operands * ops,struct map_symbol * ms,struct disasm_line * dl __maybe_unused)1307b972ffSIan Rogers static int s390_call__parse(const struct arch *arch, struct ins_operands *ops,
1407b972ffSIan Rogers 			    struct map_symbol *ms,
1507b972ffSIan Rogers 			    struct disasm_line *dl __maybe_unused)
1607b972ffSIan Rogers {
1707b972ffSIan Rogers 	char *endptr, *tok, *name;
1807b972ffSIan Rogers 	struct map *map = ms->map;
1907b972ffSIan Rogers 	struct addr_map_symbol target;
2007b972ffSIan Rogers 
2107b972ffSIan Rogers 	tok = strchr(ops->raw, ',');
2207b972ffSIan Rogers 	if (!tok)
2307b972ffSIan Rogers 		return -1;
2407b972ffSIan Rogers 
2507b972ffSIan Rogers 	ops->target.addr = strtoull(tok + 1, &endptr, 16);
2607b972ffSIan Rogers 
2707b972ffSIan Rogers 	name = strchr(endptr, '<');
2807b972ffSIan Rogers 	if (name == NULL)
2907b972ffSIan Rogers 		return -1;
3007b972ffSIan Rogers 
3107b972ffSIan Rogers 	name++;
3207b972ffSIan Rogers 
3307b972ffSIan Rogers 	if (arch->objdump.skip_functions_char &&
3407b972ffSIan Rogers 	    strchr(name, arch->objdump.skip_functions_char))
3507b972ffSIan Rogers 		return -1;
3607b972ffSIan Rogers 
3707b972ffSIan Rogers 	tok = strchr(name, '>');
3807b972ffSIan Rogers 	if (tok == NULL)
3907b972ffSIan Rogers 		return -1;
4007b972ffSIan Rogers 
4107b972ffSIan Rogers 	*tok = '\0';
4207b972ffSIan Rogers 	ops->target.name = strdup(name);
4307b972ffSIan Rogers 	*tok = '>';
4407b972ffSIan Rogers 
4507b972ffSIan Rogers 	if (ops->target.name == NULL)
4607b972ffSIan Rogers 		return -1;
4707b972ffSIan Rogers 
4807b972ffSIan Rogers 	target = (struct addr_map_symbol) {
4907b972ffSIan Rogers 		.ms = { .map = map__get(map), },
5007b972ffSIan Rogers 		.addr = map__objdump_2mem(map, ops->target.addr),
5107b972ffSIan Rogers 	};
5207b972ffSIan Rogers 
53c4e3a003SIan Rogers 	if (maps__find_ams(thread__maps(ms->thread), &target) == 0 &&
5407b972ffSIan Rogers 	    map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr)
5507b972ffSIan Rogers 		ops->target.sym = target.ms.sym;
5607b972ffSIan Rogers 
5707b972ffSIan Rogers 	addr_map_symbol__exit(&target);
5807b972ffSIan Rogers 	return 0;
5907b972ffSIan Rogers }
6007b972ffSIan Rogers 
615301cc69SIan Rogers static const struct ins_ops s390_call_ops = {
6207b972ffSIan Rogers 	.parse	   = s390_call__parse,
6307b972ffSIan Rogers 	.scnprintf = call__scnprintf,
645301cc69SIan Rogers 	.is_call   = true,
6507b972ffSIan Rogers };
6607b972ffSIan Rogers 
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)6707b972ffSIan Rogers static int s390_mov__parse(const struct arch *arch __maybe_unused,
6807b972ffSIan Rogers 			   struct ins_operands *ops,
6907b972ffSIan Rogers 			   struct map_symbol *ms __maybe_unused,
7007b972ffSIan Rogers 			   struct disasm_line *dl __maybe_unused)
7107b972ffSIan Rogers {
7207b972ffSIan Rogers 	char *s = strchr(ops->raw, ','), *target, *endptr;
7307b972ffSIan Rogers 
7407b972ffSIan Rogers 	if (s == NULL)
7507b972ffSIan Rogers 		return -1;
7607b972ffSIan Rogers 
7707b972ffSIan Rogers 	*s = '\0';
7807b972ffSIan Rogers 	ops->source.raw = strdup(ops->raw);
7907b972ffSIan Rogers 	*s = ',';
8007b972ffSIan Rogers 
8107b972ffSIan Rogers 	if (ops->source.raw == NULL)
8207b972ffSIan Rogers 		return -1;
8307b972ffSIan Rogers 
8407b972ffSIan Rogers 	target = ++s;
8507b972ffSIan Rogers 	ops->target.raw = strdup(target);
8607b972ffSIan Rogers 	if (ops->target.raw == NULL)
8707b972ffSIan Rogers 		goto out_free_source;
8807b972ffSIan Rogers 
8907b972ffSIan Rogers 	ops->target.addr = strtoull(target, &endptr, 16);
9007b972ffSIan Rogers 	if (endptr == target)
9107b972ffSIan Rogers 		goto out_free_target;
9207b972ffSIan Rogers 
9307b972ffSIan Rogers 	s = strchr(endptr, '<');
9407b972ffSIan Rogers 	if (s == NULL)
9507b972ffSIan Rogers 		goto out_free_target;
9607b972ffSIan Rogers 	endptr = strchr(s + 1, '>');
9707b972ffSIan Rogers 	if (endptr == NULL)
9807b972ffSIan Rogers 		goto out_free_target;
9907b972ffSIan Rogers 
10007b972ffSIan Rogers 	*endptr = '\0';
10107b972ffSIan Rogers 	ops->target.name = strdup(s + 1);
10207b972ffSIan Rogers 	*endptr = '>';
10307b972ffSIan Rogers 	if (ops->target.name == NULL)
10407b972ffSIan Rogers 		goto out_free_target;
10507b972ffSIan Rogers 
10607b972ffSIan Rogers 	return 0;
10707b972ffSIan Rogers 
10807b972ffSIan Rogers out_free_target:
10907b972ffSIan Rogers 	zfree(&ops->target.raw);
11007b972ffSIan Rogers out_free_source:
11107b972ffSIan Rogers 	zfree(&ops->source.raw);
11207b972ffSIan Rogers 	return -1;
11307b972ffSIan Rogers }
11407b972ffSIan Rogers 
11507b972ffSIan Rogers 
11607b972ffSIan Rogers static const struct ins_ops s390_mov_ops = {
11707b972ffSIan Rogers 	.parse	   = s390_mov__parse,
11807b972ffSIan Rogers 	.scnprintf = mov__scnprintf,
11907b972ffSIan Rogers };
12007b972ffSIan Rogers 
s390__associate_ins_ops(struct arch * arch,const char * name)12107b972ffSIan Rogers static const struct ins_ops *s390__associate_ins_ops(struct arch *arch, const char *name)
12207b972ffSIan Rogers {
12307b972ffSIan Rogers 	const struct ins_ops *ops = NULL;
12407b972ffSIan Rogers 
12507b972ffSIan Rogers 	/* catch all kind of jumps */
12607b972ffSIan Rogers 	if (strchr(name, 'j') ||
12707b972ffSIan Rogers 	    !strncmp(name, "bct", 3) ||
12807b972ffSIan Rogers 	    !strncmp(name, "br", 2))
12907b972ffSIan Rogers 		ops = &jump_ops;
13007b972ffSIan Rogers 	/* override call/returns */
13107b972ffSIan Rogers 	if (!strcmp(name, "bras") ||
13207b972ffSIan Rogers 	    !strcmp(name, "brasl") ||
13307b972ffSIan Rogers 	    !strcmp(name, "basr"))
13407b972ffSIan Rogers 		ops = &s390_call_ops;
13507b972ffSIan Rogers 	if (!strcmp(name, "br"))
13607b972ffSIan Rogers 		ops = &ret_ops;
13707b972ffSIan Rogers 	/* override load/store relative to PC */
13807b972ffSIan Rogers 	if (!strcmp(name, "lrl") ||
13907b972ffSIan Rogers 	    !strcmp(name, "lgrl") ||
14007b972ffSIan Rogers 	    !strcmp(name, "lgfrl") ||
14107b972ffSIan Rogers 	    !strcmp(name, "llgfrl") ||
14207b972ffSIan Rogers 	    !strcmp(name, "strl") ||
14307b972ffSIan Rogers 	    !strcmp(name, "stgrl"))
14407b972ffSIan Rogers 		ops = &s390_mov_ops;
14507b972ffSIan Rogers 
14607b972ffSIan Rogers 	if (ops)
14707b972ffSIan Rogers 		arch__associate_ins_ops(arch, name, ops);
14807b972ffSIan Rogers 	return ops;
14907b972ffSIan Rogers }
15007b972ffSIan Rogers 
s390__cpuid_parse(struct arch * arch,const char * cpuid)151*0e26ba5aSIan Rogers static int s390__cpuid_parse(struct arch *arch, const char *cpuid)
15207b972ffSIan Rogers {
15307b972ffSIan Rogers 	unsigned int family;
15407b972ffSIan Rogers 	char model[16], model_c[16], cpumf_v[16], cpumf_a[16];
15507b972ffSIan Rogers 	int ret;
15607b972ffSIan Rogers 
15707b972ffSIan Rogers 	/*
15807b972ffSIan Rogers 	 * cpuid string format:
15907b972ffSIan Rogers 	 * "IBM,family,model-capacity,model[,cpum_cf-version,cpum_cf-authorization]"
16007b972ffSIan Rogers 	 */
16107b972ffSIan Rogers 	ret = sscanf(cpuid, "%*[^,],%u,%[^,],%[^,],%[^,],%s", &family, model_c,
16207b972ffSIan Rogers 		     model, cpumf_v, cpumf_a);
16307b972ffSIan Rogers 	if (ret >= 2) {
16407b972ffSIan Rogers 		arch->family = family;
16507b972ffSIan Rogers 		arch->model = 0;
16607b972ffSIan Rogers 		return 0;
16707b972ffSIan Rogers 	}
16807b972ffSIan Rogers 
16907b972ffSIan Rogers 	return -1;
17007b972ffSIan Rogers }
17107b972ffSIan Rogers 
arch__new_s390(const struct e_machine_and_e_flags * id,const char * cpuid)172*0e26ba5aSIan Rogers const struct arch *arch__new_s390(const struct e_machine_and_e_flags *id, const char *cpuid)
17307b972ffSIan Rogers {
174*0e26ba5aSIan Rogers 	struct arch *arch = zalloc(sizeof(*arch));
17507b972ffSIan Rogers 
176*0e26ba5aSIan Rogers 	if (!arch)
177*0e26ba5aSIan Rogers 		return NULL;
178*0e26ba5aSIan Rogers 
179*0e26ba5aSIan Rogers 	arch->name = "s390";
180*0e26ba5aSIan Rogers 	arch->id = *id;
18107b972ffSIan Rogers 	arch->associate_instruction_ops = s390__associate_ins_ops;
18207b972ffSIan Rogers 	if (cpuid) {
183*0e26ba5aSIan Rogers 		if (s390__cpuid_parse(arch, cpuid)) {
184*0e26ba5aSIan Rogers 			errno = SYMBOL_ANNOTATE_ERRNO__ARCH_INIT_CPUID_PARSING;
185*0e26ba5aSIan Rogers 			return NULL;
186*0e26ba5aSIan Rogers 		}
18707b972ffSIan Rogers 	}
18807b972ffSIan Rogers 	arch->objdump.comment_char = '#';
189*0e26ba5aSIan Rogers 	return arch;
19007b972ffSIan Rogers }
191