aboutsummaryrefslogtreecommitdiff
path: root/opcodes/sh64-dis.c
diff options
context:
space:
mode:
Diffstat (limited to 'opcodes/sh64-dis.c')
-rw-r--r--opcodes/sh64-dis.c619
1 files changed, 0 insertions, 619 deletions
diff --git a/opcodes/sh64-dis.c b/opcodes/sh64-dis.c
deleted file mode 100644
index 7d511aa..0000000
--- a/opcodes/sh64-dis.c
+++ /dev/null
@@ -1,619 +0,0 @@
-/* Disassemble SH64 instructions.
- Copyright (C) 2000-2018 Free Software Foundation, Inc.
-
- This file is part of the GNU opcodes library.
-
- This library is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3, or (at your option)
- any later version.
-
- It is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
- License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this file; see the file COPYING. If not, write to the
- Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
- MA 02110-1301, USA. */
-
-#include "sysdep.h"
-#include <stdio.h>
-#include "disassemble.h"
-#include "sh64-opc.h"
-#include "libiberty.h"
-/* We need to refer to the ELF header structure. */
-#include "elf-bfd.h"
-#include "elf/sh.h"
-#include "elf32-sh64.h"
-
-#define ELF_MODE32_CODE_LABEL_P(SYM) \
- (((elf_symbol_type *) (SYM))->internal_elf_sym.st_other & STO_SH5_ISA32)
-
-#define SAVED_MOVI_R(INFO) \
- (((struct sh64_disassemble_info *) ((INFO)->private_data))->address_reg)
-
-#define SAVED_MOVI_IMM(INFO) \
- (((struct sh64_disassemble_info *) ((INFO)->private_data))->built_address)
-
-struct sh64_disassemble_info
- {
- /* When we see a MOVI, we save the register and the value, and merge a
- subsequent SHORI and display the address, if there is one. */
- unsigned int address_reg;
- bfd_signed_vma built_address;
-
- /* This is the range decriptor for the current address. It is kept
- around for the next call. */
- sh64_elf_crange crange;
- };
-
-/* Each item in the table is a mask to indicate which bits to be set
- to determine an instruction's operator.
- The index is as same as the instruction in the opcode table.
- Note that some archs have this as a field in the opcode table. */
-static unsigned long *shmedia_opcode_mask_table;
-
-/* Initialize the SH64 opcode mask table for each instruction in SHmedia
- mode. */
-
-static void
-initialize_shmedia_opcode_mask_table (void)
-{
- int n_opc;
- int n;
-
- /* Calculate number of opcodes. */
- for (n_opc = 0; shmedia_table[n_opc].name != NULL; n_opc++)
- ;
-
- shmedia_opcode_mask_table
- = xmalloc (sizeof (shmedia_opcode_mask_table[0]) * n_opc);
-
- for (n = 0; n < n_opc; n++)
- {
- int i;
-
- unsigned long mask = 0;
-
- for (i = 0; shmedia_table[n].arg[i] != A_NONE; i++)
- {
- int offset = shmedia_table[n].nibbles[i];
- int length;
-
- switch (shmedia_table[n].arg[i])
- {
- case A_GREG_M:
- case A_GREG_N:
- case A_GREG_D:
- case A_CREG_K:
- case A_CREG_J:
- case A_FREG_G:
- case A_FREG_H:
- case A_FREG_F:
- case A_DREG_G:
- case A_DREG_H:
- case A_DREG_F:
- case A_FMREG_G:
- case A_FMREG_H:
- case A_FMREG_F:
- case A_FPREG_G:
- case A_FPREG_H:
- case A_FPREG_F:
- case A_FVREG_G:
- case A_FVREG_H:
- case A_FVREG_F:
- case A_REUSE_PREV:
- length = 6;
- break;
-
- case A_TREG_A:
- case A_TREG_B:
- length = 3;
- break;
-
- case A_IMMM:
- abort ();
- break;
-
- case A_IMMU5:
- length = 5;
- break;
-
- case A_IMMS6:
- case A_IMMU6:
- case A_IMMS6BY32:
- length = 6;
- break;
-
- case A_IMMS10:
- case A_IMMS10BY1:
- case A_IMMS10BY2:
- case A_IMMS10BY4:
- case A_IMMS10BY8:
- length = 10;
- break;
-
- case A_IMMU16:
- case A_IMMS16:
- case A_PCIMMS16BY4:
- case A_PCIMMS16BY4_PT:
- length = 16;
- break;
-
- default:
- abort ();
- length = 0;
- break;
- }
-
- if (length != 0)
- mask |= (0xffffffff >> (32 - length)) << offset;
- }
- shmedia_opcode_mask_table[n] = 0xffffffff & ~mask;
- }
-}
-
-/* Get a predefined control-register-name, or return NULL. */
-
-static const char *
-creg_name (int cregno)
-{
- const shmedia_creg_info *cregp;
-
- /* If control register usage is common enough, change this to search a
- hash-table. */
- for (cregp = shmedia_creg_table; cregp->name != NULL; cregp++)
- if (cregp->cregno == cregno)
- return cregp->name;
-
- return NULL;
-}
-
-/* Main function to disassemble SHmedia instructions. */
-
-static int
-print_insn_shmedia (bfd_vma memaddr, struct disassemble_info *info)
-{
- fprintf_ftype fprintf_fn = info->fprintf_func;
- void *stream = info->stream;
- unsigned char insn[4];
- unsigned long instruction;
- int status;
- int n;
- const shmedia_opcode_info *op;
- int i;
- unsigned int r = 0;
- long imm = 0;
- bfd_vma disp_pc_addr;
-
- status = info->read_memory_func (memaddr, insn, 4, info);
-
- /* If we can't read four bytes, something is wrong. Display any data we
- can get as .byte:s. */
- if (status != 0)
- {
- for (i = 0; i < 3; i++)
- {
- status = info->read_memory_func (memaddr + i, insn, 1, info);
- if (status != 0)
- break;
- (*fprintf_fn) (stream, "%s0x%02x",
- i == 0 ? ".byte " : ", ",
- insn[0]);
- }
-
- return i ? i : -1;
- }
-
- /* Rearrange the bytes to make up an instruction. */
- if (info->endian == BFD_ENDIAN_LITTLE)
- instruction = bfd_getl32 (insn);
- else
- instruction = bfd_getb32 (insn);
-
- /* FIXME: Searching could be implemented using a hash on relevant
- fields. */
- for (n = 0, op = shmedia_table;
- op->name != NULL
- && ((instruction & shmedia_opcode_mask_table[n]) != op->opcode_base);
- n++, op++)
- ;
-
- /* FIXME: We should also check register number constraints. */
- if (op->name == NULL)
- {
- fprintf_fn (stream, ".long 0x%08lx", instruction);
- return 4;
- }
-
- fprintf_fn (stream, "%s\t", op->name);
-
- for (i = 0; i < 3 && op->arg[i] != A_NONE; i++)
- {
- unsigned long temp = instruction >> op->nibbles[i];
- int by_number = 0;
-
- if (i > 0 && op->arg[i] != A_REUSE_PREV)
- fprintf_fn (stream, ",");
-
- switch (op->arg[i])
- {
- case A_REUSE_PREV:
- continue;
-
- case A_GREG_M:
- case A_GREG_N:
- case A_GREG_D:
- r = temp & 0x3f;
- fprintf_fn (stream, "r%d", r);
- break;
-
- case A_FVREG_F:
- case A_FVREG_G:
- case A_FVREG_H:
- r = temp & 0x3f;
- fprintf_fn (stream, "fv%d", r);
- break;
-
- case A_FPREG_F:
- case A_FPREG_G:
- case A_FPREG_H:
- r = temp & 0x3f;
- fprintf_fn (stream, "fp%d", r);
- break;
-
- case A_FMREG_F:
- case A_FMREG_G:
- case A_FMREG_H:
- r = temp & 0x3f;
- fprintf_fn (stream, "mtrx%d", r);
- break;
-
- case A_CREG_K:
- case A_CREG_J:
- {
- const char *name;
-
- r = temp & 0x3f;
-
- name = creg_name (r);
-
- if (name != NULL)
- fprintf_fn (stream, "%s", name);
- else
- fprintf_fn (stream, "cr%d", r);
- }
- break;
-
- case A_FREG_G:
- case A_FREG_H:
- case A_FREG_F:
- r = temp & 0x3f;
- fprintf_fn (stream, "fr%d", r);
- break;
-
- case A_DREG_G:
- case A_DREG_H:
- case A_DREG_F:
- r = temp & 0x3f;
- fprintf_fn (stream, "dr%d", r);
- break;
-
- case A_TREG_A:
- case A_TREG_B:
- r = temp & 0x7;
- fprintf_fn (stream, "tr%d", r);
- break;
-
- /* A signed 6-bit number. */
- case A_IMMS6:
- imm = temp & 0x3f;
- if (imm & (unsigned long) 0x20)
- imm |= ~(unsigned long) 0x3f;
- fprintf_fn (stream, "%ld", imm);
- break;
-
- /* A signed 6-bit number, multiplied by 32 when used. */
- case A_IMMS6BY32:
- imm = temp & 0x3f;
- if (imm & (unsigned long) 0x20)
- imm |= ~(unsigned long) 0x3f;
- fprintf_fn (stream, "%ld", imm * 32);
- break;
-
- /* A signed 10-bit number, multiplied by 8 when used. */
- case A_IMMS10BY8:
- by_number++;
- /* Fall through. */
-
- /* A signed 10-bit number, multiplied by 4 when used. */
- case A_IMMS10BY4:
- by_number++;
- /* Fall through. */
-
- /* A signed 10-bit number, multiplied by 2 when used. */
- case A_IMMS10BY2:
- by_number++;
- /* Fall through. */
-
- /* A signed 10-bit number. */
- case A_IMMS10:
- case A_IMMS10BY1:
- imm = temp & 0x3ff;
- if (imm & (unsigned long) 0x200)
- imm |= ~(unsigned long) 0x3ff;
- imm <<= by_number;
- fprintf_fn (stream, "%ld", imm);
- break;
-
- /* A signed 16-bit number. */
- case A_IMMS16:
- imm = temp & 0xffff;
- if (imm & (unsigned long) 0x8000)
- imm |= ~((unsigned long) 0xffff);
- fprintf_fn (stream, "%ld", imm);
- break;
-
- /* A PC-relative signed 16-bit number, multiplied by 4 when
- used. */
- case A_PCIMMS16BY4:
- imm = temp & 0xffff; /* 16 bits */
- if (imm & (unsigned long) 0x8000)
- imm |= ~(unsigned long) 0xffff;
- imm <<= 2;
- disp_pc_addr = (bfd_vma) imm + memaddr;
- (*info->print_address_func) (disp_pc_addr, info);
- break;
-
- /* An unsigned 5-bit number. */
- case A_IMMU5:
- imm = temp & 0x1f;
- fprintf_fn (stream, "%ld", imm);
- break;
-
- /* An unsigned 6-bit number. */
- case A_IMMU6:
- imm = temp & 0x3f;
- fprintf_fn (stream, "%ld", imm);
- break;
-
- /* An unsigned 16-bit number. */
- case A_IMMU16:
- imm = temp & 0xffff;
- fprintf_fn (stream, "%ld", imm);
- break;
-
- default:
- abort ();
- break;
- }
- }
-
- /* FIXME: Looks like 32-bit values only are handled.
- FIXME: PC-relative numbers aren't handled correctly. */
- if (op->opcode_base == (unsigned long) SHMEDIA_SHORI_OPC
- && SAVED_MOVI_R (info) == r)
- {
- asection *section = info->section;
-
- /* Most callers do not set the section field correctly yet. Revert
- to getting the section from symbols, if any. */
- if (section == NULL
- && info->symbols != NULL
- && bfd_asymbol_flavour (info->symbols[0]) == bfd_target_elf_flavour
- && ! bfd_is_und_section (bfd_get_section (info->symbols[0]))
- && ! bfd_is_abs_section (bfd_get_section (info->symbols[0])))
- section = bfd_get_section (info->symbols[0]);
-
- /* Only guess addresses when the contents of this section is fully
- relocated. Otherwise, the value will be zero or perhaps even
- bogus. */
- if (section == NULL
- || section->owner == NULL
- || elf_elfheader (section->owner)->e_type == ET_EXEC)
- {
- bfd_signed_vma shori_addr;
-
- shori_addr = SAVED_MOVI_IMM (info) << 16;
- shori_addr |= imm;
-
- fprintf_fn (stream, "\t! 0x");
- (*info->print_address_func) (shori_addr, info);
- }
- }
-
- if (op->opcode_base == SHMEDIA_MOVI_OPC)
- {
- SAVED_MOVI_IMM (info) = imm;
- SAVED_MOVI_R (info) = r;
- }
- else
- {
- SAVED_MOVI_IMM (info) = 0;
- SAVED_MOVI_R (info) = 255;
- }
-
- return 4;
-}
-
-/* Check the type of contents about to be disassembled. This is like
- sh64_get_contents_type (which may be called from here), except that it
- takes the same arguments as print_insn_* and does what can be done if
- no section is available. */
-
-static enum sh64_elf_cr_type
-sh64_get_contents_type_disasm (bfd_vma memaddr, struct disassemble_info *info)
-{
- struct sh64_disassemble_info *sh64_infop = info->private_data;
-
- /* Perhaps we have a region from a previous probe and it still counts
- for this address? */
- if (sh64_infop->crange.cr_type != CRT_NONE
- && memaddr >= sh64_infop->crange.cr_addr
- && memaddr < sh64_infop->crange.cr_addr + sh64_infop->crange.cr_size)
- return sh64_infop->crange.cr_type;
-
- /* If we have a section, try and use it. */
- if (info->section
- && bfd_get_flavour (info->section->owner) == bfd_target_elf_flavour)
- {
- enum sh64_elf_cr_type cr_type
- = sh64_get_contents_type (info->section, memaddr,
- &sh64_infop->crange);
-
- if (cr_type != CRT_NONE)
- return cr_type;
- }
-
- /* If we have symbols, we can try and get at a section from *that*. */
- if (info->symbols != NULL
- && bfd_asymbol_flavour (info->symbols[0]) == bfd_target_elf_flavour
- && ! bfd_is_und_section (bfd_get_section (info->symbols[0]))
- && ! bfd_is_abs_section (bfd_get_section (info->symbols[0])))
- {
- enum sh64_elf_cr_type cr_type
- = sh64_get_contents_type (bfd_get_section (info->symbols[0]),
- memaddr, &sh64_infop->crange);
-
- if (cr_type != CRT_NONE)
- return cr_type;
- }
-
- /* We can make a reasonable guess based on the st_other field of a
- symbol; for a BranchTarget this is marked as STO_SH5_ISA32 and then
- it's most probably code there. */
- if (info->symbols
- && bfd_asymbol_flavour (info->symbols[0]) == bfd_target_elf_flavour
- && elf_symbol_from (bfd_asymbol_bfd (info->symbols[0]),
- info->symbols[0])->internal_elf_sym.st_other
- == STO_SH5_ISA32)
- return CRT_SH5_ISA32;
-
- /* If all else fails, guess this is code and guess on the low bit set. */
- return (memaddr & 1) == 1 ? CRT_SH5_ISA32 : CRT_SH5_ISA16;
-}
-
-/* Initialize static and dynamic disassembly state. */
-
-static bfd_boolean
-init_sh64_disasm_info (struct disassemble_info *info)
-{
- struct sh64_disassemble_info *sh64_infop
- = calloc (sizeof (*sh64_infop), 1);
-
- if (sh64_infop == NULL)
- return FALSE;
-
- info->private_data = sh64_infop;
-
- SAVED_MOVI_IMM (info) = 0;
- SAVED_MOVI_R (info) = 255;
-
- if (shmedia_opcode_mask_table == NULL)
- initialize_shmedia_opcode_mask_table ();
-
- return TRUE;
-}
-
-/* Main entry to disassemble SHmedia instructions, given an endian set in
- INFO. Note that the simulator uses this as the main entry and does not
- use any of the functions further below. */
-
-int
-print_insn_sh64x_media (bfd_vma memaddr, struct disassemble_info *info)
-{
- if (info->private_data == NULL && ! init_sh64_disasm_info (info))
- return -1;
-
- /* Make reasonable output. */
- info->bytes_per_line = 4;
- info->bytes_per_chunk = 4;
-
- return print_insn_shmedia (memaddr, info);
-}
-
-/* Main entry to disassemble SHmedia insns.
- If we see an SHcompact instruction, return -2. */
-
-int
-print_insn_sh64 (bfd_vma memaddr, struct disassemble_info *info)
-{
- enum bfd_endian endian = info->endian;
- enum sh64_elf_cr_type cr_type;
-
- if (info->private_data == NULL && ! init_sh64_disasm_info (info))
- return -1;
-
- cr_type = sh64_get_contents_type_disasm (memaddr, info);
- if (cr_type != CRT_SH5_ISA16)
- {
- int length = 4 - (memaddr % 4);
- info->display_endian = endian;
-
- /* If we got an uneven address to indicate SHmedia, adjust it. */
- if (cr_type == CRT_SH5_ISA32 && length == 3)
- memaddr--, length = 4;
-
- /* Only disassemble on four-byte boundaries. Addresses that are not
- a multiple of four can happen after a data region. */
- if (cr_type == CRT_SH5_ISA32 && length == 4)
- return print_insn_sh64x_media (memaddr, info);
-
- /* We get CRT_DATA *only* for data regions in a mixed-contents
- section. For sections with data only, we get indication of one
- of the ISA:s. You may think that we shouldn't disassemble
- section with only data if we can figure that out. However, the
- disassembly function is by default not called for data-only
- sections, so if the user explicitly specified disassembly of a
- data section, that's what we should do. */
- if (cr_type == CRT_DATA || length != 4)
- {
- int status;
- unsigned char data[4];
- struct sh64_disassemble_info *sh64_infop = info->private_data;
-
- if (length == 4
- && sh64_infop->crange.cr_type != CRT_NONE
- && memaddr >= sh64_infop->crange.cr_addr
- && memaddr < (sh64_infop->crange.cr_addr
- + sh64_infop->crange.cr_size))
- length
- = (sh64_infop->crange.cr_addr
- + sh64_infop->crange.cr_size - memaddr);
-
- status
- = (*info->read_memory_func) (memaddr, data,
- length >= 4 ? 4 : length, info);
-
- if (status == 0 && length >= 4)
- {
- (*info->fprintf_func) (info->stream, ".long 0x%08lx",
- endian == BFD_ENDIAN_BIG
- ? (long) (bfd_getb32 (data))
- : (long) (bfd_getl32 (data)));
- return 4;
- }
- else
- {
- int i;
-
- for (i = 0; i < length; i++)
- {
- status = info->read_memory_func (memaddr + i, data, 1, info);
- if (status != 0)
- break;
- (*info->fprintf_func) (info->stream, "%s0x%02x",
- i == 0 ? ".byte " : ", ",
- data[0]);
- }
-
- return i ? i : -1;
- }
- }
- }
-
- /* SH1 .. SH4 instruction, let caller handle it. */
- return -2;
-}