Back to index

cell-binutils  2.17cvs20070401
Classes | Defines | Functions | Variables
sh64-dis.c File Reference
#include <stdio.h>
#include "dis-asm.h"
#include "sysdep.h"
#include "sh64-opc.h"
#include "libiberty.h"
#include "elf-bfd.h"
#include "elf/sh.h"
#include "elf32-sh64.h"

Go to the source code of this file.

Classes

struct  sh64_disassemble_info

Defines

#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)

Functions

static void initialize_shmedia_opcode_mask_table (void)
static const char * creg_name (int cregno)
static int print_insn_shmedia (bfd_vma memaddr, struct disassemble_info *info)
static enum sh64_elf_cr_type sh64_get_contents_type_disasm (bfd_vma memaddr, struct disassemble_info *info)
static bfd_boolean init_sh64_disasm_info (struct disassemble_info *info)
int print_insn_sh64x_media (bfd_vma memaddr, struct disassemble_info *info)
int print_insn_sh64 (bfd_vma memaddr, struct disassemble_info *info)

Variables

static unsigned longshmedia_opcode_mask_table

Class Documentation

struct sh64_disassemble_info

Definition at line 38 of file sh64-dis.c.

Collaboration diagram for sh64_disassemble_info:
Class Members
unsigned int address_reg
bfd_signed_vma built_address
sh64_elf_crange crange

Define Documentation

#define ELF_MODE32_CODE_LABEL_P (   SYM)    (((elf_symbol_type *) (SYM))->internal_elf_sym.st_other & STO_SH5_ISA32)

Definition at line 29 of file sh64-dis.c.

#define SAVED_MOVI_IMM (   INFO)    (((struct sh64_disassemble_info *) ((INFO)->private_data))->built_address)

Definition at line 35 of file sh64-dis.c.

#define SAVED_MOVI_R (   INFO)    (((struct sh64_disassemble_info *) ((INFO)->private_data))->address_reg)

Definition at line 32 of file sh64-dis.c.


Function Documentation

static const char* creg_name ( int  cregno) [static]

Definition at line 159 of file sh64-dis.c.

{
  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;
}

Here is the caller graph for this function:

Definition at line 501 of file sh64-dis.c.

{
  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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void initialize_shmedia_opcode_mask_table ( void  ) [static]

Definition at line 60 of file sh64-dis.c.

{
  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;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

int print_insn_sh64 ( bfd_vma  memaddr,
struct disassemble_info info 
)

Definition at line 541 of file sh64-dis.c.

{
  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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 525 of file sh64-dis.c.

{
  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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int print_insn_shmedia ( bfd_vma  memaddr,
struct disassemble_info info 
) [static]

Definition at line 175 of file sh64-dis.c.

{
  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%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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static enum sh64_elf_cr_type sh64_get_contents_type_disasm ( bfd_vma  memaddr,
struct disassemble_info info 
) [static]

Definition at line 447 of file sh64-dis.c.

{
  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;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

Definition at line 54 of file sh64-dis.c.