diff options
-rw-r--r-- | opcodes/sparc-dis.c (renamed from binutils/sparc-pinsn.c) | 198 |
1 files changed, 114 insertions, 84 deletions
diff --git a/binutils/sparc-pinsn.c b/opcodes/sparc-dis.c index b639d86..2d20e60 100644 --- a/binutils/sparc-pinsn.c +++ b/opcodes/sparc-dis.c @@ -1,29 +1,23 @@ -/* disassemble sparc instructions for objdump - Copyright (C) 1986, 1987, 1989, 1991 Free Software Foundation, Inc. +/* Print SPARC instructions. + Copyright 1989, 1991, 1992, 1993 Free Software Foundation, Inc. - -This file is part of the binutils. - -The binutils are free software; you can redistribute it and/or modify +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, or (at your option) -any later version. +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. -The binutils are distributed in the hope that they will be useful, +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 the binutils; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "bfd.h" -#include "sysdep.h" -#include <stdio.h> #include "opcode/sparc.h" -#include "objdump.h" -extern int print_address(); +#include "dis-asm.h" +#include <string.h> static char *reg_names[] = { "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", @@ -38,34 +32,37 @@ static char *reg_names[] = #define freg_names (®_names[4 * 8]) +/* FIXME--need to deal with byte order (probably using masking and + shifting rather than bitfields is easiest). */ + union sparc_insn { unsigned long int code; struct { - unsigned int _OP:2; -#define op ldst._OP - unsigned int _RD:5; -#define rd ldst._RD + unsigned int anop:2; +#define op ldst.anop + unsigned int anrd:5; +#define rd ldst.anrd unsigned int op3:6; - unsigned int _RS1:5; -#define rs1 ldst._RS1 + unsigned int anrs1:5; +#define rs1 ldst.anrs1 unsigned int i:1; - unsigned int _ASI:8; -#define asi ldst._ASI - unsigned int _RS2:5; -#define rs2 ldst._RS2 + unsigned int anasi:8; +#define asi ldst.anasi + unsigned int anrs2:5; +#define rs2 ldst.anrs2 #define shcnt rs2 } ldst; struct { - unsigned int _OP:2, _RD:5, op3:6, _RS1:5, i:1; + unsigned int anop:2, anrd:5, op3:6, anrs1:5, i:1; unsigned int IMM13:13; #define imm13 IMM13.IMM13 } IMM13; struct { - unsigned int _OP:2; + unsigned int anop:2; unsigned int a:1; unsigned int cond:4; unsigned int op2:3; @@ -94,9 +91,9 @@ union sparc_insn #define imm22 disp22 struct { - unsigned int _OP:2; - unsigned int _DISP30:30; -#define disp30 call._DISP30 + unsigned int anop:2; + unsigned int adisp30:30; +#define disp30 call.adisp30 } call; }; @@ -111,23 +108,28 @@ is_delayed_branch (insn) { const struct sparc_opcode *opcode = &sparc_opcodes[i]; if ((opcode->match & insn.code) == opcode->match - && (opcode->lose & insn.code) == 0 - && (opcode->flags&F_DELAYED)) - return 1; + && (opcode->lose & insn.code) == 0) + return (opcode->flags & F_DELAYED); } return 0; } static int opcodes_sorted = 0; +extern void qsort (); + +/* Print one instruction from MEMADDR on STREAM. -/* Print one instruction from MEMADDR on STREAM. */ + We suffix the instruction with a comment that gives the absolute + address involved, as well as its symbolic form, if the instruction + is preceded by a findable `sethi' and it either adds an immediate + displacement to that register, or it is an `add' or `or' instruction + on that register. */ int -print_insn_sparc (memaddr, buffer, stream) +print_insn_sparc (memaddr, info) bfd_vma memaddr; - bfd_byte *buffer; - FILE *stream; - + disassemble_info *info; { + FILE *stream = info->stream; union sparc_insn insn; register unsigned int i; @@ -140,7 +142,15 @@ print_insn_sparc (memaddr, buffer, stream) opcodes_sorted = 1; } -memcpy(&insn,buffer, sizeof (insn)); + { + int status = + (*info->read_memory_func) (memaddr, (char *) &insn, sizeof (insn), info); + if (status != 0) + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + } for (i = 0; i < NUMOPCODES; ++i) { @@ -156,48 +166,44 @@ memcpy(&insn,buffer, sizeof (insn)); field of the opcode table. */ int found_plus = 0; - /* Do we have an 'or' instruction where rs1 is the same + /* Do we have an `add' or `or' instruction where rs1 is the same as rsd, and which has the i bit set? */ - if (opcode->match == 0x80102000 + if ((opcode->match == 0x80102000 || opcode->match == 0x80002000) + /* (or) (add) */ && insn.rs1 == insn.rd) imm_added_to_rs1 = 1; - if (strchr (opcode->args, 'S') != 0) - /* Reject the special case for `set'. - The real `sethi' will match. */ - continue; if (insn.rs1 != insn.rd && strchr (opcode->args, 'r') != 0) /* Can't do simple format if source and dest are different. */ continue; - fputs (opcode->name, stream); + (*info->fprintf_func) (stream, opcode->name); { register const char *s; if (opcode->args[0] != ',') - fputs (" ", stream); + (*info->fprintf_func) (stream, " "); for (s = opcode->args; *s != '\0'; ++s) { while (*s == ',') { - fputs (",", stream); + (*info->fprintf_func) (stream, ","); ++s; - switch (*s) { case 'a': - fputs ("a", stream); + (*info->fprintf_func) (stream, "a"); ++s; continue; #ifndef NO_V9 case 'N': - fputs("pn", stream); + (*info->fprintf_func) (stream, "pn"); ++s; continue; case 'T': - fputs("pt", stream); + (*info->fprintf_func) (stream, "pt"); ++s; continue; #endif /* NO_V9 */ @@ -207,7 +213,7 @@ memcpy(&insn,buffer, sizeof (insn)); } /* switch on arg */ } /* while there are comma started args */ - fputs (" ", stream); + (*info->fprintf_func) (stream, " "); switch (*s) { @@ -216,14 +222,14 @@ memcpy(&insn,buffer, sizeof (insn)); /* note fall-through */ default: - fprintf (stream, "%c", *s); + (*info->fprintf_func) (stream, "%c", *s); break; case '#': - fputs ("0", stream); + (*info->fprintf_func) (stream, "0"); break; -#define reg(n) fprintf (stream, "%%%s", reg_names[n]) +#define reg(n) (*info->fprintf_func) (stream, "%%%s", reg_names[n]) case '1': case 'r': reg (insn.rs1); @@ -238,7 +244,7 @@ memcpy(&insn,buffer, sizeof (insn)); break; #undef reg -#define freg(n) fprintf (stream, "%%%s", freg_names[n]) +#define freg(n) (*info->fprintf_func) (stream, "%%%s", freg_names[n]) case 'e': case 'v': /* double/even */ case 'V': /* quad/multiple of 4 */ @@ -258,7 +264,7 @@ memcpy(&insn,buffer, sizeof (insn)); break; #undef freg -#define creg(n) fprintf (stream, "%%c%u", (unsigned int) (n)) +#define creg(n) (*info->fprintf_func) (stream, "%%c%u", (unsigned int) (n)) case 'b': creg (insn.rs1); break; @@ -273,8 +279,8 @@ memcpy(&insn,buffer, sizeof (insn)); #undef creg case 'h': - fprintf (stream, "%%hi(%#x)", - (unsigned int) insn.imm22 << 10); + (*info->fprintf_func) (stream, "%%hi(%#x)", + (int) insn.imm22 << 10); break; case 'i': @@ -285,7 +291,7 @@ memcpy(&insn,buffer, sizeof (insn)); /* Check to see whether we have a 1+i, and take note of that fact. - + Note: because of the way we sort the table, we will be matching 1+i rather than i+1, so it is OK to assume that i is after +, @@ -294,9 +300,9 @@ memcpy(&insn,buffer, sizeof (insn)); imm_added_to_rs1 = 1; if (imm <= 9) - fprintf (stream, "%d", imm); + (*info->fprintf_func) (stream, "%d", imm); else - fprintf (stream, "%#x", (unsigned) imm); + (*info->fprintf_func) (stream, "%#x", imm); } break; @@ -324,9 +330,9 @@ memcpy(&insn,buffer, sizeof (insn)); imm_added_to_rs1 = 1; if (imm <= 9) - fprintf (stream, "%d", imm); + (info->fprintf_func) (stream, "%d", imm); else - fprintf (stream, "%#x", (unsigned) imm); + (info->fprintf_func) (stream, "%#x", (unsigned) imm); } break; @@ -389,8 +395,9 @@ memcpy(&insn,buffer, sizeof (insn)); if ((insn.code >> 22) == 0) /* Special case for `unimp'. Don't try to turn it's operand into a function offset. */ - fprintf (stream, "%#x", - (unsigned) (((int) insn.disp22 << 10) >> 10)); + (*info->fprintf_func) + (stream, "%#x", + (int) (((int) insn.disp22 << 10) >> 10)); else /* We cannot trust the compiler to sign-extend when extracting the bitfield, hence the shifts. */ @@ -401,39 +408,39 @@ memcpy(&insn,buffer, sizeof (insn)); break; case 'A': - fprintf (stream, "(%d)", (int) insn.asi); + (*info->fprintf_func) (stream, "(%d)", (int) insn.asi); break; case 'C': - fputs ("%csr", stream); + (*info->fprintf_func) (stream, "%csr"); break; case 'F': - fputs ("%fsr", stream); + (*info->fprintf_func) (stream, "%fsr"); break; case 'p': - fputs ("%psr", stream); + (*info->fprintf_func) (stream, "%psr"); break; case 'q': - fputs ("%fq", stream); + (*info->fprintf_func) (stream, "%fq"); break; case 'Q': - fputs ("%cq", stream); + (*info->fprintf_func) (stream, "%cq"); break; case 't': - fputs ("%tbr", stream); + (*info->fprintf_func) (stream, "%tbr"); break; case 'w': - fputs ("%wim", stream); + (*info->fprintf_func) (stream, "%wim"); break; case 'y': - fputs ("%y", stream); + (*info->fprintf_func) (stream, "%y"); break; } } @@ -448,9 +455,12 @@ memcpy(&insn,buffer, sizeof (insn)); if (imm_added_to_rs1) { union sparc_insn prev_insn; - int errcode = 0; + int errcode; - memcpy(&prev_insn, buffer -4, sizeof (prev_insn)); + errcode = + (*info->read_memory_func) + (memaddr - 4, + (char *)&prev_insn, sizeof (prev_insn)); if (errcode == 0) { @@ -464,8 +474,8 @@ memcpy(&insn,buffer, sizeof (insn)); */ if (is_delayed_branch (prev_insn)) - memcpy(&prev_insn, buffer - 8, sizeof(prev_insn)); - + errcode = (*info->read_memory_func) + (memaddr - 8, (char *)&prev_insn, sizeof (prev_insn)); } /* If there was a problem reading memory, then assume @@ -476,7 +486,7 @@ memcpy(&insn,buffer, sizeof (insn)); if ((prev_insn.code & 0xc1c00000) == 0x01000000 && prev_insn.rd == insn.rs1) { - fprintf (stream, "\t! "); + (*info->fprintf_func) (stream, "\t! "); /* We cannot trust the compiler to sign-extend when extracting the bitfield, hence the shifts. */ print_address (((int) prev_insn.imm22 << 10) @@ -489,11 +499,10 @@ memcpy(&insn,buffer, sizeof (insn)); } } - fprintf (stream, "%#8x", insn.code); + (*info->fprintf_func) (stream, "%#8x", insn.code); return sizeof (insn); } - /* Compare opcodes A and B. */ static int @@ -548,6 +557,27 @@ compare_opcodes (a, b) /* They are functionally equal. So as long as the opcode table is valid, we can put whichever one first we want, on aesthetic grounds. */ + + /* Our first aesthetic ground is that aliases defer to real insns. */ + { + int alias_diff = (op0->flags & F_ALIAS) - (op1->flags & F_ALIAS); + if (alias_diff != 0) + /* Put the one that isn't an alias first. */ + return alias_diff; + } + + /* Except for aliases, two "identical" instructions had + better have the same opcode. This is a sanity check on the table. */ + i = strcmp (op0->name, op1->name); + if (i) + if (op0->flags & F_ALIAS) /* If they're both aliases, be arbitrary. */ + return i; + else + fprintf (stderr, + "Internal error: bad sparc-opcode.h: \"%s\" == \"%s\"\n", + op0->name, op1->name); + + /* Fewer arguments are preferred. */ { int length_diff = strlen (op0->args) - strlen (op1->args); if (length_diff != 0) |