/src/binutils-gdb/opcodes/rx-dis.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Disassembler code for Renesas RX. |
2 | | Copyright (C) 2008-2023 Free Software Foundation, Inc. |
3 | | Contributed by Red Hat. |
4 | | Written by DJ Delorie. |
5 | | |
6 | | This file is part of the GNU opcodes library. |
7 | | |
8 | | This library is free software; you can redistribute it and/or modify |
9 | | it under the terms of the GNU General Public License as published by |
10 | | the Free Software Foundation; either version 3, or (at your option) |
11 | | any later version. |
12 | | |
13 | | It is distributed in the hope that it will be useful, but WITHOUT |
14 | | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
15 | | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public |
16 | | License for more details. |
17 | | |
18 | | You should have received a copy of the GNU General Public License |
19 | | along with this program; if not, write to the Free Software |
20 | | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
21 | | MA 02110-1301, USA. */ |
22 | | |
23 | | #include "sysdep.h" |
24 | | #include <stdio.h> |
25 | | |
26 | | #include "bfd.h" |
27 | | #include "dis-asm.h" |
28 | | #include "opcode/rx.h" |
29 | | #include "libiberty.h" |
30 | | #include "opintl.h" |
31 | | |
32 | | #include <setjmp.h> |
33 | | |
34 | | typedef struct |
35 | | { |
36 | | bfd_vma pc; |
37 | | disassemble_info * dis; |
38 | | } RX_Data; |
39 | | |
40 | | struct private |
41 | | { |
42 | | OPCODES_SIGJMP_BUF bailout; |
43 | | }; |
44 | | |
45 | | static int |
46 | | rx_get_byte (void * vdata) |
47 | 89.5M | { |
48 | 89.5M | bfd_byte buf[1]; |
49 | 89.5M | RX_Data *rx_data = (RX_Data *) vdata; |
50 | 89.5M | int status; |
51 | | |
52 | 89.5M | status = rx_data->dis->read_memory_func (rx_data->pc, |
53 | 89.5M | buf, |
54 | 89.5M | 1, |
55 | 89.5M | rx_data->dis); |
56 | 89.5M | if (status != 0) |
57 | 6.27k | { |
58 | 6.27k | struct private *priv = (struct private *) rx_data->dis->private_data; |
59 | | |
60 | 6.27k | rx_data->dis->memory_error_func (status, rx_data->pc, |
61 | 6.27k | rx_data->dis); |
62 | 6.27k | OPCODES_SIGLONGJMP (priv->bailout, 1); |
63 | 6.27k | } |
64 | | |
65 | 89.5M | rx_data->pc ++; |
66 | 89.5M | return buf[0]; |
67 | 89.5M | } |
68 | | |
69 | | static char const * size_names[RX_MAX_SIZE] = |
70 | | { |
71 | | "", ".b", ".ub", ".b", ".w", ".uw", ".w", ".a", ".l", "", "<error>" |
72 | | }; |
73 | | |
74 | | static char const * opsize_names[RX_MAX_SIZE] = |
75 | | { |
76 | | "", ".b", ".b", ".b", ".w", ".w", ".w", ".a", ".l", ".d", "<error>" |
77 | | }; |
78 | | |
79 | | static char const * register_names[] = |
80 | | { |
81 | | /* General registers. */ |
82 | | "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", |
83 | | "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", |
84 | | /* Control registers. */ |
85 | | "psw", "pc", "usp", "fpsw", NULL, NULL, NULL, NULL, |
86 | | "bpsw", "bpc", "isp", "fintv", "intb", "extb", NULL, NULL, |
87 | | "a0", "a1", NULL, NULL, NULL, NULL, NULL, NULL, |
88 | | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL |
89 | | }; |
90 | | |
91 | | static char const * condition_names[] = |
92 | | { |
93 | | /* Condition codes. */ |
94 | | "eq", "ne", "c", "nc", "gtu", "leu", "pz", "n", |
95 | | "ge", "lt", "gt", "le", "o", "no", "<invalid>", "<invalid>" |
96 | | }; |
97 | | |
98 | | static const char * flag_names[] = |
99 | | { |
100 | | "c", "z", "s", "o", "", "", "", "", |
101 | | "", "", "", "", "", "", "", "", |
102 | | "i", "u", "", "", "", "", "", "", |
103 | | "", "", "", "", "", "", "", "" |
104 | | }; |
105 | | |
106 | | static const char * double_register_names[] = |
107 | | { |
108 | | "dr0", "dr1", "dr2", "dr3", "dr4", "dr5", "dr6", "dr7", |
109 | | "dr8", "dr9", "dr10", "dr11", "dr12", "dr13", "dr14", "dr15" |
110 | | }; |
111 | | |
112 | | static const char * double_register_high_names[] = |
113 | | { |
114 | | "drh0", "drh1", "drh2", "drh3", "drh4", "drh5", "drh6", "drh7", |
115 | | "drh8", "drh9", "drh10", "drh11", "drh12", "drh13", "drh14", "drh15" |
116 | | }; |
117 | | |
118 | | static const char * double_register_low_names[] = |
119 | | { |
120 | | "drl0", "drl1", "drl2", "drl3", "drl4", "drl5", "drl6", "drl7", |
121 | | "drl8", "drl9", "drl10", "drl11", "drl12", "drl13", "drl14", "drl15" |
122 | | }; |
123 | | |
124 | | static const char * double_control_register_names[] = |
125 | | { |
126 | | "dpsw", "dcmr", "decnt", "depc" |
127 | | }; |
128 | | |
129 | | static const char * double_condition_names[] = |
130 | | { |
131 | | "", "un", "eq", "", "lt", "", "le" |
132 | | }; |
133 | | |
134 | | static inline const char * |
135 | | get_register_name (unsigned int reg) |
136 | 37.7M | { |
137 | 37.7M | if (reg < ARRAY_SIZE (register_names)) |
138 | 37.7M | return register_names[reg]; |
139 | 0 | return _("<invalid register number>"); |
140 | 37.7M | } |
141 | | |
142 | | static inline const char * |
143 | | get_condition_name (unsigned int cond) |
144 | 5.17M | { |
145 | 5.17M | if (cond < ARRAY_SIZE (condition_names)) |
146 | 5.17M | return condition_names[cond]; |
147 | 0 | return _("<invalid condition code>"); |
148 | 5.17M | } |
149 | | |
150 | | static inline const char * |
151 | | get_flag_name (unsigned int flag) |
152 | 12.6k | { |
153 | 12.6k | if (flag < ARRAY_SIZE (flag_names)) |
154 | 12.6k | return flag_names[flag]; |
155 | 0 | return _("<invalid flag>"); |
156 | 12.6k | } |
157 | | |
158 | | static inline const char * |
159 | | get_double_register_name (unsigned int reg) |
160 | 52.6k | { |
161 | 52.6k | if (reg < ARRAY_SIZE (double_register_names)) |
162 | 52.1k | return double_register_names[reg]; |
163 | 489 | return _("<invalid register number>"); |
164 | 52.6k | } |
165 | | |
166 | | static inline const char * |
167 | | get_double_register_high_name (unsigned int reg) |
168 | 2.50k | { |
169 | 2.50k | if (reg < ARRAY_SIZE (double_register_high_names)) |
170 | 2.50k | return double_register_high_names[reg]; |
171 | 0 | return _("<invalid register number>"); |
172 | 2.50k | } |
173 | | |
174 | | static inline const char * |
175 | | get_double_register_low_name (unsigned int reg) |
176 | 3.61k | { |
177 | 3.61k | if (reg < ARRAY_SIZE (double_register_low_names)) |
178 | 3.61k | return double_register_low_names[reg]; |
179 | 0 | return _("<invalid register number>"); |
180 | 3.61k | } |
181 | | |
182 | | static inline const char * |
183 | | get_double_control_register_name (unsigned int reg) |
184 | 9.28k | { |
185 | 9.28k | if (reg < ARRAY_SIZE (double_control_register_names)) |
186 | 2.15k | return double_control_register_names[reg]; |
187 | 7.13k | return _("<invalid register number>"); |
188 | 9.28k | } |
189 | | |
190 | | static inline const char * |
191 | | get_double_condition_name (unsigned int cond) |
192 | 4.18k | { |
193 | 4.18k | if (cond < ARRAY_SIZE (double_condition_names)) |
194 | 1.43k | return double_condition_names[cond]; |
195 | 2.75k | return _("<invalid condition code>"); |
196 | 4.18k | } |
197 | | |
198 | | static inline const char * |
199 | | get_opsize_name (unsigned int opsize) |
200 | 12.7M | { |
201 | 12.7M | if (opsize < ARRAY_SIZE (opsize_names)) |
202 | 12.7M | return opsize_names[opsize]; |
203 | 0 | return _("<invalid opsize>"); |
204 | 12.7M | } |
205 | | |
206 | | static inline const char * |
207 | | get_size_name (unsigned int size) |
208 | 3.22M | { |
209 | 3.22M | if (size < ARRAY_SIZE (size_names)) |
210 | 3.22M | return size_names[size]; |
211 | 0 | return _("<invalid size>"); |
212 | 3.22M | } |
213 | | |
214 | | |
215 | | int |
216 | | print_insn_rx (bfd_vma addr, disassemble_info * dis) |
217 | 46.2M | { |
218 | 46.2M | int rv; |
219 | 46.2M | RX_Data rx_data; |
220 | 46.2M | RX_Opcode_Decoded opcode; |
221 | 46.2M | const char * s; |
222 | 46.2M | struct private priv; |
223 | | |
224 | 46.2M | dis->private_data = &priv; |
225 | 46.2M | rx_data.pc = addr; |
226 | 46.2M | rx_data.dis = dis; |
227 | | |
228 | 46.2M | if (OPCODES_SIGSETJMP (priv.bailout) != 0) |
229 | 6.27k | { |
230 | | /* Error return. */ |
231 | 6.27k | return -1; |
232 | 6.27k | } |
233 | | |
234 | 46.2M | rv = rx_decode_opcode (addr, &opcode, rx_get_byte, &rx_data); |
235 | | |
236 | 46.2M | dis->bytes_per_line = 10; |
237 | | |
238 | 313M | #define PR (dis->fprintf_func) |
239 | 313M | #define PS (dis->stream) |
240 | 247M | #define PC(c) PR (PS, "%c", c) |
241 | | |
242 | | /* Detect illegal instructions. */ |
243 | 46.2M | if (opcode.op[0].size == RX_Bad_Size |
244 | 46.2M | || register_names [opcode.op[0].reg] == NULL |
245 | 46.2M | || register_names [opcode.op[1].reg] == NULL |
246 | 46.2M | || register_names [opcode.op[2].reg] == NULL) |
247 | 434k | { |
248 | 434k | bfd_byte buf[10]; |
249 | 434k | int i; |
250 | | |
251 | 434k | PR (PS, ".byte "); |
252 | 434k | rx_data.dis->read_memory_func (rx_data.pc - rv, buf, rv, rx_data.dis); |
253 | | |
254 | 2.18M | for (i = 0 ; i < rv; i++) |
255 | 1.74M | PR (PS, "0x%02x ", buf[i]); |
256 | 434k | return rv; |
257 | 434k | } |
258 | | |
259 | 365M | for (s = opcode.syntax; *s; s++) |
260 | 320M | { |
261 | 320M | if (*s != '%') |
262 | 247M | { |
263 | 247M | PC (*s); |
264 | 247M | } |
265 | 72.0M | else |
266 | 72.0M | { |
267 | 72.0M | RX_Opcode_Operand * oper; |
268 | 72.0M | int do_size = 0; |
269 | 72.0M | int do_hex = 0; |
270 | 72.0M | int do_addr = 0; |
271 | | |
272 | 72.0M | s ++; |
273 | | |
274 | 72.0M | if (*s == 'S') |
275 | 4.13M | { |
276 | 4.13M | do_size = 1; |
277 | 4.13M | s++; |
278 | 4.13M | } |
279 | 72.0M | if (*s == 'x') |
280 | 0 | { |
281 | 0 | do_hex = 1; |
282 | 0 | s++; |
283 | 0 | } |
284 | 72.0M | if (*s == 'a') |
285 | 7.37M | { |
286 | 7.37M | do_addr = 1; |
287 | 7.37M | s++; |
288 | 7.37M | } |
289 | | |
290 | 72.0M | switch (*s) |
291 | 72.0M | { |
292 | 0 | case '%': |
293 | 0 | PC ('%'); |
294 | 0 | break; |
295 | | |
296 | 12.7M | case 's': |
297 | 12.7M | PR (PS, "%s", get_opsize_name (opcode.size)); |
298 | 12.7M | break; |
299 | | |
300 | 269 | case 'b': |
301 | 269 | s ++; |
302 | 269 | if (*s == 'f') |
303 | 269 | { |
304 | 269 | int imm = opcode.op[2].addend; |
305 | 269 | int slsb, dlsb, width; |
306 | | |
307 | 269 | dlsb = (imm >> 5) & 0x1f; |
308 | 269 | slsb = (imm & 0x1f); |
309 | 269 | slsb = (slsb >= 0x10?(slsb ^ 0x1f) + 1:slsb); |
310 | 269 | slsb = dlsb - slsb; |
311 | 269 | slsb = (slsb < 0?-slsb:slsb); |
312 | 269 | width = ((imm >> 10) & 0x1f) - dlsb; |
313 | 269 | PR (PS, "#%d, #%d, #%d, %s, %s", |
314 | 269 | slsb, dlsb, width, |
315 | 269 | get_register_name (opcode.op[1].reg), |
316 | 269 | get_register_name (opcode.op[0].reg)); |
317 | 269 | } |
318 | 269 | break; |
319 | 26.5M | case '0': |
320 | 53.8M | case '1': |
321 | 59.3M | case '2': |
322 | 59.3M | oper = opcode.op + (*s - '0'); |
323 | 59.3M | if (do_size) |
324 | 4.13M | { |
325 | 4.13M | if (oper->type == RX_Operand_Indirect || oper->type == RX_Operand_Zero_Indirect) |
326 | 3.22M | PR (PS, "%s", get_size_name (oper->size)); |
327 | 4.13M | } |
328 | 55.2M | else |
329 | 55.2M | switch (oper->type) |
330 | 55.2M | { |
331 | 12.2M | case RX_Operand_Immediate: |
332 | 12.2M | if (do_addr) |
333 | 7.37M | dis->print_address_func (oper->addend, dis); |
334 | 4.87M | else if (do_hex |
335 | 4.87M | || oper->addend > 999 |
336 | 4.87M | || oper->addend < -999) |
337 | 701k | PR (PS, "%#x", oper->addend); |
338 | 4.17M | else |
339 | 4.17M | PR (PS, "%d", oper->addend); |
340 | 12.2M | break; |
341 | 19.9M | case RX_Operand_Register: |
342 | 20.0M | case RX_Operand_TwoReg: |
343 | 20.0M | PR (PS, "%s", get_register_name (oper->reg)); |
344 | 20.0M | break; |
345 | 13.4M | case RX_Operand_Indirect: |
346 | 13.4M | PR (PS, "%d[%s]", oper->addend, get_register_name (oper->reg)); |
347 | 13.4M | break; |
348 | 4.21M | case RX_Operand_Zero_Indirect: |
349 | 4.21M | PR (PS, "[%s]", get_register_name (oper->reg)); |
350 | 4.21M | break; |
351 | 1.76k | case RX_Operand_Postinc: |
352 | 1.76k | PR (PS, "[%s+]", get_register_name (oper->reg)); |
353 | 1.76k | break; |
354 | 2.91k | case RX_Operand_Predec: |
355 | 2.91k | PR (PS, "[-%s]", get_register_name (oper->reg)); |
356 | 2.91k | break; |
357 | 5.17M | case RX_Operand_Condition: |
358 | 5.17M | PR (PS, "%s", get_condition_name (oper->reg)); |
359 | 5.17M | break; |
360 | 12.6k | case RX_Operand_Flag: |
361 | 12.6k | PR (PS, "%s", get_flag_name (oper->reg)); |
362 | 12.6k | break; |
363 | 52.6k | case RX_Operand_DoubleReg: |
364 | 52.6k | PR (PS, "%s", get_double_register_name (oper->reg)); |
365 | 52.6k | break; |
366 | 2.50k | case RX_Operand_DoubleRegH: |
367 | 2.50k | PR (PS, "%s", get_double_register_high_name (oper->reg)); |
368 | 2.50k | break; |
369 | 3.61k | case RX_Operand_DoubleRegL: |
370 | 3.61k | PR (PS, "%s", get_double_register_low_name (oper->reg)); |
371 | 3.61k | break; |
372 | 9.28k | case RX_Operand_DoubleCReg: |
373 | 9.28k | PR (PS, "%s", get_double_control_register_name (oper->reg)); |
374 | 9.28k | break; |
375 | 4.18k | case RX_Operand_DoubleCond: |
376 | 4.18k | PR (PS, "%s", get_double_condition_name (oper->reg)); |
377 | 4.18k | break; |
378 | 0 | default: |
379 | 0 | PR (PS, "[???]"); |
380 | 0 | break; |
381 | 55.2M | } |
382 | 72.0M | } |
383 | 72.0M | } |
384 | 320M | } |
385 | | |
386 | 45.8M | return rv; |
387 | 45.8M | } |