diff options
Diffstat (limited to 'opcodes/sh64-dis.c')
-rw-r--r-- | opcodes/sh64-dis.c | 619 |
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; -} |