1 /* Disassemble SH64 instructions.
2 Copyright 2000, 2001, 2002, 2003, 2005, 2007, 2012
3 Free Software Foundation, Inc.
5 This file is part of the GNU opcodes library.
7 This library is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 It is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this file; see the file COPYING. If not, write to the
19 Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
20 MA 02110-1301, USA. */
26 #include "libiberty.h"
27 /* We need to refer to the ELF header structure. */
30 #include "elf32-sh64.h"
32 #define ELF_MODE32_CODE_LABEL_P(SYM) \
33 (((elf_symbol_type *) (SYM))->internal_elf_sym.st_other & STO_SH5_ISA32)
35 #define SAVED_MOVI_R(INFO) \
36 (((struct sh64_disassemble_info *) ((INFO)->private_data))->address_reg)
38 #define SAVED_MOVI_IMM(INFO) \
39 (((struct sh64_disassemble_info *) ((INFO)->private_data))->built_address)
41 struct sh64_disassemble_info
43 /* When we see a MOVI, we save the register and the value, and merge a
44 subsequent SHORI and display the address, if there is one. */
45 unsigned int address_reg
;
46 bfd_signed_vma built_address
;
48 /* This is the range decriptor for the current address. It is kept
49 around for the next call. */
50 sh64_elf_crange crange
;
53 /* Each item in the table is a mask to indicate which bits to be set
54 to determine an instruction's operator.
55 The index is as same as the instruction in the opcode table.
56 Note that some archs have this as a field in the opcode table. */
57 static unsigned long *shmedia_opcode_mask_table
;
59 /* Initialize the SH64 opcode mask table for each instruction in SHmedia
63 initialize_shmedia_opcode_mask_table (void)
68 /* Calculate number of opcodes. */
69 for (n_opc
= 0; shmedia_table
[n_opc
].name
!= NULL
; n_opc
++)
72 shmedia_opcode_mask_table
73 = xmalloc (sizeof (shmedia_opcode_mask_table
[0]) * n_opc
);
75 for (n
= 0; n
< n_opc
; n
++)
79 unsigned long mask
= 0;
81 for (i
= 0; shmedia_table
[n
].arg
[i
] != A_NONE
; i
++)
83 int offset
= shmedia_table
[n
].nibbles
[i
];
86 switch (shmedia_table
[n
].arg
[i
])
142 case A_PCIMMS16BY4_PT
:
153 mask
|= (0xffffffff >> (32 - length
)) << offset
;
155 shmedia_opcode_mask_table
[n
] = 0xffffffff & ~mask
;
159 /* Get a predefined control-register-name, or return NULL. */
162 creg_name (int cregno
)
164 const shmedia_creg_info
*cregp
;
166 /* If control register usage is common enough, change this to search a
168 for (cregp
= shmedia_creg_table
; cregp
->name
!= NULL
; cregp
++)
169 if (cregp
->cregno
== cregno
)
175 /* Main function to disassemble SHmedia instructions. */
178 print_insn_shmedia (bfd_vma memaddr
, struct disassemble_info
*info
)
180 fprintf_ftype fprintf_fn
= info
->fprintf_func
;
181 void *stream
= info
->stream
;
182 unsigned char insn
[4];
183 unsigned long instruction
;
186 const shmedia_opcode_info
*op
;
190 bfd_vma disp_pc_addr
;
192 status
= info
->read_memory_func (memaddr
, insn
, 4, info
);
194 /* If we can't read four bytes, something is wrong. Display any data we
195 can get as .byte:s. */
198 for (i
= 0; i
< 3; i
++)
200 status
= info
->read_memory_func (memaddr
+ i
, insn
, 1, info
);
203 (*fprintf_fn
) (stream
, "%s0x%02x",
204 i
== 0 ? ".byte " : ", ",
211 /* Rearrange the bytes to make up an instruction. */
212 if (info
->endian
== BFD_ENDIAN_LITTLE
)
213 instruction
= bfd_getl32 (insn
);
215 instruction
= bfd_getb32 (insn
);
217 /* FIXME: Searching could be implemented using a hash on relevant
219 for (n
= 0, op
= shmedia_table
;
221 && ((instruction
& shmedia_opcode_mask_table
[n
]) != op
->opcode_base
);
225 /* FIXME: We should also check register number constraints. */
226 if (op
->name
== NULL
)
228 fprintf_fn (stream
, ".long 0x%08lx", instruction
);
232 fprintf_fn (stream
, "%s\t", op
->name
);
234 for (i
= 0; i
< 3 && op
->arg
[i
] != A_NONE
; i
++)
236 unsigned long temp
= instruction
>> op
->nibbles
[i
];
239 if (i
> 0 && op
->arg
[i
] != A_REUSE_PREV
)
240 fprintf_fn (stream
, ",");
251 fprintf_fn (stream
, "r%d", r
);
258 fprintf_fn (stream
, "fv%d", r
);
265 fprintf_fn (stream
, "fp%d", r
);
272 fprintf_fn (stream
, "mtrx%d", r
);
282 name
= creg_name (r
);
285 fprintf_fn (stream
, "%s", name
);
287 fprintf_fn (stream
, "cr%d", r
);
295 fprintf_fn (stream
, "fr%d", r
);
302 fprintf_fn (stream
, "dr%d", r
);
308 fprintf_fn (stream
, "tr%d", r
);
311 /* A signed 6-bit number. */
314 if (imm
& (unsigned long) 0x20)
315 imm
|= ~(unsigned long) 0x3f;
316 fprintf_fn (stream
, "%ld", imm
);
319 /* A signed 6-bit number, multiplied by 32 when used. */
322 if (imm
& (unsigned long) 0x20)
323 imm
|= ~(unsigned long) 0x3f;
324 fprintf_fn (stream
, "%ld", imm
* 32);
327 /* A signed 10-bit number, multiplied by 8 when used. */
332 /* A signed 10-bit number, multiplied by 4 when used. */
337 /* A signed 10-bit number, multiplied by 2 when used. */
342 /* A signed 10-bit number. */
346 if (imm
& (unsigned long) 0x200)
347 imm
|= ~(unsigned long) 0x3ff;
349 fprintf_fn (stream
, "%ld", imm
);
352 /* A signed 16-bit number. */
355 if (imm
& (unsigned long) 0x8000)
356 imm
|= ~((unsigned long) 0xffff);
357 fprintf_fn (stream
, "%ld", imm
);
360 /* A PC-relative signed 16-bit number, multiplied by 4 when
363 imm
= temp
& 0xffff; /* 16 bits */
364 if (imm
& (unsigned long) 0x8000)
365 imm
|= ~(unsigned long) 0xffff;
367 disp_pc_addr
= (bfd_vma
) imm
+ memaddr
;
368 (*info
->print_address_func
) (disp_pc_addr
, info
);
371 /* An unsigned 5-bit number. */
374 fprintf_fn (stream
, "%ld", imm
);
377 /* An unsigned 6-bit number. */
380 fprintf_fn (stream
, "%ld", imm
);
383 /* An unsigned 16-bit number. */
386 fprintf_fn (stream
, "%ld", imm
);
395 /* FIXME: Looks like 32-bit values only are handled.
396 FIXME: PC-relative numbers aren't handled correctly. */
397 if (op
->opcode_base
== (unsigned long) SHMEDIA_SHORI_OPC
398 && SAVED_MOVI_R (info
) == r
)
400 asection
*section
= info
->section
;
402 /* Most callers do not set the section field correctly yet. Revert
403 to getting the section from symbols, if any. */
405 && info
->symbols
!= NULL
406 && bfd_asymbol_flavour (info
->symbols
[0]) == bfd_target_elf_flavour
407 && ! bfd_is_und_section (bfd_get_section (info
->symbols
[0]))
408 && ! bfd_is_abs_section (bfd_get_section (info
->symbols
[0])))
409 section
= bfd_get_section (info
->symbols
[0]);
411 /* Only guess addresses when the contents of this section is fully
412 relocated. Otherwise, the value will be zero or perhaps even
415 || section
->owner
== NULL
416 || elf_elfheader (section
->owner
)->e_type
== ET_EXEC
)
418 bfd_signed_vma shori_addr
;
420 shori_addr
= SAVED_MOVI_IMM (info
) << 16;
423 fprintf_fn (stream
, "\t! 0x");
424 (*info
->print_address_func
) (shori_addr
, info
);
428 if (op
->opcode_base
== SHMEDIA_MOVI_OPC
)
430 SAVED_MOVI_IMM (info
) = imm
;
431 SAVED_MOVI_R (info
) = r
;
435 SAVED_MOVI_IMM (info
) = 0;
436 SAVED_MOVI_R (info
) = 255;
442 /* Check the type of contents about to be disassembled. This is like
443 sh64_get_contents_type (which may be called from here), except that it
444 takes the same arguments as print_insn_* and does what can be done if
445 no section is available. */
447 static enum sh64_elf_cr_type
448 sh64_get_contents_type_disasm (bfd_vma memaddr
, struct disassemble_info
*info
)
450 struct sh64_disassemble_info
*sh64_infop
= info
->private_data
;
452 /* Perhaps we have a region from a previous probe and it still counts
454 if (sh64_infop
->crange
.cr_type
!= CRT_NONE
455 && memaddr
>= sh64_infop
->crange
.cr_addr
456 && memaddr
< sh64_infop
->crange
.cr_addr
+ sh64_infop
->crange
.cr_size
)
457 return sh64_infop
->crange
.cr_type
;
459 /* If we have a section, try and use it. */
461 && bfd_get_flavour (info
->section
->owner
) == bfd_target_elf_flavour
)
463 enum sh64_elf_cr_type cr_type
464 = sh64_get_contents_type (info
->section
, memaddr
,
465 &sh64_infop
->crange
);
467 if (cr_type
!= CRT_NONE
)
471 /* If we have symbols, we can try and get at a section from *that*. */
472 if (info
->symbols
!= NULL
473 && bfd_asymbol_flavour (info
->symbols
[0]) == bfd_target_elf_flavour
474 && ! bfd_is_und_section (bfd_get_section (info
->symbols
[0]))
475 && ! bfd_is_abs_section (bfd_get_section (info
->symbols
[0])))
477 enum sh64_elf_cr_type cr_type
478 = sh64_get_contents_type (bfd_get_section (info
->symbols
[0]),
479 memaddr
, &sh64_infop
->crange
);
481 if (cr_type
!= CRT_NONE
)
485 /* We can make a reasonable guess based on the st_other field of a
486 symbol; for a BranchTarget this is marked as STO_SH5_ISA32 and then
487 it's most probably code there. */
489 && bfd_asymbol_flavour (info
->symbols
[0]) == bfd_target_elf_flavour
490 && elf_symbol_from (bfd_asymbol_bfd (info
->symbols
[0]),
491 info
->symbols
[0])->internal_elf_sym
.st_other
493 return CRT_SH5_ISA32
;
495 /* If all else fails, guess this is code and guess on the low bit set. */
496 return (memaddr
& 1) == 1 ? CRT_SH5_ISA32
: CRT_SH5_ISA16
;
499 /* Initialize static and dynamic disassembly state. */
502 init_sh64_disasm_info (struct disassemble_info
*info
)
504 struct sh64_disassemble_info
*sh64_infop
505 = calloc (sizeof (*sh64_infop
), 1);
507 if (sh64_infop
== NULL
)
510 info
->private_data
= sh64_infop
;
512 SAVED_MOVI_IMM (info
) = 0;
513 SAVED_MOVI_R (info
) = 255;
515 if (shmedia_opcode_mask_table
== NULL
)
516 initialize_shmedia_opcode_mask_table ();
521 /* Main entry to disassemble SHmedia instructions, given an endian set in
522 INFO. Note that the simulator uses this as the main entry and does not
523 use any of the functions further below. */
526 print_insn_sh64x_media (bfd_vma memaddr
, struct disassemble_info
*info
)
528 if (info
->private_data
== NULL
&& ! init_sh64_disasm_info (info
))
531 /* Make reasonable output. */
532 info
->bytes_per_line
= 4;
533 info
->bytes_per_chunk
= 4;
535 return print_insn_shmedia (memaddr
, info
);
538 /* Main entry to disassemble SHmedia insns.
539 If we see an SHcompact instruction, return -2. */
542 print_insn_sh64 (bfd_vma memaddr
, struct disassemble_info
*info
)
544 enum bfd_endian endian
= info
->endian
;
545 enum sh64_elf_cr_type cr_type
;
547 if (info
->private_data
== NULL
&& ! init_sh64_disasm_info (info
))
550 cr_type
= sh64_get_contents_type_disasm (memaddr
, info
);
551 if (cr_type
!= CRT_SH5_ISA16
)
553 int length
= 4 - (memaddr
% 4);
554 info
->display_endian
= endian
;
556 /* If we got an uneven address to indicate SHmedia, adjust it. */
557 if (cr_type
== CRT_SH5_ISA32
&& length
== 3)
558 memaddr
--, length
= 4;
560 /* Only disassemble on four-byte boundaries. Addresses that are not
561 a multiple of four can happen after a data region. */
562 if (cr_type
== CRT_SH5_ISA32
&& length
== 4)
563 return print_insn_sh64x_media (memaddr
, info
);
565 /* We get CRT_DATA *only* for data regions in a mixed-contents
566 section. For sections with data only, we get indication of one
567 of the ISA:s. You may think that we shouldn't disassemble
568 section with only data if we can figure that out. However, the
569 disassembly function is by default not called for data-only
570 sections, so if the user explicitly specified disassembly of a
571 data section, that's what we should do. */
572 if (cr_type
== CRT_DATA
|| length
!= 4)
575 unsigned char data
[4];
576 struct sh64_disassemble_info
*sh64_infop
= info
->private_data
;
579 && sh64_infop
->crange
.cr_type
!= CRT_NONE
580 && memaddr
>= sh64_infop
->crange
.cr_addr
581 && memaddr
< (sh64_infop
->crange
.cr_addr
582 + sh64_infop
->crange
.cr_size
))
584 = (sh64_infop
->crange
.cr_addr
585 + sh64_infop
->crange
.cr_size
- memaddr
);
588 = (*info
->read_memory_func
) (memaddr
, data
,
589 length
>= 4 ? 4 : length
, info
);
591 if (status
== 0 && length
>= 4)
593 (*info
->fprintf_func
) (info
->stream
, ".long 0x%08lx",
594 endian
== BFD_ENDIAN_BIG
595 ? (long) (bfd_getb32 (data
))
596 : (long) (bfd_getl32 (data
)));
603 for (i
= 0; i
< length
; i
++)
605 status
= info
->read_memory_func (memaddr
+ i
, data
, 1, info
);
608 (*info
->fprintf_func
) (info
->stream
, "%s0x%02x",
609 i
== 0 ? ".byte " : ", ",
618 /* SH1 .. SH4 instruction, let caller handle it. */