1 /* Disassemble SH64 instructions.
2 Copyright 2000, 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
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.
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.
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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
23 #include "libiberty.h"
24 /* We need to refer to the ELF header structure. */
27 #include "elf32-sh64.h"
29 #define ELF_MODE32_CODE_LABEL_P(SYM) \
30 (((elf_symbol_type *) (SYM))->internal_elf_sym.st_other & STO_SH5_ISA32)
32 #define SAVED_MOVI_R(INFO) \
33 (((struct sh64_disassemble_info *) ((INFO)->private_data))->address_reg)
35 #define SAVED_MOVI_IMM(INFO) \
36 (((struct sh64_disassemble_info *) ((INFO)->private_data))->built_address)
38 struct sh64_disassemble_info
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
;
45 /* This is the range decriptor for the current address. It is kept
46 around for the next call. */
47 sh64_elf_crange crange
;
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
;
56 /* Initialize the SH64 opcode mask table for each instruction in SHmedia
60 initialize_shmedia_opcode_mask_table (void)
65 /* Calculate number of opcodes. */
66 for (n_opc
= 0; shmedia_table
[n_opc
].name
!= NULL
; n_opc
++)
69 shmedia_opcode_mask_table
70 = xmalloc (sizeof (shmedia_opcode_mask_table
[0]) * n_opc
);
72 for (n
= 0; n
< n_opc
; n
++)
76 unsigned long mask
= 0;
78 for (i
= 0; shmedia_table
[n
].arg
[i
] != A_NONE
; i
++)
80 int offset
= shmedia_table
[n
].nibbles
[i
];
83 switch (shmedia_table
[n
].arg
[i
])
139 case A_PCIMMS16BY4_PT
:
150 mask
|= (0xffffffff >> (32 - length
)) << offset
;
152 shmedia_opcode_mask_table
[n
] = 0xffffffff & ~mask
;
156 /* Get a predefined control-register-name, or return NULL. */
159 creg_name (int cregno
)
161 const shmedia_creg_info
*cregp
;
163 /* If control register usage is common enough, change this to search a
165 for (cregp
= shmedia_creg_table
; cregp
->name
!= NULL
; cregp
++)
166 if (cregp
->cregno
== cregno
)
172 /* Main function to disassemble SHmedia instructions. */
175 print_insn_shmedia (bfd_vma memaddr
, struct disassemble_info
*info
)
177 fprintf_ftype fprintf_fn
= info
->fprintf_func
;
178 void *stream
= info
->stream
;
179 unsigned char insn
[4];
180 unsigned long instruction
;
183 const shmedia_opcode_info
*op
;
187 bfd_vma disp_pc_addr
;
189 status
= info
->read_memory_func (memaddr
, insn
, 4, info
);
191 /* If we can't read four bytes, something is wrong. Display any data we
192 can get as .byte:s. */
197 for (i
= 0; i
< 3; i
++)
199 status
= info
->read_memory_func (memaddr
+ i
, insn
, 1, info
);
202 (*fprintf_fn
) (stream
, "%s0x%02x",
203 i
== 0 ? ".byte " : ", ",
210 /* Rearrange the bytes to make up an instruction. */
211 if (info
->endian
== BFD_ENDIAN_LITTLE
)
212 instruction
= bfd_getl32 (insn
);
214 instruction
= bfd_getb32 (insn
);
216 /* FIXME: Searching could be implemented using a hash on relevant
218 for (n
= 0, op
= shmedia_table
;
220 && ((instruction
& shmedia_opcode_mask_table
[n
]) != op
->opcode_base
);
224 /* FIXME: We should also check register number constraints. */
225 if (op
->name
== NULL
)
227 fprintf_fn (stream
, ".long 0x%08lx", instruction
);
231 fprintf_fn (stream
, "%s\t", op
->name
);
233 for (i
= 0; i
< 3 && op
->arg
[i
] != A_NONE
; i
++)
235 unsigned long temp
= instruction
>> op
->nibbles
[i
];
238 if (i
> 0 && op
->arg
[i
] != A_REUSE_PREV
)
239 fprintf_fn (stream
, ",");
250 fprintf_fn (stream
, "r%d", r
);
257 fprintf_fn (stream
, "fv%d", r
);
264 fprintf_fn (stream
, "fp%d", r
);
271 fprintf_fn (stream
, "mtrx%d", r
);
281 name
= creg_name (r
);
284 fprintf_fn (stream
, "%s", name
);
286 fprintf_fn (stream
, "cr%d", r
);
294 fprintf_fn (stream
, "fr%d", r
);
301 fprintf_fn (stream
, "dr%d", r
);
307 fprintf_fn (stream
, "tr%d", r
);
310 /* A signed 6-bit number. */
313 if (imm
& (unsigned long) 0x20)
314 imm
|= ~(unsigned long) 0x3f;
315 fprintf_fn (stream
, "%ld", imm
);
318 /* A signed 6-bit number, multiplied by 32 when used. */
321 if (imm
& (unsigned long) 0x20)
322 imm
|= ~(unsigned long) 0x3f;
323 fprintf_fn (stream
, "%ld", imm
* 32);
326 /* A signed 10-bit number, multiplied by 8 when used. */
331 /* A signed 10-bit number, multiplied by 4 when used. */
336 /* A signed 10-bit number, multiplied by 2 when used. */
341 /* A signed 10-bit number. */
345 if (imm
& (unsigned long) 0x200)
346 imm
|= ~(unsigned long) 0x3ff;
348 fprintf_fn (stream
, "%ld", imm
);
351 /* A signed 16-bit number. */
354 if (imm
& (unsigned long) 0x8000)
355 imm
|= ~((unsigned long) 0xffff);
356 fprintf_fn (stream
, "%ld", imm
);
359 /* A PC-relative signed 16-bit number, multiplied by 4 when
362 imm
= temp
& 0xffff; /* 16 bits */
363 if (imm
& (unsigned long) 0x8000)
364 imm
|= ~(unsigned long) 0xffff;
366 disp_pc_addr
= (bfd_vma
) imm
+ memaddr
;
367 (*info
->print_address_func
) (disp_pc_addr
, info
);
370 /* An unsigned 5-bit number. */
373 fprintf_fn (stream
, "%ld", imm
);
376 /* An unsigned 6-bit number. */
379 fprintf_fn (stream
, "%ld", imm
);
382 /* An unsigned 16-bit number. */
385 fprintf_fn (stream
, "%ld", imm
);
394 /* FIXME: Looks like 32-bit values only are handled.
395 FIXME: PC-relative numbers aren't handled correctly. */
396 if (op
->opcode_base
== (unsigned long) SHMEDIA_SHORI_OPC
397 && SAVED_MOVI_R (info
) == r
)
399 asection
*section
= info
->section
;
401 /* Most callers do not set the section field correctly yet. Revert
402 to getting the section from symbols, if any. */
404 && info
->symbols
!= NULL
405 && bfd_asymbol_flavour (info
->symbols
[0]) == bfd_target_elf_flavour
406 && ! bfd_is_und_section (bfd_get_section (info
->symbols
[0]))
407 && ! bfd_is_abs_section (bfd_get_section (info
->symbols
[0])))
408 section
= bfd_get_section (info
->symbols
[0]);
410 /* Only guess addresses when the contents of this section is fully
411 relocated. Otherwise, the value will be zero or perhaps even
414 || section
->owner
== NULL
415 || elf_elfheader (section
->owner
)->e_type
== ET_EXEC
)
417 bfd_signed_vma shori_addr
;
419 shori_addr
= SAVED_MOVI_IMM (info
) << 16;
422 fprintf_fn (stream
, "\t! 0x");
423 (*info
->print_address_func
) (shori_addr
, info
);
427 if (op
->opcode_base
== SHMEDIA_MOVI_OPC
)
429 SAVED_MOVI_IMM (info
) = imm
;
430 SAVED_MOVI_R (info
) = r
;
434 SAVED_MOVI_IMM (info
) = 0;
435 SAVED_MOVI_R (info
) = 255;
441 /* Check the type of contents about to be disassembled. This is like
442 sh64_get_contents_type (which may be called from here), except that it
443 takes the same arguments as print_insn_* and does what can be done if
444 no section is available. */
446 static enum sh64_elf_cr_type
447 sh64_get_contents_type_disasm (bfd_vma memaddr
, struct disassemble_info
*info
)
449 struct sh64_disassemble_info
*sh64_infop
= info
->private_data
;
451 /* Perhaps we have a region from a previous probe and it still counts
453 if (sh64_infop
->crange
.cr_type
!= CRT_NONE
454 && memaddr
>= sh64_infop
->crange
.cr_addr
455 && memaddr
< sh64_infop
->crange
.cr_addr
+ sh64_infop
->crange
.cr_size
)
456 return sh64_infop
->crange
.cr_type
;
458 /* If we have a section, try and use it. */
460 && bfd_get_flavour (info
->section
->owner
) == bfd_target_elf_flavour
)
462 enum sh64_elf_cr_type cr_type
463 = sh64_get_contents_type (info
->section
, memaddr
,
464 &sh64_infop
->crange
);
466 if (cr_type
!= CRT_NONE
)
470 /* If we have symbols, we can try and get at a section from *that*. */
471 if (info
->symbols
!= NULL
472 && bfd_asymbol_flavour (info
->symbols
[0]) == bfd_target_elf_flavour
473 && ! bfd_is_und_section (bfd_get_section (info
->symbols
[0]))
474 && ! bfd_is_abs_section (bfd_get_section (info
->symbols
[0])))
476 enum sh64_elf_cr_type cr_type
477 = sh64_get_contents_type (bfd_get_section (info
->symbols
[0]),
478 memaddr
, &sh64_infop
->crange
);
480 if (cr_type
!= CRT_NONE
)
484 /* We can make a reasonable guess based on the st_other field of a
485 symbol; for a BranchTarget this is marked as STO_SH5_ISA32 and then
486 it's most probably code there. */
488 && bfd_asymbol_flavour (info
->symbols
[0]) == bfd_target_elf_flavour
489 && elf_symbol_from (bfd_asymbol_bfd (info
->symbols
[0]),
490 info
->symbols
[0])->internal_elf_sym
.st_other
492 return CRT_SH5_ISA32
;
494 /* If all else fails, guess this is code and guess on the low bit set. */
495 return (memaddr
& 1) == 1 ? CRT_SH5_ISA32
: CRT_SH5_ISA16
;
498 /* Initialize static and dynamic disassembly state. */
501 init_sh64_disasm_info (struct disassemble_info
*info
)
503 struct sh64_disassemble_info
*sh64_infop
504 = calloc (sizeof (*sh64_infop
), 1);
506 if (sh64_infop
== NULL
)
509 info
->private_data
= sh64_infop
;
511 SAVED_MOVI_IMM (info
) = 0;
512 SAVED_MOVI_R (info
) = 255;
514 if (shmedia_opcode_mask_table
== NULL
)
515 initialize_shmedia_opcode_mask_table ();
520 /* Main entry to disassemble SHmedia instructions, given an endian set in
521 INFO. Note that the simulator uses this as the main entry and does not
522 use any of the functions further below. */
525 print_insn_sh64x_media (bfd_vma memaddr
, struct disassemble_info
*info
)
527 if (info
->private_data
== NULL
&& ! init_sh64_disasm_info (info
))
530 /* Make reasonable output. */
531 info
->bytes_per_line
= 4;
532 info
->bytes_per_chunk
= 4;
534 return print_insn_shmedia (memaddr
, info
);
537 /* Main entry to disassemble SHmedia insns.
538 If we see an SHcompact instruction, return -2. */
541 print_insn_sh64 (bfd_vma memaddr
, struct disassemble_info
*info
)
543 enum bfd_endian endian
= info
->endian
;
544 enum sh64_elf_cr_type cr_type
;
546 if (info
->private_data
== NULL
&& ! init_sh64_disasm_info (info
))
549 cr_type
= sh64_get_contents_type_disasm (memaddr
, info
);
550 if (cr_type
!= CRT_SH5_ISA16
)
552 int length
= 4 - (memaddr
% 4);
553 info
->display_endian
= endian
;
555 /* If we got an uneven address to indicate SHmedia, adjust it. */
556 if (cr_type
== CRT_SH5_ISA32
&& length
== 3)
557 memaddr
--, length
= 4;
559 /* Only disassemble on four-byte boundaries. Addresses that are not
560 a multiple of four can happen after a data region. */
561 if (cr_type
== CRT_SH5_ISA32
&& length
== 4)
562 return print_insn_sh64x_media (memaddr
, info
);
564 /* We get CRT_DATA *only* for data regions in a mixed-contents
565 section. For sections with data only, we get indication of one
566 of the ISA:s. You may think that we shouldn't disassemble
567 section with only data if we can figure that out. However, the
568 disassembly function is by default not called for data-only
569 sections, so if the user explicitly specified disassembly of a
570 data section, that's what we should do. */
571 if (cr_type
== CRT_DATA
|| length
!= 4)
574 unsigned char data
[4];
575 struct sh64_disassemble_info
*sh64_infop
= info
->private_data
;
578 && sh64_infop
->crange
.cr_type
!= CRT_NONE
579 && memaddr
>= sh64_infop
->crange
.cr_addr
580 && memaddr
< (sh64_infop
->crange
.cr_addr
581 + sh64_infop
->crange
.cr_size
))
583 = (sh64_infop
->crange
.cr_addr
584 + sh64_infop
->crange
.cr_size
- memaddr
);
587 = (*info
->read_memory_func
) (memaddr
, data
,
588 length
>= 4 ? 4 : length
, info
);
590 if (status
== 0 && length
>= 4)
592 (*info
->fprintf_func
) (info
->stream
, ".long 0x%08lx",
593 endian
== BFD_ENDIAN_BIG
594 ? (long) (bfd_getb32 (data
))
595 : (long) (bfd_getl32 (data
)));
602 for (i
= 0; i
< length
; i
++)
604 status
= info
->read_memory_func (memaddr
+ i
, data
, 1, info
);
607 (*info
->fprintf_func
) (info
->stream
, "%s0x%02x",
608 i
== 0 ? ".byte " : ", ",
617 /* SH1 .. SH4 instruction, let caller handle it. */