]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - opcodes/sh64-dis.c
2c760673bd20f9266f55e04c93b7533ee3a9486f
[thirdparty/binutils-gdb.git] / opcodes / sh64-dis.c
1 /* Disassemble SH64 instructions.
2 Copyright (C) 2000, 2001 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
17
18 #include <stdio.h>
19
20 #include "dis-asm.h"
21 #include "sysdep.h"
22 #include "sh64-opc.h"
23 #include "libiberty.h"
24
25 /* We need to refer to the ELF header structure. */
26 #include "elf-bfd.h"
27 #include "elf/sh.h"
28
29 #define ELF_MODE32_CODE_LABEL_P(SYM) \
30 (((elf_symbol_type *) (SYM))->internal_elf_sym.st_other & STO_SH5_ISA32)
31
32 #define SAVED_MOVI_R(INFO) \
33 (((struct sh64_disassemble_info *) ((INFO)->private_data))->address_reg)
34
35 #define SAVED_MOVI_IMM(INFO) \
36 (((struct sh64_disassemble_info *) ((INFO)->private_data))->built_address)
37
38 struct sh64_disassemble_info
39 {
40 /* When we see a MOVI, we save the register and the value, and merge a
41 subsequent SHORI and display the address, if there is one. */
42 unsigned int address_reg;
43 bfd_signed_vma built_address;
44
45 /* This is the range decriptor for the current address. It is kept
46 around for the next call. */
47 sh64_elf_crange crange;
48 };
49
50 /* Each item in the table is a mask to indicate which bits to be set
51 to determine an instruction's operator.
52 The index is as same as the instruction in the opcode table.
53 Note that some archs have this as a field in the opcode table. */
54 static unsigned long *shmedia_opcode_mask_table;
55
56 static void initialize_shmedia_opcode_mask_table PARAMS ((void));
57 static int print_insn_shmedia PARAMS ((bfd_vma, disassemble_info *));
58 static int print_insn_sh64x
59 PARAMS ((bfd_vma, disassemble_info *,
60 int (*) PARAMS ((bfd_vma, struct disassemble_info *)),
61 enum bfd_endian));
62 static const char *creg_name PARAMS ((int));
63 static boolean init_sh64_disasm_info PARAMS ((struct disassemble_info *));
64 static enum sh64_elf_cr_type sh64_get_contents_type_disasm
65 PARAMS ((bfd_vma, struct disassemble_info *));
66
67 /* Initialize the SH64 opcode mask table for each instruction in SHmedia
68 mode. */
69
70 static void
71 initialize_shmedia_opcode_mask_table ()
72 {
73 int n_opc;
74 int n;
75
76 /* Calculate number of opcodes. */
77 for (n_opc = 0; shmedia_table[n_opc].name != NULL; n_opc++)
78 ;
79
80 shmedia_opcode_mask_table
81 = xmalloc (sizeof (shmedia_opcode_mask_table[0]) * n_opc);
82
83 for (n = 0; n < n_opc; n++)
84 {
85 int i;
86
87 unsigned long mask = 0;
88
89 for (i = 0; shmedia_table[n].arg[i] != A_NONE; i++)
90 {
91 int offset = shmedia_table[n].nibbles[i];
92 int length;
93
94 switch (shmedia_table[n].arg[i])
95 {
96 case A_GREG_M:
97 case A_GREG_N:
98 case A_GREG_D:
99 case A_CREG_K:
100 case A_CREG_J:
101 case A_FREG_G:
102 case A_FREG_H:
103 case A_FREG_F:
104 case A_DREG_G:
105 case A_DREG_H:
106 case A_DREG_F:
107 case A_FMREG_G:
108 case A_FMREG_H:
109 case A_FMREG_F:
110 case A_FPREG_G:
111 case A_FPREG_H:
112 case A_FPREG_F:
113 case A_FVREG_G:
114 case A_FVREG_H:
115 case A_FVREG_F:
116 case A_REUSE_PREV:
117 length = 6;
118 break;
119
120 case A_TREG_A:
121 case A_TREG_B:
122 length = 3;
123 break;
124
125 case A_IMMM:
126 abort ();
127 break;
128
129 case A_IMMU5:
130 length = 5;
131 break;
132
133 case A_IMMS6:
134 case A_IMMU6:
135 case A_IMMS6BY32:
136 length = 6;
137 break;
138
139 case A_IMMS10:
140 case A_IMMS10BY1:
141 case A_IMMS10BY2:
142 case A_IMMS10BY4:
143 case A_IMMS10BY8:
144 length = 10;
145 break;
146
147 case A_IMMU16:
148 case A_IMMS16:
149 case A_PCIMMS16BY4:
150 case A_PCIMMS16BY4_PT:
151 length = 16;
152 break;
153
154 default:
155 abort ();
156 length = 0;
157 break;
158 }
159
160 if (length != 0)
161 mask |= (0xffffffff >> (32 - length)) << offset;
162 }
163 shmedia_opcode_mask_table[n] = 0xffffffff & ~mask;
164 }
165 }
166
167 /* Get a predefined control-register-name, or return NULL. */
168
169 const char *
170 creg_name (cregno)
171 int cregno;
172 {
173 const shmedia_creg_info *cregp;
174
175 /* If control register usage is common enough, change this to search a
176 hash-table. */
177 for (cregp = shmedia_creg_table; cregp->name != NULL; cregp++)
178 {
179 if (cregp->cregno == cregno)
180 return cregp->name;
181 }
182
183 return NULL;
184 }
185
186 /* Main function to disassemble SHmedia instructions. */
187
188 static int
189 print_insn_shmedia (memaddr, info)
190 bfd_vma memaddr;
191 struct disassemble_info *info;
192 {
193 fprintf_ftype fprintf_fn = info->fprintf_func;
194 void *stream = info->stream;
195
196 unsigned char insn[4];
197 unsigned long instruction;
198 int status;
199 int n;
200 const shmedia_opcode_info *op;
201 int i;
202 unsigned int r = 0;
203 long imm = 0;
204 bfd_vma disp_pc_addr;
205
206 status = info->read_memory_func (memaddr, insn, 4, info);
207
208 /* If we can't read four bytes, something is wrong. Display any data we
209 can get as .byte:s. */
210 if (status != 0)
211 {
212 int i;
213
214 for (i = 0; i < 3; i++)
215 {
216 status = info->read_memory_func (memaddr + i, insn, 1, info);
217 if (status != 0)
218 break;
219 (*fprintf_fn) (stream, "%s0x%02x",
220 i == 0 ? ".byte " : ", ",
221 insn[0]);
222 }
223
224 return i ? i : -1;
225 }
226
227 /* Rearrange the bytes to make up an instruction. */
228 if (info->endian == BFD_ENDIAN_LITTLE)
229 instruction = bfd_getl32 (insn);
230 else
231 instruction = bfd_getb32 (insn);
232
233 /* FIXME: Searching could be implemented using a hash on relevant
234 fields. */
235 for (n = 0, op = shmedia_table;
236 op->name != NULL
237 && ((instruction & shmedia_opcode_mask_table[n]) != op->opcode_base);
238 n++, op++)
239 ;
240
241 /* FIXME: We should also check register number constraints. */
242 if (op->name == NULL)
243 {
244 fprintf_fn (stream, ".long 0x%08x", instruction);
245 return 4;
246 }
247
248 fprintf_fn (stream, "%s\t", op->name);
249
250 for (i = 0; i < 3 && op->arg[i] != A_NONE; i++)
251 {
252 unsigned long temp = instruction >> op->nibbles[i];
253 int by_number = 0;
254
255 if (i > 0 && op->arg[i] != A_REUSE_PREV)
256 fprintf_fn (stream, ",");
257
258 switch (op->arg[i])
259 {
260 case A_REUSE_PREV:
261 continue;
262
263 case A_GREG_M:
264 case A_GREG_N:
265 case A_GREG_D:
266 r = temp & 0x3f;
267 fprintf_fn (stream, "r%d", r);
268 break;
269
270 case A_FVREG_F:
271 case A_FVREG_G:
272 case A_FVREG_H:
273 r = temp & 0x3f;
274 fprintf_fn (stream, "fv%d", r);
275 break;
276
277 case A_FPREG_F:
278 case A_FPREG_G:
279 case A_FPREG_H:
280 r = temp & 0x3f;
281 fprintf_fn (stream, "fp%d", r);
282 break;
283
284 case A_FMREG_F:
285 case A_FMREG_G:
286 case A_FMREG_H:
287 r = temp & 0x3f;
288 fprintf_fn (stream, "mtrx%d", r);
289 break;
290
291 case A_CREG_K:
292 case A_CREG_J:
293 {
294 const char *name;
295 r = temp & 0x3f;
296
297 name = creg_name (r);
298
299 if (name != NULL)
300 fprintf_fn (stream, "%s", name);
301 else
302 fprintf_fn (stream, "cr%d", r);
303 }
304 break;
305
306 case A_FREG_G:
307 case A_FREG_H:
308 case A_FREG_F:
309 r = temp & 0x3f;
310 fprintf_fn (stream, "fr%d", r);
311 break;
312
313 case A_DREG_G:
314 case A_DREG_H:
315 case A_DREG_F:
316 r = temp & 0x3f;
317 fprintf_fn (stream, "dr%d", r);
318 break;
319
320 case A_TREG_A:
321 case A_TREG_B:
322 r = temp & 0x7;
323 fprintf_fn (stream, "tr%d", r);
324 break;
325
326 /* A signed 6-bit number. */
327 case A_IMMS6:
328 imm = temp & 0x3f;
329 if (imm & (unsigned long) 0x20)
330 imm |= ~(unsigned long) 0x3f;
331 fprintf_fn (stream, "%d", imm);
332 break;
333
334 /* A signed 6-bit number, multiplied by 32 when used. */
335 case A_IMMS6BY32:
336 imm = temp & 0x3f;
337 if (imm & (unsigned long) 0x20)
338 imm |= ~(unsigned long) 0x3f;
339 fprintf_fn (stream, "%d", imm * 32);
340 break;
341
342 /* A signed 10-bit number, multiplied by 8 when used. */
343 case A_IMMS10BY8:
344 by_number++;
345 /* Fall through. */
346
347 /* A signed 10-bit number, multiplied by 4 when used. */
348 case A_IMMS10BY4:
349 by_number++;
350 /* Fall through. */
351
352 /* A signed 10-bit number, multiplied by 2 when used. */
353 case A_IMMS10BY2:
354 by_number++;
355 /* Fall through. */
356
357 /* A signed 10-bit number. */
358 case A_IMMS10:
359 case A_IMMS10BY1:
360 imm = temp & 0x3ff;
361 if (imm & (unsigned long) 0x200)
362 imm |= ~(unsigned long) 0x3ff;
363 imm <<= by_number;
364 fprintf_fn (stream, "%d", imm);
365 break;
366
367 /* A signed 16-bit number. */
368 case A_IMMS16:
369 imm = temp & 0xffff;
370 if (imm & (unsigned long) 0x8000)
371 imm |= ~((unsigned long) 0xffff);
372 fprintf_fn (stream, "%d", imm);
373 break;
374
375 /* A PC-relative signed 16-bit number, multiplied by 4 when
376 used. */
377 case A_PCIMMS16BY4:
378 imm = temp & 0xffff; /* 16 bits */
379 if (imm & (unsigned long) 0x8000)
380 imm |= ~(unsigned long) 0xffff;
381 imm <<= 2;
382 disp_pc_addr = (bfd_vma) imm + memaddr;
383 (*info->print_address_func) (disp_pc_addr, info);
384 break;
385
386 /* An unsigned 5-bit number. */
387 case A_IMMU5:
388 imm = temp & 0x1f;
389 fprintf_fn (stream, "%d", imm);
390 break;
391
392 /* An unsigned 6-bit number. */
393 case A_IMMU6:
394 imm = temp & 0x3f;
395 fprintf_fn (stream, "%d", imm);
396 break;
397
398 /* An unsigned 16-bit number. */
399 case A_IMMU16:
400 imm = temp & 0xffff;
401 fprintf_fn (stream, "%d", imm);
402 break;
403
404 default:
405 abort ();
406 break;
407 }
408 }
409
410 /* FIXME: Looks like 32-bit values only are handled.
411 FIXME: PC-relative numbers aren't handled correctly. */
412 if (op->opcode_base == (unsigned long) SHMEDIA_SHORI_OPC
413 && SAVED_MOVI_R (info) == r)
414 {
415 asection *section = info->section;
416
417 /* Most callers do not set the section field correctly yet. Revert
418 to getting the section from symbols, if any. */
419 if (section == NULL
420 && info->symbols != NULL
421 && bfd_asymbol_flavour (info->symbols[0]) == bfd_target_elf_flavour
422 && ! bfd_is_und_section (bfd_get_section (info->symbols[0]))
423 && ! bfd_is_abs_section (bfd_get_section (info->symbols[0])))
424 section = bfd_get_section (info->symbols[0]);
425
426 /* Only guess addresses when the contents of this section is fully
427 relocated. Otherwise, the value will be zero or perhaps even
428 bogus. */
429 if (section == NULL
430 || section->owner == NULL
431 || elf_elfheader (section->owner)->e_type == ET_EXEC)
432 {
433 bfd_signed_vma shori_addr;
434
435 shori_addr = SAVED_MOVI_IMM (info) << 16;
436 shori_addr |= imm;
437
438 fprintf_fn (stream, "\t! 0x");
439 (*info->print_address_func) (shori_addr, info);
440 }
441 }
442
443 if (op->opcode_base == SHMEDIA_MOVI_OPC)
444 {
445 SAVED_MOVI_IMM (info) = imm;
446 SAVED_MOVI_R (info) = r;
447 }
448 else
449 {
450 SAVED_MOVI_IMM (info) = 0;
451 SAVED_MOVI_R (info) = 255;
452 }
453
454 return 4;
455 }
456
457 /* Check the type of contents about to be disassembled. This is like
458 sh64_get_contents_type (which may be called from here), except that it
459 takes the same arguments as print_insn_* and does what can be done if
460 no section is available. */
461
462 static enum sh64_elf_cr_type
463 sh64_get_contents_type_disasm (memaddr, info)
464 bfd_vma memaddr;
465 struct disassemble_info *info;
466 {
467 struct sh64_disassemble_info *sh64_infop = info->private_data;
468
469 /* Perhaps we have a region from a previous probe and it still counts
470 for this address? */
471 if (sh64_infop->crange.cr_type != CRT_NONE
472 && memaddr >= sh64_infop->crange.cr_addr
473 && memaddr < sh64_infop->crange.cr_addr + sh64_infop->crange.cr_size)
474 return sh64_infop->crange.cr_type;
475
476 /* If we have a section, try and use it. */
477 if (info->section
478 && bfd_get_flavour (info->section->owner) == bfd_target_elf_flavour)
479 {
480 enum sh64_elf_cr_type cr_type
481 = sh64_get_contents_type (info->section, memaddr,
482 &sh64_infop->crange);
483
484 if (cr_type != CRT_NONE)
485 return cr_type;
486 }
487
488 /* If we have symbols, we can try and get at a section from *that*. */
489 if (info->symbols != NULL
490 && bfd_asymbol_flavour (info->symbols[0]) == bfd_target_elf_flavour
491 && ! bfd_is_und_section (bfd_get_section (info->symbols[0]))
492 && ! bfd_is_abs_section (bfd_get_section (info->symbols[0])))
493 {
494 enum sh64_elf_cr_type cr_type
495 = sh64_get_contents_type (bfd_get_section (info->symbols[0]),
496 memaddr, &sh64_infop->crange);
497
498 if (cr_type != CRT_NONE)
499 return cr_type;
500 }
501
502 /* We can make a reasonable guess based on the st_other field of a
503 symbol; for a BranchTarget this is marked as STO_SH5_ISA32 and then
504 it's most probably code there. */
505 if (info->symbols
506 && bfd_asymbol_flavour (info->symbols[0]) == bfd_target_elf_flavour
507 && elf_symbol_from (bfd_asymbol_bfd (info->symbols[0]),
508 info->symbols[0])->internal_elf_sym.st_other
509 == STO_SH5_ISA32)
510 return CRT_SH5_ISA32;
511
512 /* If all else fails, guess this is code and guess on the low bit set. */
513 return (memaddr & 1) == 1 ? CRT_SH5_ISA32 : CRT_SH5_ISA16;
514 }
515
516 /* Initialize static and dynamic disassembly state. */
517
518 static boolean
519 init_sh64_disasm_info (info)
520 struct disassemble_info *info;
521 {
522 struct sh64_disassemble_info *sh64_infop
523 = calloc (sizeof (*sh64_infop), 1);
524
525 if (sh64_infop == NULL)
526 return false;
527
528 info->private_data = sh64_infop;
529
530 SAVED_MOVI_IMM (info) = 0;
531 SAVED_MOVI_R (info) = 255;
532
533 if (shmedia_opcode_mask_table == NULL)
534 initialize_shmedia_opcode_mask_table ();
535
536 return true;
537 }
538
539 /* Main entry to disassemble SHmedia instructions, given an endian set in
540 INFO. Note that the simulator uses this as the main entry and does not
541 use any of the functions further below. */
542
543 int
544 print_insn_sh64x_media (memaddr, info)
545 bfd_vma memaddr;
546 struct disassemble_info *info;
547 {
548 if (info->private_data == NULL && ! init_sh64_disasm_info (info))
549 return -1;
550
551 /* Make reasonable output. */
552 info->bytes_per_line = 4;
553 info->bytes_per_chunk = 4;
554
555 return print_insn_shmedia (memaddr, info);
556 }
557
558 /* Main entry to disassemble SHcompact or SHmedia insns. */
559
560 static int
561 print_insn_sh64x (memaddr, info, pfun_compact, endian)
562 bfd_vma memaddr;
563 struct disassemble_info *info;
564 int (*pfun_compact) PARAMS ((bfd_vma, struct disassemble_info *));
565 enum bfd_endian endian;
566 {
567 enum sh64_elf_cr_type cr_type;
568
569 if (info->private_data == NULL && ! init_sh64_disasm_info (info))
570 return -1;
571
572 cr_type = sh64_get_contents_type_disasm (memaddr, info);
573 if (cr_type != CRT_SH5_ISA16)
574 {
575 int length = 4 - (memaddr % 4);
576 info->display_endian = endian;
577
578 /* Only disassemble on four-byte boundaries. Addresses that are not
579 a multiple of four can happen after a data region. */
580 if (cr_type == CRT_SH5_ISA32 && length == 4)
581 return print_insn_sh64x_media (memaddr, info);
582
583 /* We get CRT_DATA *only* for data regions in a mixed-contents
584 section. For sections with data only, we get indication of one
585 of the ISA:s. You may think that we shouldn't disassemble
586 section with only data if we can figure that out. However, the
587 disassembly function is by default not called for data-only
588 sections, so if the user explicitly specified disassembly of a
589 data section, that's what we should do. */
590 if (cr_type == CRT_DATA || length != 4)
591 {
592 int status;
593 unsigned char data[4];
594 struct sh64_disassemble_info *sh64_infop = info->private_data;
595
596 if (length == 4
597 && sh64_infop->crange.cr_type != CRT_NONE
598 && memaddr >= sh64_infop->crange.cr_addr
599 && memaddr < (sh64_infop->crange.cr_addr
600 + sh64_infop->crange.cr_size))
601 length
602 = (sh64_infop->crange.cr_addr
603 + sh64_infop->crange.cr_size - memaddr);
604
605 status
606 = (*info->read_memory_func) (memaddr, data,
607 length >= 4 ? 4 : length, info);
608
609 if (status == 0 && length >= 4)
610 {
611 (*info->fprintf_func) (info->stream, ".long 0x%08lx",
612 endian == BFD_ENDIAN_BIG
613 ? (long) (bfd_getb32 (data))
614 : (long) (bfd_getl32 (data)));
615 return 4;
616 }
617 else
618 {
619 int i;
620
621 for (i = 0; i < length; i++)
622 {
623 status = info->read_memory_func (memaddr + i, data, 1, info);
624 if (status != 0)
625 break;
626 (*info->fprintf_func) (info->stream, "%s0x%02x",
627 i == 0 ? ".byte " : ", ",
628 data[0]);
629 }
630
631 return i ? i : -1;
632 }
633 }
634 }
635
636 return (*pfun_compact) (memaddr, info);
637 }
638
639 /* Main entry to disassemble SHcompact or SHmedia insns, big endian. */
640
641 int
642 print_insn_sh64 (memaddr, info)
643 bfd_vma memaddr;
644 struct disassemble_info *info;
645 {
646 return
647 print_insn_sh64x (memaddr, info, print_insn_sh, BFD_ENDIAN_BIG);
648 }
649
650 /* Main entry to disassemble SHcompact or SHmedia insns, little endian. */
651
652 int
653 print_insn_sh64l (memaddr, info)
654 bfd_vma memaddr;
655 struct disassemble_info *info;
656 {
657 return
658 print_insn_sh64x (memaddr, info, print_insn_shl, BFD_ENDIAN_LITTLE);
659 }