diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
commit | d6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch) | |
tree | ece253b876159b39c620e62b6c9b1174642e070e /gnu/usr.bin/gdb/objdump |
initial import of NetBSD tree
Diffstat (limited to 'gnu/usr.bin/gdb/objdump')
-rw-r--r-- | gnu/usr.bin/gdb/objdump/Makefile | 32 | ||||
-rw-r--r-- | gnu/usr.bin/gdb/objdump/arch/i386/Makefile.inc | 8 | ||||
-rw-r--r-- | gnu/usr.bin/gdb/objdump/arch/i386/i386-pinsn.c | 1860 | ||||
-rw-r--r-- | gnu/usr.bin/gdb/objdump/arch/m68k/Makefile.inc | 8 | ||||
-rw-r--r-- | gnu/usr.bin/gdb/objdump/arch/m68k/m68k-pinsn.c | 807 | ||||
-rw-r--r-- | gnu/usr.bin/gdb/objdump/arch/sparc/Makefile.inc | 8 | ||||
-rw-r--r-- | gnu/usr.bin/gdb/objdump/arch/sparc/sparc-pinsn.c | 482 | ||||
-rw-r--r-- | gnu/usr.bin/gdb/objdump/bucomm.c | 146 | ||||
-rw-r--r-- | gnu/usr.bin/gdb/objdump/filemode.c | 193 | ||||
-rw-r--r-- | gnu/usr.bin/gdb/objdump/objdump.1 | 227 | ||||
-rw-r--r-- | gnu/usr.bin/gdb/objdump/objdump.c | 1087 | ||||
-rw-r--r-- | gnu/usr.bin/gdb/objdump/objdump.h | 2 | ||||
-rw-r--r-- | gnu/usr.bin/gdb/objdump/version.c | 5 |
13 files changed, 4865 insertions, 0 deletions
diff --git a/gnu/usr.bin/gdb/objdump/Makefile b/gnu/usr.bin/gdb/objdump/Makefile new file mode 100644 index 00000000000..e5507a9755b --- /dev/null +++ b/gnu/usr.bin/gdb/objdump/Makefile @@ -0,0 +1,32 @@ +# $Id: Makefile,v 1.1 1995/10/18 08:40:13 deraadt Exp $ + +# Paths to libraries +# +LIBBFD!=cd $(.CURDIR)/../bfd; \ + printf "xxx:\n\techo \$${.OBJDIR}/libbfd.a\n" | make -r -s -f - xxx + +LIBIBERTY!=cd $(.CURDIR)/../libiberty; \ + printf "xxx:\n\techo \$${.OBJDIR}/libiberty.a\n" | make -r -s -f - xxx + + +PROG= objdump + +CFLAGS+= -I$(.CURDIR)/arch/$(MACHINE_ARCH) -I$(.CURDIR)/../bfd \ + -I$(.CURDIR)/../include \ + -I$(.CURDIR)/../bfd/arch/$(MACHINE_ARCH) \ + -I$(.CURDIR) + +CFLAGS+= -DVERSION=\"2.0\" + +.PATH: $(.CURDIR)/arch/$(MACHINE_ARCH) \ + $(.CURDIR)/../gdb/arch/$(MACHINE_ARCH) + +SRCS= objdump.c bucomm.c filemode.c version.c + +LDADD= $(LIBBFD) $(LIBIBERTY) +DPADD= $(LIBBFD) $(LIBIBERTY) + +.include "$(.CURDIR)/arch/$(MACHINE_ARCH)/Makefile.inc" +.include "../../Makefile.inc" +.include <bsd.prog.mk> + diff --git a/gnu/usr.bin/gdb/objdump/arch/i386/Makefile.inc b/gnu/usr.bin/gdb/objdump/arch/i386/Makefile.inc new file mode 100644 index 00000000000..7c88f86753e --- /dev/null +++ b/gnu/usr.bin/gdb/objdump/arch/i386/Makefile.inc @@ -0,0 +1,8 @@ +# $Id: Makefile.inc,v 1.1 1995/10/18 08:40:14 deraadt Exp $ + +SRCS+= i386-pinsn.c + +CFLAGS+= -DSELECT_ARCHITECTURES=bfd_arch_i386 \ + -DPRINT_INSN=print_insn_i386 + + diff --git a/gnu/usr.bin/gdb/objdump/arch/i386/i386-pinsn.c b/gnu/usr.bin/gdb/objdump/arch/i386/i386-pinsn.c new file mode 100644 index 00000000000..8262b89b19a --- /dev/null +++ b/gnu/usr.bin/gdb/objdump/arch/i386/i386-pinsn.c @@ -0,0 +1,1860 @@ +/* Stolen from GDB on 27 mar 92 by steve chamberlain */ +/* Print i386 instructions for GDB, the GNU debugger. + Copyright (C) 1988, 1989, 1991 Free Software Foundation, Inc. + +This file is part of GDB. + +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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu) + * July 1988 + */ + +/* + * The main tables describing the instructions is essentially a copy + * of the "Opcode Map" chapter (Appendix A) of the Intel 80386 + * Programmers Manual. Usually, there is a capital letter, followed + * by a small letter. The capital letter tell the addressing mode, + * and the small letter tells about the operand size. Refer to + * the Intel manual for details. + */ +#include "bfd.h" +#include "sysdep.h" + +#if 0 +#include "defs.h" + +#include <ctype.h> + +/* For the GDB interface at the bottom of the file... */ +#include "gdbcore.h" +#endif + +#define Eb OP_E, b_mode +#define indirEb OP_indirE, b_mode +#define Gb OP_G, b_mode +#define Ev OP_E, v_mode +#define indirEv OP_indirE, v_mode +#define Ew OP_E, w_mode +#define Ma OP_E, v_mode +#define M OP_E, 0 +#define Mp OP_E, 0 /* ? */ +#define Gv OP_G, v_mode +#define Gw OP_G, w_mode +#define Rw OP_rm, w_mode +#define Rd OP_rm, d_mode +#define Ib OP_I, b_mode +#define sIb OP_sI, b_mode /* sign extened byte */ +#define Iv OP_I, v_mode +#define Iw OP_I, w_mode +#define Jb OP_J, b_mode +#define Jv OP_J, v_mode +#define ONE OP_ONE, 0 +#define Cd OP_C, d_mode +#define Dd OP_D, d_mode +#define Td OP_T, d_mode + +#define eAX OP_REG, eAX_reg +#define eBX OP_REG, eBX_reg +#define eCX OP_REG, eCX_reg +#define eDX OP_REG, eDX_reg +#define eSP OP_REG, eSP_reg +#define eBP OP_REG, eBP_reg +#define eSI OP_REG, eSI_reg +#define eDI OP_REG, eDI_reg +#define AL OP_REG, al_reg +#define CL OP_REG, cl_reg +#define DL OP_REG, dl_reg +#define BL OP_REG, bl_reg +#define AH OP_REG, ah_reg +#define CH OP_REG, ch_reg +#define DH OP_REG, dh_reg +#define BH OP_REG, bh_reg +#define AX OP_REG, ax_reg +#define DX OP_REG, dx_reg +#define indirDX OP_REG, indir_dx_reg + +#define Sw OP_SEG, w_mode +#define Ap OP_DIR, lptr +#define Av OP_DIR, v_mode +#define Ob OP_OFF, b_mode +#define Ov OP_OFF, v_mode +#define Xb OP_DSSI, b_mode +#define Xv OP_DSSI, v_mode +#define Yb OP_ESDI, b_mode +#define Yv OP_ESDI, v_mode + +#define es OP_REG, es_reg +#define ss OP_REG, ss_reg +#define cs OP_REG, cs_reg +#define ds OP_REG, ds_reg +#define fs OP_REG, fs_reg +#define gs OP_REG, gs_reg + +int OP_E(), OP_indirE(), OP_G(), OP_I(), OP_sI(), OP_REG(); +int OP_J(), OP_SEG(); +int OP_DIR(), OP_OFF(), OP_DSSI(), OP_ESDI(), OP_ONE(), OP_C(); +int OP_D(), OP_T(), OP_rm(); + + +#define b_mode 1 +#define v_mode 2 +#define w_mode 3 +#define d_mode 4 + +#define es_reg 100 +#define cs_reg 101 +#define ss_reg 102 +#define ds_reg 103 +#define fs_reg 104 +#define gs_reg 105 +#define eAX_reg 107 +#define eCX_reg 108 +#define eDX_reg 109 +#define eBX_reg 110 +#define eSP_reg 111 +#define eBP_reg 112 +#define eSI_reg 113 +#define eDI_reg 114 + +#define lptr 115 + +#define al_reg 116 +#define cl_reg 117 +#define dl_reg 118 +#define bl_reg 119 +#define ah_reg 120 +#define ch_reg 121 +#define dh_reg 122 +#define bh_reg 123 + +#define ax_reg 124 +#define cx_reg 125 +#define dx_reg 126 +#define bx_reg 127 +#define sp_reg 128 +#define bp_reg 129 +#define si_reg 130 +#define di_reg 131 + +#define indir_dx_reg 150 + +#define GRP1b NULL, NULL, 0 +#define GRP1S NULL, NULL, 1 +#define GRP1Ss NULL, NULL, 2 +#define GRP2b NULL, NULL, 3 +#define GRP2S NULL, NULL, 4 +#define GRP2b_one NULL, NULL, 5 +#define GRP2S_one NULL, NULL, 6 +#define GRP2b_cl NULL, NULL, 7 +#define GRP2S_cl NULL, NULL, 8 +#define GRP3b NULL, NULL, 9 +#define GRP3S NULL, NULL, 10 +#define GRP4 NULL, NULL, 11 +#define GRP5 NULL, NULL, 12 +#define GRP6 NULL, NULL, 13 +#define GRP7 NULL, NULL, 14 +#define GRP8 NULL, NULL, 15 + +#define FLOATCODE 50 +#define FLOAT NULL, NULL, FLOATCODE + +struct dis386 { + char *name; + int (*op1)(); + int bytemode1; + int (*op2)(); + int bytemode2; + int (*op3)(); + int bytemode3; +}; + +struct dis386 dis386[] = { + /* 00 */ + { "addb", Eb, Gb }, + { "addS", Ev, Gv }, + { "addb", Gb, Eb }, + { "addS", Gv, Ev }, + { "addb", AL, Ib }, + { "addS", eAX, Iv }, + { "pushl", es }, + { "popl", es }, + /* 08 */ + { "orb", Eb, Gb }, + { "orS", Ev, Gv }, + { "orb", Gb, Eb }, + { "orS", Gv, Ev }, + { "orb", AL, Ib }, + { "orS", eAX, Iv }, + { "pushl", cs }, + { "(bad)" }, /* 0x0f extended opcode escape */ + /* 10 */ + { "adcb", Eb, Gb }, + { "adcS", Ev, Gv }, + { "adcb", Gb, Eb }, + { "adcS", Gv, Ev }, + { "adcb", AL, Ib }, + { "adcS", eAX, Iv }, + { "pushl", ss }, + { "popl", ss }, + /* 18 */ + { "sbbb", Eb, Gb }, + { "sbbS", Ev, Gv }, + { "sbbb", Gb, Eb }, + { "sbbS", Gv, Ev }, + { "sbbb", AL, Ib }, + { "sbbS", eAX, Iv }, + { "pushl", ds }, + { "popl", ds }, + /* 20 */ + { "andb", Eb, Gb }, + { "andS", Ev, Gv }, + { "andb", Gb, Eb }, + { "andS", Gv, Ev }, + { "andb", AL, Ib }, + { "andS", eAX, Iv }, + { "(bad)" }, /* SEG ES prefix */ + { "daa" }, + /* 28 */ + { "subb", Eb, Gb }, + { "subS", Ev, Gv }, + { "subb", Gb, Eb }, + { "subS", Gv, Ev }, + { "subb", AL, Ib }, + { "subS", eAX, Iv }, + { "(bad)" }, /* SEG CS prefix */ + { "das" }, + /* 30 */ + { "xorb", Eb, Gb }, + { "xorS", Ev, Gv }, + { "xorb", Gb, Eb }, + { "xorS", Gv, Ev }, + { "xorb", AL, Ib }, + { "xorS", eAX, Iv }, + { "(bad)" }, /* SEG SS prefix */ + { "aaa" }, + /* 38 */ + { "cmpb", Eb, Gb }, + { "cmpS", Ev, Gv }, + { "cmpb", Gb, Eb }, + { "cmpS", Gv, Ev }, + { "cmpb", AL, Ib }, + { "cmpS", eAX, Iv }, + { "(bad)" }, /* SEG DS prefix */ + { "aas" }, + /* 40 */ + { "incS", eAX }, + { "incS", eCX }, + { "incS", eDX }, + { "incS", eBX }, + { "incS", eSP }, + { "incS", eBP }, + { "incS", eSI }, + { "incS", eDI }, + /* 48 */ + { "decS", eAX }, + { "decS", eCX }, + { "decS", eDX }, + { "decS", eBX }, + { "decS", eSP }, + { "decS", eBP }, + { "decS", eSI }, + { "decS", eDI }, + /* 50 */ + { "pushS", eAX }, + { "pushS", eCX }, + { "pushS", eDX }, + { "pushS", eBX }, + { "pushS", eSP }, + { "pushS", eBP }, + { "pushS", eSI }, + { "pushS", eDI }, + /* 58 */ + { "popS", eAX }, + { "popS", eCX }, + { "popS", eDX }, + { "popS", eBX }, + { "popS", eSP }, + { "popS", eBP }, + { "popS", eSI }, + { "popS", eDI }, + /* 60 */ + { "pusha" }, + { "popa" }, + { "boundS", Gv, Ma }, + { "arpl", Ew, Gw }, + { "(bad)" }, /* seg fs */ + { "(bad)" }, /* seg gs */ + { "(bad)" }, /* op size prefix */ + { "(bad)" }, /* adr size prefix */ + /* 68 */ + { "pushS", Iv }, /* 386 book wrong */ + { "imulS", Gv, Ev, Iv }, + { "pushl", sIb }, /* push of byte really pushes 4 bytes */ + { "imulS", Gv, Ev, Ib }, + { "insb", Yb, indirDX }, + { "insS", Yv, indirDX }, + { "outsb", indirDX, Xb }, + { "outsS", indirDX, Xv }, + /* 70 */ + { "jo", Jb }, + { "jno", Jb }, + { "jb", Jb }, + { "jae", Jb }, + { "je", Jb }, + { "jne", Jb }, + { "jbe", Jb }, + { "ja", Jb }, + /* 78 */ + { "js", Jb }, + { "jns", Jb }, + { "jp", Jb }, + { "jnp", Jb }, + { "jl", Jb }, + { "jnl", Jb }, + { "jle", Jb }, + { "jg", Jb }, + /* 80 */ + { GRP1b }, + { GRP1S }, + { "(bad)" }, + { GRP1Ss }, + { "testb", Eb, Gb }, + { "testS", Ev, Gv }, + { "xchgb", Eb, Gb }, + { "xchgS", Ev, Gv }, + /* 88 */ + { "movb", Eb, Gb }, + { "movS", Ev, Gv }, + { "movb", Gb, Eb }, + { "movS", Gv, Ev }, + { "movw", Ew, Sw }, + { "leaS", Gv, M }, + { "movw", Sw, Ew }, + { "popS", Ev }, + /* 90 */ + { "nop" }, + { "xchgS", eCX, eAX }, + { "xchgS", eDX, eAX }, + { "xchgS", eBX, eAX }, + { "xchgS", eSP, eAX }, + { "xchgS", eBP, eAX }, + { "xchgS", eSI, eAX }, + { "xchgS", eDI, eAX }, + /* 98 */ + { "cwtl" }, + { "cltd" }, + { "lcall", Ap }, + { "(bad)" }, /* fwait */ + { "pushf" }, + { "popf" }, + { "sahf" }, + { "lahf" }, + /* a0 */ + { "movb", AL, Ob }, + { "movS", eAX, Ov }, + { "movb", Ob, AL }, + { "movS", Ov, eAX }, + { "movsb", Yb, Xb }, + { "movsS", Yv, Xv }, + { "cmpsb", Yb, Xb }, + { "cmpsS", Yv, Xv }, + /* a8 */ + { "testb", AL, Ib }, + { "testS", eAX, Iv }, + { "stosb", Yb, AL }, + { "stosS", Yv, eAX }, + { "lodsb", AL, Xb }, + { "lodsS", eAX, Xv }, + { "scasb", AL, Xb }, + { "scasS", eAX, Xv }, + /* b0 */ + { "movb", AL, Ib }, + { "movb", CL, Ib }, + { "movb", DL, Ib }, + { "movb", BL, Ib }, + { "movb", AH, Ib }, + { "movb", CH, Ib }, + { "movb", DH, Ib }, + { "movb", BH, Ib }, + /* b8 */ + { "movS", eAX, Iv }, + { "movS", eCX, Iv }, + { "movS", eDX, Iv }, + { "movS", eBX, Iv }, + { "movS", eSP, Iv }, + { "movS", eBP, Iv }, + { "movS", eSI, Iv }, + { "movS", eDI, Iv }, + /* c0 */ + { GRP2b }, + { GRP2S }, + { "ret", Iw }, + { "ret" }, + { "lesS", Gv, Mp }, + { "ldsS", Gv, Mp }, + { "movb", Eb, Ib }, + { "movS", Ev, Iv }, + /* c8 */ + { "enter", Iw, Ib }, + { "leave" }, + { "lret", Iw }, + { "lret" }, + { "int3" }, + { "int", Ib }, + { "into" }, + { "iret" }, + /* d0 */ + { GRP2b_one }, + { GRP2S_one }, + { GRP2b_cl }, + { GRP2S_cl }, + { "aam", Ib }, + { "aad", Ib }, + { "(bad)" }, + { "xlat" }, + /* d8 */ + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + /* e0 */ + { "loopne", Jb }, + { "loope", Jb }, + { "loop", Jb }, + { "jCcxz", Jb }, + { "inb", AL, Ib }, + { "inS", eAX, Ib }, + { "outb", Ib, AL }, + { "outS", Ib, eAX }, + /* e8 */ + { "call", Av }, + { "jmp", Jv }, + { "ljmp", Ap }, + { "jmp", Jb }, + { "inb", AL, indirDX }, + { "inS", eAX, indirDX }, + { "outb", indirDX, AL }, + { "outS", indirDX, eAX }, + /* f0 */ + { "(bad)" }, /* lock prefix */ + { "(bad)" }, + { "(bad)" }, /* repne */ + { "(bad)" }, /* repz */ + { "hlt" }, + { "cmc" }, + { GRP3b }, + { GRP3S }, + /* f8 */ + { "clc" }, + { "stc" }, + { "cli" }, + { "sti" }, + { "cld" }, + { "std" }, + { GRP4 }, + { GRP5 }, +}; + +struct dis386 dis386_twobyte[] = { + /* 00 */ + { GRP6 }, + { GRP7 }, + { "larS", Gv, Ew }, + { "lslS", Gv, Ew }, + { "(bad)" }, + { "(bad)" }, + { "clts" }, + { "(bad)" }, + /* 08 */ + { "invd" }, + { "wbinvd" }, + { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 10 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 18 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 20 */ + /* these are all backward in appendix A of the intel book */ + { "movl", Rd, Cd }, + { "movl", Rd, Dd }, + { "movl", Cd, Rd }, + { "movl", Dd, Rd }, + { "movl", Rd, Td }, + { "(bad)" }, + { "movl", Td, Rd }, + { "(bad)" }, + /* 28 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 30 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 38 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 40 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 48 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 50 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 58 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 60 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 68 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 70 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 78 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* 80 */ + { "jo", Jv }, + { "jno", Jv }, + { "jb", Jv }, + { "jae", Jv }, + { "je", Jv }, + { "jne", Jv }, + { "jbe", Jv }, + { "ja", Jv }, + /* 88 */ + { "js", Jv }, + { "jns", Jv }, + { "jp", Jv }, + { "jnp", Jv }, + { "jl", Jv }, + { "jge", Jv }, + { "jle", Jv }, + { "jg", Jv }, + /* 90 */ + { "seto", Eb }, + { "setno", Eb }, + { "setb", Eb }, + { "setae", Eb }, + { "sete", Eb }, + { "setne", Eb }, + { "setbe", Eb }, + { "seta", Eb }, + /* 98 */ + { "sets", Eb }, + { "setns", Eb }, + { "setp", Eb }, + { "setnp", Eb }, + { "setl", Eb }, + { "setge", Eb }, + { "setle", Eb }, + { "setg", Eb }, + /* a0 */ + { "pushl", fs }, + { "popl", fs }, + { "cpuid" }, + { "btS", Ev, Gv }, + { "shldS", Ev, Gv, Ib }, + { "shldS", Ev, Gv, CL }, + { "(bad)" }, + { "(bad)" }, + /* a8 */ + { "pushl", gs }, + { "popl", gs }, + { "(bad)" }, + { "btsS", Ev, Gv }, + { "shrdS", Ev, Gv, Ib }, + { "shrdS", Ev, Gv, CL }, + { "(bad)" }, + { "imulS", Gv, Ev }, + /* b0 */ + { "cmpxchgb", Eb, Gb }, + { "cmpxchgS", Ev, Gv }, + { "lssS", Gv, Mp }, /* 386 lists only Mp */ + { "btrS", Ev, Gv }, + { "lfsS", Gv, Mp }, /* 386 lists only Mp */ + { "lgsS", Gv, Mp }, /* 386 lists only Mp */ + { "movzbS", Gv, Eb }, + { "movzwS", Gv, Ew }, + /* b8 */ + { "(bad)" }, + { "(bad)" }, + { GRP8 }, + { "btcS", Ev, Gv }, + { "bsfS", Gv, Ev }, + { "bsrS", Gv, Ev }, + { "movsbS", Gv, Eb }, + { "movswS", Gv, Ew }, + /* c0 */ + { "xaddb", Eb, Gb }, + { "xaddS", Ev, Gv }, + { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* c8 */ + { "bswap", eAX }, + { "bswap", eCX }, + { "bswap", eDX }, + { "bswap", eBX }, + { "bswap", eSP }, + { "bswap", eBP }, + { "bswap", eSI }, + { "bswap", eDI }, + /* d0 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* d8 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* e0 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* e8 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* f0 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + /* f8 */ + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, + { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" }, +}; + +static char obuf[100]; +static char *obufp; +static char scratchbuf[100]; +static unsigned char *start_codep; +static unsigned char *codep; +static int mod; +static int rm; +static int reg; +static void oappend (); + +static char *names32[]={ + "%eax","%ecx","%edx","%ebx", "%esp","%ebp","%esi","%edi", +}; +static char *names16[] = { + "%ax","%cx","%dx","%bx","%sp","%bp","%si","%di", +}; +static char *names8[] = { + "%al","%cl","%dl","%bl","%ah","%ch","%dh","%bh", +}; +static char *names_seg[] = { + "%es","%cs","%ss","%ds","%fs","%gs","%?","%?", +}; + +struct dis386 grps[][8] = { + /* GRP1b */ + { + { "addb", Eb, Ib }, + { "orb", Eb, Ib }, + { "adcb", Eb, Ib }, + { "sbbb", Eb, Ib }, + { "andb", Eb, Ib }, + { "subb", Eb, Ib }, + { "xorb", Eb, Ib }, + { "cmpb", Eb, Ib } + }, + /* GRP1S */ + { + { "addS", Ev, Iv }, + { "orS", Ev, Iv }, + { "adcS", Ev, Iv }, + { "sbbS", Ev, Iv }, + { "andS", Ev, Iv }, + { "subS", Ev, Iv }, + { "xorS", Ev, Iv }, + { "cmpS", Ev, Iv } + }, + /* GRP1Ss */ + { + { "addS", Ev, sIb }, + { "orS", Ev, sIb }, + { "adcS", Ev, sIb }, + { "sbbS", Ev, sIb }, + { "andS", Ev, sIb }, + { "subS", Ev, sIb }, + { "xorS", Ev, sIb }, + { "cmpS", Ev, sIb } + }, + /* GRP2b */ + { + { "rolb", Eb, Ib }, + { "rorb", Eb, Ib }, + { "rclb", Eb, Ib }, + { "rcrb", Eb, Ib }, + { "shlb", Eb, Ib }, + { "shrb", Eb, Ib }, + { "(bad)" }, + { "sarb", Eb, Ib }, + }, + /* GRP2S */ + { + { "rolS", Ev, Ib }, + { "rorS", Ev, Ib }, + { "rclS", Ev, Ib }, + { "rcrS", Ev, Ib }, + { "shlS", Ev, Ib }, + { "shrS", Ev, Ib }, + { "(bad)" }, + { "sarS", Ev, Ib }, + }, + /* GRP2b_one */ + { + { "rolb", Eb }, + { "rorb", Eb }, + { "rclb", Eb }, + { "rcrb", Eb }, + { "shlb", Eb }, + { "shrb", Eb }, + { "(bad)" }, + { "sarb", Eb }, + }, + /* GRP2S_one */ + { + { "rolS", Ev }, + { "rorS", Ev }, + { "rclS", Ev }, + { "rcrS", Ev }, + { "shlS", Ev }, + { "shrS", Ev }, + { "(bad)" }, + { "sarS", Ev }, + }, + /* GRP2b_cl */ + { + { "rolb", Eb, CL }, + { "rorb", Eb, CL }, + { "rclb", Eb, CL }, + { "rcrb", Eb, CL }, + { "shlb", Eb, CL }, + { "shrb", Eb, CL }, + { "(bad)" }, + { "sarb", Eb, CL }, + }, + /* GRP2S_cl */ + { + { "rolS", Ev, CL }, + { "rorS", Ev, CL }, + { "rclS", Ev, CL }, + { "rcrS", Ev, CL }, + { "shlS", Ev, CL }, + { "shrS", Ev, CL }, + { "(bad)" }, + { "sarS", Ev, CL } + }, + /* GRP3b */ + { + { "testb", Eb, Ib }, + { "(bad)", Eb }, + { "notb", Eb }, + { "negb", Eb }, + { "mulb", AL, Eb }, + { "imulb", AL, Eb }, + { "divb", AL, Eb }, + { "idivb", AL, Eb } + }, + /* GRP3S */ + { + { "testS", Ev, Iv }, + { "(bad)" }, + { "notS", Ev }, + { "negS", Ev }, + { "mulS", eAX, Ev }, + { "imulS", eAX, Ev }, + { "divS", eAX, Ev }, + { "idivS", eAX, Ev }, + }, + /* GRP4 */ + { + { "incb", Eb }, + { "decb", Eb }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + }, + /* GRP5 */ + { + { "incS", Ev }, + { "decS", Ev }, + { "call", indirEv }, + { "lcall", indirEv }, + { "jmp", indirEv }, + { "ljmp", indirEv }, + { "pushS", Ev }, + { "(bad)" }, + }, + /* GRP6 */ + { + { "sldt", Ew }, + { "str", Ew }, + { "lldt", Ew }, + { "ltr", Ew }, + { "verr", Ew }, + { "verw", Ew }, + { "(bad)" }, + { "(bad)" } + }, + /* GRP7 */ + { + { "sgdt", Ew }, + { "sidt", Ew }, + { "lgdt", Ew }, + { "lidt", Ew }, + { "smsw", Ew }, + { "(bad)" }, + { "lmsw", Ew }, + { "invlpg", Ew }, + }, + /* GRP8 */ + { + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "btS", Ev, Ib }, + { "btsS", Ev, Ib }, + { "btrS", Ev, Ib }, + { "btcS", Ev, Ib }, + } +}; + +#define PREFIX_REPZ 1 +#define PREFIX_REPNZ 2 +#define PREFIX_LOCK 4 +#define PREFIX_CS 8 +#define PREFIX_SS 0x10 +#define PREFIX_DS 0x20 +#define PREFIX_ES 0x40 +#define PREFIX_FS 0x80 +#define PREFIX_GS 0x100 +#define PREFIX_DATA 0x200 +#define PREFIX_ADR 0x400 +#define PREFIX_FWAIT 0x800 + +static int prefixes; + +ckprefix () +{ + prefixes = 0; + while (1) + { + switch (*codep) + { + case 0xf3: + prefixes |= PREFIX_REPZ; + break; + case 0xf2: + prefixes |= PREFIX_REPNZ; + break; + case 0xf0: + prefixes |= PREFIX_LOCK; + break; + case 0x2e: + prefixes |= PREFIX_CS; + break; + case 0x36: + prefixes |= PREFIX_SS; + break; + case 0x3e: + prefixes |= PREFIX_DS; + break; + case 0x26: + prefixes |= PREFIX_ES; + break; + case 0x64: + prefixes |= PREFIX_FS; + break; + case 0x65: + prefixes |= PREFIX_GS; + break; + case 0x66: + prefixes |= PREFIX_DATA; + break; + case 0x67: + prefixes |= PREFIX_ADR; + break; + case 0x9b: + prefixes |= PREFIX_FWAIT; + break; + default: + return; + } + codep++; + } +} + +static int dflag; +static int aflag; + +static char op1out[100], op2out[100], op3out[100]; +static int op_address[3], op_ad, op_index[3]; +static int start_pc; + + +/* + * disassemble the first instruction in 'inbuf'. You have to make + * sure all of the bytes of the instruction are filled in. + * On the 386's of 1988, the maximum length of an instruction is 15 bytes. + * (see topic "Redundant prefixes" in the "Differences from 8086" + * section of the "Virtual 8086 Mode" chapter.) + * 'pc' should be the address of this instruction, it will + * be used to print the target address if this is a relative jump or call + * 'outbuf' gets filled in with the disassembled instruction. it should + * be long enough to hold the longest disassembled instruction. + * 100 bytes is certainly enough, unless symbol printing is added later + * The function returns the length of this instruction in bytes. + */ +i386dis (pc, inbuf, stream) + int pc; + unsigned char *inbuf; + FILE *stream; +{ + struct dis386 *dp; + char *p; + int i; + int enter_instruction; + char *first, *second, *third; + int needcomma; + + obuf[0] = 0; + op1out[0] = 0; + op2out[0] = 0; + op3out[0] = 0; + + op_index[0] = op_index[1] = op_index[2] = -1; + + start_pc = pc; + start_codep = inbuf; + codep = inbuf; + + ckprefix (); + + if (*codep == 0xc8) + enter_instruction = 1; + else + enter_instruction = 0; + + obufp = obuf; + + if (prefixes & PREFIX_REPZ) + oappend ("repz "); + if (prefixes & PREFIX_REPNZ) + oappend ("repnz "); + if (prefixes & PREFIX_LOCK) + oappend ("lock "); + + if ((prefixes & PREFIX_FWAIT) + && ((*codep < 0xd8) || (*codep > 0xdf))) + { + /* fwait not followed by floating point instruction */ + fputs ("fwait", stream); + return (1); + } + + /* these would be initialized to 0 if disassembling for 8086 or 286 */ + dflag = 1; + aflag = 1; + + if (prefixes & PREFIX_DATA) + dflag ^= 1; + + if (prefixes & PREFIX_ADR) + { + aflag ^= 1; + oappend ("addr16 "); + } + + if (*codep == 0x0f) + dp = &dis386_twobyte[*++codep]; + else + dp = &dis386[*codep]; + codep++; + mod = (*codep >> 6) & 3; + reg = (*codep >> 3) & 7; + rm = *codep & 7; + + if (dp->name == NULL && dp->bytemode1 == FLOATCODE) + { + dofloat (); + } + else + { + if (dp->name == NULL) + dp = &grps[dp->bytemode1][reg]; + + putop (dp->name); + + obufp = op1out; + op_ad = 2; + if (dp->op1) + (*dp->op1)(dp->bytemode1); + + obufp = op2out; + op_ad = 1; + if (dp->op2) + (*dp->op2)(dp->bytemode2); + + obufp = op3out; + op_ad = 0; + if (dp->op3) + (*dp->op3)(dp->bytemode3); + } + + obufp = obuf + strlen (obuf); + for (i = strlen (obuf); i < 6; i++) + oappend (" "); + oappend (" "); + fputs (obuf, stream); + + /* enter instruction is printed with operands in the + * same order as the intel book; everything else + * is printed in reverse order + */ + if (enter_instruction) + { + first = op1out; + second = op2out; + third = op3out; + op_ad = op_index[0]; + op_index[0] = op_index[2]; + op_index[2] = op_ad; + } + else + { + first = op3out; + second = op2out; + third = op1out; + } + needcomma = 0; + if (*first) + { + if (op_index[0] != -1) + print_address (op_address[op_index[0]], stream); + else + fputs (first, stream); + needcomma = 1; + } + if (*second) + { + if (needcomma) + fputs (",", stream); + if (op_index[1] != -1) + print_address (op_address[op_index[1]], stream); + else + fputs (second, stream); + needcomma = 1; + } + if (*third) + { + if (needcomma) + fputs (",", stream); + if (op_index[2] != -1) + print_address (op_address[op_index[2]], stream); + else + fputs (third, stream); + } + return (codep - inbuf); +} + +char *float_mem[] = { + /* d8 */ + "fadds", + "fmuls", + "fcoms", + "fcomps", + "fsubs", + "fsubrs", + "fdivs", + "fdivrs", + /* d9 */ + "flds", + "(bad)", + "fsts", + "fstps", + "fldenv", + "fldcw", + "fNstenv", + "fNstcw", + /* da */ + "fiaddl", + "fimull", + "ficoml", + "ficompl", + "fisubl", + "fisubrl", + "fidivl", + "fidivrl", + /* db */ + "fildl", + "(bad)", + "fistl", + "fistpl", + "(bad)", + "fldt", + "(bad)", + "fstpt", + /* dc */ + "faddl", + "fmull", + "fcoml", + "fcompl", + "fsubl", + "fsubrl", + "fdivl", + "fdivrl", + /* dd */ + "fldl", + "(bad)", + "fstl", + "fstpl", + "frstor", + "(bad)", + "fNsave", + "fNstsw", + /* de */ + "fiadd", + "fimul", + "ficom", + "ficomp", + "fisub", + "fisubr", + "fidiv", + "fidivr", + /* df */ + "fild", + "(bad)", + "fist", + "fistp", + "fbld", + "fildll", + "fbstp", + "fistpll", +}; + +#define ST OP_ST, 0 +#define STi OP_STi, 0 +int OP_ST(), OP_STi(); + +#define FGRPd9_2 NULL, NULL, 0 +#define FGRPd9_4 NULL, NULL, 1 +#define FGRPd9_5 NULL, NULL, 2 +#define FGRPd9_6 NULL, NULL, 3 +#define FGRPd9_7 NULL, NULL, 4 +#define FGRPda_5 NULL, NULL, 5 +#define FGRPdb_4 NULL, NULL, 6 +#define FGRPde_3 NULL, NULL, 7 +#define FGRPdf_4 NULL, NULL, 8 + +struct dis386 float_reg[][8] = { + /* d8 */ + { + { "fadd", ST, STi }, + { "fmul", ST, STi }, + { "fcom", STi }, + { "fcomp", STi }, + { "fsub", ST, STi }, + { "fsubr", ST, STi }, + { "fdiv", ST, STi }, + { "fdivr", ST, STi }, + }, + /* d9 */ + { + { "fld", STi }, + { "fxch", STi }, + { FGRPd9_2 }, + { "(bad)" }, + { FGRPd9_4 }, + { FGRPd9_5 }, + { FGRPd9_6 }, + { FGRPd9_7 }, + }, + /* da */ + { + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { FGRPda_5 }, + { "(bad)" }, + { "(bad)" }, + }, + /* db */ + { + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { FGRPdb_4 }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + }, + /* dc */ + { + { "fadd", STi, ST }, + { "fmul", STi, ST }, + { "(bad)" }, + { "(bad)" }, + { "fsub", STi, ST }, + { "fsubr", STi, ST }, + { "fdiv", STi, ST }, + { "fdivr", STi, ST }, + }, + /* dd */ + { + { "ffree", STi }, + { "(bad)" }, + { "fst", STi }, + { "fstp", STi }, + { "fucom", STi }, + { "fucomp", STi }, + { "(bad)" }, + { "(bad)" }, + }, + /* de */ + { + { "faddp", STi, ST }, + { "fmulp", STi, ST }, + { "(bad)" }, + { FGRPde_3 }, + { "fsubp", STi, ST }, + { "fsubrp", STi, ST }, + { "fdivp", STi, ST }, + { "fdivrp", STi, ST }, + }, + /* df */ + { + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + { FGRPdf_4 }, + { "(bad)" }, + { "(bad)" }, + { "(bad)" }, + }, +}; + + +char *fgrps[][8] = { + /* d9_2 0 */ + { + "fnop","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* d9_4 1 */ + { + "fchs","fabs","(bad)","(bad)","ftst","fxam","(bad)","(bad)", + }, + + /* d9_5 2 */ + { + "fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","(bad)", + }, + + /* d9_6 3 */ + { + "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp", + }, + + /* d9_7 4 */ + { + "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos", + }, + + /* da_5 5 */ + { + "(bad)","fucompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* db_4 6 */ + { + "feni(287 only)","fdisi(287 only)","fNclex","fNinit", + "fNsetpm(287 only)","(bad)","(bad)","(bad)", + }, + + /* de_3 7 */ + { + "(bad)","fcompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* df_4 8 */ + { + "fNstsw","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, +}; + + +dofloat () +{ + struct dis386 *dp; + unsigned char floatop; + + floatop = codep[-1]; + + if (mod != 3) + { + putop (float_mem[(floatop - 0xd8) * 8 + reg]); + obufp = op1out; + OP_E (v_mode); + return; + } + codep++; + + dp = &float_reg[floatop - 0xd8][reg]; + if (dp->name == NULL) + { + putop (fgrps[dp->bytemode1][rm]); + /* instruction fnstsw is only one with strange arg */ + if (floatop == 0xdf && *codep == 0xe0) + strcpy (op1out, "%eax"); + } + else + { + putop (dp->name); + obufp = op1out; + if (dp->op1) + (*dp->op1)(dp->bytemode1); + obufp = op2out; + if (dp->op2) + (*dp->op2)(dp->bytemode2); + } +} + +/* ARGSUSED */ +OP_ST (ignore) +{ + oappend ("%st"); +} + +/* ARGSUSED */ +OP_STi (ignore) +{ + sprintf (scratchbuf, "%%st(%d)", rm); + oappend (scratchbuf); +} + + +/* capital letters in template are macros */ +putop (template) + char *template; +{ + char *p; + + for (p = template; *p; p++) + { + switch (*p) + { + default: + *obufp++ = *p; + break; + case 'C': /* For jcxz/jecxz */ + if (aflag == 0) + *obufp++ = 'e'; + break; + case 'N': + if ((prefixes & PREFIX_FWAIT) == 0) + *obufp++ = 'n'; + break; + case 'S': + /* operand size flag */ + if (dflag) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + break; + } + } + *obufp = 0; +} + +static void +oappend (s) +char *s; +{ + strcpy (obufp, s); + obufp += strlen (s); + *obufp = 0; +} + +append_prefix () +{ + if (prefixes & PREFIX_CS) + oappend ("%cs:"); + if (prefixes & PREFIX_DS) + oappend ("%ds:"); + if (prefixes & PREFIX_SS) + oappend ("%ss:"); + if (prefixes & PREFIX_ES) + oappend ("%es:"); + if (prefixes & PREFIX_FS) + oappend ("%fs:"); + if (prefixes & PREFIX_GS) + oappend ("%gs:"); +} + +OP_indirE (bytemode) +{ + oappend ("*"); + OP_E (bytemode); +} + +OP_E (bytemode) +{ + int disp; + int havesib; + int didoutput = 0; + int base; + int index; + int scale; + int havebase; + + /* skip mod/rm byte */ + codep++; + + havesib = 0; + havebase = 0; + disp = 0; + + if (mod == 3) + { + switch (bytemode) + { + case b_mode: + oappend (names8[rm]); + break; + case w_mode: + oappend (names16[rm]); + break; + case v_mode: + if (dflag) + oappend (names32[rm]); + else + oappend (names16[rm]); + break; + default: + oappend ("<bad dis table>"); + break; + } + return; + } + + append_prefix (); + if (rm == 4) + { + havesib = 1; + havebase = 1; + scale = (*codep >> 6) & 3; + index = (*codep >> 3) & 7; + base = *codep & 7; + codep++; + } + + switch (mod) + { + case 0: + switch (rm) + { + case 4: + /* implies havesib and havebase */ + if (base == 5) { + havebase = 0; + disp = get32 (); + } + break; + case 5: + disp = get32 (); + break; + default: + havebase = 1; + base = rm; + break; + } + break; + case 1: + disp = *(char *)codep++; + if (rm != 4) + { + havebase = 1; + base = rm; + } + break; + case 2: + disp = get32 (); + if (rm != 4) + { + havebase = 1; + base = rm; + } + break; + } + + if (mod != 0 || rm == 5 || (havesib && base == 5)) + { + sprintf (scratchbuf, "0x%x", disp); + oappend (scratchbuf); + } + + if (havebase || havesib) + { + oappend ("("); + if (havebase) + oappend (names32[base]); + if (havesib) + { + if (index != 4) + { + sprintf (scratchbuf, ",%s", names32[index]); + oappend (scratchbuf); + } + sprintf (scratchbuf, ",%d", 1 << scale); + oappend (scratchbuf); + } + oappend (")"); + } +} + +OP_G (bytemode) +{ + switch (bytemode) + { + case b_mode: + oappend (names8[reg]); + break; + case w_mode: + oappend (names16[reg]); + break; + case d_mode: + oappend (names32[reg]); + break; + case v_mode: + if (dflag) + oappend (names32[reg]); + else + oappend (names16[reg]); + break; + default: + oappend ("<internal disassembler error>"); + break; + } +} + +get32 () +{ + int x = 0; + + x = *codep++ & 0xff; + x |= (*codep++ & 0xff) << 8; + x |= (*codep++ & 0xff) << 16; + x |= (*codep++ & 0xff) << 24; + return (x); +} + +get16 () +{ + int x = 0; + + x = *codep++ & 0xff; + x |= (*codep++ & 0xff) << 8; + return (x); +} + +set_op (op) +int op; +{ + op_index[op_ad] = op_ad; + op_address[op_ad] = op; +} + +OP_REG (code) +{ + char *s; + + switch (code) + { + case indir_dx_reg: s = "(%dx)"; break; + case ax_reg: case cx_reg: case dx_reg: case bx_reg: + case sp_reg: case bp_reg: case si_reg: case di_reg: + s = names16[code - ax_reg]; + break; + case es_reg: case ss_reg: case cs_reg: + case ds_reg: case fs_reg: case gs_reg: + s = names_seg[code - es_reg]; + break; + case al_reg: case ah_reg: case cl_reg: case ch_reg: + case dl_reg: case dh_reg: case bl_reg: case bh_reg: + s = names8[code - al_reg]; + break; + case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg: + case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg: + if (dflag) + s = names32[code - eAX_reg]; + else + s = names16[code - eAX_reg]; + break; + default: + s = "<internal disassembler error>"; + break; + } + oappend (s); +} + +OP_I (bytemode) +{ + int op; + + switch (bytemode) + { + case b_mode: + op = *codep++ & 0xff; + break; + case v_mode: + if (dflag) + op = get32 (); + else + op = get16 (); + break; + case w_mode: + op = get16 (); + break; + default: + oappend ("<internal disassembler error>"); + return; + } + sprintf (scratchbuf, "$0x%x", op); + oappend (scratchbuf); +} + +OP_sI (bytemode) +{ + int op; + + switch (bytemode) + { + case b_mode: + op = *(char *)codep++; + break; + case v_mode: + if (dflag) + op = get32 (); + else + op = (short)get16(); + break; + case w_mode: + op = (short)get16 (); + break; + default: + oappend ("<internal disassembler error>"); + return; + } + sprintf (scratchbuf, "$0x%x", op); + oappend (scratchbuf); +} + +OP_J (bytemode) +{ + int disp; + int mask = -1; + + switch (bytemode) + { + case b_mode: + disp = *(char *)codep++; + break; + case v_mode: + if (dflag) + disp = get32 (); + else + { + disp = (short)get16 (); + /* for some reason, a data16 prefix on a jump instruction + means that the pc is masked to 16 bits after the + displacement is added! */ + mask = 0xffff; + } + break; + default: + oappend ("<internal disassembler error>"); + return; + } + disp = (start_pc + codep - start_codep + disp) & mask; + set_op (disp); + sprintf (scratchbuf, "0x%x", disp); + oappend (scratchbuf); +} + +/* ARGSUSED */ +OP_SEG (dummy) +{ + static char *sreg[] = { + "%es","%cs","%ss","%ds","%fs","%gs","%?","%?", + }; + + oappend (sreg[reg]); +} + +OP_DIR (size) +{ + int seg, offset; + + switch (size) + { + case lptr: + if (aflag) + { + offset = get32 (); + seg = get16 (); + } + else + { + offset = get16 (); + seg = get16 (); + } + sprintf (scratchbuf, "0x%x,0x%x", seg, offset); + oappend (scratchbuf); + break; + case v_mode: + if (aflag) + offset = get32 (); + else + offset = (short)get16 (); + + offset = start_pc + codep - start_codep + offset; + set_op (offset); + sprintf (scratchbuf, "0x%x", offset); + oappend (scratchbuf); + break; + default: + oappend ("<internal disassembler error>"); + break; + } +} + +/* ARGSUSED */ +OP_OFF (bytemode) +{ + int off; + + if (aflag) + off = get32 (); + else + off = get16 (); + + sprintf (scratchbuf, "0x%x", off); + oappend (scratchbuf); +} + +/* ARGSUSED */ +OP_ESDI (dummy) +{ + oappend ("%es:("); + oappend (aflag ? "%edi" : "%di"); + oappend (")"); +} + +/* ARGSUSED */ +OP_DSSI (dummy) +{ + oappend ("%ds:("); + oappend (aflag ? "%esi" : "%si"); + oappend (")"); +} + +/* ARGSUSED */ +OP_ONE (dummy) +{ + oappend ("1"); +} + +/* ARGSUSED */ +OP_C (dummy) +{ + codep++; /* skip mod/rm */ + sprintf (scratchbuf, "%%cr%d", reg); + oappend (scratchbuf); +} + +/* ARGSUSED */ +OP_D (dummy) +{ + codep++; /* skip mod/rm */ + sprintf (scratchbuf, "%%db%d", reg); + oappend (scratchbuf); +} + +/* ARGSUSED */ +OP_T (dummy) +{ + codep++; /* skip mod/rm */ + sprintf (scratchbuf, "%%tr%d", reg); + oappend (scratchbuf); +} + +OP_rm (bytemode) +{ + switch (bytemode) + { + case d_mode: + oappend (names32[rm]); + break; + case w_mode: + oappend (names16[rm]); + break; + } +} +#define MAXLEN 20 +#if 0 + +print_insn (memaddr, stream) + CORE_ADDR memaddr; + FILE *stream; +{ + unsigned char buffer[MAXLEN]; + + read_memory (memaddr, buffer, MAXLEN); + + return (i386dis ((int)memaddr, buffer, stream)); +} + +#endif + +int +print_insn_i386(memaddr, buffer, stream) +int memaddr; + char *buffer; + FILE *stream; +{ + + + return (i386dis ((int)memaddr, buffer, stream)); + + +} diff --git a/gnu/usr.bin/gdb/objdump/arch/m68k/Makefile.inc b/gnu/usr.bin/gdb/objdump/arch/m68k/Makefile.inc new file mode 100644 index 00000000000..47c4ad64fbe --- /dev/null +++ b/gnu/usr.bin/gdb/objdump/arch/m68k/Makefile.inc @@ -0,0 +1,8 @@ +# $Id: Makefile.inc,v 1.1 1995/10/18 08:40:14 deraadt Exp $ + +SRCS+= m68k-pinsn.c + +CFLAGS+= -DSELECT_ARCHITECTURES=bfd_arch_m68k \ + -DPRINT_INSN=print_insn_m68k + + diff --git a/gnu/usr.bin/gdb/objdump/arch/m68k/m68k-pinsn.c b/gnu/usr.bin/gdb/objdump/arch/m68k/m68k-pinsn.c new file mode 100644 index 00000000000..4040ae92b2d --- /dev/null +++ b/gnu/usr.bin/gdb/objdump/arch/m68k/m68k-pinsn.c @@ -0,0 +1,807 @@ +/* Print m68k instructions for objdump + Copyright (C) 1986, 1987, 1989, 1991 Free Software Foundation, Inc. + + +This file is part of the binutils. + +The binutils are 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 binutils are distributed in the hope that they 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. */ + + +#include "bfd.h" +#include "sysdep.h" +#include <stdio.h> +#include "opcode/m68k.h" + +#ifndef GDB +#define fprintf_filtered fprintf +#define fputs_filtered fputs +#endif + +/* Sign-extend an (unsigned char). */ +#if __STDC__ == 1 +#define COERCE_SIGNED_CHAR(ch) ((signed char)(ch)) +#else +#define COERCE_SIGNED_CHAR(ch) ((int)(((ch) ^ 0x80) & 0xFF) - 128) +#endif + +extern void print_address(); + +/* 68k instructions are never longer than this many bytes. */ +#define MAXLEN 22 + +/* Number of elements in the opcode table. */ +#define NOPCODES (sizeof m68k_opcodes / sizeof m68k_opcodes[0]) + +extern char *reg_names[]; +char *fpcr_names[] = { "", "fpiar", "fpsr", "fpiar/fpsr", "fpcr", + "fpiar/fpcr", "fpsr/fpcr", "fpiar/fpsr/fpcr"}; + +char *reg_names[] = {"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp", "ps", "pc"}; +static unsigned char *print_insn_arg (); +static unsigned char *print_indexed (); +static void print_base (); +static int fetch_arg (); + +#define NEXTBYTE(p) (p += 2, COERCE_SIGNED_CHAR(p[-1])) + +#define NEXTWORD(p) \ + (p += 2, ((((char *)p)[-2]) << 8) + p[-1]) + +#define NEXTLONG(p) \ + (p += 4, (((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1]) + +/* NEXTSINGLE and NEXTDOUBLE handle alignment problems, but not + * byte-swapping or other float format differences. FIXME! */ + +union number { + double d; + float f; + char c[10]; +}; + +#define NEXTSINGLE(val, p) \ + { int i; union number u;\ + for (i = 0; i < sizeof(float); i++) u.c[i] = *p++; \ + val = u.f; } + +#define NEXTDOUBLE(val, p) \ + { int i; union number u;\ + for (i = 0; i < sizeof(double); i++) u.c[i] = *p++; \ + val = u.d; } + +#define NEXTEXTEND(p) \ + (p += 12, 0.0) /* Need a function to convert from extended to double + precision... */ + +#define NEXTPACKED(p) \ + (p += 12, 0.0) /* Need a function to convert from packed to double + precision. Actually, it's easier to print a + packed number than a double anyway, so maybe + there should be a special case to handle this... */ + +/* Print the m68k instruction at address MEMADDR in debugged memory, + on STREAM. Returns length of the instruction, in bytes. */ + +int +print_insn_m68k(addr, buffer, stream) + bfd_vma addr; +unsigned char *buffer; + FILE *stream; +{ + register unsigned int i; + register unsigned char *p; + register char *d; + register unsigned int bestmask; + int best; + + + + bestmask = 0; + best = -1; + for (i = 0; i < NOPCODES; i++) + { + register unsigned int opcode = m68k_opcodes[i].opcode; + register unsigned int match = m68k_opcodes[i].match; + if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24))) + && ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16))) + && ((0xff & buffer[2] & (match >> 8)) == (0xff & (opcode >> 8))) + && ((0xff & buffer[3] & match) == (0xff & opcode))) + { + /* Don't use for printout the variants of divul and divsl + that have the same register number in two places. + The more general variants will match instead. */ + for (d = m68k_opcodes[i].args; *d; d += 2) + if (d[1] == 'D') + break; + + /* Don't use for printout the variants of most floating + point coprocessor instructions which use the same + register number in two places, as above. */ + if (*d == 0) + for (d = m68k_opcodes[i].args; *d; d += 2) + if (d[1] == 't') + break; + + if (*d == 0 && match > bestmask) + { + best = i; + bestmask = match; + } + } + } + + /* Handle undefined instructions. */ + if (best < 0) + { + fprintf_filtered (stream, "0%o", (unsigned) (buffer[0] << 8) + buffer[1]); + return 2; + } + + fprintf_filtered (stream, "%s", m68k_opcodes[best].name); + + /* Point at first word of argument data, + and at descriptor for first argument. */ + p = buffer + 2; + + /* Why do this this way? -MelloN */ + for (d = m68k_opcodes[best].args; *d; d += 2) + { + if (d[0] == '#') + { + if (d[1] == 'l' && p - buffer < 6) + p = buffer + 6; + else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8' ) + p = buffer + 4; + } + if (d[1] >= '1' && d[1] <= '3' && p - buffer < 4) + p = buffer + 4; + if (d[1] >= '4' && d[1] <= '6' && p - buffer < 6) + p = buffer + 6; + if ((d[0] == 'L' || d[0] == 'l') && d[1] == 'w' && p - buffer < 4) + p = buffer + 4; + } + + d = m68k_opcodes[best].args; + + if (*d) + fputs_filtered (" ", stream); + + while (*d) + { + p = print_insn_arg (d, buffer, p, addr + p - buffer, stream); + d += 2; + if (*d && *(d - 2) != 'I' && *d != 'k') + fputs_filtered (",", stream); + } + return p - buffer; +} + +static unsigned char * +print_insn_arg (d, buffer, p, addr, stream) + char *d; + unsigned char *buffer; + register unsigned char *p; + bfd_vma addr; /* PC for this arg to be relative to */ + FILE *stream; +{ + register int val = 0; + register int place = d[1]; + int regno; + register char *regname; + register unsigned char *p1; + register double flval = 0; + int flt_p; + + switch (*d) + { + case 'C': + fprintf_filtered (stream, "ccr"); + break; + + case 'S': + fprintf_filtered (stream, "sr"); + break; + + case 'U': + fprintf_filtered (stream, "usp"); + break; + + case 'J': + { + static struct { char *name; int value; } names[] + = {{"sfc", 0x000}, {"dfc", 0x001}, {"cacr", 0x002}, + {"usp", 0x800}, {"vbr", 0x801}, {"caar", 0x802}, + {"msp", 0x803}, {"isp", 0x804}}; + + val = fetch_arg (buffer, place, 12); + for (regno = sizeof names / sizeof names[0] - 1; regno >= 0; regno--) + if (names[regno].value == val) + { + fprintf_filtered (stream, names[regno].name); + break; + } + if (regno < 0) + fprintf_filtered (stream, "%d", val); + } + break; + + case 'Q': + val = fetch_arg (buffer, place, 3); + /* 0 means 8, except for the bkpt instruction... */ + if (val == 0 && d[1] != 's') + val = 8; + fprintf_filtered (stream, "#%d", val); + break; + + case 'M': + val = fetch_arg (buffer, place, 8); + if (val & 0x80) + val = val - 0x100; + fprintf_filtered (stream, "#%d", val); + break; + + case 'T': + val = fetch_arg (buffer, place, 4); + fprintf_filtered (stream, "#%d", val); + break; + + case 'D': + fprintf_filtered (stream, "%s", reg_names[fetch_arg (buffer, place, 3)]); + break; + + case 'A': + fprintf_filtered (stream, "%s", + reg_names[fetch_arg (buffer, place, 3) + 010]); + break; + + case 'R': + fprintf_filtered (stream, "%s", reg_names[fetch_arg (buffer, place, 4)]); + break; + + case 'r': + fprintf_filtered (stream, "%s@", reg_names[fetch_arg (buffer, place, 4)]); + break; + + case 'F': + fprintf_filtered (stream, "fp%d", fetch_arg (buffer, place, 3)); + break; + + case 'O': + val = fetch_arg (buffer, place, 6); + if (val & 0x20) + fprintf_filtered (stream, "%s", reg_names [val & 7]); + else + fprintf_filtered (stream, "%d", val); + break; + + case '+': + fprintf_filtered (stream, "%s@+", + reg_names[fetch_arg (buffer, place, 3) + 8]); + break; + + case '-': + fprintf_filtered (stream, "%s@-", + reg_names[fetch_arg (buffer, place, 3) + 8]); + break; + + case 'k': + if (place == 'k') + fprintf_filtered (stream, "{%s}", reg_names[fetch_arg (buffer, place, 3)]); + else if (place == 'C') + { + val = fetch_arg (buffer, place, 7); + if ( val > 63 ) /* This is a signed constant. */ + val -= 128; + fprintf_filtered (stream, "{#%d}", val); + } + else + fprintf_filtered(stderr, "Invalid arg format in opcode table: \"%c%c\".", + *d, place); + break; + + case '#': + case '^': + p1 = buffer + (*d == '#' ? 2 : 4); + if (place == 's') + val = fetch_arg (buffer, place, 4); + else if (place == 'C') + val = fetch_arg (buffer, place, 7); + else if (place == '8') + val = fetch_arg (buffer, place, 3); + else if (place == '3') + val = fetch_arg (buffer, place, 8); + else if (place == 'b') + val = NEXTBYTE (p1); + else if (place == 'w') + val = NEXTWORD (p1); + else if (place == 'l') + val = NEXTLONG (p1); + else + fprintf_filtered(stderr, "Invalid arg format in opcode table: \"%c%c\".", + *d, place); + fprintf_filtered (stream, "#%d", val); + break; + + case 'B': + if (place == 'b') + val = NEXTBYTE (p); + else if (place == 'B') + val = COERCE_SIGNED_CHAR(buffer[1]); + else if (place == 'w' || place == 'W') + val = NEXTWORD (p); + else if (place == 'l' || place == 'L') + val = NEXTLONG (p); + else if (place == 'g') + { + val = ((char *)buffer)[1]; + if (val == 0) + val = NEXTWORD (p); + else if (val == -1) + val = NEXTLONG (p); + } + else if (place == 'c') + { + if (buffer[1] & 0x40) /* If bit six is one, long offset */ + val = NEXTLONG (p); + else + val = NEXTWORD (p); + } + else + fprintf_filtered(stderr, "Invalid arg format in opcode table: \"%c%c\".", + *d, place); + print_address (addr + val, stream); + break; + + case 'd': + val = NEXTWORD (p); + fprintf_filtered (stream, "%s@(%d)", + reg_names[fetch_arg (buffer, place, 3)], val); + break; + + case 's': + fprintf_filtered (stream, "%s", + fpcr_names[fetch_arg (buffer, place, 3)]); + break; + + case 'I': + val = fetch_arg (buffer, 'd', 3); /* Get coprocessor ID... */ + if (val != 1) /* Unusual coprocessor ID? */ + fprintf_filtered (stream, "(cpid=%d) ", val); + if (place == 'i') + p += 2; /* Skip coprocessor extended operands */ + break; + + case '*': + case '~': + case '%': + case ';': + case '@': + case '!': + case '$': + case '?': + case '/': + case '&': + + if (place == 'd') + { + val = fetch_arg (buffer, 'x', 6); + val = ((val & 7) << 3) + ((val >> 3) & 7); + } + else + val = fetch_arg (buffer, 's', 6); + + /* Get register number assuming address register. */ + regno = (val & 7) + 8; + regname = reg_names[regno]; + switch (val >> 3) + { + case 0: + fprintf_filtered (stream, "%s", reg_names[val]); + break; + + case 1: + fprintf_filtered (stream, "%s", regname); + break; + + case 2: + fprintf_filtered (stream, "%s@", regname); + break; + + case 3: + fprintf_filtered (stream, "%s@+", regname); + break; + + case 4: + fprintf_filtered (stream, "%s@-", regname); + break; + + case 5: + val = NEXTWORD (p); + fprintf_filtered (stream, "%s@(%d)", regname, val); + break; + + case 6: + p = print_indexed (regno, p, addr, stream); + break; + + case 7: + switch (val & 7) + { + case 0: + val = NEXTWORD (p); + fprintf_filtered (stream, "@#"); + print_address (val, stream); + break; + + case 1: + val = NEXTLONG (p); + fprintf_filtered (stream, "@#"); + print_address (val, stream); + break; + + case 2: + val = NEXTWORD (p); + print_address (addr + val, stream); + break; + + case 3: + p = print_indexed (-1, p, addr, stream); + break; + + case 4: + flt_p = 1; /* Assume it's a float... */ + switch( place ) + { + case 'b': + val = NEXTBYTE (p); + flt_p = 0; + break; + + case 'w': + val = NEXTWORD (p); + flt_p = 0; + break; + + case 'l': + val = NEXTLONG (p); + flt_p = 0; + break; + + case 'f': + NEXTSINGLE(flval, p); + break; + + case 'F': + NEXTDOUBLE(flval, p); + break; + + case 'x': + flval = NEXTEXTEND(p); + break; + + case 'p': + flval = NEXTPACKED(p); + break; + + default: + fprintf_filtered(stderr, "Invalid arg format in opcode table: \"%c%c\".", + *d, place); + } + if ( flt_p ) /* Print a float? */ + fprintf_filtered (stream, "#%g", flval); + else + fprintf_filtered (stream, "#%d", val); + break; + + default: + fprintf_filtered (stream, "<invalid address mode 0%o>", (unsigned) val); + } + } + break; + + case 'L': + case 'l': + if (place == 'w') + { + char doneany; + p1 = buffer + 2; + val = NEXTWORD (p1); + /* Move the pointer ahead if this point is farther ahead + than the last. */ + p = p1 > p ? p1 : p; + if (val == 0) + { + fputs_filtered ("#0", stream); + break; + } + if (*d == 'l') + { + register int newval = 0; + for (regno = 0; regno < 16; ++regno) + if (val & (0x8000 >> regno)) + newval |= 1 << regno; + val = newval; + } + val &= 0xffff; + doneany = 0; + for (regno = 0; regno < 16; ++regno) + if (val & (1 << regno)) + { + int first_regno; + if (doneany) + fputs_filtered ("/", stream); + doneany = 1; + fprintf_filtered (stream, "%s", reg_names[regno]); + first_regno = regno; + while (val & (1 << (regno + 1))) + ++regno; + if (regno > first_regno) + fprintf_filtered (stream, "-%s", reg_names[regno]); + } + } + else if (place == '3') + { + /* `fmovem' insn. */ + char doneany; + val = fetch_arg (buffer, place, 8); + if (val == 0) + { + fputs_filtered ("#0", stream); + break; + } + if (*d == 'l') + { + register int newval = 0; + for (regno = 0; regno < 8; ++regno) + if (val & (0x80 >> regno)) + newval |= 1 << regno; + val = newval; + } + val &= 0xff; + doneany = 0; + for (regno = 0; regno < 8; ++regno) + if (val & (1 << regno)) + { + int first_regno; + if (doneany) + fputs_filtered ("/", stream); + doneany = 1; + fprintf_filtered (stream, "fp%d", regno); + first_regno = regno; + while (val & (1 << (regno + 1))) + ++regno; + if (regno > first_regno) + fprintf_filtered (stream, "-fp%d", regno); + } + } + else + goto de_fault; + break; + + default: de_fault: + fprintf_filtered(stderr, "Invalid arg format in opcode table: \"%c\".", *d); + } + + return (unsigned char *) p; +} + +/* Fetch BITS bits from a position in the instruction specified by CODE. + CODE is a "place to put an argument", or 'x' for a destination + that is a general address (mode and register). + BUFFER contains the instruction. */ + +static int +fetch_arg (buffer, code, bits) + unsigned char *buffer; + char code; + int bits; +{ + register int val = 0; + switch (code) + { + case 's': + val = buffer[1]; + break; + + case 'd': /* Destination, for register or quick. */ + val = (buffer[0] << 8) + buffer[1]; + val >>= 9; + break; + + case 'x': /* Destination, for general arg */ + val = (buffer[0] << 8) + buffer[1]; + val >>= 6; + break; + + case 'k': + val = (buffer[3] >> 4); + break; + + case 'C': + val = buffer[3]; + break; + + case '1': + val = (buffer[2] << 8) + buffer[3]; + val >>= 12; + break; + + case '2': + val = (buffer[2] << 8) + buffer[3]; + val >>= 6; + break; + + case '3': + case 'j': + val = (buffer[2] << 8) + buffer[3]; + break; + + case '4': + val = (buffer[4] << 8) + buffer[5]; + val >>= 12; + break; + + case '5': + val = (buffer[4] << 8) + buffer[5]; + val >>= 6; + break; + + case '6': + val = (buffer[4] << 8) + buffer[5]; + break; + + case '7': + val = (buffer[2] << 8) + buffer[3]; + val >>= 7; + break; + + case '8': + val = (buffer[2] << 8) + buffer[3]; + val >>= 10; + break; + + default: + abort (); + } + + switch (bits) + { + case 3: + return val & 7; + case 4: + return val & 017; + case 5: + return val & 037; + case 6: + return val & 077; + case 7: + return val & 0177; + case 8: + return val & 0377; + case 12: + return val & 07777; + default: + abort (); + return(0); + } +} /* fetch_arg() */ + +/* Print an indexed argument. The base register is BASEREG (-1 for pc). + P points to extension word, in buffer. + ADDR is the nominal core address of that extension word. */ + +static unsigned char * +print_indexed (basereg, p, addr, stream) + int basereg; + unsigned char *p; + FILE *stream; +bfd_vma addr; +{ + register int word; + static char *scales[] = {"", "*2", "*4", "*8"}; + register int base_disp; + register int outer_disp; + char buf[40]; + + word = NEXTWORD (p); + + /* Generate the text for the index register. + Where this will be output is not yet determined. */ + sprintf (buf, "[%s.%c%s]", + reg_names[(word >> 12) & 0xf], + (word & 0x800) ? 'l' : 'w', + scales[(word >> 9) & 3]); + + /* Handle the 68000 style of indexing. */ + + if ((word & 0x100) == 0) + { + print_base (basereg, + ((word & 0x80) ? word | 0xff00 : word & 0xff) + + ((basereg == -1) ? addr : 0), + stream); + fputs_filtered (buf, stream); + return p; + } + + /* Handle the generalized kind. */ + /* First, compute the displacement to add to the base register. */ + + if (word & 0200) + basereg = -2; + if (word & 0100) + buf[0] = 0; + base_disp = 0; + switch ((word >> 4) & 3) + { + case 2: + base_disp = NEXTWORD (p); + break; + case 3: + base_disp = NEXTLONG (p); + } + if (basereg == -1) + base_disp += addr; + + /* Handle single-level case (not indirect) */ + + if ((word & 7) == 0) + { + print_base (basereg, base_disp, stream); + fputs_filtered (buf, stream); + return p; + } + + /* Two level. Compute displacement to add after indirection. */ + + outer_disp = 0; + switch (word & 3) + { + case 2: + outer_disp = NEXTWORD (p); + break; + case 3: + outer_disp = NEXTLONG (p); + } + + fprintf_filtered (stream, "%d(", outer_disp); + print_base (basereg, base_disp, stream); + + /* If postindexed, print the closeparen before the index. */ + if (word & 4) + fprintf_filtered (stream, ")%s", buf); + /* If preindexed, print the closeparen after the index. */ + else + fprintf_filtered (stream, "%s)", buf); + + return p; +} + +/* Print a base register REGNO and displacement DISP, on STREAM. + REGNO = -1 for pc, -2 for none (suppressed). */ + +static void +print_base (regno, disp, stream) + int regno; + int disp; + FILE *stream; +{ + if (regno == -2) + fprintf_filtered (stream, "%d", disp); + else if (regno == -1) + fprintf_filtered (stream, "0x%x", (unsigned) disp); + else + fprintf_filtered (stream, "%d(%s)", disp, reg_names[regno]); +} diff --git a/gnu/usr.bin/gdb/objdump/arch/sparc/Makefile.inc b/gnu/usr.bin/gdb/objdump/arch/sparc/Makefile.inc new file mode 100644 index 00000000000..d2c3227a651 --- /dev/null +++ b/gnu/usr.bin/gdb/objdump/arch/sparc/Makefile.inc @@ -0,0 +1,8 @@ +# $Id: Makefile.inc,v 1.1 1995/10/18 08:40:14 deraadt Exp $ + +SRCS+= sparc-pinsn.c sparc-opc.c + +CFLAGS+= -DSELECT_ARCHITECTURES=bfd_arch_sparc \ + -DPRINT_INSN=print_insn_sparc + + diff --git a/gnu/usr.bin/gdb/objdump/arch/sparc/sparc-pinsn.c b/gnu/usr.bin/gdb/objdump/arch/sparc/sparc-pinsn.c new file mode 100644 index 00000000000..a82b5447f16 --- /dev/null +++ b/gnu/usr.bin/gdb/objdump/arch/sparc/sparc-pinsn.c @@ -0,0 +1,482 @@ +/* disassemble sparc instructions for objdump + Copyright (C) 1986, 1987, 1989, 1991 Free Software Foundation, Inc. + + +This file is part of the binutils. + +The binutils are 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 binutils are distributed in the hope that they 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. */ + +#include "bfd.h" +#include "sysdep.h" +#include <stdio.h> +#include "opcode/sparc.h" +#include "objdump.h" +extern int print_address(); + +static char *reg_names[] = + { "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", + "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7", + "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", + "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7", + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", + "y", "psr", "wim", "tbr", "pc", "npc", "fpsr", "cpsr" }; + +#define freg_names (®_names[4 * 8]) + +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 op3:6; + unsigned int _RS1:5; +#define rs1 ldst._RS1 + unsigned int i:1; + unsigned int _ASI:8; +#define asi ldst._ASI + unsigned int _RS2:5; +#define rs2 ldst._RS2 +#define shcnt rs2 + } ldst; + struct + { + unsigned int _OP:2, _RD:5, op3:6, _RS1:5, i:1; + unsigned int IMM13:13; +#define imm13 IMM13.IMM13 + } IMM13; + struct + { + unsigned int _OP:2; + unsigned int a:1; + unsigned int cond:4; + unsigned int op2:3; + unsigned int DISP22:22; +#define disp22 branch.DISP22 + } branch; + +#define imm22 disp22 + struct + { + unsigned int _OP:2; + unsigned int _DISP30:30; +#define disp30 call._DISP30 + } call; + }; + +/* Nonzero if INSN is the opcode for a delayed branch. */ +static int +is_delayed_branch (insn) + union sparc_insn insn; +{ + unsigned int i; + + for (i = 0; i < NUMOPCODES; ++i) + { + 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; + } + return 0; +} + +static int opcodes_sorted = 0; + +/* Print one instruction from MEMADDR on STREAM. */ +int +print_insn_sparc (memaddr, buffer, stream) + bfd_vma memaddr; + bfd_byte *buffer; + FILE *stream; + +{ + union sparc_insn insn; + + register unsigned int i; + + if (!opcodes_sorted) + { + static int compare_opcodes (); + qsort ((char *) sparc_opcodes, NUMOPCODES, + sizeof (sparc_opcodes[0]), compare_opcodes); + opcodes_sorted = 1; + } + +memcpy(&insn,buffer, sizeof (insn)); + + for (i = 0; i < NUMOPCODES; ++i) + { + const struct sparc_opcode *opcode = &sparc_opcodes[i]; + if ((opcode->match & insn.code) == opcode->match + && (opcode->lose & insn.code) == 0) + { + /* Nonzero means that we have found an instruction which has + the effect of adding or or'ing the imm13 field to rs1. */ + int imm_added_to_rs1 = 0; + + /* Nonzero means that we have found a plus sign in the args + field of the opcode table. */ + int found_plus = 0; + + /* Do we have an 'or' instruction where rs1 is the same + as rsd, and which has the i bit set? */ + if (opcode->match == 0x80102000 + && insn.rs1 == insn.rd) + imm_added_to_rs1 = 1; + + if (index (opcode->args, 'S') != 0) + /* Reject the special case for `set'. + The real `sethi' will match. */ + continue; + if (insn.rs1 != insn.rd + && index (opcode->args, 'r') != 0) + /* Can't do simple format if source and dest are different. */ + continue; + + fputs (opcode->name, stream); + + { + register const char *s; + + if (opcode->args[0] != ',') + fputs (" ", stream); + for (s = opcode->args; *s != '\0'; ++s) + { + while (*s == ',') + { + fputs (",", stream); + ++s; + + switch (*s) { + case 'a': + fputs ("a", stream); + ++s; + continue; + + default: + break; + } /* switch on arg */ + } /* while there are comma started args */ + + fputs (" ", stream); + + switch (*s) + { + case '+': + found_plus = 1; + + /* note fall-through */ + default: + fprintf (stream, "%c", *s); + break; + + case '#': + fputs ("0", stream); + break; + +#define reg(n) fprintf (stream, "%%%s", reg_names[n]) + case '1': + case 'r': + reg (insn.rs1); + break; + + case '2': + reg (insn.rs2); + break; + + case 'd': + reg (insn.rd); + break; +#undef reg + +#define freg(n) fprintf (stream, "%%%s", freg_names[n]) + case 'e': + case 'v': /* double/even */ + case 'V': /* quad/multiple of 4 */ + freg (insn.rs1); + break; + + case 'f': + case 'B': /* double/even */ + case 'R': /* quad/multiple of 4 */ + freg (insn.rs2); + break; + + case 'g': + case 'H': /* double/even */ + case 'J': /* quad/multiple of 4 */ + freg (insn.rd); + break; +#undef freg + +#define creg(n) fprintf (stream, "%%c%u", (unsigned int) (n)) + case 'b': + creg (insn.rs1); + break; + + case 'c': + creg (insn.rs2); + break; + + case 'D': + creg (insn.rd); + break; +#undef creg + + case 'h': + fprintf (stream, "%%hi(%#x)", + (unsigned int) insn.imm22 << 10); + break; + + case 'i': + { + /* We cannot trust the compiler to sign-extend + when extracting the bitfield, hence the shifts. */ + int imm = ((int) insn.imm13 << 19) >> 19; + + /* 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 +, + not before it. */ + if (found_plus) + imm_added_to_rs1 = 1; + + if (imm <= 9) + fprintf (stream, "%d", imm); + else + fprintf (stream, "%#x", (unsigned) imm); + } + break; + + + case 'M': + fprintf(stream, "%%asr%d", insn.rs1); + break; + + case 'm': + fprintf(stream, "%%asr%d", insn.rd); + break; + + case 'L': + print_address ((bfd_vma) memaddr + insn.disp30 * 4, + stream); + break; + + case 'l': + 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)); + else + /* We cannot trust the compiler to sign-extend + when extracting the bitfield, hence the shifts. */ + print_address ((bfd_vma) + (memaddr + + (((int) insn.disp22 << 10) >> 10) * 4), + stream); + break; + + case 'A': + fprintf (stream, "(%d)", (int) insn.asi); + break; + + case 'C': + fputs ("%csr", stream); + break; + + case 'F': + fputs ("%fsr", stream); + break; + + case 'p': + fputs ("%psr", stream); + break; + + case 'q': + fputs ("%fq", stream); + break; + + case 'Q': + fputs ("%cq", stream); + break; + + case 't': + fputs ("%tbr", stream); + break; + + case 'w': + fputs ("%wim", stream); + break; + + case 'y': + fputs ("%y", stream); + break; + } + } + } + + /* If we are adding or or'ing something to rs1, then + check to see whether the previous instruction was + a sethi to the same register as in the sethi. + If so, attempt to print the result of the add or + or (in this context add and or do the same thing) + and its symbolic value. */ + if (imm_added_to_rs1) + { + union sparc_insn prev_insn; + int errcode = 0; + + memcpy(&prev_insn, buffer -4, sizeof (prev_insn)); + + if (errcode == 0) + { + /* If it is a delayed branch, we need to look at the + instruction before the delayed branch. This handles + sequences such as + + sethi %o1, %hi(_foo), %o1 + call _printf + or %o1, %lo(_foo), %o1 + */ + + if (is_delayed_branch (prev_insn)) + memcpy(&prev_insn, buffer - 8, sizeof(prev_insn)); + + } + + /* If there was a problem reading memory, then assume + the previous instruction was not sethi. */ + if (errcode == 0) + { + /* Is it sethi to the same register? */ + if ((prev_insn.code & 0xc1c00000) == 0x01000000 + && prev_insn.rd == insn.rs1) + { + fprintf (stream, "\t! "); + /* We cannot trust the compiler to sign-extend + when extracting the bitfield, hence the shifts. */ + print_address (((int) prev_insn.imm22 << 10) + | (insn.imm13 << 19) >> 19, stream); + } + } + } + + return sizeof (insn); + } + } + + fprintf (stream, "%#8x", insn.code); + return sizeof (insn); +} + + +/* Compare opcodes A and B. */ + +static int +compare_opcodes (a, b) + char *a, *b; +{ + struct sparc_opcode *op0 = (struct sparc_opcode *) a; + struct sparc_opcode *op1 = (struct sparc_opcode *) b; + unsigned long int match0 = op0->match, match1 = op1->match; + unsigned long int lose0 = op0->lose, lose1 = op1->lose; + register unsigned int i; + + /* If a bit is set in both match and lose, there is something + wrong with the opcode table. */ + if (match0 & lose0) + { + fprintf (stderr, "Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n", + op0->name, match0, lose0); + op0->lose &= ~op0->match; + lose0 = op0->lose; + } + + if (match1 & lose1) + { + fprintf (stderr, "Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n", + op1->name, match1, lose1); + op1->lose &= ~op1->match; + lose1 = op1->lose; + } + + /* Because the bits that are variable in one opcode are constant in + another, it is important to order the opcodes in the right order. */ + for (i = 0; i < 32; ++i) + { + unsigned long int x = 1 << i; + int x0 = (match0 & x) != 0; + int x1 = (match1 & x) != 0; + + if (x0 != x1) + return x1 - x0; + } + + for (i = 0; i < 32; ++i) + { + unsigned long int x = 1 << i; + int x0 = (lose0 & x) != 0; + int x1 = (lose1 & x) != 0; + + if (x0 != x1) + return x1 - x0; + } + + /* They are functionally equal. So as long as the opcode table is + valid, we can put whichever one first we want, on aesthetic grounds. */ + { + int length_diff = strlen (op0->args) - strlen (op1->args); + if (length_diff != 0) + /* Put the one with fewer arguments first. */ + return length_diff; + } + + /* Put 1+i before i+1. */ + { + char *p0 = (char *) index(op0->args, '+'); + char *p1 = (char *) index(op1->args, '+'); + + if (p0 && p1) + { + /* There is a plus in both operands. Note that a plus + sign cannot be the first character in args, + so the following [-1]'s are valid. */ + if (p0[-1] == 'i' && p1[1] == 'i') + /* op0 is i+1 and op1 is 1+i, so op1 goes first. */ + return 1; + if (p0[1] == 'i' && p1[-1] == 'i') + /* op0 is 1+i and op1 is i+1, so op0 goes first. */ + return -1; + } + } + + /* They are, as far as we can tell, identical. + Since qsort may have rearranged the table partially, there is + no way to tell which one was first in the opcode table as + written, so just say there are equal. */ + return 0; +} diff --git a/gnu/usr.bin/gdb/objdump/bucomm.c b/gnu/usr.bin/gdb/objdump/bucomm.c new file mode 100644 index 00000000000..728892d52c5 --- /dev/null +++ b/gnu/usr.bin/gdb/objdump/bucomm.c @@ -0,0 +1,146 @@ +/* bucomm.c -- Bin Utils COMmon code. + Copyright (C) 1991 Free Software Foundation, Inc. + +This file is part of GNU Binutils. + +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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* We might put this in a library someday so it could be dynamically + loaded, but for now it's not necessary */ + +#include "bfd.h" +#include "sysdep.h" +#include <varargs.h> + +char *target = NULL; /* default as late as possible */ + +/* Yes, this is what atexit is for, but that isn't guaranteed yet. + And yes, I know this isn't as good, but it does what is needed just fine */ +void (*exit_handler) (); + + + + +/* Error reporting */ + +char *program_name; + +void +DEFUN(bfd_fatal,(string), + char *string) +{ + CONST char *errmsg = bfd_errmsg (bfd_error); + + if (string) + fprintf (stderr, "%s: %s: %s\n", program_name, string, errmsg); + else + fprintf (stderr, "%s: %s\n", program_name, errmsg); + + if (NULL != exit_handler) (*exit_handler) (); + exit (1); +} + +#if 0 /* !defined(NO_STDARG) */ +void +fatal (Format) + const char *Format; +{ + va_list args; + + va_start (args, Format); + vfprintf (stderr, Format, args); + va_end (args); + (void) putc ('\n', stderr); + if (NULL != exit_handler) (*exit_handler) (); + exit (1); +} +#else +void fatal (va_alist) + va_dcl +{ + char *Format; + va_list args; + + va_start (args); + Format = va_arg(args, char *); + vfprintf (stderr, Format, args); + va_end (args); + (void) putc ('\n', stderr); + if (NULL != exit_handler) (*exit_handler) (); + exit (1); +} /* fatal() */ +#endif + + +/** Display the archive header for an element as if it were an ls -l listing */ + +/* Mode User\tGroup\tSize\tDate Name */ + +void +DEFUN(print_arelt_descr,(file, abfd, verbose), + FILE *file AND + bfd *abfd AND + boolean verbose) +{ + void mode_string (); + struct stat buf; + + if (verbose) { + + if (bfd_stat_arch_elt (abfd, &buf) == 0) { /* if not, huh? */ + char modebuf[11]; + char timebuf[40]; + long when = buf.st_mtime; + CONST char *ctime_result = (CONST char *)ctime (&when); + + /* Posix format: skip weekday and seconds from ctime output. */ + sprintf(timebuf, "%.12s %.4s", ctime_result+4, ctime_result+20); + + mode_string (buf.st_mode, modebuf); + modebuf[10] = '\0'; + /* Posix 1003.2/D11 says to skip first character (entry type). */ + fprintf (file, "%s %d/%d %6qd %s ", modebuf+1, buf.st_uid, buf.st_gid, buf.st_size, timebuf); + } + } + + fprintf (file, "%s\n",abfd->filename); +} + +/* Like malloc but get fatal error if memory is exhausted. */ +char * +xmalloc (size) + unsigned size; +{ + register char *result = malloc (size); + if (result == (char *) NULL && size != 0) { + fatal ("virtual memory exhausted"); + } + + return result; +} + +/* Like realloc but get fatal error if memory is exhausted. */ +char * +xrealloc (ptr, size) + char *ptr; + unsigned size; +{ + register char *result = realloc (ptr, size); + if (result == 0 && size != 0) { + fatal ("virtual memory exhausted"); + } + + return result; +} diff --git a/gnu/usr.bin/gdb/objdump/filemode.c b/gnu/usr.bin/gdb/objdump/filemode.c new file mode 100644 index 00000000000..d53cef11d34 --- /dev/null +++ b/gnu/usr.bin/gdb/objdump/filemode.c @@ -0,0 +1,193 @@ +/* filemode.c -- make a string describing file modes + Copyright (C) 1985, 1990 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <sys/types.h> +#include <sys/stat.h> + +void mode_string (); +static char ftypelet (); +static void rwx (); +static void setst (); + +/* filemodestring - fill in string STR with an ls-style ASCII + representation of the st_mode field of file stats block STATP. + 10 characters are stored in STR; no terminating null is added. + The characters stored in STR are: + + 0 File type. 'd' for directory, 'c' for character + special, 'b' for block special, 'm' for multiplex, + 'l' for symbolic link, 's' for socket, 'p' for fifo, + '-' for any other file type + + 1 'r' if the owner may read, '-' otherwise. + + 2 'w' if the owner may write, '-' otherwise. + + 3 'x' if the owner may execute, 's' if the file is + set-user-id, '-' otherwise. + 'S' if the file is set-user-id, but the execute + bit isn't set. + + 4 'r' if group members may read, '-' otherwise. + + 5 'w' if group members may write, '-' otherwise. + + 6 'x' if group members may execute, 's' if the file is + set-group-id, '-' otherwise. + 'S' if it is set-group-id but not executable. + + 7 'r' if any user may read, '-' otherwise. + + 8 'w' if any user may write, '-' otherwise. + + 9 'x' if any user may execute, 't' if the file is "sticky" + (will be retained in swap space after execution), '-' + otherwise. + 'T' if the file is sticky but not executable. */ + +void +filemodestring (statp, str) + struct stat *statp; + char *str; +{ + mode_string (statp->st_mode, str); +} + +/* Like filemodestring, but only the relevant part of the `struct stat' + is given as an argument. */ + +void +mode_string (mode, str) + unsigned short mode; + char *str; +{ + str[0] = ftypelet (mode); + rwx ((mode & 0700) << 0, &str[1]); + rwx ((mode & 0070) << 3, &str[4]); + rwx ((mode & 0007) << 6, &str[7]); + setst (mode, str); +} + +/* Return a character indicating the type of file described by + file mode BITS: + 'd' for directories + 'b' for block special files + 'c' for character special files + 'm' for multiplexor files + 'l' for symbolic links + 's' for sockets + 'p' for fifos + '-' for any other file type. */ + +static char +ftypelet (bits) + unsigned short bits; +{ + switch (bits & S_IFMT) + { + default: + return '-'; + case S_IFDIR: + return 'd'; +#ifdef S_IFLNK + case S_IFLNK: + return 'l'; +#endif +#ifdef S_IFCHR + case S_IFCHR: + return 'c'; +#endif +#ifdef S_IFBLK + case S_IFBLK: + return 'b'; +#endif +#ifdef S_IFMPC + case S_IFMPC: + case S_IFMPB: + return 'm'; +#endif +#ifdef S_IFSOCK + case S_IFSOCK: + return 's'; +#endif +#ifdef S_IFIFO +#if S_IFIFO != S_IFSOCK + case S_IFIFO: + return 'p'; +#endif +#endif +#ifdef S_IFNWK /* HP-UX */ + case S_IFNWK: + return 'n'; +#endif + } +} + +/* Look at read, write, and execute bits in BITS and set + flags in CHARS accordingly. */ + +static void +rwx (bits, chars) + unsigned short bits; + char *chars; +{ + chars[0] = (bits & S_IREAD) ? 'r' : '-'; + chars[1] = (bits & S_IWRITE) ? 'w' : '-'; + chars[2] = (bits & S_IEXEC) ? 'x' : '-'; +} + +/* Set the 's' and 't' flags in file attributes string CHARS, + according to the file mode BITS. */ + +static void +setst (bits, chars) + unsigned short bits; + char *chars; +{ +#ifdef S_ISUID + if (bits & S_ISUID) + { + if (chars[3] != 'x') + /* Set-uid, but not executable by owner. */ + chars[3] = 'S'; + else + chars[3] = 's'; + } +#endif +#ifdef S_ISGID + if (bits & S_ISGID) + { + if (chars[6] != 'x') + /* Set-gid, but not executable by group. */ + chars[6] = 'S'; + else + chars[6] = 's'; + } +#endif +#ifdef S_ISVTX + if (bits & S_ISVTX) + { + if (chars[9] != 'x') + /* Sticky, but not executable by others. */ + chars[9] = 'T'; + else + chars[9] = 't'; + } +#endif +} + + diff --git a/gnu/usr.bin/gdb/objdump/objdump.1 b/gnu/usr.bin/gdb/objdump/objdump.1 new file mode 100644 index 00000000000..b26fb7cb027 --- /dev/null +++ b/gnu/usr.bin/gdb/objdump/objdump.1 @@ -0,0 +1,227 @@ +.\" Copyright (c) 1991 Free Software Foundation +.\" See section COPYING for conditions for redistribution +.TH objdump 1 "5 November 1991" "cygnus support" "GNU Development Tools" +.de BP +.sp +.ti \-.2i +\(** +.. + +.SH NAME +objdump\(em\&display information from object files. + +.SH SYNOPSIS +.hy 0 +.na +.TP +.B objdump +.RB "[\|" \-a "\|]" +.RB "[\|" "\-b\ "\c +.I bfdname\c +\&\|] +.RB "[\|" \-d "\|]" +.RB "[\|" \-f "\|]" +.RB "[\|" \-h | --header "\|]" +.RB "[\|" \-i "\|]" +.RB "[\|" "\-j\ "\c +.I section\c +\&\|] +.RB "[\|" \-l "\|]" +.RB "[\|" "\-m\ "\c +.I machine\c +\&\|] +.RB "[\|" \-r | --reloc "\|]" +.RB "[\|" \-s "\|]" +.RB "[\|" \--stabs "\|]" +.RB "[\|" \-t | --syms "\|]" +.RB "[\|" \-x "\|]" +.I objfiles\c +\&.\|.\|. +.ad b +.hy 1 +.SH DESCRIPTION +\c +.B objdump\c +\& displays information about one or more object files. +The options control what particular information to display. This +information is mostly useful to programmers who are working on the +compilation tools, as opposed to programmers who just want their +program to compile and work. +.SH OPTIONS +Where long and short forms of an option are shown together, they are +equivalent. + +.TP +.IR "objfiles" .\|.\|. +The object files to be examined. When you specify archives, +\c +.B objdump\c +\& shows information on each of the member object files. + +.TP +.B \-a +If any files from \c +.I objfiles\c +\& are archives, display the archive +header information (in a format similar to `\|\c +.B ls \-l\c +\|'). Besides the +information you could list with `\|\c +.B ar tv\c +\|', `\|\c +.B objdump \-a\c +\|' shows +the object file format of each archive member. + +.TP +.BI "-b " "bfdname"\c +\& +You can specify a particular object-code format for your object files as +\c +.I bfdname\c +\&. This may not be necessary; \c +.I objdump\c +\& can +automatically recognize many formats. For example, +.sp +.br +objdump\ \-b\ oasys\ \-m\ vax\ \-h\ fu.o +.br +.sp + +Displays summary information from the section headers (`\|\c +.B \-h\c +\|') of +`\|\c +.B fu.o\c +\|', which is explicitly identified (`\|\c +.B \-m\c +\|') as a Vax object +file in the format produced by Oasys compilers. You can list the +formats available with the `\|\c +.B \-i\c +\|' option. + +.TP +.B \-d +Disassemble. Display the assembler mnemonics for the machine +instructions from \c +.I objfiles\c +\&. + +.TP +.B \-f +File header. Display summary information from the overall header of +each file in \c +.I objfiles\c +\&. + +.TP +.B \-h +.TP +.B --header +Header. Display summary information from the section headers of the +object file. + +.TP +.B \-i +Display a list showing all architectures and object formats available +for specification with \c +.B \-b\c +\& or \c +.B \-m\c +\&. + +.TP +.BI "-j " "name"\c +\& +Display information only for section \c +.I name\c +\& + +.TP +.B \-l +Label the display (using debugging information) with the source filename +and line numbers corresponding to the object code shown. + +.TP +.BI "-m " "machine"\c +\& +Specify the object files \c +.I objfiles\c +\& are for architecture +\c +.I machine\c +\&. You can list available architectures using the `\|\c +.B \-i\c +\|' +option. + +.TP +.B \-r +.TP +.B --reloc +Relocation. Print the relocation entries of the file. + +.TP +.B \-s +Display the full contents of any sections requested. + +.TP +.B \--stabs +Display the contents of the .stab, .stab.index, and .stab.excl +sections from an ELF file. This is only useful on systems (such as +Solaris 2.0) in which .stab debugging symbol-table entries are carried +in an ELF section. In most other file formats, debugging symbol-table +entries are interleaved with linkage symbols, and are visible in the +--syms output. + +.TP +.B \-t +.TP +.B --syms +Symbol Table. Print the symbol table entries of the file. +This is similar to the information provided by the `\|\c +.B nm\c +\|' program. + +.TP +.B \-x +Display all available header information, including the symbol table and +relocation entries. Using `\|\c +.B \-x\c +\|' is equivalent to specifying all of +`\|\c +.B \-a \-f \-h \-r \-t\c +\|'. + +.PP + +.SH "SEE ALSO" +.RB "`\|" binutils "\|'" +entry in +.B +info\c +\&; +.I +The GNU Binary Utilities\c +\&, Roland H. Pesch (October 1991); +.BR nm "(" 1 ")." + +.SH COPYING +Copyright (c) 1991 Free Software Foundation, Inc. +.PP +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. +.PP +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. +.PP +Permission is granted to copy and distribute translations of this +manual into another language, under the above conditions for modified +versions, except that this permission notice may be included in +translations approved by the Free Software Foundation instead of in +the original English. diff --git a/gnu/usr.bin/gdb/objdump/objdump.c b/gnu/usr.bin/gdb/objdump/objdump.c new file mode 100644 index 00000000000..982b7d2a427 --- /dev/null +++ b/gnu/usr.bin/gdb/objdump/objdump.c @@ -0,0 +1,1087 @@ +/* objdump.c -- dump information about an object file. + Copyright (C) 1990, 1991 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Diddler. + +BFD 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. + +BFD 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 BFD; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + * Until there is other documentation, refer to the manual page dump(1) in + * the system 5 program's reference manual + */ + +#include "bfd.h" +#include "sysdep.h" +#include "getopt.h" +#include <stdio.h> +#include <ctype.h> + +#define ELF_STAB_DISPLAY /* This code works, but uses internal + bfd and elf stuff. Flip this define + off if you need to just use generic + BFD interfaces. */ + +#ifdef ELF_STAB_DISPLAY +/* Internal headers for the ELF .stab-dump code - sorry. */ +#define BYTES_IN_WORD 32 +#include "aout/aout64.h" +#include "elf/internal.h" +extern Elf_Internal_Shdr *bfd_elf_find_section(); +#endif /* ELF_STAB_DISPLAY */ + +char *xmalloc (); + +char *default_target = NULL; /* default at runtime */ + +extern *program_version; +char *program_name = NULL; + +int show_version = 0; /* show the version number */ +int dump_section_contents; /* -s */ +int dump_section_headers; /* -h */ +boolean dump_file_header; /* -f */ +int dump_symtab; /* -t */ +int dump_reloc_info; /* -r */ +int dump_ar_hdrs; /* -a */ +int with_line_numbers; /* -l */ +int dump_stab_section_info; /* -stabs */ +boolean disassemble; /* -d */ +boolean info; /* -i */ +char *only; + +PROTO (void, display_file, (char *filename, char *target)); +PROTO (void, dump_data, (bfd * abfd)); +PROTO (void, dump_relocs, (bfd * abfd)); +PROTO (void, dump_symbols, (bfd * abfd)); +PROTO (void, print_arelt_descr, (FILE *, bfd * abfd, boolean verbose)); + + + + + + + +char *machine = (char *) NULL; +asymbol **syms; +asymbol **syms2; + + +unsigned int storage; + +unsigned int symcount = 0; + +void +usage () +{ + fprintf (stderr, + "usage: %s [-ahifdrtxsl] [-m machine] [-j section_name] obj ...\n", + program_name); + exit (1); +} + +static struct option long_options[]= +{ + {"syms", no_argument, &dump_symtab, 1}, + {"reloc", no_argument, &dump_reloc_info, 1}, + {"header", no_argument, &dump_section_headers, 1}, + {"version", no_argument, &show_version, 1}, +#ifdef ELF_STAB_DISPLAY + {"stabs", no_argument, &dump_stab_section_info, 1}, +#endif + {0, no_argument, 0, 0}}; + + +static void +dump_headers (abfd) + bfd *abfd; +{ + asection *section; + + for (section = abfd->sections; + section != (asection *) NULL; + section = section->next) + { + char *comma = ""; + +#define PF(x,y) \ + if (section->flags & x) { printf("%s%s",comma,y); comma = ", "; } + + + printf ("SECTION %d [%s]\t: size %08x", + section->index, + section->name, + (unsigned) bfd_get_section_size_before_reloc (section)); + printf (" vma "); + printf_vma (section->vma); + printf (" align 2**%u\n ", + section->alignment_power); + PF (SEC_ALLOC, "ALLOC"); + PF (SEC_CONSTRUCTOR, "CONSTRUCTOR"); + PF (SEC_CONSTRUCTOR_TEXT, "CONSTRUCTOR TEXT"); + PF (SEC_CONSTRUCTOR_DATA, "CONSTRUCTOR DATA"); + PF (SEC_CONSTRUCTOR_BSS, "CONSTRUCTOR BSS"); + PF (SEC_LOAD, "LOAD"); + PF (SEC_RELOC, "RELOC"); +#ifdef SEC_BALIGN + PF (SEC_BALIGN, "BALIGN"); +#endif + PF (SEC_READONLY, "READONLY"); + PF (SEC_CODE, "CODE"); + PF (SEC_DATA, "DATA"); + PF (SEC_ROM, "ROM"); + printf ("\n"); +#undef PF + } +} + +static asymbol ** +DEFUN (slurp_symtab, (abfd), + bfd * abfd) +{ + asymbol **sy = (asymbol **) NULL; + + if (!(bfd_get_file_flags (abfd) & HAS_SYMS)) + { + (void) printf ("No symbols in \"%s\".\n", bfd_get_filename (abfd)); + return (NULL); + } + + storage = get_symtab_upper_bound (abfd); + if (storage) + { + sy = (asymbol **) malloc (storage); + if (sy == NULL) + { + fprintf (stderr, "%s: out of memory.\n", program_name); + exit (1); + } + } + symcount = bfd_canonicalize_symtab (abfd, sy); + return sy; +} + +/* Sort symbols into value order */ +static int +comp (ap, bp) + PTR ap; + PTR bp; +{ + asymbol *a = *(asymbol **)ap; + asymbol *b = *(asymbol **)bp; + int diff; + + if (a->name == (char *) NULL || (a->flags & (BSF_DEBUGGING))) + a->the_bfd = 0; + if (b->name == (char *) NULL || (b->flags & (BSF_DEBUGGING))) + b->the_bfd = 0; + + diff = a->the_bfd - b->the_bfd; + if (diff) + { + return -diff; + } + diff = a->value - b->value; + if (diff) + { + return diff; + } + return a->section - b->section; +} + +/* Print the supplied address symbolically if possible */ +void +print_address (vma, stream) + bfd_vma vma; + FILE *stream; +{ + /* Perform a binary search looking for the closest symbol to + the required value */ + + unsigned int min = 0; + unsigned int max = symcount; + + unsigned int thisplace = 1; + unsigned int oldthisplace; + + int vardiff; + + if (symcount == 0) + { + fprintf_vma (stream, vma); + } + else + { + while (true) + { + oldthisplace = thisplace; + thisplace = (max + min) / 2; + if (thisplace == oldthisplace) + break; + vardiff = syms[thisplace]->value - vma; + + if (vardiff) + { + if (vardiff > 0) + { + max = thisplace; + } + else + { + min = thisplace; + } + } + else + { + /* Totally awesome! the exact right symbol */ + CONST char *match_name = syms[thisplace]->name; + int sym_len = strlen (match_name); + + /* Avoid "filename.o" as a match */ + if (sym_len > 2 + && match_name[sym_len - 2] == '.' + && match_name[sym_len - 1] == 'o' + && thisplace + 1 < symcount + && syms[thisplace + 1]->value == vma) + match_name = syms[thisplace + 1]->name; + /* Totally awesome! the exact right symbol */ + fprintf_vma (stream, vma); + fprintf (stream, " (%s+)0000", syms[thisplace]->name); + return; + } + } + /* We've run out of places to look, print the symbol before this one + see if this or the symbol before describes this location the best */ + + if (thisplace != 0) + { + if (syms[thisplace - 1]->value - vma > + syms[thisplace]->value - vma) + { + /* Previous symbol is in correct section and is closer */ + thisplace--; + } + } + + fprintf_vma (stream, vma); + if (syms[thisplace]->value > vma) + { + fprintf (stream, " (%s-)", syms[thisplace]->name); + fprintf (stream, "%04x", syms[thisplace]->value - vma); + } + else + { + fprintf (stream, " (%s+)", syms[thisplace]->name); + fprintf (stream, "%04x", vma - syms[thisplace]->value); + } + } +} + +void +disassemble_data (abfd) + bfd *abfd; +{ + bfd_byte *data = NULL; + bfd_arch_info_type *info; + bfd_size_type datasize = 0; + bfd_size_type i; + unsigned int (*print) ()= 0; + unsigned int print_insn_m68k (); + unsigned int print_insn_a29k (); + unsigned int print_insn_z8k (); + unsigned int print_insn_i960 (); + unsigned int print_insn_sparc (); + unsigned int print_insn_i386 (); + unsigned int print_insn_h8300 (); + enum bfd_architecture a; + + asection *section; + + /* Replace symbol section relative values with abs values */ + boolean done_dot = false; + + for (i = 0; i < symcount; i++) + { + syms[i]->value += syms[i]->section->vma; + } + + /* We keep a copy of the symbols in the original order */ + syms2 = slurp_symtab (abfd); + + /* Sort the symbols into section and symbol order */ + (void) qsort (syms, symcount, sizeof (asymbol *), comp); + + /* Find the first useless symbol */ + { + unsigned int i; + + for (i = 0; i < symcount; i++) + { + if (syms[i]->the_bfd == 0) + { + symcount = i; + break; + } + } + } + + + if (machine != (char *) NULL) + { + info = bfd_scan_arch (machine); + if (info == 0) + { + fprintf (stderr, "%s: Can't use supplied machine %s\n", + program_name, + machine); + exit (1); + } + abfd->arch_info = info; + } + + /* See if we can disassemble using bfd */ + + if (abfd->arch_info->disassemble) + { + print = abfd->arch_info->disassemble; + } + else + { + a = bfd_get_arch (abfd); + switch (a) + { +#ifdef SELECT_ARCHITECTURES + case SELECT_ARCHITECTURES: + print = PRINT_INSN; + break; +#else + case bfd_arch_sparc: + print = print_insn_sparc; + break; + case bfd_arch_i386: + print = print_insn_i386; + break; + case bfd_arch_m68k: + print = print_insn_m68k; + break; + case bfd_arch_a29k: + print = print_insn_a29k; + break; + case bfd_arch_i960: + print = print_insn_i960; + break; + case bfd_arch_z8k: + print = print_insn_z8k; + break; +#endif + default: + fprintf (stderr, "%s: Can't disassemble for architecture %s\n", + program_name, + bfd_printable_arch_mach (bfd_get_arch (abfd), 0)); + exit (1); + } + + } + + for (section = abfd->sections; + section != (asection *) NULL; + section = section->next) + { + + if ((section->flags & SEC_LOAD) + && (only == (char *) NULL || strcmp (only, section->name) == 0)) + { + printf ("Disassembly of section %s:\n", section->name); + + if (bfd_get_section_size_before_reloc (section) == 0) + continue; + + data = (bfd_byte *) malloc (bfd_get_section_size_before_reloc (section)); + + if (data == (bfd_byte *) NULL) + { + fprintf (stderr, "%s: memory exhausted.\n", program_name); + exit (1); + } + datasize = bfd_get_section_size_before_reloc (section); + + bfd_get_section_contents (abfd, section, data, 0, bfd_get_section_size_before_reloc (section)); + + i = 0; + while (i < bfd_get_section_size_before_reloc (section)) + { + if (data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 0 && + data[i + 3] == 0) + { + if (done_dot == false) + { + printf ("...\n"); + done_dot = true; + } + i += 4; + } + else + { + done_dot = false; + if (with_line_numbers) + { + static prevline; + CONST char *filename; + CONST char *functionname; + unsigned int line; + + bfd_find_nearest_line (abfd, + section, + syms, + section->vma + i, + &filename, + &functionname, + &line); + + if (filename && functionname && line && line != prevline) + { + printf ("%s:%u\n", filename, line); + prevline = line; + } + } + print_address (section->vma + i, stdout); + printf (" "); + + i += print (section->vma + i, + data + i, + stdout); + putchar ('\n'); + } + } + free (data); + } + } +} + +#ifdef ELF_STAB_DISPLAY + +/* Define a table of stab values and print-strings. We wish the initializer + could be a direct-mapped table, but instead we build one the first + time we need it. */ + +#define STAB_STRING_LENGTH 6 + +char stab_name[256][STAB_STRING_LENGTH]; + +struct stab_print { + int value; + char string[STAB_STRING_LENGTH]; +}; + +struct stab_print stab_print[] = { +#define __define_stab(NAME, CODE, STRING) {CODE, STRING}, +#include "aout/stab.def" +#undef __define_stab + {0, 0} +}; + +void dump_elf_stabs_1 (); + +/* This is a kludge for dumping the stabs section from an ELF file that + uses Sun stabs encoding. It has to use some hooks into BFD because + string table sections are not normally visible to BFD callers. */ + +void +dump_elf_stabs (abfd) + bfd *abfd; +{ + int i; + + /* Initialize stab name array if first time. */ + if (stab_name[0][0] == 0) + { + /* Fill in numeric values for all possible strings. */ + for (i = 0; i < 256; i++) + { + sprintf (stab_name[i], "%d", i); + } + for (i = 0; stab_print[i].string[0]; i++) + strcpy (stab_name[stab_print[i].value], stab_print[i].string); + } + + if (0 != strncmp ("elf", abfd->xvec->name, 3)) + { + fprintf (stderr, "%s: %s is not in ELF format.\n", program_name, + abfd->filename); + return; + } + + dump_elf_stabs_1 (abfd, ".stab", ".stabstr"); + dump_elf_stabs_1 (abfd, ".stab.excl", ".stab.exclstr"); + dump_elf_stabs_1 (abfd, ".stab.index", ".stab.indexstr"); +} + +void +dump_elf_stabs_1 (abfd, name1, name2) + bfd *abfd; + char *name1; /* Section name of .stab */ + char *name2; /* Section name of its string section */ +{ + Elf_Internal_Shdr *stab_hdr, *stabstr_hdr; + char *strtab; + struct internal_nlist *stabs, *stabs_end; + int i; + unsigned file_string_table_offset, next_file_string_table_offset; + + stab_hdr = bfd_elf_find_section (abfd, name1); + if (0 == stab_hdr) + { + printf ("Contents of %s section: none.\n\n", name1); + return; + } + + stabstr_hdr = bfd_elf_find_section (abfd, name2); + if (0 == stabstr_hdr) + { + fprintf (stderr, "%s: %s has no %s section.\n", program_name, + abfd->filename, name2); + return; + } + + stabs = (struct internal_nlist *) xmalloc (stab_hdr ->sh_size); + strtab = (char *) xmalloc (stabstr_hdr->sh_size); + stabs_end = (struct internal_nlist *) (stab_hdr->sh_size + (char *)stabs); + + if (bfd_seek (abfd, stab_hdr->sh_offset, L_SET) < 0 || + stab_hdr->sh_size != bfd_read ((PTR)stabs, stab_hdr->sh_size, 1, abfd)) + { + fprintf (stderr, "%s: reading %s section of %s failed.\n", + program_name, name1, + abfd->filename); + return; + } + + if (bfd_seek (abfd, stabstr_hdr->sh_offset, L_SET) < 0 || + stabstr_hdr->sh_size != bfd_read ((PTR)strtab, stabstr_hdr->sh_size, + 1, abfd)) + { + fprintf (stderr, "%s: reading %s section of %s failed.\n", + program_name, name2, + abfd->filename); + return; + } + +#define SWAP_SYMBOL(symp, abfd) \ + { \ + (symp)->n_strx = bfd_h_get_32(abfd, \ + (unsigned char *)&(symp)->n_strx); \ + (symp)->n_desc = bfd_h_get_16 (abfd, \ + (unsigned char *)&(symp)->n_desc); \ + (symp)->n_value = bfd_h_get_32 (abfd, \ + (unsigned char *)&(symp)->n_value); \ + } + + printf ("Contents of %s section:\n\n", name1); + printf ("Symnum n_type n_othr n_desc n_value n_strx String\n"); + + file_string_table_offset = 0; + next_file_string_table_offset = 0; + + /* Loop through all symbols and print them. + + We start the index at -1 because there is a dummy symbol on + the front of Sun's stabs-in-elf sections. */ + + for (i = -1; stabs < stabs_end; stabs++, i++) + { + SWAP_SYMBOL (stabs, abfd); + printf ("\n%-6d %-6s %-6d %-6d %08x %-6d", i, + stab_name [stabs->n_type], + stabs->n_other, stabs->n_desc, stabs->n_value, + stabs->n_strx); + + /* Symbols with type == 0 (N_UNDF) specify the length of the + string table associated with this file. We use that info + to know how to relocate the *next* file's string table indices. */ + + if (stabs->n_type == N_UNDF) + { + file_string_table_offset = next_file_string_table_offset; + next_file_string_table_offset += stabs->n_value; + } + + /* Now, using the possibly updated string table offset, print the + string (if any) associated with this symbol. */ + + if ((stabs->n_strx + file_string_table_offset) < stabstr_hdr->sh_size) + printf (" %s", &strtab[stabs->n_strx + file_string_table_offset]); + else + printf (" *"); + } + printf ("\n\n"); +} +#endif /* ELF_STAB_DISPLAY */ + +display_bfd (abfd) + bfd *abfd; +{ + + if (!bfd_check_format (abfd, bfd_object)) + { + fprintf (stderr, "%s: %s not an object file\n", program_name, + abfd->filename); + return; + } + printf ("\n%s: file format %s\n", abfd->filename, abfd->xvec->name); + if (dump_ar_hdrs) + print_arelt_descr (stdout, abfd, true); + + if (dump_file_header) + { + char *comma = ""; + + printf ("architecture: %s, ", + bfd_printable_arch_mach (bfd_get_arch (abfd), + bfd_get_mach (abfd))); + printf ("flags 0x%08x:\n", abfd->flags); + +#define PF(x, y) if (abfd->flags & x) {printf("%s%s", comma, y); comma=", ";} + PF (HAS_RELOC, "HAS_RELOC"); + PF (EXEC_P, "EXEC_P"); + PF (HAS_LINENO, "HAS_LINENO"); + PF (HAS_DEBUG, "HAS_DEBUG"); + PF (HAS_SYMS, "HAS_SYMS"); + PF (HAS_LOCALS, "HAS_LOCALS"); + PF (DYNAMIC, "DYNAMIC"); + PF (WP_TEXT, "WP_TEXT"); + PF (D_PAGED, "D_PAGED"); + PF (BFD_IS_RELAXABLE, "BFD_IS_RELAXABLE"); + printf ("\nstart address 0x"); + printf_vma (abfd->start_address); + } + printf ("\n"); + + if (dump_section_headers) + dump_headers (abfd); + if (dump_symtab || dump_reloc_info || disassemble) + { + syms = slurp_symtab (abfd); + } + if (dump_symtab) + dump_symbols (abfd); +#ifdef ELF_STAB_DISPLAY + if (dump_stab_section_info) + dump_elf_stabs (abfd); +#endif + if (dump_reloc_info) + dump_relocs (abfd); + if (dump_section_contents) + dump_data (abfd); + if (disassemble) + disassemble_data (abfd); +} + +void +display_file (filename, target) + char *filename; + char *target; +{ + bfd *file, *arfile = (bfd *) NULL; + + file = bfd_openr (filename, target); + if (file == NULL) + { + bfd_perror (filename); + return; + } + + if (bfd_check_format (file, bfd_archive) == true) + { + printf ("In archive %s:\n", bfd_get_filename (file)); + for (;;) + { + bfd_error = no_error; + + arfile = bfd_openr_next_archived_file (file, arfile); + if (arfile == NULL) + { + if (bfd_error != no_more_archived_files) + bfd_perror (bfd_get_filename (file)); + return; + } + + display_bfd (arfile); + /* Don't close the archive elements; we need them for next_archive */ + } + } + else + display_bfd (file); + + bfd_close (file); +} + +/* Actually display the various requested regions */ + +void +dump_data (abfd) + bfd *abfd; +{ + asection *section; + bfd_byte *data = 0; + bfd_size_type datasize = 0; + bfd_size_type i; + + for (section = abfd->sections; section != NULL; section = + section->next) + { + int onaline = 16; + + if (only == (char *) NULL || + strcmp (only, section->name) == 0) + { + if (section->flags & SEC_HAS_CONTENTS) + { + printf ("Contents of section %s:\n", section->name); + + if (bfd_get_section_size_before_reloc (section) == 0) + continue; + data = (bfd_byte *) malloc (bfd_get_section_size_before_reloc (section)); + if (data == (bfd_byte *) NULL) + { + fprintf (stderr, "%s: memory exhausted.\n", program_name); + exit (1); + } + datasize = bfd_get_section_size_before_reloc (section); + + + bfd_get_section_contents (abfd, section, (PTR) data, 0, bfd_get_section_size_before_reloc (section)); + + for (i = 0; i < bfd_get_section_size_before_reloc (section); i += onaline) + { + bfd_size_type j; + + printf (" %04lx ", (unsigned long int) (i + section->vma)); + for (j = i; j < i + onaline; j++) + { + if (j < bfd_get_section_size_before_reloc (section)) + printf ("%02x", (unsigned) (data[j])); + else + printf (" "); + if ((j & 3) == 3) + printf (" "); + } + + printf (" "); + for (j = i; j < i + onaline; j++) + { + if (j >= bfd_get_section_size_before_reloc (section)) + printf (" "); + else + printf ("%c", isprint (data[j]) ? data[j] : '.'); + } + putchar ('\n'); + } + } + } + free (data); + } +} + +/* Should perhaps share code and display with nm? */ +void +dump_symbols (abfd) + bfd *abfd; +{ + + unsigned int count; + asymbol **current = syms; + + printf ("SYMBOL TABLE:\n"); + + for (count = 0; count < symcount; count++) + { + + if (*current && (*current)->the_bfd) + { + bfd_print_symbol ((*current)->the_bfd, + stdout, + *current, bfd_print_symbol_all); + + printf ("\n"); + + } + current++; + } + printf ("\n"); + printf ("\n"); +} + +void +dump_relocs (abfd) + bfd *abfd; +{ + arelent **relpp; + unsigned int relcount; + asection *a; + + for (a = abfd->sections; a != (asection *) NULL; a = a->next) + { + if (a == &bfd_abs_section) + continue; + if (a == &bfd_und_section) + continue; + if (a == &bfd_com_section) + continue; + + printf ("RELOCATION RECORDS FOR [%s]:", a->name); + + if (bfd_get_reloc_upper_bound (abfd, a) == 0) + { + printf (" (none)\n\n"); + } + else + { + arelent **p; + + relpp = (arelent **) xmalloc (bfd_get_reloc_upper_bound (abfd, a)); + relcount = bfd_canonicalize_reloc (abfd, a, relpp, syms); + if (relcount == 0) + { + printf (" (none)\n\n"); + } + else + { + printf ("\n"); + printf ("OFFSET TYPE VALUE \n"); + + for (p = relpp; relcount && *p != (arelent *) NULL; p++, + relcount--) + { + arelent *q = *p; + CONST char *sym_name; + + /* CONST char *section_name = q->section == (asection *)NULL ? "*abs" :*/ + /* q->section->name;*/ + CONST char *section_name = (*(q->sym_ptr_ptr))->section->name; + + if (q->sym_ptr_ptr && *q->sym_ptr_ptr) + { + sym_name = (*(q->sym_ptr_ptr))->name; + } + else + { + sym_name = 0; + } + if (sym_name) + { + printf_vma (q->address); + printf (" %-8s %s", + q->howto->name, + sym_name); + } + else + { + printf_vma (q->address); + printf (" %-8s [%s]", + q->howto->name, + section_name); + } + if (q->addend) + { + printf ("+0x"); + printf_vma (q->addend); + } + printf ("\n"); + } + printf ("\n\n"); + free (relpp); + } + } + + } +} + +#ifdef unix +#define _DUMMY_NAME_ "/dev/null" +#else +#define _DUMMY_NAME_ "##dummy" +#endif +static void +DEFUN (display_info_table, (first, last), + int first AND int last) +{ + unsigned int i, j; + extern bfd_target *target_vector[]; + + printf ("\n%12s", " "); + for (i = first; i++ < last && target_vector[i];) + printf ("%s ", target_vector[i]->name); + printf ("\n"); + + for (j = (int) bfd_arch_obscure + 1; (int) j < (int) bfd_arch_last; j++) + if (strcmp (bfd_printable_arch_mach (j, 0), "UNKNOWN!") != 0) + { + printf ("%11s ", bfd_printable_arch_mach (j, 0)); + for (i = first; i++ < last && target_vector[i];) + { + bfd_target *p = target_vector[i]; + bfd *abfd = bfd_openw (_DUMMY_NAME_, p->name); + int l = strlen (p->name); + int ok; + bfd_set_format (abfd, bfd_object); + ok = bfd_set_arch_mach (abfd, j, 0); + + if (ok) + printf ("%s ", p->name); + else + { + while (l--) + printf ("%c", ok ? '*' : '-'); + printf (" "); + } + } + printf ("\n"); + } +} + +static void +DEFUN_VOID (display_info) +{ + char *colum; + unsigned int i, j, columns; + extern bfd_target *target_vector[]; + extern char *getenv (); + + printf ("BFD header file version %s\n", BFD_VERSION); + for (i = 0; target_vector[i]; i++) + { + bfd_target *p = target_vector[i]; + bfd *abfd = bfd_openw (_DUMMY_NAME_, p->name); + bfd_set_format (abfd, bfd_object); + printf ("%s\n (header %s, data %s)\n", p->name, + p->header_byteorder_big_p ? "big endian" : "little endian", + p->byteorder_big_p ? "big endian" : "little endian"); + for (j = (int) bfd_arch_obscure + 1; j < (int) bfd_arch_last; j++) + if (bfd_set_arch_mach (abfd, (enum bfd_architecture) j, 0)) + printf (" %s\n", + bfd_printable_arch_mach ((enum bfd_architecture) j, 0)); + } + columns = 0; + if (colum = getenv ("COLUMNS")) + columns = atoi (colum); + if (!columns) + columns = 80; + for (i = 0; target_vector[i];) + { + int old; + old = i; + for (j = 12; target_vector[i] && j < columns; i++) + j += strlen (target_vector[i]->name) + 1; + i--; + if (old == i) + break; + display_info_table (old, i); + } +} + +/** main and like trivia */ +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + extern int optind; + extern char *optarg; + char *target = default_target; + boolean seenflag = false; + int ind = 0; + + bfd_init (); + program_name = *argv; + + while ((c = getopt_long (argc, argv, "ib:m:Vdlfahrtxsj:", long_options, &ind)) + != EOF) + { + seenflag = true; + switch (c) + { + case 'm': + machine = optarg; + break; + case 'j': + only = optarg; + break; + case 'l': + with_line_numbers = 1; + break; + case 'b': + target = optarg; + break; + case 'f': + dump_file_header = true; + break; + case 'i': + info = true; + break; + case 'x': + dump_symtab = 1; + dump_reloc_info = 1; + dump_file_header = true; + dump_ar_hdrs = 1; + dump_section_headers = 1; + break; + case 0: + break; /* we've been given a long option */ + case 't': + dump_symtab = 1; + break; + case 'd': + disassemble = true; + break; + case 's': + dump_section_contents = 1; + break; + case 'r': + dump_reloc_info = 1; + break; + case 'a': + dump_ar_hdrs = 1; + break; + case 'h': + dump_section_headers = 1; + break; + case 'V': + show_version = 1; + break; + default: + usage (); + } + } + + if (show_version) + printf ("%s version %s\n", program_name, program_version); + + if (seenflag == false) + usage (); + + if (info) + { + display_info (); + } + else + { + if (optind == argc) + display_file ("a.out", target); + else + for (; optind < argc;) + display_file (argv[optind++], target); + } + return 0; +} diff --git a/gnu/usr.bin/gdb/objdump/objdump.h b/gnu/usr.bin/gdb/objdump/objdump.h new file mode 100644 index 00000000000..14cf8f071a9 --- /dev/null +++ b/gnu/usr.bin/gdb/objdump/objdump.h @@ -0,0 +1,2 @@ + +int EXFUN(print_address,(bfd_vma, FILE*)); diff --git a/gnu/usr.bin/gdb/objdump/version.c b/gnu/usr.bin/gdb/objdump/version.c new file mode 100644 index 00000000000..5a19113953e --- /dev/null +++ b/gnu/usr.bin/gdb/objdump/version.c @@ -0,0 +1,5 @@ +/*** version.c -- version number for binutils. + They all change in lockstep -- it's easier that way +*/ + +char *program_version = VERSION; |