Back to index

cell-binutils  2.17cvs20070401
sh64-dis.c
Go to the documentation of this file.
00001 /* Disassemble SH64 instructions.
00002    Copyright 2000, 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
00003 
00004    This program is free software; you can redistribute it and/or modify
00005    it under the terms of the GNU General Public License as published by
00006    the Free Software Foundation; either version 2 of the License, or
00007    (at your option) any later version.
00008 
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012    GNU General Public License for more details.
00013 
00014    You should have received a copy of the GNU General Public License
00015    along with this program; if not, write to the Free Software
00016    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
00017 
00018 #include <stdio.h>
00019 
00020 #include "dis-asm.h"
00021 #include "sysdep.h"
00022 #include "sh64-opc.h"
00023 #include "libiberty.h"
00024 /* We need to refer to the ELF header structure.  */
00025 #include "elf-bfd.h"
00026 #include "elf/sh.h"
00027 #include "elf32-sh64.h"
00028 
00029 #define ELF_MODE32_CODE_LABEL_P(SYM) \
00030  (((elf_symbol_type *) (SYM))->internal_elf_sym.st_other & STO_SH5_ISA32)
00031 
00032 #define SAVED_MOVI_R(INFO) \
00033  (((struct sh64_disassemble_info *) ((INFO)->private_data))->address_reg)
00034 
00035 #define SAVED_MOVI_IMM(INFO) \
00036  (((struct sh64_disassemble_info *) ((INFO)->private_data))->built_address)
00037 
00038 struct sh64_disassemble_info
00039  {
00040    /* When we see a MOVI, we save the register and the value, and merge a
00041       subsequent SHORI and display the address, if there is one.  */
00042    unsigned int address_reg;
00043    bfd_signed_vma built_address;
00044 
00045    /* This is the range decriptor for the current address.  It is kept
00046       around for the next call.  */
00047    sh64_elf_crange crange;
00048  };
00049 
00050 /* Each item in the table is a mask to indicate which bits to be set
00051    to determine an instruction's operator.
00052    The index is as same as the instruction in the opcode table.
00053    Note that some archs have this as a field in the opcode table.  */
00054 static unsigned long *shmedia_opcode_mask_table;
00055 
00056 /* Initialize the SH64 opcode mask table for each instruction in SHmedia
00057    mode.  */
00058 
00059 static void
00060 initialize_shmedia_opcode_mask_table (void)
00061 {
00062   int n_opc;
00063   int n;
00064 
00065   /* Calculate number of opcodes.  */
00066   for (n_opc = 0; shmedia_table[n_opc].name != NULL; n_opc++)
00067     ;
00068 
00069   shmedia_opcode_mask_table
00070     = xmalloc (sizeof (shmedia_opcode_mask_table[0]) * n_opc);
00071 
00072   for (n = 0; n < n_opc; n++)
00073     {
00074       int i;
00075 
00076       unsigned long mask = 0;
00077 
00078       for (i = 0; shmedia_table[n].arg[i] != A_NONE; i++)
00079        {
00080          int offset = shmedia_table[n].nibbles[i];
00081          int length;
00082 
00083          switch (shmedia_table[n].arg[i])
00084            {
00085            case A_GREG_M:
00086            case A_GREG_N:
00087            case A_GREG_D:
00088            case A_CREG_K:
00089            case A_CREG_J:
00090            case A_FREG_G:
00091            case A_FREG_H:
00092            case A_FREG_F:
00093            case A_DREG_G:
00094            case A_DREG_H:
00095            case A_DREG_F:
00096            case A_FMREG_G:
00097            case A_FMREG_H:
00098            case A_FMREG_F:
00099            case A_FPREG_G:
00100            case A_FPREG_H:
00101            case A_FPREG_F:
00102            case A_FVREG_G:
00103            case A_FVREG_H:
00104            case A_FVREG_F:
00105            case A_REUSE_PREV:
00106              length = 6;
00107              break;
00108 
00109            case A_TREG_A:
00110            case A_TREG_B:
00111              length = 3;
00112              break;
00113 
00114            case A_IMMM:
00115              abort ();
00116              break;
00117 
00118            case A_IMMU5:
00119              length = 5;
00120              break;
00121 
00122            case A_IMMS6:
00123            case A_IMMU6:
00124            case A_IMMS6BY32:
00125              length = 6;
00126              break;
00127 
00128            case A_IMMS10:
00129            case A_IMMS10BY1:
00130            case A_IMMS10BY2:
00131            case A_IMMS10BY4:
00132            case A_IMMS10BY8:
00133              length = 10;
00134              break;
00135 
00136            case A_IMMU16:
00137            case A_IMMS16:
00138            case A_PCIMMS16BY4:
00139            case A_PCIMMS16BY4_PT:
00140              length = 16;
00141              break;
00142 
00143            default:
00144              abort ();
00145              length = 0;
00146              break;
00147            }
00148 
00149          if (length != 0)
00150            mask |= (0xffffffff >> (32 - length)) << offset;
00151        }
00152       shmedia_opcode_mask_table[n] = 0xffffffff & ~mask;
00153     }
00154 }
00155 
00156 /* Get a predefined control-register-name, or return NULL.  */
00157 
00158 static const char *
00159 creg_name (int cregno)
00160 {
00161   const shmedia_creg_info *cregp;
00162 
00163   /* If control register usage is common enough, change this to search a
00164      hash-table.  */
00165   for (cregp = shmedia_creg_table; cregp->name != NULL; cregp++)
00166     if (cregp->cregno == cregno)
00167       return cregp->name;
00168 
00169   return NULL;
00170 }
00171 
00172 /* Main function to disassemble SHmedia instructions.  */
00173 
00174 static int
00175 print_insn_shmedia (bfd_vma memaddr, struct disassemble_info *info)
00176 {
00177   fprintf_ftype fprintf_fn = info->fprintf_func;
00178   void *stream = info->stream;
00179   unsigned char insn[4];
00180   unsigned long instruction;
00181   int status;
00182   int n;
00183   const shmedia_opcode_info *op;
00184   int i;
00185   unsigned int r = 0;
00186   long imm = 0;
00187   bfd_vma disp_pc_addr;
00188 
00189   status = info->read_memory_func (memaddr, insn, 4, info);
00190 
00191   /* If we can't read four bytes, something is wrong.  Display any data we
00192      can get as .byte:s.  */
00193   if (status != 0)
00194     {
00195       int i;
00196 
00197       for (i = 0; i < 3; i++)
00198        {
00199          status = info->read_memory_func (memaddr + i, insn, 1, info);
00200          if (status != 0)
00201            break;
00202          (*fprintf_fn) (stream, "%s0x%02x",
00203                       i == 0 ? ".byte " : ", ",
00204                       insn[0]);
00205        }
00206 
00207       return i ? i : -1;
00208     }
00209 
00210   /* Rearrange the bytes to make up an instruction.  */
00211   if (info->endian == BFD_ENDIAN_LITTLE)
00212     instruction = bfd_getl32 (insn);
00213   else
00214     instruction = bfd_getb32 (insn);
00215 
00216   /* FIXME: Searching could be implemented using a hash on relevant
00217      fields.  */
00218   for (n = 0, op = shmedia_table;
00219        op->name != NULL
00220        && ((instruction & shmedia_opcode_mask_table[n]) != op->opcode_base);
00221        n++, op++)
00222     ;
00223 
00224   /* FIXME: We should also check register number constraints.  */
00225   if (op->name == NULL)
00226     {
00227       fprintf_fn (stream, ".long 0x%08lx", instruction);
00228       return 4;
00229     }
00230 
00231   fprintf_fn (stream, "%s\t", op->name);
00232 
00233   for (i = 0; i < 3 && op->arg[i] != A_NONE; i++)
00234     {
00235       unsigned long temp = instruction >> op->nibbles[i];
00236       int by_number = 0;
00237 
00238       if (i > 0 && op->arg[i] != A_REUSE_PREV)
00239        fprintf_fn (stream, ",");
00240 
00241       switch (op->arg[i])
00242        {
00243        case A_REUSE_PREV:
00244          continue;
00245 
00246        case A_GREG_M:
00247        case A_GREG_N:
00248        case A_GREG_D:
00249          r = temp & 0x3f;
00250          fprintf_fn (stream, "r%d", r);
00251          break;
00252 
00253        case A_FVREG_F:
00254        case A_FVREG_G:
00255        case A_FVREG_H:
00256          r = temp & 0x3f;
00257          fprintf_fn (stream, "fv%d", r);
00258          break;
00259 
00260        case A_FPREG_F:
00261        case A_FPREG_G:
00262        case A_FPREG_H:
00263          r = temp & 0x3f;
00264          fprintf_fn (stream, "fp%d", r);
00265          break;
00266 
00267        case A_FMREG_F:
00268        case A_FMREG_G:
00269        case A_FMREG_H:
00270          r = temp & 0x3f;
00271          fprintf_fn (stream, "mtrx%d", r);
00272          break;
00273 
00274        case A_CREG_K:
00275        case A_CREG_J:
00276          {
00277            const char *name;
00278 
00279            r = temp & 0x3f;
00280 
00281            name = creg_name (r);
00282 
00283            if (name != NULL)
00284              fprintf_fn (stream, "%s", name);
00285            else
00286              fprintf_fn (stream, "cr%d", r);
00287          }
00288          break;
00289 
00290        case A_FREG_G:
00291        case A_FREG_H:
00292        case A_FREG_F:
00293          r = temp & 0x3f;
00294          fprintf_fn (stream, "fr%d", r);
00295          break;
00296 
00297        case A_DREG_G:
00298        case A_DREG_H:
00299        case A_DREG_F:
00300          r = temp & 0x3f;
00301          fprintf_fn (stream, "dr%d", r);
00302          break;
00303 
00304        case A_TREG_A:
00305        case A_TREG_B:
00306          r = temp & 0x7;
00307          fprintf_fn (stream, "tr%d", r);
00308          break;
00309 
00310          /* A signed 6-bit number.  */
00311        case A_IMMS6:
00312          imm = temp & 0x3f;
00313          if (imm & (unsigned long) 0x20)
00314            imm |= ~(unsigned long) 0x3f;
00315          fprintf_fn (stream, "%ld", imm);
00316          break;
00317 
00318          /* A signed 6-bit number, multiplied by 32 when used.  */
00319        case A_IMMS6BY32:
00320          imm = temp & 0x3f;
00321          if (imm & (unsigned long) 0x20)
00322            imm |= ~(unsigned long) 0x3f;
00323          fprintf_fn (stream, "%ld", imm * 32);
00324          break;
00325 
00326          /* A signed 10-bit number, multiplied by 8 when used.  */
00327        case A_IMMS10BY8:
00328          by_number++;
00329          /* Fall through.  */
00330 
00331          /* A signed 10-bit number, multiplied by 4 when used.  */
00332        case A_IMMS10BY4:
00333          by_number++;
00334          /* Fall through.  */
00335 
00336          /* A signed 10-bit number, multiplied by 2 when used.  */
00337        case A_IMMS10BY2:
00338          by_number++;
00339          /* Fall through.  */
00340 
00341          /* A signed 10-bit number.  */
00342        case A_IMMS10:
00343        case A_IMMS10BY1:
00344          imm = temp & 0x3ff;
00345          if (imm & (unsigned long) 0x200)
00346            imm |= ~(unsigned long) 0x3ff;
00347          imm <<= by_number;
00348          fprintf_fn (stream, "%ld", imm);
00349          break;
00350 
00351          /* A signed 16-bit number.  */
00352        case A_IMMS16:
00353          imm = temp & 0xffff;
00354          if (imm & (unsigned long) 0x8000)
00355            imm |= ~((unsigned long) 0xffff);
00356          fprintf_fn (stream, "%ld", imm);
00357          break;
00358 
00359          /* A PC-relative signed 16-bit number, multiplied by 4 when
00360             used.  */
00361        case A_PCIMMS16BY4:
00362          imm = temp & 0xffff;      /* 16 bits */
00363          if (imm & (unsigned long) 0x8000)
00364            imm |= ~(unsigned long) 0xffff;
00365          imm <<= 2;
00366          disp_pc_addr = (bfd_vma) imm + memaddr;
00367          (*info->print_address_func) (disp_pc_addr, info);
00368          break;
00369 
00370          /* An unsigned 5-bit number.  */
00371        case A_IMMU5:
00372          imm = temp & 0x1f;
00373          fprintf_fn (stream, "%ld", imm);
00374          break;
00375 
00376          /* An unsigned 6-bit number.  */
00377        case A_IMMU6:
00378          imm = temp & 0x3f;
00379          fprintf_fn (stream, "%ld", imm);
00380          break;
00381 
00382          /* An unsigned 16-bit number.  */
00383        case A_IMMU16:
00384          imm = temp & 0xffff;
00385          fprintf_fn (stream, "%ld", imm);
00386          break;
00387 
00388        default:
00389          abort ();
00390          break;
00391        }
00392     }
00393 
00394   /* FIXME: Looks like 32-bit values only are handled.
00395      FIXME: PC-relative numbers aren't handled correctly.  */
00396   if (op->opcode_base == (unsigned long) SHMEDIA_SHORI_OPC
00397       && SAVED_MOVI_R (info) == r)
00398     {
00399       asection *section = info->section;
00400 
00401       /* Most callers do not set the section field correctly yet.  Revert
00402         to getting the section from symbols, if any. */
00403       if (section == NULL
00404          && info->symbols != NULL
00405          && bfd_asymbol_flavour (info->symbols[0]) == bfd_target_elf_flavour
00406          && ! bfd_is_und_section (bfd_get_section (info->symbols[0]))
00407          && ! bfd_is_abs_section (bfd_get_section (info->symbols[0])))
00408        section = bfd_get_section (info->symbols[0]);
00409 
00410       /* Only guess addresses when the contents of this section is fully
00411         relocated.  Otherwise, the value will be zero or perhaps even
00412         bogus.  */
00413       if (section == NULL
00414          || section->owner == NULL
00415          || elf_elfheader (section->owner)->e_type == ET_EXEC)
00416        {
00417          bfd_signed_vma shori_addr;
00418 
00419          shori_addr = SAVED_MOVI_IMM (info) << 16;
00420          shori_addr |= imm;
00421 
00422          fprintf_fn (stream, "\t! 0x");
00423          (*info->print_address_func) (shori_addr, info);
00424        }
00425     }
00426 
00427   if (op->opcode_base == SHMEDIA_MOVI_OPC)
00428     {
00429       SAVED_MOVI_IMM (info) = imm;
00430       SAVED_MOVI_R (info) = r;
00431     }
00432   else
00433     {
00434       SAVED_MOVI_IMM (info) = 0;
00435       SAVED_MOVI_R (info) = 255;
00436     }
00437 
00438   return 4;
00439 }
00440 
00441 /* Check the type of contents about to be disassembled.  This is like
00442    sh64_get_contents_type (which may be called from here), except that it
00443    takes the same arguments as print_insn_* and does what can be done if
00444    no section is available.  */
00445 
00446 static enum sh64_elf_cr_type
00447 sh64_get_contents_type_disasm (bfd_vma memaddr, struct disassemble_info *info)
00448 {
00449   struct sh64_disassemble_info *sh64_infop = info->private_data;
00450 
00451   /* Perhaps we have a region from a previous probe and it still counts
00452      for this address?  */
00453   if (sh64_infop->crange.cr_type != CRT_NONE
00454       && memaddr >= sh64_infop->crange.cr_addr
00455       && memaddr < sh64_infop->crange.cr_addr + sh64_infop->crange.cr_size)
00456     return sh64_infop->crange.cr_type;
00457 
00458   /* If we have a section, try and use it.  */
00459   if (info->section
00460       && bfd_get_flavour (info->section->owner) == bfd_target_elf_flavour)
00461     {
00462       enum sh64_elf_cr_type cr_type
00463        = sh64_get_contents_type (info->section, memaddr,
00464                               &sh64_infop->crange);
00465 
00466       if (cr_type != CRT_NONE)
00467        return cr_type;
00468     }
00469 
00470   /* If we have symbols, we can try and get at a section from *that*.  */
00471   if (info->symbols != NULL
00472       && bfd_asymbol_flavour (info->symbols[0]) == bfd_target_elf_flavour
00473       && ! bfd_is_und_section (bfd_get_section (info->symbols[0]))
00474       && ! bfd_is_abs_section (bfd_get_section (info->symbols[0])))
00475     {
00476       enum sh64_elf_cr_type cr_type
00477        = sh64_get_contents_type (bfd_get_section (info->symbols[0]),
00478                               memaddr, &sh64_infop->crange);
00479 
00480       if (cr_type != CRT_NONE)
00481        return cr_type;
00482     }
00483 
00484   /* We can make a reasonable guess based on the st_other field of a
00485      symbol; for a BranchTarget this is marked as STO_SH5_ISA32 and then
00486      it's most probably code there.  */
00487   if (info->symbols
00488       && bfd_asymbol_flavour (info->symbols[0]) == bfd_target_elf_flavour
00489       && elf_symbol_from (bfd_asymbol_bfd (info->symbols[0]),
00490                        info->symbols[0])->internal_elf_sym.st_other
00491       == STO_SH5_ISA32)
00492     return CRT_SH5_ISA32;
00493 
00494   /* If all else fails, guess this is code and guess on the low bit set.  */
00495   return (memaddr & 1) == 1 ? CRT_SH5_ISA32 : CRT_SH5_ISA16;
00496 }
00497 
00498 /* Initialize static and dynamic disassembly state.  */
00499 
00500 static bfd_boolean
00501 init_sh64_disasm_info (struct disassemble_info *info)
00502 {
00503   struct sh64_disassemble_info *sh64_infop
00504     = calloc (sizeof (*sh64_infop), 1);
00505 
00506   if (sh64_infop == NULL)
00507     return FALSE;
00508 
00509   info->private_data = sh64_infop;
00510 
00511   SAVED_MOVI_IMM (info) = 0;
00512   SAVED_MOVI_R (info) = 255;
00513 
00514   if (shmedia_opcode_mask_table == NULL)
00515     initialize_shmedia_opcode_mask_table ();
00516 
00517   return TRUE;
00518 }
00519 
00520 /* Main entry to disassemble SHmedia instructions, given an endian set in
00521    INFO.  Note that the simulator uses this as the main entry and does not
00522    use any of the functions further below.  */
00523 
00524 int
00525 print_insn_sh64x_media (bfd_vma memaddr, struct disassemble_info *info)
00526 {
00527   if (info->private_data == NULL && ! init_sh64_disasm_info (info))
00528     return -1;
00529 
00530   /* Make reasonable output.  */
00531   info->bytes_per_line = 4;
00532   info->bytes_per_chunk = 4;
00533 
00534   return print_insn_shmedia (memaddr, info);
00535 }
00536 
00537 /* Main entry to disassemble SHmedia insns.
00538    If we see an SHcompact instruction, return -2.  */
00539 
00540 int
00541 print_insn_sh64 (bfd_vma memaddr, struct disassemble_info *info)
00542 {
00543   enum bfd_endian endian = info->endian;
00544   enum sh64_elf_cr_type cr_type;
00545 
00546   if (info->private_data == NULL && ! init_sh64_disasm_info (info))
00547     return -1;
00548 
00549   cr_type = sh64_get_contents_type_disasm (memaddr, info);
00550   if (cr_type != CRT_SH5_ISA16)
00551     {
00552       int length = 4 - (memaddr % 4);
00553       info->display_endian = endian;
00554 
00555       /* If we got an uneven address to indicate SHmedia, adjust it.  */
00556       if (cr_type == CRT_SH5_ISA32 && length == 3)
00557        memaddr--, length = 4;
00558 
00559       /* Only disassemble on four-byte boundaries.  Addresses that are not
00560         a multiple of four can happen after a data region.  */
00561       if (cr_type == CRT_SH5_ISA32 && length == 4)
00562        return print_insn_sh64x_media (memaddr, info);
00563 
00564       /* We get CRT_DATA *only* for data regions in a mixed-contents
00565         section.  For sections with data only, we get indication of one
00566         of the ISA:s.  You may think that we shouldn't disassemble
00567         section with only data if we can figure that out.  However, the
00568         disassembly function is by default not called for data-only
00569         sections, so if the user explicitly specified disassembly of a
00570         data section, that's what we should do.  */
00571       if (cr_type == CRT_DATA || length != 4)
00572        {
00573          int status;
00574          unsigned char data[4];
00575          struct sh64_disassemble_info *sh64_infop = info->private_data;
00576 
00577          if (length == 4
00578              && sh64_infop->crange.cr_type != CRT_NONE
00579              && memaddr >= sh64_infop->crange.cr_addr
00580              && memaddr < (sh64_infop->crange.cr_addr
00581                          + sh64_infop->crange.cr_size))
00582            length
00583              = (sh64_infop->crange.cr_addr
00584                + sh64_infop->crange.cr_size - memaddr);
00585 
00586          status
00587            = (*info->read_memory_func) (memaddr, data,
00588                                     length >= 4 ? 4 : length, info);
00589 
00590          if (status == 0 && length >= 4)
00591            {
00592              (*info->fprintf_func) (info->stream, ".long 0x%08lx",
00593                                  endian == BFD_ENDIAN_BIG
00594                                  ? (long) (bfd_getb32 (data))
00595                                  : (long) (bfd_getl32 (data)));
00596              return 4;
00597            }
00598          else
00599            {
00600              int i;
00601 
00602              for (i = 0; i < length; i++)
00603               {
00604                 status = info->read_memory_func (memaddr + i, data, 1, info);
00605                 if (status != 0)
00606                   break;
00607                 (*info->fprintf_func) (info->stream, "%s0x%02x",
00608                                     i == 0 ? ".byte " : ", ",
00609                                     data[0]);
00610               }
00611 
00612              return i ? i : -1;
00613            }
00614        }
00615     }
00616 
00617   /* SH1 .. SH4 instruction, let caller handle it.  */
00618   return -2;
00619 }