d28847ce8e
2001-10-08 Nick Clifton <nickc@cambridge.redhat.com> * sh64-opc.c: Regenerate. 2001-03-13 DJ Delorie <dj@redhat.com> * sh64-opc.h: Rename A_RESV_Fx to A_REUSE_PREV so that its purpose is more obvious. * sh64-opc.c (shmedia_table): Ditto. * sh64-dis.c (initialize_shmedia_opcode_mask_table): Ditto. (print_insn_shmedia): Ditto. 2001-03-12 DJ Delorie <dj@redhat.com> * sh64-opc.c: Adjust comments to reflect reality: replace bits 3:0 with zeros (not "reserved"), replace "rrrrrr" with "gggggg" for two-operand floating point opcodes. Remove "fsina". 2001-01-08 Hans-Peter Nilsson <hpn@cygnus.com> * sh64-dis.c (print_insn_shmedia) <failing read_memory_func>: Correct printing of .byte:s. Return number of printed bytes or -1; never 0. (print_insn_sh64x) <not CRT_SH5_ISA16>: Ditto. Print as .byte:s to next four-byte-alignment if insn or data is not aligned. 2001-01-06 Hans-Peter Nilsson <hpn@cygnus.com> * sh64-dis.c: Update comments and fix comment formatting. (initialize_shmedia_opcode_mask_table) <case A_IMMM>: Abort instead of setting length to 0. (crange_qsort_cmpb, crange_qsort_cmpl, crange_bsearch_cmpb, crange_bsearch_cmpl, sh64_get_contents_type, sh64_address_in_cranges): Move to bfd/elf32-sh64.c. 2001-01-05 Hans-Peter Nilsson <hpn@cygnus.com> * sh64-opc.c: Remove #if 0:d entries for instructions not found in SH-5/ST50-023-04: fcosa.s, fsrra.s and prefo. 2000-12-30 Hans-Peter Nilsson <hpn@cygnus.com> * sh64-dis.c (print_insn_shmedia): Display MOVI/SHORI-formed address with same prefix as SHcompact. In the disassembler, use a .cranges section for linked executables. * sh64-dis.c (SAVED_MOVI_R, SAVED_MOVI_IMM): Move to head of file and update for using structure in info->private_data. (struct sh64_disassemble_info): New. (is_shmedia_p): Delete. (crange_qsort_cmpb): New function. (crange_qsort_cmpl, crange_bsearch_cmpb): New functions. (crange_bsearch_cmpl, sh64_address_in_cranges): New functions. (init_sh64_disasm_info, sh64_get_contents_type_disasm): New functions. (sh64_get_contents_type, sh64_address_is_shmedia): New functions. (print_insn_shmedia): Correct displaying of address after MOVI/SHORI pair. Display addresses for linked executables only. (print_insn_sh64x_media): Initialize info->private_data by calling init_sh64_disasm_info. (print_insn_sh64x): Ditto. Find out type of contents by calling sh64_contents_type_disasm. Display data regions using ".long" and ".byte" similar to unrecognized opcodes. 2000-12-19 Hans-Peter Nilsson <hpn@cygnus.com> * sh64-dis.c (is_shmedia_p): Check info->section and look for ISA information in section flags before considering symbols. Don't assume an info->mach setting of bfd_mach_sh5 means SHmedia code. * configure.in (bfd_sh_arch): Check presence of sh64 insns by matching $target $canon_targets instead of looking at the now-removed -DINCLUDE_SHMEDIA in $targ_cflags. * configure: Regenerate. 2000-11-25 Hans-Peter Nilsson <hpn@cygnus.com> * sh64-opc.c (shmedia_creg_table): New. * sh64-opc.h (shmedia_creg_info): New type. (shmedia_creg_table): Declare. * sh64-dis.c (creg_name): New function. (print_insn_shmedia): Use it. * disassemble.c (disassembler) [ARCH_sh, INCLUDE_SHMEDIA]: Map bfd_mach_sh5 to print_insn_sh64 if big-endian and to print_insn_sh64l if little-endian. * sh64-dis.c (print_insn_shmedia): Make r unsigned. (print_insn_sh64l): New. (print_insn_sh64x): New. (print_insn_sh64x_media): New. (print_insn_sh64): Break out code to print_insn_sh64x and print_insn_sh64x_media. 2000-11-24 Hans-Peter Nilsson <hpn@cygnus.com> * sh64-opc.h: New file * sh64-opc.c: New file * sh64-dis.c: New file * Makefile.am: Add sh64 targets. (HFILES): Add sh64-opc.h. (CFILES): Add sh64-opc.c and sh64-dis.c. (ALL_MACHINES): Add sh64 files. * Makefile.in: Regenerate. * configure.in: Add support for sh64 to bfd_sh_arch. * configure: Regenerate. * disassemble.c [ARCH_all] (INCLUDE_SHMEDIA): Define. (disassembler) [ARCH_sh, INCLUDE_SHMEDIA]: Map bfd_mach_sh5 to print_insn_sh64. * sh-dis.c (print_insn_shx): Handle bfd_mach_sh5 as arch_sh4. * po/POTFILES.in: Regenerate. * po/opcodes.pot: Regenerate.
660 lines
17 KiB
C
660 lines
17 KiB
C
/* Disassemble SH64 instructions.
|
|
Copyright (C) 2000, 2001 Free Software Foundation, Inc.
|
|
|
|
This program 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 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program 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 program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "dis-asm.h"
|
|
#include "sysdep.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"
|
|
|
|
#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;
|
|
|
|
static void initialize_shmedia_opcode_mask_table PARAMS ((void));
|
|
static int print_insn_shmedia PARAMS ((bfd_vma, disassemble_info *));
|
|
static int print_insn_sh64x
|
|
PARAMS ((bfd_vma, disassemble_info *,
|
|
int (*) PARAMS ((bfd_vma, struct disassemble_info *)),
|
|
enum bfd_endian));
|
|
static const char *creg_name PARAMS ((int));
|
|
static boolean init_sh64_disasm_info PARAMS ((struct disassemble_info *));
|
|
static enum sh64_elf_cr_type sh64_get_contents_type_disasm
|
|
PARAMS ((bfd_vma, struct disassemble_info *));
|
|
|
|
/* Initialize the SH64 opcode mask table for each instruction in SHmedia
|
|
mode. */
|
|
|
|
static void
|
|
initialize_shmedia_opcode_mask_table ()
|
|
{
|
|
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. */
|
|
|
|
const char *
|
|
creg_name (cregno)
|
|
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 (memaddr, info)
|
|
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)
|
|
{
|
|
int i;
|
|
|
|
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%08x", 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, "%d", 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, "%d", 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, "%d", 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, "%d", 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, "%d", imm);
|
|
break;
|
|
|
|
/* An unsigned 6-bit number. */
|
|
case A_IMMU6:
|
|
imm = temp & 0x3f;
|
|
fprintf_fn (stream, "%d", imm);
|
|
break;
|
|
|
|
/* An unsigned 16-bit number. */
|
|
case A_IMMU16:
|
|
imm = temp & 0xffff;
|
|
fprintf_fn (stream, "%d", 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 (memaddr, info)
|
|
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 boolean
|
|
init_sh64_disasm_info (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 (memaddr, info)
|
|
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 SHcompact or SHmedia insns. */
|
|
|
|
static int
|
|
print_insn_sh64x (memaddr, info, pfun_compact, endian)
|
|
bfd_vma memaddr;
|
|
struct disassemble_info *info;
|
|
int (*pfun_compact) PARAMS ((bfd_vma, struct disassemble_info *));
|
|
enum bfd_endian 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;
|
|
|
|
/* 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
return (*pfun_compact) (memaddr, info);
|
|
}
|
|
|
|
/* Main entry to disassemble SHcompact or SHmedia insns, big endian. */
|
|
|
|
int
|
|
print_insn_sh64 (memaddr, info)
|
|
bfd_vma memaddr;
|
|
struct disassemble_info *info;
|
|
{
|
|
return
|
|
print_insn_sh64x (memaddr, info, print_insn_sh, BFD_ENDIAN_BIG);
|
|
}
|
|
|
|
/* Main entry to disassemble SHcompact or SHmedia insns, little endian. */
|
|
|
|
int
|
|
print_insn_sh64l (memaddr, info)
|
|
bfd_vma memaddr;
|
|
struct disassemble_info *info;
|
|
{
|
|
return
|
|
print_insn_sh64x (memaddr, info, print_insn_shl, BFD_ENDIAN_LITTLE);
|
|
}
|