]> Cypherpunks repositories - gostls13.git/commitdiff
Add 6db
authorRob Pike <r@golang.org>
Thu, 12 Jun 2008 21:50:25 +0000 (14:50 -0700)
committerRob Pike <r@golang.org>
Thu, 12 Jun 2008 21:50:25 +0000 (14:50 -0700)
SVN=122505

21 files changed:
include/bootexec.h [new file with mode: 0644]
include/mach_amd64.h [new file with mode: 0644]
include/ureg_amd64.h [new file with mode: 0644]
include/ureg_x86.h [new file with mode: 0644]
src/cmd/make.bash
src/libmachamd64/6.c [new file with mode: 0644]
src/libmachamd64/6obj.c [new file with mode: 0644]
src/libmachamd64/8.c [new file with mode: 0644]
src/libmachamd64/8db.c [new file with mode: 0644]
src/libmachamd64/Makefile [new file with mode: 0644]
src/libmachamd64/access.c [new file with mode: 0644]
src/libmachamd64/elf.h [new file with mode: 0644]
src/libmachamd64/executable.c [new file with mode: 0644]
src/libmachamd64/machdata.c [new file with mode: 0644]
src/libmachamd64/map.c [new file with mode: 0644]
src/libmachamd64/obj.c [new file with mode: 0644]
src/libmachamd64/obj.h [new file with mode: 0644]
src/libmachamd64/setmach.c [new file with mode: 0644]
src/libmachamd64/swap.c [new file with mode: 0644]
src/libmachamd64/sym.c [new file with mode: 0644]
src/make.bash

diff --git a/include/bootexec.h b/include/bootexec.h
new file mode 100644 (file)
index 0000000..7442733
--- /dev/null
@@ -0,0 +1,169 @@
+// Inferno libmach/bootexec.h
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/bootexec.h
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.
+//     Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+//     Portions Copyright © 1997-1999 Vita Nuova Limited.
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+//     Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+//     Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+struct coffsect
+{
+       char    name[8];
+       ulong   phys;
+       ulong   virt;
+       ulong   size;
+       ulong   fptr;
+       ulong   fptrreloc;
+       ulong   fptrlineno;
+       ulong   nrelocnlineno;
+       ulong   flags;
+};
+
+/*
+ * proprietary exec headers, needed to bootstrap various machines
+ */
+struct mipsexec
+{
+       short   mmagic;         /* (0x160) mips magic number */
+       short   nscns;          /* (unused) number of sections */
+       long    timdat;         /* (unused) time & date stamp */
+       long    symptr;         /* offset to symbol table */
+       long    nsyms;          /* size of symbol table */
+       short   opthdr;         /* (0x38) sizeof(optional hdr) */
+       short   pcszs;          /* flags */
+       short   amagic;         /* see above */
+       short   vstamp;         /* version stamp */
+       long    tsize;          /* text size in bytes */
+       long    dsize;          /* initialized data */
+       long    bsize;          /* uninitialized data */
+       long    mentry;         /* entry pt.                            */
+       long    text_start;     /* base of text used for this file      */
+       long    data_start;     /* base of data used for this file      */
+       long    bss_start;      /* base of bss used for this file       */
+       long    gprmask;        /* general purpose register mask        */
+union{
+       long    cprmask[4];     /* co-processor register masks          */
+       long    pcsize;
+};
+       long    gp_value;       /* the gp value used for this object    */
+};
+
+struct mips4kexec
+{
+       struct mipsexec h;
+       struct coffsect itexts;
+       struct coffsect idatas;
+       struct coffsect ibsss;
+};
+
+struct sparcexec
+{
+       short   sjunk;          /* dynamic bit and version number */
+       short   smagic;         /* 0407 */
+       ulong   stext;
+       ulong   sdata;
+       ulong   sbss;
+       ulong   ssyms;
+       ulong   sentry;
+       ulong   strsize;
+       ulong   sdrsize;
+};
+
+struct nextexec
+{
+/* UNUSED
+       struct  nexthdr{
+               ulong   nmagic;
+               ulong   ncputype;
+               ulong   ncpusubtype;
+               ulong   nfiletype;
+               ulong   ncmds;
+               ulong   nsizeofcmds;
+               ulong   nflags;
+       };
+
+       struct nextcmd{
+               ulong   cmd;
+               ulong   cmdsize;
+               uchar   segname[16];
+               ulong   vmaddr;
+               ulong   vmsize;
+               ulong   fileoff;
+               ulong   filesize;
+               ulong   maxprot;
+               ulong   initprot;
+               ulong   nsects;
+               ulong   flags;
+       }textc;
+       struct nextsect{
+               char    sectname[16];
+               char    segname[16];
+               ulong   addr;
+               ulong   size;
+               ulong   offset;
+               ulong   align;
+               ulong   reloff;
+               ulong   nreloc;
+               ulong   flags;
+               ulong   reserved1;
+               ulong   reserved2;
+       }texts;
+       struct nextcmd  datac;
+       struct nextsect datas;
+       struct nextsect bsss;
+       struct nextsym{
+               ulong   cmd;
+               ulong   cmdsize;
+               ulong   symoff;
+               ulong   nsyms;
+               ulong   spoff;
+               ulong   pcoff;
+       }symc;
+*/
+};
+
+struct i386exec
+{
+/* UNUSED
+       struct  i386coff{
+               ulong   isectmagic;
+               ulong   itime;
+               ulong   isyms;
+               ulong   insyms;
+               ulong   iflags;
+       };
+       struct  i386hdr{
+               ulong   imagic;
+               ulong   itextsize;
+               ulong   idatasize;
+               ulong   ibsssize;
+               ulong   ientry;
+               ulong   itextstart;
+               ulong   idatastart;
+       };
+       struct coffsect itexts;
+       struct coffsect idatas;
+       struct coffsect ibsss;
+       struct coffsect icomments;
+*/
+};
diff --git a/include/mach_amd64.h b/include/mach_amd64.h
new file mode 100644 (file)
index 0000000..eb046d8
--- /dev/null
@@ -0,0 +1,403 @@
+// Inferno libmach/a.out.h and libmach/mach.h
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/a.out.h
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/mach.h
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.
+//     Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+//     Portions Copyright © 1997-1999 Vita Nuova Limited.
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+//     Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+/*
+ *     Architecture-dependent application data
+ *     This is just Plan 9's mach.h, tweaked to support only amd64 for now.
+ */
+/*
+ * Start of Plan 9 a.out.h
+ * Don't use system a.out; instead just lay in the Plan 9 one for now.
+ */
+/*
+#include "a.out.h"
+*/
+
+typedef        struct  Exec    Exec;
+struct Exec
+{
+       long    magic;          /* magic number */
+       long    text;           /* size of text segment */
+       long    data;           /* size of initialized data */
+       long    bss;            /* size of uninitialized data */
+       long    syms;           /* size of symbol table */
+       long    entry;          /* entry point */
+       long    spsz;           /* size of pc/sp offset table */
+       long    pcsz;           /* size of pc/line number table */
+};
+
+#define HDR_MAGIC      0x00008000              /* header expansion */
+
+#define        _MAGIC(f, b)    ((f)|((((4*(b))+0)*(b))+7))
+#define        A_MAGIC         _MAGIC(0, 8)            /* 68020 */
+#define        I_MAGIC         _MAGIC(0, 11)           /* intel 386 */
+#define        J_MAGIC         _MAGIC(0, 12)           /* intel 960 (retired) */
+#define        K_MAGIC         _MAGIC(0, 13)           /* sparc */
+#define        V_MAGIC         _MAGIC(0, 16)           /* mips 3000 BE */
+#define        X_MAGIC         _MAGIC(0, 17)           /* att dsp 3210 (retired) */
+#define        M_MAGIC         _MAGIC(0, 18)           /* mips 4000 BE */
+#define        D_MAGIC         _MAGIC(0, 19)           /* amd 29000 (retired) */
+#define        E_MAGIC         _MAGIC(0, 20)           /* arm */
+#define        Q_MAGIC         _MAGIC(0, 21)           /* powerpc */
+#define        N_MAGIC         _MAGIC(0, 22)           /* mips 4000 LE */
+#define        L_MAGIC         _MAGIC(0, 23)           /* dec alpha */
+#define        P_MAGIC         _MAGIC(0, 24)           /* mips 3000 LE */
+#define        U_MAGIC         _MAGIC(0, 25)           /* sparc64 */
+#define        S_MAGIC         _MAGIC(HDR_MAGIC, 26)   /* amd64 */
+#define        T_MAGIC         _MAGIC(HDR_MAGIC, 27)   /* powerpc64 */
+
+#define        MIN_MAGIC       8
+#define        MAX_MAGIC       27                      /* <= 90 */
+
+#define        DYN_MAGIC       0x80000000              /* dlm */
+
+typedef        struct  Sym     Sym;
+struct Sym
+{
+       vlong   value;
+       uint    sig;
+       char    type;
+       char    *name;
+};
+/*
+ * End of Plan 9 a.out.h
+ * Don't use system a.out; instead just lay in the Plan 9 one for now.
+ */
+
+
+/*
+ *     Supported architectures:
+ *             mips,
+ *             68020,
+ *             i386,
+ *             amd64,
+ *             sparc,
+ *             sparc64,
+ *             mips2 (R4000)
+ *             arm
+ *             powerpc,
+ *             powerpc64
+ *             alpha
+ */
+enum
+{
+       MMIPS,                  /* machine types */
+       MSPARC,
+       M68020,
+       MI386,
+       MI960,                  /* retired */
+       M3210,                  /* retired */
+       MMIPS2,
+       NMIPS2,
+       M29000,                 /* retired */
+       MARM,
+       MPOWER,
+       MALPHA,
+       NMIPS,
+       MSPARC64,
+       MAMD64,
+       MPOWER64,
+                               /* types of executables */
+       FNONE = 0,              /* unidentified */
+       FMIPS,                  /* v.out */
+       FMIPSB,                 /* mips bootable */
+       FSPARC,                 /* k.out */
+       FSPARCB,                /* Sparc bootable */
+       F68020,                 /* 2.out */
+       F68020B,                /* 68020 bootable */
+       FNEXTB,                 /* Next bootable */
+       FI386,                  /* 8.out */
+       FI386B,                 /* I386 bootable */
+       FI960,                  /* retired */
+       FI960B,                 /* retired */
+       F3210,                  /* retired */
+       FMIPS2BE,               /* 4.out */
+       F29000,                 /* retired */
+       FARM,                   /* 5.out */
+       FARMB,                  /* ARM bootable */
+       FPOWER,                 /* q.out */
+       FPOWERB,                /* power pc bootable */
+       FMIPS2LE,               /* 0.out */
+       FALPHA,                 /* 7.out */
+       FALPHAB,                /* DEC Alpha bootable */
+       FMIPSLE,                /* 3k little endian */
+       FSPARC64,               /* u.out */
+       FAMD64,                 /* 6.out */
+       FAMD64B,                /* 6.out bootable */
+       FPOWER64,               /* 9.out */
+       FPOWER64B,              /* 9.out bootable */
+
+       ANONE = 0,              /* dissembler types */
+       AMIPS,
+       AMIPSCO,                /* native mips */
+       ASPARC,
+       ASUNSPARC,              /* native sun */
+       A68020,
+       AI386,
+       AI8086,                 /* oh god */
+       AI960,                  /* retired */
+       A29000,                 /* retired */
+       AARM,
+       APOWER,
+       AALPHA,
+       ASPARC64,
+       AAMD64,
+       APOWER64,
+                               /* object file types */
+       Obj68020 = 0,           /* .2 */
+       ObjSparc,               /* .k */
+       ObjMips,                /* .v */
+       Obj386,                 /* .8 */
+       Obj960,                 /* retired */
+       Obj3210,                /* retired */
+       ObjMips2,               /* .4 */
+       Obj29000,               /* retired */
+       ObjArm,                 /* .5 */
+       ObjPower,               /* .q */
+       ObjMips2le,             /* .0 */
+       ObjAlpha,               /* .7 */
+       ObjSparc64,             /* .u */
+       ObjAmd64,               /* .6 */
+       ObjSpim,                /* .0 */
+       ObjPower64,             /* .9 */
+       Maxobjtype,
+
+       CNONE  = 0,             /* symbol table classes */
+       CAUTO,
+       CPARAM,
+       CSTAB,
+       CTEXT,
+       CDATA,
+       CANY,                   /* to look for any class */
+};
+
+typedef        struct  Map     Map;
+typedef struct Symbol  Symbol;
+typedef        struct  Reglist Reglist;
+typedef        struct  Mach    Mach;
+typedef        struct  Machdata Machdata;
+
+/*
+ *     Structure to map a segment to a position in a file
+ */
+struct Map {
+       int     nsegs;                  /* number of segments */
+       struct segment {                /* per-segment map */
+               char    *name;          /* the segment name */
+               int     fd;             /* file descriptor */
+               int     inuse;          /* in use - not in use */
+               int     cache;          /* should cache reads? */
+               uvlong  b;              /* base */
+               uvlong  e;              /* end */
+               vlong   f;              /* offset within file */
+       } seg[1];                       /* actually n of these */
+};
+
+/*
+ *     Internal structure describing a symbol table entry
+ */
+struct Symbol {
+       void    *handle;                /* used internally - owning func */
+       struct {
+               char    *name;
+               vlong   value;          /* address or stack offset */
+               char    type;           /* as in a.out.h */
+               char    class;          /* as above */
+               int     index;          /* in findlocal, globalsym, textsym */
+       };
+};
+
+/*
+ *     machine register description
+ */
+struct Reglist {
+       char    *rname;                 /* register name */
+       short   roffs;                  /* offset in u-block */
+       char    rflags;                 /* INTEGER/FLOAT, WRITABLE */
+       char    rformat;                /* print format: 'x', 'X', 'f', '8', '3', 'Y', 'W' */
+};
+
+enum {                                 /* bits in rflags field */
+       RINT    = (0<<0),
+       RFLT    = (1<<0),
+       RRDONLY = (1<<1),
+};
+
+/*
+ *     Machine-dependent data is stored in two structures:
+ *             Mach  - miscellaneous general parameters
+ *             Machdata - jump vector of service functions used by debuggers
+ *
+ *     Mach is defined in ?.c and set in executable.c
+ *
+ *     Machdata is defined in ?db.c
+ *             and set in the debugger startup.
+ */
+struct Mach{
+       char    *name;
+       int     mtype;                  /* machine type code */
+       Reglist *reglist;               /* register set */
+       long    regsize;                /* sizeof registers in bytes */
+       long    fpregsize;              /* sizeof fp registers in bytes */
+       char    *pc;                    /* pc name */
+       char    *sp;                    /* sp name */
+       char    *link;                  /* link register name */
+       char    *sbreg;                 /* static base register name */
+       uvlong  sb;                     /* static base register value */
+       int     pgsize;                 /* page size */
+       uvlong  kbase;                  /* kernel base address */
+       uvlong  ktmask;                 /* ktzero = kbase & ~ktmask */
+       uvlong  utop;                   /* user stack top */
+       int     pcquant;                /* quantization of pc */
+       int     szaddr;                 /* sizeof(void*) */
+       int     szreg;                  /* sizeof(register) */
+       int     szfloat;                /* sizeof(float) */
+       int     szdouble;               /* sizeof(double) */
+};
+
+extern Mach    *mach;                  /* Current machine */
+
+typedef uvlong (*Rgetter)(Map*, char*);
+typedef        void    (*Tracer)(Map*, uvlong, uvlong, Symbol*);
+
+struct Machdata {              /* Machine-dependent debugger support */
+       uchar   bpinst[4];                      /* break point instr. */
+       short   bpsize;                         /* size of break point instr. */
+
+       ushort  (*swab)(ushort);                /* ushort to local byte order */
+       ulong   (*swal)(ulong);                 /* ulong to local byte order */
+       uvlong  (*swav)(uvlong);                /* uvlong to local byte order */
+       int     (*ctrace)(Map*, uvlong, uvlong, uvlong, Tracer); /* C traceback */
+       uvlong  (*findframe)(Map*, uvlong, uvlong, uvlong, uvlong);/* frame finder */
+       char*   (*excep)(Map*, Rgetter);        /* last exception */
+       ulong   (*bpfix)(uvlong);               /* breakpoint fixup */
+       int     (*sftos)(char*, int, void*);    /* single precision float */
+       int     (*dftos)(char*, int, void*);    /* double precision float */
+       int     (*foll)(Map*, uvlong, Rgetter, uvlong*);/* follow set */
+       int     (*das)(Map*, uvlong, char, char*, int); /* symbolic disassembly */
+       int     (*hexinst)(Map*, uvlong, char*, int);   /* hex disassembly */
+       int     (*instsize)(Map*, uvlong);      /* instruction size */
+};
+
+/*
+ *     Common a.out header describing all architectures
+ */
+typedef struct Fhdr
+{
+       char    *name;          /* identifier of executable */
+       uchar   type;           /* file type - see codes above */
+       uchar   hdrsz;          /* header size */
+       uchar   _magic;         /* _MAGIC() magic */
+       uchar   spare;
+       long    magic;          /* magic number */
+       uvlong  txtaddr;        /* text address */
+       vlong   txtoff;         /* start of text in file */
+       uvlong  dataddr;        /* start of data segment */
+       vlong   datoff;         /* offset to data seg in file */
+       vlong   symoff;         /* offset of symbol table in file */
+       uvlong  entry;          /* entry point */
+       vlong   sppcoff;        /* offset of sp-pc table in file */
+       vlong   lnpcoff;        /* offset of line number-pc table in file */
+       long    txtsz;          /* text size */
+       long    datsz;          /* size of data seg */
+       long    bsssz;          /* size of bss */
+       long    symsz;          /* size of symbol table */
+       long    sppcsz;         /* size of sp-pc table */
+       long    lnpcsz;         /* size of line number-pc table */
+} Fhdr;
+
+extern int     asstype;        /* dissembler type - machdata.c */
+extern Machdata *machdata;     /* jump vector - machdata.c */
+
+Map*           attachproc(int, int, int, Fhdr*);
+int            beieee80ftos(char*, int, void*);
+int            beieeesftos(char*, int, void*);
+int            beieeedftos(char*, int, void*);
+ushort         beswab(ushort);
+ulong          beswal(ulong);
+uvlong         beswav(uvlong);
+uvlong         ciscframe(Map*, uvlong, uvlong, uvlong, uvlong);
+int            cisctrace(Map*, uvlong, uvlong, uvlong, Tracer);
+int            crackhdr(int fd, Fhdr*);
+uvlong         file2pc(char*, long);
+int            fileelem(Sym**, uchar *, char*, int);
+long           fileline(char*, int, uvlong);
+int            filesym(int, char*, int);
+int            findlocal(Symbol*, char*, Symbol*);
+int            findseg(Map*, char*);
+int            findsym(uvlong, int, Symbol *);
+int            fnbound(uvlong, uvlong*);
+int            fpformat(Map*, Reglist*, char*, int, int);
+int            get1(Map*, uvlong, uchar*, int);
+int            get2(Map*, uvlong, ushort*);
+int            get4(Map*, uvlong, ulong*);
+int            get8(Map*, uvlong, uvlong*);
+int            geta(Map*, uvlong, uvlong*);
+int            getauto(Symbol*, int, int, Symbol*);
+Sym*           getsym(int);
+int            globalsym(Symbol *, int);
+char*          _hexify(char*, ulong, int);
+int            ieeesftos(char*, int, ulong);
+int            ieeedftos(char*, int, ulong, ulong);
+int            isar(Biobuf*);
+int            leieee80ftos(char*, int, void*);
+int            leieeesftos(char*, int, void*);
+int            leieeedftos(char*, int, void*);
+ushort         leswab(ushort);
+ulong          leswal(ulong);
+uvlong         leswav(uvlong);
+uvlong         line2addr(long, uvlong, uvlong);
+Map*           loadmap(Map*, int, Fhdr*);
+int            localaddr(Map*, char*, char*, uvlong*, Rgetter);
+int            localsym(Symbol*, int);
+int            lookup(char*, char*, Symbol*);
+void           machbytype(int);
+int            machbyname(char*);
+int            nextar(Biobuf*, int, char*);
+Map*           newmap(Map*, int);
+void           objtraverse(void(*)(Sym*, void*), void*);
+int            objtype(Biobuf*, char**);
+uvlong         pc2sp(uvlong);
+long           pc2line(uvlong);
+int            put1(Map*, uvlong, uchar*, int);
+int            put2(Map*, uvlong, ushort);
+int            put4(Map*, uvlong, ulong);
+int            put8(Map*, uvlong, uvlong);
+int            puta(Map*, uvlong, uvlong);
+int            readar(Biobuf*, int, vlong, int);
+int            readobj(Biobuf*, int);
+uvlong         riscframe(Map*, uvlong, uvlong, uvlong, uvlong);
+int            risctrace(Map*, uvlong, uvlong, uvlong, Tracer);
+int            setmap(Map*, int, uvlong, uvlong, vlong, char*);
+Sym*           symbase(long*);
+int            syminit(int, Fhdr*);
+int            symoff(char*, int, uvlong, int);
+void           textseg(uvlong, Fhdr*);
+int            textsym(Symbol*, int);
+void           unusemap(Map*, int);
diff --git a/include/ureg_amd64.h b/include/ureg_amd64.h
new file mode 100644 (file)
index 0000000..2c39f17
--- /dev/null
@@ -0,0 +1,58 @@
+// Inferno utils/libmach/ureg6.h
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/ureg6.h
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.
+//     Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+//     Portions Copyright © 1997-1999 Vita Nuova Limited.
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+//     Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+struct Ureg {
+       u64int  ax;
+       u64int  bx;
+       u64int  cx;
+       u64int  dx;
+       u64int  si;
+       u64int  di;
+       u64int  bp;
+       u64int  r8;
+       u64int  r9;
+       u64int  r10;
+       u64int  r11;
+       u64int  r12;
+       u64int  r13;
+       u64int  r14;
+       u64int  r15;
+
+       u16int  ds;
+       u16int  es;
+       u16int  fs;
+       u16int  gs;
+
+       u64int  type;
+       u64int  error;          /* error code (or zero) */
+       u64int  ip;             /* pc */
+       u64int  cs;             /* old context */
+       u64int  flags;          /* old flags */
+       u64int  sp;             /* sp */
+       u64int  ss;             /* old stack segment */
+};
diff --git a/include/ureg_x86.h b/include/ureg_x86.h
new file mode 100644 (file)
index 0000000..84d32fc
--- /dev/null
@@ -0,0 +1,53 @@
+// Inferno utils/libmach/ureg8.h
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/ureg8.h
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.
+//     Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+//     Portions Copyright © 1997-1999 Vita Nuova Limited.
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+//     Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+struct Ureg
+{
+       ulong   di;             /* general registers */
+       ulong   si;             /* ... */
+       ulong   bp;             /* ... */
+       ulong   nsp;
+       ulong   bx;             /* ... */
+       ulong   dx;             /* ... */
+       ulong   cx;             /* ... */
+       ulong   ax;             /* ... */
+       ulong   gs;             /* data segments */
+       ulong   fs;             /* ... */
+       ulong   es;             /* ... */
+       ulong   ds;             /* ... */
+       ulong   trap;           /* trap type */
+       ulong   ecode;          /* error code (or zero) */
+       ulong   pc;             /* pc */
+       ulong   cs;             /* old context */
+       ulong   flags;          /* old flags */
+       union {
+               ulong   usp;
+               ulong   sp;
+       };
+       ulong   ss;             /* old stack segment */
+};
index 83c97039c2408fafcf9cd6285732fd1a4498af75..349aa3954055c294b53faef87f85b6822e3b5619 100644 (file)
@@ -40,3 +40,8 @@ echo; echo; echo %%%% making 6g %%%%; echo
 cd 6g
 make install
 cd ..
+
+echo; echo; echo %%%% making db %%%%; echo
+cd db
+make install
+cd ..
diff --git a/src/libmachamd64/6.c b/src/libmachamd64/6.c
new file mode 100644 (file)
index 0000000..1d470c3
--- /dev/null
@@ -0,0 +1,145 @@
+// Inferno libmach/6.c
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/6.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.
+//     Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+//     Portions Copyright © 1997-1999 Vita Nuova Limited.
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+//     Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+/*
+ * amd64 definition
+ */
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "ureg_amd64.h"
+#include <mach_amd64.h>
+
+#define        REGOFF(x)       offsetof(struct Ureg, x)
+
+#define        REGSIZE         sizeof(struct Ureg)
+#define FP_CTLS(x)     (REGSIZE+2*(x))
+#define FP_CTL(x)      (REGSIZE+4*(x))
+#define FP_REG(x)      (FP_CTL(8)+16*(x))
+#define XM_REG(x)      (FP_CTL(8)+8*16+16*(x))
+
+#define        FPREGSIZE       512     /* TO DO? currently only 0x1A0 used */
+
+Reglist amd64reglist[] = {
+       {"AX",          REGOFF(ax),     RINT, 'Y'},
+       {"BX",          REGOFF(bx),     RINT, 'Y'},
+       {"CX",          REGOFF(cx),     RINT, 'Y'},
+       {"DX",          REGOFF(dx),     RINT, 'Y'},
+       {"SI",          REGOFF(si),     RINT, 'Y'},
+       {"DI",          REGOFF(di),     RINT, 'Y'},
+       {"BP",          REGOFF(bp),     RINT, 'Y'},
+       {"R8",          REGOFF(r8),     RINT, 'Y'},
+       {"R9",          REGOFF(r9),     RINT, 'Y'},
+       {"R10",         REGOFF(r10),    RINT, 'Y'},
+       {"R11",         REGOFF(r11),    RINT, 'Y'},
+       {"R12",         REGOFF(r12),    RINT, 'Y'},
+       {"R13",         REGOFF(r13),    RINT, 'Y'},
+       {"R14",         REGOFF(r14),    RINT, 'Y'},
+       {"R15",         REGOFF(r15),    RINT, 'Y'},
+       {"DS",          REGOFF(ds),     RINT, 'x'},
+       {"ES",          REGOFF(es),     RINT, 'x'},
+       {"FS",          REGOFF(fs),     RINT, 'x'},
+       {"GS",          REGOFF(gs),     RINT, 'x'},
+       {"TYPE",        REGOFF(type),   RINT, 'Y'},
+       {"TRAP",        REGOFF(type),   RINT, 'Y'},     /* alias for acid */
+       {"ERROR",       REGOFF(error),  RINT, 'Y'},
+       {"IP",          REGOFF(ip),     RINT, 'Y'},
+       {"PC",          REGOFF(ip),     RINT, 'Y'},     /* alias for acid */
+       {"CS",          REGOFF(cs),     RINT, 'Y'},
+       {"FLAGS",       REGOFF(flags),  RINT, 'Y'},
+       {"SP",          REGOFF(sp),     RINT, 'Y'},
+       {"SS",          REGOFF(ss),     RINT, 'Y'},
+
+       {"FCW",         FP_CTLS(0),     RFLT, 'x'},
+       {"FSW",         FP_CTLS(1),     RFLT, 'x'},
+       {"FTW",         FP_CTLS(2),     RFLT, 'b'},
+       {"FOP",         FP_CTLS(3),     RFLT, 'x'},
+       {"RIP",         FP_CTL(2),      RFLT, 'Y'},
+       {"RDP",         FP_CTL(4),      RFLT, 'Y'},
+       {"MXCSR",       FP_CTL(6),      RFLT, 'X'},
+       {"MXCSRMASK",   FP_CTL(7),      RFLT, 'X'},
+       {"M0",          FP_REG(0),      RFLT, 'F'},     /* assumes double */
+       {"M1",          FP_REG(1),      RFLT, 'F'},
+       {"M2",          FP_REG(2),      RFLT, 'F'},
+       {"M3",          FP_REG(3),      RFLT, 'F'},
+       {"M4",          FP_REG(4),      RFLT, 'F'},
+       {"M5",          FP_REG(5),      RFLT, 'F'},
+       {"M6",          FP_REG(6),      RFLT, 'F'},
+       {"M7",          FP_REG(7),      RFLT, 'F'},
+       {"X0",          XM_REG(0),      RFLT, 'F'},     /* assumes double */
+       {"X1",          XM_REG(1),      RFLT, 'F'},
+       {"X2",          XM_REG(2),      RFLT, 'F'},
+       {"X3",          XM_REG(3),      RFLT, 'F'},
+       {"X4",          XM_REG(4),      RFLT, 'F'},
+       {"X5",          XM_REG(5),      RFLT, 'F'},
+       {"X6",          XM_REG(6),      RFLT, 'F'},
+       {"X7",          XM_REG(7),      RFLT, 'F'},
+       {"X8",          XM_REG(8),      RFLT, 'F'},
+       {"X9",          XM_REG(9),      RFLT, 'F'},
+       {"X10",         XM_REG(10),     RFLT, 'F'},
+       {"X11",         XM_REG(11),     RFLT, 'F'},
+       {"X12",         XM_REG(12),     RFLT, 'F'},
+       {"X13",         XM_REG(13),     RFLT, 'F'},
+       {"X14",         XM_REG(14),     RFLT, 'F'},
+       {"X15",         XM_REG(15),     RFLT, 'F'},
+       {"X16",         XM_REG(16),     RFLT, 'F'},
+/*
+       {"F0",          FP_REG(7),      RFLT, '3'},
+       {"F1",          FP_REG(6),      RFLT, '3'},
+       {"F2",          FP_REG(5),      RFLT, '3'},
+       {"F3",          FP_REG(4),      RFLT, '3'},
+       {"F4",          FP_REG(3),      RFLT, '3'},
+       {"F5",          FP_REG(2),      RFLT, '3'},
+       {"F6",          FP_REG(1),      RFLT, '3'},
+       {"F7",          FP_REG(0),      RFLT, '3'},
+*/
+       {  0 }
+};
+
+Mach mamd64=
+{
+       "amd64",
+       MAMD64,                 /* machine type */
+       amd64reglist,           /* register list */
+       REGSIZE,                /* size of registers in bytes */
+       FPREGSIZE,              /* size of fp registers in bytes */
+       "PC",                   /* name of PC */
+       "SP",                   /* name of SP */
+       0,                      /* link register */
+       "setSB",                /* static base register name (bogus anyways) */
+       0,                      /* static base register value */
+       0x1000,                 /* page size */
+       0xFFFFFFFF80110000ULL,  /* kernel base */
+       0xFFFF800000000000ULL,  /* kernel text mask */
+       0x00007FFFFFFFF000ULL,  /* user stack top */
+       1,                      /* quantization of pc */
+       8,                      /* szaddr */
+       4,                      /* szreg */
+       4,                      /* szfloat */
+       8,                      /* szdouble */
+};
diff --git a/src/libmachamd64/6obj.c b/src/libmachamd64/6obj.c
new file mode 100644 (file)
index 0000000..62c218e
--- /dev/null
@@ -0,0 +1,175 @@
+// Inferno libmach/6obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/6obj.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.
+//     Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+//     Portions Copyright © 1997-1999 Vita Nuova Limited.
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+//     Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+/*
+ * 6obj.c - identify and parse an amd64 object file
+ */
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach_amd64.h>
+#include "../cmd/6l/6.out.h"
+#include "obj.h"
+
+typedef struct Addr    Addr;
+struct Addr
+{
+       char    sym;
+       char    flags;
+};
+static Addr    addr(Biobuf*);
+static char    type2char(int);
+static void    skip(Biobuf*, int);
+
+int
+_is6(char *t)
+{
+       uchar *s = (uchar*)t;
+
+       return  s[0] == (ANAME&0xff)                    /* aslo = ANAME */
+               && s[1] == ((ANAME>>8)&0xff)
+               && s[2] == D_FILE                       /* type */
+               && s[3] == 1                            /* sym */
+               && s[4] == '<';                         /* name of file */
+}
+
+int
+_read6(Biobuf *bp, Prog* p)
+{
+       int as, n, c;
+       Addr a;
+
+       as = Bgetc(bp);         /* as(low) */
+       if(as < 0)
+               return 0;
+       c = Bgetc(bp);          /* as(high) */
+       if(c < 0)
+               return 0;
+       as |= ((c & 0xff) << 8);
+       p->kind = aNone;
+       p->sig = 0;
+       if(as == ANAME || as == ASIGNAME){
+               if(as == ASIGNAME){
+                       Bread(bp, &p->sig, 4);
+                       p->sig = leswal(p->sig);
+               }
+               p->kind = aName;
+               p->type = type2char(Bgetc(bp));         /* type */
+               p->sym = Bgetc(bp);                     /* sym */
+               n = 0;
+               for(;;) {
+                       as = Bgetc(bp);
+                       if(as < 0)
+                               return 0;
+                       n++;
+                       if(as == 0)
+                               break;
+               }
+               p->id = malloc(n);
+               if(p->id == 0)
+                       return 0;
+               Bseek(bp, -n, 1);
+               if(Bread(bp, p->id, n) != n)
+                       return 0;
+               return 1;
+       }
+       if(as == ATEXT)
+               p->kind = aText;
+       if(as == AGLOBL)
+               p->kind = aData;
+       skip(bp, 4);            /* lineno(4) */
+       a = addr(bp);
+       addr(bp);
+       if(!(a.flags & T_SYM))
+               p->kind = aNone;
+       p->sym = a.sym;
+       return 1;
+}
+
+static Addr
+addr(Biobuf *bp)
+{
+       Addr a;
+       int t;
+       long l;
+       vlong off;
+
+       off = 0;
+       a.sym = -1;
+       a.flags = Bgetc(bp);                    /* flags */
+       if(a.flags & T_INDEX)
+               skip(bp, 2);
+       if(a.flags & T_OFFSET){
+               l = Bgetc(bp);
+               l |= Bgetc(bp) << 8;
+               l |= Bgetc(bp) << 16;
+               l |= Bgetc(bp) << 24;
+               off = l;
+               if(a.flags & T_64){
+                       l = Bgetc(bp);
+                       l |= Bgetc(bp) << 8;
+                       l |= Bgetc(bp) << 16;
+                       l |= Bgetc(bp) << 24;
+                       off = ((vlong)l << 32) | (off & 0xFFFFFFFF);
+               }
+               if(off < 0)
+                       off = -off;
+       }
+       if(a.flags & T_SYM)
+               a.sym = Bgetc(bp);
+       if(a.flags & T_FCONST)
+               skip(bp, 8);
+       else
+       if(a.flags & T_SCONST)
+               skip(bp, NSNAME);
+       if(a.flags & T_TYPE) {
+               t = Bgetc(bp);
+               if(a.sym > 0 && (t==D_PARAM || t==D_AUTO))
+                       _offset(a.sym, off);
+       }
+       return a;
+}
+
+static char
+type2char(int t)
+{
+       switch(t){
+       case D_EXTERN:          return 'U';
+       case D_STATIC:          return 'b';
+       case D_AUTO:            return 'a';
+       case D_PARAM:           return 'p';
+       default:                return UNKNOWN;
+       }
+}
+
+static void
+skip(Biobuf *bp, int n)
+{
+       while (n-- > 0)
+               Bgetc(bp);
+}
diff --git a/src/libmachamd64/8.c b/src/libmachamd64/8.c
new file mode 100644 (file)
index 0000000..b6c87be
--- /dev/null
@@ -0,0 +1,107 @@
+// Inferno libmach/8.c
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/8.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.
+//     Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+//     Portions Copyright © 1997-1999 Vita Nuova Limited.
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+//     Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+/*
+ * 386 definition
+ */
+#include <u.h>
+#include <bio.h>
+#include <ureg_x86.h>
+#include <mach_amd64.h>
+
+#define        REGOFF(x)       (ulong)(&((struct Ureg *) 0)->x)
+
+#define PC             REGOFF(pc)
+#define SP             REGOFF(sp)
+#define        AX              REGOFF(ax)
+
+#define        REGSIZE         sizeof(struct Ureg)
+#define FP_CTL(x)      (REGSIZE+4*(x))
+#define FP_REG(x)      (FP_CTL(7)+10*(x))
+#define        FPREGSIZE       (7*4+8*10)
+
+Reglist i386reglist[] = {
+       {"DI",          REGOFF(di),     RINT, 'X'},
+       {"SI",          REGOFF(si),     RINT, 'X'},
+       {"BP",          REGOFF(bp),     RINT, 'X'},
+       {"BX",          REGOFF(bx),     RINT, 'X'},
+       {"DX",          REGOFF(dx),     RINT, 'X'},
+       {"CX",          REGOFF(cx),     RINT, 'X'},
+       {"AX",          REGOFF(ax),     RINT, 'X'},
+       {"GS",          REGOFF(gs),     RINT, 'X'},
+       {"FS",          REGOFF(fs),     RINT, 'X'},
+       {"ES",          REGOFF(es),     RINT, 'X'},
+       {"DS",          REGOFF(ds),     RINT, 'X'},
+       {"TRAP",        REGOFF(trap),   RINT, 'X'},
+       {"ECODE",       REGOFF(ecode),  RINT, 'X'},
+       {"PC",          PC,             RINT, 'X'},
+       {"CS",          REGOFF(cs),     RINT, 'X'},
+       {"EFLAGS",      REGOFF(flags),  RINT, 'X'},
+       {"SP",          SP,             RINT, 'X'},
+       {"SS",          REGOFF(ss),     RINT, 'X'},
+
+       {"E0",          FP_CTL(0),      RFLT, 'X'},
+       {"E1",          FP_CTL(1),      RFLT, 'X'},
+       {"E2",          FP_CTL(2),      RFLT, 'X'},
+       {"E3",          FP_CTL(3),      RFLT, 'X'},
+       {"E4",          FP_CTL(4),      RFLT, 'X'},
+       {"E5",          FP_CTL(5),      RFLT, 'X'},
+       {"E6",          FP_CTL(6),      RFLT, 'X'},
+       {"F0",          FP_REG(0),      RFLT, '3'},
+       {"F1",          FP_REG(1),      RFLT, '3'},
+       {"F2",          FP_REG(2),      RFLT, '3'},
+       {"F3",          FP_REG(3),      RFLT, '3'},
+       {"F4",          FP_REG(4),      RFLT, '3'},
+       {"F5",          FP_REG(5),      RFLT, '3'},
+       {"F6",          FP_REG(6),      RFLT, '3'},
+       {"F7",          FP_REG(7),      RFLT, '3'},
+       {  0 }
+};
+
+Mach mi386 =
+{
+       "386",
+       MI386,          /* machine type */
+       i386reglist,    /* register list */
+       REGSIZE,        /* size of registers in bytes */
+       FPREGSIZE,      /* size of fp registers in bytes */
+       "PC",           /* name of PC */
+       "SP",           /* name of SP */
+       0,              /* link register */
+       "setSB",        /* static base register name (bogus anyways) */
+       0,              /* static base register value */
+       0x1000,         /* page size */
+       0x80100000ULL,  /* kernel base */
+       0xF0000000ULL,  /* kernel text mask */
+       0x7FFFFFFFULL,  /* user stack top */
+       1,              /* quantization of pc */
+       4,              /* szaddr */
+       4,              /* szreg */
+       4,              /* szfloat */
+       8,              /* szdouble */
+};
diff --git a/src/libmachamd64/8db.c b/src/libmachamd64/8db.c
new file mode 100644 (file)
index 0000000..0ded151
--- /dev/null
@@ -0,0 +1,2204 @@
+// Inferno libmach/8db.c
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/8db.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.
+//     Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+//     Portions Copyright © 1997-1999 Vita Nuova Limited.
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+//     Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach_amd64.h>
+
+/*
+ * i386-specific debugger interface
+ * also amd64 extensions
+ */
+
+static char    *i386excep(Map*, Rgetter);
+
+static int     i386trace(Map*, uvlong, uvlong, uvlong, Tracer);
+static uvlong  i386frame(Map*, uvlong, uvlong, uvlong, uvlong);
+static int     i386foll(Map*, uvlong, Rgetter, uvlong*);
+static int     i386inst(Map*, uvlong, char, char*, int);
+static int     i386das(Map*, uvlong, char*, int);
+static int     i386instlen(Map*, uvlong);
+
+static char    STARTSYM[] =    "_main";
+static char    PROFSYM[] =     "_mainp";
+static char    FRAMENAME[] =   ".frame";
+static char *excname[] =
+{
+[0]    "divide error",
+[1]    "debug exception",
+[4]    "overflow",
+[5]    "bounds check",
+[6]    "invalid opcode",
+[7]    "math coprocessor emulation",
+[8]    "double fault",
+[9]    "math coprocessor overrun",
+[10]   "invalid TSS",
+[11]   "segment not present",
+[12]   "stack exception",
+[13]   "general protection violation",
+[14]   "page fault",
+[16]   "math coprocessor error",
+[17]   "alignment check",
+[18]   "machine check",
+[19]   "floating-point exception",
+[24]   "clock",
+[25]   "keyboard",
+[27]   "modem status",
+[28]   "serial line status",
+[30]   "floppy disk",
+[36]   "mouse",
+[37]   "math coprocessor",
+[38]   "hard disk",
+[64]   "system call",
+};
+
+Machdata i386mach =
+{
+       {0xCC, 0, 0, 0},        /* break point: INT 3 */
+       1,                      /* break point size */
+
+       leswab,                 /* convert short to local byte order */
+       leswal,                 /* convert long to local byte order */
+       leswav,                 /* convert vlong to local byte order */
+       i386trace,              /* C traceback */
+       i386frame,              /* frame finder */
+       i386excep,              /* print exception */
+       0,                      /* breakpoint fixup */
+       leieeesftos,            /* single precision float printer */
+       leieeedftos,            /* double precision float printer */
+       i386foll,               /* following addresses */
+       i386inst,               /* print instruction */
+       i386das,                /* dissembler */
+       i386instlen,            /* instruction size calculation */
+};
+
+static char*
+i386excep(Map *map, Rgetter rget)
+{
+       ulong c;
+       uvlong pc;
+       static char buf[16];
+
+       c = (*rget)(map, "TRAP");
+       if(c > 64 || excname[c] == 0) {
+               if (c == 3) {
+                       pc = (*rget)(map, "PC");
+                       if (get1(map, pc, (uchar*)buf, machdata->bpsize) > 0)
+                       if (memcmp(buf, machdata->bpinst, machdata->bpsize) == 0)
+                               return "breakpoint";
+               }
+               snprint(buf, sizeof(buf), "exception %ld", c);
+               return buf;
+       } else
+               return excname[c];
+}
+
+static int
+i386trace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace)
+{
+       int i;
+       uvlong osp;
+       Symbol s, f;
+
+       USED(link);
+       i = 0;
+       osp = 0;
+       while(findsym(pc, CTEXT, &s)) {
+               if (osp == sp)
+                       break;
+               osp = sp;
+
+               if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
+                       break;
+
+               if(pc != s.value) {     /* not at first instruction */
+                       if(findlocal(&s, FRAMENAME, &f) == 0)
+                               break;
+                       sp += f.value-mach->szaddr;
+               }
+
+               if (geta(map, sp, &pc) < 0)
+                       break;
+
+               if(pc == 0)
+                       break;
+
+               (*trace)(map, pc, sp, &s);
+               sp += mach->szaddr;
+
+               if(++i > 1000)
+                       break;
+       }
+       return i;
+}
+
+static uvlong
+i386frame(Map *map, uvlong addr, uvlong pc, uvlong sp, uvlong link)
+{
+       Symbol s, f;
+
+       USED(link);
+       while (findsym(pc, CTEXT, &s)) {
+               if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
+                       break;
+
+               if(pc != s.value) {     /* not first instruction */
+                       if(findlocal(&s, FRAMENAME, &f) == 0)
+                               break;
+                       sp += f.value-mach->szaddr;
+               }
+
+               if (s.value == addr)
+                       return sp;
+
+               if (geta(map, sp, &pc) < 0)
+                       break;
+               sp += mach->szaddr;
+       }
+       return 0;
+}
+
+       /* I386/486 - Disassembler and related functions */
+
+/*
+ *  an instruction
+ */
+typedef struct Instr Instr;
+struct Instr
+{
+       uchar   mem[1+1+1+1+2+1+1+4+4];         /* raw instruction */
+       uvlong  addr;           /* address of start of instruction */
+       int     n;              /* number of bytes in instruction */
+       char    *prefix;        /* instr prefix */
+       char    *segment;       /* segment override */
+       uchar   jumptype;       /* set to the operand type for jump/ret/call */
+       uchar   amd64;
+       uchar   rex;            /* REX prefix (or zero) */
+       char    osize;          /* 'W' or 'L' (or 'Q' on amd64) */
+       char    asize;          /* address size 'W' or 'L' (or 'Q' or amd64) */
+       uchar   mod;            /* bits 6-7 of mod r/m field */
+       uchar   reg;            /* bits 3-5 of mod r/m field */
+       char    ss;             /* bits 6-7 of SIB */
+       char    index;          /* bits 3-5 of SIB */
+       char    base;           /* bits 0-2 of SIB */
+       char    rip;            /* RIP-relative in amd64 mode */
+       uchar   opre;           /* f2/f3 could introduce media */
+       short   seg;            /* segment of far address */
+       ulong   disp;           /* displacement */
+       ulong   imm;            /* immediate */
+       ulong   imm2;           /* second immediate operand */
+       uvlong  imm64;          /* big immediate */
+       char    *curr;          /* fill level in output buffer */
+       char    *end;           /* end of output buffer */
+       char    *err;           /* error message */
+};
+
+       /* 386 register (ha!) set */
+enum{
+       AX=0,
+       CX,
+       DX,
+       BX,
+       SP,
+       BP,
+       SI,
+       DI,
+
+       /* amd64 */
+       R8,
+       R9,
+       R10,
+       R11,
+       R12,
+       R13,
+       R14,
+       R15
+};
+
+       /* amd64 rex extension byte */
+enum{
+       REXW            = 1<<3, /* =1, 64-bit operand size */
+       REXR            = 1<<2, /* extend modrm reg */
+       REXX            = 1<<1, /* extend sib index */
+       REXB            = 1<<0  /* extend modrm r/m, sib base, or opcode reg */
+};
+       
+       /* Operand Format codes */
+/*
+%A     -       address size register modifier (!asize -> 'E')
+%C     -       Control register CR0/CR1/CR2
+%D     -       Debug register DR0/DR1/DR2/DR3/DR6/DR7
+%I     -       second immediate operand
+%O     -       Operand size register modifier (!osize -> 'E')
+%T     -       Test register TR6/TR7
+%S     -       size code ('W' or 'L')
+%W     -       Weird opcode: OSIZE == 'W' => "CBW"; else => "CWDE"
+%d     -       displacement 16-32 bits
+%e     -       effective address - Mod R/M value
+%f     -       floating point register F0-F7 - from Mod R/M register
+%g     -       segment register
+%i     -       immediate operand 8-32 bits
+%p     -       PC-relative - signed displacement in immediate field
+%r     -       Reg from Mod R/M
+%w     -       Weird opcode: OSIZE == 'W' => "CWD"; else => "CDQ"
+*/
+
+typedef struct Optable Optable;
+struct Optable
+{
+       char    operand[2];
+       void    *proto;         /* actually either (char*) or (Optable*) */
+};
+       /* Operand decoding codes */
+enum {
+       Ib = 1,                 /* 8-bit immediate - (no sign extension)*/
+       Ibs,                    /* 8-bit immediate (sign extended) */
+       Jbs,                    /* 8-bit sign-extended immediate in jump or call */
+       Iw,                     /* 16-bit immediate -> imm */
+       Iw2,                    /* 16-bit immediate -> imm2 */
+       Iwd,                    /* Operand-sized immediate (no sign extension)*/
+       Iwdq,                   /* Operand-sized immediate, possibly 64 bits */
+       Awd,                    /* Address offset */
+       Iwds,                   /* Operand-sized immediate (sign extended) */
+       RM,                     /* Word or long R/M field with register (/r) */
+       RMB,                    /* Byte R/M field with register (/r) */
+       RMOP,                   /* Word or long R/M field with op code (/digit) */
+       RMOPB,                  /* Byte R/M field with op code (/digit) */
+       RMR,                    /* R/M register only (mod = 11) */
+       RMM,                    /* R/M memory only (mod = 0/1/2) */
+       R0,                     /* Base reg of Mod R/M is literal 0x00 */
+       R1,                     /* Base reg of Mod R/M is literal 0x01 */
+       FRMOP,                  /* Floating point R/M field with opcode */
+       FRMEX,                  /* Extended floating point R/M field with opcode */
+       JUMP,                   /* Jump or Call flag - no operand */
+       RET,                    /* Return flag - no operand */
+       OA,                     /* literal 0x0a byte */
+       PTR,                    /* Seg:Displacement addr (ptr16:16 or ptr16:32) */
+       AUX,                    /* Multi-byte op code - Auxiliary table */
+       AUXMM,                  /* multi-byte op code - auxiliary table chosen by prefix */
+       PRE,                    /* Instr Prefix */
+       OPRE,                   /* Instr Prefix or media op extension */
+       SEG,                    /* Segment Prefix */
+       OPOVER,                 /* Operand size override */
+       ADDOVER,                /* Address size override */
+};
+       
+static Optable optab0F00[8]=
+{
+[0x00] 0,0,            "MOVW   LDT,%e",
+[0x01] 0,0,            "MOVW   TR,%e",
+[0x02] 0,0,            "MOVW   %e,LDT",
+[0x03] 0,0,            "MOVW   %e,TR",
+[0x04] 0,0,            "VERR   %e",
+[0x05] 0,0,            "VERW   %e",
+};
+
+static Optable optab0F01[8]=
+{
+[0x00] 0,0,            "MOVL   GDTR,%e",
+[0x01] 0,0,            "MOVL   IDTR,%e",
+[0x02] 0,0,            "MOVL   %e,GDTR",
+[0x03] 0,0,            "MOVL   %e,IDTR",
+[0x04] 0,0,            "MOVW   MSW,%e",        /* word */
+[0x06] 0,0,            "MOVW   %e,MSW",        /* word */
+[0x07] 0,0,            "INVLPG %e",            /* or SWAPGS */
+};
+
+static Optable optab0F01F8[1]=
+{
+[0x00] 0,0,            "SWAPGS",
+};
+
+/* 0F71 */
+/* 0F72 */
+/* 0F73 */
+
+static Optable optab0FAE[8]=
+{
+[0x00] 0,0,            "FXSAVE %e",
+[0x01] 0,0,            "FXRSTOR        %e",
+[0x02] 0,0,            "LDMXCSR        %e",
+[0x03] 0,0,            "STMXCSR        %e",
+[0x05] 0,0,            "LFENCE",
+[0x06] 0,0,            "MFENCE",
+[0x07] 0,0,            "SFENCE",
+};
+
+/* 0F18 */
+/* 0F0D */
+
+static Optable optab0FBA[8]=
+{
+[0x04] Ib,0,           "BT%S   %i,%e",
+[0x05] Ib,0,           "BTS%S  %i,%e",
+[0x06] Ib,0,           "BTR%S  %i,%e",
+[0x07] Ib,0,           "BTC%S  %i,%e",
+};
+
+static Optable optab0F0F[256]=
+{
+[0x0c] 0,0,            "PI2FW  %m,%M",
+[0x0d] 0,0,            "PI2L   %m,%M",
+[0x1c] 0,0,            "PF2IW  %m,%M",
+[0x1d] 0,0,            "PF2IL  %m,%M",
+[0x8a] 0,0,            "PFNACC %m,%M",
+[0x8e] 0,0,            "PFPNACC        %m,%M",
+[0x90] 0,0,            "PFCMPGE        %m,%M",
+[0x94] 0,0,            "PFMIN  %m,%M",
+[0x96] 0,0,            "PFRCP  %m,%M",
+[0x97] 0,0,            "PFRSQRT        %m,%M",
+[0x9a] 0,0,            "PFSUB  %m,%M",
+[0x9e] 0,0,            "PFADD  %m,%M",
+[0xa0] 0,0,            "PFCMPGT        %m,%M",
+[0xa4] 0,0,            "PFMAX  %m,%M",
+[0xa6] 0,0,            "PFRCPIT1       %m,%M",
+[0xa7] 0,0,            "PFRSQIT1       %m,%M",
+[0xaa] 0,0,            "PFSUBR %m,%M",
+[0xae] 0,0,            "PFACC  %m,%M",
+[0xb0] 0,0,            "PFCMPEQ        %m,%M",
+[0xb4] 0,0,            "PFMUL  %m,%M",
+[0xb6] 0,0,            "PFRCPI2T       %m,%M",
+[0xb7] 0,0,            "PMULHRW        %m,%M",
+[0xbb] 0,0,            "PSWAPL %m,%M",
+};
+
+static Optable optab0FC7[8]=
+{
+[0x01] 0,0,            "CMPXCHG8B      %e",
+};
+
+static Optable optab660F71[8]=
+{
+[0x02] Ib,0,           "PSRLW  %i,%X",
+[0x04] Ib,0,           "PSRAW  %i,%X",
+[0x06] Ib,0,           "PSLLW  %i,%X",
+};
+
+static Optable optab660F72[8]=
+{
+[0x02] Ib,0,           "PSRLL  %i,%X",
+[0x04] Ib,0,           "PSRAL  %i,%X",
+[0x06] Ib,0,           "PSLLL  %i,%X",
+};
+
+static Optable optab660F73[8]=
+{
+[0x02] Ib,0,           "PSRLQ  %i,%X",
+[0x03] Ib,0,           "PSRLO  %i,%X",
+[0x06] Ib,0,           "PSLLQ  %i,%X",
+[0x07] Ib,0,           "PSLLO  %i,%X",
+};
+
+static Optable optab660F[256]=
+{
+[0x2B] RM,0,           "MOVNTPD        %x,%e",
+[0x2E] RM,0,           "UCOMISD        %x,%X",
+[0x2F] RM,0,           "COMISD %x,%X",
+[0x5A] RM,0,           "CVTPD2PS       %x,%X",
+[0x5B] RM,0,           "CVTPS2PL       %x,%X",
+[0x6A] RM,0,           "PUNPCKHLQ %x,%X",
+[0x6B] RM,0,           "PACKSSLW %x,%X",
+[0x6C] RM,0,           "PUNPCKLQDQ %x,%X",
+[0x6D] RM,0,           "PUNPCKHQDQ %x,%X",
+[0x6E] RM,0,           "MOV%S  %e,%X",
+[0x6F] RM,0,           "MOVO   %x,%X",         /* MOVDQA */
+[0x70] RM,Ib,          "PSHUFL %i,%x,%X",
+[0x71] RMOP,0,         optab660F71,
+[0x72] RMOP,0,         optab660F72,
+[0x73] RMOP,0,         optab660F73,
+[0x7E] RM,0,           "MOV%S  %X,%e",
+[0x7F] RM,0,           "MOVO   %X,%x",
+[0xC4] RM,Ib,          "PINSRW %i,%e,%X",
+[0xC5] RMR,Ib,         "PEXTRW %i,%X,%e",
+[0xD4] RM,0,           "PADDQ  %x,%X",
+[0xD5] RM,0,           "PMULLW %x,%X",
+[0xD6] RM,0,           "MOVQ   %X,%x",
+[0xE6] RM,0,           "CVTTPD2PL      %x,%X",
+[0xE7] RM,0,           "MOVNTO %X,%e",
+[0xF7] RM,0,           "MASKMOVOU      %x,%X",
+};
+
+static Optable optabF20F[256]=
+{
+[0x10] RM,0,           "MOVSD  %x,%X",
+[0x11] RM,0,           "MOVSD  %X,%x",
+[0x2A] RM,0,           "CVTS%S2SD      %e,%X",
+[0x2C] RM,0,           "CVTTSD2S%S     %x,%r",
+[0x2D] RM,0,           "CVTSD2S%S      %x,%r",
+[0x5A] RM,0,           "CVTSD2SS       %x,%X",
+[0x6F] RM,0,           "MOVOU  %x,%X",
+[0x70] RM,Ib,          "PSHUFLW        %i,%x,%X",
+[0x7F] RM,0,           "MOVOU  %X,%x",
+[0xD6] RM,0,           "MOVQOZX        %M,%X",
+[0xE6] RM,0,           "CVTPD2PL       %x,%X",
+};
+
+static Optable optabF30F[256]=
+{
+[0x10] RM,0,           "MOVSS  %x,%X",
+[0x11] RM,0,           "MOVSS  %X,%x",
+[0x2A] RM,0,           "CVTS%S2SS      %e,%X",
+[0x2C] RM,0,           "CVTTSS2S%S     %x,%r",
+[0x2D] RM,0,           "CVTSS2S%S      %x,%r",
+[0x5A] RM,0,           "CVTSS2SD       %x,%X",
+[0x5B] RM,0,           "CVTTPS2PL      %x,%X",
+[0x6F] RM,0,           "MOVOU  %x,%X",
+[0x70] RM,Ib,          "PSHUFHW        %i,%x,%X",
+[0x7E] RM,0,           "MOVQOZX        %x,%X",
+[0x7F] RM,0,           "MOVOU  %X,%x",
+[0xD6] RM,0,           "MOVQOZX        %m*,%X",
+[0xE6] RM,0,           "CVTPL2PD       %x,%X",
+};
+
+static Optable optab0F[256]=
+{
+[0x00] RMOP,0,         optab0F00,
+[0x01] RMOP,0,         optab0F01,
+[0x02] RM,0,           "LAR    %e,%r",
+[0x03] RM,0,           "LSL    %e,%r",
+[0x05] 0,0,            "SYSCALL",
+[0x06] 0,0,            "CLTS",
+[0x07] 0,0,            "SYSRET",
+[0x08] 0,0,            "INVD",
+[0x09] 0,0,            "WBINVD",
+[0x0B] 0,0,            "UD2",
+[0x0F] RM,AUX,         optab0F0F,              /* 3DNow! */
+[0x10] RM,0,           "MOVU%s %x,%X",
+[0x11] RM,0,           "MOVU%s %X,%x",
+[0x12] RM,0,           "MOV[H]L%s      %x,%X", /* TO DO: H if source is XMM */
+[0x13] RM,0,           "MOVL%s %X,%e",
+[0x14] RM,0,           "UNPCKL%s       %x,%X",
+[0x15] RM,0,           "UNPCKH%s       %x,%X",
+[0x16] RM,0,           "MOV[L]H%s      %x,%X", /* TO DO: L if source is XMM */
+[0x17] RM,0,           "MOVH%s %X,%x",
+[0x20] RMR,0,          "MOVL   %C,%e",
+[0x21] RMR,0,          "MOVL   %D,%e",
+[0x22] RMR,0,          "MOVL   %e,%C",
+[0x23] RMR,0,          "MOVL   %e,%D",
+[0x24] RMR,0,          "MOVL   %T,%e",
+[0x26] RMR,0,          "MOVL   %e,%T",
+[0x28] RM,0,           "MOVA%s %x,%X",
+[0x29] RM,0,           "MOVA%s %X,%x",
+[0x2A] RM,0,           "CVTPL2%s       %m*,%X",
+[0x2B] RM,0,           "MOVNT%s        %X,%e",
+[0x2C] RM,0,           "CVTT%s2PL      %x,%M",
+[0x2D] RM,0,           "CVT%s2PL       %x,%M",
+[0x2E] RM,0,           "UCOMISS        %x,%X",
+[0x2F] RM,0,           "COMISS %x,%X",
+[0x30] 0,0,            "WRMSR",
+[0x31] 0,0,            "RDTSC",
+[0x32] 0,0,            "RDMSR",
+[0x33] 0,0,            "RDPMC",
+[0x42] RM,0,           "CMOVC  %e,%r",         /* CF */
+[0x43] RM,0,           "CMOVNC %e,%r",         /* ¬ CF */
+[0x44] RM,0,           "CMOVZ  %e,%r",         /* ZF */
+[0x45] RM,0,           "CMOVNZ %e,%r",         /* ¬ ZF */
+[0x46] RM,0,           "CMOVBE %e,%r",         /* CF ∨ ZF */
+[0x47] RM,0,           "CMOVA  %e,%r",         /* ¬CF ∧ ¬ZF */
+[0x48] RM,0,           "CMOVS  %e,%r",         /* SF */
+[0x49] RM,0,           "CMOVNS %e,%r",         /* ¬ SF */
+[0x4A] RM,0,           "CMOVP  %e,%r",         /* PF */
+[0x4B] RM,0,           "CMOVNP %e,%r",         /* ¬ PF */
+[0x4C] RM,0,           "CMOVLT %e,%r",         /* LT ≡ OF ≠ SF */
+[0x4D] RM,0,           "CMOVGE %e,%r",         /* GE ≡ ZF ∨ SF */
+[0x4E] RM,0,           "CMOVLE %e,%r",         /* LE ≡ ZF ∨ LT */
+[0x4F] RM,0,           "CMOVGT %e,%r",         /* GT ≡ ¬ZF ∧ GE */
+[0x50] RM,0,           "MOVMSK%s       %X,%r", /* TO DO: check */
+[0x51] RM,0,           "SQRT%s %x,%X",
+[0x52] RM,0,           "RSQRT%s        %x,%X",
+[0x53] RM,0,           "RCP%s  %x,%X",
+[0x54] RM,0,           "AND%s  %x,%X",
+[0x55] RM,0,           "ANDN%s %x,%X",
+[0x56] RM,0,           "OR%s   %x,%X",         /* TO DO: S/D */
+[0x57] RM,0,           "XOR%s  %x,%X",         /* S/D */
+[0x58] RM,0,           "ADD%s  %x,%X",         /* S/P S/D */
+[0x59] RM,0,           "MUL%s  %x,%X",
+[0x5A] RM,0,           "CVTPS2PD       %x,%X",
+[0x5B] RM,0,           "CVTPL2PS       %x,%X",
+[0x5C] RM,0,           "SUB%s  %x,%X",
+[0x5D] RM,0,           "MIN%s  %x,%X",
+[0x5E] RM,0,           "DIV%s  %x,%X",         /* TO DO: S/P S/D */
+[0x5F] RM,0,           "MAX%s  %x,%X",
+[0x60] RM,0,           "PUNPCKLBW %m,%M",
+[0x61] RM,0,           "PUNPCKLWL %m,%M",
+[0x62] RM,0,           "PUNPCKLLQ %m,%M",
+[0x63] RM,0,           "PACKSSWB %m,%M",
+[0x64] RM,0,           "PCMPGTB %m,%M",
+[0x65] RM,0,           "PCMPGTW %m,%M",
+[0x66] RM,0,           "PCMPGTL %m,%M",
+[0x67] RM,0,           "PACKUSWB %m,%M",
+[0x68] RM,0,           "PUNPCKHBW %m,%M",
+[0x69] RM,0,           "PUNPCKHWL %m,%M",
+[0x6A] RM,0,           "PUNPCKHLQ %m,%M",
+[0x6B] RM,0,           "PACKSSLW %m,%M",
+[0x6E] RM,0,           "MOV%S %e,%M",
+[0x6F] RM,0,           "MOVQ %m,%M",
+[0x70] RM,Ib,          "PSHUFW %i,%m,%M",
+[0x74] RM,0,           "PCMPEQB %m,%M",
+[0x75] RM,0,           "PCMPEQW %m,%M",
+[0x76] RM,0,           "PCMPEQL %m,%M",
+[0x7E] RM,0,           "MOV%S %M,%e",
+[0x7F] RM,0,           "MOVQ %M,%m",
+[0xAE] RMOP,0,         optab0FAE,
+[0xAA] 0,0,            "RSM",
+[0xB0] RM,0,           "CMPXCHGB       %r,%e",
+[0xB1] RM,0,           "CMPXCHG%S      %r,%e",
+[0xC0] RMB,0,          "XADDB  %r,%e",
+[0xC1] RM,0,           "XADD%S %r,%e",
+[0xC2] RM,Ib,          "CMP%s  %i,%x,%X",
+[0xC3] RM,0,           "MOVNTI%S       %r,%e",
+[0xC6] RM,Ib,          "SHUF%s %i,%x,%X",
+[0xC8] 0,0,            "BSWAP  AX",
+[0xC9] 0,0,            "BSWAP  CX",
+[0xCA] 0,0,            "BSWAP  DX",
+[0xCB] 0,0,            "BSWAP  BX",
+[0xCC] 0,0,            "BSWAP  SP",
+[0xCD] 0,0,            "BSWAP  BP",
+[0xCE] 0,0,            "BSWAP  SI",
+[0xCF] 0,0,            "BSWAP  DI",
+[0xD1] RM,0,           "PSRLW %m,%M",
+[0xD2] RM,0,           "PSRLL %m,%M",
+[0xD3] RM,0,           "PSRLQ %m,%M",
+[0xD5] RM,0,           "PMULLW %m,%M",
+[0xD6] RM,0,           "MOVQOZX        %m*,%X",
+[0xD7] RM,0,           "PMOVMSKB %m,%r",
+[0xD8] RM,0,           "PSUBUSB %m,%M",
+[0xD9] RM,0,           "PSUBUSW %m,%M",
+[0xDA] RM,0,           "PMINUB %m,%M",
+[0xDB] RM,0,           "PAND %m,%M",
+[0xDC] RM,0,           "PADDUSB %m,%M",
+[0xDD] RM,0,           "PADDUSW %m,%M",
+[0xDE] RM,0,           "PMAXUB %m,%M",
+[0xDF] RM,0,           "PANDN %m,%M",
+[0xE0] RM,0,           "PAVGB %m,%M",
+[0xE1] RM,0,           "PSRAW %m,%M",
+[0xE2] RM,0,           "PSRAL %m,%M",
+[0xE3] RM,0,           "PAVGW %m,%M",
+[0xE4] RM,0,           "PMULHUW %m,%M",
+[0xE5] RM,0,           "PMULHW %m,%M",
+[0xE7] RM,0,           "MOVNTQ %M,%e",
+[0xE8] RM,0,           "PSUBSB %m,%M",
+[0xE9] RM,0,           "PSUBSW %m,%M",
+[0xEA] RM,0,           "PMINSW %m,%M",
+[0xEB] RM,0,           "POR %m,%M",
+[0xEC] RM,0,           "PADDSB %m,%M",
+[0xED] RM,0,           "PADDSW %m,%M",
+[0xEE] RM,0,           "PMAXSW %m,%M",
+[0xEF] RM,0,           "PXOR %m,%M",
+[0xF1] RM,0,           "PSLLW %m,%M",
+[0xF2] RM,0,           "PSLLL %m,%M",
+[0xF3] RM,0,           "PSLLQ %m,%M",
+[0xF4] RM,0,           "PMULULQ        %m,%M",
+[0xF5] RM,0,           "PMADDWL %m,%M",
+[0xF6] RM,0,           "PSADBW %m,%M",
+[0xF7] RMR,0,          "MASKMOVQ       %m,%M",
+[0xF8] RM,0,           "PSUBB %m,%M",
+[0xF9] RM,0,           "PSUBW %m,%M",
+[0xFA] RM,0,           "PSUBL %m,%M",
+[0xFC] RM,0,           "PADDB %m,%M",
+[0xFD] RM,0,           "PADDW %m,%M",
+[0xFE] RM,0,           "PADDL %m,%M",
+
+[0x80] Iwds,0,         "JOS    %p",
+[0x81] Iwds,0,         "JOC    %p",
+[0x82] Iwds,0,         "JCS    %p",
+[0x83] Iwds,0,         "JCC    %p",
+[0x84] Iwds,0,         "JEQ    %p",
+[0x85] Iwds,0,         "JNE    %p",
+[0x86] Iwds,0,         "JLS    %p",
+[0x87] Iwds,0,         "JHI    %p",
+[0x88] Iwds,0,         "JMI    %p",
+[0x89] Iwds,0,         "JPL    %p",
+[0x8a] Iwds,0,         "JPS    %p",
+[0x8b] Iwds,0,         "JPC    %p",
+[0x8c] Iwds,0,         "JLT    %p",
+[0x8d] Iwds,0,         "JGE    %p",
+[0x8e] Iwds,0,         "JLE    %p",
+[0x8f] Iwds,0,         "JGT    %p",
+[0x90] RMB,0,          "SETOS  %e",
+[0x91] RMB,0,          "SETOC  %e",
+[0x92] RMB,0,          "SETCS  %e",
+[0x93] RMB,0,          "SETCC  %e",
+[0x94] RMB,0,          "SETEQ  %e",
+[0x95] RMB,0,          "SETNE  %e",
+[0x96] RMB,0,          "SETLS  %e",
+[0x97] RMB,0,          "SETHI  %e",
+[0x98] RMB,0,          "SETMI  %e",
+[0x99] RMB,0,          "SETPL  %e",
+[0x9a] RMB,0,          "SETPS  %e",
+[0x9b] RMB,0,          "SETPC  %e",
+[0x9c] RMB,0,          "SETLT  %e",
+[0x9d] RMB,0,          "SETGE  %e",
+[0x9e] RMB,0,          "SETLE  %e",
+[0x9f] RMB,0,          "SETGT  %e",
+[0xa0] 0,0,            "PUSHL  FS",
+[0xa1] 0,0,            "POPL   FS",
+[0xa2] 0,0,            "CPUID",
+[0xa3] RM,0,           "BT%S   %r,%e",
+[0xa4] RM,Ib,          "SHLD%S %r,%i,%e",
+[0xa5] RM,0,           "SHLD%S %r,CL,%e",
+[0xa8] 0,0,            "PUSHL  GS",
+[0xa9] 0,0,            "POPL   GS",
+[0xab] RM,0,           "BTS%S  %r,%e",
+[0xac] RM,Ib,          "SHRD%S %r,%i,%e",
+[0xad] RM,0,           "SHRD%S %r,CL,%e",
+[0xaf] RM,0,           "IMUL%S %e,%r",
+[0xb2] RMM,0,          "LSS    %e,%r",
+[0xb3] RM,0,           "BTR%S  %r,%e",
+[0xb4] RMM,0,          "LFS    %e,%r",
+[0xb5] RMM,0,          "LGS    %e,%r",
+[0xb6] RMB,0,          "MOVBZX %e,%R",
+[0xb7] RM,0,           "MOVWZX %e,%R",
+[0xba] RMOP,0,         optab0FBA,
+[0xbb] RM,0,           "BTC%S  %e,%r",
+[0xbc] RM,0,           "BSF%S  %e,%r",
+[0xbd] RM,0,           "BSR%S  %e,%r",
+[0xbe] RMB,0,          "MOVBSX %e,%R",
+[0xbf] RM,0,           "MOVWSX %e,%R",
+[0xc7] RMOP,0,         optab0FC7,
+};
+
+static Optable optab80[8]=
+{
+[0x00] Ib,0,           "ADDB   %i,%e",
+[0x01] Ib,0,           "ORB    %i,%e",
+[0x02] Ib,0,           "ADCB   %i,%e",
+[0x03] Ib,0,           "SBBB   %i,%e",
+[0x04] Ib,0,           "ANDB   %i,%e",
+[0x05] Ib,0,           "SUBB   %i,%e",
+[0x06] Ib,0,           "XORB   %i,%e",
+[0x07] Ib,0,           "CMPB   %e,%i",
+};
+
+static Optable optab81[8]=
+{
+[0x00] Iwd,0,          "ADD%S  %i,%e",
+[0x01] Iwd,0,          "OR%S   %i,%e",
+[0x02] Iwd,0,          "ADC%S  %i,%e",
+[0x03] Iwd,0,          "SBB%S  %i,%e",
+[0x04] Iwd,0,          "AND%S  %i,%e",
+[0x05] Iwd,0,          "SUB%S  %i,%e",
+[0x06] Iwd,0,          "XOR%S  %i,%e",
+[0x07] Iwd,0,          "CMP%S  %e,%i",
+};
+
+static Optable optab83[8]=
+{
+[0x00] Ibs,0,          "ADD%S  %i,%e",
+[0x01] Ibs,0,          "OR%S   %i,%e",
+[0x02] Ibs,0,          "ADC%S  %i,%e",
+[0x03] Ibs,0,          "SBB%S  %i,%e",
+[0x04] Ibs,0,          "AND%S  %i,%e",
+[0x05] Ibs,0,          "SUB%S  %i,%e",
+[0x06] Ibs,0,          "XOR%S  %i,%e",
+[0x07] Ibs,0,          "CMP%S  %e,%i",
+};
+
+static Optable optabC0[8] =
+{
+[0x00] Ib,0,           "ROLB   %i,%e",
+[0x01] Ib,0,           "RORB   %i,%e",
+[0x02] Ib,0,           "RCLB   %i,%e",
+[0x03] Ib,0,           "RCRB   %i,%e",
+[0x04] Ib,0,           "SHLB   %i,%e",
+[0x05] Ib,0,           "SHRB   %i,%e",
+[0x07] Ib,0,           "SARB   %i,%e",
+};
+
+static Optable optabC1[8] =
+{
+[0x00] Ib,0,           "ROL%S  %i,%e",
+[0x01] Ib,0,           "ROR%S  %i,%e",
+[0x02] Ib,0,           "RCL%S  %i,%e",
+[0x03] Ib,0,           "RCR%S  %i,%e",
+[0x04] Ib,0,           "SHL%S  %i,%e",
+[0x05] Ib,0,           "SHR%S  %i,%e",
+[0x07] Ib,0,           "SAR%S  %i,%e",
+};
+
+static Optable optabD0[8] =
+{
+[0x00] 0,0,            "ROLB   %e",
+[0x01] 0,0,            "RORB   %e",
+[0x02] 0,0,            "RCLB   %e",
+[0x03] 0,0,            "RCRB   %e",
+[0x04] 0,0,            "SHLB   %e",
+[0x05] 0,0,            "SHRB   %e",
+[0x07] 0,0,            "SARB   %e",
+};
+
+static Optable optabD1[8] =
+{
+[0x00] 0,0,            "ROL%S  %e",
+[0x01] 0,0,            "ROR%S  %e",
+[0x02] 0,0,            "RCL%S  %e",
+[0x03] 0,0,            "RCR%S  %e",
+[0x04] 0,0,            "SHL%S  %e",
+[0x05] 0,0,            "SHR%S  %e",
+[0x07] 0,0,            "SAR%S  %e",
+};
+
+static Optable optabD2[8] =
+{
+[0x00] 0,0,            "ROLB   CL,%e",
+[0x01] 0,0,            "RORB   CL,%e",
+[0x02] 0,0,            "RCLB   CL,%e",
+[0x03] 0,0,            "RCRB   CL,%e",
+[0x04] 0,0,            "SHLB   CL,%e",
+[0x05] 0,0,            "SHRB   CL,%e",
+[0x07] 0,0,            "SARB   CL,%e",
+};
+
+static Optable optabD3[8] =
+{
+[0x00] 0,0,            "ROL%S  CL,%e",
+[0x01] 0,0,            "ROR%S  CL,%e",
+[0x02] 0,0,            "RCL%S  CL,%e",
+[0x03] 0,0,            "RCR%S  CL,%e",
+[0x04] 0,0,            "SHL%S  CL,%e",
+[0x05] 0,0,            "SHR%S  CL,%e",
+[0x07] 0,0,            "SAR%S  CL,%e",
+};
+
+static Optable optabD8[8+8] =
+{
+[0x00] 0,0,            "FADDF  %e,F0",
+[0x01] 0,0,            "FMULF  %e,F0",
+[0x02] 0,0,            "FCOMF  %e,F0",
+[0x03] 0,0,            "FCOMFP %e,F0",
+[0x04] 0,0,            "FSUBF  %e,F0",
+[0x05] 0,0,            "FSUBRF %e,F0",
+[0x06] 0,0,            "FDIVF  %e,F0",
+[0x07] 0,0,            "FDIVRF %e,F0",
+[0x08] 0,0,            "FADDD  %f,F0",
+[0x09] 0,0,            "FMULD  %f,F0",
+[0x0a] 0,0,            "FCOMD  %f,F0",
+[0x0b] 0,0,            "FCOMPD %f,F0",
+[0x0c] 0,0,            "FSUBD  %f,F0",
+[0x0d] 0,0,            "FSUBRD %f,F0",
+[0x0e] 0,0,            "FDIVD  %f,F0",
+[0x0f] 0,0,            "FDIVRD %f,F0",
+};
+/*
+ *     optabD9 and optabDB use the following encoding: 
+ *     if (0 <= modrm <= 2) instruction = optabDx[modrm&0x07];
+ *     else instruction = optabDx[(modrm&0x3f)+8];
+ *
+ *     the instructions for MOD == 3, follow the 8 instructions
+ *     for the other MOD values stored at the front of the table.
+ */
+static Optable optabD9[64+8] =
+{
+[0x00] 0,0,            "FMOVF  %e,F0",
+[0x02] 0,0,            "FMOVF  F0,%e",
+[0x03] 0,0,            "FMOVFP F0,%e",
+[0x04] 0,0,            "FLDENV%S %e",
+[0x05] 0,0,            "FLDCW  %e",
+[0x06] 0,0,            "FSTENV%S %e",
+[0x07] 0,0,            "FSTCW  %e",
+[0x08] 0,0,            "FMOVD  F0,F0",         /* Mod R/M = 11xx xxxx*/
+[0x09] 0,0,            "FMOVD  F1,F0",
+[0x0a] 0,0,            "FMOVD  F2,F0",
+[0x0b] 0,0,            "FMOVD  F3,F0",
+[0x0c] 0,0,            "FMOVD  F4,F0",
+[0x0d] 0,0,            "FMOVD  F5,F0",
+[0x0e] 0,0,            "FMOVD  F6,F0",
+[0x0f] 0,0,            "FMOVD  F7,F0",
+[0x10] 0,0,            "FXCHD  F0,F0",
+[0x11] 0,0,            "FXCHD  F1,F0",
+[0x12] 0,0,            "FXCHD  F2,F0",
+[0x13] 0,0,            "FXCHD  F3,F0",
+[0x14] 0,0,            "FXCHD  F4,F0",
+[0x15] 0,0,            "FXCHD  F5,F0",
+[0x16] 0,0,            "FXCHD  F6,F0",
+[0x17] 0,0,            "FXCHD  F7,F0",
+[0x18] 0,0,            "FNOP",
+[0x28] 0,0,            "FCHS",
+[0x29] 0,0,            "FABS",
+[0x2c] 0,0,            "FTST",
+[0x2d] 0,0,            "FXAM",
+[0x30] 0,0,            "FLD1",
+[0x31] 0,0,            "FLDL2T",
+[0x32] 0,0,            "FLDL2E",
+[0x33] 0,0,            "FLDPI",
+[0x34] 0,0,            "FLDLG2",
+[0x35] 0,0,            "FLDLN2",
+[0x36] 0,0,            "FLDZ",
+[0x38] 0,0,            "F2XM1",
+[0x39] 0,0,            "FYL2X",
+[0x3a] 0,0,            "FPTAN",
+[0x3b] 0,0,            "FPATAN",
+[0x3c] 0,0,            "FXTRACT",
+[0x3d] 0,0,            "FPREM1",
+[0x3e] 0,0,            "FDECSTP",
+[0x3f] 0,0,            "FNCSTP",
+[0x40] 0,0,            "FPREM",
+[0x41] 0,0,            "FYL2XP1",
+[0x42] 0,0,            "FSQRT",
+[0x43] 0,0,            "FSINCOS",
+[0x44] 0,0,            "FRNDINT",
+[0x45] 0,0,            "FSCALE",
+[0x46] 0,0,            "FSIN",
+[0x47] 0,0,            "FCOS",
+};
+
+static Optable optabDA[8+8] =
+{
+[0x00] 0,0,            "FADDL  %e,F0",
+[0x01] 0,0,            "FMULL  %e,F0",
+[0x02] 0,0,            "FCOML  %e,F0",
+[0x03] 0,0,            "FCOMLP %e,F0",
+[0x04] 0,0,            "FSUBL  %e,F0",
+[0x05] 0,0,            "FSUBRL %e,F0",
+[0x06] 0,0,            "FDIVL  %e,F0",
+[0x07] 0,0,            "FDIVRL %e,F0",
+[0x0d] R1,0,           "FUCOMPP",
+};
+
+static Optable optabDB[8+64] =
+{
+[0x00] 0,0,            "FMOVL  %e,F0",
+[0x02] 0,0,            "FMOVL  F0,%e",
+[0x03] 0,0,            "FMOVLP F0,%e",
+[0x05] 0,0,            "FMOVX  %e,F0",
+[0x07] 0,0,            "FMOVXP F0,%e",
+[0x2a] 0,0,            "FCLEX",
+[0x2b] 0,0,            "FINIT",
+};
+
+static Optable optabDC[8+8] =
+{
+[0x00] 0,0,            "FADDD  %e,F0",
+[0x01] 0,0,            "FMULD  %e,F0",
+[0x02] 0,0,            "FCOMD  %e,F0",
+[0x03] 0,0,            "FCOMDP %e,F0",
+[0x04] 0,0,            "FSUBD  %e,F0",
+[0x05] 0,0,            "FSUBRD %e,F0",
+[0x06] 0,0,            "FDIVD  %e,F0",
+[0x07] 0,0,            "FDIVRD %e,F0",
+[0x08] 0,0,            "FADDD  F0,%f",
+[0x09] 0,0,            "FMULD  F0,%f",
+[0x0c] 0,0,            "FSUBRD F0,%f",
+[0x0d] 0,0,            "FSUBD  F0,%f",
+[0x0e] 0,0,            "FDIVRD F0,%f",
+[0x0f] 0,0,            "FDIVD  F0,%f",
+};
+
+static Optable optabDD[8+8] =
+{
+[0x00] 0,0,            "FMOVD  %e,F0",
+[0x02] 0,0,            "FMOVD  F0,%e",
+[0x03] 0,0,            "FMOVDP F0,%e",
+[0x04] 0,0,            "FRSTOR%S %e",
+[0x06] 0,0,            "FSAVE%S %e",
+[0x07] 0,0,            "FSTSW  %e",
+[0x08] 0,0,            "FFREED %f",
+[0x0a] 0,0,            "FMOVD  %f,F0",
+[0x0b] 0,0,            "FMOVDP %f,F0",
+[0x0c] 0,0,            "FUCOMD %f,F0",
+[0x0d] 0,0,            "FUCOMDP %f,F0",
+};
+
+static Optable optabDE[8+8] =
+{
+[0x00] 0,0,            "FADDW  %e,F0",
+[0x01] 0,0,            "FMULW  %e,F0",
+[0x02] 0,0,            "FCOMW  %e,F0",
+[0x03] 0,0,            "FCOMWP %e,F0",
+[0x04] 0,0,            "FSUBW  %e,F0",
+[0x05] 0,0,            "FSUBRW %e,F0",
+[0x06] 0,0,            "FDIVW  %e,F0",
+[0x07] 0,0,            "FDIVRW %e,F0",
+[0x08] 0,0,            "FADDDP F0,%f",
+[0x09] 0,0,            "FMULDP F0,%f",
+[0x0b] R1,0,           "FCOMPDP",
+[0x0c] 0,0,            "FSUBRDP F0,%f",
+[0x0d] 0,0,            "FSUBDP F0,%f",
+[0x0e] 0,0,            "FDIVRDP F0,%f",
+[0x0f] 0,0,            "FDIVDP F0,%f",
+};
+
+static Optable optabDF[8+8] =
+{
+[0x00] 0,0,            "FMOVW  %e,F0",
+[0x02] 0,0,            "FMOVW  F0,%e",
+[0x03] 0,0,            "FMOVWP F0,%e",
+[0x04] 0,0,            "FBLD   %e",
+[0x05] 0,0,            "FMOVL  %e,F0",
+[0x06] 0,0,            "FBSTP  %e",
+[0x07] 0,0,            "FMOVLP F0,%e",
+[0x0c] R0,0,           "FSTSW  %OAX",
+};
+
+static Optable optabF6[8] =
+{
+[0x00] Ib,0,           "TESTB  %i,%e",
+[0x02] 0,0,            "NOTB   %e",
+[0x03] 0,0,            "NEGB   %e",
+[0x04] 0,0,            "MULB   AL,%e",
+[0x05] 0,0,            "IMULB  AL,%e",
+[0x06] 0,0,            "DIVB   AL,%e",
+[0x07] 0,0,            "IDIVB  AL,%e",
+};
+
+static Optable optabF7[8] =
+{
+[0x00] Iwd,0,          "TEST%S %i,%e",
+[0x02] 0,0,            "NOT%S  %e",
+[0x03] 0,0,            "NEG%S  %e",
+[0x04] 0,0,            "MUL%S  %OAX,%e",
+[0x05] 0,0,            "IMUL%S %OAX,%e",
+[0x06] 0,0,            "DIV%S  %OAX,%e",
+[0x07] 0,0,            "IDIV%S %OAX,%e",
+};
+
+static Optable optabFE[8] =
+{
+[0x00] 0,0,            "INCB   %e",
+[0x01] 0,0,            "DECB   %e",
+};
+
+static Optable optabFF[8] =
+{
+[0x00] 0,0,            "INC%S  %e",
+[0x01] 0,0,            "DEC%S  %e",
+[0x02] JUMP,0,         "CALL*  %e",
+[0x03] JUMP,0,         "CALLF* %e",
+[0x04] JUMP,0,         "JMP*   %e",
+[0x05] JUMP,0,         "JMPF*  %e",
+[0x06] 0,0,            "PUSHL  %e",
+};
+
+static Optable optable[256+1] =
+{
+[0x00] RMB,0,          "ADDB   %r,%e",
+[0x01] RM,0,           "ADD%S  %r,%e",
+[0x02] RMB,0,          "ADDB   %e,%r",
+[0x03] RM,0,           "ADD%S  %e,%r",
+[0x04] Ib,0,           "ADDB   %i,AL",
+[0x05] Iwd,0,          "ADD%S  %i,%OAX",
+[0x06] 0,0,            "PUSHL  ES",
+[0x07] 0,0,            "POPL   ES",
+[0x08] RMB,0,          "ORB    %r,%e",
+[0x09] RM,0,           "OR%S   %r,%e",
+[0x0a] RMB,0,          "ORB    %e,%r",
+[0x0b] RM,0,           "OR%S   %e,%r",
+[0x0c] Ib,0,           "ORB    %i,AL",
+[0x0d] Iwd,0,          "OR%S   %i,%OAX",
+[0x0e] 0,0,            "PUSHL  CS",
+[0x0f] AUXMM,0,        optab0F,
+[0x10] RMB,0,          "ADCB   %r,%e",
+[0x11] RM,0,           "ADC%S  %r,%e",
+[0x12] RMB,0,          "ADCB   %e,%r",
+[0x13] RM,0,           "ADC%S  %e,%r",
+[0x14] Ib,0,           "ADCB   %i,AL",
+[0x15] Iwd,0,          "ADC%S  %i,%OAX",
+[0x16] 0,0,            "PUSHL  SS",
+[0x17] 0,0,            "POPL   SS",
+[0x18] RMB,0,          "SBBB   %r,%e",
+[0x19] RM,0,           "SBB%S  %r,%e",
+[0x1a] RMB,0,          "SBBB   %e,%r",
+[0x1b] RM,0,           "SBB%S  %e,%r",
+[0x1c] Ib,0,           "SBBB   %i,AL",
+[0x1d] Iwd,0,          "SBB%S  %i,%OAX",
+[0x1e] 0,0,            "PUSHL  DS",
+[0x1f] 0,0,            "POPL   DS",
+[0x20] RMB,0,          "ANDB   %r,%e",
+[0x21] RM,0,           "AND%S  %r,%e",
+[0x22] RMB,0,          "ANDB   %e,%r",
+[0x23] RM,0,           "AND%S  %e,%r",
+[0x24] Ib,0,           "ANDB   %i,AL",
+[0x25] Iwd,0,          "AND%S  %i,%OAX",
+[0x26] SEG,0,          "ES:",
+[0x27] 0,0,            "DAA",
+[0x28] RMB,0,          "SUBB   %r,%e",
+[0x29] RM,0,           "SUB%S  %r,%e",
+[0x2a] RMB,0,          "SUBB   %e,%r",
+[0x2b] RM,0,           "SUB%S  %e,%r",
+[0x2c] Ib,0,           "SUBB   %i,AL",
+[0x2d] Iwd,0,          "SUB%S  %i,%OAX",
+[0x2e] SEG,0,          "CS:",
+[0x2f] 0,0,            "DAS",
+[0x30] RMB,0,          "XORB   %r,%e",
+[0x31] RM,0,           "XOR%S  %r,%e",
+[0x32] RMB,0,          "XORB   %e,%r",
+[0x33] RM,0,           "XOR%S  %e,%r",
+[0x34] Ib,0,           "XORB   %i,AL",
+[0x35] Iwd,0,          "XOR%S  %i,%OAX",
+[0x36] SEG,0,          "SS:",
+[0x37] 0,0,            "AAA",
+[0x38] RMB,0,          "CMPB   %r,%e",
+[0x39] RM,0,           "CMP%S  %r,%e",
+[0x3a] RMB,0,          "CMPB   %e,%r",
+[0x3b] RM,0,           "CMP%S  %e,%r",
+[0x3c] Ib,0,           "CMPB   %i,AL",
+[0x3d] Iwd,0,          "CMP%S  %i,%OAX",
+[0x3e] SEG,0,          "DS:",
+[0x3f] 0,0,            "AAS",
+[0x40] 0,0,            "INC%S  %OAX",
+[0x41] 0,0,            "INC%S  %OCX",
+[0x42] 0,0,            "INC%S  %ODX",
+[0x43] 0,0,            "INC%S  %OBX",
+[0x44] 0,0,            "INC%S  %OSP",
+[0x45] 0,0,            "INC%S  %OBP",
+[0x46] 0,0,            "INC%S  %OSI",
+[0x47] 0,0,            "INC%S  %ODI",
+[0x48] 0,0,            "DEC%S  %OAX",
+[0x49] 0,0,            "DEC%S  %OCX",
+[0x4a] 0,0,            "DEC%S  %ODX",
+[0x4b] 0,0,            "DEC%S  %OBX",
+[0x4c] 0,0,            "DEC%S  %OSP",
+[0x4d] 0,0,            "DEC%S  %OBP",
+[0x4e] 0,0,            "DEC%S  %OSI",
+[0x4f] 0,0,            "DEC%S  %ODI",
+[0x50] 0,0,            "PUSH%S %OAX",
+[0x51] 0,0,            "PUSH%S %OCX",
+[0x52] 0,0,            "PUSH%S %ODX",
+[0x53] 0,0,            "PUSH%S %OBX",
+[0x54] 0,0,            "PUSH%S %OSP",
+[0x55] 0,0,            "PUSH%S %OBP",
+[0x56] 0,0,            "PUSH%S %OSI",
+[0x57] 0,0,            "PUSH%S %ODI",
+[0x58] 0,0,            "POP%S  %OAX",
+[0x59] 0,0,            "POP%S  %OCX",
+[0x5a] 0,0,            "POP%S  %ODX",
+[0x5b] 0,0,            "POP%S  %OBX",
+[0x5c] 0,0,            "POP%S  %OSP",
+[0x5d] 0,0,            "POP%S  %OBP",
+[0x5e] 0,0,            "POP%S  %OSI",
+[0x5f] 0,0,            "POP%S  %ODI",
+[0x60] 0,0,            "PUSHA%S",
+[0x61] 0,0,            "POPA%S",
+[0x62] RMM,0,          "BOUND  %e,%r",
+[0x63] RM,0,           "ARPL   %r,%e",
+[0x64] SEG,0,          "FS:",
+[0x65] SEG,0,          "GS:",
+[0x66] OPOVER,0,       "",
+[0x67] ADDOVER,0,      "",
+[0x68] Iwd,0,          "PUSH%S %i",
+[0x69] RM,Iwd,         "IMUL%S %e,%i,%r",
+[0x6a] Ib,0,           "PUSH%S %i",
+[0x6b] RM,Ibs,         "IMUL%S %e,%i,%r",
+[0x6c] 0,0,            "INSB   DX,(%ODI)",
+[0x6d] 0,0,            "INS%S  DX,(%ODI)",
+[0x6e] 0,0,            "OUTSB  (%ASI),DX",
+[0x6f] 0,0,            "OUTS%S (%ASI),DX",
+[0x70] Jbs,0,          "JOS    %p",
+[0x71] Jbs,0,          "JOC    %p",
+[0x72] Jbs,0,          "JCS    %p",
+[0x73] Jbs,0,          "JCC    %p",
+[0x74] Jbs,0,          "JEQ    %p",
+[0x75] Jbs,0,          "JNE    %p",
+[0x76] Jbs,0,          "JLS    %p",
+[0x77] Jbs,0,          "JHI    %p",
+[0x78] Jbs,0,          "JMI    %p",
+[0x79] Jbs,0,          "JPL    %p",
+[0x7a] Jbs,0,          "JPS    %p",
+[0x7b] Jbs,0,          "JPC    %p",
+[0x7c] Jbs,0,          "JLT    %p",
+[0x7d] Jbs,0,          "JGE    %p",
+[0x7e] Jbs,0,          "JLE    %p",
+[0x7f] Jbs,0,          "JGT    %p",
+[0x80] RMOPB,0,        optab80,
+[0x81] RMOP,0,         optab81,
+[0x83] RMOP,0,         optab83,
+[0x84] RMB,0,          "TESTB  %r,%e",
+[0x85] RM,0,           "TEST%S %r,%e",
+[0x86] RMB,0,          "XCHGB  %r,%e",
+[0x87] RM,0,           "XCHG%S %r,%e",
+[0x88] RMB,0,          "MOVB   %r,%e",
+[0x89] RM,0,           "MOV%S  %r,%e",
+[0x8a] RMB,0,          "MOVB   %e,%r",
+[0x8b] RM,0,           "MOV%S  %e,%r",
+[0x8c] RM,0,           "MOVW   %g,%e",
+[0x8d] RM,0,           "LEA%S  %e,%r",
+[0x8e] RM,0,           "MOVW   %e,%g",
+[0x8f] RM,0,           "POP%S  %e",
+[0x90] 0,0,            "NOP",
+[0x91] 0,0,            "XCHG   %OCX,%OAX",
+[0x92] 0,0,            "XCHG   %ODX,%OAX",
+[0x93] 0,0,            "XCHG   %OBX,%OAX",
+[0x94] 0,0,            "XCHG   %OSP,%OAX",
+[0x95] 0,0,            "XCHG   %OBP,%OAX",
+[0x96] 0,0,            "XCHG   %OSI,%OAX",
+[0x97] 0,0,            "XCHG   %ODI,%OAX",
+[0x98] 0,0,            "%W",                   /* miserable CBW or CWDE */
+[0x99] 0,0,            "%w",                   /* idiotic CWD or CDQ */
+[0x9a] PTR,0,          "CALL%S %d",
+[0x9b] 0,0,            "WAIT",
+[0x9c] 0,0,            "PUSHF",
+[0x9d] 0,0,            "POPF",
+[0x9e] 0,0,            "SAHF",
+[0x9f] 0,0,            "LAHF",
+[0xa0] Awd,0,          "MOVB   %i,AL",
+[0xa1] Awd,0,          "MOV%S  %i,%OAX",
+[0xa2] Awd,0,          "MOVB   AL,%i",
+[0xa3] Awd,0,          "MOV%S  %OAX,%i",
+[0xa4] 0,0,            "MOVSB  (%ASI),(%ADI)",
+[0xa5] 0,0,            "MOVS%S (%ASI),(%ADI)",
+[0xa6] 0,0,            "CMPSB  (%ASI),(%ADI)",
+[0xa7] 0,0,            "CMPS%S (%ASI),(%ADI)",
+[0xa8] Ib,0,           "TESTB  %i,AL",
+[0xa9] Iwd,0,          "TEST%S %i,%OAX",
+[0xaa] 0,0,            "STOSB  AL,(%ADI)",
+[0xab] 0,0,            "STOS%S %OAX,(%ADI)",
+[0xac] 0,0,            "LODSB  (%ASI),AL",
+[0xad] 0,0,            "LODS%S (%ASI),%OAX",
+[0xae] 0,0,            "SCASB  (%ADI),AL",
+[0xaf] 0,0,            "SCAS%S (%ADI),%OAX",
+[0xb0] Ib,0,           "MOVB   %i,AL",
+[0xb1] Ib,0,           "MOVB   %i,CL",
+[0xb2] Ib,0,           "MOVB   %i,DL",
+[0xb3] Ib,0,           "MOVB   %i,BL",
+[0xb4] Ib,0,           "MOVB   %i,AH",
+[0xb5] Ib,0,           "MOVB   %i,CH",
+[0xb6] Ib,0,           "MOVB   %i,DH",
+[0xb7] Ib,0,           "MOVB   %i,BH",
+[0xb8] Iwdq,0,         "MOV%S  %i,%OAX",
+[0xb9] Iwdq,0,         "MOV%S  %i,%OCX",
+[0xba] Iwdq,0,         "MOV%S  %i,%ODX",
+[0xbb] Iwdq,0,         "MOV%S  %i,%OBX",
+[0xbc] Iwdq,0,         "MOV%S  %i,%OSP",
+[0xbd] Iwdq,0,         "MOV%S  %i,%OBP",
+[0xbe] Iwdq,0,         "MOV%S  %i,%OSI",
+[0xbf] Iwdq,0,         "MOV%S  %i,%ODI",
+[0xc0] RMOPB,0,        optabC0,
+[0xc1] RMOP,0,         optabC1,
+[0xc2] Iw,0,           "RET    %i",
+[0xc3] RET,0,          "RET",
+[0xc4] RM,0,           "LES    %e,%r",
+[0xc5] RM,0,           "LDS    %e,%r",
+[0xc6] RMB,Ib,         "MOVB   %i,%e",
+[0xc7] RM,Iwd,         "MOV%S  %i,%e",
+[0xc8] Iw2,Ib,         "ENTER  %i,%I",         /* loony ENTER */
+[0xc9] RET,0,          "LEAVE",                /* bizarre LEAVE */
+[0xca] Iw,0,           "RETF   %i",
+[0xcb] RET,0,          "RETF",
+[0xcc] 0,0,            "INT    3",
+[0xcd] Ib,0,           "INTB   %i",
+[0xce] 0,0,            "INTO",
+[0xcf] 0,0,            "IRET",
+[0xd0] RMOPB,0,        optabD0,
+[0xd1] RMOP,0,         optabD1,
+[0xd2] RMOPB,0,        optabD2,
+[0xd3] RMOP,0,         optabD3,
+[0xd4] OA,0,           "AAM",
+[0xd5] OA,0,           "AAD",
+[0xd7] 0,0,            "XLAT",
+[0xd8] FRMOP,0,        optabD8,
+[0xd9] FRMEX,0,        optabD9,
+[0xda] FRMOP,0,        optabDA,
+[0xdb] FRMEX,0,        optabDB,
+[0xdc] FRMOP,0,        optabDC,
+[0xdd] FRMOP,0,        optabDD,
+[0xde] FRMOP,0,        optabDE,
+[0xdf] FRMOP,0,        optabDF,
+[0xe0] Jbs,0,          "LOOPNE %p",
+[0xe1] Jbs,0,          "LOOPE  %p",
+[0xe2] Jbs,0,          "LOOP   %p",
+[0xe3] Jbs,0,          "JCXZ   %p",
+[0xe4] Ib,0,           "INB    %i,AL",
+[0xe5] Ib,0,           "IN%S   %i,%OAX",
+[0xe6] Ib,0,           "OUTB   AL,%i",
+[0xe7] Ib,0,           "OUT%S  %OAX,%i",
+[0xe8] Iwds,0,         "CALL   %p",
+[0xe9] Iwds,0,         "JMP    %p",
+[0xea] PTR,0,          "JMP    %d",
+[0xeb] Jbs,0,          "JMP    %p",
+[0xec] 0,0,            "INB    DX,AL",
+[0xed] 0,0,            "IN%S   DX,%OAX",
+[0xee] 0,0,            "OUTB   AL,DX",
+[0xef] 0,0,            "OUT%S  %OAX,DX",
+[0xf0] PRE,0,          "LOCK",
+[0xf2] OPRE,0,         "REPNE",
+[0xf3] OPRE,0,         "REP",
+[0xf4] 0,0,            "HLT",
+[0xf5] 0,0,            "CMC",
+[0xf6] RMOPB,0,        optabF6,
+[0xf7] RMOP,0,         optabF7,
+[0xf8] 0,0,            "CLC",
+[0xf9] 0,0,            "STC",
+[0xfa] 0,0,            "CLI",
+[0xfb] 0,0,            "STI",
+[0xfc] 0,0,            "CLD",
+[0xfd] 0,0,            "STD",
+[0xfe] RMOPB,0,        optabFE,
+[0xff] RMOP,0,         optabFF,
+[0x100]        RM,0,           "MOVLQSX        %r,%e",
+};
+
+/*
+ *  get a byte of the instruction
+ */
+static int
+igetc(Map *map, Instr *ip, uchar *c)
+{
+       if(ip->n+1 > sizeof(ip->mem)){
+               werrstr("instruction too long");
+               return -1;
+       }
+       if (get1(map, ip->addr+ip->n, c, 1) < 0) {
+               werrstr("can't read instruction: %r");
+               return -1;
+       }
+       ip->mem[ip->n++] = *c;
+       return 1;
+}
+
+/*
+ *  get two bytes of the instruction
+ */
+static int
+igets(Map *map, Instr *ip, ushort *sp)
+{
+       uchar c;
+       ushort s;
+
+       if (igetc(map, ip, &c) < 0)
+               return -1;
+       s = c;
+       if (igetc(map, ip, &c) < 0)
+               return -1;
+       s |= (c<<8);
+       *sp = s;
+       return 1;
+}
+
+/*
+ *  get 4 bytes of the instruction
+ */
+static int
+igetl(Map *map, Instr *ip, ulong *lp)
+{
+       ushort s;
+       long    l;
+
+       if (igets(map, ip, &s) < 0)
+               return -1;
+       l = s;
+       if (igets(map, ip, &s) < 0)
+               return -1;
+       l |= (s<<16);
+       *lp = l;
+       return 1;
+}
+
+/*
+ *  get 8 bytes of the instruction
+ */
+static int
+igetq(Map *map, Instr *ip, vlong *qp)
+{
+       ulong   l;
+       uvlong q;
+
+       if (igetl(map, ip, &l) < 0)
+               return -1;
+       q = l;
+       if (igetl(map, ip, &l) < 0)
+               return -1;
+       q |= ((uvlong)l<<32);
+       *qp = q;
+       return 1;
+}
+
+static int
+getdisp(Map *map, Instr *ip, int mod, int rm, int code, int pcrel)
+{
+       uchar c;
+       ushort s;
+
+       if (mod > 2)
+               return 1;
+       if (mod == 1) {
+               if (igetc(map, ip, &c) < 0)
+                       return -1;
+               if (c&0x80)
+                       ip->disp = c|0xffffff00;
+               else
+                       ip->disp = c&0xff;
+       } else if (mod == 2 || rm == code) {
+               if (ip->asize == 'E') {
+                       if (igetl(map, ip, &ip->disp) < 0)
+                               return -1;
+                       if (mod == 0)
+                               ip->rip = pcrel;
+               } else {
+                       if (igets(map, ip, &s) < 0)
+                               return -1;
+                       if (s&0x8000)
+                               ip->disp = s|0xffff0000;
+                       else
+                               ip->disp = s;
+               }
+               if (mod == 0)
+                       ip->base = -1;
+       }
+       return 1;
+}
+
+static int
+modrm(Map *map, Instr *ip, uchar c)
+{
+       uchar rm, mod;
+
+       mod = (c>>6)&3;
+       rm = c&7;
+       ip->mod = mod;
+       ip->base = rm;
+       ip->reg = (c>>3)&7;
+       ip->rip = 0;
+       if (mod == 3)                   /* register */
+               return 1;
+       if (ip->asize == 0) {           /* 16-bit mode */
+               switch(rm) {
+               case 0:
+                       ip->base = BX; ip->index = SI;
+                       break;
+               case 1:
+                       ip->base = BX; ip->index = DI;
+                       break;
+               case 2:
+                       ip->base = BP; ip->index = SI;
+                       break;
+               case 3:
+                       ip->base = BP; ip->index = DI;
+                       break;
+               case 4:
+                       ip->base = SI;
+                       break;
+               case 5:
+                       ip->base = DI;
+                       break;
+               case 6:
+                       ip->base = BP;
+                       break;
+               case 7:
+                       ip->base = BX;
+                       break;
+               default:
+                       break;
+               }
+               return getdisp(map, ip, mod, rm, 6, 0);
+       }
+       if (rm == 4) {  /* scummy sib byte */
+               if (igetc(map, ip, &c) < 0)
+                       return -1;
+               ip->ss = (c>>6)&0x03;
+               ip->index = (c>>3)&0x07;
+               if (ip->index == 4)
+                       ip->index = -1;
+               ip->base = c&0x07;
+               return getdisp(map, ip, mod, ip->base, 5, 0);
+       }
+       return getdisp(map, ip, mod, rm, 5, ip->amd64);
+}
+
+static Optable *
+mkinstr(Map *map, Instr *ip, uvlong pc)
+{
+       int i, n, norex;
+       uchar c;
+       ushort s;
+       Optable *op, *obase;
+       char buf[128];
+
+       memset(ip, 0, sizeof(*ip));
+       norex = 1;
+       ip->base = -1;
+       ip->index = -1;
+       if(asstype == AI8086)
+               ip->osize = 'W';
+       else {
+               ip->osize = 'L';
+               ip->asize = 'E';
+               ip->amd64 = asstype != AI386;
+               norex = 0;
+       }
+       ip->addr = pc;
+       if (igetc(map, ip, &c) < 0)
+               return 0;
+       obase = optable;
+newop:
+       if(ip->amd64 && !norex){
+               if(c >= 0x40 && c <= 0x4f) {
+                       ip->rex = c;
+                       if(igetc(map, ip, &c) < 0)
+                               return 0;
+               }
+               if(c == 0x63){
+                       op = &obase[0x100];     /* MOVLQSX */
+                       goto hack;
+               }
+       }
+       op = &obase[c];
+hack:
+       if (op->proto == 0) {
+badop:
+               n = snprint(buf, sizeof(buf), "opcode: ??");
+               for (i = 0; i < ip->n && n < sizeof(buf)-3; i++, n+=2)
+                       _hexify(buf+n, ip->mem[i], 1);
+               strcpy(buf+n, "??");
+               werrstr(buf);
+               return 0;
+       }
+       for(i = 0; i < 2 && op->operand[i]; i++) {
+               switch(op->operand[i]) {
+               case Ib:        /* 8-bit immediate - (no sign extension)*/
+                       if (igetc(map, ip, &c) < 0)
+                               return 0;
+                       ip->imm = c&0xff;
+                       ip->imm64 = ip->imm;
+                       break;
+               case Jbs:       /* 8-bit jump immediate (sign extended) */
+                       if (igetc(map, ip, &c) < 0)
+                               return 0;
+                       if (c&0x80)
+                               ip->imm = c|0xffffff00;
+                       else
+                               ip->imm = c&0xff;
+                       ip->imm64 = (long)ip->imm;
+                       ip->jumptype = Jbs;
+                       break;
+               case Ibs:       /* 8-bit immediate (sign extended) */
+                       if (igetc(map, ip, &c) < 0)
+                               return 0;
+                       if (c&0x80)
+                               if (ip->osize == 'L')
+                                       ip->imm = c|0xffffff00;
+                               else
+                                       ip->imm = c|0xff00;
+                       else
+                               ip->imm = c&0xff;
+                       ip->imm64 = (long)ip->imm;
+                       break;
+               case Iw:        /* 16-bit immediate -> imm */
+                       if (igets(map, ip, &s) < 0)
+                               return 0;
+                       ip->imm = s&0xffff;
+                       ip->imm64 = ip->imm;
+                       ip->jumptype = Iw;
+                       break;
+               case Iw2:       /* 16-bit immediate -> in imm2*/
+                       if (igets(map, ip, &s) < 0)
+                               return 0;
+                       ip->imm2 = s&0xffff;
+                       break;
+               case Iwd:       /* Operand-sized immediate (no sign extension unless 64 bits)*/
+                       if (ip->osize == 'L') {
+                               if (igetl(map, ip, &ip->imm) < 0)
+                                       return 0;
+                               ip->imm64 = ip->imm;
+                               if(ip->rex&REXW && (ip->imm & (1<<31)) != 0)
+                                       ip->imm64 |= (vlong)~0 << 32;
+                       } else {
+                               if (igets(map, ip, &s)< 0)
+                                       return 0;
+                               ip->imm = s&0xffff;
+                               ip->imm64 = ip->imm;
+                       }
+                       break;
+               case Iwdq:      /* Operand-sized immediate, possibly big */
+                       if (ip->osize == 'L') {
+                               if (igetl(map, ip, &ip->imm) < 0)
+                                       return 0;
+                               ip->imm64 = ip->imm;
+                               if (ip->rex & REXW) {
+                                       ulong l;
+                                       if (igetl(map, ip, &l) < 0)
+                                               return 0;
+                                       ip->imm64 |= (uvlong)l << 32;
+                               }
+                       } else {
+                               if (igets(map, ip, &s)< 0)
+                                       return 0;
+                               ip->imm = s&0xffff;
+                       }
+                       break;
+               case Awd:       /* Address-sized immediate (no sign extension)*/
+                       if (ip->asize == 'E') {
+                               if (igetl(map, ip, &ip->imm) < 0)
+                                       return 0;
+                               /* TO DO: REX */
+                       } else {
+                               if (igets(map, ip, &s)< 0)
+                                       return 0;
+                               ip->imm = s&0xffff;
+                       }
+                       break;
+               case Iwds:      /* Operand-sized immediate (sign extended) */
+                       if (ip->osize == 'L') {
+                               if (igetl(map, ip, &ip->imm) < 0)
+                                       return 0;
+                       } else {
+                               if (igets(map, ip, &s)< 0)
+                                       return 0;
+                               if (s&0x8000)
+                                       ip->imm = s|0xffff0000;
+                               else
+                                       ip->imm = s&0xffff;
+                       }
+                       ip->jumptype = Iwds;
+                       break;
+               case OA:        /* literal 0x0a byte */
+                       if (igetc(map, ip, &c) < 0)
+                               return 0;
+                       if (c != 0x0a)
+                               goto badop;
+                       break;
+               case R0:        /* base register must be R0 */
+                       if (ip->base != 0)
+                               goto badop;
+                       break;
+               case R1:        /* base register must be R1 */
+                       if (ip->base != 1)
+                               goto badop;
+                       break;
+               case RMB:       /* R/M field with byte register (/r)*/
+                       if (igetc(map, ip, &c) < 0)
+                               return 0;
+                       if (modrm(map, ip, c) < 0)
+                               return 0;
+                       ip->osize = 'B';
+                       break;
+               case RM:        /* R/M field with register (/r) */
+                       if (igetc(map, ip, &c) < 0)
+                               return 0;
+                       if (modrm(map, ip, c) < 0)
+                               return 0;
+                       break;
+               case RMOPB:     /* R/M field with op code (/digit) */
+                       if (igetc(map, ip, &c) < 0)
+                               return 0;
+                       if (modrm(map, ip, c) < 0)
+                               return 0;
+                       c = ip->reg;            /* secondary op code */
+                       obase = (Optable*)op->proto;
+                       ip->osize = 'B';
+                       goto newop;
+               case RMOP:      /* R/M field with op code (/digit) */
+                       if (igetc(map, ip, &c) < 0)
+                               return 0;
+                       if (modrm(map, ip, c) < 0)
+                               return 0;
+                       obase = (Optable*)op->proto;
+                       if(ip->amd64 && obase == optab0F01 && c == 0xF8)
+                               return optab0F01F8;
+                       c = ip->reg;
+                       goto newop;
+               case FRMOP:     /* FP R/M field with op code (/digit) */
+                       if (igetc(map, ip, &c) < 0)
+                               return 0;
+                       if (modrm(map, ip, c) < 0)
+                               return 0;
+                       if ((c&0xc0) == 0xc0)
+                               c = ip->reg+8;          /* 16 entry table */
+                       else
+                               c = ip->reg;
+                       obase = (Optable*)op->proto;
+                       goto newop;
+               case FRMEX:     /* Extended FP R/M field with op code (/digit) */
+                       if (igetc(map, ip, &c) < 0)
+                               return 0;
+                       if (modrm(map, ip, c) < 0)
+                               return 0;
+                       if ((c&0xc0) == 0xc0)
+                               c = (c&0x3f)+8;         /* 64-entry table */
+                       else
+                               c = ip->reg;
+                       obase = (Optable*)op->proto;
+                       goto newop;
+               case RMR:       /* R/M register only (mod = 11) */
+                       if (igetc(map, ip, &c) < 0)
+                               return 0;
+                       if ((c&0xc0) != 0xc0) {
+                               werrstr("invalid R/M register: %x", c);
+                               return 0;
+                       }
+                       if (modrm(map, ip, c) < 0)
+                               return 0;
+                       break;
+               case RMM:       /* R/M register only (mod = 11) */
+                       if (igetc(map, ip, &c) < 0)
+                               return 0;
+                       if ((c&0xc0) == 0xc0) {
+                               werrstr("invalid R/M memory mode: %x", c);
+                               return 0;
+                       }
+                       if (modrm(map, ip, c) < 0)
+                               return 0;
+                       break;
+               case PTR:       /* Seg:Displacement addr (ptr16:16 or ptr16:32) */
+                       if (ip->osize == 'L') {
+                               if (igetl(map, ip, &ip->disp) < 0)
+                                       return 0;
+                       } else {
+                               if (igets(map, ip, &s)< 0)
+                                       return 0;
+                               ip->disp = s&0xffff;
+                       }
+                       if (igets(map, ip, (ushort*)&ip->seg) < 0)
+                               return 0;
+                       ip->jumptype = PTR;
+                       break;
+               case AUXMM:     /* Multi-byte op code; prefix determines table selection */
+                       if (igetc(map, ip, &c) < 0)
+                               return 0;
+                       obase = (Optable*)op->proto;
+                       switch (ip->opre) {
+                       case 0x66:      op = optab660F; break;
+                       case 0xF2:      op = optabF20F; break;
+                       case 0xF3:      op = optabF30F; break;
+                       default:        op = nil; break;
+                       }
+                       if(op != nil && op[c].proto != nil)
+                               obase = op;
+                       norex = 1;      /* no more rex prefixes */
+                       /* otherwise the optab entry captures it */
+                       goto newop;
+               case AUX:       /* Multi-byte op code - Auxiliary table */
+                       obase = (Optable*)op->proto;
+                       if (igetc(map, ip, &c) < 0)
+                               return 0;
+                       goto newop;
+               case OPRE:      /* Instr Prefix or media op */
+                       ip->opre = c;
+                       /* fall through */
+               case PRE:       /* Instr Prefix */
+                       ip->prefix = (char*)op->proto;
+                       if (igetc(map, ip, &c) < 0)
+                               return 0;
+                       if (ip->opre && c == 0x0F)
+                               ip->prefix = 0;
+                       goto newop;
+               case SEG:       /* Segment Prefix */
+                       ip->segment = (char*)op->proto;
+                       if (igetc(map, ip, &c) < 0)
+                               return 0;
+                       goto newop;
+               case OPOVER:    /* Operand size override */
+                       ip->opre = c;
+                       ip->osize = 'W';
+                       if (igetc(map, ip, &c) < 0)
+                               return 0;
+                       if (c == 0x0F)
+                               ip->osize = 'L';
+                       else if (ip->amd64 && (c&0xF0) == 0x40)
+                               ip->osize = 'Q';
+                       goto newop;
+               case ADDOVER:   /* Address size override */
+                       ip->asize = 0;
+                       if (igetc(map, ip, &c) < 0)
+                               return 0;
+                       goto newop;
+               case JUMP:      /* mark instruction as JUMP or RET */
+               case RET:
+                       ip->jumptype = op->operand[i];
+                       break;
+               default:
+                       werrstr("bad operand type %d", op->operand[i]);
+                       return 0;
+               }
+       }
+       return op;
+}
+
+#pragma        varargck        argpos  bprint          2
+
+static void
+bprint(Instr *ip, char *fmt, ...)
+{
+       va_list arg;
+
+       va_start(arg, fmt);
+       ip->curr = vseprint(ip->curr, ip->end, fmt, arg);
+       va_end(arg);
+}
+
+/*
+ *  if we want to call 16 bit regs AX,BX,CX,...
+ *  and 32 bit regs EAX,EBX,ECX,... then
+ *  change the defs of ANAME and ONAME to:
+ *  #define    ANAME(ip)       ((ip->asize == 'E' ? "E" : "")
+ *  #define    ONAME(ip)       ((ip)->osize == 'L' ? "E" : "")
+ */
+#define        ANAME(ip)       ""
+#define        ONAME(ip)       ""
+
+static char *reg[] =  {
+[AX]   "AX",
+[CX]   "CX",
+[DX]   "DX",
+[BX]   "BX",
+[SP]   "SP",
+[BP]   "BP",
+[SI]   "SI",
+[DI]   "DI",
+
+       /* amd64 */
+[R8]   "R8",
+[R9]   "R9",
+[R10]  "R10",
+[R11]  "R11",
+[R12]  "R12",
+[R13]  "R13",
+[R14]  "R14",
+[R15]  "R15",
+};
+
+static char *breg[] = { "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH" };
+static char *breg64[] = { "AL", "CL", "DL", "BL", "SPB", "BPB", "SIB", "DIB",
+       "R8B", "R9B", "R10B", "R11B", "R12B", "R13B", "R14B", "R15B" };
+static char *sreg[] = { "ES", "CS", "SS", "DS", "FS", "GS" };
+
+static void
+plocal(Instr *ip)
+{
+       int ret;
+       long offset;
+       Symbol s;
+       char *reg;
+
+       offset = ip->disp;
+       if (!findsym(ip->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s)) {
+               bprint(ip, "%lux(SP)", offset);
+               return;
+       }
+
+       if (s.value > ip->disp) {
+               ret = getauto(&s, s.value-ip->disp-mach->szaddr, CAUTO, &s);
+               reg = "(SP)";
+       } else {
+               offset -= s.value;
+               ret = getauto(&s, offset, CPARAM, &s);
+               reg = "(FP)";
+       }
+       if (ret)
+               bprint(ip, "%s+", s.name);
+       else
+               offset = ip->disp;
+       bprint(ip, "%lux%s", offset, reg);
+}
+
+static int
+isjmp(Instr *ip)
+{
+       switch(ip->jumptype){
+       case Iwds:
+       case Jbs:
+       case JUMP:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+/*
+ * This is too smart for its own good, but it really is nice
+ * to have accurate translations when debugging, and it
+ * helps us identify which code is different in binaries that
+ * are changed on sources.
+ */
+static int
+issymref(Instr *ip, Symbol *s, long w, long val)
+{
+       Symbol next, tmp;
+       long isstring, size;
+
+       if (isjmp(ip))
+               return 1;
+       if (s->class==CTEXT && w==0)
+               return 1;
+       if (s->class==CDATA) {
+               /* use first bss symbol (or "end") rather than edata */
+               if (s->name[0]=='e' && strcmp(s->name, "edata") == 0){
+                       if((s ->index >= 0 && globalsym(&tmp, s->index+1) && tmp.value==s->value)
+                       || (s->index > 0 && globalsym(&tmp, s->index-1) && tmp.value==s->value))
+                               *s = tmp;
+               }
+               if (w == 0)
+                       return 1;
+               for (next=*s; next.value==s->value; next=tmp)
+                       if (!globalsym(&tmp, next.index+1))
+                               break;
+               size = next.value - s->value;
+               if (w >= size)
+                       return 0;
+               if (w > size-w)
+                       w = size-w;
+               /* huge distances are usually wrong except in .string */
+               isstring = (s->name[0]=='.' && strcmp(s->name, ".string") == 0);
+               if (w > 8192 && !isstring)
+                       return 0;
+               /* medium distances are tricky - look for constants */
+               /* near powers of two */
+               if ((val&(val-1)) == 0 || (val&(val+1)) == 0)
+                       return 0;
+               return 1;
+       }
+       return 0;
+}
+
+static void
+immediate(Instr *ip, vlong val)
+{
+       Symbol s;
+       long w;
+
+       if (findsym(val, CANY, &s)) {           /* TO DO */
+               w = val - s.value;
+               if (w < 0)
+                       w = -w;
+               if (issymref(ip, &s, w, val)) {
+                       if (w)
+                               bprint(ip, "%s+%lux(SB)", s.name, w);
+                       else
+                               bprint(ip, "%s(SB)", s.name);
+                       return;
+               }
+/*
+               if (s.class==CDATA && globalsym(&s, s.index+1)) {
+                       w = s.value - val;
+                       if (w < 0)
+                               w = -w;
+                       if (w < 4096) {
+                               bprint(ip, "%s-%lux(SB)", s.name, w);
+                               return;
+                       }
+               }
+*/
+       }
+       if((ip->rex & REXW) == 0)
+               bprint(ip, "%lux", (long)val);
+       else
+               bprint(ip, "%llux", val);
+}
+
+static void
+pea(Instr *ip)
+{
+       if (ip->mod == 3) {
+               if (ip->osize == 'B')
+                       bprint(ip, (ip->rex & REXB? breg64: breg)[ip->base]);
+               else if(ip->rex & REXB)
+                       bprint(ip, "%s%s", ANAME(ip), reg[ip->base+8]);
+               else
+                       bprint(ip, "%s%s", ANAME(ip), reg[ip->base]);
+               return;
+       }
+       if (ip->segment)
+               bprint(ip, ip->segment);
+       if (ip->asize == 'E' && ip->base == SP)
+               plocal(ip);
+       else {
+               if (ip->base < 0)
+                       immediate(ip, ip->disp);
+               else {
+                       bprint(ip, "%lux", ip->disp);
+                       if(ip->rip)
+                               bprint(ip, "(RIP)");
+                       bprint(ip,"(%s%s)", ANAME(ip), reg[ip->rex&REXB? ip->base+8: ip->base]);
+               }
+       }
+       if (ip->index >= 0)
+               bprint(ip,"(%s%s*%d)", ANAME(ip), reg[ip->rex&REXX? ip->index+8: ip->index], 1<<ip->ss);
+}
+
+static void
+prinstr(Instr *ip, char *fmt)
+{
+       vlong v;
+
+       if (ip->prefix)
+               bprint(ip, "%s ", ip->prefix);
+       for (; *fmt && ip->curr < ip->end; fmt++) {
+               if (*fmt != '%'){
+                       *ip->curr++ = *fmt;
+                       continue;
+               }
+               switch(*++fmt){
+               case '%':
+                       *ip->curr++ = '%';
+                       break;
+               case 'A':
+                       bprint(ip, "%s", ANAME(ip));
+                       break;
+               case 'C':
+                       bprint(ip, "CR%d", ip->reg);
+                       break;
+               case 'D':
+                       if (ip->reg < 4 || ip->reg == 6 || ip->reg == 7)
+                               bprint(ip, "DR%d",ip->reg);
+                       else
+                               bprint(ip, "???");
+                       break;
+               case 'I':
+                       bprint(ip, "$");
+                       immediate(ip, ip->imm2);
+                       break;
+               case 'O':
+                       bprint(ip,"%s", ONAME(ip));
+                       break;
+               case 'i':
+                       bprint(ip, "$");
+                       v = ip->imm;
+                       if(ip->rex & REXW)
+                               v = ip->imm64;
+                       immediate(ip, v);
+                       break;
+               case 'R':
+                       bprint(ip, "%s%s", ONAME(ip), reg[ip->rex&REXR? ip->reg+8: ip->reg]);
+                       break;
+               case 'S':
+                       if(ip->osize == 'Q' || ip->osize == 'L' && ip->rex & REXW)
+                               bprint(ip, "Q");
+                       else
+                               bprint(ip, "%c", ip->osize);
+                       break;
+               case 's':
+                       if(ip->opre == 0 || ip->opre == 0x66)
+                               bprint(ip, "P");
+                       else
+                               bprint(ip, "S");
+                       if(ip->opre == 0xf2 || ip->opre == 0x66)
+                               bprint(ip, "D");
+                       else
+                               bprint(ip, "S");
+                       break;
+               case 'T':
+                       if (ip->reg == 6 || ip->reg == 7)
+                               bprint(ip, "TR%d",ip->reg);
+                       else
+                               bprint(ip, "???");
+                       break;
+               case 'W':
+                       if (ip->osize == 'Q' || ip->osize == 'L' && ip->rex & REXW)
+                               bprint(ip, "CDQE");
+                       else if (ip->osize == 'L')
+                               bprint(ip,"CWDE");
+                       else
+                               bprint(ip, "CBW");
+                       break;
+               case 'd':
+                       bprint(ip,"%ux:%lux",ip->seg,ip->disp);
+                       break;
+               case 'm':
+                       if (ip->mod == 3 && ip->osize != 'B') {
+                               if(fmt[1] != '*'){
+                                       if(ip->opre != 0) {
+                                               bprint(ip, "X%d", ip->rex&REXB? ip->base+8: ip->base);
+                                               break;
+                                       }
+                               } else
+                                       fmt++;
+                               bprint(ip, "M%d", ip->base);
+                               break;
+                       }
+                       pea(ip);
+                       break;
+               case 'e':
+                       pea(ip);
+                       break;
+               case 'f':
+                       bprint(ip, "F%d", ip->base);
+                       break;
+               case 'g':
+                       if (ip->reg < 6)
+                               bprint(ip,"%s",sreg[ip->reg]);
+                       else
+                               bprint(ip,"???");
+                       break;
+               case 'p':
+                       /*
+                        * signed immediate in the ulong ip->imm.
+                        */
+                       v = (long)ip->imm;
+                       immediate(ip, v+ip->addr+ip->n);
+                       break;
+               case 'r':
+                       if (ip->osize == 'B')
+                               bprint(ip,"%s", (ip->rex? breg64: breg)[ip->rex&REXR? ip->reg+8: ip->reg]);
+                       else
+                               bprint(ip, reg[ip->rex&REXR? ip->reg+8: ip->reg]);
+                       break;
+               case 'w':
+                       if (ip->osize == 'Q' || ip->rex & REXW)
+                               bprint(ip, "CQO");
+                       else if (ip->osize == 'L')
+                               bprint(ip,"CDQ");
+                       else
+                               bprint(ip, "CWD");
+                       break;
+               case 'M':
+                       if(ip->opre != 0)
+                               bprint(ip, "X%d", ip->rex&REXR? ip->reg+8: ip->reg);
+                       else
+                               bprint(ip, "M%d", ip->reg);
+                       break;
+               case 'x':
+                       if (ip->mod == 3 && ip->osize != 'B') {
+                               bprint(ip, "X%d", ip->rex&REXB? ip->base+8: ip->base);
+                               break;
+                       }
+                       pea(ip);
+                       break;
+               case 'X':
+                       bprint(ip, "X%d", ip->rex&REXR? ip->reg+8: ip->reg);
+                       break;
+               default:
+                       bprint(ip, "%%%c", *fmt);
+                       break;
+               }
+       }
+       *ip->curr = 0;          /* there's always room for 1 byte */
+}
+
+static int
+i386inst(Map *map, uvlong pc, char modifier, char *buf, int n)
+{
+       Instr instr;
+       Optable *op;
+
+       USED(modifier);
+       op = mkinstr(map, &instr, pc);
+       if (op == 0) {
+               errstr(buf, n);
+               return -1;
+       }
+       instr.curr = buf;
+       instr.end = buf+n-1;
+       prinstr(&instr, op->proto);
+       return instr.n;
+}
+
+static int
+i386das(Map *map, uvlong pc, char *buf, int n)
+{
+       Instr instr;
+       int i;
+
+       if (mkinstr(map, &instr, pc) == 0) {
+               errstr(buf, n);
+               return -1;
+       }
+       for(i = 0; i < instr.n && n > 2; i++) {
+               _hexify(buf, instr.mem[i], 1);
+               buf += 2;
+               n -= 2;
+       }
+       *buf = 0;
+       return instr.n;
+}
+
+static int
+i386instlen(Map *map, uvlong pc)
+{
+       Instr i;
+
+       if (mkinstr(map, &i, pc))
+               return i.n;
+       return -1;
+}
+
+static int
+i386foll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
+{
+       Instr i;
+       Optable *op;
+       ushort s;
+       uvlong l, addr;
+       vlong v;
+       int n;
+
+       op = mkinstr(map, &i, pc);
+       if (!op)
+               return -1;
+
+       n = 0;
+
+       switch(i.jumptype) {
+       case RET:               /* RETURN or LEAVE */
+       case Iw:                /* RETURN */
+               if (strcmp(op->proto, "LEAVE") == 0) {
+                       if (geta(map, (*rget)(map, "BP"), &l) < 0)
+                               return -1;
+               } else if (geta(map, (*rget)(map, mach->sp), &l) < 0)
+                       return -1;
+               foll[0] = l;
+               return 1;
+       case Iwds:              /* pc relative JUMP or CALL*/
+       case Jbs:               /* pc relative JUMP or CALL */
+               v = (long)i.imm;
+               foll[0] = pc+v+i.n;
+               n = 1;
+               break;
+       case PTR:               /* seg:displacement JUMP or CALL */
+               foll[0] = (i.seg<<4)+i.disp;
+               return 1;
+       case JUMP:              /* JUMP or CALL EA */
+
+               if(i.mod == 3) {
+                       foll[0] = (*rget)(map, reg[i.rex&REXB? i.base+8: i.base]);
+                       return 1;
+               }
+                       /* calculate the effective address */
+               addr = i.disp;
+               if (i.base >= 0) {
+                       if (geta(map, (*rget)(map, reg[i.rex&REXB? i.base+8: i.base]), &l) < 0)
+                               return -1;
+                       addr += l;
+               }
+               if (i.index >= 0) {
+                       if (geta(map, (*rget)(map, reg[i.rex&REXX? i.index+8: i.index]), &l) < 0)
+                               return -1;
+                       addr += l*(1<<i.ss);
+               }
+                       /* now retrieve a seg:disp value at that address */
+               if (get2(map, addr, &s) < 0)                    /* seg */
+                       return -1;
+               foll[0] = s<<4;
+               addr += 2;
+               if (i.asize == 'L') {
+                       if (geta(map, addr, &l) < 0)            /* disp32 */
+                               return -1;
+                       foll[0] += l;
+               } else {                                        /* disp16 */
+                       if (get2(map, addr, &s) < 0)
+                               return -1;
+                       foll[0] += s;
+               }
+               return 1;
+       default:
+               break;
+       }               
+       if (strncmp(op->proto,"JMP", 3) == 0 || strncmp(op->proto,"CALL", 4) == 0)
+               return 1;
+       foll[n++] = pc+i.n;
+       return n;
+}
diff --git a/src/libmachamd64/Makefile b/src/libmachamd64/Makefile
new file mode 100644 (file)
index 0000000..00cd72c
--- /dev/null
@@ -0,0 +1,84 @@
+# Derived from Inferno libmach/mkfile
+# http://code.google.com/p/inferno-os/source/browse/utils/libmach/mkfile
+#
+#      Copyright © 1994-1999 Lucent Technologies Inc.
+#      Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+#      Portions Copyright © 1997-1999 Vita Nuova Limited.
+#      Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+#      Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+#      Portions Copyright © 2009 The Go Authors.  All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+CFLAGS=-I$(GOROOT)/include
+O=o
+
+LIB=libmach_amd64.a
+OFILES=\
+       executable.$O\
+       map.$O\
+       obj.$O\
+       swap.$O\
+       sym.$O\
+       access.$O\
+       machdata.$O\
+       setmach.$O\
+       6.$O\
+       8.$O\
+       8db.$O\
+       6obj.$O\
+#      v.$O\
+#      k.$O\
+#      u.$O\
+#      q.$O\
+#      0.$O\
+#      2.$O\
+#      5.$O\
+#      7.$O\
+#      9.$O\
+#      vdb.$O\
+#      kdb.$O\
+#      udb.$O\
+#      qdb.$O\
+#      2db.$O\
+#      5db.$O\
+#      7db.$O\
+#      vobj.$O\
+#      kobj.$O\
+#      uobj.$O\
+#      2obj.$O\
+#      5obj.$O\
+#      7obj.$O\
+#      8obj.$O\
+#      9obj.$O\
+#      qobj.$O\
+#      vcodas.$O\
+
+HFILES=$(GOROOT)/include/mach_amd64.h elf.h obj.h
+
+install: $(LIB)
+       cp $(LIB) $(GOROOT)/lib
+
+$(LIB): $(OFILES)
+       ar rsc $(LIB) $(OFILES)
+
+$(OFILES): $(HFILES)
+
+clean:
+       rm -f $(OFILES) $(LIB)
diff --git a/src/libmachamd64/access.c b/src/libmachamd64/access.c
new file mode 100644 (file)
index 0000000..fe75f71
--- /dev/null
@@ -0,0 +1,300 @@
+// Inferno libmach/access.c
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/access.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.
+//     Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+//     Portions Copyright © 1997-1999 Vita Nuova Limited.
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+//     Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+/*
+ * functions to read and write an executable or file image
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach_amd64.h>
+
+static int     mget(Map*, uvlong, void*, int);
+static int     mput(Map*, uvlong, void*, int);
+static struct  segment*        reloc(Map*, uvlong, vlong*);
+
+/*
+ * routines to get/put various types
+ */
+int
+geta(Map *map, uvlong addr, uvlong *x)
+{
+       ulong l;
+       uvlong vl;
+
+       if (mach->szaddr == 8){
+               if (get8(map, addr, &vl) < 0)
+                       return -1;
+               *x = vl;
+               return 1;
+       }
+
+       if (get4(map, addr, &l) < 0)
+               return -1;
+       *x = l;
+
+       return 1;
+}
+
+int
+get8(Map *map, uvlong addr, uvlong *x)
+{
+       if (!map) {
+               werrstr("get8: invalid map");
+               return -1;
+       }
+
+       if (map->nsegs == 1 && map->seg[0].fd < 0) {
+               *x = addr;
+               return 1;
+       }
+       if (mget(map, addr, x, 8) < 0)
+               return -1;
+       *x = machdata->swav(*x);
+       return 1;
+}
+
+int
+get4(Map *map, uvlong addr, ulong *x)
+{
+       if (!map) {
+               werrstr("get4: invalid map");
+               return -1;
+       }
+
+       if (map->nsegs == 1 && map->seg[0].fd < 0) {
+               *x = addr;
+               return 1;
+       }
+       if (mget(map, addr, x, 4) < 0)
+               return -1;
+       *x = machdata->swal(*x);
+       return 1;
+}
+
+int
+get2(Map *map, uvlong addr, ushort *x)
+{
+       if (!map) {
+               werrstr("get2: invalid map");
+               return -1;
+       }
+
+       if (map->nsegs == 1 && map->seg[0].fd < 0) {
+               *x = addr;
+               return 1;
+       }
+       if (mget(map, addr, x, 2) < 0)
+               return -1;
+       *x = machdata->swab(*x);
+       return 1;
+}
+
+int
+get1(Map *map, uvlong addr, uchar *x, int size)
+{
+       uchar *cp;
+
+       if (!map) {
+               werrstr("get1: invalid map");
+               return -1;
+       }
+
+       if (map->nsegs == 1 && map->seg[0].fd < 0) {
+               cp = (uchar*)&addr;
+               while (cp < (uchar*)(&addr+1) && size-- > 0)
+                       *x++ = *cp++;
+               while (size-- > 0)
+                       *x++ = 0;
+       } else
+               return mget(map, addr, x, size);
+       return 1;
+}
+
+int
+puta(Map *map, uvlong addr, uvlong v)
+{
+       if (mach->szaddr == 8)
+               return put8(map, addr, v);
+
+       return put4(map, addr, v);
+}
+
+int
+put8(Map *map, uvlong addr, uvlong v)
+{
+       if (!map) {
+               werrstr("put8: invalid map");
+               return -1;
+       }
+       v = machdata->swav(v);
+       return mput(map, addr, &v, 8);
+}
+
+int
+put4(Map *map, uvlong addr, ulong v)
+{
+       if (!map) {
+               werrstr("put4: invalid map");
+               return -1;
+       }
+       v = machdata->swal(v);
+       return mput(map, addr, &v, 4);
+}
+
+int
+put2(Map *map, uvlong addr, ushort v)
+{
+       if (!map) {
+               werrstr("put2: invalid map");
+               return -1;
+       }
+       v = machdata->swab(v);
+       return mput(map, addr, &v, 2);
+}
+
+int
+put1(Map *map, uvlong addr, uchar *v, int size)
+{
+       if (!map) {
+               werrstr("put1: invalid map");
+               return -1;
+       }
+       return mput(map, addr, v, size);
+}
+
+static int
+spread(struct segment *s, void *buf, int n, uvlong off)
+{
+       uvlong base;
+
+       static struct {
+               struct segment *s;
+               char a[8192];
+               uvlong off;
+       } cache;
+
+       if(s->cache){
+               base = off&~(sizeof cache.a-1);
+               if(cache.s != s || cache.off != base){
+                       cache.off = ~0;
+                       if(seek(s->fd, base, 0) >= 0
+                       && readn(s->fd, cache.a, sizeof cache.a) == sizeof cache.a){
+                               cache.s = s;
+                               cache.off = base;
+                       }
+               }
+               if(cache.s == s && cache.off == base){
+                       off &= sizeof cache.a-1;
+                       if(off+n > sizeof cache.a)
+                               n = sizeof cache.a - off;
+                       memmove(buf, cache.a+off, n);
+                       return n;
+               }
+       }
+
+       return pread(s->fd, buf, n, off);
+}
+
+static int
+mget(Map *map, uvlong addr, void *buf, int size)
+{
+       uvlong off;
+       int i, j, k;
+       struct segment *s;
+
+       s = reloc(map, addr, (vlong*)&off);
+       if (!s)
+               return -1;
+       if (s->fd < 0) {
+               werrstr("unreadable map");
+               return -1;
+       }
+       for (i = j = 0; i < 2; i++) {   /* in case read crosses page */
+               k = spread(s, buf, size-j, off+j);
+               if (k < 0) {
+                       werrstr("can't read address %llux: %r", addr);
+                       return -1;
+               }
+               j += k;
+               if (j == size)
+                       return j;
+       }
+       werrstr("partial read at address %llux (size %d j %d)", addr, size, j);
+       return -1;
+}
+
+static int
+mput(Map *map, uvlong addr, void *buf, int size)
+{
+       vlong off;
+       int i, j, k;
+       struct segment *s;
+
+       s = reloc(map, addr, &off);
+       if (!s)
+               return -1;
+       if (s->fd < 0) {
+               werrstr("unwritable map");
+               return -1;
+       }
+
+       seek(s->fd, off, 0);
+       for (i = j = 0; i < 2; i++) {   /* in case read crosses page */
+               k = write(s->fd, buf, size-j);
+               if (k < 0) {
+                       werrstr("can't write address %llux: %r", addr);
+                       return -1;
+               }
+               j += k;
+               if (j == size)
+                       return j;
+       }
+       werrstr("partial write at address %llux", addr);
+       return -1;
+}
+
+/*
+ *     convert address to file offset; returns nonzero if ok
+ */
+static struct segment*
+reloc(Map *map, uvlong addr, vlong *offp)
+{
+       int i;
+
+       for (i = 0; i < map->nsegs; i++) {
+               if (map->seg[i].inuse)
+               if (map->seg[i].b <= addr && addr < map->seg[i].e) {
+                       *offp = addr + map->seg[i].f - map->seg[i].b;
+                       return &map->seg[i];
+               }
+       }
+       werrstr("can't translate address %llux", addr);
+       return 0;
+}
diff --git a/src/libmachamd64/elf.h b/src/libmachamd64/elf.h
new file mode 100644 (file)
index 0000000..1079b72
--- /dev/null
@@ -0,0 +1,182 @@
+// Inferno libmach/elf.h
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/elf.h
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.
+//     Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+//     Portions Copyright © 1997-1999 Vita Nuova Limited.
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+//     Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+/*
+ *     Definitions needed for  accessing ELF headers.
+ *     32-bit and 64-bit structs differ.
+ */
+typedef struct {
+       uchar   ident[16];      /* ident bytes */
+       ushort  type;           /* file type */
+       ushort  machine;        /* target machine */
+       int     version;        /* file version */
+       ulong   elfentry;       /* start address */
+       ulong   phoff;          /* phdr file offset */
+       ulong   shoff;          /* shdr file offset */
+       int     flags;          /* file flags */
+       ushort  ehsize;         /* sizeof ehdr */
+       ushort  phentsize;      /* sizeof phdr */
+       ushort  phnum;          /* number phdrs */
+       ushort  shentsize;      /* sizeof shdr */
+       ushort  shnum;          /* number shdrs */
+       ushort  shstrndx;       /* shdr string index */
+} Ehdr32;
+
+typedef struct {
+       uchar   ident[16];      /* ident bytes */
+       ushort  type;           /* file type */
+       ushort  machine;        /* target machine */
+       int     version;        /* file version */
+       uvlong  elfentry;       /* start address */
+       uvlong  phoff;          /* phdr file offset */
+       uvlong  shoff;          /* shdr file offset */
+       int     flags;          /* file flags */
+       ushort  ehsize;         /* sizeof ehdr */
+       ushort  phentsize;      /* sizeof phdr */
+       ushort  phnum;          /* number phdrs */
+       ushort  shentsize;      /* sizeof shdr */
+       ushort  shnum;          /* number shdrs */
+       ushort  shstrndx;       /* shdr string index */
+} Ehdr64;
+
+typedef struct {
+       int     type;           /* entry type */
+       ulong   offset;         /* file offset */
+       ulong   vaddr;          /* virtual address */
+       ulong   paddr;          /* physical address */
+       int     filesz;         /* file size */
+       ulong   memsz;          /* memory size */
+       int     flags;          /* entry flags */
+       int     align;          /* memory/file alignment */
+} Phdr32;
+
+typedef struct {
+       int     type;           /* entry type */
+       int     flags;          /* entry flags */
+       uvlong  offset;         /* file offset */
+       uvlong  vaddr;          /* virtual address */
+       uvlong  paddr;          /* physical address */
+       uvlong  filesz;         /* file size */
+       uvlong  memsz;          /* memory size */
+       uvlong  align;          /* memory/file alignment */
+} Phdr64;
+
+typedef struct {
+       ulong   name;           /* section name */
+       ulong   type;           /* SHT_... */
+       ulong   flags;          /* SHF_... */
+       ulong   addr;           /* virtual address */
+       ulong   offset;         /* file offset */
+       ulong   size;           /* section size */
+       ulong   link;           /* misc info */
+       ulong   info;           /* misc info */
+       ulong   addralign;      /* memory alignment */
+       ulong   entsize;        /* entry size if table */
+} Shdr32;
+
+typedef struct {
+       ulong   name;           /* section name */
+       ulong   type;           /* SHT_... */
+       uvlong  flags;          /* SHF_... */
+       uvlong  addr;           /* virtual address */
+       uvlong  offset;         /* file offset */
+       uvlong  size;           /* section size */
+       ulong   link;           /* misc info */
+       ulong   info;           /* misc info */
+       uvlong  addralign;      /* memory alignment */
+       uvlong  entsize;        /* entry size if table */
+} Shdr64;
+
+enum {
+       /* Ehdr codes */
+       MAG0 = 0,               /* ident[] indexes */
+       MAG1 = 1,
+       MAG2 = 2,
+       MAG3 = 3,
+       CLASS = 4,
+       DATA = 5,
+       VERSION = 6,
+
+       ELFCLASSNONE = 0,       /* ident[CLASS] */
+       ELFCLASS32 = 1,
+       ELFCLASS64 = 2,
+       ELFCLASSNUM = 3,
+
+       ELFDATANONE = 0,        /* ident[DATA] */
+       ELFDATA2LSB = 1,
+       ELFDATA2MSB = 2,
+       ELFDATANUM = 3,
+
+       NOETYPE = 0,            /* type */
+       REL = 1,
+       EXEC = 2,
+       DYN = 3,
+       CORE = 4,
+
+       NONE = 0,               /* machine */
+       M32 = 1,                /* AT&T WE 32100 */
+       SPARC = 2,              /* Sun SPARC */
+       I386 = 3,               /* Intel 80386 */
+       M68K = 4,               /* Motorola 68000 */
+       M88K = 5,               /* Motorola 88000 */
+       I486 = 6,               /* Intel 80486 */
+       I860 = 7,               /* Intel i860 */
+       MIPS = 8,               /* Mips R2000 */
+       S370 = 9,               /* Amdhal       */
+       SPARC64 = 18,           /* Sun SPARC v9 */
+       POWER = 20,             /* PowerPC */
+       ARM = 40,                       /* ARM */
+       AMD64 = 62,             /* Amd64 */
+
+       NO_VERSION = 0,         /* version, ident[VERSION] */
+       CURRENT = 1,
+
+       /* Phdr Codes */
+       NOPTYPE = 0,            /* type */
+       LOAD = 1,
+       DYNAMIC = 2,
+       INTERP = 3,
+       NOTE = 4,
+       SHLIB = 5,
+       PHDR = 6,
+
+       R = 0x4,                /* flags */
+       W = 0x2,
+       X = 0x1,
+
+       /* Shdr Codes */
+       Progbits = 1,   /* section types */
+       Strtab = 3,
+       Nobits = 8,
+
+       Swrite = 1,     /* section attributes */
+       Salloc = 2,
+       Sexec = 4,
+};
+
+#define        ELF_MAG         ((0x7f<<24) | ('E'<<16) | ('L'<<8) | 'F')
diff --git a/src/libmachamd64/executable.c b/src/libmachamd64/executable.c
new file mode 100644 (file)
index 0000000..23505f5
--- /dev/null
@@ -0,0 +1,963 @@
+// Inferno libmach/executable.c
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/executable.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.
+//     Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+//     Portions Copyright © 1997-1999 Vita Nuova Limited.
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+//     Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include       <u.h>
+#include       <libc.h>
+#include       <bio.h>
+#include       <bootexec.h>
+#include       <mach_amd64.h>
+#include       "elf.h"
+
+/*
+ *     All a.out header types.  The dummy entry allows canonical
+ *     processing of the union as a sequence of longs
+ */
+
+typedef struct {
+       union{
+               /*struct { */
+                       Exec exechdr;           /* a.out.h */
+               /*      uvlong hdr[1];*/
+               /*};*/
+               Ehdr32 elfhdr32;                        /* elf.h */
+               Ehdr64 elfhdr64;                        /* elf.h */
+               struct mipsexec mips;   /* bootexec.h */
+               struct mips4kexec mipsk4;       /* bootexec.h */
+               struct sparcexec sparc; /* bootexec.h */
+               struct nextexec next;   /* bootexec.h */
+       } e;
+       long dummy;                     /* padding to ensure extra long */
+} ExecHdr;
+
+static int     nextboot(int, Fhdr*, ExecHdr*);
+static int     sparcboot(int, Fhdr*, ExecHdr*);
+static int     mipsboot(int, Fhdr*, ExecHdr*);
+static int     mips4kboot(int, Fhdr*, ExecHdr*);
+static int     common(int, Fhdr*, ExecHdr*);
+static int     commonllp64(int, Fhdr*, ExecHdr*);
+static int     adotout(int, Fhdr*, ExecHdr*);
+static int     elfdotout(int, Fhdr*, ExecHdr*);
+static int     armdotout(int, Fhdr*, ExecHdr*);
+static void    setsym(Fhdr*, long, long, long, vlong);
+static void    setdata(Fhdr*, uvlong, long, vlong, long);
+static void    settext(Fhdr*, uvlong, uvlong, long, vlong);
+static void    hswal(void*, int, ulong(*)(ulong));
+static uvlong  _round(uvlong, ulong);
+
+/*
+ *     definition of per-executable file type structures
+ */
+
+typedef struct Exectable{
+       long    magic;                  /* big-endian magic number of file */
+       char    *name;                  /* executable identifier */
+       char    *dlmname;               /* dynamically loadable module identifier */
+       uchar   type;                   /* Internal code */
+       uchar   _magic;                 /* _MAGIC() magic */
+       Mach    *mach;                  /* Per-machine data */
+       long    hsize;                  /* header size */
+       ulong   (*swal)(ulong);         /* beswal or leswal */
+       int     (*hparse)(int, Fhdr*, ExecHdr*);
+} ExecTable;
+
+extern Mach    mmips;
+extern Mach    mmips2le;
+extern Mach    mmips2be;
+extern Mach    msparc;
+extern Mach    msparc64;
+extern Mach    m68020;
+extern Mach    mi386;
+extern Mach    mamd64;
+extern Mach    marm;
+extern Mach    mpower;
+extern Mach    mpower64;
+extern Mach    malpha;
+
+/* BUG: FIX THESE WHEN NEEDED */
+Mach   mmips;
+Mach   mmips2le;
+Mach   mmips2be;
+Mach   msparc;
+Mach   msparc64;
+Mach   m68020;
+Mach   marm;
+Mach   mpower;
+Mach   mpower64;
+Mach   malpha;
+
+ExecTable exectab[] =
+{
+       { V_MAGIC,                      /* Mips v.out */
+               "mips plan 9 executable BE",
+               "mips plan 9 dlm BE",
+               FMIPS,
+               1,
+               &mmips,
+               sizeof(Exec),
+               beswal,
+               adotout },
+       { P_MAGIC,                      /* Mips 0.out (r3k le) */
+               "mips plan 9 executable LE",
+               "mips plan 9 dlm LE",
+               FMIPSLE,
+               1,
+               &mmips,
+               sizeof(Exec),
+               beswal,
+               adotout },
+       { M_MAGIC,                      /* Mips 4.out */
+               "mips 4k plan 9 executable BE",
+               "mips 4k plan 9 dlm BE",
+               FMIPS2BE,
+               1,
+               &mmips2be,
+               sizeof(Exec),
+               beswal,
+               adotout },
+       { N_MAGIC,                      /* Mips 0.out */
+               "mips 4k plan 9 executable LE",
+               "mips 4k plan 9 dlm LE",
+               FMIPS2LE,
+               1,
+               &mmips2le,
+               sizeof(Exec),
+               beswal,
+               adotout },
+       { 0x160<<16,                    /* Mips boot image */
+               "mips plan 9 boot image",
+               nil,
+               FMIPSB,
+               0,
+               &mmips,
+               sizeof(struct mipsexec),
+               beswal,
+               mipsboot },
+       { (0x160<<16)|3,                /* Mips boot image */
+               "mips 4k plan 9 boot image",
+               nil,
+               FMIPSB,
+               0,
+               &mmips2be,
+               sizeof(struct mips4kexec),
+               beswal,
+               mips4kboot },
+       { K_MAGIC,                      /* Sparc k.out */
+               "sparc plan 9 executable",
+               "sparc plan 9 dlm",
+               FSPARC,
+               1,
+               &msparc,
+               sizeof(Exec),
+               beswal,
+               adotout },
+       { 0x01030107,                   /* Sparc boot image */
+               "sparc plan 9 boot image",
+               nil,
+               FSPARCB,
+               0,
+               &msparc,
+               sizeof(struct sparcexec),
+               beswal,
+               sparcboot },
+       { U_MAGIC,                      /* Sparc64 u.out */
+               "sparc64 plan 9 executable",
+               "sparc64 plan 9 dlm",
+               FSPARC64,
+               1,
+               &msparc64,
+               sizeof(Exec),
+               beswal,
+               adotout },
+       { A_MAGIC,                      /* 68020 2.out & boot image */
+               "68020 plan 9 executable",
+               "68020 plan 9 dlm",
+               F68020,
+               1,
+               &m68020,
+               sizeof(Exec),
+               beswal,
+               common },
+       { 0xFEEDFACE,                   /* Next boot image */
+               "next plan 9 boot image",
+               nil,
+               FNEXTB,
+               0,
+               &m68020,
+               sizeof(struct nextexec),
+               beswal,
+               nextboot },
+       { I_MAGIC,                      /* I386 8.out & boot image */
+               "386 plan 9 executable",
+               "386 plan 9 dlm",
+               FI386,
+               1,
+               &mi386,
+               sizeof(Exec),
+               beswal,
+               common },
+       { S_MAGIC,                      /* amd64 6.out & boot image */
+               "amd64 plan 9 executable",
+               "amd64 plan 9 dlm",
+               FAMD64,
+               1,
+               &mamd64,
+               sizeof(Exec)+8,
+               nil,
+               commonllp64 },
+       { Q_MAGIC,                      /* PowerPC q.out & boot image */
+               "power plan 9 executable",
+               "power plan 9 dlm",
+               FPOWER,
+               1,
+               &mpower,
+               sizeof(Exec),
+               beswal,
+               common },
+       { T_MAGIC,                      /* power64 9.out & boot image */
+               "power64 plan 9 executable",
+               "power64 plan 9 dlm",
+               FPOWER64,
+               1,
+               &mpower64,
+               sizeof(Exec)+8,
+               nil,
+               commonllp64 },
+       { ELF_MAG,                      /* any elf32 or elf64 */
+               "elf executable",
+               nil,
+               FNONE,
+               0,
+               &mi386,
+               sizeof(Ehdr64),
+               nil,
+               elfdotout },
+       { E_MAGIC,                      /* Arm 5.out and boot image */
+               "arm plan 9 executable",
+               "arm plan 9 dlm",
+               FARM,
+               1,
+               &marm,
+               sizeof(Exec),
+               beswal,
+               common },
+       { (143<<16)|0413,               /* (Free|Net)BSD Arm */
+               "arm *bsd executable",
+               nil,
+               FARM,
+               0,
+               &marm,
+               sizeof(Exec),
+               leswal,
+               armdotout },
+       { L_MAGIC,                      /* alpha 7.out */
+               "alpha plan 9 executable",
+               "alpha plan 9 dlm",
+               FALPHA,
+               1,
+               &malpha,
+               sizeof(Exec),
+               beswal,
+               common },
+       { 0x0700e0c3,                   /* alpha boot image */
+               "alpha plan 9 boot image",
+               nil,
+               FALPHA,
+               0,
+               &malpha,
+               sizeof(Exec),
+               beswal,
+               common },
+       { 0 },
+};
+
+Mach   *mach = &mi386;                 /* Global current machine table */
+
+static ExecTable*
+couldbe4k(ExecTable *mp)
+{
+       Dir *d;
+       ExecTable *f;
+
+       if((d=dirstat("/proc/1/regs")) == nil)
+               return mp;
+       if(d->length < 32*8){           /* R3000 */
+               free(d);
+               return mp;
+       }
+       free(d);
+       for (f = exectab; f->magic; f++)
+               if(f->magic == M_MAGIC) {
+                       f->name = "mips plan 9 executable on mips2 kernel";
+                       return f;
+               }
+       return mp;
+}
+
+int
+crackhdr(int fd, Fhdr *fp)
+{
+       ExecTable *mp;
+       ExecHdr d;
+       int nb, ret;
+       ulong magic;
+
+       fp->type = FNONE;
+       nb = read(fd, (char *)&d.e, sizeof(d.e));
+       if (nb <= 0)
+               return 0;
+
+       ret = 0;
+       magic = beswal(d.e.exechdr.magic);              /* big-endian */
+       for (mp = exectab; mp->magic; mp++) {
+               if (nb < mp->hsize)
+                       continue;
+
+               /*
+                * The magic number has morphed into something
+                * with fields (the straw was DYN_MAGIC) so now
+                * a flag is needed in Fhdr to distinguish _MAGIC()
+                * magic numbers from foreign magic numbers.
+                *
+                * This code is creaking a bit and if it has to
+                * be modified/extended much more it's probably
+                * time to step back and redo it all.
+                */
+               if(mp->_magic){
+                       if(mp->magic != (magic & ~DYN_MAGIC))
+                               continue;
+
+                       if(mp->magic == V_MAGIC)
+                               mp = couldbe4k(mp);
+
+                       if ((magic & DYN_MAGIC) && mp->dlmname != nil)
+                               fp->name = mp->dlmname;
+                       else
+                               fp->name = mp->name;
+               }
+               else{
+                       if(mp->magic != magic)
+                               continue;
+                       fp->name = mp->name;
+               }
+               fp->type = mp->type;
+               fp->hdrsz = mp->hsize;          /* will be zero on bootables */
+               fp->_magic = mp->_magic;
+               fp->magic = magic;
+
+               mach = mp->mach;
+               if(mp->swal != nil)
+                       hswal(&d, sizeof(d.e)/sizeof(ulong), mp->swal);
+               ret = mp->hparse(fd, fp, &d);
+               seek(fd, mp->hsize, 0);         /* seek to end of header */
+               break;
+       }
+       if(mp->magic == 0)
+               werrstr("unknown header type");
+       return ret;
+}
+
+/*
+ * Convert header to canonical form
+ */
+static void
+hswal(void *v, int n, ulong (*swap)(ulong))
+{
+       ulong *ulp;
+
+       for(ulp = v; n--; ulp++)
+               *ulp = (*swap)(*ulp);
+}
+
+/*
+ *     Crack a normal a.out-type header
+ */
+static int
+adotout(int fd, Fhdr *fp, ExecHdr *hp)
+{
+       long pgsize;
+
+       USED(fd);
+       pgsize = mach->pgsize;
+       settext(fp, hp->e.exechdr.entry, pgsize+sizeof(Exec),
+                       hp->e.exechdr.text, sizeof(Exec));
+       setdata(fp, _round(pgsize+fp->txtsz+sizeof(Exec), pgsize),
+               hp->e.exechdr.data, fp->txtsz+sizeof(Exec), hp->e.exechdr.bss);
+       setsym(fp, hp->e.exechdr.syms, hp->e.exechdr.spsz, hp->e.exechdr.pcsz, fp->datoff+fp->datsz);
+       return 1;
+}
+
+static void
+commonboot(Fhdr *fp)
+{
+       if (!(fp->entry & mach->ktmask))
+               return;
+
+       switch(fp->type) {                              /* boot image */
+       case F68020:
+               fp->type = F68020B;
+               fp->name = "68020 plan 9 boot image";
+               break;
+       case FI386:
+               fp->type = FI386B;
+               fp->txtaddr = (u32int)fp->entry;
+               fp->name = "386 plan 9 boot image";
+               fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
+               break;
+       case FARM:
+               fp->type = FARMB;
+               fp->txtaddr = (u32int)fp->entry;
+               fp->name = "ARM plan 9 boot image";
+               fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
+               return;
+       case FALPHA:
+               fp->type = FALPHAB;
+               fp->txtaddr = (u32int)fp->entry;
+               fp->name = "alpha plan 9 boot image";
+               fp->dataddr = fp->txtaddr+fp->txtsz;
+               break;
+       case FPOWER:
+               fp->type = FPOWERB;
+               fp->txtaddr = (u32int)fp->entry;
+               fp->name = "power plan 9 boot image";
+               fp->dataddr = fp->txtaddr+fp->txtsz;
+               break;
+       case FAMD64:
+               fp->type = FAMD64B;
+               fp->txtaddr = fp->entry;
+               fp->name = "amd64 plan 9 boot image";
+               fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
+               break;
+       default:
+               return;
+       }
+       fp->hdrsz = 0;                  /* header stripped */
+}
+
+/*
+ *     _MAGIC() style headers and
+ *     alpha plan9-style bootable images for axp "headerless" boot
+ *
+ */
+static int
+common(int fd, Fhdr *fp, ExecHdr *hp)
+{
+       adotout(fd, fp, hp);
+       if(hp->e.exechdr.magic & DYN_MAGIC) {
+               fp->txtaddr = 0;
+               fp->dataddr = fp->txtsz;
+               return 1;
+       }
+       commonboot(fp);
+       return 1;
+}
+
+static int
+commonllp64(int unused, Fhdr *fp, ExecHdr *hp)
+{
+       long pgsize;
+       uvlong entry;
+
+       hswal(&hp->e, sizeof(Exec)/sizeof(long), beswal);
+       if(!(hp->e.exechdr.magic & HDR_MAGIC))
+               return 0;
+
+       /*
+        * There can be more magic here if the
+        * header ever needs more expansion.
+        * For now just catch use of any of the
+        * unused bits.
+        */
+       if((hp->e.exechdr.magic & ~DYN_MAGIC)>>16)
+               return 0;
+       entry = beswav(*(uvlong*)&hp->e.exechdr);
+
+       pgsize = mach->pgsize;
+       settext(fp, entry, pgsize+fp->hdrsz, hp->e.exechdr.text, fp->hdrsz);
+       setdata(fp, _round(pgsize+fp->txtsz+fp->hdrsz, pgsize),
+               hp->e.exechdr.data, fp->txtsz+fp->hdrsz, hp->e.exechdr.bss);
+       setsym(fp, hp->e.exechdr.syms, hp->e.exechdr.spsz, hp->e.exechdr.pcsz, fp->datoff+fp->datsz);
+
+       if(hp->e.exechdr.magic & DYN_MAGIC) {
+               fp->txtaddr = 0;
+               fp->dataddr = fp->txtsz;
+               return 1;
+       }
+       commonboot(fp);
+       return 1;
+}
+
+/*
+ *     mips bootable image.
+ */
+static int
+mipsboot(int fd, Fhdr *fp, ExecHdr *hp)
+{
+abort();
+#ifdef unused
+       USED(fd);
+       fp->type = FMIPSB;
+       switch(hp->e.exechdr.amagic) {
+       default:
+       case 0407:      /* some kind of mips */
+               settext(fp, (u32int)hp->e.mentry, (u32int)hp->e.text_start,
+                       hp->e.tsize, sizeof(struct mipsexec)+4);
+               setdata(fp, (u32int)hp->e.data_start, hp->e.dsize,
+                       fp->txtoff+hp->e.tsize, hp->e.bsize);
+               break;
+       case 0413:      /* some kind of mips */
+               settext(fp, (u32int)hp->e.mentry, (u32int)hp->e.text_start,
+                       hp->e.tsize, 0);
+               setdata(fp, (u32int)hp->e.data_start, hp->e.dsize,
+                       hp->e.tsize, hp->e.bsize);
+               break;
+       }
+       setsym(fp, hp->e.nsyms, 0, hp->e.pcsize, hp->e.symptr);
+       fp->hdrsz = 0;                  /* header stripped */
+#endif
+       return 1;
+}
+
+/*
+ *     mips4k bootable image.
+ */
+static int
+mips4kboot(int fd, Fhdr *fp, ExecHdr *hp)
+{
+abort();
+#ifdef unused
+       USED(fd);
+       fp->type = FMIPSB;
+       switch(hp->e.h.amagic) {
+       default:
+       case 0407:      /* some kind of mips */
+               settext(fp, (u32int)hp->e.h.mentry, (u32int)hp->e.h.text_start,
+                       hp->e.h.tsize, sizeof(struct mips4kexec));
+               setdata(fp, (u32int)hp->e.h.data_start, hp->e.h.dsize,
+                       fp->txtoff+hp->e.h.tsize, hp->e.h.bsize);
+               break;
+       case 0413:      /* some kind of mips */
+               settext(fp, (u32int)hp->e.h.mentry, (u32int)hp->e.h.text_start,
+                       hp->e.h.tsize, 0);
+               setdata(fp, (u32int)hp->e.h.data_start, hp->e.h.dsize,
+                       hp->e.h.tsize, hp->e.h.bsize);
+               break;
+       }
+       setsym(fp, hp->e.h.nsyms, 0, hp->e.h.pcsize, hp->e.h.symptr);
+       fp->hdrsz = 0;                  /* header stripped */
+#endif
+       return 1;
+}
+
+/*
+ *     sparc bootable image
+ */
+static int
+sparcboot(int fd, Fhdr *fp, ExecHdr *hp)
+{
+abort();
+#ifdef unused
+       USED(fd);
+       fp->type = FSPARCB;
+       settext(fp, hp->e.sentry, hp->e.sentry, hp->e.stext,
+               sizeof(struct sparcexec));
+       setdata(fp, hp->e.sentry+hp->e.stext, hp->e.sdata,
+               fp->txtoff+hp->e.stext, hp->e.sbss);
+       setsym(fp, hp->e.ssyms, 0, hp->e.sdrsize, fp->datoff+hp->e.sdata);
+       fp->hdrsz = 0;                  /* header stripped */
+#endif
+       return 1;
+}
+
+/*
+ *     next bootable image
+ */
+static int
+nextboot(int fd, Fhdr *fp, ExecHdr *hp)
+{
+abort();
+#ifdef unused
+       USED(fd);
+       fp->type = FNEXTB;
+       settext(fp, hp->e.textc.vmaddr, hp->e.textc.vmaddr,
+               hp->e.texts.size, hp->e.texts.offset);
+       setdata(fp, hp->e.datac.vmaddr, hp->e.datas.size,
+               hp->e.datas.offset, hp->e.bsss.size);
+       setsym(fp, hp->e.symc.nsyms, hp->e.symc.spoff, hp->e.symc.pcoff,
+               hp->e.symc.symoff);
+       fp->hdrsz = 0;                  /* header stripped */
+#endif
+       return 1;
+}
+
+/*
+ * Elf32 and Elf64 binaries.
+ */
+static int
+elf64dotout(int fd, Fhdr *fp, ExecHdr *hp)
+{
+
+       uvlong (*swav)(uvlong);
+       ulong (*swal)(ulong);
+       ushort (*swab)(ushort);
+       Ehdr64 *ep;
+       Phdr64 *ph;
+       int i, it, id, is, phsz;
+
+       /* bitswap the header according to the DATA format */
+       ep = &hp->e.elfhdr64;
+       if(ep->ident[CLASS] != ELFCLASS64) {
+               werrstr("bad ELF class - not 32 bit or 64 bit");
+               return 0;
+       }
+       if(ep->ident[DATA] == ELFDATA2LSB) {
+               swab = leswab;
+               swal = leswal;
+               swav = leswav;
+       } else if(ep->ident[DATA] == ELFDATA2MSB) {
+               swab = beswab;
+               swal = beswal;
+               swav = beswav;
+       } else {
+               werrstr("bad ELF encoding - not big or little endian");
+               return 0;
+       }
+
+       ep->type = swab(ep->type);
+       ep->machine = swab(ep->machine);
+       ep->version = swal(ep->version);
+       ep->elfentry = swal(ep->elfentry);
+print("entry: 0x%x\n", ep->elfentry);
+       ep->phoff = swav(ep->phoff);
+       ep->shoff = swav(ep->shoff);
+       ep->flags = swav(ep->flags);
+       ep->ehsize = swab(ep->ehsize);
+       ep->phentsize = swab(ep->phentsize);
+       ep->phnum = swab(ep->phnum);
+       ep->shentsize = swab(ep->shentsize);
+       ep->shnum = swab(ep->shnum);
+       ep->shstrndx = swab(ep->shstrndx);
+       if(ep->type != EXEC || ep->version != CURRENT)
+               return 0;
+
+       /* we could definitely support a lot more machines here */
+       fp->magic = ELF_MAG;
+       fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15;
+       switch(ep->machine) {
+       case I386:
+               mach = &mi386;
+               fp->type = FI386;
+               break;
+       case MIPS:
+               mach = &mmips;
+               fp->type = FMIPS;
+               break;
+       case SPARC64:
+               mach = &msparc64;
+               fp->type = FSPARC64;
+               break;
+       case POWER:
+               mach = &mpower;
+               fp->type = FPOWER;
+               break;
+       case AMD64:
+               mach = &mamd64;
+               fp->type = FAMD64;
+               break;
+       case ARM:
+               mach = &marm;
+               fp->type = FARM;
+               break;
+       default:
+               return 0;
+       }
+
+       if(ep->phentsize != sizeof(Phdr64)) {
+               werrstr("bad ELF header size");
+               return 0;
+       }
+       phsz = sizeof(Phdr64)*ep->phnum;
+       ph = malloc(phsz);
+       if(!ph)
+               return 0;
+       seek(fd, ep->phoff, 0);
+       if(read(fd, ph, phsz) < 0) {
+               free(ph);
+               return 0;
+       }
+       hswal(ph, phsz/sizeof(ulong), swal);
+
+       /* find text, data and symbols and install them */
+       it = id = is = -1;
+       for(i = 0; i < ep->phnum; i++) {
+               if(ph[i].type == LOAD
+               && (ph[i].flags & (R|X)) == (R|X) && it == -1)
+                       it = i;
+               else if(ph[i].type == LOAD
+               && (ph[i].flags & (R|W)) == (R|W) && id == -1)
+                       id = i;
+               else if(ph[i].type == NOPTYPE && is == -1)
+                       is = i;
+       }
+       if(it == -1 || id == -1) {
+               /*
+                * The SPARC64 boot image is something of an ELF hack.
+                * Text+Data+BSS are represented by ph[0].  Symbols
+                * are represented by ph[1]:
+                *
+                *              filesz, memsz, vaddr, paddr, off
+                * ph[0] : txtsz+datsz, txtsz+datsz+bsssz, txtaddr-KZERO, datasize, txtoff
+                * ph[1] : symsz, lcsz, 0, 0, symoff
+                */
+               if(ep->machine == SPARC64 && ep->phnum == 2) {
+                       ulong txtaddr, txtsz, dataddr, bsssz;
+
+                       txtaddr = ph[0].vaddr | 0x80000000;
+                       txtsz = ph[0].filesz - ph[0].paddr;
+                       dataddr = txtaddr + txtsz;
+                       bsssz = ph[0].memsz - ph[0].filesz;
+                       settext(fp, ep->elfentry | 0x80000000, txtaddr, txtsz, ph[0].offset);
+                       setdata(fp, dataddr, ph[0].paddr, ph[0].offset + txtsz, bsssz);
+                       setsym(fp, ph[1].filesz, 0, ph[1].memsz, ph[1].offset);
+                       free(ph);
+                       return 1;
+               }
+
+               werrstr("No TEXT or DATA sections");
+               free(ph);
+               return 0;
+       }
+
+       settext(fp, ep->elfentry, ph[it].vaddr, ph[it].memsz, ph[it].offset);
+       setdata(fp, ph[id].vaddr, ph[id].filesz, ph[id].offset, ph[id].memsz - ph[id].filesz);
+       if(is != -1)
+               setsym(fp, ph[is].filesz, 0, ph[is].memsz, ph[is].offset);
+       free(ph);
+       return 1;
+}
+
+static int
+elfdotout(int fd, Fhdr *fp, ExecHdr *hp)
+{
+
+       ulong (*swal)(ulong);
+       ushort (*swab)(ushort);
+       Ehdr32 *ep;
+       Phdr32 *ph;
+       int i, it, id, is, phsz;
+
+       /* bitswap the header according to the DATA format */
+       ep = &hp->e.elfhdr32;
+       if(ep->ident[CLASS] != ELFCLASS32) {
+               return elf64dotout(fd, fp, hp);
+       }
+       if(ep->ident[DATA] == ELFDATA2LSB) {
+               swab = leswab;
+               swal = leswal;
+       } else if(ep->ident[DATA] == ELFDATA2MSB) {
+               swab = beswab;
+               swal = beswal;
+       } else {
+               werrstr("bad ELF encoding - not big or little endian");
+               return 0;
+       }
+
+       ep->type = swab(ep->type);
+       ep->machine = swab(ep->machine);
+       ep->version = swal(ep->version);
+       ep->elfentry = swal(ep->elfentry);
+       ep->phoff = swal(ep->phoff);
+       ep->shoff = swal(ep->shoff);
+       ep->flags = swal(ep->flags);
+       ep->ehsize = swab(ep->ehsize);
+       ep->phentsize = swab(ep->phentsize);
+       ep->phnum = swab(ep->phnum);
+       ep->shentsize = swab(ep->shentsize);
+       ep->shnum = swab(ep->shnum);
+       ep->shstrndx = swab(ep->shstrndx);
+       if(ep->type != EXEC || ep->version != CURRENT)
+               return 0;
+
+       /* we could definitely support a lot more machines here */
+       fp->magic = ELF_MAG;
+       fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15;
+       switch(ep->machine) {
+       case I386:
+               mach = &mi386;
+               fp->type = FI386;
+               break;
+       case MIPS:
+               mach = &mmips;
+               fp->type = FMIPS;
+               break;
+       case SPARC64:
+               mach = &msparc64;
+               fp->type = FSPARC64;
+               break;
+       case POWER:
+               mach = &mpower;
+               fp->type = FPOWER;
+               break;
+       case AMD64:
+               mach = &mamd64;
+               fp->type = FAMD64;
+               break;
+       case ARM:
+               mach = &marm;
+               fp->type = FARM;
+               break;
+       default:
+               return 0;
+       }
+
+       if(ep->phentsize != sizeof(Phdr32)) {
+               werrstr("bad ELF header size");
+               return 0;
+       }
+       phsz = sizeof(Phdr32)*ep->phnum;
+       ph = malloc(phsz);
+       if(!ph)
+               return 0;
+       seek(fd, ep->phoff, 0);
+       if(read(fd, ph, phsz) < 0) {
+               free(ph);
+               return 0;
+       }
+       hswal(ph, phsz/sizeof(ulong), swal);
+
+       /* find text, data and symbols and install them */
+       it = id = is = -1;
+       for(i = 0; i < ep->phnum; i++) {
+               if(ph[i].type == LOAD
+               && (ph[i].flags & (R|X)) == (R|X) && it == -1)
+                       it = i;
+               else if(ph[i].type == LOAD
+               && (ph[i].flags & (R|W)) == (R|W) && id == -1)
+                       id = i;
+               else if(ph[i].type == NOPTYPE && is == -1)
+                       is = i;
+       }
+       if(it == -1 || id == -1) {
+               /*
+                * The SPARC64 boot image is something of an ELF hack.
+                * Text+Data+BSS are represented by ph[0].  Symbols
+                * are represented by ph[1]:
+                *
+                *              filesz, memsz, vaddr, paddr, off
+                * ph[0] : txtsz+datsz, txtsz+datsz+bsssz, txtaddr-KZERO, datasize, txtoff
+                * ph[1] : symsz, lcsz, 0, 0, symoff
+                */
+               if(ep->machine == SPARC64 && ep->phnum == 2) {
+                       ulong txtaddr, txtsz, dataddr, bsssz;
+
+                       txtaddr = ph[0].vaddr | 0x80000000;
+                       txtsz = ph[0].filesz - ph[0].paddr;
+                       dataddr = txtaddr + txtsz;
+                       bsssz = ph[0].memsz - ph[0].filesz;
+                       settext(fp, ep->elfentry | 0x80000000, txtaddr, txtsz, ph[0].offset);
+                       setdata(fp, dataddr, ph[0].paddr, ph[0].offset + txtsz, bsssz);
+                       setsym(fp, ph[1].filesz, 0, ph[1].memsz, ph[1].offset);
+                       free(ph);
+                       return 1;
+               }
+
+               werrstr("No TEXT or DATA sections");
+               free(ph);
+               return 0;
+       }
+
+       settext(fp, ep->elfentry, ph[it].vaddr, ph[it].memsz, ph[it].offset);
+       setdata(fp, ph[id].vaddr, ph[id].filesz, ph[id].offset, ph[id].memsz - ph[id].filesz);
+       if(is != -1)
+               setsym(fp, ph[is].filesz, 0, ph[is].memsz, ph[is].offset);
+       free(ph);
+       return 1;
+}
+
+/*
+ * (Free|Net)BSD ARM header.
+ */
+static int
+armdotout(int fd, Fhdr *fp, ExecHdr *hp)
+{
+       uvlong kbase;
+
+       USED(fd);
+       settext(fp, hp->e.exechdr.entry, sizeof(Exec), hp->e.exechdr.text, sizeof(Exec));
+       setdata(fp, fp->txtsz, hp->e.exechdr.data, fp->txtsz, hp->e.exechdr.bss);
+       setsym(fp, hp->e.exechdr.syms, hp->e.exechdr.spsz, hp->e.exechdr.pcsz, fp->datoff+fp->datsz);
+
+       kbase = 0xF0000000;
+       if ((fp->entry & kbase) == kbase) {             /* Boot image */
+               fp->txtaddr = kbase+sizeof(Exec);
+               fp->name = "ARM *BSD boot image";
+               fp->hdrsz = 0;          /* header stripped */
+               fp->dataddr = kbase+fp->txtsz;
+       }
+       return 1;
+}
+
+static void
+settext(Fhdr *fp, uvlong e, uvlong a, long s, vlong off)
+{
+       fp->txtaddr = a;
+       fp->entry = e;
+       fp->txtsz = s;
+       fp->txtoff = off;
+}
+
+static void
+setdata(Fhdr *fp, uvlong a, long s, vlong off, long bss)
+{
+       fp->dataddr = a;
+       fp->datsz = s;
+       fp->datoff = off;
+       fp->bsssz = bss;
+}
+
+static void
+setsym(Fhdr *fp, long symsz, long sppcsz, long lnpcsz, vlong symoff)
+{
+       fp->symsz = symsz;
+       fp->symoff = symoff;
+       fp->sppcsz = sppcsz;
+       fp->sppcoff = fp->symoff+fp->symsz;
+       fp->lnpcsz = lnpcsz;
+       fp->lnpcoff = fp->sppcoff+fp->sppcsz;
+}
+
+
+static uvlong
+_round(uvlong a, ulong b)
+{
+       uvlong w;
+
+       w = (a/b)*b;
+       if (a!=w)
+               w += b;
+       return(w);
+}
diff --git a/src/libmachamd64/machdata.c b/src/libmachamd64/machdata.c
new file mode 100644 (file)
index 0000000..8a25d1d
--- /dev/null
@@ -0,0 +1,477 @@
+// Inferno libmach/machdata.c
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/machdata.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.
+//     Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+//     Portions Copyright © 1997-1999 Vita Nuova Limited.
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+//     Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+/*
+ * Debugger utilities shared by at least two architectures
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach_amd64.h>
+
+#define STARTSYM       "_main"
+#define PROFSYM                "_mainp"
+#define        FRAMENAME       ".frame"
+
+extern Machdata        mipsmach;
+
+int    asstype = AMIPS;                /* disassembler type */
+Machdata *machdata;            /* machine-dependent functions */
+
+int
+localaddr(Map *map, char *fn, char *var, uvlong *r, Rgetter rget)
+{
+       Symbol s;
+       uvlong fp, pc, sp, link;
+
+       if (!lookup(fn, 0, &s)) {
+               werrstr("function not found");
+               return -1;
+       }
+       pc = rget(map, mach->pc);
+       sp = rget(map, mach->sp);
+       if(mach->link)
+               link = rget(map, mach->link);
+       else
+               link = 0;
+       fp = machdata->findframe(map, s.value, pc, sp, link);
+       if (fp == 0) {
+               werrstr("stack frame not found");
+               return -1;
+       }
+
+       if (!var || !var[0]) {
+               *r = fp;
+               return 1;
+       }
+
+       if (findlocal(&s, var, &s) == 0) {
+               werrstr("local variable not found");
+               return -1;
+       }
+
+       switch (s.class) {
+       case CAUTO:
+               *r = fp - s.value;
+               break;
+       case CPARAM:            /* assume address size is stack width */
+               *r = fp + s.value + mach->szaddr;
+               break;
+       default:
+               werrstr("local variable not found: %d", s.class);
+               return -1;
+       }
+       return 1;
+}
+
+/*
+ * Print value v as s.name[+offset] if possible, or just v.
+ */
+int
+symoff(char *buf, int n, uvlong v, int space)
+{
+       Symbol s;
+       int r;
+       long delta;
+
+       r = delta = 0;          /* to shut compiler up */
+       if (v) {
+               r = findsym(v, space, &s);
+               if (r)
+                       delta = v-s.value;
+               if (delta < 0)
+                       delta = -delta;
+       }
+       if (v == 0 || r == 0)
+               return snprint(buf, n, "%llux", v);
+       if (s.type != 't' && s.type != 'T' && delta >= 4096)
+               return snprint(buf, n, "%llux", v);
+       else if (delta)
+               return snprint(buf, n, "%s+%lux", s.name, delta);
+       else
+               return snprint(buf, n, "%s", s.name);
+}
+
+/*
+ *     Format floating point registers
+ *
+ *     Register codes in format field:
+ *     'X' - print as 32-bit hexadecimal value
+ *     'F' - 64-bit double register when modif == 'F'; else 32-bit single reg
+ *     'f' - 32-bit ieee float
+ *     '8' - big endian 80-bit ieee extended float
+ *     '3' - little endian 80-bit ieee extended float with hole in bytes 8&9
+ */
+int
+fpformat(Map *map, Reglist *rp, char *buf, int n, int modif)
+{
+       char reg[12];
+       ulong r;
+
+       switch(rp->rformat)
+       {
+       case 'X':
+               if (get4(map, rp->roffs, &r) < 0)
+                       return -1;
+               snprint(buf, n, "%lux", r);
+               break;
+       case 'F':       /* first reg of double reg pair */
+               if (modif == 'F')
+               if ((rp->rformat=='F') || (((rp+1)->rflags&RFLT) && (rp+1)->rformat == 'f')) {
+                       if (get1(map, rp->roffs, (uchar *)reg, 8) < 0)
+                               return -1;
+                       machdata->dftos(buf, n, reg);
+                       if (rp->rformat == 'F')
+                               return 1;
+                       return 2;
+               }       
+                       /* treat it like 'f' */
+               if (get1(map, rp->roffs, (uchar *)reg, 4) < 0)
+                       return -1;
+               machdata->sftos(buf, n, reg);
+               break;
+       case 'f':       /* 32 bit float */
+               if (get1(map, rp->roffs, (uchar *)reg, 4) < 0)
+                       return -1;
+               machdata->sftos(buf, n, reg);
+               break;
+       case '3':       /* little endian ieee 80 with hole in bytes 8&9 */
+               if (get1(map, rp->roffs, (uchar *)reg, 10) < 0)
+                       return -1;
+               memmove(reg+10, reg+8, 2);      /* open hole */
+               memset(reg+8, 0, 2);            /* fill it */
+               leieee80ftos(buf, n, reg);
+               break;
+       case '8':       /* big-endian ieee 80 */
+               if (get1(map, rp->roffs, (uchar *)reg, 10) < 0)
+                       return -1;
+               beieee80ftos(buf, n, reg);
+               break;
+       default:        /* unknown */
+               break;
+       }
+       return 1;
+}
+
+char *
+_hexify(char *buf, ulong p, int zeros)
+{
+       ulong d;
+
+       d = p/16;
+       if(d)
+               buf = _hexify(buf, d, zeros-1);
+       else
+               while(zeros--)
+                       *buf++ = '0';
+       *buf++ = "0123456789abcdef"[p&0x0f];
+       return buf;
+}
+
+/*
+ * These routines assume that if the number is representable
+ * in IEEE floating point, it will be representable in the native
+ * double format.  Naive but workable, probably.
+ */
+int
+ieeedftos(char *buf, int n, ulong h, ulong l)
+{
+       double fr;
+       int exp;
+
+       if (n <= 0)
+               return 0;
+
+
+       if(h & (1L<<31)){
+               *buf++ = '-';
+               h &= ~(1L<<31);
+       }else
+               *buf++ = ' ';
+       n--;
+       if(l == 0 && h == 0)
+               return snprint(buf, n, "0.");
+       exp = (h>>20) & ((1L<<11)-1L);
+       if(exp == 0)
+               return snprint(buf, n, "DeN(%.8lux%.8lux)", h, l);
+       if(exp == ((1L<<11)-1L)){
+               if(l==0 && (h&((1L<<20)-1L)) == 0)
+                       return snprint(buf, n, "Inf");
+               else
+                       return snprint(buf, n, "NaN(%.8lux%.8lux)", h&((1L<<20)-1L), l);
+       }
+       exp -= (1L<<10) - 2L;
+       fr = l & ((1L<<16)-1L);
+       fr /= 1L<<16;
+       fr += (l>>16) & ((1L<<16)-1L);
+       fr /= 1L<<16;
+       fr += (h & (1L<<20)-1L) | (1L<<20);
+       fr /= 1L<<21;
+       fr = ldexp(fr, exp);
+       return snprint(buf, n, "%.18g", fr);
+}
+
+int
+ieeesftos(char *buf, int n, ulong h)
+{
+       double fr;
+       int exp;
+
+       if (n <= 0)
+               return 0;
+
+       if(h & (1L<<31)){
+               *buf++ = '-';
+               h &= ~(1L<<31);
+       }else
+               *buf++ = ' ';
+       n--;
+       if(h == 0)
+               return snprint(buf, n, "0.");
+       exp = (h>>23) & ((1L<<8)-1L);
+       if(exp == 0)
+               return snprint(buf, n, "DeN(%.8lux)", h);
+       if(exp == ((1L<<8)-1L)){
+               if((h&((1L<<23)-1L)) == 0)
+                       return snprint(buf, n, "Inf");
+               else
+                       return snprint(buf, n, "NaN(%.8lux)", h&((1L<<23)-1L));
+       }
+       exp -= (1L<<7) - 2L;
+       fr = (h & ((1L<<23)-1L)) | (1L<<23);
+       fr /= 1L<<24;
+       fr = ldexp(fr, exp);
+       return snprint(buf, n, "%.9g", fr);
+}
+
+int
+beieeesftos(char *buf, int n, void *s)
+{
+       return ieeesftos(buf, n, beswal(*(ulong*)s));
+}
+
+int
+beieeedftos(char *buf, int n, void *s)
+{
+       return ieeedftos(buf, n, beswal(*(ulong*)s), beswal(((ulong*)(s))[1]));
+}
+
+int
+leieeesftos(char *buf, int n, void *s)
+{
+       return ieeesftos(buf, n, leswal(*(ulong*)s));
+}
+
+int
+leieeedftos(char *buf, int n, void *s)
+{
+       return ieeedftos(buf, n, leswal(((ulong*)(s))[1]), leswal(*(ulong*)s));
+}
+
+/* packed in 12 bytes, with s[2]==s[3]==0; mantissa starts at s[4]*/
+int
+beieee80ftos(char *buf, int n, void *s)
+{
+       uchar *reg = (uchar*)s;
+       int i;
+       ulong x;
+       uchar ieee[8+8];        /* room for slop */
+       uchar *p, *q;
+
+       memset(ieee, 0, sizeof(ieee));
+       /* sign */
+       if(reg[0] & 0x80)
+               ieee[0] |= 0x80;
+
+       /* exponent */
+       x = ((reg[0]&0x7F)<<8) | reg[1];
+       if(x == 0)              /* number is ±0 */
+               goto done;
+       if(x == 0x7FFF){
+               if(memcmp(reg+4, ieee+1, 8) == 0){ /* infinity */
+                       x = 2047;
+               }else{                          /* NaN */
+                       x = 2047;
+                       ieee[7] = 0x1;          /* make sure */
+               }
+               ieee[0] |= x>>4;
+               ieee[1] |= (x&0xF)<<4;
+               goto done;
+       }
+       x -= 0x3FFF;            /* exponent bias */
+       x += 1023;
+       if(x >= (1<<11) || ((reg[4]&0x80)==0 && x!=0))
+               return snprint(buf, n, "not in range");
+       ieee[0] |= x>>4;
+       ieee[1] |= (x&0xF)<<4;
+
+       /* mantissa */
+       p = reg+4;
+       q = ieee+1;
+       for(i=0; i<56; i+=8, p++, q++){ /* move one byte */
+               x = (p[0]&0x7F) << 1;
+               if(p[1] & 0x80)
+                       x |= 1;
+               q[0] |= x>>4;
+               q[1] |= (x&0xF)<<4;
+       }
+    done:
+       return beieeedftos(buf, n, (void*)ieee);
+}
+
+int
+leieee80ftos(char *buf, int n, void *s)
+{
+       int i;
+       char *cp;
+       char b[12];
+
+       cp = (char*) s;
+       for(i=0; i<12; i++)
+               b[11-i] = *cp++;
+       return beieee80ftos(buf, n, b);
+}
+
+int
+cisctrace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace)
+{
+       Symbol s;
+       int found, i;
+       uvlong opc, moved;
+
+       USED(link);
+       i = 0;
+       opc = 0;
+       while(pc && opc != pc) {
+               moved = pc2sp(pc);
+               if (moved == ~0)
+                       break;
+               found = findsym(pc, CTEXT, &s);
+               if (!found)
+                       break;
+               if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
+                       break;
+
+               sp += moved;
+               opc = pc;
+               if (geta(map, sp, &pc) < 0)
+                       break;
+               (*trace)(map, pc, sp, &s);
+               sp += mach->szaddr;     /*assumes address size = stack width*/
+               if(++i > 40)
+                       break;
+       }
+       return i;
+}
+
+int
+risctrace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace)
+{
+       int i;
+       Symbol s, f;
+       uvlong oldpc;
+
+       i = 0;
+       while(findsym(pc, CTEXT, &s)) {
+               if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
+                       break;
+
+               if(pc == s.value)       /* at first instruction */
+                       f.value = 0;
+               else if(findlocal(&s, FRAMENAME, &f) == 0)
+                       break;
+
+               oldpc = pc;
+               if(s.type == 'L' || s.type == 'l' || pc <= s.value+mach->pcquant)
+                       pc = link;
+               else
+                       if (geta(map, sp, &pc) < 0)
+                               break;
+
+               if(pc == 0 || (pc == oldpc && f.value == 0))
+                       break;
+
+               sp += f.value;
+               (*trace)(map, pc-8, sp, &s);
+
+               if(++i > 40)
+                       break;
+       }
+       return i;
+}
+
+uvlong
+ciscframe(Map *map, uvlong addr, uvlong pc, uvlong sp, uvlong link)
+{
+       Symbol s;
+       uvlong moved;
+
+       USED(link);
+       for(;;) {
+               moved = pc2sp(pc);
+               if (moved  == ~0)
+                       break;
+               sp += moved;
+               findsym(pc, CTEXT, &s);
+               if (addr == s.value)
+                       return sp;
+               if (geta(map, sp, &pc) < 0)
+                       break;
+               sp += mach->szaddr;     /*assumes sizeof(addr) = stack width*/
+       }
+       return 0;
+}
+
+uvlong
+riscframe(Map *map, uvlong addr, uvlong pc, uvlong sp, uvlong link)
+{
+       Symbol s, f;
+
+       while (findsym(pc, CTEXT, &s)) {
+               if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
+                       break;
+
+               if(pc == s.value)       /* at first instruction */
+                       f.value = 0;
+               else
+               if(findlocal(&s, FRAMENAME, &f) == 0)
+                       break;
+
+               sp += f.value;
+               if (s.value == addr)
+                       return sp;
+
+               if (s.type == 'L' || s.type == 'l' || pc-s.value <= mach->szaddr*2)
+                       pc = link;
+               else
+               if (geta(map, sp-f.value, &pc) < 0)
+                       break;
+       }
+       return 0;
+}
diff --git a/src/libmachamd64/map.c b/src/libmachamd64/map.c
new file mode 100644 (file)
index 0000000..5bc8067
--- /dev/null
@@ -0,0 +1,205 @@
+// Derived from Inferno libmach/map.c and
+// Plan 9 from User Space src/libmach/map.c
+//
+// http://code.swtch.com/plan9port/src/tip/src/libmach/map.c
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/map.c
+//
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.
+//     Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+//     Portions Copyright © 1997-1999 Vita Nuova Limited.
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+//     Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+//     Portions Copyright © 2001-2007 Russ Cox.
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+/*
+ * file map routines
+ */
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach_amd64.h>
+
+Map *
+newmap(Map *map, int n)
+{
+       int size;
+
+       size = sizeof(Map)+(n-1)*sizeof(struct segment);
+       if (map == 0)
+               map = malloc(size);
+       else
+               map = realloc(map, size);
+       if (map == 0) {
+               werrstr("out of memory: %r");
+               return 0;
+       }
+       memset(map, 0, size);
+       map->nsegs = n;
+       return map;
+}
+
+int
+setmap(Map *map, int fd, uvlong b, uvlong e, vlong f, char *name)
+{
+       int i;
+
+       if (map == 0)
+               return 0;
+       for (i = 0; i < map->nsegs; i++)
+               if (!map->seg[i].inuse)
+                       break;
+       if (i >= map->nsegs)
+               return 0;
+       map->seg[i].b = b;
+       map->seg[i].e = e;
+       map->seg[i].f = f;
+       map->seg[i].inuse = 1;
+       map->seg[i].name = name;
+       map->seg[i].fd = fd;
+       return 1;
+}
+
+static uvlong
+stacktop(int pid)
+{
+       char buf[64];
+       int fd;
+       int n;
+       char *cp;
+
+       snprint(buf, sizeof(buf), "/proc/%d/segment", pid);
+       fd = open(buf, 0);
+       if (fd < 0)
+               return 0;
+       n = read(fd, buf, sizeof(buf)-1);
+       close(fd);
+       buf[n] = 0;
+       if (strncmp(buf, "Stack", 5))
+               return 0;
+       for (cp = buf+5; *cp && *cp == ' '; cp++)
+               ;
+       if (!*cp)
+               return 0;
+       cp = strchr(cp, ' ');
+       if (!cp)
+               return 0;
+       while (*cp && *cp == ' ')
+               cp++;
+       if (!*cp)
+               return 0;
+       return strtoull(cp, 0, 16);
+}
+
+Map*
+attachproc(int pid, int kflag, int corefd, Fhdr *fp)
+{
+       char buf[64], *regs;
+       int fd;
+       Map *map;
+       uvlong n;
+       int mode;
+
+       map = newmap(0, 4);
+       if (!map)
+               return 0;
+       if(kflag) {
+               regs = "kregs";
+               mode = OREAD;
+       } else {
+               regs = "regs";
+               mode = ORDWR;
+       }
+       if (mach->regsize) {
+               sprint(buf, "/proc/%d/%s", pid, regs);
+               fd = open(buf, mode);
+               if(fd < 0) {
+                       free(map);
+                       return 0;
+               }
+               setmap(map, fd, 0, mach->regsize, 0, "regs");
+       }
+       if (mach->fpregsize) {
+               sprint(buf, "/proc/%d/fpregs", pid);
+               fd = open(buf, mode);
+               if(fd < 0) {
+                       close(map->seg[0].fd);
+                       free(map);
+                       return 0;
+               }
+               setmap(map, fd, mach->regsize, mach->regsize+mach->fpregsize, 0, "fpregs");
+       }
+       setmap(map, corefd, fp->txtaddr, fp->txtaddr+fp->txtsz, fp->txtaddr, "text");
+       if(kflag || fp->dataddr >= mach->utop) {
+               setmap(map, corefd, fp->dataddr, ~0, fp->dataddr, "data");
+               return map;
+       }
+       n = stacktop(pid);
+       if (n == 0) {
+               setmap(map, corefd, fp->dataddr, mach->utop, fp->dataddr, "data");
+               return map;
+       }
+       setmap(map, corefd, fp->dataddr, n, fp->dataddr, "data");
+       return map;
+}
+       
+int
+findseg(Map *map, char *name)
+{
+       int i;
+
+       if (!map)
+               return -1;
+       for (i = 0; i < map->nsegs; i++)
+               if (map->seg[i].inuse && !strcmp(map->seg[i].name, name))
+                       return i;
+       return -1;
+}
+
+void
+unusemap(Map *map, int i)
+{
+       if (map != 0 && 0 <= i && i < map->nsegs)
+               map->seg[i].inuse = 0;
+}
+
+Map*
+loadmap(Map *map, int fd, Fhdr *fp)
+{
+       map = newmap(map, 2);
+       if (map == 0)
+               return 0;
+
+       map->seg[0].b = fp->txtaddr;
+       map->seg[0].e = fp->txtaddr+fp->txtsz;
+       map->seg[0].f = fp->txtoff;
+       map->seg[0].fd = fd;
+       map->seg[0].inuse = 1;
+       map->seg[0].name = "text";
+       map->seg[1].b = fp->dataddr;
+       map->seg[1].e = fp->dataddr+fp->datsz;
+       map->seg[1].f = fp->datoff;
+       map->seg[1].fd = fd;
+       map->seg[1].inuse = 1;
+       map->seg[1].name = "data";
+       return map;
+}
diff --git a/src/libmachamd64/obj.c b/src/libmachamd64/obj.c
new file mode 100644 (file)
index 0000000..5741f7a
--- /dev/null
@@ -0,0 +1,356 @@
+// Inferno libmach/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/obj.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.
+//     Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+//     Portions Copyright © 1997-1999 Vita Nuova Limited.
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+//     Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+/*
+ * obj.c
+ * routines universal to all object files
+ */
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <ar.h>
+#include <mach_amd64.h>
+#include "obj.h"
+
+#define islocal(t)     ((t)=='a' || (t)=='p')
+
+enum
+{
+       NNAMES  = 50,
+       MAXIS   = 8,            /* max length to determine if a file is a .? file */
+       MAXOFF  = 0x7fffffff,   /* larger than any possible local offset */
+       NHASH   = 1024,         /* must be power of two */
+       HASHMUL = 79L,
+};
+
+int    _is2(char*),            /* in [$OS].c */
+       _is5(char*),
+       _is6(char*),
+       _is7(char*),
+       _is8(char*),
+       _is9(char*),
+       _isk(char*),
+       _isq(char*),
+       _isv(char*),
+       _isu(char*),
+       _read2(Biobuf*, Prog*),
+       _read5(Biobuf*, Prog*),
+       _read6(Biobuf*, Prog*),
+       _read7(Biobuf*, Prog*),
+       _read8(Biobuf*, Prog*),
+       _read9(Biobuf*, Prog*),
+       _readk(Biobuf*, Prog*),
+       _readq(Biobuf*, Prog*),
+       _readv(Biobuf*, Prog*),
+       _readu(Biobuf*, Prog*);
+
+typedef struct Obj     Obj;
+typedef struct Symtab  Symtab;
+
+struct Obj             /* functions to handle each intermediate (.$O) file */
+{
+       char    *name;                          /* name of each $O file */
+       int     (*is)(char*);                   /* test for each type of $O file */
+       int     (*read)(Biobuf*, Prog*);        /* read for each type of $O file*/
+};
+
+static Obj     obj[] =
+{                      /* functions to identify and parse each type of obj */
+       [Obj68020]      "68020 .2",     _is2, _read2,
+       [ObjAmd64]      "amd64 .6",     _is6, _read6,
+       [ObjArm]        "arm .5",       _is5, _read5,
+       [ObjAlpha]      "alpha .7",     _is7, _read7,
+       [Obj386]        "386 .8",       _is8, _read8,
+       [ObjSparc]      "sparc .k",     _isk, _readk,
+       [ObjPower]      "power .q",     _isq, _readq,
+       [ObjMips]       "mips .v",      _isv, _readv,
+       [ObjSparc64]    "sparc64 .u",   _isu, _readu,
+       [ObjPower64]    "power64 .9",   _is9, _read9,
+       [Maxobjtype]    0, 0
+};
+
+struct Symtab
+{
+       struct  Sym     s;
+       struct  Symtab  *next;
+};
+
+static Symtab *hash[NHASH];
+static Sym     *names[NNAMES]; /* working set of active names */
+
+static int     processprog(Prog*,int); /* decode each symbol reference */
+static void    objreset(void);
+static void    objlookup(int, char *, int, uint);
+static void    objupdate(int, int);
+
+int
+objtype(Biobuf *bp, char **name)
+{
+       int i;
+       char buf[MAXIS];
+
+       if(Bread(bp, buf, MAXIS) < MAXIS)
+               return -1;
+       Bseek(bp, -MAXIS, 1);
+       for (i = 0; i < Maxobjtype; i++) {
+               if (obj[i].is && (*obj[i].is)(buf)) {
+                       if (name)
+                               *name = obj[i].name;
+                       return i;
+               }
+       }
+       return -1;
+}
+
+int
+isar(Biobuf *bp)
+{
+       int n;
+       char magbuf[SARMAG];
+
+       n = Bread(bp, magbuf, SARMAG);
+       if(n == SARMAG && strncmp(magbuf, ARMAG, SARMAG) == 0)
+               return 1;
+       return 0;
+}
+
+/*
+ * determine what kind of object file this is and process it.
+ * return whether or not this was a recognized intermediate file.
+ */
+int
+readobj(Biobuf *bp, int objtype)
+{
+       Prog p;
+
+       if (objtype < 0 || objtype >= Maxobjtype || obj[objtype].is == 0)
+               return 1;
+       objreset();
+       while ((*obj[objtype].read)(bp, &p))
+               if (!processprog(&p, 1))
+                       return 0;
+       return 1;
+}
+
+int
+readar(Biobuf *bp, int objtype, vlong end, int doautos)
+{
+       Prog p;
+
+       if (objtype < 0 || objtype >= Maxobjtype || obj[objtype].is == 0)
+               return 1;
+       objreset();
+       while ((*obj[objtype].read)(bp, &p) && Boffset(bp) < end)
+               if (!processprog(&p, doautos))
+                       return 0;
+       return 1;
+}
+
+/*
+ *     decode a symbol reference or definition
+ */
+static int
+processprog(Prog *p, int doautos)
+{
+       if(p->kind == aNone)
+               return 1;
+       if(p->sym < 0 || p->sym >= NNAMES)
+               return 0;
+       switch(p->kind)
+       {
+       case aName:
+               if (!doautos)
+               if(p->type != 'U' && p->type != 'b')
+                       break;
+               objlookup(p->sym, p->id, p->type, p->sig);
+               break;
+       case aText:
+               objupdate(p->sym, 'T');
+               break;
+       case aData:
+               objupdate(p->sym, 'D');
+               break;
+       default:
+               break;
+       }
+       return 1;
+}
+
+/*
+ * find the entry for s in the symbol array.
+ * make a new entry if it is not already there.
+ */
+static void
+objlookup(int id, char *name, int type, uint sig)
+{
+       long h;
+       char *cp;
+       Sym *s;
+       Symtab *sp;
+
+       s = names[id];
+       if(s && strcmp(s->name, name) == 0) {
+               s->type = type;
+               s->sig = sig;
+               return;
+       }
+
+       h = *name;
+       for(cp = name+1; *cp; h += *cp++)
+               h *= HASHMUL;
+       if(h < 0)
+               h = ~h;
+       h &= (NHASH-1);
+       if (type == 'U' || type == 'b' || islocal(type)) {
+               for(sp = hash[h]; sp; sp = sp->next)
+                       if(strcmp(sp->s.name, name) == 0) {
+                               switch(sp->s.type) {
+                               case 'T':
+                               case 'D':
+                               case 'U':
+                                       if (type == 'U') {
+                                               names[id] = &sp->s;
+                                               return;
+                                       }
+                                       break;
+                               case 't':
+                               case 'd':
+                               case 'b':
+                                       if (type == 'b') {
+                                               names[id] = &sp->s;
+                                               return;
+                                       }
+                                       break;
+                               case 'a':
+                               case 'p':
+                                       if (islocal(type)) {
+                                               names[id] = &sp->s;
+                                               return;
+                                       }
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
+       }
+       sp = malloc(sizeof(Symtab));
+       sp->s.name = name;
+       sp->s.type = type;
+       sp->s.sig = sig;
+       sp->s.value = islocal(type) ? MAXOFF : 0;
+       names[id] = &sp->s;
+       sp->next = hash[h];
+       hash[h] = sp;
+       return;
+}
+/*
+ *     traverse the symbol lists
+ */
+void
+objtraverse(void (*fn)(Sym*, void*), void *pointer)
+{
+       int i;
+       Symtab *s;
+
+       for(i = 0; i < NHASH; i++)
+               for(s = hash[i]; s; s = s->next)
+                       (*fn)(&s->s, pointer);
+}
+
+/*
+ * update the offset information for a 'a' or 'p' symbol in an intermediate file
+ */
+void
+_offset(int id, vlong off)
+{
+       Sym *s;
+
+       s = names[id];
+       if (s && s->name[0] && islocal(s->type) && s->value > off)
+               s->value = off;
+}
+
+/*
+ * update the type of a global text or data symbol
+ */
+static void 
+objupdate(int id, int type)
+{
+       Sym *s;
+
+       s = names[id];
+       if (s && s->name[0])
+               if (s->type == 'U')
+                       s->type = type;
+               else if (s->type == 'b')
+                       s->type = tolower(type);
+}
+
+/*
+ * look for the next file in an archive
+ */
+int
+nextar(Biobuf *bp, int offset, char *buf)
+{
+       struct ar_hdr a;
+       int i, r;
+       long arsize;
+
+       if (offset&01)
+               offset++;
+       Bseek(bp, offset, 0);
+       r = Bread(bp, &a, SAR_HDR);
+       if(r != SAR_HDR)
+               return 0;
+       if(strncmp(a.fmag, ARFMAG, sizeof(a.fmag)))
+               return -1;
+       for(i=0; i<sizeof(a.name) && i<SARNAME && a.name[i] != ' '; i++)
+               buf[i] = a.name[i];
+       buf[i] = 0;
+       arsize = strtol(a.size, 0, 0);
+       if (arsize&1)
+               arsize++;
+       return arsize + SAR_HDR;
+}
+
+static void
+objreset(void)
+{
+       int i;
+       Symtab *s, *n;
+
+       for(i = 0; i < NHASH; i++) {
+               for(s = hash[i]; s; s = n) {
+                       n = s->next;
+                       free(s->s.name);
+                       free(s);
+               }
+               hash[i] = 0;
+       }
+       memset(names, 0, sizeof names);
+}
diff --git a/src/libmachamd64/obj.h b/src/libmachamd64/obj.h
new file mode 100644 (file)
index 0000000..35ec413
--- /dev/null
@@ -0,0 +1,53 @@
+// Inferno libmach/obj.h
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/obj.h
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.
+//     Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+//     Portions Copyright © 1997-1999 Vita Nuova Limited.
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+//     Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+/*
+ * obj.h -- defs for dealing with object files
+ */
+
+typedef enum Kind              /* variable defs and references in obj */
+{
+       aNone,                  /* we don't care about this prog */
+       aName,                  /* introduces a name */
+       aText,                  /* starts a function */
+       aData,                  /* references to a global object */
+} Kind;
+
+typedef struct Prog    Prog;
+
+struct Prog            /* info from .$O files */
+{
+       Kind    kind;           /* what kind of symbol */
+       char    type;           /* type of the symbol: ie, 'T', 'a', etc. */
+       char    sym;            /* index of symbol's name */
+       char    *id;            /* name for the symbol, if it introduces one */
+       uint    sig;            /* type signature for symbol */
+};
+
+#define UNKNOWN        '?'
+void           _offset(int, vlong);
diff --git a/src/libmachamd64/setmach.c b/src/libmachamd64/setmach.c
new file mode 100644 (file)
index 0000000..613ad3c
--- /dev/null
@@ -0,0 +1,203 @@
+// Inferno libmach/setmach.c
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/setmach.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.
+//     Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+//     Portions Copyright © 1997-1999 Vita Nuova Limited.
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+//     Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include       <u.h>
+#include       <libc.h>
+#include       <bio.h>
+#include       <mach_amd64.h>
+               /* table for selecting machine-dependent parameters */
+
+typedef        struct machtab Machtab;
+
+struct machtab
+{
+       char            *name;                  /* machine name */
+       short           type;                   /* executable type */
+       short           boottype;               /* bootable type */
+       int             asstype;                /* disassembler code */
+       Mach            *mach;                  /* machine description */
+       Machdata        *machdata;              /* machine functions */
+};
+
+/*
+extern Mach            mmips, msparc, m68020, mi386, mamd64,
+                       marm, mmips2be, mmips2le, mpower, mpower64, malpha, msparc64;
+extern Machdata        mipsmach, sparcmach, m68020mach, i386mach,
+                       armmach, mipsmach2le, powermach, alphamach, sparc64mach;
+*/
+extern Mach            mi386, mamd64;
+extern Machdata                i386mach;
+
+/*
+ *     machine selection table.  machines with native disassemblers should
+ *     follow the plan 9 variant in the table; native modes are selectable
+ *     only by name.
+ */
+Machtab        machines[] =
+{
+       {       "386",                          /*plan 9 386*/
+               FI386,
+               FI386B,
+               AI386,
+               &mi386,
+               &i386mach,      },
+       {       "amd64",                        /*amd64*/
+               FAMD64,
+               FAMD64B,
+               AAMD64,
+               &mamd64,
+               &i386mach,      },
+#ifdef unused
+       {       "68020",                        /*68020*/
+               F68020,
+               F68020B,
+               A68020,
+               &m68020,
+               &m68020mach,    },
+       {       "68020",                        /*Next 68040 bootable*/
+               F68020,
+               FNEXTB,
+               A68020,
+               &m68020,
+               &m68020mach,    },
+       {       "mips2LE",                      /*plan 9 mips2 little endian*/
+               FMIPS2LE,
+               0,
+               AMIPS,
+               &mmips2le,
+               &mipsmach2le,   },
+       {       "mips",                         /*plan 9 mips*/
+               FMIPS,
+               FMIPSB,
+               AMIPS,
+               &mmips,
+               &mipsmach,      },
+       {       "mips2",                        /*plan 9 mips2*/
+               FMIPS2BE,
+               FMIPSB,
+               AMIPS,
+               &mmips2be,
+               &mipsmach,      },              /* shares debuggers with native mips */
+       {       "mipsco",                       /*native mips - must follow plan 9*/
+               FMIPS,
+               FMIPSB,
+               AMIPSCO,
+               &mmips,
+               &mipsmach,      },
+       {       "sparc",                        /*plan 9 sparc */
+               FSPARC,
+               FSPARCB,
+               ASPARC,
+               &msparc,
+               &sparcmach,     },
+       {       "sunsparc",                     /*native sparc - must follow plan 9*/
+               FSPARC,
+               FSPARCB,
+               ASUNSPARC,
+               &msparc,
+               &sparcmach,     },
+       {       "86",                           /*8086 - a peach of a machine*/
+               FI386,
+               FI386B,
+               AI8086,
+               &mi386,
+               &i386mach,      },
+       {       "arm",                          /*ARM*/
+               FARM,
+               FARMB,
+               AARM,
+               &marm,
+               &armmach,       },
+       {       "power",                        /*PowerPC*/
+               FPOWER,
+               FPOWERB,
+               APOWER,
+               &mpower,
+               &powermach,     },
+       {       "power64",                      /*PowerPC*/
+               FPOWER64,
+               FPOWER64B,
+               APOWER64,
+               &mpower64,
+               &powermach,     },
+       {       "alpha",                        /*Alpha*/
+               FALPHA,
+               FALPHAB,
+               AALPHA,
+               &malpha,
+               &alphamach,     },
+       {       "sparc64",                      /*plan 9 sparc64 */
+               FSPARC64,
+               FSPARCB,                        /* XXX? */
+               ASPARC64,
+               &msparc64,
+               &sparc64mach,   },
+#endif
+       {       0               },              /*the terminator*/
+};
+
+/*
+ *     select a machine by executable file type
+ */
+void
+machbytype(int type)
+{
+       Machtab *mp;
+
+       for (mp = machines; mp->name; mp++){
+               if (mp->type == type || mp->boottype == type) {
+                       asstype = mp->asstype;
+                       machdata = mp->machdata;
+                       break;
+               }
+       }
+}
+/*
+ *     select a machine by name
+ */
+int
+machbyname(char *name)
+{
+       Machtab *mp;
+
+       if (!name) {
+               asstype = AAMD64;
+               machdata = &i386mach;
+               mach = &mamd64;
+               return 1;
+       }
+       for (mp = machines; mp->name; mp++){
+               if (strcmp(mp->name, name) == 0) {
+                       asstype = mp->asstype;
+                       machdata = mp->machdata;
+                       mach = mp->mach;
+                       return 1;
+               }
+       }
+       return 0;
+}
diff --git a/src/libmachamd64/swap.c b/src/libmachamd64/swap.c
new file mode 100644 (file)
index 0000000..77cdac8
--- /dev/null
@@ -0,0 +1,107 @@
+// Inferno libmach/swap.c
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/swap.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.
+//     Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+//     Portions Copyright © 1997-1999 Vita Nuova Limited.
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+//     Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <u.h>
+
+/*
+ * big-endian short
+ */
+ushort
+beswab(ushort s)
+{
+       uchar *p;
+
+       p = (uchar*)&s;
+       return (p[0]<<8) | p[1];
+}
+
+/*
+ * big-endian long
+ */
+ulong
+beswal(ulong l)
+{
+       uchar *p;
+
+       p = (uchar*)&l;
+       return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
+}
+
+/*
+ * big-endian vlong
+ */
+uvlong
+beswav(uvlong v)
+{
+       uchar *p;
+
+       p = (uchar*)&v;
+       return ((uvlong)p[0]<<56) | ((uvlong)p[1]<<48) | ((uvlong)p[2]<<40)
+                                 | ((uvlong)p[3]<<32) | ((uvlong)p[4]<<24)
+                                 | ((uvlong)p[5]<<16) | ((uvlong)p[6]<<8)
+                                 | (uvlong)p[7];
+}
+
+/*
+ * little-endian short
+ */
+ushort
+leswab(ushort s)
+{
+       uchar *p;
+
+       p = (uchar*)&s;
+       return (p[1]<<8) | p[0];
+}
+
+/*
+ * little-endian long
+ */
+ulong
+leswal(ulong l)
+{
+       uchar *p;
+
+       p = (uchar*)&l;
+       return (p[3]<<24) | (p[2]<<16) | (p[1]<<8) | p[0];
+}
+
+/*
+ * little-endian vlong
+ */
+uvlong
+leswav(uvlong v)
+{
+       uchar *p;
+
+       p = (uchar*)&v;
+       return ((uvlong)p[7]<<56) | ((uvlong)p[6]<<48) | ((uvlong)p[5]<<40)
+                                 | ((uvlong)p[4]<<32) | ((uvlong)p[3]<<24)
+                                 | ((uvlong)p[2]<<16) | ((uvlong)p[1]<<8)
+                                 | (uvlong)p[0];
+}
diff --git a/src/libmachamd64/sym.c b/src/libmachamd64/sym.c
new file mode 100644 (file)
index 0000000..22baa59
--- /dev/null
@@ -0,0 +1,1402 @@
+// Inferno libmach/sym.c
+// http://code.google.com/p/inferno-os/source/browse/utils/libmach/sym.c
+//
+//     Copyright © 1994-1999 Lucent Technologies Inc.
+//     Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
+//     Portions Copyright © 1997-1999 Vita Nuova Limited.
+//     Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
+//     Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
+//     Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach_amd64.h>
+
+#define        HUGEINT 0x7fffffff
+#define        NNAME   20              /* a relic of the past */
+
+typedef        struct txtsym Txtsym;
+typedef        struct file File;
+typedef        struct hist Hist;
+
+struct txtsym {                                /* Text Symbol table */
+       int     n;                      /* number of local vars */
+       Sym     **locals;               /* array of ptrs to autos */
+       Sym     *sym;                   /* function symbol entry */
+};
+
+struct hist {                          /* Stack of include files & #line directives */
+       char    *name;                  /* Assumes names Null terminated in file */
+       long    line;                   /* line # where it was included */
+       long    offset;                 /* line # of #line directive */
+};
+
+struct file {                          /* Per input file header to history stack */
+       uvlong  addr;                   /* address of first text sym */
+       union {
+               Txtsym  *txt;           /* first text symbol */
+               Sym     *sym;           /* only during initilization */
+       };
+       int     n;                      /* size of history stack */
+       Hist    *hist;                  /* history stack */
+};
+
+static int     debug = 0;
+
+static Sym     **autos;                /* Base of auto variables */
+static File    *files;                 /* Base of file arena */
+static int     fmaxi;                  /* largest file path index */
+static Sym     **fnames;               /* file names path component table */
+static Sym     **globals;              /* globals by addr table */
+static Hist    *hist;                  /* base of history stack */
+static int     isbuilt;                /* internal table init flag */
+static long    nauto;                  /* number of automatics */
+static long    nfiles;                 /* number of files */
+static long    nglob;                  /* number of globals */
+static long    nhist;                  /* number of history stack entries */
+static long    nsym;                   /* number of symbols */
+static int     ntxt;                   /* number of text symbols */
+static uchar   *pcline;                /* start of pc-line state table */
+static uchar   *pclineend;             /* end of pc-line table */
+static uchar   *spoff;                 /* start of pc-sp state table */
+static uchar   *spoffend;              /* end of pc-sp offset table */
+static Sym     *symbols;               /* symbol table */
+static Txtsym  *txt;                   /* Base of text symbol table */
+static uvlong  txtstart;               /* start of text segment */
+static uvlong  txtend;                 /* end of text segment */
+
+static void    cleansyms(void);
+static long    decodename(Biobuf*, Sym*);
+static short   *encfname(char*);
+static int     fline(char*, int, long, Hist*, Hist**);
+static void    fillsym(Sym*, Symbol*);
+static int     findglobal(char*, Symbol*);
+static int     findlocvar(Symbol*, char *, Symbol*);
+static int     findtext(char*, Symbol*);
+static int     hcomp(Hist*, short*);
+static int     hline(File*, short*, long*);
+static void    printhist(char*, Hist*, int);
+static int     buildtbls(void);
+static int     symcomp(const void*, const void*);
+static int     symerrmsg(int, char*);
+static int     txtcomp(const void*, const void*);
+static int     filecomp(const void*, const void*);
+
+/*
+ *     initialize the symbol tables
+ */
+int
+syminit(int fd, Fhdr *fp)
+{
+       Sym *p;
+       long i, l, size;
+       vlong vl;
+       Biobuf b;
+       int svalsz;
+
+       if(fp->symsz == 0)
+               return 0;
+       if(fp->type == FNONE)
+               return 0;
+
+       cleansyms();
+       textseg(fp->txtaddr, fp);
+               /* minimum symbol record size = 4+1+2 bytes */
+       symbols = malloc((fp->symsz/(4+1+2)+1)*sizeof(Sym));
+       if(symbols == 0) {
+               werrstr("can't malloc %ld bytes", fp->symsz);
+               return -1;
+       }
+       Binit(&b, fd, OREAD);
+       Bseek(&b, fp->symoff, 0);
+       nsym = 0;
+       size = 0;
+       for(p = symbols; size < fp->symsz; p++, nsym++) {
+               if(fp->_magic && (fp->magic & HDR_MAGIC)){
+                       svalsz = 8;
+                       if(Bread(&b, &vl, 8) != 8)
+                               return symerrmsg(8, "symbol");
+                       p->value = beswav(vl);
+               }
+               else{
+                       svalsz = 4;
+                       if(Bread(&b, &l, 4) != 4)
+                               return symerrmsg(4, "symbol");
+                       p->value = (u32int)beswal(l);
+               }
+               if(Bread(&b, &p->type, sizeof(p->type)) != sizeof(p->type))
+                       return symerrmsg(sizeof(p->value), "symbol");
+
+               i = decodename(&b, p);
+               if(i < 0)
+                       return -1;
+               size += i+svalsz+sizeof(p->type);
+
+               /* count global & auto vars, text symbols, and file names */
+               switch (p->type) {
+               case 'l':
+               case 'L':
+               case 't':
+               case 'T':
+                       ntxt++;
+                       break;
+               case 'd':
+               case 'D':
+               case 'b':
+               case 'B':
+                       nglob++;
+                       break;
+               case 'f':
+                       if(strcmp(p->name, ".frame") == 0) {
+                               p->type = 'm';
+                               nauto++;
+                       }
+                       else if(p->value > fmaxi)
+                               fmaxi = p->value;       /* highest path index */
+                       break;
+               case 'a':
+               case 'p':
+               case 'm':
+                       nauto++;
+                       break;
+               case 'z':
+                       if(p->value == 1) {             /* one extra per file */
+                               nhist++;
+                               nfiles++;
+                       }
+                       nhist++;
+                       break;
+               default:
+                       break;
+               }
+       }
+       if (debug)
+               print("NG: %ld NT: %d NF: %d\n", nglob, ntxt, fmaxi);
+       if (fp->sppcsz) {                       /* pc-sp offset table */
+               spoff = (uchar *)malloc(fp->sppcsz);
+               if(spoff == 0) {
+                       werrstr("can't malloc %ld bytes", fp->sppcsz);
+                       return -1;
+               }
+               Bseek(&b, fp->sppcoff, 0);
+               if(Bread(&b, spoff, fp->sppcsz) != fp->sppcsz){
+                       spoff = 0;
+                       return symerrmsg(fp->sppcsz, "sp-pc");
+               }
+               spoffend = spoff+fp->sppcsz;
+       }
+       if (fp->lnpcsz) {                       /* pc-line number table */
+               pcline = (uchar *)malloc(fp->lnpcsz);
+               if(pcline == 0) {
+                       werrstr("can't malloc %ld bytes", fp->lnpcsz);
+                       return -1;
+               }
+               Bseek(&b, fp->lnpcoff, 0);
+               if(Bread(&b, pcline, fp->lnpcsz) != fp->lnpcsz){
+                       pcline = 0;
+                       return symerrmsg(fp->lnpcsz, "pc-line");
+               }
+               pclineend = pcline+fp->lnpcsz;
+       }
+       return nsym;
+}
+
+static int
+symerrmsg(int n, char *table)
+{
+       werrstr("can't read %d bytes of %s table", n, table);
+       return -1;
+}
+
+static long
+decodename(Biobuf *bp, Sym *p)
+{
+       char *cp;
+       int c1, c2;
+       long n;
+       vlong o;
+
+       if((p->type & 0x80) == 0) {             /* old-style, fixed length names */
+               p->name = malloc(NNAME);
+               if(p->name == 0) {
+                       werrstr("can't malloc %d bytes", NNAME);
+                       return -1;
+               }
+               if(Bread(bp, p->name, NNAME) != NNAME)
+                       return symerrmsg(NNAME, "symbol");
+               Bseek(bp, 3, 1);
+               return NNAME+3;
+       }
+
+       p->type &= ~0x80;
+       if(p->type == 'z' || p->type == 'Z') {
+               o = Bseek(bp, 0, 1);
+               if(Bgetc(bp) < 0) {
+                       werrstr("can't read symbol name");
+                       return -1;
+               }
+               for(;;) {
+                       c1 = Bgetc(bp);
+                       c2 = Bgetc(bp);
+                       if(c1 < 0 || c2 < 0) {
+                               werrstr("can't read symbol name");
+                               return -1;
+                       }
+                       if(c1 == 0 && c2 == 0)
+                               break;
+               }
+               n = Bseek(bp, 0, 1)-o;
+               p->name = malloc(n);
+               if(p->name == 0) {
+                       werrstr("can't malloc %ld bytes", n);
+                       return -1;
+               }
+               Bseek(bp, -n, 1);
+               if(Bread(bp, p->name, n) != n) {
+                       werrstr("can't read %ld bytes of symbol name", n);
+                       return -1;
+               }
+       } else {
+               cp = Brdline(bp, '\0');
+               if(cp == 0) {
+                       werrstr("can't read symbol name");
+                       return -1;
+               }
+               n = Blinelen(bp);
+               p->name = malloc(n);
+               if(p->name == 0) {
+                       werrstr("can't malloc %ld bytes", n);
+                       return -1;
+               }
+               strcpy(p->name, cp);
+       }
+       return n;
+}
+
+/*
+ *     free any previously loaded symbol tables
+ */
+static void
+cleansyms(void)
+{
+       if(globals)
+               free(globals);
+       globals = 0;
+       nglob = 0;
+       if(txt)
+               free(txt);
+       txt = 0;
+       ntxt = 0;
+       if(fnames)
+               free(fnames);
+       fnames = 0;
+       fmaxi = 0;
+
+       if(files)
+               free(files);
+       files = 0;
+       nfiles = 0;
+       if(hist)
+               free(hist);
+       hist = 0;
+       nhist = 0;
+       if(autos)
+               free(autos);
+       autos = 0;
+       nauto = 0;
+       isbuilt = 0;
+       if(symbols)
+               free(symbols);
+       symbols = 0;
+       nsym = 0;
+       if(spoff)
+               free(spoff);
+       spoff = 0;
+       if(pcline)
+               free(pcline);
+       pcline = 0;
+}
+
+/*
+ *     delimit the text segment
+ */
+void
+textseg(uvlong base, Fhdr *fp)
+{
+       txtstart = base;
+       txtend = base+fp->txtsz;
+}
+
+/*
+ *     symbase: return base and size of raw symbol table
+ *             (special hack for high access rate operations)
+ */
+Sym *
+symbase(long *n)
+{
+       *n = nsym;
+       return symbols;
+}
+
+/*
+ *     Get the ith symbol table entry
+ */
+Sym *
+getsym(int index)
+{
+       if(index >= 0 && index < nsym)
+               return &symbols[index];
+       return 0;
+}
+
+/*
+ *     initialize internal symbol tables
+ */
+static int
+buildtbls(void)
+{
+       long i;
+       int j, nh, ng, nt;
+       File *f;
+       Txtsym *tp;
+       Hist *hp;
+       Sym *p, **ap;
+
+       if(isbuilt)
+               return 1;
+       isbuilt = 1;
+                       /* allocate the tables */
+       if(nglob) {
+               globals = malloc(nglob*sizeof(*globals));
+               if(!globals) {
+                       werrstr("can't malloc global symbol table");
+                       return 0;
+               }
+       }
+       if(ntxt) {
+               txt = malloc(ntxt*sizeof(*txt));
+               if (!txt) {
+                       werrstr("can't malloc text symbol table");
+                       return 0;
+               }
+       }
+       fnames = malloc((fmaxi+1)*sizeof(*fnames));
+       if (!fnames) {
+               werrstr("can't malloc file name table");
+               return 0;
+       }
+       memset(fnames, 0, (fmaxi+1)*sizeof(*fnames));
+       files = malloc(nfiles*sizeof(*files));
+       if(!files) {
+               werrstr("can't malloc file table");
+               return 0;
+       }
+       hist = malloc(nhist*sizeof(Hist));
+       if(hist == 0) {
+               werrstr("can't malloc history stack");
+               return 0;
+       }
+       autos = malloc(nauto*sizeof(Sym*));
+       if(autos == 0) {
+               werrstr("can't malloc auto symbol table");
+               return 0;
+       }
+               /* load the tables */
+       ng = nt = nh = 0;
+       f = 0;
+       tp = 0;
+       i = nsym;
+       hp = hist;
+       ap = autos;
+       for(p = symbols; i-- > 0; p++) {
+               switch(p->type) {
+               case 'D':
+               case 'd':
+               case 'B':
+               case 'b':
+                       if(debug)
+                               print("Global: %s %llux\n", p->name, p->value);
+                       globals[ng++] = p;
+                       break;
+               case 'z':
+                       if(p->value == 1) {             /* New file */
+                               if(f) {
+                                       f->n = nh;
+                                       f->hist[nh].name = 0;   /* one extra */
+                                       hp += nh+1;
+                                       f++;
+                               }
+                               else
+                                       f = files;
+                               f->hist = hp;
+                               f->sym = 0;
+                               f->addr = 0;
+                               nh = 0;
+                       }
+                               /* alloc one slot extra as terminator */
+                       f->hist[nh].name = p->name;
+                       f->hist[nh].line = p->value;
+                       f->hist[nh].offset = 0;
+                       if(debug)
+                               printhist("-> ", &f->hist[nh], 1);
+                       nh++;
+                       break;
+               case 'Z':
+                       if(f && nh > 0)
+                               f->hist[nh-1].offset = p->value;
+                       break;
+               case 'T':
+               case 't':       /* Text: terminate history if first in file */
+               case 'L':
+               case 'l':
+                       tp = &txt[nt++];
+                       tp->n = 0;
+                       tp->sym = p;
+                       tp->locals = ap;
+                       if(debug)
+                               print("TEXT: %s at %llux\n", p->name, p->value);
+                       if(f && !f->sym) {                      /* first  */
+                               f->sym = p;
+                               f->addr = p->value;
+                       }
+                       break;
+               case 'a':
+               case 'p':
+               case 'm':               /* Local Vars */
+                       if(!tp)
+                               print("Warning: Free floating local var: %s\n",
+                                       p->name);
+                       else {
+                               if(debug)
+                                       print("Local: %s %llux\n", p->name, p->value);
+                               tp->locals[tp->n] = p;
+                               tp->n++;
+                               ap++;
+                       }
+                       break;
+               case 'f':               /* File names */
+                       if(debug)
+                               print("Fname: %s\n", p->name);
+                       fnames[p->value] = p;
+                       break;
+               default:
+                       break;
+               }
+       }
+               /* sort global and text tables into ascending address order */
+       qsort(globals, nglob, sizeof(Sym*), symcomp);
+       qsort(txt, ntxt, sizeof(Txtsym), txtcomp);
+       qsort(files, nfiles, sizeof(File), filecomp);
+       tp = txt;
+       for(i = 0, f = files; i < nfiles; i++, f++) {
+               for(j = 0; j < ntxt; j++) {
+                       if(f->sym == tp->sym) {
+                               if(debug) {
+                                       print("LINK: %s to at %llux", f->sym->name, f->addr);
+                                       printhist("... ", f->hist, 1);
+                               }
+                               f->txt = tp++;
+                               break;
+                       }
+                       if(++tp >= txt+ntxt)    /* wrap around */
+                               tp = txt;
+               }
+       }
+       return 1;
+}
+
+/*
+ * find symbol function.var by name.
+ *     fn != 0 && var != 0     => look for fn in text, var in data
+ *     fn != 0 && var == 0     => look for fn in text
+ *     fn == 0 && var != 0     => look for var first in text then in data space.
+ */
+int
+lookup(char *fn, char *var, Symbol *s)
+{
+       int found;
+
+       if(buildtbls() == 0)
+               return 0;
+       if(fn) {
+               found = findtext(fn, s);
+               if(var == 0)            /* case 2: fn not in text */
+                       return found;
+               else if(!found)         /* case 1: fn not found */
+                       return 0;
+       } else if(var) {
+               found = findtext(var, s);
+               if(found)
+                       return 1;       /* case 3: var found in text */
+       } else return 0;                /* case 4: fn & var == zero */
+
+       if(found)
+               return findlocal(s, var, s);    /* case 1: fn found */
+       return findglobal(var, s);              /* case 3: var not found */
+
+}
+
+/*
+ * find a function by name
+ */
+static int
+findtext(char *name, Symbol *s)
+{
+       int i;
+
+       for(i = 0; i < ntxt; i++) {
+               if(strcmp(txt[i].sym->name, name) == 0) {
+                       fillsym(txt[i].sym, s);
+                       s->handle = (void *) &txt[i];
+                       s->index = i;
+                       return 1;
+               }
+       }
+       return 0;
+}
+/*
+ * find global variable by name
+ */
+static int
+findglobal(char *name, Symbol *s)
+{
+       long i;
+
+       for(i = 0; i < nglob; i++) {
+               if(strcmp(globals[i]->name, name) == 0) {
+                       fillsym(globals[i], s);
+                       s->index = i;
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+/*
+ *     find the local variable by name within a given function
+ */
+int
+findlocal(Symbol *s1, char *name, Symbol *s2)
+{
+       if(s1 == 0)
+               return 0;
+       if(buildtbls() == 0)
+               return 0;
+       return findlocvar(s1, name, s2);
+}
+
+/*
+ *     find the local variable by name within a given function
+ *             (internal function - does no parameter validation)
+ */
+static int
+findlocvar(Symbol *s1, char *name, Symbol *s2)
+{
+       Txtsym *tp;
+       int i;
+
+       tp = (Txtsym *)s1->handle;
+       if(tp && tp->locals) {
+               for(i = 0; i < tp->n; i++)
+                       if (strcmp(tp->locals[i]->name, name) == 0) {
+                               fillsym(tp->locals[i], s2);
+                               s2->handle = (void *)tp;
+                               s2->index = tp->n-1 - i;
+                               return 1;
+                       }
+       }
+       return 0;
+}
+
+/*
+ *     Get ith text symbol
+ */
+int
+textsym(Symbol *s, int index)
+{
+
+       if(buildtbls() == 0)
+               return 0;
+       if(index < 0 || index >= ntxt)
+               return 0;
+       fillsym(txt[index].sym, s);
+       s->handle = (void *)&txt[index];
+       s->index = index;
+       return 1;
+}
+
+/*     
+ *     Get ith file name
+ */
+int
+filesym(int index, char *buf, int n)
+{
+       Hist *hp;
+
+       if(buildtbls() == 0)
+               return 0;
+       if(index < 0 || index >= nfiles)
+               return 0;
+       hp = files[index].hist;
+       if(!hp || !hp->name)
+               return 0;
+       return fileelem(fnames, (uchar*)hp->name, buf, n);
+}
+
+/*
+ *     Lookup name of local variable located at an offset into the frame.
+ *     The type selects either a parameter or automatic.
+ */
+int
+getauto(Symbol *s1, int off, int type, Symbol *s2)
+{
+       Txtsym *tp;
+       Sym *p;
+       int i, t;
+
+       if(s1 == 0)
+               return 0;
+       if(type == CPARAM)
+               t = 'p';
+       else if(type == CAUTO)
+               t = 'a';
+       else
+               return 0;
+       if(buildtbls() == 0)
+               return 0;
+       tp = (Txtsym *)s1->handle;
+       if(tp == 0)
+               return 0;
+       for(i = 0; i < tp->n; i++) {
+               p = tp->locals[i];
+               if(p->type == t && p->value == off) {
+                       fillsym(p, s2);
+                       s2->handle = s1->handle;
+                       s2->index = tp->n-1 - i;
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+/*
+ * Find text symbol containing addr; binary search assumes text array is sorted by addr
+ */
+static int
+srchtext(uvlong addr)
+{
+       uvlong val;
+       int top, bot, mid;
+       Sym *sp;
+
+       val = addr;
+       bot = 0;
+       top = ntxt;
+       for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
+               sp = txt[mid].sym;
+               if(val < sp->value)
+                       top = mid;
+               else if(mid != ntxt-1 && val >= txt[mid+1].sym->value)
+                       bot = mid;
+               else
+                       return mid;
+       }
+       return -1;
+}
+
+/*
+ * Find data symbol containing addr; binary search assumes data array is sorted by addr
+ */
+static int
+srchdata(uvlong addr)
+{
+       uvlong val;
+       int top, bot, mid;
+       Sym *sp;
+
+       bot = 0;
+       top = nglob;
+       val = addr;
+       for(mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
+               sp = globals[mid];
+               if(val < sp->value)
+                       top = mid;
+               else if(mid < nglob-1 && val >= globals[mid+1]->value)
+                       bot = mid;
+               else
+                       return mid;
+       }
+       return -1;
+}
+
+/*
+ * Find symbol containing val in specified search space
+ * There is a special case when a value falls beyond the end
+ * of the text segment; if the search space is CTEXT, that value
+ * (usually etext) is returned.  If the search space is CANY, symbols in the
+ * data space are searched for a match.
+ */
+int
+findsym(uvlong val, int type, Symbol *s)
+{
+       int i;
+
+       if(buildtbls() == 0)
+               return 0;
+
+       if(type == CTEXT || type == CANY) {
+               i = srchtext(val);
+               if(i >= 0) {
+                       if(type == CTEXT || i != ntxt-1) {
+                               fillsym(txt[i].sym, s);
+                               s->handle = (void *) &txt[i];
+                               s->index = i;
+                               return 1;
+                       }
+               }
+       }
+       if(type == CDATA || type == CANY) {
+               i = srchdata(val);
+               if(i >= 0) {
+                       fillsym(globals[i], s);
+                       s->index = i;
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+/*
+ *     Find the start and end address of the function containing addr
+ */
+int
+fnbound(uvlong addr, uvlong *bounds)
+{
+       int i;
+
+       if(buildtbls() == 0)
+               return 0;
+
+       i = srchtext(addr);
+       if(0 <= i && i < ntxt-1) {
+               bounds[0] = txt[i].sym->value;
+               bounds[1] = txt[i+1].sym->value;
+               return 1;
+       }
+       return 0;
+}
+
+/*
+ * get the ith local symbol for a function
+ * the input symbol table is reverse ordered, so we reverse
+ * accesses here to maintain approx. parameter ordering in a stack trace.
+ */
+int
+localsym(Symbol *s, int index)
+{
+       Txtsym *tp;
+
+       if(s == 0 || index < 0)
+               return 0;
+       if(buildtbls() == 0)
+               return 0;
+
+       tp = (Txtsym *)s->handle;
+       if(tp && tp->locals && index < tp->n) {
+               fillsym(tp->locals[tp->n-index-1], s);  /* reverse */
+               s->handle = (void *)tp;
+               s->index = index;
+               return 1;
+       }
+       return 0;
+}
+
+/*
+ * get the ith global symbol
+ */
+int
+globalsym(Symbol *s, int index)
+{
+       if(s == 0)
+               return 0;
+       if(buildtbls() == 0)
+               return 0;
+
+       if(index >=0 && index < nglob) {
+               fillsym(globals[index], s);
+               s->index = index;
+               return 1;
+       }
+       return 0;
+}
+
+/*
+ *     find the pc given a file name and line offset into it.
+ */
+uvlong
+file2pc(char *file, long line)
+{
+       File *fp;
+       long i;
+       uvlong pc, start, end;
+       short *name;
+
+       if(buildtbls() == 0 || files == 0)
+               return ~0;
+       name = encfname(file);
+       if(name == 0) {                 /* encode the file name */
+               werrstr("file %s not found", file);
+               return ~0;
+       } 
+               /* find this history stack */
+       for(i = 0, fp = files; i < nfiles; i++, fp++)
+               if (hline(fp, name, &line))
+                       break;
+       free(name);
+       if(i >= nfiles) {
+               werrstr("line %ld in file %s not found", line, file);
+               return ~0;
+       }
+       start = fp->addr;               /* first text addr this file */
+       if(i < nfiles-1)
+               end = (fp+1)->addr;     /* first text addr next file */
+       else
+               end = 0;                /* last file in load module */
+       /*
+        * At this point, line contains the offset into the file.
+        * run the state machine to locate the pc closest to that value.
+        */
+       if(debug)
+               print("find pc for %ld - between: %llux and %llux\n", line, start, end);
+       pc = line2addr(line, start, end);
+       if(pc == ~0) {
+               werrstr("line %ld not in file %s", line, file);
+               return ~0;
+       }
+       return pc;
+}
+
+/*
+ *     search for a path component index
+ */
+static int
+pathcomp(char *s, int n)
+{
+       int i;
+
+       for(i = 0; i <= fmaxi; i++)
+               if(fnames[i] && strncmp(s, fnames[i]->name, n) == 0)
+                       return i;
+       return -1;
+}
+
+/*
+ *     Encode a char file name as a sequence of short indices
+ *     into the file name dictionary.
+ */
+static short*
+encfname(char *file)
+{
+       int i, j;
+       char *cp, *cp2;
+       short *dest;
+
+       if(*file == '/')        /* always check first '/' */
+               cp2 = file+1;
+       else {
+               cp2 = strchr(file, '/');
+               if(!cp2)
+                       cp2 = strchr(file, 0);
+       }
+       cp = file;
+       dest = 0;
+       for(i = 0; *cp; i++) {
+               j = pathcomp(cp, cp2-cp);
+               if(j < 0)
+                       return 0;       /* not found */
+               dest = realloc(dest, (i+1)*sizeof(short));
+               dest[i] = j;
+               cp = cp2;
+               while(*cp == '/')       /* skip embedded '/'s */
+                       cp++;
+               cp2 = strchr(cp, '/');
+               if(!cp2)
+                       cp2 = strchr(cp, 0);
+       }
+       dest = realloc(dest, (i+1)*sizeof(short));
+       dest[i] = 0;
+       return dest;
+}
+
+/*
+ *     Search a history stack for a matching file name accumulating
+ *     the size of intervening files in the stack.
+ */
+static int
+hline(File *fp, short *name, long *line)
+{
+       Hist *hp;
+       int offset, depth;
+       long ln;
+
+       for(hp = fp->hist; hp->name; hp++)              /* find name in stack */
+               if(hp->name[1] || hp->name[2]) {
+                       if(hcomp(hp, name))
+                               break;
+               }
+       if(!hp->name)           /* match not found */
+               return 0;
+       if(debug)
+               printhist("hline found ... ", hp, 1);
+       /*
+        * unwind the stack until empty or we hit an entry beyond our line
+        */
+       ln = *line;
+       offset = hp->line-1;
+       depth = 1;
+       for(hp++; depth && hp->name; hp++) {
+               if(debug)
+                       printhist("hline inspect ... ", hp, 1);
+               if(hp->name[1] || hp->name[2]) {
+                       if(hp->offset){                 /* Z record */
+                               offset = 0;
+                               if(hcomp(hp, name)) {
+                                       if(*line <= hp->offset)
+                                               break;
+                                       ln = *line+hp->line-hp->offset;
+                                       depth = 1;      /* implicit pop */
+                               } else
+                                       depth = 2;      /* implicit push */
+                       } else if(depth == 1 && ln < hp->line-offset)
+                                       break;          /* Beyond our line */
+                       else if(depth++ == 1)           /* push */
+                               offset -= hp->line;
+               } else if(--depth == 1)         /* pop */
+                       offset += hp->line;     
+       }
+       *line = ln+offset;
+       return 1;
+}
+
+/*
+ *     compare two encoded file names
+ */
+static int
+hcomp(Hist *hp, short *sp)
+{
+       uchar *cp;
+       int i, j;
+       short *s;
+
+       cp = (uchar *)hp->name;
+       s = sp;
+       if (*s == 0)
+               return 0;
+       for (i = 1; j = (cp[i]<<8)|cp[i+1]; i += 2) {
+               if(j == 0)
+                       break;
+               if(*s == j)
+                       s++;
+               else
+                       s = sp;
+       }
+       return *s == 0;
+}
+
+/*
+ *     Convert a pc to a "file:line {file:line}" string.
+ */
+long
+fileline(char *str, int n, uvlong dot)
+{
+       long line, top, bot, mid;
+       File *f;
+
+       *str = 0;
+       if(buildtbls() == 0)
+               return 0;
+               /* binary search assumes file list is sorted by addr */
+       bot = 0;
+       top = nfiles;
+       for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
+               f = &files[mid];
+               if(dot < f->addr)
+                       top = mid;
+               else if(mid < nfiles-1 && dot >= (f+1)->addr)
+                       bot = mid;
+               else {
+                       line = pc2line(dot);
+                       if(line > 0 && fline(str, n, line, f->hist, 0) >= 0)
+                               return 1;
+                       break;
+               }
+       }
+       return 0;
+}
+
+/*
+ *     Convert a line number within a composite file to relative line
+ *     number in a source file.  A composite file is the source
+ *     file with included files inserted in line.
+ */
+static int
+fline(char *str, int n, long line, Hist *base, Hist **ret)
+{
+       Hist *start;                    /* start of current level */
+       Hist *h;                        /* current entry */
+       long delta;                     /* sum of size of files this level */
+       int k;
+
+       start = base;
+       h = base;
+       delta = h->line;
+       while(h && h->name && line > h->line) {
+               if(h->name[1] || h->name[2]) {
+                       if(h->offset != 0) {    /* #line Directive */
+                               delta = h->line-h->offset+1;
+                               start = h;
+                               base = h++;
+                       } else {                /* beginning of File */
+                               if(start == base)
+                                       start = h++;
+                               else {
+                                       k = fline(str, n, line, start, &h);
+                                       if(k <= 0)
+                                               return k;
+                               }
+                       }
+               } else {
+                       if(start == base && ret) {      /* end of recursion level */
+                               *ret = h;
+                               return 1;
+                       } else {                        /* end of included file */
+                               delta += h->line-start->line;
+                               h++;
+                               start = base;
+                       }
+               }
+       }
+       if(!h)
+               return -1;
+       if(start != base)
+               line = line-start->line+1;
+       else
+               line = line-delta+1;
+       if(!h->name)
+               strncpy(str, "<eof>", n);
+       else {
+               k = fileelem(fnames, (uchar*)start->name, str, n);
+               if(k+8 < n)
+                       sprint(str+k, ":%ld", line);
+       }
+/**********Remove comments for complete back-trace of include sequence
+ *     if(start != base) {
+ *             k = strlen(str);
+ *             if(k+2 < n) {
+ *                     str[k++] = ' ';
+ *                     str[k++] = '{';
+ *             }
+ *             k += fileelem(fnames, (uchar*) base->name, str+k, n-k);
+ *             if(k+10 < n)
+ *                     sprint(str+k, ":%ld}", start->line-delta);
+ *     }
+ ********************/
+       return 0;
+}
+
+/*
+ *     convert an encoded file name to a string.
+ */
+int
+fileelem(Sym **fp, uchar *cp, char *buf, int n)
+{
+       int i, j;
+       char *c, *bp, *end;
+
+       bp = buf;
+       end = buf+n-1;
+       for(i = 1; j = (cp[i]<<8)|cp[i+1]; i+=2){
+               c = fp[j]->name;
+               if(bp != buf && bp[-1] != '/' && bp < end)
+                       *bp++ = '/';
+               while(bp < end && *c)
+                       *bp++ = *c++;
+       }
+       *bp = 0;
+       i =  bp-buf;
+       if(i > 1) {
+               cleanname(buf);
+               i = strlen(buf);
+       }
+       return i;
+}
+
+/*
+ *     compare the values of two symbol table entries.
+ */
+static int
+symcomp(const void *a, const void *b)
+{
+       int i;
+
+       i = (*(Sym**)a)->value - (*(Sym**)b)->value;
+       if (i)
+               return i;
+       return strcmp((*(Sym**)a)->name, (*(Sym**)b)->name);
+}
+
+/*
+ *     compare the values of the symbols referenced by two text table entries
+ */
+static int
+txtcomp(const void *a, const void *b)
+{
+       return ((Txtsym*)a)->sym->value - ((Txtsym*)b)->sym->value;
+}
+
+/*
+ *     compare the values of the symbols referenced by two file table entries
+ */
+static int
+filecomp(const void *a, const void *b)
+{
+       return ((File*)a)->addr - ((File*)b)->addr;
+}
+
+/*
+ *     fill an interface Symbol structure from a symbol table entry
+ */
+static void
+fillsym(Sym *sp, Symbol *s)
+{
+       s->type = sp->type;
+       s->value = sp->value;
+       s->name = sp->name;
+       s->index = 0;
+       switch(sp->type) {
+       case 'b':
+       case 'B':
+       case 'D':
+       case 'd':
+               s->class = CDATA;
+               break;
+       case 't':
+       case 'T':
+       case 'l':
+       case 'L':
+               s->class = CTEXT;
+               break;
+       case 'a':
+               s->class = CAUTO;
+               break;
+       case 'p':
+               s->class = CPARAM;
+               break;
+       case 'm':
+               s->class = CSTAB;
+               break;
+       default:
+               s->class = CNONE;
+               break;
+       }
+       s->handle = 0;
+}
+
+/*
+ *     find the stack frame, given the pc
+ */
+uvlong
+pc2sp(uvlong pc)
+{
+       uchar *c, u;
+       uvlong currpc, currsp;
+
+       if(spoff == 0)
+               return ~0;
+       currsp = 0;
+       currpc = txtstart - mach->pcquant;
+
+       if(pc<currpc || pc>txtend)
+               return ~0;
+       for(c = spoff; c < spoffend; c++) {
+               if (currpc >= pc)
+                       return currsp;
+               u = *c;
+               if (u == 0) {
+                       currsp += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
+                       c += 4;
+               }
+               else if (u < 65)
+                       currsp += 4*u;
+               else if (u < 129)
+                       currsp -= 4*(u-64);
+               else 
+                       currpc += mach->pcquant*(u-129);
+               currpc += mach->pcquant;
+       }
+       return ~0;
+}
+
+/*
+ *     find the source file line number for a given value of the pc
+ */
+long
+pc2line(uvlong pc)
+{
+       uchar *c, u;
+       uvlong currpc;
+       long currline;
+
+       if(pcline == 0)
+               return -1;
+       currline = 0;
+       currpc = txtstart-mach->pcquant;
+       if(pc<currpc || pc>txtend)
+               return ~0;
+
+       for(c = pcline; c < pclineend; c++) {
+               if(currpc >= pc)
+                       return currline;
+               u = *c;
+               if(u == 0) {
+                       currline += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
+                       c += 4;
+               }
+               else if(u < 65)
+                       currline += u;
+               else if(u < 129)
+                       currline -= (u-64);
+               else 
+                       currpc += mach->pcquant*(u-129);
+               currpc += mach->pcquant;
+       }
+       return ~0;
+}
+
+/*
+ *     find the pc associated with a line number
+ *     basepc and endpc are text addresses bounding the search.
+ *     if endpc == 0, the end of the table is used (i.e., no upper bound).
+ *     usually, basepc and endpc contain the first text address in
+ *     a file and the first text address in the following file, respectively.
+ */
+uvlong
+line2addr(long line, uvlong basepc, uvlong endpc)
+{
+       uchar *c,  u;
+       uvlong currpc, pc;
+       long currline;
+       long delta, d;
+       int found;
+
+       if(pcline == 0 || line == 0)
+               return ~0;
+
+       currline = 0;
+       currpc = txtstart-mach->pcquant;
+       pc = ~0;
+       found = 0;
+       delta = HUGEINT;
+
+       for(c = pcline; c < pclineend; c++) {
+               if(endpc && currpc >= endpc)    /* end of file of interest */
+                       break;
+               if(currpc >= basepc) {          /* proper file */
+                       if(currline >= line) {
+                               d = currline-line;
+                               found = 1;
+                       } else
+                               d = line-currline;
+                       if(d < delta) {
+                               delta = d;
+                               pc = currpc;
+                       }
+               }
+               u = *c;
+               if(u == 0) {
+                       currline += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
+                       c += 4;
+               }
+               else if(u < 65)
+                       currline += u;
+               else if(u < 129)
+                       currline -= (u-64);
+               else 
+                       currpc += mach->pcquant*(u-129);
+               currpc += mach->pcquant;
+       }
+       if(found)
+               return pc;
+       return ~0;
+}
+
+/*
+ *     Print a history stack (debug). if count is 0, prints the whole stack
+ */
+static void
+printhist(char *msg, Hist *hp, int count)
+{
+       int i;
+       uchar *cp;
+       char buf[128];
+
+       i = 0;
+       while(hp->name) {
+               if(count && ++i > count)
+                       break;
+               print("%s Line: %lx (%ld)  Offset: %lx (%ld)  Name: ", msg,
+                       hp->line, hp->line, hp->offset, hp->offset);
+               for(cp = (uchar *)hp->name+1; (*cp<<8)|cp[1]; cp += 2) {
+                       if (cp != (uchar *)hp->name+1)
+                               print("/");
+                       print("%x", (*cp<<8)|cp[1]);
+               }
+               fileelem(fnames, (uchar *) hp->name, buf, sizeof(buf));
+               print(" (%s)\n", buf);
+               hp++;
+       }
+}
+
+#ifdef DEBUG
+/*
+ *     print the history stack for a file. (debug only)
+ *     if (name == 0) => print all history stacks.
+ */
+void
+dumphist(char *name)
+{
+       int i;
+       File *f;
+       short *fname;
+
+       if(buildtbls() == 0)
+               return;
+       if(name)
+               fname = encfname(name);
+       for(i = 0, f = files; i < nfiles; i++, f++)
+               if(fname == 0 || hcomp(f->hist, fname))
+                       printhist("> ", f->hist, f->n);
+
+       if(fname)
+               free(fname);
+}
+#endif
index e81a2a4e5fb6cfa3222cec7280bcaba38648388d..d9a46a0f6884304b33ad5df0a2e19114f50559ed 100755 (executable)
@@ -3,7 +3,7 @@
 # Use of this source code is governed by a BSD-style
 # license that can be found in the LICENSE file.
 
-for i in lib9 libbio
+for i in lib9 libbio libmach_amd64
 do
        cd $i
        make install