00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
00025
00026 #include "elf-bfd.h"
00027 #include "elf/sh.h"
00028 #include "elf32-sh64.h"
00029
00030 #define ELF_MODE32_CODE_LABEL_P(SYM) \
00031 (((elf_symbol_type *) (SYM))->internal_elf_sym.st_other & STO_SH5_ISA32)
00032
00033 #define SAVED_MOVI_R(INFO) \
00034 (((struct sh64_disassemble_info *) ((INFO)->private_data))->address_reg)
00035
00036 #define SAVED_MOVI_IMM(INFO) \
00037 (((struct sh64_disassemble_info *) ((INFO)->private_data))->built_address)
00038
00039 struct sh64_disassemble_info
00040 {
00041
00042
00043 unsigned int address_reg;
00044 bfd_signed_vma built_address;
00045
00046
00047
00048 sh64_elf_crange crange;
00049 };
00050
00051
00052
00053
00054
00055 static unsigned long *shmedia_opcode_mask_table;
00056
00057 static void initialize_shmedia_opcode_mask_table PARAMS ((void));
00058 static int print_insn_shmedia PARAMS ((bfd_vma, disassemble_info *));
00059 static const char *creg_name PARAMS ((int));
00060 static bfd_boolean init_sh64_disasm_info PARAMS ((struct disassemble_info *));
00061 static enum sh64_elf_cr_type sh64_get_contents_type_disasm
00062 PARAMS ((bfd_vma, struct disassemble_info *));
00063
00064
00065
00066
00067 static void
00068 initialize_shmedia_opcode_mask_table ()
00069 {
00070 int n_opc;
00071 int n;
00072
00073
00074 for (n_opc = 0; shmedia_table[n_opc].name != NULL; n_opc++)
00075 ;
00076
00077 shmedia_opcode_mask_table
00078 = xmalloc (sizeof (shmedia_opcode_mask_table[0]) * n_opc);
00079
00080 for (n = 0; n < n_opc; n++)
00081 {
00082 int i;
00083
00084 unsigned long mask = 0;
00085
00086 for (i = 0; shmedia_table[n].arg[i] != A_NONE; i++)
00087 {
00088 int offset = shmedia_table[n].nibbles[i];
00089 int length;
00090
00091 switch (shmedia_table[n].arg[i])
00092 {
00093 case A_GREG_M:
00094 case A_GREG_N:
00095 case A_GREG_D:
00096 case A_CREG_K:
00097 case A_CREG_J:
00098 case A_FREG_G:
00099 case A_FREG_H:
00100 case A_FREG_F:
00101 case A_DREG_G:
00102 case A_DREG_H:
00103 case A_DREG_F:
00104 case A_FMREG_G:
00105 case A_FMREG_H:
00106 case A_FMREG_F:
00107 case A_FPREG_G:
00108 case A_FPREG_H:
00109 case A_FPREG_F:
00110 case A_FVREG_G:
00111 case A_FVREG_H:
00112 case A_FVREG_F:
00113 case A_REUSE_PREV:
00114 length = 6;
00115 break;
00116
00117 case A_TREG_A:
00118 case A_TREG_B:
00119 length = 3;
00120 break;
00121
00122 case A_IMMM:
00123 abort ();
00124 break;
00125
00126 case A_IMMU5:
00127 length = 5;
00128 break;
00129
00130 case A_IMMS6:
00131 case A_IMMU6:
00132 case A_IMMS6BY32:
00133 length = 6;
00134 break;
00135
00136 case A_IMMS10:
00137 case A_IMMS10BY1:
00138 case A_IMMS10BY2:
00139 case A_IMMS10BY4:
00140 case A_IMMS10BY8:
00141 length = 10;
00142 break;
00143
00144 case A_IMMU16:
00145 case A_IMMS16:
00146 case A_PCIMMS16BY4:
00147 case A_PCIMMS16BY4_PT:
00148 length = 16;
00149 break;
00150
00151 default:
00152 abort ();
00153 length = 0;
00154 break;
00155 }
00156
00157 if (length != 0)
00158 mask |= (0xffffffff >> (32 - length)) << offset;
00159 }
00160 shmedia_opcode_mask_table[n] = 0xffffffff & ~mask;
00161 }
00162 }
00163
00164
00165
00166 const char *
00167 creg_name (cregno)
00168 int cregno;
00169 {
00170 const shmedia_creg_info *cregp;
00171
00172
00173
00174 for (cregp = shmedia_creg_table; cregp->name != NULL; cregp++)
00175 {
00176 if (cregp->cregno == cregno)
00177 return cregp->name;
00178 }
00179
00180 return NULL;
00181 }
00182
00183
00184
00185 static int
00186 print_insn_shmedia (memaddr, info)
00187 bfd_vma memaddr;
00188 struct disassemble_info *info;
00189 {
00190 fprintf_ftype fprintf_fn = info->fprintf_func;
00191 void *stream = info->stream;
00192
00193 unsigned char insn[4];
00194 unsigned long instruction;
00195 int status;
00196 int n;
00197 const shmedia_opcode_info *op;
00198 int i;
00199 unsigned int r = 0;
00200 long imm = 0;
00201 bfd_vma disp_pc_addr;
00202
00203 status = info->read_memory_func (memaddr, insn, 4, info);
00204
00205
00206
00207 if (status != 0)
00208 {
00209 int i;
00210
00211 for (i = 0; i < 3; i++)
00212 {
00213 status = info->read_memory_func (memaddr + i, insn, 1, info);
00214 if (status != 0)
00215 break;
00216 (*fprintf_fn) (stream, "%s0x%02x",
00217 i == 0 ? ".byte " : ", ",
00218 insn[0]);
00219 }
00220
00221 return i ? i : -1;
00222 }
00223
00224
00225 if (info->endian == BFD_ENDIAN_LITTLE)
00226 instruction = bfd_getl32 (insn);
00227 else
00228 instruction = bfd_getb32 (insn);
00229
00230
00231
00232 for (n = 0, op = shmedia_table;
00233 op->name != NULL
00234 && ((instruction & shmedia_opcode_mask_table[n]) != op->opcode_base);
00235 n++, op++)
00236 ;
00237
00238
00239 if (op->name == NULL)
00240 {
00241 fprintf_fn (stream, ".long 0x%08x", instruction);
00242 return 4;
00243 }
00244
00245 fprintf_fn (stream, "%s\t", op->name);
00246
00247 for (i = 0; i < 3 && op->arg[i] != A_NONE; i++)
00248 {
00249 unsigned long temp = instruction >> op->nibbles[i];
00250 int by_number = 0;
00251
00252 if (i > 0 && op->arg[i] != A_REUSE_PREV)
00253 fprintf_fn (stream, ",");
00254
00255 switch (op->arg[i])
00256 {
00257 case A_REUSE_PREV:
00258 continue;
00259
00260 case A_GREG_M:
00261 case A_GREG_N:
00262 case A_GREG_D:
00263 r = temp & 0x3f;
00264 fprintf_fn (stream, "r%d", r);
00265 break;
00266
00267 case A_FVREG_F:
00268 case A_FVREG_G:
00269 case A_FVREG_H:
00270 r = temp & 0x3f;
00271 fprintf_fn (stream, "fv%d", r);
00272 break;
00273
00274 case A_FPREG_F:
00275 case A_FPREG_G:
00276 case A_FPREG_H:
00277 r = temp & 0x3f;
00278 fprintf_fn (stream, "fp%d", r);
00279 break;
00280
00281 case A_FMREG_F:
00282 case A_FMREG_G:
00283 case A_FMREG_H:
00284 r = temp & 0x3f;
00285 fprintf_fn (stream, "mtrx%d", r);
00286 break;
00287
00288 case A_CREG_K:
00289 case A_CREG_J:
00290 {
00291 const char *name;
00292 r = temp & 0x3f;
00293
00294 name = creg_name (r);
00295
00296 if (name != NULL)
00297 fprintf_fn (stream, "%s", name);
00298 else
00299 fprintf_fn (stream, "cr%d", r);
00300 }
00301 break;
00302
00303 case A_FREG_G:
00304 case A_FREG_H:
00305 case A_FREG_F:
00306 r = temp & 0x3f;
00307 fprintf_fn (stream, "fr%d", r);
00308 break;
00309
00310 case A_DREG_G:
00311 case A_DREG_H:
00312 case A_DREG_F:
00313 r = temp & 0x3f;
00314 fprintf_fn (stream, "dr%d", r);
00315 break;
00316
00317 case A_TREG_A:
00318 case A_TREG_B:
00319 r = temp & 0x7;
00320 fprintf_fn (stream, "tr%d", r);
00321 break;
00322
00323
00324 case A_IMMS6:
00325 imm = temp & 0x3f;
00326 if (imm & (unsigned long) 0x20)
00327 imm |= ~(unsigned long) 0x3f;
00328 fprintf_fn (stream, "%d", imm);
00329 break;
00330
00331
00332 case A_IMMS6BY32:
00333 imm = temp & 0x3f;
00334 if (imm & (unsigned long) 0x20)
00335 imm |= ~(unsigned long) 0x3f;
00336 fprintf_fn (stream, "%d", imm * 32);
00337 break;
00338
00339
00340 case A_IMMS10BY8:
00341 by_number++;
00342
00343
00344
00345 case A_IMMS10BY4:
00346 by_number++;
00347
00348
00349
00350 case A_IMMS10BY2:
00351 by_number++;
00352
00353
00354
00355 case A_IMMS10:
00356 case A_IMMS10BY1:
00357 imm = temp & 0x3ff;
00358 if (imm & (unsigned long) 0x200)
00359 imm |= ~(unsigned long) 0x3ff;
00360 imm <<= by_number;
00361 fprintf_fn (stream, "%d", imm);
00362 break;
00363
00364
00365 case A_IMMS16:
00366 imm = temp & 0xffff;
00367 if (imm & (unsigned long) 0x8000)
00368 imm |= ~((unsigned long) 0xffff);
00369 fprintf_fn (stream, "%d", imm);
00370 break;
00371
00372
00373
00374 case A_PCIMMS16BY4:
00375 imm = temp & 0xffff;
00376 if (imm & (unsigned long) 0x8000)
00377 imm |= ~(unsigned long) 0xffff;
00378 imm <<= 2;
00379 disp_pc_addr = (bfd_vma) imm + memaddr;
00380 (*info->print_address_func) (disp_pc_addr, info);
00381 break;
00382
00383
00384 case A_IMMU5:
00385 imm = temp & 0x1f;
00386 fprintf_fn (stream, "%d", imm);
00387 break;
00388
00389
00390 case A_IMMU6:
00391 imm = temp & 0x3f;
00392 fprintf_fn (stream, "%d", imm);
00393 break;
00394
00395
00396 case A_IMMU16:
00397 imm = temp & 0xffff;
00398 fprintf_fn (stream, "%d", imm);
00399 break;
00400
00401 default:
00402 abort ();
00403 break;
00404 }
00405 }
00406
00407
00408
00409 if (op->opcode_base == (unsigned long) SHMEDIA_SHORI_OPC
00410 && SAVED_MOVI_R (info) == r)
00411 {
00412 asection *section = info->section;
00413
00414
00415
00416 if (section == NULL
00417 && info->symbols != NULL
00418 && bfd_asymbol_flavour (info->symbols[0]) == bfd_target_elf_flavour
00419 && ! bfd_is_und_section (bfd_get_section (info->symbols[0]))
00420 && ! bfd_is_abs_section (bfd_get_section (info->symbols[0])))
00421 section = bfd_get_section (info->symbols[0]);
00422
00423
00424
00425
00426 if (section == NULL
00427 || section->owner == NULL
00428 || elf_elfheader (section->owner)->e_type == ET_EXEC)
00429 {
00430 bfd_signed_vma shori_addr;
00431
00432 shori_addr = SAVED_MOVI_IMM (info) << 16;
00433 shori_addr |= imm;
00434
00435 fprintf_fn (stream, "\t! 0x");
00436 (*info->print_address_func) (shori_addr, info);
00437 }
00438 }
00439
00440 if (op->opcode_base == SHMEDIA_MOVI_OPC)
00441 {
00442 SAVED_MOVI_IMM (info) = imm;
00443 SAVED_MOVI_R (info) = r;
00444 }
00445 else
00446 {
00447 SAVED_MOVI_IMM (info) = 0;
00448 SAVED_MOVI_R (info) = 255;
00449 }
00450
00451 return 4;
00452 }
00453
00454
00455
00456
00457
00458
00459 static enum sh64_elf_cr_type
00460 sh64_get_contents_type_disasm (memaddr, info)
00461 bfd_vma memaddr;
00462 struct disassemble_info *info;
00463 {
00464 struct sh64_disassemble_info *sh64_infop = info->private_data;
00465
00466
00467
00468 if (sh64_infop->crange.cr_type != CRT_NONE
00469 && memaddr >= sh64_infop->crange.cr_addr
00470 && memaddr < sh64_infop->crange.cr_addr + sh64_infop->crange.cr_size)
00471 return sh64_infop->crange.cr_type;
00472
00473
00474 if (info->section
00475 && bfd_get_flavour (info->section->owner) == bfd_target_elf_flavour)
00476 {
00477 enum sh64_elf_cr_type cr_type
00478 = sh64_get_contents_type (info->section, memaddr,
00479 &sh64_infop->crange);
00480
00481 if (cr_type != CRT_NONE)
00482 return cr_type;
00483 }
00484
00485
00486 if (info->symbols != NULL
00487 && bfd_asymbol_flavour (info->symbols[0]) == bfd_target_elf_flavour
00488 && ! bfd_is_und_section (bfd_get_section (info->symbols[0]))
00489 && ! bfd_is_abs_section (bfd_get_section (info->symbols[0])))
00490 {
00491 enum sh64_elf_cr_type cr_type
00492 = sh64_get_contents_type (bfd_get_section (info->symbols[0]),
00493 memaddr, &sh64_infop->crange);
00494
00495 if (cr_type != CRT_NONE)
00496 return cr_type;
00497 }
00498
00499
00500
00501
00502 if (info->symbols
00503 && bfd_asymbol_flavour (info->symbols[0]) == bfd_target_elf_flavour
00504 && elf_symbol_from (bfd_asymbol_bfd (info->symbols[0]),
00505 info->symbols[0])->internal_elf_sym.st_other
00506 == STO_SH5_ISA32)
00507 return CRT_SH5_ISA32;
00508
00509
00510 return (memaddr & 1) == 1 ? CRT_SH5_ISA32 : CRT_SH5_ISA16;
00511 }
00512
00513
00514
00515 static bfd_boolean
00516 init_sh64_disasm_info (info)
00517 struct disassemble_info *info;
00518 {
00519 struct sh64_disassemble_info *sh64_infop
00520 = calloc (sizeof (*sh64_infop), 1);
00521
00522 if (sh64_infop == NULL)
00523 return FALSE;
00524
00525 info->private_data = sh64_infop;
00526
00527 SAVED_MOVI_IMM (info) = 0;
00528 SAVED_MOVI_R (info) = 255;
00529
00530 if (shmedia_opcode_mask_table == NULL)
00531 initialize_shmedia_opcode_mask_table ();
00532
00533 return TRUE;
00534 }
00535
00536
00537
00538
00539
00540 int
00541 print_insn_sh64x_media (memaddr, info)
00542 bfd_vma memaddr;
00543 struct disassemble_info *info;
00544 {
00545 if (info->private_data == NULL && ! init_sh64_disasm_info (info))
00546 return -1;
00547
00548
00549 info->bytes_per_line = 4;
00550 info->bytes_per_chunk = 4;
00551
00552 return print_insn_shmedia (memaddr, info);
00553 }
00554
00555
00556
00557
00558 int
00559 print_insn_sh64 (memaddr, info)
00560 bfd_vma memaddr;
00561 struct disassemble_info *info;
00562 {
00563 enum bfd_endian endian = info->endian;
00564 enum sh64_elf_cr_type cr_type;
00565
00566 if (info->private_data == NULL && ! init_sh64_disasm_info (info))
00567 return -1;
00568
00569 cr_type = sh64_get_contents_type_disasm (memaddr, info);
00570 if (cr_type != CRT_SH5_ISA16)
00571 {
00572 int length = 4 - (memaddr % 4);
00573 info->display_endian = endian;
00574
00575
00576 if (cr_type == CRT_SH5_ISA32 && length == 3)
00577 memaddr--, length = 4;
00578
00579
00580
00581 if (cr_type == CRT_SH5_ISA32 && length == 4)
00582 return print_insn_sh64x_media (memaddr, info);
00583
00584
00585
00586
00587
00588
00589
00590
00591 if (cr_type == CRT_DATA || length != 4)
00592 {
00593 int status;
00594 unsigned char data[4];
00595 struct sh64_disassemble_info *sh64_infop = info->private_data;
00596
00597 if (length == 4
00598 && sh64_infop->crange.cr_type != CRT_NONE
00599 && memaddr >= sh64_infop->crange.cr_addr
00600 && memaddr < (sh64_infop->crange.cr_addr
00601 + sh64_infop->crange.cr_size))
00602 length
00603 = (sh64_infop->crange.cr_addr
00604 + sh64_infop->crange.cr_size - memaddr);
00605
00606 status
00607 = (*info->read_memory_func) (memaddr, data,
00608 length >= 4 ? 4 : length, info);
00609
00610 if (status == 0 && length >= 4)
00611 {
00612 (*info->fprintf_func) (info->stream, ".long 0x%08lx",
00613 endian == BFD_ENDIAN_BIG
00614 ? (long) (bfd_getb32 (data))
00615 : (long) (bfd_getl32 (data)));
00616 return 4;
00617 }
00618 else
00619 {
00620 int i;
00621
00622 for (i = 0; i < length; i++)
00623 {
00624 status = info->read_memory_func (memaddr + i, data, 1, info);
00625 if (status != 0)
00626 break;
00627 (*info->fprintf_func) (info->stream, "%s0x%02x",
00628 i == 0 ? ".byte " : ", ",
00629 data[0]);
00630 }
00631
00632 return i ? i : -1;
00633 }
00634 }
00635 }
00636
00637
00638 return -2;
00639 }