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