]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - opcodes/avr-dis.c
Fix heap-use-after-free because all_objfiles_removed triggers tui_display_main
[thirdparty/binutils-gdb.git] / opcodes / avr-dis.c
CommitLineData
adde6300 1/* Disassemble AVR instructions.
fd67aa11 2 Copyright (C) 1999-2024 Free Software Foundation, Inc.
adde6300
AM
3
4 Contributed by Denis Chertykov <denisc@overta.ru>
5
9b201bb5
NC
6 This file is part of libopcodes.
7
8 This library is free software; you can redistribute it and/or modify
47b0e7ad 9 it under the terms of the GNU General Public License as published by
9b201bb5
NC
10 the Free Software Foundation; either version 3, or (at your option)
11 any later version.
adde6300 12
9b201bb5
NC
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.
adde6300 17
47b0e7ad
NC
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
9b201bb5
NC
20 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21 MA 02110-1301, USA. */
adde6300 22
0d8dfecf 23#include "sysdep.h"
df7b86aa 24#include <assert.h>
88c1242d 25#include "disassemble.h"
adde6300 26#include "opintl.h"
11041102 27#include "libiberty.h"
3dfb1b6d 28#include <stdint.h>
3c504221 29
bab84c47 30struct avr_opcodes_s
adde6300 31{
bab84c47
DC
32 char *name;
33 char *constraints;
34 char *opcode;
47b0e7ad 35 int insn_size; /* In words. */
bab84c47
DC
36 int isa;
37 unsigned int bin_opcode;
bab84c47 38};
adde6300 39
bab84c47 40#define AVR_INSN(NAME, CONSTR, OPCODE, SIZE, ISA, BIN) \
11041102 41{#NAME, CONSTR, OPCODE, SIZE, ISA, BIN},
adde6300 42
11041102 43const struct avr_opcodes_s avr_opcodes[] =
adde6300 44{
bab84c47 45 #include "opcode/avr.h"
11041102 46 {NULL, NULL, NULL, 0, 0, 0}
bab84c47 47};
adde6300 48
af692060
NC
49static const char * comment_start = "0x";
50
463f102c 51static int
96c7115a
MN
52avr_operand (unsigned int insn,
53 unsigned int insn2,
54 unsigned int pc,
55 int constraint,
56 char * opcode_str,
57 char * buf,
58 char * comment,
a0f3a4c6 59 enum disassembler_style * style,
96c7115a
MN
60 int regs,
61 int * sym,
62 bfd_vma * sym_addr,
63 disassemble_info * info)
adde6300 64{
463f102c 65 int ok = 1;
246f4c05 66 *sym = 0;
463f102c 67
bab84c47
DC
68 switch (constraint)
69 {
70 /* Any register operand. */
71 case 'r':
72 if (regs)
47b0e7ad 73 insn = (insn & 0xf) | ((insn & 0x0200) >> 5); /* Source register. */
bab84c47 74 else
47b0e7ad 75 insn = (insn & 0x01f0) >> 4; /* Destination register. */
43e65147 76
bab84c47 77 sprintf (buf, "r%d", insn);
a0f3a4c6 78 *style = dis_style_register;
bab84c47
DC
79 break;
80
81 case 'd':
82 if (regs)
83 sprintf (buf, "r%d", 16 + (insn & 0xf));
84 else
85 sprintf (buf, "r%d", 16 + ((insn & 0xf0) >> 4));
a0f3a4c6 86 *style = dis_style_register;
bab84c47 87 break;
43e65147 88
bab84c47
DC
89 case 'w':
90 sprintf (buf, "r%d", 24 + ((insn & 0x30) >> 3));
a0f3a4c6 91 *style = dis_style_register;
bab84c47 92 break;
43e65147 93
bab84c47
DC
94 case 'a':
95 if (regs)
96 sprintf (buf, "r%d", 16 + (insn & 7));
97 else
98 sprintf (buf, "r%d", 16 + ((insn >> 4) & 7));
a0f3a4c6 99 *style = dis_style_register;
bab84c47 100 break;
adde6300 101
bab84c47
DC
102 case 'v':
103 if (regs)
104 sprintf (buf, "r%d", (insn & 0xf) * 2);
105 else
106 sprintf (buf, "r%d", ((insn & 0xf0) >> 3));
a0f3a4c6 107 *style = dis_style_register;
bab84c47
DC
108 break;
109
110 case 'e':
463f102c
DC
111 {
112 char *xyz;
113
114 switch (insn & 0x100f)
115 {
116 case 0x0000: xyz = "Z"; break;
117 case 0x1001: xyz = "Z+"; break;
118 case 0x1002: xyz = "-Z"; break;
119 case 0x0008: xyz = "Y"; break;
120 case 0x1009: xyz = "Y+"; break;
121 case 0x100a: xyz = "-Y"; break;
122 case 0x100c: xyz = "X"; break;
123 case 0x100d: xyz = "X+"; break;
124 case 0x100e: xyz = "-X"; break;
125 default: xyz = "??"; ok = 0;
126 }
c8941035 127 strcpy (buf, xyz);
463f102c
DC
128
129 if (AVR_UNDEF_P (insn))
130 sprintf (comment, _("undefined"));
131 }
a0f3a4c6 132 *style = dis_style_register;
bab84c47
DC
133 break;
134
135 case 'z':
136 *buf++ = 'Z';
8cc66334
EW
137
138 /* Check for post-increment. */
139 char *s;
140 for (s = opcode_str; *s; ++s)
141 {
142 if (*s == '+')
143 {
5d73b1f1
NC
144 if (insn & (1 << (15 - (s - opcode_str))))
145 *buf++ = '+';
8cc66334
EW
146 break;
147 }
148 }
149
bab84c47 150 *buf = '\0';
463f102c
DC
151 if (AVR_UNDEF_P (insn))
152 sprintf (comment, _("undefined"));
a0f3a4c6 153 *style = dis_style_register;
bab84c47
DC
154 break;
155
156 case 'b':
157 {
463f102c 158 unsigned int x;
43e65147 159
bab84c47
DC
160 x = (insn & 7);
161 x |= (insn >> 7) & (3 << 3);
162 x |= (insn >> 8) & (1 << 5);
43e65147 163
bab84c47
DC
164 if (insn & 0x8)
165 *buf++ = 'Y';
166 else
167 *buf++ = 'Z';
168 sprintf (buf, "+%d", x);
169 sprintf (comment, "0x%02x", x);
a0f3a4c6 170 *style = dis_style_register;
bab84c47
DC
171 }
172 break;
43e65147 173
bab84c47 174 case 'h':
246f4c05
SS
175 *sym = 1;
176 *sym_addr = ((((insn & 1) | ((insn & 0x1f0) >> 3)) << 16) | insn2) * 2;
c4f5c3d7 177 /* See PR binutils/2454. Ideally we would like to display the hex
52f16a0e
NC
178 value of the address only once, but this would mean recoding
179 objdump_print_address() which would affect many targets. */
43e65147 180 sprintf (buf, "%#lx", (unsigned long) *sym_addr);
c8941035 181 strcpy (comment, comment_start);
96c7115a
MN
182 info->insn_info_valid = 1;
183 info->insn_type = dis_jsr;
184 info->target = *sym_addr;
a0f3a4c6 185 *style = dis_style_address;
bab84c47 186 break;
43e65147 187
bab84c47
DC
188 case 'L':
189 {
190 int rel_addr = (((insn & 0xfff) ^ 0x800) - 0x800) * 2;
191 sprintf (buf, ".%+-8d", rel_addr);
246f4c05
SS
192 *sym = 1;
193 *sym_addr = pc + 2 + rel_addr;
c8941035 194 strcpy (comment, comment_start);
96c7115a
MN
195 info->insn_info_valid = 1;
196 info->insn_type = dis_branch;
197 info->target = *sym_addr;
a0f3a4c6 198 *style = dis_style_address_offset;
bab84c47
DC
199 }
200 break;
201
202 case 'l':
203 {
204 int rel_addr = ((((insn >> 3) & 0x7f) ^ 0x40) - 0x40) * 2;
af692060 205
bab84c47 206 sprintf (buf, ".%+-8d", rel_addr);
246f4c05
SS
207 *sym = 1;
208 *sym_addr = pc + 2 + rel_addr;
c8941035 209 strcpy (comment, comment_start);
96c7115a
MN
210 info->insn_info_valid = 1;
211 info->insn_type = dis_condbranch;
212 info->target = *sym_addr;
a0f3a4c6 213 *style = dis_style_address_offset;
bab84c47
DC
214 }
215 break;
216
217 case 'i':
1857fe72
DC
218 {
219 unsigned int val = insn2 | 0x800000;
220 *sym = 1;
221 *sym_addr = val;
222 sprintf (buf, "0x%04X", insn2);
223 strcpy (comment, comment_start);
a0f3a4c6 224 *style = dis_style_immediate;
1857fe72 225 }
bab84c47 226 break;
f36e8886
BS
227
228 case 'j':
229 {
230 unsigned int val = ((insn & 0xf) | ((insn & 0x600) >> 5)
231 | ((insn & 0x100) >> 2));
1d378749
NC
232 if ((insn & 0x100) == 0)
233 val |= 0x80;
1857fe72
DC
234 *sym = 1;
235 *sym_addr = val | 0x800000;
f36e8886 236 sprintf (buf, "0x%02x", val);
1857fe72 237 strcpy (comment, comment_start);
a0f3a4c6 238 *style = dis_style_immediate;
f36e8886
BS
239 }
240 break;
43e65147 241
bab84c47
DC
242 case 'M':
243 sprintf (buf, "0x%02X", ((insn & 0xf00) >> 4) | (insn & 0xf));
244 sprintf (comment, "%d", ((insn & 0xf00) >> 4) | (insn & 0xf));
a0f3a4c6 245 *style = dis_style_immediate;
bab84c47
DC
246 break;
247
248 case 'n':
463f102c 249 sprintf (buf, "??");
a6743a54
AM
250 /* xgettext:c-format */
251 opcodes_error_handler (_("internal disassembler error"));
463f102c 252 ok = 0;
a0f3a4c6 253 *style = dis_style_immediate;
bab84c47 254 break;
43e65147 255
bab84c47 256 case 'K':
463f102c
DC
257 {
258 unsigned int x;
259
260 x = (insn & 0xf) | ((insn >> 2) & 0x30);
261 sprintf (buf, "0x%02x", x);
262 sprintf (comment, "%d", x);
a0f3a4c6 263 *style = dis_style_immediate;
463f102c 264 }
bab84c47 265 break;
43e65147 266
bab84c47
DC
267 case 's':
268 sprintf (buf, "%d", insn & 7);
a0f3a4c6 269 *style = dis_style_immediate;
bab84c47 270 break;
43e65147 271
bab84c47
DC
272 case 'S':
273 sprintf (buf, "%d", (insn >> 4) & 7);
a0f3a4c6 274 *style = dis_style_immediate;
bab84c47 275 break;
43e65147 276
bab84c47
DC
277 case 'P':
278 {
279 unsigned int x;
47b0e7ad 280
bab84c47
DC
281 x = (insn & 0xf);
282 x |= (insn >> 5) & 0x30;
283 sprintf (buf, "0x%02x", x);
284 sprintf (comment, "%d", x);
a0f3a4c6 285 *style = dis_style_address;
bab84c47
DC
286 }
287 break;
288
289 case 'p':
290 {
291 unsigned int x;
43e65147 292
bab84c47
DC
293 x = (insn >> 3) & 0x1f;
294 sprintf (buf, "0x%02x", x);
295 sprintf (comment, "%d", x);
a0f3a4c6 296 *style = dis_style_address;
bab84c47
DC
297 }
298 break;
43e65147 299
8cc66334
EW
300 case 'E':
301 sprintf (buf, "%d", (insn >> 4) & 15);
a0f3a4c6 302 *style = dis_style_immediate;
8cc66334 303 break;
43e65147 304
bab84c47
DC
305 case '?':
306 *buf = '\0';
307 break;
43e65147 308
bab84c47 309 default:
463f102c 310 sprintf (buf, "??");
a6743a54
AM
311 /* xgettext:c-format */
312 opcodes_error_handler (_("unknown constraint `%c'"), constraint);
463f102c 313 ok = 0;
bab84c47 314 }
463f102c
DC
315
316 return ok;
adde6300
AM
317}
318
0a7e1018
YQ
319/* Read the opcode from ADDR. Return 0 in success and save opcode
320 in *INSN, otherwise, return -1. */
321
322static int
323avrdis_opcode (bfd_vma addr, disassemble_info *info, uint16_t *insn)
adde6300
AM
324{
325 bfd_byte buffer[2];
326 int status;
47b0e7ad
NC
327
328 status = info->read_memory_func (addr, buffer, 2, info);
329
330 if (status == 0)
0a7e1018
YQ
331 {
332 *insn = bfd_getl16 (buffer);
333 return 0;
334 }
47b0e7ad
NC
335
336 info->memory_error_func (status, addr, info);
337 return -1;
adde6300
AM
338}
339
340
341int
47b0e7ad 342print_insn_avr (bfd_vma addr, disassemble_info *info)
adde6300 343{
0a7e1018 344 uint16_t insn, insn2;
11041102
KD
345 const struct avr_opcodes_s *opcode;
346 static unsigned int *maskptr;
adde6300 347 void *stream = info->stream;
a0f3a4c6 348 fprintf_styled_ftype prin = info->fprintf_styled_func;
11041102 349 static unsigned int *avr_bin_masks;
bab84c47 350 static int initialized;
adde6300 351 int cmd_len = 2;
463f102c
DC
352 int ok = 0;
353 char op1[20], op2[20], comment1[40], comment2[40];
a0f3a4c6 354 enum disassembler_style style_op1, style_op2;
246f4c05
SS
355 int sym_op1 = 0, sym_op2 = 0;
356 bfd_vma sym_addr1, sym_addr2;
adde6300 357
96c7115a
MN
358 /* Clear instruction information field. */
359 info->insn_info_valid = 0;
360 info->branch_delay_insns = 0;
361 info->data_size = 0;
362 info->insn_type = dis_noninsn;
363 info->target = 0;
364 info->target2 = 0;
af692060 365
bab84c47
DC
366 if (!initialized)
367 {
11041102
KD
368 unsigned int nopcodes;
369
af692060
NC
370 /* PR 4045: Try to avoid duplicating the 0x prefix that
371 objdump_print_addr() will put on addresses when there
372 is no symbol table available. */
373 if (info->symtab_size == 0)
374 comment_start = " ";
375
11041102 376 nopcodes = sizeof (avr_opcodes) / sizeof (struct avr_opcodes_s);
43e65147 377
47b0e7ad 378 avr_bin_masks = xmalloc (nopcodes * sizeof (unsigned int));
11041102
KD
379
380 for (opcode = avr_opcodes, maskptr = avr_bin_masks;
381 opcode->name;
382 opcode++, maskptr++)
bab84c47
DC
383 {
384 char * s;
385 unsigned int bin = 0;
386 unsigned int mask = 0;
43e65147 387
bab84c47
DC
388 for (s = opcode->opcode; *s; ++s)
389 {
390 bin <<= 1;
391 mask <<= 1;
392 bin |= (*s == '1');
393 mask |= (*s == '1' || *s == '0');
394 }
395 assert (s - opcode->opcode == 16);
396 assert (opcode->bin_opcode == bin);
11041102 397 *maskptr = mask;
bab84c47 398 }
11041102
KD
399
400 initialized = 1;
bab84c47 401 }
adde6300 402
0a7e1018
YQ
403 if (avrdis_opcode (addr, info, &insn) != 0)
404 return -1;
43e65147 405
11041102
KD
406 for (opcode = avr_opcodes, maskptr = avr_bin_masks;
407 opcode->name;
408 opcode++, maskptr++)
f36e8886
BS
409 {
410 if ((opcode->isa == AVR_ISA_TINY) && (info->mach != bfd_mach_avrtiny))
411 continue;
412 if ((insn & *maskptr) == opcode->bin_opcode)
413 break;
414 }
43e65147 415
463f102c
DC
416 /* Special case: disassemble `ldd r,b+0' as `ld r,b', and
417 `std b+0,r' as `st b,r' (next entry in the table). */
418
419 if (AVR_DISP0_P (insn))
420 opcode++;
421
422 op1[0] = 0;
423 op2[0] = 0;
424 comment1[0] = 0;
425 comment2[0] = 0;
a0f3a4c6
MN
426 style_op1 = dis_style_text;
427 style_op2 = dis_style_text;
463f102c 428
bab84c47 429 if (opcode->name)
adde6300 430 {
8cc66334
EW
431 char *constraints = opcode->constraints;
432 char *opcode_str = opcode->opcode;
bab84c47 433
00d2865b 434 insn2 = 0;
463f102c 435 ok = 1;
bab84c47
DC
436
437 if (opcode->insn_size > 1)
438 {
0a7e1018
YQ
439 if (avrdis_opcode (addr + 2, info, &insn2) != 0)
440 return -1;
bab84c47
DC
441 cmd_len = 4;
442 }
443
8cc66334 444 if (*constraints && *constraints != '?')
bab84c47 445 {
8cc66334 446 int regs = REGISTER_P (*constraints);
bab84c47 447
96c7115a 448 ok = avr_operand (insn, insn2, addr, *constraints, opcode_str, op1,
a0f3a4c6
MN
449 comment1, &style_op1, 0, &sym_op1, &sym_addr1,
450 info);
bab84c47 451
8cc66334 452 if (ok && *(++constraints) == ',')
96c7115a 453 ok = avr_operand (insn, insn2, addr, *(++constraints), opcode_str,
a0f3a4c6
MN
454 op2, *comment1 ? comment2 : comment1,
455 &style_op2, regs, &sym_op2, &sym_addr2,
456 info);
bab84c47 457 }
463f102c 458 }
bab84c47 459
463f102c
DC
460 if (!ok)
461 {
462 /* Unknown opcode, or invalid combination of operands. */
463 sprintf (op1, "0x%04x", insn);
464 op2[0] = 0;
465 sprintf (comment1, "????");
466 comment2[0] = 0;
467 }
bab84c47 468
a0f3a4c6
MN
469 (*prin) (stream, ok ? dis_style_mnemonic : dis_style_assembler_directive,
470 "%s", ok ? opcode->name : ".word");
471
463f102c 472 if (*op1)
a0f3a4c6 473 (*prin) (stream, style_op1, "\t%s", op1);
bab84c47 474
463f102c 475 if (*op2)
a0f3a4c6
MN
476 {
477 (*prin) (stream, dis_style_text, ", ");
478 (*prin) (stream, style_op2, "%s", op2);
479 }
463f102c
DC
480
481 if (*comment1)
a0f3a4c6 482 (*prin) (stream, dis_style_comment_start, "\t; %s", comment1);
463f102c 483
246f4c05 484 if (sym_op1)
73f643e9 485 info->print_address_func (sym_addr1, info);
246f4c05 486
463f102c 487 if (*comment2)
a0f3a4c6 488 (*prin) (stream, dis_style_comment_start, " %s", comment2);
bab84c47 489
246f4c05 490 if (sym_op2)
73f643e9 491 info->print_address_func (sym_addr2, info);
246f4c05 492
adde6300
AM
493 return cmd_len;
494}