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