+++ /dev/null
-// 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];
- uint32 phys;
- uint32 virt;
- uint32 size;
- uint32 fptr;
- uint32 fptrreloc;
- uint32 fptrlineno;
- uint32 nrelocnlineno;
- uint32 flags;
-};
-
-/*
- * proprietary exec headers, needed to bootstrap various machines
- */
-struct mipsexec
-{
- short mmagic; /* (0x160) mips magic number */
- short nscns; /* (unused) number of sections */
- int32 timdat; /* (unused) time & date stamp */
- int32 symptr; /* offset to symbol table */
- int32 nsyms; /* size of symbol table */
- short opthdr; /* (0x38) sizeof(optional hdr) */
- short pcszs; /* flags */
- short amagic; /* see above */
- short vstamp; /* version stamp */
- int32 tsize; /* text size in bytes */
- int32 dsize; /* initialized data */
- int32 bsize; /* uninitialized data */
- int32 mentry; /* entry pt. */
- int32 text_start; /* base of text used for this file */
- int32 data_start; /* base of data used for this file */
- int32 bss_start; /* base of bss used for this file */
- int32 gprmask; /* general purpose register mask */
-union{
- int32 cprmask[4]; /* co-processor register masks */
- int32 pcsize;
-};
- int32 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 */
- uint32 stext;
- uint32 sdata;
- uint32 sbss;
- uint32 ssyms;
- uint32 sentry;
- uint32 strsize;
- uint32 sdrsize;
-};
-
-struct nextexec
-{
-/* UNUSED
- struct nexthdr{
- uint32 nmagic;
- uint32 ncputype;
- uint32 ncpusubtype;
- uint32 nfiletype;
- uint32 ncmds;
- uint32 nsizeofcmds;
- uint32 nflags;
- };
-
- struct nextcmd{
- uint32 cmd;
- uint32 cmdsize;
- uchar segname[16];
- uint32 vmaddr;
- uint32 vmsize;
- uint32 fileoff;
- uint32 filesize;
- uint32 maxprot;
- uint32 initprot;
- uint32 nsects;
- uint32 flags;
- }textc;
- struct nextsect{
- char sectname[16];
- char segname[16];
- uint32 addr;
- uint32 size;
- uint32 offset;
- uint32 align;
- uint32 reloff;
- uint32 nreloc;
- uint32 flags;
- uint32 reserved1;
- uint32 reserved2;
- }texts;
- struct nextcmd datac;
- struct nextsect datas;
- struct nextsect bsss;
- struct nextsym{
- uint32 cmd;
- uint32 cmdsize;
- uint32 symoff;
- uint32 nsyms;
- uint32 spoff;
- uint32 pcoff;
- }symc;
-*/
-};
-
-struct i386exec
-{
-/* UNUSED
- struct i386coff{
- uint32 isectmagic;
- uint32 itime;
- uint32 isyms;
- uint32 insyms;
- uint32 iflags;
- };
- struct i386hdr{
- uint32 imagic;
- uint32 itextsize;
- uint32 idatasize;
- uint32 ibsssize;
- uint32 ientry;
- uint32 itextstart;
- uint32 idatastart;
- };
- struct coffsect itexts;
- struct coffsect idatas;
- struct coffsect ibsss;
- struct coffsect icomments;
-*/
-};
+++ /dev/null
-// 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
- */
-
-typedef struct Exec Exec;
-struct Exec
-{
- int32 magic; /* magic number */
- int32 text; /* size of text segment */
- int32 data; /* size of initialized data */
- int32 bss; /* size of uninitialized data */
- int32 syms; /* size of symbol table */
- int32 entry; /* entry point */
- int32 spsz; /* size of pc/sp offset table */
- int32 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;
- vlong gotype;
- int sequence; // order in file
-};
-
-
-/*
- * 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 */
- FWINPE, /* windows PE executable */
-
- 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;
-typedef struct Seg Seg;
-
-typedef int Maprw(Map *m, Seg *s, uvlong addr, void *v, uint n, int isread);
-
-struct Seg {
- 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 */
- Maprw *rw; /* read/write fn for seg */
-};
-
-/*
- * Structure to map a segment to data
- */
-struct Map {
- int pid;
- int tid;
- int nsegs; /* number of segments */
- Seg 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 */
- int32 regsize; /* sizeof registers in bytes */
- int32 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 */
- uint32 (*swal)(uint32); /* uint32 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 */
- uint32 (*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;
- int32 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 */
- int32 txtsz; /* text size */
- int32 datsz; /* size of data seg */
- int32 bsssz; /* size of bss */
- int32 symsz; /* size of symbol table */
- int32 sppcsz; /* size of sp-pc table */
- int32 lnpcsz; /* size of line number-pc table */
-} Fhdr;
-
-extern int asstype; /* dissembler type - machdata.c */
-extern Machdata *machdata; /* jump vector - machdata.c */
-
-int beieee80ftos(char*, int, void*);
-int beieeesftos(char*, int, void*);
-int beieeedftos(char*, int, void*);
-ushort beswab(ushort);
-uint32 beswal(uint32);
-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*, int32);
-int fileelem(Sym**, uchar *, char*, int);
-int32 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, uint32*);
-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*, uint32, int);
-int ieeesftos(char*, int, uint32);
-int ieeedftos(char*, int, uint32, uint32);
-int isar(Biobuf*);
-int leieee80ftos(char*, int, void*);
-int leieeesftos(char*, int, void*);
-int leieeedftos(char*, int, void*);
-ushort leswab(ushort);
-uint32 leswal(uint32);
-uvlong leswav(uvlong);
-uvlong line2addr(int32, 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);
-int32 pc2line(uvlong);
-int put1(Map*, uvlong, uchar*, int);
-int put2(Map*, uvlong, ushort);
-int put4(Map*, uvlong, uint32);
-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*, Maprw *rw);
-Sym* symbase(int32*);
-int syminit(int, Fhdr*);
-int symoff(char*, int, uvlong, int);
-void textseg(uvlong, Fhdr*);
-int textsym(Symbol*, int);
-void unusemap(Map*, int);
-
-Map* attachproc(int pid, Fhdr *fp);
-int ctlproc(int pid, char *msg);
-void detachproc(Map *m);
-int procnotes(int pid, char ***pnotes);
-char* proctextfile(int pid);
-int procthreadpids(int pid, int *tid, int ntid);
-char* procstatus(int);
-
-Maprw fdrw;
+++ /dev/null
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "../mach.h"
+++ /dev/null
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "../ureg_amd64.h"
+++ /dev/null
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "../ureg_arm.h"
+++ /dev/null
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "../ureg_x86.h"
+++ /dev/null
-// 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.
-
-typedef struct UregAmd64 UregAmd64;
-struct UregAmd64 {
- 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 */
-};
+++ /dev/null
-// Inferno utils/libmach/ureg5.h
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/ureg5.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.
-
-typedef struct UregArm UregArm;
-struct UregArm {
- uint r0;
- uint r1;
- uint r2;
- uint r3;
- uint r4;
- uint r5;
- uint r6;
- uint r7;
- uint r8;
- uint r9;
- uint r10;
- uint r11;
- uint r12;
- uint r13;
- uint r14;
- uint link;
- uint type;
- uint psr;
- uint pc;
-};
+++ /dev/null
-// 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.
-
-typedef struct Ureg386 Ureg386;
-struct Ureg386
-{
- uint32 di; /* general registers */
- uint32 si; /* ... */
- uint32 bp; /* ... */
- uint32 nsp;
- uint32 bx; /* ... */
- uint32 dx; /* ... */
- uint32 cx; /* ... */
- uint32 ax; /* ... */
- uint32 gs; /* data segments */
- uint32 fs; /* ... */
- uint32 es; /* ... */
- uint32 ds; /* ... */
- uint32 trap; /* trap type */
- uint32 ecode; /* error code (or zero) */
- uint32 pc; /* pc */
- uint32 cs; /* old context */
- uint32 flags; /* old flags */
- union {
- uint32 usp;
- uint32 sp;
- };
- uint32 ss; /* old stack segment */
-};
// Unreleased directories (relative to $GOROOT) that should
// not be in release branches.
static char *unreleased[] = {
- "src/cmd/prof",
"src/pkg/old",
};
"$GOROOT/include/libc.h",
"$GOROOT/include/bio.h",
}},
- {"libmach", {
- "$GOROOT/include/u.h",
- "$GOROOT/include/utf.h",
- "$GOROOT/include/fmt.h",
- "$GOROOT/include/libc.h",
- "$GOROOT/include/bio.h",
- "$GOROOT/include/ar.h",
- "$GOROOT/include/bootexec.h",
- "$GOROOT/include/mach.h",
- "$GOROOT/include/ureg_amd64.h",
- "$GOROOT/include/ureg_arm.h",
- "$GOROOT/include/ureg_x86.h",
- }},
{"liblink", {
"$GOROOT/include/u.h",
"$GOROOT/include/utf.h",
}},
{"cmd/", {
"$GOROOT/pkg/obj/$GOOS_$GOARCH/liblink.a",
- "$GOROOT/pkg/obj/$GOOS_$GOARCH/libmach.a",
"$GOROOT/pkg/obj/$GOOS_$GOARCH/libbio.a",
"$GOROOT/pkg/obj/$GOOS_$GOARCH/lib9.a",
}},
goto out;
}
- // For release, cmd/prof is not included.
- if((streq(dir, "cmd/prof")) && !isdir(bstr(&path))) {
- if(vflag > 1)
- errprintf("skipping %s - does not exist\n", dir);
- goto out;
- }
-
// set up gcc command line on first run.
if(gccargs.len == 0) {
bprintf(&b, "%s %s", defaultcc, defaultcflags);
static char *buildorder[] = {
"lib9",
"libbio",
- "libmach",
"liblink",
"misc/pprof",
- "cmd/prof",
-
"cmd/cc", // must be before c
"cmd/gc", // must be before g
"cmd/%sl", // must be before a, c, g
"cmd/cc",
"cmd/gc",
"cmd/go",
- "cmd/prof",
"lib9",
"libbio",
- "libmach",
"liblink",
"pkg/bufio",
"pkg/bytes",
vinit(&dir);
for(i=0; i<nelem(cleantab); i++) {
- if((streq(cleantab[i], "cmd/prof")) && !isdir(cleantab[i]))
- continue;
bpathf(&path, "%s/src/%s", goroot, cleantab[i]);
xreaddir(&dir, bstr(&path));
// Remove generated files.
+++ /dev/null
-# Copyright 2012 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../Make.dist
+++ /dev/null
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build ignore
-
-/*
-
-Prof is a rudimentary real-time profiler.
-
-Given a command to run or the process id (pid) of a command already
-running, it samples the program's state at regular intervals and reports
-on its behavior. With no options, it prints a histogram of the locations
-in the code that were sampled during execution.
-
-Since it is a real-time profiler, unlike a traditional profiler it samples
-the program's state even when it is not running, such as when it is
-asleep or waiting for I/O. Each thread contributes equally to the
-statistics.
-
-Usage:
- go tool prof -p pid [-t total_secs] [-d delta_msec] [6.out args ...]
-
-The output modes (default -h) are:
-
- -P file.prof:
- Write the profile information to file.prof, in the format used by pprof.
- At the moment, this only works on Linux amd64 binaries and requires that the
- binary be written using 6l -e to produce ELF debug info.
- See http://code.google.com/p/google-perftools for details.
- -h: histograms
- How many times a sample occurred at each location.
- -f: dynamic functions
- At each sample period, print the name of the executing function.
- -l: dynamic file and line numbers
- At each sample period, print the file and line number of the executing instruction.
- -r: dynamic registers
- At each sample period, print the register contents.
- -s: dynamic function stack traces
- At each sample period, print the symbolic stack trace.
-
-Flag -t sets the maximum real time to sample, in seconds, and -d
-sets the sampling interval in milliseconds. The default is to sample
-every 100ms until the program completes.
-
-It is installed as go tool prof and is architecture-independent.
-
-*/
-package main
+++ /dev/null
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !plan9
-
-#include <u.h>
-#include <time.h>
-#include <libc.h>
-#include <bio.h>
-#include <ctype.h>
-#include <ureg_amd64.h>
-#include <ureg_x86.h>
-#include <mach.h>
-
-char* file = "6.out";
-static Fhdr fhdr;
-int have_syms;
-int fd;
-struct UregAmd64 ureg_amd64;
-struct Ureg386 ureg_x86;
-int total_sec = 0;
-int delta_msec = 100;
-int nsample;
-int nsamplethread;
-
-// pprof data, stored as sequences of N followed by N PC values.
-// See http://code.google.com/p/google-perftools .
-uvlong *ppdata; // traces
-Biobuf* pproffd; // file descriptor to write trace info
-long ppstart; // start position of current trace
-long nppdata; // length of data
-long ppalloc; // size of allocated data
-char ppmapdata[10*1024]; // the map information for the output file
-
-// output formats
-int pprof; // print pprof output to named file
-int functions; // print functions
-int histograms; // print histograms
-int linenums; // print file and line numbers rather than function names
-int registers; // print registers
-int stacks; // print stack traces
-
-int pid; // main process pid
-
-int nthread; // number of threads
-int thread[32]; // thread pids
-Map *map[32]; // thread maps
-
-void
-Usage(void)
-{
- fprint(2, "Usage: prof -p pid [-t total_secs] [-d delta_msec]\n");
- fprint(2, " prof [-t total_secs] [-d delta_msec] 6.out args ...\n");
- fprint(2, "\tformats (default -h):\n");
- fprint(2, "\t\t-P file.prof: write [c]pprof output to file.prof\n");
- fprint(2, "\t\t-h: histograms\n");
- fprint(2, "\t\t-f: dynamic functions\n");
- fprint(2, "\t\t-l: dynamic file and line numbers\n");
- fprint(2, "\t\t-r: dynamic registers\n");
- fprint(2, "\t\t-s: dynamic function stack traces\n");
- fprint(2, "\t\t-hs: include stack info in histograms\n");
- exit(2);
-}
-
-typedef struct PC PC;
-struct PC {
- uvlong pc;
- uvlong callerpc;
- unsigned int count;
- PC* next;
-};
-
-enum {
- Ncounters = 256
-};
-
-PC *counters[Ncounters];
-
-// Set up by setarch() to make most of the code architecture-independent.
-typedef struct Arch Arch;
-struct Arch {
- char* name;
- void (*regprint)(void);
- int (*getregs)(Map*);
- int (*getPC)(Map*);
- int (*getSP)(Map*);
- uvlong (*uregPC)(void);
- uvlong (*uregSP)(void);
- void (*ppword)(uvlong w);
-};
-
-void
-amd64_regprint(void)
-{
- fprint(2, "ax\t0x%llux\n", ureg_amd64.ax);
- fprint(2, "bx\t0x%llux\n", ureg_amd64.bx);
- fprint(2, "cx\t0x%llux\n", ureg_amd64.cx);
- fprint(2, "dx\t0x%llux\n", ureg_amd64.dx);
- fprint(2, "si\t0x%llux\n", ureg_amd64.si);
- fprint(2, "di\t0x%llux\n", ureg_amd64.di);
- fprint(2, "bp\t0x%llux\n", ureg_amd64.bp);
- fprint(2, "r8\t0x%llux\n", ureg_amd64.r8);
- fprint(2, "r9\t0x%llux\n", ureg_amd64.r9);
- fprint(2, "r10\t0x%llux\n", ureg_amd64.r10);
- fprint(2, "r11\t0x%llux\n", ureg_amd64.r11);
- fprint(2, "r12\t0x%llux\n", ureg_amd64.r12);
- fprint(2, "r13\t0x%llux\n", ureg_amd64.r13);
- fprint(2, "r14\t0x%llux\n", ureg_amd64.r14);
- fprint(2, "r15\t0x%llux\n", ureg_amd64.r15);
- fprint(2, "ds\t0x%llux\n", ureg_amd64.ds);
- fprint(2, "es\t0x%llux\n", ureg_amd64.es);
- fprint(2, "fs\t0x%llux\n", ureg_amd64.fs);
- fprint(2, "gs\t0x%llux\n", ureg_amd64.gs);
- fprint(2, "type\t0x%llux\n", ureg_amd64.type);
- fprint(2, "error\t0x%llux\n", ureg_amd64.error);
- fprint(2, "pc\t0x%llux\n", ureg_amd64.ip);
- fprint(2, "cs\t0x%llux\n", ureg_amd64.cs);
- fprint(2, "flags\t0x%llux\n", ureg_amd64.flags);
- fprint(2, "sp\t0x%llux\n", ureg_amd64.sp);
- fprint(2, "ss\t0x%llux\n", ureg_amd64.ss);
-}
-
-int
-amd64_getregs(Map *map)
-{
- int i;
- union {
- uvlong regs[1];
- struct UregAmd64 ureg;
- } u;
-
- for(i = 0; i < sizeof ureg_amd64; i+=8) {
- if(get8(map, (uvlong)i, &u.regs[i/8]) < 0)
- return -1;
- }
- ureg_amd64 = u.ureg;
- return 0;
-}
-
-int
-amd64_getPC(Map *map)
-{
- uvlong x;
- int r;
-
- r = get8(map, offsetof(struct UregAmd64, ip), &x);
- ureg_amd64.ip = x;
- return r;
-}
-
-int
-amd64_getSP(Map *map)
-{
- uvlong x;
- int r;
-
- r = get8(map, offsetof(struct UregAmd64, sp), &x);
- ureg_amd64.sp = x;
- return r;
-}
-
-uvlong
-amd64_uregPC(void)
-{
- return ureg_amd64.ip;
-}
-
-uvlong
-amd64_uregSP(void)
-{
- return ureg_amd64.sp;
-}
-
-void
-amd64_ppword(uvlong w)
-{
- uchar buf[8];
-
- buf[0] = w;
- buf[1] = w >> 8;
- buf[2] = w >> 16;
- buf[3] = w >> 24;
- buf[4] = w >> 32;
- buf[5] = w >> 40;
- buf[6] = w >> 48;
- buf[7] = w >> 56;
- Bwrite(pproffd, buf, 8);
-}
-
-void
-x86_regprint(void)
-{
- fprint(2, "ax\t0x%ux\n", ureg_x86.ax);
- fprint(2, "bx\t0x%ux\n", ureg_x86.bx);
- fprint(2, "cx\t0x%ux\n", ureg_x86.cx);
- fprint(2, "dx\t0x%ux\n", ureg_x86.dx);
- fprint(2, "si\t0x%ux\n", ureg_x86.si);
- fprint(2, "di\t0x%ux\n", ureg_x86.di);
- fprint(2, "bp\t0x%ux\n", ureg_x86.bp);
- fprint(2, "ds\t0x%ux\n", ureg_x86.ds);
- fprint(2, "es\t0x%ux\n", ureg_x86.es);
- fprint(2, "fs\t0x%ux\n", ureg_x86.fs);
- fprint(2, "gs\t0x%ux\n", ureg_x86.gs);
- fprint(2, "cs\t0x%ux\n", ureg_x86.cs);
- fprint(2, "flags\t0x%ux\n", ureg_x86.flags);
- fprint(2, "pc\t0x%ux\n", ureg_x86.pc);
- fprint(2, "sp\t0x%ux\n", ureg_x86.sp);
- fprint(2, "ss\t0x%ux\n", ureg_x86.ss);
-}
-
-int
-x86_getregs(Map *map)
-{
- int i;
-
- for(i = 0; i < sizeof ureg_x86; i+=4) {
- if(get4(map, (uvlong)i, &((uint32*)&ureg_x86)[i/4]) < 0)
- return -1;
- }
- return 0;
-}
-
-int
-x86_getPC(Map* map)
-{
- return get4(map, offsetof(struct Ureg386, pc), &ureg_x86.pc);
-}
-
-int
-x86_getSP(Map* map)
-{
- return get4(map, offsetof(struct Ureg386, sp), &ureg_x86.sp);
-}
-
-uvlong
-x86_uregPC(void)
-{
- return (uvlong)ureg_x86.pc;
-}
-
-uvlong
-x86_uregSP(void)
-{
- return (uvlong)ureg_x86.sp;
-}
-
-void
-x86_ppword(uvlong w)
-{
- uchar buf[4];
-
- buf[0] = w;
- buf[1] = w >> 8;
- buf[2] = w >> 16;
- buf[3] = w >> 24;
- Bwrite(pproffd, buf, 4);
-}
-
-Arch archtab[] = {
- {
- "amd64",
- amd64_regprint,
- amd64_getregs,
- amd64_getPC,
- amd64_getSP,
- amd64_uregPC,
- amd64_uregSP,
- amd64_ppword,
- },
- {
- "386",
- x86_regprint,
- x86_getregs,
- x86_getPC,
- x86_getSP,
- x86_uregPC,
- x86_uregSP,
- x86_ppword,
- },
- {
- nil
- }
-};
-
-Arch *arch;
-
-int
-setarch(void)
-{
- int i;
-
- if(mach != nil) {
- for(i = 0; archtab[i].name != nil; i++) {
- if (strcmp(mach->name, archtab[i].name) == 0) {
- arch = &archtab[i];
- return 0;
- }
- }
- }
- return -1;
-}
-
-int
-getthreads(void)
-{
- int i, j, curn, found;
- Map *curmap[nelem(map)];
- int curthread[nelem(map)];
- static int complained = 0;
-
- curn = procthreadpids(pid, curthread, nelem(curthread));
- if(curn <= 0)
- return curn;
-
- if(curn > nelem(map)) {
- if(complained == 0) {
- fprint(2, "prof: too many threads; limiting to %d\n", nthread, nelem(map));
- complained = 1;
- }
- curn = nelem(map);
- }
- if(curn == nthread && memcmp(thread, curthread, curn*sizeof(*thread)) == 0)
- return curn; // no changes
-
- // Number of threads has changed (might be the init case).
- // A bit expensive but rare enough not to bother being clever.
- for(i = 0; i < curn; i++) {
- found = 0;
- for(j = 0; j < nthread; j++) {
- if(curthread[i] == thread[j]) {
- found = 1;
- curmap[i] = map[j];
- map[j] = nil;
- break;
- }
- }
- if(found)
- continue;
-
- // map new thread
- curmap[i] = attachproc(curthread[i], &fhdr);
- if(curmap[i] == nil) {
- fprint(2, "prof: can't attach to %d: %r\n", curthread[i]);
- return -1;
- }
- }
-
- for(j = 0; j < nthread; j++)
- if(map[j] != nil)
- detachproc(map[j]);
-
- nthread = curn;
- memmove(thread, curthread, nthread*sizeof thread[0]);
- memmove(map, curmap, sizeof map);
- return nthread;
-}
-
-int
-sample(Map *map)
-{
- static int n;
-
- n++;
- if(registers) {
- if(arch->getregs(map) < 0)
- goto bad;
- } else {
- // we need only two registers
- if(arch->getPC(map) < 0)
- goto bad;
- if(arch->getSP(map) < 0)
- goto bad;
- }
- return 1;
-bad:
- if(n == 1)
- fprint(2, "prof: can't read registers: %r\n");
- return 0;
-}
-
-void
-addtohistogram(uvlong pc, uvlong callerpc, uvlong sp)
-{
- int h;
- PC *x;
-
- USED(sp);
-
- h = (pc + callerpc*101) % Ncounters;
- for(x = counters[h]; x != NULL; x = x->next) {
- if(x->pc == pc && x->callerpc == callerpc) {
- x->count++;
- return;
- }
- }
- x = malloc(sizeof(PC));
- if(x == nil)
- sysfatal("out of memory");
- x->pc = pc;
- x->callerpc = callerpc;
- x->count = 1;
- x->next = counters[h];
- counters[h] = x;
-}
-
-void
-addppword(uvlong pc)
-{
- if(pc == 0) {
- return;
- }
- if(nppdata == ppalloc) {
- ppalloc = (1000+nppdata)*2;
- ppdata = realloc(ppdata, ppalloc * sizeof ppdata[0]);
- if(ppdata == nil) {
- fprint(2, "prof: realloc failed: %r\n");
- exit(2);
- }
- }
- ppdata[nppdata++] = pc;
-}
-
-void
-startpptrace(void)
-{
- ppstart = nppdata;
- addppword(~0);
-}
-
-void
-endpptrace(void)
-{
- ppdata[ppstart] = nppdata-ppstart-1;
-}
-
-uvlong nextpc;
-
-void
-xptrace(Map *map, uvlong pc, uvlong sp, Symbol *sym)
-{
- USED(map);
-
- char buf[1024];
- if(sym == nil){
- fprint(2, "syms\n");
- return;
- }
- if(histograms)
- addtohistogram(nextpc, pc, sp);
- if(!histograms || stacks > 1 || pprof) {
- if(nextpc == 0)
- nextpc = sym->value;
- if(stacks){
- fprint(2, "%s(", sym->name);
- fprint(2, ")");
- if(nextpc != sym->value)
- fprint(2, "+%#llux ", nextpc - sym->value);
- if(have_syms && linenums && fileline(buf, sizeof buf, pc)) {
- fprint(2, " %s", buf);
- }
- fprint(2, "\n");
- }
- if (pprof) {
- addppword(nextpc);
- }
- }
- nextpc = pc;
-}
-
-void
-stacktracepcsp(Map *map, uvlong pc, uvlong sp)
-{
- nextpc = pc;
- if(pprof){
- startpptrace();
- }
- if(machdata->ctrace==nil)
- fprint(2, "no machdata->ctrace\n");
- else if(machdata->ctrace(map, pc, sp, 0, xptrace) <= 0)
- fprint(2, "no stack frame: pc=%#p sp=%#p\n", pc, sp);
- else {
- addtohistogram(nextpc, 0, sp);
- if(stacks)
- fprint(2, "\n");
- }
- if(pprof){
- endpptrace();
- }
-}
-
-void
-printpc(Map *map, uvlong pc, uvlong sp)
-{
- char buf[1024];
- if(registers)
- arch->regprint();
- if(have_syms > 0 && linenums && fileline(buf, sizeof buf, pc))
- fprint(2, "%s\n", buf);
- if(have_syms > 0 && functions) {
- symoff(buf, sizeof(buf), pc, CANY);
- fprint(2, "%s\n", buf);
- }
- if(stacks || pprof){
- stacktracepcsp(map, pc, sp);
- }
- else if(histograms){
- addtohistogram(pc, 0, sp);
- }
-}
-
-void
-ppmaps(void)
-{
- int fd, n;
- char tmp[100];
- Seg *seg;
-
- // If it's Linux, the info is in /proc/$pid/maps
- snprint(tmp, sizeof tmp, "/proc/%d/maps", pid);
- fd = open(tmp, 0);
- if(fd >= 0) {
- n = read(fd, ppmapdata, sizeof ppmapdata - 1);
- close(fd);
- if(n < 0) {
- fprint(2, "prof: can't read %s: %r\n", tmp);
- exit(2);
- }
- ppmapdata[n] = 0;
- return;
- }
-
- // It's probably a mac. Synthesize an entry for the text file.
- // The register segment may come first but it has a zero offset, so grab the first non-zero offset segment.
- for(n = 0; n < 3; n++){
- seg = &map[0]->seg[n];
- if(seg->b == 0) {
- continue;
- }
- snprint(ppmapdata, sizeof ppmapdata,
- "%.16x-%.16x r-xp %d 00:00 34968549 %s\n",
- seg->b, seg->e, seg->f, "/home/r/6.out"
- );
- return;
- }
- fprint(2, "prof: no text segment in maps for %s\n", file);
- exit(2);
-}
-
-void
-samples(void)
-{
- int i, pid, msec;
- struct timespec req;
- int getmaps;
-
- req.tv_sec = delta_msec/1000;
- req.tv_nsec = 1000000*(delta_msec % 1000);
- getmaps = 0;
- if(pprof)
- getmaps= 1;
- for(msec = 0; total_sec <= 0 || msec < 1000*total_sec; msec += delta_msec) {
- nsample++;
- nsamplethread += nthread;
- for(i = 0; i < nthread; i++) {
- pid = thread[i];
- if(ctlproc(pid, "stop") < 0)
- return;
- if(!sample(map[i])) {
- ctlproc(pid, "start");
- return;
- }
- printpc(map[i], arch->uregPC(), arch->uregSP());
- ctlproc(pid, "start");
- }
- nanosleep(&req, NULL);
- getthreads();
- if(nthread == 0)
- break;
- if(getmaps) {
- getmaps = 0;
- ppmaps();
- }
- }
-}
-
-typedef struct Func Func;
-struct Func
-{
- Func *next;
- Symbol s;
- uint onstack;
- uint leaf;
-};
-
-Func *func[257];
-int nfunc;
-
-Func*
-findfunc(uvlong pc)
-{
- Func *f;
- uint h;
- Symbol s;
-
- if(pc == 0)
- return nil;
-
- if(!findsym(pc, CTEXT, &s))
- return nil;
-
- h = s.value % nelem(func);
- for(f = func[h]; f != NULL; f = f->next)
- if(f->s.value == s.value)
- return f;
-
- f = malloc(sizeof *f);
- if(f == nil)
- sysfatal("out of memory");
- memset(f, 0, sizeof *f);
- f->s = s;
- f->next = func[h];
- func[h] = f;
- nfunc++;
- return f;
-}
-
-int
-compareleaf(const void *va, const void *vb)
-{
- Func *a, *b;
-
- a = *(Func**)va;
- b = *(Func**)vb;
- if(a->leaf != b->leaf)
- return b->leaf - a->leaf;
- if(a->onstack != b->onstack)
- return b->onstack - a->onstack;
- return strcmp(a->s.name, b->s.name);
-}
-
-void
-dumphistogram(void)
-{
- int i, h, n;
- PC *x;
- Func *f, **ff;
-
- if(!histograms)
- return;
-
- // assign counts to functions.
- for(h = 0; h < Ncounters; h++) {
- for(x = counters[h]; x != NULL; x = x->next) {
- f = findfunc(x->pc);
- if(f) {
- f->onstack += x->count;
- f->leaf += x->count;
- }
- f = findfunc(x->callerpc);
- if(f)
- f->leaf -= x->count;
- }
- }
-
- // build array
- ff = malloc(nfunc*sizeof ff[0]);
- if(ff == nil)
- sysfatal("out of memory");
- n = 0;
- for(h = 0; h < nelem(func); h++)
- for(f = func[h]; f != NULL; f = f->next)
- ff[n++] = f;
-
- // sort by leaf counts
- qsort(ff, nfunc, sizeof ff[0], compareleaf);
-
- // print.
- fprint(2, "%d samples (avg %.1g threads)\n", nsample, (double)nsamplethread/nsample);
- for(i = 0; i < nfunc; i++) {
- f = ff[i];
- fprint(2, "%6.2f%%\t", 100.0*(double)f->leaf/nsample);
- if(stacks)
- fprint(2, "%6.2f%%\t", 100.0*(double)f->onstack/nsample);
- fprint(2, "%s\n", f->s.name);
- }
-}
-
-typedef struct Trace Trace;
-struct Trace {
- int count;
- int npc;
- uvlong *pc;
- Trace *next;
-};
-
-void
-dumppprof(void)
-{
- uvlong i, n, *p, *e;
- int ntrace;
- Trace *trace, *tp, *up, *prev;
-
- if(!pprof)
- return;
- e = ppdata + nppdata;
- // Create list of traces. First, count the traces
- ntrace = 0;
- for(p = ppdata; p < e;) {
- n = *p++;
- p += n;
- if(n == 0)
- continue;
- ntrace++;
- }
- if(ntrace <= 0)
- return;
- // Allocate and link the traces together.
- trace = malloc(ntrace * sizeof(Trace));
- if(trace == nil)
- sysfatal("out of memory");
- tp = trace;
- for(p = ppdata; p < e;) {
- n = *p++;
- if(n == 0)
- continue;
- tp->count = 1;
- tp->npc = n;
- tp->pc = p;
- tp->next = tp+1;
- tp++;
- p += n;
- }
- trace[ntrace-1].next = nil;
- // Eliminate duplicates. Lousy algorithm, although not as bad as it looks because
- // the list collapses fast.
- for(tp = trace; tp != nil; tp = tp->next) {
- prev = tp;
- for(up = tp->next; up != nil; up = up->next) {
- if(up->npc == tp->npc && memcmp(up->pc, tp->pc, up->npc*sizeof up->pc[0]) == 0) {
- tp->count++;
- prev->next = up->next;
- } else {
- prev = up;
- }
- }
- }
- // Write file.
- // See http://code.google.com/p/google-perftools/source/browse/trunk/doc/cpuprofile-fileformat.html
- // 1) Header
- arch->ppword(0); // must be zero
- arch->ppword(3); // 3 words follow in header
- arch->ppword(0); // must be zero
- arch->ppword(delta_msec * 1000); // sampling period in microseconds
- arch->ppword(0); // must be zero (padding)
- // 2) One record for each trace.
- for(tp = trace; tp != nil; tp = tp->next) {
- arch->ppword(tp->count);
- arch->ppword(tp->npc);
- for(i = 0; i < tp->npc; i++) {
- arch->ppword(tp->pc[i]);
- }
- }
- // 3) Binary trailer
- arch->ppword(0); // must be zero
- arch->ppword(1); // must be one
- arch->ppword(0); // must be zero
- // 4) Mapped objects.
- Bwrite(pproffd, ppmapdata, strlen(ppmapdata));
- // 5) That's it.
- Bterm(pproffd);
-}
-
-int
-startprocess(char **argv)
-{
- int pid;
-
- if((pid = fork()) == 0) {
- pid = getpid();
- if(ctlproc(pid, "hang") < 0){
- fprint(2, "prof: child process could not hang\n");
- exits(0);
- }
- execv(argv[0], argv);
- fprint(2, "prof: could not exec %s: %r\n", argv[0]);
- exits(0);
- }
-
- if(pid == -1) {
- fprint(2, "prof: could not fork\n");
- exit(1);
- }
- if(ctlproc(pid, "attached") < 0 || ctlproc(pid, "waitstop") < 0) {
- fprint(2, "prof: could not attach to child process: %r\n");
- exit(1);
- }
- return pid;
-}
-
-void
-detach(void)
-{
- int i;
-
- for(i = 0; i < nthread; i++)
- detachproc(map[i]);
-}
-
-int
-main(int argc, char *argv[])
-{
- int i;
- char *ppfile;
-
- ARGBEGIN{
- case 'P':
- pprof =1;
- ppfile = EARGF(Usage());
- pproffd = Bopen(ppfile, OWRITE);
- if(pproffd == nil) {
- fprint(2, "prof: cannot open %s: %r\n", ppfile);
- exit(2);
- }
- break;
- case 'd':
- delta_msec = atoi(EARGF(Usage()));
- break;
- case 't':
- total_sec = atoi(EARGF(Usage()));
- break;
- case 'p':
- pid = atoi(EARGF(Usage()));
- break;
- case 'f':
- functions = 1;
- break;
- case 'h':
- histograms = 1;
- break;
- case 'l':
- linenums = 1;
- break;
- case 'r':
- registers = 1;
- break;
- case 's':
- stacks++;
- break;
- default:
- Usage();
- }ARGEND
- if(pid <= 0 && argc == 0)
- Usage();
- if(functions+linenums+registers+stacks+pprof == 0)
- histograms = 1;
- if(!machbyname("amd64")) {
- fprint(2, "prof: no amd64 support\n", pid);
- exit(1);
- }
- if(argc > 0)
- file = argv[0];
- else if(pid) {
- file = proctextfile(pid);
- if (file == NULL) {
- fprint(2, "prof: can't find file for pid %d: %r\n", pid);
- fprint(2, "prof: on Darwin, need to provide file name explicitly\n");
- exit(1);
- }
- }
- fd = open(file, 0);
- if(fd < 0) {
- fprint(2, "prof: can't open %s: %r\n", file);
- exit(1);
- }
- if(crackhdr(fd, &fhdr)) {
- have_syms = syminit(fd, &fhdr);
- if(!have_syms) {
- fprint(2, "prof: no symbols for %s: %r\n", file);
- }
- } else {
- fprint(2, "prof: crack header for %s: %r\n", file);
- exit(1);
- }
- if(pid <= 0)
- pid = startprocess(argv);
- attachproc(pid, &fhdr); // initializes thread list
- if(setarch() < 0) {
- detach();
- fprint(2, "prof: can't identify binary architecture for pid %d\n", pid);
- exit(1);
- }
- if(getthreads() <= 0) {
- detach();
- fprint(2, "prof: can't find threads for pid %d\n", pid);
- exit(1);
- }
- for(i = 0; i < nthread; i++)
- ctlproc(thread[i], "start");
- samples();
- detach();
- dumphistogram();
- dumppprof();
- exit(0);
-}
+++ /dev/null
-// Inferno libmach/5.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/5.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.
-
-/*
- * arm definition
- */
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include "ureg_arm.h"
-#include <mach.h>
-
-#define REGOFF(x) (uintptr) (&((struct UregArm *) 0)->x)
-
-#define SP REGOFF(r13)
-#define PC REGOFF(pc)
-
-#define REGSIZE sizeof(struct UregArm)
-
-Reglist armreglist[] =
-{
- {"LINK", REGOFF(link), RINT|RRDONLY, 'X'},
- {"TYPE", REGOFF(type), RINT|RRDONLY, 'X'},
- {"PSR", REGOFF(psr), RINT|RRDONLY, 'X'},
- {"PC", PC, RINT, 'X'},
- {"SP", SP, RINT, 'X'},
- {"R15", PC, RINT, 'X'},
- {"R14", REGOFF(r14), RINT, 'X'},
- {"R13", REGOFF(r13), RINT, 'X'},
- {"R12", REGOFF(r12), RINT, 'X'},
- {"R11", REGOFF(r11), RINT, 'X'},
- {"R10", REGOFF(r10), RINT, 'X'},
- {"R9", REGOFF(r9), RINT, 'X'},
- {"R8", REGOFF(r8), RINT, 'X'},
- {"R7", REGOFF(r7), RINT, 'X'},
- {"R6", REGOFF(r6), RINT, 'X'},
- {"R5", REGOFF(r5), RINT, 'X'},
- {"R4", REGOFF(r4), RINT, 'X'},
- {"R3", REGOFF(r3), RINT, 'X'},
- {"R2", REGOFF(r2), RINT, 'X'},
- {"R1", REGOFF(r1), RINT, 'X'},
- {"R0", REGOFF(r0), RINT, 'X'},
- { 0 }
-};
-
- /* the machine description */
-Mach marm =
-{
- "arm",
- MARM, /* machine type */
- armreglist, /* register set */
- REGSIZE, /* register set size */
- 0, /* fp register set size */
- "PC", /* name of PC */
- "SP", /* name of SP */
- "R15", /* name of link register */
- "setR12", /* static base register name */
- 0, /* static base register value */
- 0x1000, /* page size */
- 0xC0000000, /* kernel base */
- 0, /* kernel text mask */
- 4, /* quantization of pc */
- 4, /* szaddr */
- 4, /* szreg */
- 4, /* szfloat */
- 8, /* szdouble */
-};
+++ /dev/null
-// Inferno libmach/5db.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/5db.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 "ureg_arm.h"
-#include <mach.h>
-
-static int debug = 0;
-
-#define BITS(a, b) ((1<<(b+1))-(1<<a))
-
-#define LSR(v, s) ((ulong)(v) >> (s))
-#define ASR(v, s) ((long)(v) >> (s))
-#define ROR(v, s) (LSR((v), (s)) | (((v) & ((1 << (s))-1)) << (32 - (s))))
-
-typedef struct Instr Instr;
-struct Instr
-{
- Map *map;
- ulong w;
- ulong addr;
- uchar op; /* super opcode */
-
- uchar cond; /* bits 28-31 */
- uchar store; /* bit 20 */
-
- uchar rd; /* bits 12-15 */
- uchar rn; /* bits 16-19 */
- uchar rs; /* bits 0-11 (shifter operand) */
-
- long imm; /* rotated imm */
- char* curr; /* fill point in buffer */
- char* end; /* end of buffer */
- char* err; /* error message */
-};
-
-typedef struct Opcode Opcode;
-struct Opcode
-{
- char* o;
- void (*fmt)(Opcode*, Instr*);
- ulong (*foll)(Map*, Rgetter, Instr*, ulong);
- char* a;
-};
-
-static void format(char*, Instr*, char*);
-static char FRAMENAME[] = ".frame";
-
-/*
- * Arm-specific debugger interface
- */
-
-extern char *armexcep(Map*, Rgetter);
-static int armfoll(Map*, uvlong, Rgetter, uvlong*);
-static int arminst(Map*, uvlong, char, char*, int);
-static int armdas(Map*, uvlong, char*, int);
-static int arminstlen(Map*, uvlong);
-
-/*
- * Debugger interface
- */
-Machdata armmach =
-{
- {0, 0, 0, 0xD}, /* break point */
- 4, /* break point size */
-
- leswab, /* short to local byte order */
- leswal, /* long to local byte order */
- leswav, /* long to local byte order */
- risctrace, /* C traceback */
- riscframe, /* Frame finder */
- armexcep, /* print exception */
- 0, /* breakpoint fixup */
- 0, /* single precision float printer */
- 0, /* double precision float printer */
- armfoll, /* following addresses */
- arminst, /* print instruction */
- armdas, /* dissembler */
- arminstlen, /* instruction size */
-};
-
-char*
-armexcep(Map *map, Rgetter rget)
-{
- long c;
-
- c = (*rget)(map, "TYPE");
- switch (c&0x1f) {
- case 0x11:
- return "Fiq interrupt";
- case 0x12:
- return "Mirq interrupt";
- case 0x13:
- return "SVC/SWI Exception";
- case 0x17:
- return "Prefetch Abort/Data Abort";
- case 0x18:
- return "Data Abort";
- case 0x1b:
- return "Undefined instruction/Breakpoint";
- case 0x1f:
- return "Sys trap";
- default:
- return "Undefined trap";
- }
-}
-
-static
-char* cond[16] =
-{
- "EQ", "NE", "CS", "CC",
- "MI", "PL", "VS", "VC",
- "HI", "LS", "GE", "LT",
- "GT", "LE", 0, "NV"
-};
-
-static
-char* shtype[4] =
-{
- "<<", ">>", "->", "@>"
-};
-
-static
-char *hb[4] =
-{
- "???", "HU", "B", "H"
-};
-
-static
-char* addsub[2] =
-{
- "-", "+",
-};
-
-int
-armclass(long w)
-{
- int op;
-
- op = (w >> 25) & 0x7;
- switch(op) {
- case 0: /* data processing r,r,r */
- op = ((w >> 4) & 0xf);
- if(op == 0x9) {
- op = 48+16; /* mul */
- if(w & (1<<24)) {
- op += 2;
- if(w & (1<<22))
- op++; /* swap */
- break;
- }
- if(w & (1<<21))
- op++; /* mla */
- break;
- }
- if ((op & 0x9) == 0x9) /* ld/st byte/half s/u */
- {
- op = (48+16+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
- break;
- }
- op = (w >> 21) & 0xf;
- if(w & (1<<4))
- op += 32;
- else
- if(w & (31<<7))
- op += 16;
- break;
- case 1: /* data processing i,r,r */
- op = (48) + ((w >> 21) & 0xf);
- break;
- case 2: /* load/store byte/word i(r) */
- op = (48+24) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
- break;
- case 3: /* load/store byte/word (r)(r) */
- op = (48+24+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
- break;
- case 4: /* block data transfer (r)(r) */
- op = (48+24+4+4) + ((w >> 20) & 0x1);
- break;
- case 5: /* branch / branch link */
- op = (48+24+4+4+2) + ((w >> 24) & 0x1);
- break;
- case 7: /* coprocessor crap */
- op = (48+24+4+4+2+2) + ((w >> 3) & 0x2) + ((w >> 20) & 0x1);
- break;
- default:
- op = (48+24+4+4+2+2+4);
- break;
- }
- return op;
-}
-
-static int
-decode(Map *map, ulong pc, Instr *i)
-{
- uint32 w;
-
- if(get4(map, pc, &w) < 0) {
- werrstr("can't read instruction: %r");
- return -1;
- }
- i->w = w;
- i->addr = pc;
- i->cond = (w >> 28) & 0xF;
- i->op = armclass(w);
- i->map = map;
- return 1;
-}
-
-static void
-bprint(Instr *i, char *fmt, ...)
-{
- va_list arg;
-
- va_start(arg, fmt);
- i->curr = vseprint(i->curr, i->end, fmt, arg);
- va_end(arg);
-}
-
-static int
-plocal(Instr *i)
-{
- char *reg;
- Symbol s;
- char *fn;
- int class;
- int offset;
-
- if(!findsym(i->addr, CTEXT, &s)) {
- if(debug)fprint(2,"fn not found @%lux: %r\n", i->addr);
- return 0;
- }
- fn = s.name;
- if (!findlocal(&s, FRAMENAME, &s)) {
- if(debug)fprint(2,"%s.%s not found @%s: %r\n", fn, FRAMENAME, s.name);
- return 0;
- }
- if(s.value > i->imm) {
- class = CAUTO;
- offset = s.value-i->imm;
- reg = "(SP)";
- } else {
- class = CPARAM;
- offset = i->imm-s.value-4;
- reg = "(FP)";
- }
- if(!getauto(&s, offset, class, &s)) {
- if(debug)fprint(2,"%s %s not found @%ux: %r\n", fn,
- class == CAUTO ? " auto" : "param", offset);
- return 0;
- }
- bprint(i, "%s%c%d%s", s.name, class == CPARAM ? '+' : '-', s.value, reg);
- return 1;
-}
-
-/*
- * Print value v as name[+offset]
- */
-int
-gsymoff(char *buf, int n, long 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 || delta >= 4096)
- return snprint(buf, n, "#%lux", v);
- if (strcmp(s.name, ".string") == 0)
- return snprint(buf, n, "#%lux", v);
- if (!delta)
- return snprint(buf, n, "%s", s.name);
- if (s.type != 't' && s.type != 'T')
- return snprint(buf, n, "%s+%llux", s.name, v-s.value);
- else
- return snprint(buf, n, "#%lux", v);
-}
-
-static void
-armdps(Opcode *o, Instr *i)
-{
- i->store = (i->w >> 20) & 1;
- i->rn = (i->w >> 16) & 0xf;
- i->rd = (i->w >> 12) & 0xf;
- i->rs = (i->w >> 0) & 0xf;
- if(i->rn == 15 && i->rs == 0) {
- if(i->op == 8) {
- format("MOVW", i,"CPSR, R%d");
- return;
- } else
- if(i->op == 10) {
- format("MOVW", i,"SPSR, R%d");
- return;
- }
- } else
- if(i->rn == 9 && i->rd == 15) {
- if(i->op == 9) {
- format("MOVW", i, "R%s, CPSR");
- return;
- } else
- if(i->op == 11) {
- format("MOVW", i, "R%s, SPSR");
- return;
- }
- }
- format(o->o, i, o->a);
-}
-
-static void
-armdpi(Opcode *o, Instr *i)
-{
- ulong v;
- int c;
-
- v = (i->w >> 0) & 0xff;
- c = (i->w >> 8) & 0xf;
- while(c) {
- v = (v<<30) | (v>>2);
- c--;
- }
- i->imm = v;
- i->store = (i->w >> 20) & 1;
- i->rn = (i->w >> 16) & 0xf;
- i->rd = (i->w >> 12) & 0xf;
- i->rs = i->w&0x0f;
-
- /* RET is encoded as ADD #0,R14,R15 */
- if((i->w & 0x0fffffff) == 0x028ef000){
- format("RET%C", i, "");
- return;
- }
- if((i->w & 0x0ff0ffff) == 0x0280f000){
- format("B%C", i, "0(R%n)");
- return;
- }
- format(o->o, i, o->a);
-}
-
-static void
-armsdti(Opcode *o, Instr *i)
-{
- ulong v;
-
- v = i->w & 0xfff;
- if(!(i->w & (1<<23)))
- v = -v;
- i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
- i->imm = v;
- i->rn = (i->w >> 16) & 0xf;
- i->rd = (i->w >> 12) & 0xf;
- /* RET is encoded as LW.P x,R13,R15 */
- if ((i->w & 0x0ffff000) == 0x049df000)
- {
- format("RET%C%p", i, "%I");
- return;
- }
- format(o->o, i, o->a);
-}
-
-/* arm V4 ld/st halfword, signed byte */
-static void
-armhwby(Opcode *o, Instr *i)
-{
- i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
- i->imm = (i->w & 0xf) | ((i->w >> 8) & 0xf);
- if (!(i->w & (1 << 23)))
- i->imm = - i->imm;
- i->rn = (i->w >> 16) & 0xf;
- i->rd = (i->w >> 12) & 0xf;
- i->rs = (i->w >> 0) & 0xf;
- format(o->o, i, o->a);
-}
-
-static void
-armsdts(Opcode *o, Instr *i)
-{
- i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
- i->rs = (i->w >> 0) & 0xf;
- i->rn = (i->w >> 16) & 0xf;
- i->rd = (i->w >> 12) & 0xf;
- format(o->o, i, o->a);
-}
-
-static void
-armbdt(Opcode *o, Instr *i)
-{
- i->store = (i->w >> 21) & 0x3; /* S & W bits */
- i->rn = (i->w >> 16) & 0xf;
- i->imm = i->w & 0xffff;
- if(i->w == 0xe8fd8000)
- format("RFE", i, "");
- else
- format(o->o, i, o->a);
-}
-
-/*
-static void
-armund(Opcode *o, Instr *i)
-{
- format(o->o, i, o->a);
-}
-
-static void
-armcdt(Opcode *o, Instr *i)
-{
- format(o->o, i, o->a);
-}
-*/
-
-static void
-armunk(Opcode *o, Instr *i)
-{
- format(o->o, i, o->a);
-}
-
-static void
-armb(Opcode *o, Instr *i)
-{
- ulong v;
-
- v = i->w & 0xffffff;
- if(v & 0x800000)
- v |= ~0xffffff;
- i->imm = (v<<2) + i->addr + 8;
- format(o->o, i, o->a);
-}
-
-static void
-armco(Opcode *o, Instr *i) /* coprocessor instructions */
-{
- int op, p, cp;
-
- char buf[1024];
-
- i->rn = (i->w >> 16) & 0xf;
- i->rd = (i->w >> 12) & 0xf;
- i->rs = i->w&0xf;
- cp = (i->w >> 8) & 0xf;
- p = (i->w >> 5) & 0x7;
- if(i->w&(1<<4)) {
- op = (i->w >> 21) & 0x07;
- snprint(buf, sizeof(buf), "#%x, #%x, R%d, C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p);
- } else {
- op = (i->w >> 20) & 0x0f;
- snprint(buf, sizeof(buf), "#%x, #%x, C(%d), C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p);
- }
- format(o->o, i, buf);
-}
-
-static int
-armcondpass(Map *map, Rgetter rget, uchar cond)
-{
- ulong psr;
- uchar n;
- uchar z;
- uchar c;
- uchar v;
-
- psr = rget(map, "PSR");
- n = (psr >> 31) & 1;
- z = (psr >> 30) & 1;
- c = (psr >> 29) & 1;
- v = (psr >> 28) & 1;
-
- switch(cond) {
- case 0: return z;
- case 1: return !z;
- case 2: return c;
- case 3: return !c;
- case 4: return n;
- case 5: return !n;
- case 6: return v;
- case 7: return !v;
- case 8: return c && !z;
- case 9: return !c || z;
- case 10: return n == v;
- case 11: return n != v;
- case 12: return !z && (n == v);
- case 13: return z && (n != v);
- case 14: return 1;
- case 15: return 0;
- }
- return 0;
-}
-
-static ulong
-armshiftval(Map *map, Rgetter rget, Instr *i)
-{
- if(i->w & (1 << 25)) { /* immediate */
- ulong imm = i->w & BITS(0, 7);
- ulong s = (i->w & BITS(8, 11)) >> 7; /* this contains the *2 */
- return ROR(imm, s);
- } else {
- char buf[8];
- ulong v;
- ulong s = (i->w & BITS(7,11)) >> 7;
-
- sprint(buf, "R%ld", i->w & 0xf);
- v = rget(map, buf);
-
- switch((i->w & BITS(4, 6)) >> 4) {
- case 0: /* LSLIMM */
- return v << s;
- case 1: /* LSLREG */
- sprint(buf, "R%lud", s >> 1);
- s = rget(map, buf) & 0xFF;
- if(s >= 32) return 0;
- return v << s;
- case 2: /* LSRIMM */
- return LSR(v, s);
- case 3: /* LSRREG */
- sprint(buf, "R%ld", s >> 1);
- s = rget(map, buf) & 0xFF;
- if(s >= 32) return 0;
- return LSR(v, s);
- case 4: /* ASRIMM */
- if(s == 0) {
- if((v & (1U<<31)) == 0)
- return 0;
- return 0xFFFFFFFF;
- }
- return ASR(v, s);
- case 5: /* ASRREG */
- sprint(buf, "R%ld", s >> 1);
- s = rget(map, buf) & 0xFF;
- if(s >= 32) {
- if((v & (1U<<31)) == 0)
- return 0;
- return 0xFFFFFFFF;
- }
- return ASR(v, s);
- case 6: /* RORIMM */
- if(s == 0) {
- ulong c = (rget(map, "PSR") >> 29) & 1;
-
- return (c << 31) | LSR(v, 1);
- }
- return ROR(v, s);
- case 7: /* RORREG */
- sprint(buf, "R%ld", (s>>1)&0xF);
- s = rget(map, buf);
- if(s == 0 || (s & 0xF) == 0)
- return v;
- return ROR(v, s & 0xF);
- }
- }
- return 0;
-}
-
-static int
-nbits(ulong v)
-{
- int n = 0;
- int i;
-
- for(i=0; i < 32 ; i++) {
- if(v & 1) ++n;
- v >>= 1;
- }
-
- return n;
-}
-
-static ulong
-armmaddr(Map *map, Rgetter rget, Instr *i)
-{
- ulong v;
- ulong nb;
- char buf[8];
- ulong rn;
-
- rn = (i->w >> 16) & 0xf;
- sprint(buf,"R%ld", rn);
-
- v = rget(map, buf);
- nb = nbits(i->w & ((1 << 15) - 1));
-
- switch((i->w >> 23) & 3) {
- case 0: return (v - (nb*4)) + 4;
- case 1: return v;
- case 2: return v - (nb*4);
- case 3: return v + 4;
- }
- return 0;
-}
-
-static ulong
-armaddr(Map *map, Rgetter rget, Instr *i)
-{
- char buf[8];
- ulong rn;
-
- sprint(buf, "R%ld", (i->w >> 16) & 0xf);
- rn = rget(map, buf);
-
- if((i->w & (1<<24)) == 0) { /* POSTIDX */
- sprint(buf, "R%ld", rn);
- return rget(map, buf);
- }
-
- if((i->w & (1<<25)) == 0) { /* OFFSET */
- sprint(buf, "R%ld", rn);
- if(i->w & (1U<<23))
- return rget(map, buf) + (i->w & BITS(0,11));
- return rget(map, buf) - (i->w & BITS(0,11));
- } else { /* REGOFF */
- ulong index = 0;
- uchar c;
- uchar rm;
-
- sprint(buf, "R%ld", i->w & 0xf);
- rm = rget(map, buf);
-
- switch((i->w & BITS(5,6)) >> 5) {
- case 0: index = rm << ((i->w & BITS(7,11)) >> 7); break;
- case 1: index = LSR(rm, ((i->w & BITS(7,11)) >> 7)); break;
- case 2: index = ASR(rm, ((i->w & BITS(7,11)) >> 7)); break;
- case 3:
- if((i->w & BITS(7,11)) == 0) {
- c = (rget(map, "PSR") >> 29) & 1;
- index = c << 31 | LSR(rm, 1);
- } else {
- index = ROR(rm, ((i->w & BITS(7,11)) >> 7));
- }
- break;
- }
- if(i->w & (1<<23))
- return rn + index;
- return rn - index;
- }
-}
-
-static ulong
-armfadd(Map *map, Rgetter rget, Instr *i, ulong pc)
-{
- char buf[8];
- int r;
-
- r = (i->w >> 12) & 0xf;
- if(r != 15 || !armcondpass(map, rget, (i->w >> 28) & 0xf))
- return pc+4;
-
- r = (i->w >> 16) & 0xf;
- sprint(buf, "R%d", r);
-
- return rget(map, buf) + armshiftval(map, rget, i);
-}
-
-static ulong
-armfmovm(Map *map, Rgetter rget, Instr *i, ulong pc)
-{
- uint32 v;
- ulong addr;
-
- v = i->w & 1<<15;
- if(!v || !armcondpass(map, rget, (i->w>>28)&0xf))
- return pc+4;
-
- addr = armmaddr(map, rget, i) + nbits(i->w & BITS(0,15));
- if(get4(map, addr, &v) < 0) {
- werrstr("can't read addr: %r");
- return -1;
- }
- return v;
-}
-
-static ulong
-armfbranch(Map *map, Rgetter rget, Instr *i, ulong pc)
-{
- if(!armcondpass(map, rget, (i->w >> 28) & 0xf))
- return pc+4;
-
- return pc + (((signed long)i->w << 8) >> 6) + 8;
-}
-
-static ulong
-armfmov(Map *map, Rgetter rget, Instr *i, ulong pc)
-{
- ulong rd;
- uint32 v;
-
- rd = (i->w >> 12) & 0xf;
- if(rd != 15 || !armcondpass(map, rget, (i->w>>28)&0xf))
- return pc+4;
-
- /* LDR */
- /* BUG: Needs LDH/B, too */
- if(((i->w>>26)&0x3) == 1) {
- if(get4(map, armaddr(map, rget, i), &v) < 0) {
- werrstr("can't read instruction: %r");
- return pc+4;
- }
- return v;
- }
-
- /* MOV */
- return armshiftval(map, rget, i);
-}
-
-static Opcode opcodes[] =
-{
- "AND%C%S", armdps, 0, "R%s,R%n,R%d",
- "EOR%C%S", armdps, 0, "R%s,R%n,R%d",
- "SUB%C%S", armdps, 0, "R%s,R%n,R%d",
- "RSB%C%S", armdps, 0, "R%s,R%n,R%d",
- "ADD%C%S", armdps, armfadd, "R%s,R%n,R%d",
- "ADC%C%S", armdps, 0, "R%s,R%n,R%d",
- "SBC%C%S", armdps, 0, "R%s,R%n,R%d",
- "RSC%C%S", armdps, 0, "R%s,R%n,R%d",
- "TST%C%S", armdps, 0, "R%s,R%n",
- "TEQ%C%S", armdps, 0, "R%s,R%n",
- "CMP%C%S", armdps, 0, "R%s,R%n",
- "CMN%C%S", armdps, 0, "R%s,R%n",
- "ORR%C%S", armdps, 0, "R%s,R%n,R%d",
- "MOVW%C%S", armdps, armfmov, "R%s,R%d",
- "BIC%C%S", armdps, 0, "R%s,R%n,R%d",
- "MVN%C%S", armdps, 0, "R%s,R%d",
-
-/* 16 */
- "AND%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
- "EOR%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
- "SUB%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
- "RSB%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
- "ADD%C%S", armdps, armfadd, "(R%s%h%m),R%n,R%d",
- "ADC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
- "SBC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
- "RSC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
- "TST%C%S", armdps, 0, "(R%s%h%m),R%n",
- "TEQ%C%S", armdps, 0, "(R%s%h%m),R%n",
- "CMP%C%S", armdps, 0, "(R%s%h%m),R%n",
- "CMN%C%S", armdps, 0, "(R%s%h%m),R%n",
- "ORR%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
- "MOVW%C%S", armdps, armfmov, "(R%s%h%m),R%d",
- "BIC%C%S", armdps, 0, "(R%s%h%m),R%n,R%d",
- "MVN%C%S", armdps, 0, "(R%s%h%m),R%d",
-
-/* 32 */
- "AND%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
- "EOR%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
- "SUB%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
- "RSB%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
- "ADD%C%S", armdps, armfadd, "(R%s%hR%M),R%n,R%d",
- "ADC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
- "SBC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
- "RSC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
- "TST%C%S", armdps, 0, "(R%s%hR%M),R%n",
- "TEQ%C%S", armdps, 0, "(R%s%hR%M),R%n",
- "CMP%C%S", armdps, 0, "(R%s%hR%M),R%n",
- "CMN%C%S", armdps, 0, "(R%s%hR%M),R%n",
- "ORR%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
- "MOVW%C%S", armdps, armfmov, "(R%s%hR%M),R%d",
- "BIC%C%S", armdps, 0, "(R%s%hR%M),R%n,R%d",
- "MVN%C%S", armdps, 0, "(R%s%hR%M),R%d",
-
-/* 48 */
- "AND%C%S", armdpi, 0, "$#%i,R%n,R%d",
- "EOR%C%S", armdpi, 0, "$#%i,R%n,R%d",
- "SUB%C%S", armdpi, 0, "$#%i,R%n,R%d",
- "RSB%C%S", armdpi, 0, "$#%i,R%n,R%d",
- "ADD%C%S", armdpi, armfadd, "$#%i,R%n,R%d",
- "ADC%C%S", armdpi, 0, "$#%i,R%n,R%d",
- "SBC%C%S", armdpi, 0, "$#%i,R%n,R%d",
- "RSC%C%S", armdpi, 0, "$#%i,R%n,R%d",
- "TST%C%S", armdpi, 0, "$#%i,R%n",
- "TEQ%C%S", armdpi, 0, "$#%i,R%n",
- "CMP%C%S", armdpi, 0, "$#%i,R%n",
- "CMN%C%S", armdpi, 0, "$#%i,R%n",
- "ORR%C%S", armdpi, 0, "$#%i,R%n,R%d",
- "MOVW%C%S", armdpi, armfmov, "$#%i,R%d",
- "BIC%C%S", armdpi, 0, "$#%i,R%n,R%d",
- "MVN%C%S", armdpi, 0, "$#%i,R%d",
-
-/* 48+16 */
- "MUL%C%S", armdpi, 0, "R%s,R%M,R%n",
- "MULA%C%S", armdpi, 0, "R%s,R%M,R%n,R%d",
- "SWPW", armdpi, 0, "R%s,(R%n),R%d",
- "SWPB", armdpi, 0, "R%s,(R%n),R%d",
-
-/* 48+16+4 */
- "MOV%u%C%p", armhwby, 0, "R%d,(R%n%UR%M)",
- "MOV%u%C%p", armhwby, 0, "R%d,%I",
- "MOV%u%C%p", armhwby, armfmov, "(R%n%UR%M),R%d",
- "MOV%u%C%p", armhwby, armfmov, "%I,R%d",
-
-/* 48+24 */
- "MOVW%C%p", armsdti, 0, "R%d,%I",
- "MOVB%C%p", armsdti, 0, "R%d,%I",
- "MOVW%C%p", armsdti, armfmov, "%I,R%d",
- "MOVBU%C%p", armsdti, armfmov, "%I,R%d",
-
- "MOVW%C%p", armsdts, 0, "R%d,(R%s%h%m)(R%n)",
- "MOVB%C%p", armsdts, 0, "R%d,(R%s%h%m)(R%n)",
- "MOVW%C%p", armsdts, armfmov, "(R%s%h%m)(R%n),R%d",
- "MOVBU%C%p", armsdts, armfmov, "(R%s%h%m)(R%n),R%d",
-
- "MOVM%C%P%a", armbdt, armfmovm, "[%r],(R%n)",
- "MOVM%C%P%a", armbdt, armfmovm, "(R%n),[%r]",
-
- "B%C", armb, armfbranch, "%b",
- "BL%C", armb, armfbranch, "%b",
-
- "CDP%C", armco, 0, "",
- "CDP%C", armco, 0, "",
- "MCR%C", armco, 0, "",
- "MRC%C", armco, 0, "",
-
- "UNK", armunk, 0, "",
-};
-
-static void
-gaddr(Instr *i)
-{
- *i->curr++ = '$';
- i->curr += gsymoff(i->curr, i->end-i->curr, i->imm, CANY);
-}
-
-static char *mode[] = { 0, "IA", "DB", "IB" };
-static char *pw[] = { "P", "PW", 0, "W" };
-static char *sw[] = { 0, "W", "S", "SW" };
-
-static void
-format(char *mnemonic, Instr *i, char *f)
-{
- int j, k, m, n;
- int g;
- char *fmt;
-
- if(mnemonic)
- format(0, i, mnemonic);
- if(f == 0)
- return;
- if(mnemonic)
- if(i->curr < i->end)
- *i->curr++ = '\t';
- for ( ; *f && i->curr < i->end; f++) {
- if(*f != '%') {
- *i->curr++ = *f;
- continue;
- }
- switch (*++f) {
-
- case 'C': /* .CONDITION */
- if(cond[i->cond])
- bprint(i, ".%s", cond[i->cond]);
- break;
-
- case 'S': /* .STORE */
- if(i->store)
- bprint(i, ".S");
- break;
-
- case 'P': /* P & U bits for block move */
- n = (i->w >>23) & 0x3;
- if (mode[n])
- bprint(i, ".%s", mode[n]);
- break;
-
- case 'p': /* P & W bits for single data xfer*/
- if (pw[i->store])
- bprint(i, ".%s", pw[i->store]);
- break;
-
- case 'a': /* S & W bits for single data xfer*/
- if (sw[i->store])
- bprint(i, ".%s", sw[i->store]);
- break;
-
- case 's':
- bprint(i, "%d", i->rs & 0xf);
- break;
-
- case 'M':
- bprint(i, "%d", (i->w>>8) & 0xf);
- break;
-
- case 'm':
- bprint(i, "%d", (i->w>>7) & 0x1f);
- break;
-
- case 'h':
- bprint(i, shtype[(i->w>>5) & 0x3]);
- break;
-
- case 'u': /* Signed/unsigned Byte/Halfword */
- bprint(i, hb[(i->w>>5) & 0x3]);
- break;
-
- case 'I':
- if (i->rn == 13) {
- if (plocal(i))
- break;
- }
- g = 0;
- fmt = "#%lx(R%d)";
- if (i->rn == 15) {
- /* convert load of offset(PC) to a load immediate */
- uint32 x;
- if (get4(i->map, i->addr+i->imm+8, &x) > 0)
- {
- i->imm = (int32)x;
- g = 1;
- fmt = "";
- }
- }
- if (mach->sb)
- {
- if (i->rd == 11) {
- uint32 nxti;
-
- if (get4(i->map, i->addr+4, &nxti) > 0) {
- if ((nxti & 0x0e0f0fff) == 0x060c000b) {
- i->imm += mach->sb;
- g = 1;
- fmt = "-SB";
- }
- }
- }
- if (i->rn == 12)
- {
- i->imm += mach->sb;
- g = 1;
- fmt = "-SB(SB)";
- }
- }
- if (g)
- {
- gaddr(i);
- bprint(i, fmt, i->rn);
- }
- else
- bprint(i, fmt, i->imm, i->rn);
- break;
- case 'U': /* Add/subtract from base */
- bprint(i, addsub[(i->w >> 23) & 1]);
- break;
-
- case 'n':
- bprint(i, "%d", i->rn);
- break;
-
- case 'd':
- bprint(i, "%d", i->rd);
- break;
-
- case 'i':
- bprint(i, "%lux", i->imm);
- break;
-
- case 'b':
- i->curr += symoff(i->curr, i->end-i->curr,
- i->imm, CTEXT);
- break;
-
- case 'g':
- i->curr += gsymoff(i->curr, i->end-i->curr,
- i->imm, CANY);
- break;
-
- case 'r':
- n = i->imm&0xffff;
- j = 0;
- k = 0;
- while(n) {
- m = j;
- while(n&0x1) {
- j++;
- n >>= 1;
- }
- if(j != m) {
- if(k)
- bprint(i, ",");
- if(j == m+1)
- bprint(i, "R%d", m);
- else
- bprint(i, "R%d-R%d", m, j-1);
- k = 1;
- }
- j++;
- n >>= 1;
- }
- break;
-
- case '\0':
- *i->curr++ = '%';
- return;
-
- default:
- bprint(i, "%%%c", *f);
- break;
- }
- }
- *i->curr = 0;
-}
-
-static int
-printins(Map *map, ulong pc, char *buf, int n)
-{
- Instr i;
-
- i.curr = buf;
- i.end = buf+n-1;
- if(decode(map, pc, &i) < 0)
- return -1;
-
- (*opcodes[i.op].fmt)(&opcodes[i.op], &i);
- return 4;
-}
-
-static int
-arminst(Map *map, uvlong pc, char modifier, char *buf, int n)
-{
- USED(modifier);
- return printins(map, pc, buf, n);
-}
-
-static int
-armdas(Map *map, uvlong pc, char *buf, int n)
-{
- Instr i;
-
- i.curr = buf;
- i.end = buf+n;
- if(decode(map, pc, &i) < 0)
- return -1;
- if(i.end-i.curr > 8)
- i.curr = _hexify(buf, i.w, 7);
- *i.curr = 0;
- return 4;
-}
-
-static int
-arminstlen(Map *map, uvlong pc)
-{
- Instr i;
-
- if(decode(map, pc, &i) < 0)
- return -1;
- return 4;
-}
-
-static int
-armfoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
-{
- ulong d;
- Instr i;
-
- if(decode(map, pc, &i) < 0)
- return -1;
-
- if(opcodes[i.op].foll) {
- d = (*opcodes[i.op].foll)(map, rget, &i, pc);
- if(d == -1)
- return -1;
- } else
- d = pc+4;
-
- foll[0] = d;
- return 1;
-}
+++ /dev/null
-// 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.h>
-
-#define REGOFF(x) offsetof(struct UregAmd64, x)
-
-#define REGSIZE sizeof(struct UregAmd64)
-#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 */
-};
+++ /dev/null
-// 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 <libc.h>
-#include <bio.h>
-#include <ureg_x86.h>
-#include <mach.h>
-
-#define REGOFF(x) (uintptr)(&((struct Ureg386 *) 0)->x)
-
-#define PC REGOFF(pc)
-#define SP REGOFF(sp)
-#define AX REGOFF(ax)
-
-#define REGSIZE sizeof(struct Ureg386)
-#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 */
- 0xFFFFFFFFULL, /* user stack top */
- 1, /* quantization of pc */
- 4, /* szaddr */
- 4, /* szreg */
- 4, /* szfloat */
- 8, /* szdouble */
-};
+++ /dev/null
-// 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.h>
-#include <ureg_amd64.h>
-#include <ureg_x86.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 GOSTARTSYM[] = "sys·goexit";
-static char PROFSYM[] = "_mainp";
-static char FRAMENAME[] = ".frame";
-static char LESSSTACK[] = "sys·lessstack";
-static char MORESTACK[] = "sys·morestack";
-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 int32 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)
-{
- uint32 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 %d", c);
- return buf;
- } else
- return excname[c];
-}
-
-static int
-i386trace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace)
-{
- int i;
- uvlong osp, pc1;
- Symbol s, f, s1;
- extern Mach mamd64;
- int isamd64;
- uvlong g, m, lessstack, morestack, stktop;
-
- isamd64 = (mach == &mamd64);
-
- // ../pkg/runtime/runtime.h
- // G is
- // byte* stackguard
- // byte* stackbase (= Stktop*)
- // TODO(rsc): Need some way to get at the g for other threads.
- // Probably need to pass it into the trace function.
- g = 0;
- if(isamd64)
- geta(map, offsetof(struct UregAmd64, r15), &g);
- else {
- // TODO(rsc): How to fetch g on 386?
- }
- stktop = 0;
- if(g != 0)
- geta(map, g+1*mach->szaddr, &stktop);
-
- lessstack = 0;
- if(lookup(0, LESSSTACK, &s))
- lessstack = s.value;
- morestack = 0;
- if(lookup(0, MORESTACK, &s))
- morestack = s.value;
-
- USED(link);
- osp = 0;
- i = 0;
-
- for(;;) {
- if(!findsym(pc, CTEXT, &s)) {
- // check for closure return sequence
- uchar buf[8], *p;
- if(get1(map, pc, buf, 8) < 0)
- break;
- // ADDQ $xxx, SP; RET
- p = buf;
- if(mach == &mamd64) {
- if(p[0] != 0x48)
- break;
- p++;
- }
- if(p[0] != 0x81 || p[1] != 0xc4 || p[6] != 0xc3)
- break;
- sp += p[2] | (p[3]<<8) | (p[4]<<16) | (p[5]<<24);
- if(geta(map, sp, &pc) < 0)
- break;
- sp += mach->szaddr;
- continue;
- }
-
- if (osp == sp)
- break;
- osp = sp;
-
- if(strcmp(STARTSYM, s.name) == 0 ||
- strcmp(GOSTARTSYM, s.name) == 0 ||
- strcmp(PROFSYM, s.name) == 0)
- break;
-
- if(s.value == morestack) {
- if (0) {
- // This code is old and won't work anymore.
- // But no one uses it anyway.
- // Leave it obviously broken until someone needs it.
- // In the middle of morestack.
- // Caller is m->morepc.
- // Caller's caller is in m->morearg.
- // TODO(rsc): 386
- geta(map, offsetof(struct UregAmd64, r14), &m);
-
- pc = 0;
- sp = 0;
- pc1 = 0;
- s1 = s;
- memset(&s, 0, sizeof s);
- geta(map, m+1*mach->szaddr, &pc1); // m->morepc
- geta(map, m+2*mach->szaddr, &sp); // m->morebuf.sp
- geta(map, m+3*mach->szaddr, &pc); // m->morebuf.pc
- findsym(pc1, CTEXT, &s);
- (*trace)(map, pc1, sp-mach->szaddr, &s1); // morestack symbol; caller's PC/SP
-
- // caller's caller
- s1 = s;
- findsym(pc, CTEXT, &s);
- (*trace)(map, pc, sp, &s1); // morestack's caller; caller's caller's PC/SP
- continue;
- } else {
- werrstr("morestack not implemented correctly");
- return -1;
- }
- }
-
- if(pc == lessstack) {
- // ../pkg/runtime/runtime.h
- // Stktop is
- // byte* stackguard
- // byte* stackbase
- // Gobuf gobuf
- // byte* sp;
- // byte* pc;
- // G* g;
- if(!isamd64)
- fprint(2, "warning: cannot unwind stack split on 386\n");
- if(stktop == 0)
- break;
- pc = 0;
- sp = 0;
- geta(map, stktop+2*mach->szaddr, &sp);
- geta(map, stktop+3*mach->szaddr, &pc);
- geta(map, stktop+1*mach->szaddr, &stktop);
- (*trace)(map, pc, sp, &s1);
- continue;
- }
-
- s1 = s;
- pc1 = 0;
- if(pc != s.value) { /* not at first instruction */
- if(findlocal(&s, FRAMENAME, &f) == 0)
- break;
- geta(map, sp, &pc1);
- sp += f.value-mach->szaddr;
- }
- if(geta(map, sp, &pc) < 0)
- break;
-
- // If PC is not valid, assume we caught the function
- // before it moved the stack pointer down or perhaps
- // after it moved the stack pointer back up.
- // Try the PC we'd have gotten without the stack
- // pointer adjustment above (pc != s.value).
- // This only matters for the first frame, and it is only
- // a heuristic, but it does help.
- if(!findsym(pc, CTEXT, &s) || strcmp(s.name, "etext") == 0)
- pc = pc1;
-
- if(pc == 0)
- break;
-
- if(pc != lessstack)
- (*trace)(map, pc, sp, &s1);
- 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 */
- schar index; /* bits 3-5 of SIB */
- schar 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 */
- uint32 disp; /* displacement */
- uint32 imm; /* immediate */
- uint32 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 */
- /* be careful: some unix system headers #define R8, R9, etc */
- AMD64_R8,
- AMD64_R9,
- AMD64_R10,
- AMD64_R11,
- AMD64_R12,
- AMD64_R13,
- AMD64_R14,
- AMD64_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 int32 R/M field with register (/r) */
- RMB, /* Byte R/M field with register (/r) */
- RMOP, /* Word or int32 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) */
- Op_R0, /* Base reg of Mod R/M is literal 0x00 */
- Op_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" },
-};
-
-static Optable optab0F18[4]=
-{
-[0x00] = { 0,0, "PREFETCHNTA %e" },
-[0x01] = { 0,0, "PREFECTCH0 %e" },
-[0x02] = { 0,0, "PREFECTCH1 %e" },
-[0x03] = { 0,0, "PREFECTCH2 %e" },
-};
-
-/* 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 optab660F38[256]=
-{
-[0x00] = { RM,0, "PSHUFB %x,%X" },
-[0xdc] = { RM,0, "AESENC %x,%X" },
-[0xdb] = { RM,0, "AESIMC %x,%X," },
-[0xdd] = { RM,0, "AESENCLAST %x,%X" },
-[0xde] = { RM,0, "AESDEC %x,%X" },
-[0xdf] = { RM,0, "AESDECLAST %x,%X" },
-};
-
-static Optable optab660F3A[256]=
-{
-[0x22] = { RM,Ib, "PINSR%S %i,%e,%X" },
-[0xdf] = { RM,Ib, "AESKEYGENASSIST %i,%x,%X" },
-};
-
-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" },
-[0x38] = { AUX,0, optab660F38 },
-[0x3A] = { AUX,0, optab660F3A },
-[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 optabF20F38[256]=
-{
-[0xf0] = { RM,0, "CRC32B %e, %r" },
-[0xf1] = { RM,0, "CRC32%S %e, %r" },
-};
-
-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" },
-[0x38] = { AUX,0, optabF20F38 },
-[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" },
-[0x18] = { RMOP,0, optab0F18 },
-[0x1F] = { RM,0, "NOP%S %e" },
-[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" },
-[0x77] = { 0,0, "EMMS" },
-[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 %x,%X,%#i" },
-[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" },
-[0x08] = { 0,0, "FCMOVCS %f,F0" },
-[0x09] = { 0,0, "FCMOVEQ %f,F0" },
-[0x0a] = { 0,0, "FCMOVLS %f,F0" },
-[0x0b] = { 0,0, "FCMOVUN %f,F0" },
-[0x0d] = { Op_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" },
-[0x08] = { 0,0, "FCMOVCC F0,F0" }, /* Mod R/M = 11xx xxxx*/
-[0x09] = { 0,0, "FCMOVCC F1,F0" },
-[0x0a] = { 0,0, "FCMOVCC F2,F0" },
-[0x0b] = { 0,0, "FCMOVCC F3,F0" },
-[0x0c] = { 0,0, "FCMOVCC F4,F0" },
-[0x0d] = { 0,0, "FCMOVCC F5,F0" },
-[0x0e] = { 0,0, "FCMOVCC F6,F0" },
-[0x0f] = { 0,0, "FCMOVCC F7,F0" },
-[0x10] = { 0,0, "FCMOVNE F0,F0" },
-[0x11] = { 0,0, "FCMOVNE F1,F0" },
-[0x12] = { 0,0, "FCMOVNE F2,F0" },
-[0x13] = { 0,0, "FCMOVNE F3,F0" },
-[0x14] = { 0,0, "FCMOVNE F4,F0" },
-[0x15] = { 0,0, "FCMOVNE F5,F0" },
-[0x16] = { 0,0, "FCMOVNE F6,F0" },
-[0x17] = { 0,0, "FCMOVNE F7,F0" },
-[0x18] = { 0,0, "FCMOVHI F0,F0" },
-[0x19] = { 0,0, "FCMOVHI F1,F0" },
-[0x1a] = { 0,0, "FCMOVHI F2,F0" },
-[0x1b] = { 0,0, "FCMOVHI F3,F0" },
-[0x1c] = { 0,0, "FCMOVHI F4,F0" },
-[0x1d] = { 0,0, "FCMOVHI F5,F0" },
-[0x1e] = { 0,0, "FCMOVHI F6,F0" },
-[0x1f] = { 0,0, "FCMOVHI F7,F0" },
-[0x20] = { 0,0, "FCMOVNU F0,F0" },
-[0x21] = { 0,0, "FCMOVNU F1,F0" },
-[0x22] = { 0,0, "FCMOVNU F2,F0" },
-[0x23] = { 0,0, "FCMOVNU F3,F0" },
-[0x24] = { 0,0, "FCMOVNU F4,F0" },
-[0x25] = { 0,0, "FCMOVNU F5,F0" },
-[0x26] = { 0,0, "FCMOVNU F6,F0" },
-[0x27] = { 0,0, "FCMOVNU F7,F0" },
-[0x2a] = { 0,0, "FCLEX" },
-[0x2b] = { 0,0, "FINIT" },
-[0x30] = { 0,0, "FUCOMI F0,F0" },
-[0x31] = { 0,0, "FUCOMI F1,F0" },
-[0x32] = { 0,0, "FUCOMI F2,F0" },
-[0x33] = { 0,0, "FUCOMI F3,F0" },
-[0x34] = { 0,0, "FUCOMI F4,F0" },
-[0x35] = { 0,0, "FUCOMI F5,F0" },
-[0x36] = { 0,0, "FUCOMI F6,F0" },
-[0x37] = { 0,0, "FUCOMI F7,F0" },
-[0x38] = { 0,0, "FCOMI F0,F0" },
-[0x39] = { 0,0, "FCOMI F1,F0" },
-[0x3a] = { 0,0, "FCOMI F2,F0" },
-[0x3b] = { 0,0, "FCOMI F3,F0" },
-[0x3c] = { 0,0, "FCOMI F4,F0" },
-[0x3d] = { 0,0, "FCOMI F5,F0" },
-[0x3e] = { 0,0, "FCOMI F6,F0" },
-[0x3f] = { 0,0, "FCOMI F7,F0" },
-};
-
-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] = { Op_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] = { Op_R0,0, "FSTSW %OAX" },
-[0x0d] = { 0,0, "FUCOMIP F0,%f" },
-[0x0e] = { 0,0, "FCOMIP F0,%f" },
-};
-
-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+2] =
-{
-[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 %e,%r" },
-[0x101] = { RM,0, "MOVLQZX %e,%r" },
-};
-
-/*
- * 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, uint32 *lp)
-{
- ushort s;
- int32 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)
-{
- uint32 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){
- if(ip->rex&REXW)
- op = &obase[0x100]; /* MOVLQSX */
- else
- op = &obase[0x101]; /* MOVLQZX */
- 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 = (int32)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 = (int32)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) {
- uint32 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 Op_R0: /* base register must be R0 */
- if (ip->base != 0)
- goto badop;
- break;
- case Op_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;
- ip->prefix = 0; /* discard REPNE */
- break;
- case 0xF3:
- op = optabF30F;
- ip->prefix = 0; /* discard REP */
- break;
- default:
- op = nil;
- break;
- }
- if(op != nil && op[c].proto != nil)
- obase = op;
- /* 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;
- 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 */
-[AMD64_R8] = "R8",
-[AMD64_R9] = "R9",
-[AMD64_R10] = "R10",
-[AMD64_R11] = "R11",
-[AMD64_R12] = "R12",
-[AMD64_R13] = "R13",
-[AMD64_R14] = "R14",
-[AMD64_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;
- int32 offset;
- Symbol s;
- char *reg;
-
- offset = ip->disp;
- if (!findsym(ip->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s)) {
- bprint(ip, "%ux(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, "%ux%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, int32 w, int32 val)
-{
- Symbol next, tmp;
- int32 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;
- int32 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+%#ux(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)
-{
- int base;
-
- base = ip->base;
- if(base >= 0 && (ip->rex & REXB))
- base += 8;
-
- if (ip->mod == 3) {
- if (ip->osize == 'B')
- bprint(ip, (ip->rex & REXB? breg64: breg)[(uchar)ip->base]);
- else
- bprint(ip, "%s%s", ANAME(ip), reg[base]);
- return;
- }
-
- if (ip->segment)
- bprint(ip, ip->segment);
- if (ip->asize == 'E' && base == SP)
- plocal(ip);
- else {
- if (ip->base < 0)
- immediate(ip, ip->disp);
- else {
- bprint(ip, "%ux", 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)
-{
- int sharp;
- vlong v;
-
- if (ip->prefix)
- bprint(ip, "%s ", ip->prefix);
- for (; *fmt && ip->curr < ip->end; fmt++) {
- if (*fmt != '%'){
- *ip->curr++ = *fmt;
- continue;
- }
- sharp = 0;
- if(*++fmt == '#') {
- sharp = 1;
- ++fmt;
- }
- 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':
- if(!sharp)
- 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:%ux", 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 uint32 ip->imm.
- */
- v = (int32)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 = (int32)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;
-}
+++ /dev/null
-# Copyright 2012 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../Make.dist
+++ /dev/null
-// 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.h>
-
-static int mget(Map*, uvlong, void*, int);
-static int mput(Map*, uvlong, void*, int);
-static Seg* reloc(Map*, uvlong, vlong*);
-
-/*
- * routines to get/put various types
- */
-int
-geta(Map *map, uvlong addr, uvlong *x)
-{
- uint32 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, uint32 *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, uint32 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
-mget(Map *map, uvlong addr, void *buf, int size)
-{
- uvlong off;
- Seg *s;
-
- s = reloc(map, addr, (vlong*)&off);
- if (!s)
- return -1;
- if (s->rw == nil) {
- werrstr("unreadable map");
- return -1;
- }
- return s->rw(map, s, off, buf, size, 1);
-}
-
-static int
-mput(Map *map, uvlong addr, void *buf, int size)
-{
- vlong off;
- Seg *s;
-
- s = reloc(map, addr, &off);
- if (!s)
- return -1;
- if (s->rw == nil) {
- werrstr("unwritable map");
- return -1;
- }
- return s->rw(map, s, off, buf, size, 0);
-}
-
-/*
- * convert address to file offset; returns nonzero if ok
- */
-static Seg*
-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;
-}
+++ /dev/null
-// 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.
-
-#define __DARWIN_UNIX03 0
-
-#include <u.h>
-#include <sys/ptrace.h>
-#include <sys/signal.h>
-#include <mach/mach.h>
-#include <mach/mach_traps.h>
-#include <errno.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-#include <ureg_x86.h>
-#include <ureg_amd64.h>
-#undef waitpid /* want Unix waitpid, not Plan 9 */
-
-extern mach_port_t mach_reply_port(void); // should be in system headers, is not
-
-// Mach-error wrapper.
-// Takes a mach return code and converts it into 0 / -1,
-// setting errstr when it returns -1.
-
-static struct {
- int code;
- char *name;
-} macherr[] = {
- KERN_INVALID_ADDRESS, "invalid address",
- KERN_PROTECTION_FAILURE, "protection failure",
- KERN_NO_SPACE, "no space",
- KERN_INVALID_ARGUMENT, "invalid argument",
- KERN_FAILURE, "failure",
- KERN_RESOURCE_SHORTAGE, "resource shortage",
- KERN_NOT_RECEIVER, "not receiver",
- KERN_NO_ACCESS, "no access",
- KERN_MEMORY_FAILURE, "memory failure",
- KERN_MEMORY_ERROR, "memory error",
- KERN_ALREADY_IN_SET, "already in set",
- KERN_NOT_IN_SET, "not in set",
- KERN_NAME_EXISTS, "name exists",
- KERN_ABORTED, "aborted",
- KERN_INVALID_NAME, "invalid name",
- KERN_INVALID_TASK, "invalid task",
- KERN_INVALID_RIGHT, "invalid right",
- KERN_INVALID_VALUE, "invalid value",
- KERN_UREFS_OVERFLOW, "urefs overflow",
- KERN_INVALID_CAPABILITY, "invalid capability",
- KERN_RIGHT_EXISTS, "right exists",
- KERN_INVALID_HOST, "invalid host",
- KERN_MEMORY_PRESENT, "memory present",
- KERN_MEMORY_DATA_MOVED, "memory data moved",
- KERN_MEMORY_RESTART_COPY, "memory restart copy",
- KERN_INVALID_PROCESSOR_SET, "invalid processor set",
- KERN_POLICY_LIMIT, "policy limit",
- KERN_INVALID_POLICY, "invalid policy",
- KERN_INVALID_OBJECT, "invalid object",
- KERN_ALREADY_WAITING, "already waiting",
- KERN_DEFAULT_SET, "default set",
- KERN_EXCEPTION_PROTECTED, "exception protected",
- KERN_INVALID_LEDGER, "invalid ledger",
- KERN_INVALID_MEMORY_CONTROL, "invalid memory control",
- KERN_INVALID_SECURITY, "invalid security",
- KERN_NOT_DEPRESSED, "not depressed",
- KERN_TERMINATED, "terminated",
- KERN_LOCK_SET_DESTROYED, "lock set destroyed",
- KERN_LOCK_UNSTABLE, "lock unstable",
- KERN_LOCK_OWNED, "lock owned",
- KERN_LOCK_OWNED_SELF, "lock owned self",
- KERN_SEMAPHORE_DESTROYED, "semaphore destroyed",
- KERN_RPC_SERVER_TERMINATED, "rpc server terminated",
- KERN_RPC_TERMINATE_ORPHAN, "rpc terminate orphan",
- KERN_RPC_CONTINUE_ORPHAN, "rpc continue orphan",
- KERN_NOT_SUPPORTED, "not supported",
- KERN_NODE_DOWN, "node down",
- KERN_NOT_WAITING, "not waiting",
- KERN_OPERATION_TIMED_OUT, "operation timed out",
- KERN_RETURN_MAX, "return max",
-
- MACH_SEND_IN_PROGRESS, "send in progress",
- MACH_SEND_INVALID_DATA, "send invalid data",
- MACH_SEND_INVALID_DEST, "send invalid dest",
- MACH_SEND_TIMED_OUT, "send timed out",
- MACH_SEND_INTERRUPTED, "send interrupted",
- MACH_SEND_MSG_TOO_SMALL, "send msg too small",
- MACH_SEND_INVALID_REPLY, "send invalid reply",
- MACH_SEND_INVALID_RIGHT, "send invalid right",
- MACH_SEND_INVALID_NOTIFY, "send invalid notify",
- MACH_SEND_INVALID_MEMORY, "send invalid memory",
- MACH_SEND_NO_BUFFER, "send no buffer",
- MACH_SEND_TOO_LARGE, "send too large",
- MACH_SEND_INVALID_TYPE, "send invalid type",
- MACH_SEND_INVALID_HEADER, "send invalid header",
- MACH_SEND_INVALID_TRAILER, "send invalid trailer",
- MACH_SEND_INVALID_RT_OOL_SIZE, "send invalid rt ool size",
- MACH_RCV_IN_PROGRESS, "rcv in progress",
- MACH_RCV_INVALID_NAME, "rcv invalid name",
- MACH_RCV_TIMED_OUT, "rcv timed out",
- MACH_RCV_TOO_LARGE, "rcv too large",
- MACH_RCV_INTERRUPTED, "rcv interrupted",
- MACH_RCV_PORT_CHANGED, "rcv port changed",
- MACH_RCV_INVALID_NOTIFY, "rcv invalid notify",
- MACH_RCV_INVALID_DATA, "rcv invalid data",
- MACH_RCV_PORT_DIED, "rcv port died",
- MACH_RCV_IN_SET, "rcv in set",
- MACH_RCV_HEADER_ERROR, "rcv header error",
- MACH_RCV_BODY_ERROR, "rcv body error",
- MACH_RCV_INVALID_TYPE, "rcv invalid type",
- MACH_RCV_SCATTER_SMALL, "rcv scatter small",
- MACH_RCV_INVALID_TRAILER, "rcv invalid trailer",
- MACH_RCV_IN_PROGRESS_TIMED, "rcv in progress timed",
-
- MIG_TYPE_ERROR, "mig type error",
- MIG_REPLY_MISMATCH, "mig reply mismatch",
- MIG_REMOTE_ERROR, "mig remote error",
- MIG_BAD_ID, "mig bad id",
- MIG_BAD_ARGUMENTS, "mig bad arguments",
- MIG_NO_REPLY, "mig no reply",
- MIG_EXCEPTION, "mig exception",
- MIG_ARRAY_TOO_LARGE, "mig array too large",
- MIG_SERVER_DIED, "server died",
- MIG_TRAILER_ERROR, "trailer has an unknown format",
-};
-
-static int
-me(kern_return_t r)
-{
- int i;
-
- if(r == 0)
- return 0;
-
- for(i=0; i<nelem(macherr); i++){
- if(r == macherr[i].code){
- werrstr("mach: %s", macherr[i].name);
- return -1;
- }
- }
- werrstr("mach error %#x", r);
- return -1;
-}
-
-// Plan 9 and Linux do not distinguish between
-// process ids and thread ids, so the interface here doesn't either.
-// Unfortunately, Mach has three kinds of identifiers: process ids,
-// handles to tasks (processes), and handles to threads within a
-// process. All of them are small integers.
-//
-// To accommodate Mach, we employ a clumsy hack: in this interface,
-// if you pass in a positive number, that's a process id.
-// If you pass in a negative number, that identifies a thread that
-// has been previously returned by procthreadpids (it indexes
-// into the Thread table below).
-
-// Table of threads we have handles for.
-typedef struct Thread Thread;
-struct Thread
-{
- int pid;
- mach_port_t task;
- mach_port_t thread;
- int stopped;
- int exc;
- int code[10];
- Map *map;
-};
-static Thread thr[1000];
-static int nthr;
-static pthread_mutex_t mu;
-static pthread_cond_t cond;
-static void* excthread(void*);
-static void* waitthread(void*);
-static mach_port_t excport;
-
-enum {
- ExcMask = EXC_MASK_BAD_ACCESS |
- EXC_MASK_BAD_INSTRUCTION |
- EXC_MASK_ARITHMETIC |
- EXC_MASK_BREAKPOINT |
- EXC_MASK_SOFTWARE
-};
-
-// Add process pid to the thread table.
-// If it's already there, don't re-add it (unless force != 0).
-static Thread*
-addpid(int pid, int force)
-{
- int i, j;
- mach_port_t task;
- mach_port_t *thread;
- uint nthread;
- Thread *ret;
- static int first = 1;
-
- if(first){
- // Allocate a port for exception messages and
- // send all thread exceptions to that port.
- // The excthread reads that port and signals
- // us if we are waiting on that thread.
- pthread_t p;
- int err;
-
- excport = mach_reply_port();
- pthread_mutex_init(&mu, nil);
- pthread_cond_init(&cond, nil);
- err = pthread_create(&p, nil, excthread, nil);
- if (err != 0) {
- fprint(2, "pthread_create failed: %s\n", strerror(err));
- abort();
- }
- err = pthread_create(&p, nil, waitthread, (void*)(uintptr)pid);
- if (err != 0) {
- fprint(2, "pthread_create failed: %s\n", strerror(err));
- abort();
- }
- first = 0;
- }
-
- if(!force){
- for(i=0; i<nthr; i++)
- if(thr[i].pid == pid)
- return &thr[i];
- }
- if(me(task_for_pid(mach_task_self(), pid, &task)) < 0)
- return nil;
- if(me(task_threads(task, &thread, &nthread)) < 0)
- return nil;
- mach_port_insert_right(mach_task_self(), excport, excport, MACH_MSG_TYPE_MAKE_SEND);
- if(me(task_set_exception_ports(task, ExcMask,
- excport, EXCEPTION_DEFAULT, MACHINE_THREAD_STATE)) < 0){
- fprint(2, "warning: cannot set excport: %r\n");
- }
- ret = nil;
- for(j=0; j<nthread; j++){
- if(force){
- // If we're forcing a refresh, don't re-add existing threads.
- for(i=0; i<nthr; i++)
- if(thr[i].pid == pid && thr[i].thread == thread[j]){
- if(ret == nil)
- ret = &thr[i];
- goto skip;
- }
- }
- if(nthr >= nelem(thr))
- return nil;
- // TODO: We probably should save the old thread exception
- // ports for each bit and then put them back when we exit.
- // Probably the BSD signal handlers have put stuff there.
- mach_port_insert_right(mach_task_self(), excport, excport, MACH_MSG_TYPE_MAKE_SEND);
- if(me(thread_set_exception_ports(thread[j], ExcMask,
- excport, EXCEPTION_DEFAULT, MACHINE_THREAD_STATE)) < 0){
- fprint(2, "warning: cannot set excport: %r\n");
- }
- thr[nthr].pid = pid;
- thr[nthr].task = task;
- thr[nthr].thread = thread[j];
- if(ret == nil)
- ret = &thr[nthr];
- nthr++;
- skip:;
- }
- return ret;
-}
-
-static Thread*
-idtotable(int id)
-{
- if(id >= 0)
- return addpid(id, 1);
-
- id = -(id+1);
- if(id >= nthr)
- return nil;
- return &thr[id];
-}
-
-/*
-static int
-idtopid(int id)
-{
- Thread *t;
-
- if((t = idtotable(id)) == nil)
- return -1;
- return t->pid;
-}
-*/
-
-static mach_port_t
-idtotask(int id)
-{
- Thread *t;
-
- if((t = idtotable(id)) == nil)
- return -1;
- return t->task;
-}
-
-static mach_port_t
-idtothread(int id)
-{
- Thread *t;
-
- if((t = idtotable(id)) == nil)
- return -1;
- return t->thread;
-}
-
-static int machsegrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr);
-static int machregrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr);
-
-Map*
-attachproc(int id, Fhdr *fp)
-{
- Thread *t;
- Map *map;
-
- if((t = idtotable(id)) == nil)
- return nil;
- if(t->map)
- return t->map;
- map = newmap(0, 4);
- if(!map)
- return nil;
- map->pid = -((t-thr) + 1);
- if(mach->regsize)
- setmap(map, -1, 0, mach->regsize, 0, "regs", machregrw);
- setmap(map, -1, fp->txtaddr, fp->txtaddr+fp->txtsz, fp->txtaddr, "*text", machsegrw);
- setmap(map, -1, fp->dataddr, mach->utop, fp->dataddr, "*data", machsegrw);
- t->map = map;
- return map;
-}
-
-// Return list of ids for threads in id.
-int
-procthreadpids(int id, int *out, int nout)
-{
- Thread *t;
- int i, n, pid;
-
- t = idtotable(id);
- if(t == nil)
- return -1;
- pid = t->pid;
- addpid(pid, 1); // force refresh of thread list
- n = 0;
- for(i=0; i<nthr; i++) {
- if(thr[i].pid == pid) {
- if(n < nout)
- out[n] = -(i+1);
- n++;
- }
- }
- return n;
-}
-
-// Detach from proc.
-// TODO(rsc): Perhaps should unsuspend any threads and clean-up the table.
-void
-detachproc(Map *m)
-{
- free(m);
-}
-
-// Should return array of pending signals (notes)
-// but don't know how to do that on OS X.
-int
-procnotes(int pid, char ***pnotes)
-{
- USED(pid);
- *pnotes = 0;
- return 0;
-}
-
-// There must be a way to do this. Gdb can do it.
-// But I don't see, in the Apple gdb sources, how.
-char*
-proctextfile(int pid)
-{
- USED(pid);
- return nil;
-}
-
-// Read/write from a Mach data segment.
-static int
-machsegrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr)
-{
- mach_port_t task;
- int r;
-
- USED(seg);
-
- task = idtotask(map->pid);
- if(task == -1)
- return -1;
-
- if(isr){
- vm_size_t nn;
- nn = n;
- if(me(vm_read_overwrite(task, addr, n, (uintptr)v, &nn)) < 0) {
- fprint(2, "vm_read_overwrite %#llux %d to %p: %r\n", addr, n, v);
- return -1;
- }
- return nn;
- }else{
- r = vm_write(task, addr, (uintptr)v, n);
- if(r == KERN_INVALID_ADDRESS){
- // Happens when writing to text segment.
- // Change protections.
- if(me(vm_protect(task, addr, n, 0, VM_PROT_WRITE|VM_PROT_READ|VM_PROT_EXECUTE)) < 0){
- fprint(2, "vm_protect: %s\n", r);
- return -1;
- }
- r = vm_write(task, addr, (uintptr)v, n);
- }
- if(r != 0){
- me(r);
- return -1;
- }
- return n;
- }
-}
-
-// Convert Ureg offset to x86_thread_state32_t offset.
-static int
-go2darwin32(uvlong addr)
-{
- switch(addr){
- case offsetof(Ureg386, ax):
- return offsetof(x86_thread_state32_t, eax);
- case offsetof(Ureg386, bx):
- return offsetof(x86_thread_state32_t, ebx);
- case offsetof(Ureg386, cx):
- return offsetof(x86_thread_state32_t, ecx);
- case offsetof(Ureg386, dx):
- return offsetof(x86_thread_state32_t, edx);
- case offsetof(Ureg386, si):
- return offsetof(x86_thread_state32_t, esi);
- case offsetof(Ureg386, di):
- return offsetof(x86_thread_state32_t, edi);
- case offsetof(Ureg386, bp):
- return offsetof(x86_thread_state32_t, ebp);
- case offsetof(Ureg386, fs):
- return offsetof(x86_thread_state32_t, fs);
- case offsetof(Ureg386, gs):
- return offsetof(x86_thread_state32_t, gs);
- case offsetof(Ureg386, pc):
- return offsetof(x86_thread_state32_t, eip);
- case offsetof(Ureg386, cs):
- return offsetof(x86_thread_state32_t, cs);
- case offsetof(Ureg386, flags):
- return offsetof(x86_thread_state32_t, eflags);
- case offsetof(Ureg386, sp):
- return offsetof(x86_thread_state32_t, esp);
- }
- return -1;
-}
-
-// Convert Ureg offset to x86_thread_state64_t offset.
-static int
-go2darwin64(uvlong addr)
-{
- switch(addr){
- case offsetof(UregAmd64, ax):
- return offsetof(x86_thread_state64_t, rax);
- case offsetof(UregAmd64, bx):
- return offsetof(x86_thread_state64_t, rbx);
- case offsetof(UregAmd64, cx):
- return offsetof(x86_thread_state64_t, rcx);
- case offsetof(UregAmd64, dx):
- return offsetof(x86_thread_state64_t, rdx);
- case offsetof(UregAmd64, si):
- return offsetof(x86_thread_state64_t, rsi);
- case offsetof(UregAmd64, di):
- return offsetof(x86_thread_state64_t, rdi);
- case offsetof(UregAmd64, bp):
- return offsetof(x86_thread_state64_t, rbp);
- case offsetof(UregAmd64, r8):
- return offsetof(x86_thread_state64_t, r8);
- case offsetof(UregAmd64, r9):
- return offsetof(x86_thread_state64_t, r9);
- case offsetof(UregAmd64, r10):
- return offsetof(x86_thread_state64_t, r10);
- case offsetof(UregAmd64, r11):
- return offsetof(x86_thread_state64_t, r11);
- case offsetof(UregAmd64, r12):
- return offsetof(x86_thread_state64_t, r12);
- case offsetof(UregAmd64, r13):
- return offsetof(x86_thread_state64_t, r13);
- case offsetof(UregAmd64, r14):
- return offsetof(x86_thread_state64_t, r14);
- case offsetof(UregAmd64, r15):
- return offsetof(x86_thread_state64_t, r15);
- case offsetof(UregAmd64, fs):
- return offsetof(x86_thread_state64_t, fs);
- case offsetof(UregAmd64, gs):
- return offsetof(x86_thread_state64_t, gs);
- case offsetof(UregAmd64, ip):
- return offsetof(x86_thread_state64_t, rip);
- case offsetof(UregAmd64, cs):
- return offsetof(x86_thread_state64_t, cs);
- case offsetof(UregAmd64, flags):
- return offsetof(x86_thread_state64_t, rflags);
- case offsetof(UregAmd64, sp):
- return offsetof(x86_thread_state64_t, rsp);
- }
- return -1;
-}
-
-extern Mach mi386;
-
-// Read/write from fake register segment.
-static int
-machregrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr)
-{
- uint nn, count, state;
- mach_port_t thread;
- int reg;
- char buf[100];
- union {
- x86_thread_state64_t reg64;
- x86_thread_state32_t reg32;
- uchar p[1];
- } u;
- uchar *p;
-
- USED(seg);
-
- if(n > 8){
- werrstr("asked for %d-byte register", n);
- return -1;
- }
-
- thread = idtothread(map->pid);
- if(thread == -1){
- werrstr("no such id");
- return -1;
- }
-
- if(mach == &mi386) {
- count = x86_THREAD_STATE32_COUNT;
- state = x86_THREAD_STATE32;
- if((reg = go2darwin32(addr)) < 0 || reg+n > sizeof u){
- if(isr){
- memset(v, 0, n);
- return 0;
- }
- werrstr("register %llud not available", addr);
- return -1;
- }
- } else {
- count = x86_THREAD_STATE64_COUNT;
- state = x86_THREAD_STATE64;
- if((reg = go2darwin64(addr)) < 0 || reg+n > sizeof u){
- if(isr){
- memset(v, 0, n);
- return 0;
- }
- werrstr("register %llud not available", addr);
- return -1;
- }
- }
-
- if(!isr && me(thread_suspend(thread)) < 0){
- werrstr("thread suspend %#x: %r", thread);
- return -1;
- }
- nn = count;
- if(me(thread_get_state(thread, state, (void*)u.p, &nn)) < 0){
- if(!isr)
- thread_resume(thread);
- rerrstr(buf, sizeof buf);
- if(strstr(buf, "send invalid dest") != nil)
- werrstr("process exited");
- else
- werrstr("thread_get_state: %r");
- return -1;
- }
-
- p = u.p+reg;
- if(isr)
- memmove(v, p, n);
- else{
- memmove(p, v, n);
- nn = count;
- if(me(thread_set_state(thread, state, (void*)u.p, nn)) < 0){
- thread_resume(thread);
- werrstr("thread_set_state: %r");
- return -1;
- }
-
- if(me(thread_resume(thread)) < 0){
- werrstr("thread_resume: %r");
- return -1;
- }
- }
- return 0;
-}
-
-enum
-{
- FLAGS_TF = 0x100 // x86 single-step processor flag
-};
-
-// Is thread t suspended?
-static int
-threadstopped(Thread *t)
-{
- struct thread_basic_info info;
- uint size;
-
- size = sizeof info;
- if(me(thread_info(t->thread, THREAD_BASIC_INFO, (thread_info_t)&info, &size)) < 0){
- fprint(2, "threadstopped thread_info %#x: %r\n");
- return 1;
- }
- return info.suspend_count > 0;
-}
-
-// If thread t is suspended, start it up again.
-// If singlestep is set, only let it execute one instruction.
-static int
-threadstart(Thread *t, int singlestep)
-{
- int i;
- uint n;
- struct thread_basic_info info;
-
- if(!threadstopped(t))
- return 0;
-
- // Set or clear the processor single-step flag, as appropriate.
- if(mach == &mi386) {
- x86_thread_state32_t regs;
- n = x86_THREAD_STATE32_COUNT;
- if(me(thread_get_state(t->thread, x86_THREAD_STATE32,
- (thread_state_t)®s,
- &n)) < 0)
- return -1;
- if(singlestep)
- regs.eflags |= FLAGS_TF;
- else
- regs.eflags &= ~FLAGS_TF;
- if(me(thread_set_state(t->thread, x86_THREAD_STATE32,
- (thread_state_t)®s,
- x86_THREAD_STATE32_COUNT)) < 0)
- return -1;
- } else {
- x86_thread_state64_t regs;
- n = x86_THREAD_STATE64_COUNT;
- if(me(thread_get_state(t->thread, x86_THREAD_STATE64,
- (thread_state_t)®s,
- &n)) < 0)
- return -1;
- if(singlestep)
- regs.rflags |= FLAGS_TF;
- else
- regs.rflags &= ~FLAGS_TF;
- if(me(thread_set_state(t->thread, x86_THREAD_STATE64,
- (thread_state_t)®s,
- x86_THREAD_STATE64_COUNT)) < 0)
- return -1;
- }
-
- // Run.
- n = sizeof info;
- if(me(thread_info(t->thread, THREAD_BASIC_INFO, (thread_info_t)&info, &n)) < 0)
- return -1;
- for(i=0; i<info.suspend_count; i++)
- if(me(thread_resume(t->thread)) < 0)
- return -1;
- return 0;
-}
-
-// Stop thread t.
-static int
-threadstop(Thread *t)
-{
- if(threadstopped(t))
- return 0;
- if(me(thread_suspend(t->thread)) < 0)
- return -1;
- return 0;
-}
-
-// Callback for exc_server below. Called when a thread we are
-// watching has an exception like hitting a breakpoint.
-kern_return_t
-catch_exception_raise(mach_port_t eport, mach_port_t thread,
- mach_port_t task, exception_type_t exception,
- exception_data_t code, mach_msg_type_number_t ncode)
-{
- Thread *t;
- int i;
-
- USED(eport);
- USED(task);
-
- t = nil;
- for(i=0; i<nthr; i++){
- if(thr[i].thread == thread){
- t = &thr[i];
- goto havet;
- }
- }
- if(nthr > 0)
- addpid(thr[0].pid, 1);
- for(i=0; i<nthr; i++){
- if(thr[i].thread == thread){
- t = &thr[i];
- goto havet;
- }
- }
- fprint(2, "did not find thread in catch_exception_raise\n");
- return KERN_SUCCESS; // let thread continue
-
-havet:
- t->exc = exception;
- if(ncode > nelem(t->code))
- ncode = nelem(t->code);
- memmove(t->code, code, ncode*sizeof t->code[0]);
-
- // Suspend thread, so that we can look at it & restart it later.
- if(me(thread_suspend(thread)) < 0)
- fprint(2, "catch_exception_raise thread_suspend: %r\n");
-
- // Synchronize with waitstop below.
- pthread_mutex_lock(&mu);
- pthread_cond_broadcast(&cond);
- pthread_mutex_unlock(&mu);
-
- return KERN_SUCCESS;
-}
-
-// Exception watching thread, started in addpid above.
-static void*
-excthread(void *v)
-{
- USED(v);
- extern boolean_t exc_server(mach_msg_header_t *, mach_msg_header_t *);
- mach_msg_server(exc_server, 2048, excport, 0);
- return 0;
-}
-
-// Wait for pid to exit.
-static int exited;
-static void*
-waitthread(void *v)
-{
- int pid, status;
-
- pid = (int)(uintptr)v;
- waitpid(pid, &status, 0);
- exited = 1;
- // Synchronize with waitstop below.
- pthread_mutex_lock(&mu);
- pthread_cond_broadcast(&cond);
- pthread_mutex_unlock(&mu);
- return nil;
-}
-
-// Wait for thread t to stop.
-static int
-waitstop(Thread *t)
-{
- pthread_mutex_lock(&mu);
- while(!exited && !threadstopped(t))
- pthread_cond_wait(&cond, &mu);
- pthread_mutex_unlock(&mu);
- return 0;
-}
-
-int
-ctlproc(int id, char *msg)
-{
- Thread *t;
- int status;
-
- // Hang/attached dance is for debugging newly exec'ed programs.
- // After fork, the child does ctlproc("hang") before exec,
- // and the parent does ctlproc("attached") and then waitstop.
- // Using these requires the BSD ptrace interface, unlike everything
- // else we do, which uses only the Mach interface. Our goal here
- // is to do as little as possible using ptrace and then flip over to Mach.
-
- if(strcmp(msg, "hang") == 0)
- return ptrace(PT_TRACE_ME, 0, 0, 0);
-
- if(strcmp(msg, "attached") == 0){
- // The pid "id" has done a ctlproc "hang" and then
- // exec, so we should find it stoppped just before exec
- // of the new program.
- #undef waitpid
- if(waitpid(id, &status, WUNTRACED) < 0){
- fprint(2, "ctlproc attached waitpid: %r\n");
- return -1;
- }
- if(WIFEXITED(status) || !WIFSTOPPED(status)){
- fprint(2, "ctlproc attached: bad process state\n");
- return -1;
- }
-
- // Find Mach thread for pid and suspend it.
- t = addpid(id, 1);
- if(t == nil) {
- fprint(2, "ctlproc attached: addpid: %r\n");
- return -1;
- }
- if(me(thread_suspend(t->thread)) < 0){
- fprint(2, "ctlproc attached: thread_suspend: %r\n");
- return -1;
- }
-
- // Let ptrace tell the process to keep going:
- // then ptrace is out of the way and we're back in Mach land.
- if(ptrace(PT_CONTINUE, id, (caddr_t)1, 0) < 0) {
- fprint(2, "ctlproc attached: ptrace continue: %r\n");
- return -1;
- }
-
- return 0;
- }
-
- // All the other control messages require a Thread structure.
- if((t = idtotable(id)) == nil){
- werrstr("no such thread");
- return -1;
- }
-
- if(strcmp(msg, "kill") == 0)
- return ptrace(PT_KILL, t->pid, 0, 0);
-
- if(strcmp(msg, "start") == 0)
- return threadstart(t, 0);
-
- if(strcmp(msg, "stop") == 0)
- return threadstop(t);
-
- if(strcmp(msg, "startstop") == 0){
- if(threadstart(t, 0) < 0)
- return -1;
- return waitstop(t);
- }
-
- if(strcmp(msg, "step") == 0){
- if(threadstart(t, 1) < 0)
- return -1;
- return waitstop(t);
- }
-
- if(strcmp(msg, "waitstop") == 0)
- return waitstop(t);
-
- // sysstop not available on OS X
-
- werrstr("unknown control message");
- return -1;
-}
-
-char*
-procstatus(int id)
-{
- Thread *t;
-
- if((t = idtotable(id)) == nil)
- return "gone!";
-
- if(threadstopped(t))
- return "Stopped";
-
- return "Running";
-}
-
+++ /dev/null
-// This is stubbed out for the moment. Will revisit when the time comes.
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-int
-ctlproc(int pid, char *msg)
-{
- USED(pid);
- USED(msg);
-
- sysfatal("ctlproc unimplemented in DragonFly");
- return -1;
-}
-
-char*
-proctextfile(int pid)
-{
- USED(pid);
-
- sysfatal("proctextfile unimplemented in DragonFly");
- return nil;
-}
-
-char*
-procstatus(int pid)
-{
- USED(pid);
-
- sysfatal("procstatus unimplemented in DragonFly");
- return nil;
-}
-
-Map*
-attachproc(int pid, Fhdr *fp)
-{
- USED(pid);
- USED(fp);
-
- sysfatal("attachproc unimplemented in DragonFly");
- return nil;
-}
-
-void
-detachproc(Map *m)
-{
- USED(m);
-
- sysfatal("detachproc unimplemented in DragonFly");
-}
-
-int
-procthreadpids(int pid, int *p, int np)
-{
- USED(pid);
- USED(p);
- USED(np);
-
- sysfatal("procthreadpids unimplemented in DragonFly");
- return -1;
-}
+++ /dev/null
-// 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 */
- uint32 elfentry; /* start address */
- uint32 phoff; /* phdr file offset */
- uint32 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 */
- uint32 offset; /* file offset */
- uint32 vaddr; /* virtual address */
- uint32 paddr; /* physical address */
- int filesz; /* file size */
- uint32 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 {
- uint32 name; /* section name */
- uint32 type; /* SHT_... */
- uint32 flags; /* SHF_... */
- uint32 addr; /* virtual address */
- uint32 offset; /* file offset */
- uint32 size; /* section size */
- uint32 link; /* misc info */
- uint32 info; /* misc info */
- uint32 addralign; /* memory alignment */
- uint32 entsize; /* entry size if table */
-} Shdr32;
-
-typedef struct {
- uint32 name; /* section name */
- uint32 type; /* SHT_... */
- uvlong flags; /* SHF_... */
- uvlong addr; /* virtual address */
- uvlong offset; /* file offset */
- uvlong size; /* section size */
- uint32 link; /* misc info */
- uint32 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')
+++ /dev/null
-// 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.h>
-#include "elf.h"
-#include "macho.h"
-
-/*
- * All a.out header types. The dummy entry allows canonical
- * processing of the union as a sequence of int32s
- */
-
-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 */
- Machhdr machhdr; /* macho.h */
- } e;
- int32 dummy; /* padding to ensure extra int32 */
-} 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 machdotout(int, Fhdr*, ExecHdr*);
-static int armdotout(int, Fhdr*, ExecHdr*);
-static int pedotout(int, Fhdr*, ExecHdr*);
-static void setsym(Fhdr*, vlong, int32, vlong, int32, vlong, int32);
-static void setdata(Fhdr*, uvlong, int32, vlong, int32);
-static void settext(Fhdr*, uvlong, uvlong, int32, vlong);
-static void hswal(void*, int, uint32(*)(uint32));
-static uvlong _round(uvlong, uint32);
-
-/*
- * definition of per-executable file type structures
- */
-
-typedef struct Exectable{
- int32 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 */
- int32 hsize; /* header size */
- uint32 (*swal)(uint32); /* 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 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 },
- { MACH64_MAG, /* 64-bit MACH (apple mac) */
- "mach executable",
- nil,
- FAMD64,
- 0,
- &mamd64,
- sizeof(Machhdr),
- nil,
- machdotout },
- { MACH32_MAG, /* 32-bit MACH (apple mac) */
- "mach executable",
- nil,
- FI386,
- 0,
- &mi386,
- sizeof(Machhdr),
- nil,
- machdotout },
- { 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 },
- { 0x4d5a9000, /* see dosstub[] in pe.c */
- "windows PE executable",
- nil,
- FWINPE,
- 0,
- &mi386,
- sizeof(Exec), /* TODO */
- nil,
- pedotout },
- { 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;
- uint32 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(uint32), 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, uint32 (*swap)(uint32))
-{
- uint32 *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)
-{
- int32 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, fp->datoff+fp->datsz, hp->e.exechdr.syms, 0, hp->e.exechdr.spsz, 0, hp->e.exechdr.pcsz);
- 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)
-{
- int32 pgsize;
- uvlong entry;
-
- USED(unused);
-
- hswal(&hp->e, sizeof(Exec)/sizeof(int32), 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;
- union {
- char *p;
- uvlong *v;
- } u;
- u.p = (char*)&hp->e.exechdr;
- entry = beswav(*u.v);
-
- 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, fp->datoff+fp->datsz, hp->e.exechdr.syms, 0, hp->e.exechdr.spsz, 0, hp->e.exechdr.pcsz);
-
- 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)
-{
- USED(fd);
- USED(fp);
- USED(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)
-{
- USED(fd);
- USED(fp);
- USED(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)
-{
- USED(fd);
- USED(fp);
- USED(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)
-{
- USED(fd);
- USED(fp);
- USED(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);
- uint32 (*swal)(uint32);
- ushort (*swab)(ushort);
- Ehdr64 *ep;
- Phdr64 *ph, *pph;
- Shdr64 *sh;
- int i, it, id, is, phsz, shsz;
-
- /* 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);
- 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 AMD64:
- mach = &mamd64;
- fp->type = FAMD64;
- 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(uint32), swal);
-
- shsz = sizeof(Shdr64)*ep->shnum;
- sh = malloc(shsz);
- if(sh) {
- seek(fd, ep->shoff, 0);
- if(read(fd, sh, shsz) < 0) {
- free(sh);
- sh = 0;
- } else
- hswal(sh, shsz/sizeof(uint32), 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) {
- uint32 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].offset, ph[1].filesz, 0, 0, 0, ph[1].memsz);
- free(ph);
- return 1;
- }
-
- werrstr("No TEXT or DATA sections");
- free(ph);
- free(sh);
- return 0;
- }
-
- settext(fp, ep->elfentry, ph[it].vaddr, ph[it].memsz, ph[it].offset);
- pph = ph + id;
- setdata(fp, pph->vaddr, pph->filesz, pph->offset, pph->memsz - pph->filesz);
- if(is != -1)
- setsym(fp, ph[is].offset, ph[is].filesz, 0, 0, 0, ph[is].memsz);
- else if(sh != 0){
- char *buf;
- uvlong symsize = 0;
- uvlong symoff = 0;
- uvlong pclnsz = 0;
- uvlong pclnoff = 0;
-
- /* load shstrtab names */
- buf = malloc(sh[ep->shstrndx].size);
- if (buf == 0)
- goto done;
- memset(buf, 0, sh[ep->shstrndx].size);
- seek(fd, sh[ep->shstrndx].offset, 0);
- i = read(fd, buf, sh[ep->shstrndx].size);
- USED(i); // shut up ubuntu gcc
-
- for(i = 0; i < ep->shnum; i++) {
- if (strcmp(&buf[sh[i].name], ".gosymtab") == 0) {
- symsize = sh[i].size;
- symoff = sh[i].offset;
- }
- if (strcmp(&buf[sh[i].name], ".gopclntab") == 0) {
- pclnsz = sh[i].size;
- pclnoff = sh[i].offset;
- }
- }
- setsym(fp, symoff, symsize, 0, 0, pclnoff, pclnsz);
- free(buf);
- }
-done:
- free(ph);
- free(sh);
- return 1;
-}
-
-static int
-elfdotout(int fd, Fhdr *fp, ExecHdr *hp)
-{
-
- uint32 (*swal)(uint32);
- ushort (*swab)(ushort);
- Ehdr32 *ep;
- Phdr32 *ph;
- int i, it, id, is, phsz, shsz;
- Shdr32 *sh;
-
- /* 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 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(uint32), swal);
-
- shsz = sizeof(Shdr32)*ep->shnum;
- sh = malloc(shsz);
- if(sh) {
- seek(fd, ep->shoff, 0);
- if(read(fd, sh, shsz) < 0) {
- free(sh);
- sh = 0;
- } else
- hswal(sh, shsz/sizeof(uint32), 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) {
- uint32 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].offset, ph[1].filesz, 0, 0, 0, ph[1].memsz);
- free(ph);
- return 1;
- }
-
- werrstr("No TEXT or DATA sections");
- free(sh);
- 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].offset, ph[is].filesz, 0, 0, 0, ph[is].memsz);
- else if(sh != 0){
- char *buf;
- uvlong symsize = 0;
- uvlong symoff = 0;
- uvlong pclnsize = 0;
- uvlong pclnoff = 0;
-
- /* load shstrtab names */
- buf = malloc(sh[ep->shstrndx].size);
- if (buf == 0)
- goto done;
- memset(buf, 0, sh[ep->shstrndx].size);
- seek(fd, sh[ep->shstrndx].offset, 0);
- i = read(fd, buf, sh[ep->shstrndx].size);
- USED(i); // shut up ubuntu gcc
-
- for(i = 0; i < ep->shnum; i++) {
- if (strcmp(&buf[sh[i].name], ".gosymtab") == 0) {
- symsize = sh[i].size;
- symoff = sh[i].offset;
- }
- if (strcmp(&buf[sh[i].name], ".gopclntab") == 0) {
- pclnsize = sh[i].size;
- pclnoff = sh[i].offset;
- }
- }
- setsym(fp, symoff, symsize, 0, 0, pclnoff, pclnsize);
- free(buf);
- }
-done:
- free(sh);
- free(ph);
- return 1;
-}
-
-static int
-machdotout(int fd, Fhdr *fp, ExecHdr *hp)
-{
- uvlong (*swav)(uvlong);
- uint32 (*swal)(uint32);
- Machhdr *mp;
- MachCmd **cmd;
- MachSymSeg *symtab;
- MachSymSeg *pclntab;
- MachSeg64 *seg;
- MachSect64 *sect;
- MachSeg32 *seg32;
- MachSect32 *sect32;
- uvlong textsize, datasize, bsssize;
- uchar *cmdbuf;
- uchar *cmdp;
- int i, j, hdrsize;
- uint32 textva, textoff, datava, dataoff, symoff, symsize, pclnoff, pclnsize;
-
- mp = &hp->e.machhdr;
- if (leswal(mp->filetype) != MACH_EXECUTABLE_TYPE) {
- werrstr("bad MACH executable type %#ux", leswal(mp->filetype));
- return 0;
- }
-
- swal = leswal;
- swav = leswav;
-
- mp->magic = swal(mp->magic);
- mp->cputype = swal(mp->cputype);
- mp->cpusubtype = swal(mp->cpusubtype);
- mp->filetype = swal(mp->filetype);
- mp->ncmds = swal(mp->ncmds);
- mp->sizeofcmds = swal(mp->sizeofcmds);
- mp->flags = swal(mp->flags);
- mp->reserved = swal(mp->reserved);
-
- switch(mp->magic) {
- case 0xFEEDFACE: // 32-bit mach
- if (mp->cputype != MACH_CPU_TYPE_X86) {
- werrstr("bad MACH cpu type - not 386");
- return 0;
- }
- if (mp->cpusubtype != MACH_CPU_SUBTYPE_X86) {
- werrstr("bad MACH cpu subtype - not 386");
- return 0;
- }
- if (mp->filetype != MACH_EXECUTABLE_TYPE) {
- werrstr("bad MACH executable type");
- return 0;
- }
- mach = &mi386;
- fp->type = FI386;
- hdrsize = 28;
- break;
-
- case 0xFEEDFACF: // 64-bit mach
- if (mp->cputype != MACH_CPU_TYPE_X86_64) {
- werrstr("bad MACH cpu type - not amd64");
- return 0;
- }
-
- if (mp->cpusubtype != MACH_CPU_SUBTYPE_X86 && mp->cpusubtype != MACH_CPU_SUBTYPE_X86_64) {
- werrstr("bad MACH cpu subtype - not amd64");
- return 0;
- }
- mach = &mamd64;
- fp->type = FAMD64;
- hdrsize = 32;
- break;
-
- default:
- werrstr("not mach %#ux", mp->magic);
- return 0;
- }
-
- cmdbuf = malloc(mp->sizeofcmds);
- if(!cmdbuf) {
- werrstr("out of memory");
- return 0;
- }
- seek(fd, hdrsize, 0);
- if(read(fd, cmdbuf, mp->sizeofcmds) != mp->sizeofcmds) {
- free(cmdbuf);
- return 0;
- }
- cmd = malloc(mp->ncmds * sizeof(MachCmd*));
- if(!cmd) {
- free(cmdbuf);
- werrstr("out of memory");
- return 0;
- }
- cmdp = cmdbuf;
- textva = 0;
- textoff = 0;
- dataoff = 0;
- datava = 0;
- symtab = 0;
- pclntab = 0;
- textsize = 0;
- datasize = 0;
- bsssize = 0;
- symoff = 0;
- symsize = 0;
- pclnoff = 0;
- pclnsize = 0;
- for (i = 0; i < mp->ncmds; i++) {
- MachCmd *c;
-
- cmd[i] = (MachCmd*)cmdp;
- c = cmd[i];
- c->type = swal(c->type);
- c->size = swal(c->size);
- switch(c->type) {
- case MACH_SEGMENT_32:
- if(mp->magic != 0xFEEDFACE) {
- werrstr("segment 32 in mach 64");
- goto bad;
- }
- seg32 = (MachSeg32*)c;
- seg32->vmaddr = swav(seg32->vmaddr);
- seg32->vmsize = swav(seg32->vmsize);
- seg32->fileoff = swav(seg32->fileoff);
- seg32->filesize = swav(seg32->filesize);
- seg32->maxprot = swal(seg32->maxprot);
- seg32->initprot = swal(seg32->initprot);
- seg32->nsects = swal(seg32->nsects);
- seg32->flags = swal(seg32->flags);
- if (strcmp(seg32->segname, "__TEXT") == 0) {
- textva = seg32->vmaddr;
- textoff = seg32->fileoff;
- textsize = seg32->vmsize;
- sect32 = (MachSect32*)(cmdp + sizeof(MachSeg32));
- for(j = 0; j < seg32->nsects; j++, sect32++) {
- if (strcmp(sect32->sectname, "__gosymtab") == 0) {
- symoff = swal(sect32->offset);
- symsize = swal(sect32->size);
- }
- if (strcmp(sect32->sectname, "__gopclntab") == 0) {
- pclnoff = swal(sect32->offset);
- pclnsize = swal(sect32->size);
- }
- }
- }
- if (strcmp(seg32->segname, "__DATA") == 0) {
- datava = seg32->vmaddr;
- dataoff = seg32->fileoff;
- datasize = seg32->filesize;
- bsssize = seg32->vmsize - seg32->filesize;
- }
- break;
-
- case MACH_SEGMENT_64:
- if(mp->magic != 0xFEEDFACF) {
- werrstr("segment 32 in mach 64");
- goto bad;
- }
- seg = (MachSeg64*)c;
- seg->vmaddr = swav(seg->vmaddr);
- seg->vmsize = swav(seg->vmsize);
- seg->fileoff = swav(seg->fileoff);
- seg->filesize = swav(seg->filesize);
- seg->maxprot = swal(seg->maxprot);
- seg->initprot = swal(seg->initprot);
- seg->nsects = swal(seg->nsects);
- seg->flags = swal(seg->flags);
- if (strcmp(seg->segname, "__TEXT") == 0) {
- textva = seg->vmaddr;
- textoff = seg->fileoff;
- textsize = seg->vmsize;
- sect = (MachSect64*)(cmdp + sizeof(MachSeg64));
- for(j = 0; j < seg->nsects; j++, sect++) {
- if (strcmp(sect->sectname, "__gosymtab") == 0) {
- symoff = swal(sect->offset);
- symsize = swal(sect->size);
- }
- if (strcmp(sect->sectname, "__gopclntab") == 0) {
- pclnoff = swal(sect->offset);
- pclnsize = swal(sect->size);
- }
- }
- }
- if (strcmp(seg->segname, "__DATA") == 0) {
- datava = seg->vmaddr;
- dataoff = seg->fileoff;
- datasize = seg->filesize;
- bsssize = seg->vmsize - seg->filesize;
- }
- break;
- case MACH_UNIXTHREAD:
- break;
- case MACH_SYMSEG:
- if (symtab == 0) {
- symtab = (MachSymSeg*)c;
- symoff = swal(symtab->fileoff);
- symsize = swal(symtab->filesize);
- } else if (pclntab == 0) {
- pclntab = (MachSymSeg*)c;
- pclnoff = swal(pclntab->fileoff);
- pclnsize = swal(pclntab->filesize);
- }
- break;
- }
- cmdp += c->size;
- }
- if (textva == 0 || datava == 0) {
- free(cmd);
- free(cmdbuf);
- return 0;
- }
- /* compute entry by taking address after header - weird - BUG? */
- settext(fp, textva+sizeof(Machhdr) + mp->sizeofcmds, textva, textsize, textoff);
- setdata(fp, datava, datasize, dataoff, bsssize);
- if(symoff > 0)
- setsym(fp, symoff, symsize, 0, 0, pclnoff, pclnsize);
- free(cmd);
- free(cmdbuf);
- return 1;
-bad:
- free(cmd);
- free(cmdbuf);
- return 0;
-}
-
-/*
- * (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, fp->datoff+fp->datsz, hp->e.exechdr.syms, 0, hp->e.exechdr.spsz, 0, hp->e.exechdr.pcsz);
-
- 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;
-}
-
-/*
- * Structures needed to parse PE image.
- */
-typedef struct {
- uint16 Machine;
- uint16 NumberOfSections;
- uint32 TimeDateStamp;
- uint32 PointerToSymbolTable;
- uint32 NumberOfSymbols;
- uint16 SizeOfOptionalHeader;
- uint16 Characteristics;
-} IMAGE_FILE_HEADER;
-
-typedef struct {
- uint8 Name[8];
- uint32 VirtualSize;
- uint32 VirtualAddress;
- uint32 SizeOfRawData;
- uint32 PointerToRawData;
- uint32 PointerToRelocations;
- uint32 PointerToLineNumbers;
- uint16 NumberOfRelocations;
- uint16 NumberOfLineNumbers;
- uint32 Characteristics;
-} IMAGE_SECTION_HEADER;
-
-typedef struct {
- uint32 VirtualAddress;
- uint32 Size;
-} IMAGE_DATA_DIRECTORY;
-
-typedef struct {
- uint16 Magic;
- uint8 MajorLinkerVersion;
- uint8 MinorLinkerVersion;
- uint32 SizeOfCode;
- uint32 SizeOfInitializedData;
- uint32 SizeOfUninitializedData;
- uint32 AddressOfEntryPoint;
- uint32 BaseOfCode;
- uint32 BaseOfData;
- uint32 ImageBase;
- uint32 SectionAlignment;
- uint32 FileAlignment;
- uint16 MajorOperatingSystemVersion;
- uint16 MinorOperatingSystemVersion;
- uint16 MajorImageVersion;
- uint16 MinorImageVersion;
- uint16 MajorSubsystemVersion;
- uint16 MinorSubsystemVersion;
- uint32 Win32VersionValue;
- uint32 SizeOfImage;
- uint32 SizeOfHeaders;
- uint32 CheckSum;
- uint16 Subsystem;
- uint16 DllCharacteristics;
- uint32 SizeOfStackReserve;
- uint32 SizeOfStackCommit;
- uint32 SizeOfHeapReserve;
- uint32 SizeOfHeapCommit;
- uint32 LoaderFlags;
- uint32 NumberOfRvaAndSizes;
- IMAGE_DATA_DIRECTORY DataDirectory[16];
-} IMAGE_OPTIONAL_HEADER;
-
-typedef struct {
- uint16 Magic;
- uint8 MajorLinkerVersion;
- uint8 MinorLinkerVersion;
- uint32 SizeOfCode;
- uint32 SizeOfInitializedData;
- uint32 SizeOfUninitializedData;
- uint32 AddressOfEntryPoint;
- uint32 BaseOfCode;
- uint64 ImageBase;
- uint32 SectionAlignment;
- uint32 FileAlignment;
- uint16 MajorOperatingSystemVersion;
- uint16 MinorOperatingSystemVersion;
- uint16 MajorImageVersion;
- uint16 MinorImageVersion;
- uint16 MajorSubsystemVersion;
- uint16 MinorSubsystemVersion;
- uint32 Win32VersionValue;
- uint32 SizeOfImage;
- uint32 SizeOfHeaders;
- uint32 CheckSum;
- uint16 Subsystem;
- uint16 DllCharacteristics;
- uint64 SizeOfStackReserve;
- uint64 SizeOfStackCommit;
- uint64 SizeOfHeapReserve;
- uint64 SizeOfHeapCommit;
- uint32 LoaderFlags;
- uint32 NumberOfRvaAndSizes;
- IMAGE_DATA_DIRECTORY DataDirectory[16];
-} PE64_IMAGE_OPTIONAL_HEADER;
-
-static int
-match8(void *buf, char *cmp)
-{
- return strncmp((char*)buf, cmp, 8) == 0;
-}
-
-/*
- * Read from Windows PE/COFF .exe file image.
- */
-static int
-pedotout(int fd, Fhdr *fp, ExecHdr *hp)
-{
- uint32 start, magic;
- uint32 symtab, esymtab, pclntab, epclntab;
- IMAGE_FILE_HEADER fh;
- IMAGE_SECTION_HEADER sh;
- IMAGE_OPTIONAL_HEADER oh;
- PE64_IMAGE_OPTIONAL_HEADER oh64;
- uint8 sym[18];
- uint32 *valp, ib, entry;
- int i, ohoffset;
-
- USED(hp);
- seek(fd, 0x3c, 0);
- if (readn(fd, &start, sizeof(start)) != sizeof(start)) {
- werrstr("crippled PE MSDOS header");
- return 0;
- }
- start = leswal(start);
-
- seek(fd, start, 0);
- if (readn(fd, &magic, sizeof(magic)) != sizeof(magic)) {
- werrstr("no PE magic number found");
- return 0;
- }
- if (beswal(magic) != 0x50450000) { /* "PE\0\0" */
- werrstr("incorrect PE magic number");
- return 0;
- }
-
- if (readn(fd, &fh, sizeof(fh)) != sizeof(fh)) {
- werrstr("crippled PE File Header");
- return 0;
- }
- if (fh.PointerToSymbolTable == 0) {
- werrstr("zero pointer to COFF symbol table");
- return 0;
- }
-
- ohoffset = seek(fd, 0, 1);
- if (readn(fd, &oh, sizeof(oh)) != sizeof(oh)) {
- werrstr("crippled PE Optional Header");
- return 0;
- }
-
- switch(oh.Magic) {
- case 0x10b: // PE32
- fp->type = FI386;
- ib = leswal(oh.ImageBase);
- entry = leswal(oh.AddressOfEntryPoint);
- break;
- case 0x20b: // PE32+
- fp->type = FAMD64;
- seek(fd, ohoffset, 0);
- if (readn(fd, &oh64, sizeof(oh64)) != sizeof(oh64)) {
- werrstr("crippled PE32+ Optional Header");
- return 0;
- }
- ib = leswal(oh64.ImageBase);
- entry = leswal(oh64.AddressOfEntryPoint);
- break;
- default:
- werrstr("invalid PE Optional Header magic number");
- return 0;
- }
-
- fp->txtaddr = 0;
- fp->dataddr = 0;
- for (i=0; i<leswab(fh.NumberOfSections); i++) {
- if (readn(fd, &sh, sizeof(sh)) != sizeof(sh)) {
- werrstr("could not read Section Header %d", i+1);
- return 0;
- }
- if (match8(sh.Name, ".text"))
- settext(fp, ib+entry, ib+leswal(sh.VirtualAddress), leswal(sh.VirtualSize), leswal(sh.PointerToRawData));
- if (match8(sh.Name, ".data"))
- setdata(fp, ib+leswal(sh.VirtualAddress), leswal(sh.SizeOfRawData), leswal(sh.PointerToRawData), leswal(sh.VirtualSize)-leswal(sh.SizeOfRawData));
- }
- if (fp->txtaddr==0 || fp->dataddr==0) {
- werrstr("no .text or .data");
- return 0;
- }
-
- seek(fd, leswal(fh.PointerToSymbolTable), 0);
- symtab = esymtab = pclntab = epclntab = 0;
- for (i=0; i<leswal(fh.NumberOfSymbols); i++) {
- if (readn(fd, sym, sizeof(sym)) != sizeof(sym)) {
- werrstr("crippled COFF symbol %d", i);
- return 0;
- }
- valp = (uint32 *)&sym[8];
- if (match8(sym, "symtab"))
- symtab = leswal(*valp);
- if (match8(sym, "esymtab"))
- esymtab = leswal(*valp);
- if (match8(sym, "pclntab"))
- pclntab = leswal(*valp);
- if (match8(sym, "epclntab"))
- epclntab = leswal(*valp);
- }
- if (symtab==0 || esymtab==0 || pclntab==0 || epclntab==0) {
- werrstr("no symtab or esymtab or pclntab or epclntab in COFF symbol table");
- return 0;
- }
- setsym(fp, symtab, esymtab-symtab, 0, 0, pclntab, epclntab-pclntab);
-
- return 1;
-}
-
-static void
-settext(Fhdr *fp, uvlong e, uvlong a, int32 s, vlong off)
-{
- fp->txtaddr = a;
- fp->entry = e;
- fp->txtsz = s;
- fp->txtoff = off;
-}
-
-static void
-setdata(Fhdr *fp, uvlong a, int32 s, vlong off, int32 bss)
-{
- fp->dataddr = a;
- fp->datsz = s;
- fp->datoff = off;
- fp->bsssz = bss;
-}
-
-static void
-setsym(Fhdr *fp, vlong symoff, int32 symsz, vlong sppcoff, int32 sppcsz, vlong lnpcoff, int32 lnpcsz)
-{
- fp->symoff = symoff;
- fp->symsz = symsz;
-
- if(sppcoff == 0)
- sppcoff = symoff+symsz;
- fp->sppcoff = symoff;
- fp->sppcsz = sppcsz;
-
- if(lnpcoff == 0)
- lnpcoff = sppcoff + sppcsz;
- fp->lnpcoff = lnpcoff;
- fp->lnpcsz = lnpcsz;
-}
-
-static uvlong
-_round(uvlong a, uint32 b)
-{
- uvlong w;
-
- w = (a/b)*b;
- if (a!=w)
- w += b;
- return(w);
-}
+++ /dev/null
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
- * obj.c
- * routines universal to all object files
- */
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <ar.h>
-#include <mach.h>
-#include "obj.h"
-
-int _is2(char* x) { USED(x); return 0; }
-int _is7(char* x) { USED(x); return 0; }
-int _is9(char* x) { USED(x); return 0; }
-int _isk(char* x) { USED(x); return 0; }
-int _isq(char* x) { USED(x); return 0; }
-int _isv(char* x) { USED(x); return 0; }
-int _isu(char* x) { USED(x); return 0; }
-int _read2(Biobuf* b, Prog* p) { USED(b); USED(p); return 0; }
-int _read7(Biobuf* b, Prog* p) { USED(b); USED(p); return 0; }
-int _read9(Biobuf* b, Prog* p) { USED(b); USED(p); return 0; }
-int _readk(Biobuf* b, Prog* p) { USED(b); USED(p); return 0; }
-int _readq(Biobuf* b, Prog* p) { USED(b); USED(p); return 0; }
-int _readv(Biobuf* b, Prog* p) { USED(b); USED(p); return 0; }
-int _readu(Biobuf* b, Prog* p) { USED(b); USED(p); return 0; }
+++ /dev/null
-// This is stubbed out for the moment. Will revisit when the time comes.
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-int
-ctlproc(int pid, char *msg)
-{
- USED(pid);
- USED(msg);
-
- sysfatal("ctlproc unimplemented in FreeBSD");
- return -1;
-}
-
-char*
-proctextfile(int pid)
-{
- USED(pid);
-
- sysfatal("proctextfile unimplemented in FreeBSD");
- return nil;
-}
-
-char*
-procstatus(int pid)
-{
- USED(pid);
-
- sysfatal("procstatus unimplemented in FreeBSD");
- return nil;
-}
-
-Map*
-attachproc(int pid, Fhdr *fp)
-{
- USED(pid);
- USED(fp);
-
- sysfatal("attachproc unimplemented in FreeBSD");
- return nil;
-}
-
-void
-detachproc(Map *m)
-{
- USED(m);
-
- sysfatal("detachproc unimplemented in FreeBSD");
-}
-
-int
-procthreadpids(int pid, int *p, int np)
-{
- USED(pid);
- USED(p);
- USED(np);
-
- sysfatal("procthreadpids unimplemented in FreeBSD");
- return -1;
-}
+++ /dev/null
-// Derived from Plan 9 from User Space src/libmach/Linux.c
-// http://code.swtch.com/plan9port/src/tip/src/libmach/Linux.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.
-
-#include <u.h>
-#include <sys/syscall.h> /* for tkill */
-#include <unistd.h>
-#include <dirent.h>
-#include <sys/ptrace.h>
-#include <sys/signal.h>
-#include <sys/wait.h>
-#include <errno.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-#include <ureg_x86.h>
-#include <ureg_amd64.h>
-#undef waitpid
-
-// The old glibc used with crosstool compilers on thresher
-// doesn't know these numbers, but the Linux kernel
-// had them as far back as 2.6.0.
-#ifndef WSTOPPED
-#define WSTOPPED 2
-#define WCONTINUED 8
-#define WIFCONTINUED(x) ((x) == 0xffff)
-#endif
-#ifndef PTRACE_SETOPTIONS
-#define PTRACE_SETOPTIONS 0x4200
-#define PTRACE_GETEVENTMSG 0x4201
-#define PTRACE_O_TRACEFORK 0x2
-#define PTRACE_O_TRACEVFORK 0x4
-#define PTRACE_O_TRACECLONE 0x8
-#define PTRACE_O_TRACEEXEC 0x10
-#define PTRACE_O_TRACEVFORKDONE 0x20
-#define PTRACE_O_TRACEEXIT 0x40
-#define PTRACE_EVENT_FORK 0x1
-#define PTRACE_EVENT_VFORK 0x2
-#define PTRACE_EVENT_CLONE 0x3
-#define PTRACE_EVENT_EXEC 0x4
-#define PTRACE_EVENT_VFORK_DONE 0x5
-#define PTRACE_EVENT_EXIT 0x6
-#endif
-
-static Maprw ptracesegrw;
-static Maprw ptraceregrw;
-
-// /usr/include/asm-x86_64/user.h
-struct user_regs_struct {
- unsigned long r15,r14,r13,r12,rbp,rbx,r11,r10;
- unsigned long r9,r8,rax,rcx,rdx,rsi,rdi,orig_rax;
- unsigned long rip,cs,eflags;
- unsigned long rsp,ss;
- unsigned long fs_base, gs_base;
- unsigned long ds,es,fs,gs;
-};
-
-// Linux gets very upset if a debugger forgets the reported state
-// of a debugged process, so we keep everything we know about
-// a debugged process in the LinuxThread structure.
-//
-// We can poll for state changes by calling waitpid and interpreting
-// the integer status code that comes back. Wait1 does this.
-//
-// If the process is already running, it is an error to PTRACE_CONT it.
-//
-// If the process is already stopped, it is an error to stop it again.
-//
-// If the process is stopped because of a signal, the debugger must
-// relay the signal to the PTRACE_CONT call, or else the signal is
-// dropped.
-//
-// If the process exits, the debugger should detach so that the real
-// parent can reap the zombie.
-//
-// On first attach, the debugger should set a handful of flags in order
-// to catch future events like fork, clone, exec, etc.
-
-// One for every attached thread.
-typedef struct LinuxThread LinuxThread;
-struct LinuxThread
-{
- int pid;
- int tid;
- int state;
- int signal;
- int child;
- int exitcode;
-};
-
-static int trace = 0;
-
-static LinuxThread **thr;
-static int nthr;
-static int mthr;
-
-static int realpid(int pid);
-
-enum
-{
- Unknown,
- Detached,
- Attached,
- AttachStop,
- Stopped,
- Running,
- Forking,
- Vforking,
- VforkDone,
- Cloning,
- Execing,
- Exiting,
- Exited,
- Killed,
-
- NSTATE,
-};
-
-static char* statestr[NSTATE] = {
- "Unknown",
- "Detached",
- "Attached",
- "AttachStop",
- "Stopped",
- "Running",
- "Forking",
- "Vforking",
- "VforkDone",
- "Cloning",
- "Execing",
- "Exiting",
- "Exited",
- "Killed"
-};
-
-static LinuxThread*
-attachthread(int pid, int tid, int *new, int newstate)
-{
- int i, n, status;
- LinuxThread **p, *t;
- uintptr flags;
-
- if(new)
- *new = 0;
-
- for(i=0; i<nthr; i++)
- if((pid == 0 || thr[i]->pid == pid) && thr[i]->tid == tid) {
- t = thr[i];
- goto fixup;
- }
-
- if(!new)
- return nil;
-
- if(nthr >= mthr) {
- n = mthr;
- if(n == 0)
- n = 64;
- else
- n *= 2;
- p = realloc(thr, n*sizeof thr[0]);
- if(p == nil)
- return nil;
- thr = p;
- mthr = n;
- }
-
- t = malloc(sizeof *t);
- if(t == nil)
- return nil;
- memset(t, 0, sizeof *t);
-
- thr[nthr++] = t;
- if(pid == 0 && nthr > 0)
- pid = thr[0]->pid;
- t->pid = pid;
- t->tid = tid;
- t->state = newstate;
- if(trace)
- fprint(2, "new thread %d %d\n", t->pid, t->tid);
- if(new)
- *new = 1;
-
-fixup:
- if(t->state == Detached) {
- if(ptrace(PTRACE_ATTACH, tid, 0, 0) < 0) {
- fprint(2, "ptrace ATTACH %d: %r\n", tid);
- return nil;
- }
- t->state = Attached;
- }
-
- if(t->state == Attached) {
- // wait for stop, so we can set options
- if(waitpid(tid, &status, __WALL|WUNTRACED|WSTOPPED) < 0)
- return nil;
- if(!WIFSTOPPED(status)) {
- fprint(2, "waitpid %d: status=%#x not stopped\n", tid);
- return nil;
- }
- t->state = AttachStop;
- }
-
- if(t->state == AttachStop) {
- // set options so we'll find out about new threads
- flags = PTRACE_O_TRACEFORK |
- PTRACE_O_TRACEVFORK |
- PTRACE_O_TRACECLONE |
- PTRACE_O_TRACEEXEC |
- PTRACE_O_TRACEVFORKDONE;
- if(ptrace(PTRACE_SETOPTIONS, tid, 0, (void*)flags) < 0) {
- fprint(2, "ptrace PTRACE_SETOPTIONS %d: %r\n", tid);
- return nil;
- }
- t->state = Stopped;
- }
-
- return t;
-}
-
-static LinuxThread*
-findthread(int tid)
-{
- return attachthread(0, tid, nil, 0);
-}
-
-int
-procthreadpids(int pid, int *p, int np)
-{
- int i, n;
- LinuxThread *t;
-
- n = 0;
- for(i=0; i<nthr; i++) {
- t = thr[i];
- if(t->pid == pid) {
- switch(t->state) {
- case Exited:
- case Detached:
- case Killed:
- break;
-
- default:
- if(n < np)
- p[n] = t->tid;
- n++;
- break;
- }
- }
- }
- return n;
-}
-
-// Execute a single wait and update the corresponding thread.
-static int
-wait1(int nohang)
-{
- int tid, new, status, event;
- ulong data;
- LinuxThread *t;
- enum
- {
- NormalStop = 0x137f
- };
-
- if(nohang != 0)
- nohang = WNOHANG;
-
- status = 0;
- tid = waitpid(-1, &status, __WALL|WUNTRACED|WSTOPPED|WCONTINUED|nohang);
-
- if(tid < 0)
- return -1;
- if(tid == 0)
- return 0;
-
- if(trace > 0 && status != NormalStop)
- fprint(2, "TID %d: %#x\n", tid, status);
-
- t = findthread(tid);
- if(t == nil) {
- // Sometimes the kernel tells us about new threads
- // before we see the parent clone.
- t = attachthread(0, tid, &new, Stopped);
- if(t == nil) {
- fprint(2, "failed to attach to new thread %d\n", tid);
- return -1;
- }
- }
-
- if(WIFSTOPPED(status)) {
- t->state = Stopped;
- t->signal = WSTOPSIG(status);
- if(trace)
- fprint(2, "tid %d: stopped %#x%s\n", tid, status,
- status != NormalStop ? " ***" : "");
- if(t->signal == SIGTRAP && (event = status>>16) != 0) { // ptrace event
- switch(event) {
- case PTRACE_EVENT_FORK:
- t->state = Forking;
- goto child;
-
- case PTRACE_EVENT_VFORK:
- t->state = Vforking;
- goto child;
-
- case PTRACE_EVENT_CLONE:
- t->state = Cloning;
- goto child;
-
- child:
- if(ptrace(PTRACE_GETEVENTMSG, t->tid, 0, &data) < 0) {
- fprint(2, "ptrace GETEVENTMSG tid %d: %r\n", tid);
- break;
- }
- t->child = data;
- attachthread(t->pid, t->child, &new, Running);
- break;
-
- case PTRACE_EVENT_EXEC:
- t->state = Execing;
- break;
-
- case PTRACE_EVENT_VFORK_DONE:
- t->state = VforkDone;
- break;
-
- case PTRACE_EVENT_EXIT:
- // We won't see this unless we set PTRACE_O_TRACEEXIT.
- // The debuggers assume that a read or write on a Map
- // will fail for a thread that has exited. This event
- // breaks that assumption. It's not a big deal: we
- // only lose the ability to see the register state at
- // the time of exit.
- if(trace)
- fprint(2, "tid %d: exiting %#x\n", tid, status);
- t->state = Exiting;
- if(ptrace(PTRACE_GETEVENTMSG, t->tid, 0, &data) < 0) {
- fprint(2, "ptrace GETEVENTMSG tid %d: %r\n", tid);
- break;
- }
- t->exitcode = data;
- break;
- }
- }
- }
- if(WIFCONTINUED(status)) {
- if(trace)
- fprint(2, "tid %d: continued %#x\n", tid, status);
- t->state = Running;
- }
- if(WIFEXITED(status)) {
- if(trace)
- fprint(2, "tid %d: exited %#x\n", tid, status);
- t->state = Exited;
- t->exitcode = WEXITSTATUS(status);
- t->signal = -1;
- ptrace(PTRACE_DETACH, t->tid, 0, 0);
- if(trace)
- fprint(2, "tid %d: detach exited\n", tid);
- }
- if(WIFSIGNALED(status)) {
- if(trace)
- fprint(2, "tid %d: signaled %#x\n", tid, status);
- t->state = Exited;
- t->signal = WTERMSIG(status);
- t->exitcode = -1;
- ptrace(PTRACE_DETACH, t->tid, 0, 0);
- if(trace)
- fprint(2, "tid %d: detach signaled\n", tid);
- }
- return 1;
-}
-
-static int
-waitstop(LinuxThread *t)
-{
- while(t->state == Running)
- if(wait1(0) < 0)
- return -1;
- return 0;
-}
-
-// Attach to and stop all threads in process pid.
-// Must stop everyone in order to make sure we set
-// the "tell me about new threads" option in every
-// task.
-int
-attachallthreads(int pid)
-{
- int tid, foundnew, new;
- char buf[100];
- DIR *d;
- struct dirent *de;
- LinuxThread *t;
-
- if(pid == 0) {
- fprint(2, "attachallthreads(0)\n");
- return -1;
- }
-
- pid = realpid(pid);
-
- snprint(buf, sizeof buf, "/proc/%d/task", pid);
- if((d = opendir(buf)) == nil) {
- fprint(2, "opendir %s: %r\n", buf);
- return -1;
- }
-
- // Loop in case new threads are being created right now.
- // We stop every thread as we find it, so eventually
- // this has to stop (or the system runs out of procs).
- do {
- foundnew = 0;
- while((de = readdir(d)) != nil) {
- tid = atoi(de->d_name);
- if(tid == 0)
- continue;
- t = attachthread(pid, tid, &new, Detached);
- foundnew |= new;
- if(t)
- waitstop(t);
- }
- rewinddir(d);
- } while(foundnew);
- closedir(d);
-
- return 0;
-}
-
-Map*
-attachproc(int pid, Fhdr *fp)
-{
- Map *map;
-
- if(pid == 0) {
- fprint(2, "attachproc(0)\n");
- return nil;
- }
-
- if(findthread(pid) == nil && attachallthreads(pid) < 0)
- return nil;
-
- map = newmap(0, 4);
- if (!map)
- return 0;
- map->pid = pid;
- if(mach->regsize)
- setmap(map, -1, 0, mach->regsize, 0, "regs", ptraceregrw);
-// if(mach->fpregsize)
-// setmap(map, -1, mach->regsize, mach->regsize+mach->fpregsize, 0, "fpregs", ptraceregrw);
- setmap(map, -1, fp->txtaddr, fp->txtaddr+fp->txtsz, fp->txtaddr, "*text", ptracesegrw);
- setmap(map, -1, fp->dataddr, mach->utop, fp->dataddr, "*data", ptracesegrw);
- return map;
-}
-
-void
-detachproc(Map *m)
-{
- LinuxThread *t;
-
- t = findthread(m->pid);
- if(t != nil) {
- ptrace(PTRACE_DETACH, t->tid, 0, 0);
- t->state = Detached;
- if(trace)
- fprint(2, "tid %d: detachproc\n", t->tid);
- // TODO(rsc): Reclaim thread structs somehow?
- }
- free(m);
-}
-
-/* /proc/pid/stat contains
- pid
- command in parens
- 0. state
- 1. ppid
- 2. pgrp
- 3. session
- 4. tty_nr
- 5. tpgid
- 6. flags (math=4, traced=10)
- 7. minflt
- 8. cminflt
- 9. majflt
- 10. cmajflt
- 11. utime
- 12. stime
- 13. cutime
- 14. cstime
- 15. priority
- 16. nice
- 17. 0
- 18. itrealvalue
- 19. starttime
- 20. vsize
- 21. rss
- 22. rlim
- 23. startcode
- 24. endcode
- 25. startstack
- 26. kstkesp
- 27. kstkeip
- 28. pending signal bitmap
- 29. blocked signal bitmap
- 30. ignored signal bitmap
- 31. caught signal bitmap
- 32. wchan
- 33. nswap
- 34. cnswap
- 35. exit_signal
- 36. processor
-*/
-
-static int
-readstat(int pid, char *buf, int nbuf, char **f, int nf)
-{
- int fd, n;
- char *p;
-
- snprint(buf, nbuf, "/proc/%d/stat", pid);
- if((fd = open(buf, OREAD)) < 0){
- fprint(2, "open %s: %r\n", buf);
- return -1;
- }
- n = read(fd, buf, nbuf-1);
- close(fd);
- if(n <= 0){
- fprint(2, "read %s: %r\n", buf);
- return -1;
- }
- buf[n] = 0;
-
- /* command name is in parens, no parens afterward */
- p = strrchr(buf, ')');
- if(p == nil || *++p != ' '){
- fprint(2, "bad format in /proc/%d/stat\n", pid);
- return -1;
- }
- ++p;
-
- nf = tokenize(p, f, nf);
- if(0) print("code 0x%lux-0x%lux stack 0x%lux kstk 0x%lux keip 0x%lux pending 0x%lux\n",
- strtoul(f[23], 0, 0), strtoul(f[24], 0, 0), strtoul(f[25], 0, 0),
- strtoul(f[26], 0, 0), strtoul(f[27], 0, 0), strtoul(f[28], 0, 0));
-
- return nf;
-}
-
-static char*
-readstatus(int pid, char *buf, int nbuf, char *key)
-{
- int fd, n;
- char *p;
-
- snprint(buf, nbuf, "/proc/%d/status", pid);
- if((fd = open(buf, OREAD)) < 0){
- fprint(2, "open %s: %r\n", buf);
- return nil;
- }
- n = read(fd, buf, nbuf-1);
- close(fd);
- if(n <= 0){
- fprint(2, "read %s: %r\n", buf);
- return nil;
- }
- buf[n] = 0;
- p = strstr(buf, key);
- if(p)
- return p+strlen(key);
- return nil;
-}
-
-int
-procnotes(int pid, char ***pnotes)
-{
- char buf[1024], *f[40];
- int i, n, nf;
- char *s, **notes;
- ulong sigs;
- extern char *_p9sigstr(int, char*);
-
- *pnotes = nil;
- nf = readstat(pid, buf, sizeof buf, f, nelem(f));
- if(nf <= 28)
- return -1;
-
- sigs = strtoul(f[28], 0, 0) & ~(1<<SIGCONT);
- if(sigs == 0){
- *pnotes = nil;
- return 0;
- }
-
- notes = malloc(32*sizeof(char*));
- if(notes == nil)
- return -1;
- memset(notes, 0, 32*sizeof(char*));
- n = 0;
- for(i=0; i<32; i++){
- if((sigs&(1<<i)) == 0)
- continue;
- if((s = _p9sigstr(i, nil)) == nil)
- continue;
- notes[n++] = s;
- }
- *pnotes = notes;
- return n;
-}
-
-static int
-realpid(int pid)
-{
- char buf[1024], *p;
-
- p = readstatus(pid, buf, sizeof buf, "\nTgid:");
- if(p == nil)
- return pid;
- return atoi(p);
-}
-
-int
-ctlproc(int pid, char *msg)
-{
- int new;
- LinuxThread *t;
- uintptr data;
-
- while(wait1(1) > 0)
- ;
-
- if(strcmp(msg, "attached") == 0){
- t = attachthread(pid, pid, &new, Attached);
- if(t == nil)
- return -1;
- return 0;
- }
-
- if(strcmp(msg, "hang") == 0){
- if(pid == getpid())
- return ptrace(PTRACE_TRACEME, 0, 0, 0);
- werrstr("can only hang self");
- return -1;
- }
-
- t = findthread(pid);
- if(t == nil) {
- werrstr("not attached to pid %d", pid);
- return -1;
- }
- if(t->state == Exited) {
- werrstr("pid %d has exited", pid);
- return -1;
- }
- if(t->state == Killed) {
- werrstr("pid %d has been killed", pid);
- return -1;
- }
-
- if(strcmp(msg, "kill") == 0) {
- if(ptrace(PTRACE_KILL, pid, 0, 0) < 0)
- return -1;
- t->state = Killed;
- return 0;
- }
- if(strcmp(msg, "startstop") == 0){
- if(ctlproc(pid, "start") < 0)
- return -1;
- return waitstop(t);
- }
- if(strcmp(msg, "sysstop") == 0){
- if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
- return -1;
- t->state = Running;
- return waitstop(t);
- }
- if(strcmp(msg, "stop") == 0){
- if(trace > 1)
- fprint(2, "tid %d: tkill stop\n", pid);
- if(t->state == Stopped)
- return 0;
- if(syscall(__NR_tkill, pid, SIGSTOP) < 0)
- return -1;
- return waitstop(t);
- }
- if(strcmp(msg, "step") == 0){
- if(t->state == Running) {
- werrstr("cannot single-step unstopped %d", pid);
- return -1;
- }
- if(ptrace(PTRACE_SINGLESTEP, pid, 0, 0) < 0)
- return -1;
- return waitstop(t);
- }
- if(strcmp(msg, "start") == 0) {
- if(t->state == Running)
- return 0;
- data = 0;
- if(t->state == Stopped && t->signal != SIGSTOP && t->signal != SIGTRAP)
- data = t->signal;
- if(trace && data)
- fprint(2, "tid %d: continue %lud\n", pid, (ulong)data);
- if(ptrace(PTRACE_CONT, pid, 0, (void*)data) < 0)
- return -1;
- t->state = Running;
- return 0;
- }
- if(strcmp(msg, "waitstop") == 0) {
- return waitstop(t);
- }
- werrstr("unknown control message '%s'", msg);
- return -1;
-}
-
-char*
-proctextfile(int pid)
-{
- static char buf[1024], pbuf[128];
-
- snprint(pbuf, sizeof pbuf, "/proc/%d/exe", pid);
- if(readlink(pbuf, buf, sizeof buf) >= 0)
- return strdup(buf);
- if(access(pbuf, AEXIST) >= 0)
- return strdup(pbuf);
- return nil;
-}
-
-
-static int
-ptracerw(int type, int xtype, int isr, int pid, uvlong addr, void *v, uint n)
-{
- int i;
- uintptr u, a;
- uchar buf[sizeof(uintptr)];
-
- for(i=0; i<n; i+=sizeof(uintptr)){
- // Tread carefully here. On recent versions of glibc,
- // ptrace is a variadic function which means the third
- // argument will be pushed onto the stack as a uvlong.
- // This is fine on amd64 but will not work for 386.
- // We must convert addr to a uintptr.
- a = addr+i;
- if(isr){
- errno = 0;
- u = ptrace(type, pid, a, 0);
- if(errno)
- goto ptraceerr;
- if(n-i >= sizeof(uintptr))
- memmove((char*)v+i, &u, sizeof(uintptr));
- else{
- memmove(buf, &u, sizeof u);
- memmove((char*)v+i, buf, n-i);
- }
- }else{
- if(n-i >= sizeof(uintptr))
- u = *(uintptr*)((char*)v+i);
- else{
- errno = 0;
- u = ptrace(xtype, pid, a, 0);
- if(errno)
- return -1;
- memmove(buf, &u, sizeof u);
- memmove(buf, (char*)v+i, n-i);
- memmove(&u, buf, sizeof u);
- }
- if(ptrace(type, pid, a, u) < 0)
- goto ptraceerr;
- }
- }
- return 0;
-
-ptraceerr:
- werrstr("ptrace %s addr=%#llux pid=%d: %r", isr ? "read" : "write", addr, pid);
- return -1;
-}
-
-static int
-ptracesegrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr)
-{
- USED(seg);
-
- return ptracerw(isr ? PTRACE_PEEKDATA : PTRACE_POKEDATA, PTRACE_PEEKDATA,
- isr, map->pid, addr, v, n);
-}
-
-// If the debugger is compiled as an x86-64 program,
-// then all the ptrace register read/writes are done on
-// a 64-bit register set. If the target program
-// is a 32-bit program, the debugger is expected to
-// read the bottom half of the relevant registers
-// out of the 64-bit set.
-
-// Linux 32-bit is
-// BX CX DX SI DI BP AX DS ES FS GS OrigAX IP CS EFLAGS SP SS
-
-// Linux 64-bit is
-// R15 R14 R13 R12 BP BX R11 R10 R9 R8 AX CX DX SI DI OrigAX IP CS EFLAGS SP SS FSBase GSBase DS ES FS GS
-
-// Go 32-bit is
-// DI SI BP NSP BX DX CX AX GS FS ES DS TRAP ECODE PC CS EFLAGS SP SS
-
-uint go32tolinux32tab[] = {
- 4, 3, 5, 15, 0, 2, 1, 6, 10, 9, 8, 7, -1, -1, 12, 13, 14, 15, 16
-};
-static int
-go32tolinux32(uvlong addr)
-{
- int r;
-
- if(addr%4 || addr/4 >= nelem(go32tolinux32tab))
- return -1;
- r = go32tolinux32tab[addr/4];
- if(r < 0)
- return -1;
- return r*4;
-}
-
-uint go32tolinux64tab[] = {
- 14, 13, 4, 19, 5, 12, 11, 10, 26, 25, 24, 23, -1, -1, 16, 17, 18, 19, 20
-};
-static int
-go32tolinux64(uvlong addr)
-{
- int r;
-
- if(addr%4 || addr/4 >= nelem(go32tolinux64tab))
- return -1;
- r = go32tolinux64tab[addr/4];
- if(r < 0)
- return -1;
- return r*8;
-}
-
-extern Mach mi386;
-extern Mach mamd64;
-
-static int
-go2linux(uvlong addr)
-{
- if(sizeof(void*) == 4) {
- if(mach == &mi386)
- return go32tolinux32(addr);
- werrstr("unsupported architecture");
- return -1;
- }
-
- if(mach == &mi386)
- return go32tolinux64(addr);
- if(mach != &mamd64) {
- werrstr("unsupported architecture");
- return -1;
- }
-
- switch(addr){
- case offsetof(UregAmd64, ax):
- return offsetof(struct user_regs_struct, rax);
- case offsetof(UregAmd64, bx):
- return offsetof(struct user_regs_struct, rbx);
- case offsetof(UregAmd64, cx):
- return offsetof(struct user_regs_struct, rcx);
- case offsetof(UregAmd64, dx):
- return offsetof(struct user_regs_struct, rdx);
- case offsetof(UregAmd64, si):
- return offsetof(struct user_regs_struct, rsi);
- case offsetof(UregAmd64, di):
- return offsetof(struct user_regs_struct, rdi);
- case offsetof(UregAmd64, bp):
- return offsetof(struct user_regs_struct, rbp);
- case offsetof(UregAmd64, r8):
- return offsetof(struct user_regs_struct, r8);
- case offsetof(UregAmd64, r9):
- return offsetof(struct user_regs_struct, r9);
- case offsetof(UregAmd64, r10):
- return offsetof(struct user_regs_struct, r10);
- case offsetof(UregAmd64, r11):
- return offsetof(struct user_regs_struct, r11);
- case offsetof(UregAmd64, r12):
- return offsetof(struct user_regs_struct, r12);
- case offsetof(UregAmd64, r13):
- return offsetof(struct user_regs_struct, r13);
- case offsetof(UregAmd64, r14):
- return offsetof(struct user_regs_struct, r14);
- case offsetof(UregAmd64, r15):
- return offsetof(struct user_regs_struct, r15);
- case offsetof(UregAmd64, ds):
- return offsetof(struct user_regs_struct, ds);
- case offsetof(UregAmd64, es):
- return offsetof(struct user_regs_struct, es);
- case offsetof(UregAmd64, fs):
- return offsetof(struct user_regs_struct, fs);
- case offsetof(UregAmd64, gs):
- return offsetof(struct user_regs_struct, gs);
- case offsetof(UregAmd64, ip):
- return offsetof(struct user_regs_struct, rip);
- case offsetof(UregAmd64, cs):
- return offsetof(struct user_regs_struct, cs);
- case offsetof(UregAmd64, flags):
- return offsetof(struct user_regs_struct, eflags);
- case offsetof(UregAmd64, sp):
- return offsetof(struct user_regs_struct, rsp);
- case offsetof(UregAmd64, ss):
- return offsetof(struct user_regs_struct, ss);
- }
- return -1;
-}
-
-static int
-ptraceregrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr)
-{
- int laddr;
- uvlong u;
-
- USED(seg);
-
- if((laddr = go2linux(addr)) < 0){
- if(isr){
- memset(v, 0, n);
- return 0;
- }
- werrstr("register %llud not available", addr);
- return -1;
- }
-
- if(isr){
- errno = 0;
- u = ptrace(PTRACE_PEEKUSER, map->pid, laddr, 0);
- if(errno)
- goto ptraceerr;
- switch(n){
- case 1:
- *(uint8*)v = u;
- break;
- case 2:
- *(uint16*)v = u;
- break;
- case 4:
- *(uint32*)v = u;
- break;
- case 8:
- *(uint64*)v = u;
- break;
- default:
- werrstr("bad register size");
- return -1;
- }
- }else{
- switch(n){
- case 1:
- u = *(uint8*)v;
- break;
- case 2:
- u = *(uint16*)v;
- break;
- case 4:
- u = *(uint32*)v;
- break;
- case 8:
- u = *(uint64*)v;
- break;
- default:
- werrstr("bad register size");
- return -1;
- }
- if(ptrace(PTRACE_POKEUSER, map->pid, laddr, (void*)(uintptr)u) < 0)
- goto ptraceerr;
- }
- return 0;
-
-ptraceerr:
- werrstr("ptrace %s register laddr=%d pid=%d n=%d: %r", isr ? "read" : "write", laddr, map->pid, n);
- return -1;
-}
-
-char*
-procstatus(int pid)
-{
- LinuxThread *t;
-
- t = findthread(pid);
- if(t == nil)
- return "???";
-
- return statestr[t->state];
-}
+++ /dev/null
-// 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.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;
- int32 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+%#ux", 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];
- uint32 r;
-
- switch(rp->rformat)
- {
- case 'X':
- if (get4(map, rp->roffs, &r) < 0)
- return -1;
- snprint(buf, n, "%ux", 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, uint32 p, int zeros)
-{
- uint32 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, uint32 h, uint32 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(%.8ux%.8ux)", 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(%.8ux%.8ux)", h&((1<<20)-1), 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, uint32 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(%.8ux)", 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(*(uint32*)s));
-}
-
-int
-beieeedftos(char *buf, int n, void *s)
-{
- return ieeedftos(buf, n, beswal(*(uint32*)s), beswal(((uint32*)(s))[1]));
-}
-
-int
-leieeesftos(char *buf, int n, void *s)
-{
- return ieeesftos(buf, n, leswal(*(uint32*)s));
-}
-
-int
-leieeedftos(char *buf, int n, void *s)
-{
- return ieeedftos(buf, n, leswal(((uint32*)(s))[1]), leswal(*(uint32*)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;
- uint32 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;
-}
+++ /dev/null
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
- * Definitions needed for accessing MACH object headers.
- */
-
-typedef struct {
- uint32 magic; /* mach magic number identifier */
- uint32 cputype; /* cpu specifier */
- uint32 cpusubtype; /* machine specifier */
- uint32 filetype; /* type of file */
- uint32 ncmds; /* number of load commands */
- uint32 sizeofcmds; /* the size of all the load commands */
- uint32 flags; /* flags */
- uint32 reserved; /* reserved */
-} Machhdr;
-
-typedef struct {
- uint32 type; /* type of load command */
- uint32 size; /* total size in bytes */
-} MachCmd;
-
-typedef struct {
- MachCmd cmd;
- char segname[16]; /* segment name */
- uint32 vmaddr; /* memory address of this segment */
- uint32 vmsize; /* memory size of this segment */
- uint32 fileoff; /* file offset of this segment */
- uint32 filesize; /* amount to map from the file */
- uint32 maxprot; /* maximum VM protection */
- uint32 initprot; /* initial VM protection */
- uint32 nsects; /* number of sections in segment */
- uint32 flags; /* flags */
-} MachSeg32; /* for 32-bit architectures */
-
-typedef struct {
- MachCmd cmd;
- char segname[16]; /* segment name */
- uvlong vmaddr; /* memory address of this segment */
- uvlong vmsize; /* memory size of this segment */
- uvlong fileoff; /* file offset of this segment */
- uvlong filesize; /* amount to map from the file */
- uint32 maxprot; /* maximum VM protection */
- uint32 initprot; /* initial VM protection */
- uint32 nsects; /* number of sections in segment */
- uint32 flags; /* flags */
-} MachSeg64; /* for 64-bit architectures */
-
-typedef struct {
- MachCmd cmd;
- uint32 fileoff; /* file offset of this segment */
- uint32 filesize; /* amount to map from the file */
-} MachSymSeg;
-
-typedef struct {
- char sectname[16]; /* name of this section */
- char segname[16]; /* segment this section goes in */
- uint32 addr; /* memory address of this section */
- uint32 size; /* size in bytes of this section */
- uint32 offset; /* file offset of this section */
- uint32 align; /* section alignment (power of 2) */
- uint32 reloff; /* file offset of relocation entries */
- uint32 nreloc; /* number of relocation entries */
- uint32 flags; /* flags (section type and attributes)*/
- uint32 reserved1; /* reserved (for offset or index) */
- uint32 reserved2; /* reserved (for count or sizeof) */
-} MachSect32; /* for 32-bit architectures */
-
-typedef struct {
- char sectname[16]; /* name of this section */
- char segname[16]; /* segment this section goes in */
- uvlong addr; /* memory address of this section */
- uvlong size; /* size in bytes of this section */
- uint32 offset; /* file offset of this section */
- uint32 align; /* section alignment (power of 2) */
- uint32 reloff; /* file offset of relocation entries */
- uint32 nreloc; /* number of relocation entries */
- uint32 flags; /* flags (section type and attributes)*/
- uint32 reserved1; /* reserved (for offset or index) */
- uint32 reserved2; /* reserved (for count or sizeof) */
- uint32 reserved3; /* reserved */
-} MachSect64; /* for 64-bit architectures */
-
-enum {
- MACH_CPU_TYPE_X86_64 = (1<<24)|7,
- MACH_CPU_TYPE_X86 = 7,
- MACH_CPU_SUBTYPE_X86 = 3,
- MACH_CPU_SUBTYPE_X86_64 = (1<<31)|3,
- MACH_EXECUTABLE_TYPE = 2,
- MACH_SEGMENT_32 = 1, /* 32-bit mapped segment */
- MACH_SEGMENT_64 = 0x19, /* 64-bit mapped segment */
- MACH_SYMSEG = 3, /* obsolete gdb symtab, reused by go */
- MACH_UNIXTHREAD = 0x5, /* thread (for stack) */
-};
-
-
-#define MACH64_MAG ((0xcf<<24) | (0xfa<<16) | (0xed<<8) | 0xfe)
-#define MACH32_MAG ((0xce<<24) | (0xfa<<16) | (0xed<<8) | 0xfe)
+++ /dev/null
-// 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.h>
-
-Map *
-newmap(Map *map, int n)
-{
- int size;
-
- size = sizeof(Map)+(n-1)*sizeof(Seg);
- 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, Maprw *rw)
-{
- 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;
- map->seg[i].rw = rw;
- 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);
-}
-*/
-
-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;
-}
-
-int
-fdrw(Map *map, Seg *s, uvlong addr, void *v, uint n, int isread)
-{
- int tot, m;
-
- USED(map);
-
- for(tot=0; tot<n; tot+=m){
- if(isread)
- m = pread(s->fd, (uchar*)v+tot, n-tot, addr+tot);
- else
- m = pwrite(s->fd, (uchar*)v+tot, n-tot, addr+tot);
- if(m == 0){
- werrstr("short %s", isread ? "read" : "write");
- return -1;
- }
- if(m < 0){
- werrstr("%s %d at %#llux (+%#llux): %r", isread ? "read" : "write", n, addr, s->f);
- return -1;
- }
- }
- return 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[0].rw = fdrw;
- 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";
- map->seg[0].rw = fdrw;
- return map;
-}
+++ /dev/null
-// This is stubbed out for the moment. Will revisit when the time comes.
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-int
-ctlproc(int pid, char *msg)
-{
- USED(pid);
- USED(msg);
- sysfatal("ctlproc unimplemented in NetBSD");
- return -1;
-}
-
-char*
-proctextfile(int pid)
-{
- USED(pid);
- sysfatal("proctextfile unimplemented in NetBSD");
- return nil;
-}
-
-char*
-procstatus(int pid)
-{
- USED(pid);
- sysfatal("procstatus unimplemented in NetBSD");
- return nil;
-}
-
-Map*
-attachproc(int pid, Fhdr *fp)
-{
- USED(pid);
- USED(fp);
- sysfatal("attachproc unimplemented in NetBSD");
- return nil;
-}
-
-void
-detachproc(Map *m)
-{
- USED(m);
- sysfatal("detachproc unimplemented in NetBSD");
-}
-
-int
-procthreadpids(int pid, int *p, int np)
-{
- USED(pid);
- USED(p);
- USED(np);
- sysfatal("procthreadpids unimplemented in NetBSD");
- return -1;
-}
+++ /dev/null
-// 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.h>
-#include "obj.h"
-
-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;
-}
-
-/*
- * look for the next file in an archive
- */
-int
-nextar(Biobuf *bp, int offset, char *buf)
-{
- struct ar_hdr a;
- int i, r;
- int32 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;
-}
+++ /dev/null
-// 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);
+++ /dev/null
-// This is stubbed out for the moment. Will revisit when the time comes.
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-int
-ctlproc(int pid, char *msg)
-{
- USED(pid);
- USED(msg);
- sysfatal("ctlproc unimplemented in OpenBSD");
- return -1;
-}
-
-char*
-proctextfile(int pid)
-{
- USED(pid);
- sysfatal("proctextfile unimplemented in OpenBSD");
- return nil;
-}
-
-char*
-procstatus(int pid)
-{
- USED(pid);
- sysfatal("procstatus unimplemented in OpenBSD");
- return nil;
-}
-
-Map*
-attachproc(int pid, Fhdr *fp)
-{
- USED(pid);
- USED(fp);
- sysfatal("attachproc unimplemented in OpenBSD");
- return nil;
-}
-
-void
-detachproc(Map *m)
-{
- USED(m);
- sysfatal("detachproc unimplemented in OpenBSD");
-}
-
-int
-procthreadpids(int pid, int *p, int np)
-{
- USED(pid);
- USED(p);
- USED(np);
- sysfatal("procthreadpids unimplemented in OpenBSD");
- return -1;
-}
+++ /dev/null
-// This is stubbed out for the moment. Will revisit when the time comes.
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-int
-ctlproc(int pid, char *msg)
-{
- USED(pid);
- USED(msg);
-
- sysfatal("ctlproc unimplemented on Plan 9");
- return -1;
-}
-
-char*
-proctextfile(int pid)
-{
- USED(pid);
-
- sysfatal("proctextfile unimplemented on Plan 9");
- return nil;
-}
-
-char*
-procstatus(int pid)
-{
- USED(pid);
-
- sysfatal("procstatus unimplemented on Plan 9");
- return nil;
-}
-
-Map*
-attachproc(int pid, Fhdr *fp)
-{
- USED(pid);
- USED(fp);
-
- sysfatal("attachproc unimplemented on Plan 9");
- return nil;
-}
-
-void
-detachproc(Map *m)
-{
- USED(m);
-
- sysfatal("detachproc unimplemented on Plan 9");
-}
-
-int
-procthreadpids(int pid, int *p, int np)
-{
- USED(pid);
- USED(p);
- USED(np);
-
- sysfatal("procthreadpids unimplemented on Plan 9");
- return -1;
-}
-
-int
-nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
-{
- USED(rqtp);
- USED(rmtp);
-
- sysfatal("nanosleep unimplemented on Plan 9");
- return -1;
-}
+++ /dev/null
-// 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.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, marm;
-extern Machdata i386mach, armmach;
-
-/*
- * 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, },
- { "arm", /*ARM*/
- FARM,
- FARMB,
- AARM,
- &marm,
- &armmach, },
-#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, },
- { "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;
-}
+++ /dev/null
-// This is stubbed out for the moment. Will revisit when the time comes.
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-int
-ctlproc(int pid, char *msg)
-{
- USED(pid);
- USED(msg);
- sysfatal("ctlproc unimplemented in Solaris");
- return -1;
-}
-
-char*
-proctextfile(int pid)
-{
- USED(pid);
- sysfatal("proctextfile unimplemented in Solaris");
- return nil;
-}
-
-char*
-procstatus(int pid)
-{
- USED(pid);
- sysfatal("procstatus unimplemented in Solaris");
- return nil;
-}
-
-Map*
-attachproc(int pid, Fhdr *fp)
-{
- USED(pid);
- USED(fp);
- sysfatal("attachproc unimplemented in Solaris");
- return nil;
-}
-
-void
-detachproc(Map *m)
-{
- USED(m);
- sysfatal("detachproc unimplemented in Solaris");
-}
-
-int
-procthreadpids(int pid, int *p, int np)
-{
- USED(pid);
- USED(p);
- USED(np);
- sysfatal("procthreadpids unimplemented in Solaris");
- return -1;
-}
+++ /dev/null
-// 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 int32
- */
-uint32
-beswal(uint32 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 int32
- */
-uint32
-leswal(uint32 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];
-}
+++ /dev/null
-// 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.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 */
- int32 line; /* line # where it was included */
- int32 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 int32 nauto; /* number of automatics */
-static int32 nfiles; /* number of files */
-static int32 nglob; /* number of globals */
-static int32 nhist; /* number of history stack entries */
-static int32 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 uvlong firstinstr; /* as found from symtab; needed for amd64 */
-
-static void cleansyms(void);
-static int32 decodename(Biobuf*, Sym*);
-static short *encfname(char*);
-static int fline(char*, int, int32, 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*, int32*);
-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*);
-
-/*
- * Go 1.2 pcln table (also contains pcsp).
- */
-#define Go12PclnMagic 0xfffffffb
-#define Go12PclnMagicRev 0xfbffffff
-static int isgo12pcline(void);
-static uvlong go12pc2sp(uvlong);
-static int32 go12fileline(char*, int, uvlong);
-static void go12clean(void);
-static uvlong go12file2pc(char*, int);
-
-/*
- * initialize the symbol tables
- */
-int
-syminit(int fd, Fhdr *fp)
-{
- Sym *p;
- int32 i, l, size, symsz;
- vlong vl;
- Biobuf b;
- int svalsz, newformat, shift;
- uvlong (*swav)(uvlong);
- uint32 (*swal)(uint32);
- uchar buf[8], c;
-
- if(fp->symsz == 0)
- return 0;
- if(fp->type == FNONE)
- return 0;
-
- swav = beswav;
- swal = beswal;
-
- 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 %d bytes", fp->symsz);
- return -1;
- }
- Binit(&b, fd, OREAD);
- Bseek(&b, fp->symoff, 0);
- memset(buf, 0, sizeof buf);
- Bread(&b, buf, sizeof buf);
- newformat = 0;
- symsz = fp->symsz;
- if(memcmp(buf, "\xfd\xff\xff\xff\x00\x00\x00", 7) == 0) {
- swav = leswav;
- swal = leswal;
- newformat = 1;
- } else if(memcmp(buf, "\xff\xff\xff\xfd\x00\x00\x00", 7) == 0) {
- newformat = 1;
- } else if(memcmp(buf, "\xfe\xff\xff\xff\x00\x00", 6) == 0) {
- // Table format used between Go 1.0 and Go 1.1:
- // little-endian but otherwise same as the old Go 1.0 table.
- // Not likely to be seen much in practice, but easy to handle.
- swav = leswav;
- swal = leswal;
- Bseek(&b, fp->symoff+6, 0);
- symsz -= 6;
- } else {
- Bseek(&b, fp->symoff, 0);
- }
- svalsz = 0;
- if(newformat) {
- svalsz = buf[7];
- if(svalsz != 4 && svalsz != 8) {
- werrstr("invalid word size %d bytes", svalsz);
- return -1;
- }
- symsz -= 8;
- }
-
- nsym = 0;
- size = 0;
- for(p = symbols; size < symsz; p++, nsym++) {
- if(newformat) {
- // Go 1.1 format. See comment at top of ../pkg/runtime/symtab.c.
- if(Bread(&b, &c, 1) != 1)
- return symerrmsg(1, "symbol");
- if((c&0x3F) < 26)
- p->type = (c&0x3F)+ 'A';
- else
- p->type = (c&0x3F) - 26 + 'a';
- size++;
-
- if(c&0x40) {
- // Fixed-width address.
- if(svalsz == 8) {
- if(Bread(&b, &vl, 8) != 8)
- return symerrmsg(8, "symbol");
- p->value = swav(vl);
- } else {
- if(Bread(&b, &l, 4) != 4)
- return symerrmsg(4, "symbol");
- p->value = (u32int)swal(l);
- }
- size += svalsz;
- } else {
- // Varint address.
- shift = 0;
- p->value = 0;
- for(;;) {
- if(Bread(&b, buf, 1) != 1)
- return symerrmsg(1, "symbol");
- p->value |= (uint64)(buf[0]&0x7F)<<shift;
- shift += 7;
- size++;
- if((buf[0]&0x80) == 0)
- break;
- }
- }
- p->gotype = 0;
- if(c&0x80) {
- // Has Go type. Fixed-width address.
- if(svalsz == 8) {
- if(Bread(&b, &vl, 8) != 8)
- return symerrmsg(8, "symbol");
- p->gotype = swav(vl);
- } else {
- if(Bread(&b, &l, 4) != 4)
- return symerrmsg(4, "symbol");
- p->gotype = (u32int)swal(l);
- }
- size += svalsz;
- }
-
- // Name.
- p->type |= 0x80; // for decodename
- i = decodename(&b, p);
- if(i < 0)
- return -1;
- size += i;
- } else {
- // Go 1.0 format: Plan 9 format + go type symbol.
- if(fp->_magic && (fp->magic & HDR_MAGIC)){
- svalsz = 8;
- if(Bread(&b, &vl, 8) != 8)
- return symerrmsg(8, "symbol");
- p->value = swav(vl);
- }
- else{
- svalsz = 4;
- if(Bread(&b, &l, 4) != 4)
- return symerrmsg(4, "symbol");
- p->value = (u32int)swal(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);
-
- if(svalsz == 8){
- if(Bread(&b, &vl, 8) != 8)
- return symerrmsg(8, "symbol");
- p->gotype = swav(vl);
- }
- else{
- if(Bread(&b, &l, 4) != 4)
- return symerrmsg(4, "symbol");
- p->gotype = (u32int)swal(l);
- }
- size += svalsz;
- }
-
- /* 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: %d 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 %d 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 %d 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 int32
-decodename(Biobuf *bp, Sym *p)
-{
- char *cp;
- int c1, c2;
- int32 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 %d bytes", n);
- return -1;
- }
- Bseek(bp, -n, 1);
- if(Bread(bp, p->name, n) != n) {
- werrstr("can't read %d 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 %d 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;
- go12clean();
-}
-
-/*
- * 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(int32 *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)
-{
- int32 i;
- int j, nh, ng, nt;
- File *f;
- Txtsym *tp;
- Hist *hp;
- Sym *p, **ap;
-
- if(isbuilt)
- return 1;
- isbuilt = 1;
- /* allocate the tables */
- firstinstr = 0;
- 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++) {
-//print("sym %d type %c name %s value %llux\n", p-symbols, p->type, p->name, p->value);
- 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 (firstinstr == 0 || p->value < firstinstr)
- firstinstr = 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 */
-
-}
-
-/*
- * strcmp, but allow '_' to match center dot (rune 00b7 == bytes c2 b7)
- */
-int
-cdotstrcmp(char *sym, char *user)
-{
- for (;;) {
- while (*sym == *user) {
- if (*sym++ == '\0')
- return 0;
- user++;
- }
- /* unequal - but maybe '_' matches center dot */
- if (user[0] == '_' && (sym[0]&0xFF) == 0xc2 && (sym[1]&0xFF) == 0xb7) {
- /* '_' matches center dot - advance and continue */
- user++;
- sym += 2;
- continue;
- }
- break;
- }
- return *user - *sym;
-}
-
-/*
- * find a function by name
- */
-static int
-findtext(char *name, Symbol *s)
-{
- int i;
-
- for(i = 0; i < ntxt; i++) {
- if(cdotstrcmp(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)
-{
- int32 i;
-
- for(i = 0; i < nglob; i++) {
- if(cdotstrcmp(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 (cdotstrcmp(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, int32 line)
-{
- File *fp;
- int32 i;
- uvlong pc, start, end;
- short *name;
-
- if(isgo12pcline())
- return go12file2pc(file, line);
- if(buildtbls() == 0 || files == 0)
- return ~(uvlong)0;
- name = encfname(file);
- if(name == 0) { /* encode the file name */
- werrstr("file %s not found", file);
- return ~(uvlong)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 %d in file %s not found", line, file);
- return ~(uvlong)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 %d - between: %llux and %llux\n", line, start, end);
- pc = line2addr(line, start, end);
- if(pc == ~(uvlong)0) {
- werrstr("line %d not in file %s", line, file);
- return ~(uvlong)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, int32 *line)
-{
- Hist *hp;
- int offset, depth;
- int32 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.
- */
-int32
-fileline(char *str, int n, uvlong dot)
-{
- int32 line, top, bot, mid;
- File *f;
-
- if(isgo12pcline())
- return go12fileline(str, n, dot);
-
- *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, int32 line, Hist *base, Hist **ret)
-{
- Hist *start; /* start of current level */
- Hist *h; /* current entry */
- int32 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, ":%d", 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(isgo12pcline())
- return go12pc2sp(pc);
-
- if(spoff == 0)
- return ~(uvlong)0;
- currsp = 0;
- currpc = txtstart - mach->pcquant;
-
- if(pc<currpc || pc>txtend)
- return ~(uvlong)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 ~(uvlong)0;
-}
-
-/*
- * find the source file line number for a given value of the pc
- */
-int32
-pc2line(uvlong pc)
-{
- uchar *c, u;
- uvlong currpc;
- int32 currline;
-
- if(pcline == 0)
- return -1;
- currline = 0;
- if (firstinstr != 0)
- currpc = firstinstr-mach->pcquant;
- else
- currpc = txtstart-mach->pcquant;
- if(pc<currpc || pc>txtend)
- return -1;
-
- for(c = pcline; c < pclineend && currpc < pc; c++) {
- 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 currline;
-}
-
-/*
- * 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(int32 line, uvlong basepc, uvlong endpc)
-{
- uchar *c, u;
- uvlong currpc, pc;
- int32 currline;
- int32 delta, d;
- int found;
-
- if(pcline == 0 || line == 0)
- return ~(uvlong)0;
-
- currline = 0;
- currpc = txtstart-mach->pcquant;
- pc = ~(uvlong)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 ~(uvlong)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: %x (%d) Offset: %x (%d) 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
-
-// Go 1.2 pcln table
-// See golang.org/s/go12symtab.
-
-// Func layout
-#define FuncEntry (0)
-#define FuncName (pcptrsize)
-#define FuncArgs (pcptrsize+4)
-#define FuncFrame (pcptrsize+2*4)
-#define FuncPCSP (pcptrsize+3*4)
-#define FuncPCFile (pcptrsize+4*4)
-#define FuncPCLine (pcptrsize+5*4)
-
-static int32 pcquantum;
-static int32 pcptrsize;
-static uvlong (*pcswav)(uvlong);
-static uint32 (*pcswal)(uint32);
-static uvlong (*pcuintptr)(uchar*);
-static uchar *functab;
-static uint32 nfunctab;
-static uint32 *filetab;
-static uint32 nfiletab;
-
-static uint32
-xswal(uint32 v)
-{
- return (v>>24) | ((v>>8)&0xFF00) | ((v<<8)&0xFF0000) | v<<24;
-}
-
-static uvlong
-xswav(uvlong v)
-{
- return (uvlong)xswal(v)<<32 | xswal(v>>32);
-}
-
-static uvlong
-noswav(uvlong v)
-{
- return v;
-}
-
-static uint32
-noswal(uint32 v)
-{
- return v;
-}
-
-static uvlong
-readuintptr64(uchar *p)
-{
- return pcswav(*(uvlong*)p);
-}
-
-static uvlong
-readuintptr32(uchar *p)
-{
- return pcswal(*(uint32*)p);
-}
-
-static void
-go12clean(void)
-{
- pcquantum = 0;
- pcswav = nil;
- pcswal = nil;
- functab = nil;
- nfunctab = 0;
- filetab = nil;
- nfiletab = 0;
-}
-
-static void
-go12init(void)
-{
- uint32 m;
- uchar *p;
-
- if(pcquantum != 0)
- return;
- pcquantum = -1; // not go 1.2
- if(pcline == nil || pclineend - pcline < 16 ||
- pcline[4] != 0 || pcline[5] != 0 ||
- (pcline[6] != 1 && pcline[6] != 4) ||
- (pcline[7] != 4 && pcline[7] != 8))
- return;
-
- // header is magic, 00 00 pcquantum ptrsize
- m = *(uint32*)pcline;
- if(m == Go12PclnMagic) {
- pcswav = noswav;
- pcswal = noswal;
- } else {
- pcswav = xswav;
- pcswal = xswal;
- }
- pcptrsize = pcline[7];
-
- if(pcptrsize == 4)
- pcuintptr = readuintptr32;
- else
- pcuintptr = readuintptr64;
-
- nfunctab = pcuintptr(pcline+8);
- functab = pcline + 8 + pcptrsize;
-
- // functab is 2*nfunctab pointer-sized values.
- // The offset to the file table follows.
- p = functab + nfunctab*2*pcptrsize + pcptrsize;
- if(p+4 > pclineend)
- return;
- filetab = (uint32*)(pcline + pcswal(*(uint32*)p));
- if((uchar*)filetab+4 > pclineend)
- return;
-
- // File table begins with count.
- nfiletab = pcswal(filetab[0]);
- if((uchar*)(filetab + nfiletab) > pclineend)
- return;
-
- // Committed.
- pcquantum = pcline[6];
-}
-
-static int
-isgo12pcline(void)
-{
- go12init();
- return pcquantum > 0;
-}
-
-static uchar*
-go12findfunc(uvlong pc)
-{
- uchar *f, *fm;
- int32 nf, m;
-
- if(pc < pcuintptr(functab) || pc >= pcuintptr(functab+2*nfunctab*pcptrsize))
- return nil;
-
- // binary search to find func with entry <= addr.
- f = functab;
- nf = nfunctab;
- while(nf > 0) {
- m = nf/2;
- fm = f + 2*pcptrsize*m;
- if(pcuintptr(fm) <= pc && pc < pcuintptr(fm+2*pcptrsize)) {
- f = pcline + pcuintptr(fm+pcptrsize);
- if(f >= pclineend)
- return nil;
- return f;
- } else if(pc < pcuintptr(fm))
- nf = m;
- else {
- f += (m+1)*2*pcptrsize;
- nf -= m+1;
- }
- }
- return nil;
-}
-
-static uint32
-readvarint(uchar **pp)
-{
- uchar *p;
- uint32 v;
- int32 shift;
-
- v = 0;
- p = *pp;
- for(shift = 0;; shift += 7) {
- v |= (*p & 0x7F) << shift;
- if(!(*p++ & 0x80))
- break;
- }
- *pp = p;
- return v;
-}
-
-static char*
-pcstring(uint32 off)
-{
- if(off == 0 || off >= pclineend - pcline ||
- memchr(pcline + off, '\0', pclineend - (pcline + off)) == nil)
- return "?";
- return (char*)pcline+off;
-}
-
-
-static int
-step(uchar **pp, uvlong *pc, int32 *value, int first)
-{
- uint32 uvdelta, pcdelta;
- int32 vdelta;
-
- uvdelta = readvarint(pp);
- if(uvdelta == 0 && !first)
- return 0;
- if(uvdelta&1)
- uvdelta = ~(uvdelta>>1);
- else
- uvdelta >>= 1;
- vdelta = (int32)uvdelta;
- pcdelta = readvarint(pp) * pcquantum;
- *value += vdelta;
- *pc += pcdelta;
- return 1;
-}
-
-static int32
-pcvalue(uint32 off, uvlong entry, uvlong targetpc)
-{
- uvlong pc;
- int32 val;
- uchar *p;
-
- val = -1;
- pc = entry;
- if(off == 0 || off >= pclineend - pcline)
- return -1;
- p = pcline + off;
- while(step(&p, &pc, &val, pc == entry)) {
- if(targetpc < pc)
- return val;
- }
- return -1;
-}
-
-static uvlong
-go12pc2sp(uvlong pc)
-{
- uchar *f;
- uint32 off;
- uvlong entry;
- int32 sp;
-
- f = go12findfunc(pc);
- if(f == nil)
- return ~(uvlong)0;
- entry = pcuintptr(f+FuncEntry);
- off = pcswal(*(uint32*)(f+FuncPCSP));
- sp = pcvalue(off, entry, pc);
- if(sp < 0)
- return ~(uvlong)0;
- return sp;
-}
-
-static int32
-go12fileline(char *str, int n, uvlong pc)
-{
- uchar *f;
- uint32 fileoff, lineoff;
- uvlong entry;
- int lno, fno;
-
- f = go12findfunc(pc);
- if(f == nil)
- return 0;
- entry = pcuintptr(f+FuncEntry);
- fileoff = pcswal(*(uint32*)(f+FuncPCFile));
- lineoff = pcswal(*(uint32*)(f+FuncPCLine));
- lno = pcvalue(lineoff, entry, pc);
- fno = pcvalue(fileoff, entry, pc);
- if(lno < 0 || fno <= 0 || fno >= nfiletab) {
- return 0;
- }
- snprint(str, n, "%s:%d", pcstring(pcswal(filetab[fno])), lno);
- return 1;
-}
-
-static uvlong
-go12file2pc(char *file, int line)
-{
- int fno;
- int32 i, fval, lval;
- uchar *func, *fp, *lp;
- uvlong fpc, lpc, fstartpc, lstartpc, entry;
-
- // Map file to file number.
- // NOTE(rsc): Could introduce a hash table for repeated
- // lookups if anyone ever calls this.
- for(fno=1; fno<nfiletab; fno++)
- if(strcmp(pcstring(pcswal(filetab[fno])), file) == 0)
- goto havefile;
- werrstr("cannot find file");
- return ~(uvlong)0;
-
-havefile:
- // Consider each func.
- // Run file number program to find file match,
- // then run line number program to find line match.
- // Most file number programs are tiny, and most will
- // not mention the file number, so this should be fairly
- // quick.
- for(i=0; i<nfunctab; i++) {
- func = pcline + pcuintptr(functab+i*2*pcptrsize+pcptrsize);
- entry = pcuintptr(func+FuncEntry);
- fp = pcline + pcswal(*(uint32*)(func+FuncPCFile));
- lp = pcline + pcswal(*(uint32*)(func+FuncPCLine));
- fval = lval = -1;
- lpc = entry;
- fpc = lpc;
- fstartpc = fpc;
- while(step(&fp, &fpc, &fval, fpc==entry)) {
- if(fval == fno && fstartpc < fpc) {
- lstartpc = lpc;
- while(lpc < fpc && step(&lp, &lpc, &lval, lpc==entry)) {
- if(lval == line) {
- if(fstartpc <= lstartpc) {
- return lstartpc;
- }
- if(fstartpc < lpc) {
- return fstartpc;
- }
- }
- lstartpc = lpc;
- }
- }
- fstartpc = fpc;
- }
- }
- werrstr("cannot find line in file");
- return ~(uvlong)0;
-}
+++ /dev/null
-// This is stubbed out for the moment. Will revisit when the time comes.
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-int
-ctlproc(int pid, char *msg)
-{
- USED(pid);
- USED(msg);
- sysfatal("ctlproc unimplemented in Windows");
- return -1;
-}
-
-char*
-proctextfile(int pid)
-{
- USED(pid);
- sysfatal("proctextfile unimplemented in Windows");
- return nil;
-}
-
-char*
-procstatus(int pid)
-{
- USED(pid);
- sysfatal("procstatus unimplemented in Windows");
- return nil;
-}
-
-Map*
-attachproc(int pid, Fhdr *fp)
-{
- USED(pid);
- USED(fp);
- sysfatal("attachproc unimplemented in Windows");
- return nil;
-}
-
-void
-detachproc(Map *m)
-{
- USED(m);
- sysfatal("detachproc unimplemented in Windows");
-}
-
-int
-procthreadpids(int pid, int *p, int np)
-{
- USED(pid);
- USED(p);
- USED(np);
- sysfatal("procthreadpids unimplemented in Windows");
- return -1;
-}
-
-int
-pread(int fd, void *buf, int count, int offset)
-{
- int oldoffset, n;
-
- oldoffset = seek(fd, offset, 0);
- n = read(fd, buf, count);
- seek(fd, oldoffset, 0);
- return n;
-}
-
-int
-pwrite(int fd, void *buf, int count, int offset)
-{
- USED(fd);
- USED(buf);
- USED(count);
- USED(offset);
- sysfatal("pwrite unimplemented in Windows");
- return -1;
-}
-
-int
-nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
-{
- USED(rqtp);
- USED(rmtp);
- sysfatal("nanosleep unimplemented in Windows");
- return -1;
-}