URI: 
       tlibmach - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46
   DIR parent 0e3cc9f456ea49919459bf1164d0c8309a6134fa
  HTML Author: rsc <devnull@localhost>
       Date:   Mon, 19 Apr 2004 19:29:25 +0000
       
       libmach
       
       Diffstat:
         A src/libmach/FreeBSD.c               |      43 ++++++++++++++++++++++++++++++
         A src/libmach/Linux.c                 |     450 +++++++++++++++++++++++++++++++
         A src/libmach/Notes                   |      13 +++++++++++++
         A src/libmach/Notes.stab              |     166 +++++++++++++++++++++++++++++++
         A src/libmach/crack.c                 |      91 +++++++++++++++++++++++++++++++
         A src/libmach/crackelf.c              |     342 +++++++++++++++++++++++++++++++
         A src/libmach/crackmacho.c            |     198 +++++++++++++++++++++++++++++++
         A src/libmach/dwarf.h                 |     460 +++++++++++++++++++++++++++++++
         A src/libmach/dwarf386.c              |      24 ++++++++++++++++++++++++
         A src/libmach/dwarfabbrev.c           |     129 +++++++++++++++++++++++++++++++
         A src/libmach/dwarfaranges.c          |      63 +++++++++++++++++++++++++++++++
         A src/libmach/dwarfcfa.c              |     391 ++++++++++++++++++++++++++++++
         A src/libmach/dwarfdump.c             |     138 ++++++++++++++++++++++++++++++
         A src/libmach/dwarfeval.c             |      62 +++++++++++++++++++++++++++++++
         A src/libmach/dwarfget.c              |     217 +++++++++++++++++++++++++++++++
         A src/libmach/dwarfinfo.c             |     646 +++++++++++++++++++++++++++++++
         A src/libmach/dwarfopen.c             |     107 +++++++++++++++++++++++++++++++
         A src/libmach/dwarfpc.c               |     338 +++++++++++++++++++++++++++++++
         A src/libmach/dwarfpubnames.c         |      76 +++++++++++++++++++++++++++++++
         A src/libmach/elf.c                   |     405 +++++++++++++++++++++++++++++++
         A src/libmach/elf.h                   |     233 +++++++++++++++++++++++++++++++
         A src/libmach/elfcore.h               |     142 +++++++++++++++++++++++++++++++
         A src/libmach/elfcorefreebsd386.c     |      89 +++++++++++++++++++++++++++++++
         A src/libmach/elfcorelinux386.c       |      95 ++++++++++++++++++++++++++++++
         A src/libmach/elfdump.c               |     133 +++++++++++++++++++++++++++++++
         A src/libmach/elfdynsym.c             |       7 +++++++
         A src/libmach/fpformat.c              |      65 +++++++++++++++++++++++++++++++
         A src/libmach/frame.c                 |     130 +++++++++++++++++++++++++++++++
         A src/libmach/hexify.c                |      20 ++++++++++++++++++++
         A src/libmach/ieee.c                  |     169 +++++++++++++++++++++++++++++++
         A src/libmach/loc.c                   |     253 +++++++++++++++++++++++++++++++
         A src/libmach/localaddr.c             |      56 +++++++++++++++++++++++++++++++
         A src/libmach/mach.c                  |      30 ++++++++++++++++++++++++++++++
         A src/libmach/mach386.c               |    1786 ++++++++++++++++++++++++++++++
         A src/libmach/macho.c                 |     128 +++++++++++++++++++++++++++++++
         A src/libmach/macho.h                 |      71 +++++++++++++++++++++++++++++++
         A src/libmach/machocorepower.c        |     173 +++++++++++++++++++++++++++++++
         A src/libmach/machodump.c             |      93 +++++++++++++++++++++++++++++++
         A src/libmach/machpower.c             |    1409 ++++++++++++++++++++++++++++++
         A src/libmach/map.c                   |     306 +++++++++++++++++++++++++++++++
         A src/libmach/mkfile                  |      58 ++++++++++++++++++++++++++++++
         A src/libmach/nm.c                    |     289 +++++++++++++++++++++++++++++++
         A src/libmach/regs.c                  |      59 +++++++++++++++++++++++++++++++
         A src/libmach/stabs.c                 |      54 +++++++++++++++++++++++++++++++
         A src/libmach/stabs.h                 |     117 +++++++++++++++++++++++++++++++
         A src/libmach/swap.c                  |     118 +++++++++++++++++++++++++++++++
         A src/libmach/sym.c                   |     478 +++++++++++++++++++++++++++++++
         A src/libmach/symdwarf.c              |     466 +++++++++++++++++++++++++++++++
         A src/libmach/symelf.c                |     103 +++++++++++++++++++++++++++++++
         A src/libmach/symmacho.c              |      50 +++++++++++++++++++++++++++++++
         A src/libmach/symstabs.c              |     401 +++++++++++++++++++++++++++++++
         A src/libmach/ureg386.h               |      45 +++++++++++++++++++++++++++++++
         A src/libmach/uregpower.h             |      54 +++++++++++++++++++++++++++++++
       
       53 files changed, 12039 insertions(+), 0 deletions(-)
       ---
   DIR diff --git a/src/libmach/FreeBSD.c b/src/libmach/FreeBSD.c
       t@@ -0,0 +1,43 @@
       +/*
       + * process interface for FreeBSD 
       + */
       +
       +#include <u.h>
       +#include <sys/ptrace.h>
       +#include <sys/types.h>
       +#include <sys/wait.h>
       +#include <signal.h>
       +#include <errno.h>
       +#include <libc.h>
       +#include <mach.h>
       +#include "ureg386.h"
       +
       +void
       +unmapproc(Map*)
       +{
       +}
       +
       +int
       +mapproc(int, Map*, Regs**)
       +{
       +}
       +
       +int
       +detachproc(int)
       +{
       +}
       +
       +int
       +procnotes(int, char***)
       +{
       +}
       +
       +int
       +ctlproc(int, char*)
       +{
       +}
       +
       +char*
       +proctextfile(int)
       +{
       +}
   DIR diff --git a/src/libmach/Linux.c b/src/libmach/Linux.c
       t@@ -0,0 +1,450 @@
       +/*
       + * process interface for Linux.
       + * 
       + * Uses ptrace for registers and data,
       + * /proc for some process status.
       + * There's not much point to worrying about
       + * byte order here -- using ptrace means
       + * we're running on the architecture we're debugging,
       + * unless truly weird stuff is going on.
       + *
       + * It is tempting to use /proc/%d/mem along with
       + * the sp and pc in the stat file to get a stack trace
       + * without attaching to the program, but unfortunately
       + * you can't read the mem file unless you've attached.
       + */
       +
       +#include <u.h>
       +#include <sys/ptrace.h>
       +#include <sys/types.h>
       +#include <sys/wait.h>
       +#include <signal.h>
       +#include <errno.h>
       +#include <libc.h>
       +#include <mach.h>
       +#include "ureg386.h"
       +
       +Mach *machcpu = &mach386;
       +
       +typedef struct PtraceRegs PtraceRegs;
       +
       +struct PtraceRegs
       +{
       +        Regs r;
       +        int pid;
       +};
       +
       +static int ptracerw(Map*, Seg*, ulong, void*, uint, int);
       +static int ptraceregrw(Regs*, char*, ulong*, int);
       +
       +void
       +unmapproc(Map *map)
       +{
       +        int i;
       +
       +        if(map == nil)
       +                return;
       +        for(i=0; i<map->nseg; i++)
       +                while(i<map->nseg && map->seg[i].pid){
       +                        map->nseg--;
       +                        memmove(&map->seg[i], &map->seg[i+1], 
       +                                (map->nseg-i)*sizeof(map->seg[0]));
       +                }
       +}
       +
       +int
       +mapproc(int pid, Map *map, Regs **rp)
       +{
       +        Seg s;
       +        PtraceRegs *r;
       +
       +        if(ptrace(PTRACE_ATTACH, pid, 0, 0) < 0)
       +        if(ptrace(PTRACE_PEEKUSER, pid, 0, 0) < 0)
       +        if(ptrace(PTRACE_ATTACH, pid, 0, 0) < 0){
       +                werrstr("ptrace attach %d: %r", pid);
       +                return -1;
       +        }
       +
       +        if(ctlproc(pid, "waitstop") < 0){
       +                ptrace(PTRACE_DETACH, pid, 0, 0);
       +                return -1;
       +        }
       +
       +        memset(&s, 0, sizeof s);
       +        s.base = 0;
       +        s.size = 0xFFFFFFFF;
       +        s.offset = 0;
       +        s.name = "data";
       +        s.file = nil;
       +        s.rw = ptracerw;
       +        s.pid = pid;
       +        if(addseg(map, s) < 0)
       +                return -1;
       +
       +        if((r = mallocz(sizeof(PtraceRegs), 1)) == nil)
       +                return -1;
       +        r->r.rw = ptraceregrw;
       +        r->pid = pid;
       +        *rp = (Regs*)r;
       +        return 0;
       +}
       +
       +int
       +detachproc(int pid)
       +{
       +        return ptrace(PTRACE_DETACH, pid, 0, 0);
       +}
       +
       +static int
       +ptracerw(Map *map, Seg *seg, ulong addr, void *v, uint n, int isr)
       +{
       +        int i;
       +        u32int u;
       +        uchar buf[4];
       +
       +        addr += seg->base;
       +        for(i=0; i<n; i+=4){
       +                if(isr){
       +                        errno = 0;
       +                        u = ptrace(PTRACE_PEEKDATA, seg->pid, addr+i, 0);
       +                        if(errno)
       +                                goto ptraceerr;
       +                        if(n-i >= 4)
       +                                *(u32int*)((char*)v+i) = u;
       +                        else{
       +                                *(u32int*)buf = u;
       +                                memmove((char*)v+i, buf, n-i);
       +                        }
       +                }else{
       +                        if(n-i >= 4)
       +                                u = *(u32int*)((char*)v+i);
       +                        else{
       +                                errno = 0;
       +                                u = ptrace(PTRACE_PEEKDATA, seg->pid, addr+i, 0);
       +                                if(errno)
       +                                        return -1;
       +                                *(u32int*)buf = u;
       +                                memmove(buf, (char*)v+i, n-i);
       +                                u = *(u32int*)buf;
       +                        }
       +                        if(ptrace(PTRACE_POKEDATA, seg->pid, addr+i, &u) < 0)
       +                                goto ptraceerr;
       +                }
       +        }
       +        return 0;
       +
       +ptraceerr:
       +        werrstr("ptrace: %r");
       +        return -1;
       +}
       +
       +static char* linuxregs[] = {
       +        "BX",
       +        "CX",
       +        "DX",
       +        "SI",
       +        "DI",
       +        "BP",
       +        "AX",
       +        "DS",
       +        "ES",
       +        "FS",
       +        "GS",
       +        "OAX",
       +        "PC",
       +        "CS",
       +        "EFLAGS",
       +        "SP",
       +        "SS",
       +};
       +
       +static ulong
       +reg2linux(char *reg)
       +{
       +        int i;
       +
       +        for(i=0; i<nelem(linuxregs); i++)
       +                if(strcmp(linuxregs[i], reg) == 0)
       +                        return 4*i;
       +        return ~(ulong)0;
       +}
       +
       +static int
       +ptraceregrw(Regs *regs, char *name, ulong *val, int isr)
       +{
       +        int pid;
       +        ulong addr;
       +        u32int u;
       +
       +        pid = ((PtraceRegs*)regs)->pid;
       +        addr = reg2linux(name);
       +        if(~addr == 0){
       +                if(isr){
       +                        *val = ~(ulong)0;
       +                        return 0;
       +                }
       +                werrstr("register not available");
       +                return -1;
       +        }
       +        if(isr){
       +                errno = 0;
       +                u = ptrace(PTRACE_PEEKUSER, pid, addr, 0);
       +                if(errno)
       +                        goto ptraceerr;
       +                *val = u;
       +        }else{
       +                u = *val;
       +                if(ptrace(PTRACE_POKEUSER, pid, addr, &u) < 0)
       +                        goto ptraceerr;
       +        }
       +        return 0;
       +
       +ptraceerr:
       +        werrstr("ptrace: %r");
       +        return -1;
       +}
       +
       +static int
       +isstopped(int pid)
       +{
       +        char buf[1024];
       +        int fd, n;
       +        char *p;
       +
       +        snprint(buf, sizeof buf, "/proc/%d/stat", pid);
       +        if((fd = open(buf, OREAD)) < 0)
       +                return 0;
       +        n = read(fd, buf, sizeof buf-1);
       +        close(fd);
       +        if(n <= 0)
       +                return 0;
       +        buf[n] = 0;
       +
       +        /* command name is in parens, no parens afterward */
       +        p = strrchr(buf, ')');
       +        if(p == nil || *++p != ' ')
       +                return 0;
       +        ++p;
       +
       +        /* next is state - T is stopped for tracing */
       +        return *p == 'T';
       +}
       +
       +/* /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
       +*/
       +
       +
       +int
       +procnotes(int pid, char ***pnotes)
       +{
       +        char buf[1024], *f[40];
       +        int fd, i, n, nf;
       +        char *p, *s, **notes;
       +        ulong sigs;
       +        extern char *_p9sigstr(int, char*);
       +
       +        *pnotes = nil;
       +        snprint(buf, sizeof buf, "/proc/%d/stat", pid);
       +        if((fd = open(buf, OREAD)) < 0){
       +                fprint(2, "open %s: %r\n", buf);
       +                return -1;
       +        }
       +        n = read(fd, buf, sizeof buf-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, nelem(f));
       +        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));
       +        if(nf <= 28)
       +                return -1;
       +
       +        sigs = strtoul(f[28], 0, 0) & ~(1<<SIGCONT);
       +        if(sigs == 0){
       +                *pnotes = nil;
       +                return 0;
       +        }
       +
       +        notes = mallocz(32*sizeof(char*), 0);
       +        if(notes == nil)
       +                return -1;
       +        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;
       +}
       +
       +#undef waitpid
       +
       +int
       +ctlproc(int pid, char *msg)
       +{
       +        int p, status;
       +
       +        if(strcmp(msg, "hang") == 0){
       +                if(pid == getpid())
       +                        return ptrace(PTRACE_TRACEME, 0, 0, 0);
       +                werrstr("can only hang self");
       +                return -1;
       +        }
       +        if(strcmp(msg, "kill") == 0)
       +                return ptrace(PTRACE_KILL, pid, 0, 0);
       +        if(strcmp(msg, "startstop") == 0){
       +                if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
       +                        return -1;
       +                goto waitstop;
       +        }
       +        if(strcmp(msg, "sysstop") == 0){
       +                if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
       +                        return -1;
       +                goto waitstop;
       +        }
       +        if(strcmp(msg, "stop") == 0){
       +                if(kill(pid, SIGSTOP) < 0)
       +                        return -1;
       +                goto waitstop;
       +        }
       +        if(strcmp(msg, "waitstop") == 0){
       +        waitstop:
       +                if(isstopped(pid))
       +                        return 0;
       +                for(;;){
       +                        p = waitpid(pid, &status, WUNTRACED);
       +                        if(p <= 0)
       +                                return -1;
       +                        if(WIFEXITED(status) || WIFSTOPPED(status))
       +                                return 0;
       +                }
       +        }
       +        if(strcmp(msg, "start") == 0)
       +                return ptrace(PTRACE_CONT, pid, 0, 0);
       +        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 buf;
       +        if(access(pbuf, AEXIST) >= 0)
       +                return pbuf;
       +        return nil;
       +}
       +
       +
       +#if 0
       +        snprint(buf, sizeof buf, "/proc/%d/maps", pid);
       +        if((b = Bopen(buf, OREAD)) == nil){
       +                werrstr("open %s: %r", buf);
       +                return -1;
       +        }
       +
       +/*
       +        08048000-08056000 r-xp 00000000 03:0c 64593      /usr/sbin/gpm
       +        08056000-08058000 rw-p 0000d000 03:0c 64593      /usr/sbin/gpm
       +        08058000-0805b000 rwxp 00000000 00:00 0
       +        40000000-40013000 r-xp 00000000 03:0c 4165       /lib/ld-2.2.4.so
       +        40013000-40015000 rw-p 00012000 03:0c 4165       /lib/ld-2.2.4.so
       +        4001f000-40135000 r-xp 00000000 03:0c 45494      /lib/libc-2.2.4.so
       +        40135000-4013e000 rw-p 00115000 03:0c 45494      /lib/libc-2.2.4.so
       +        4013e000-40142000 rw-p 00000000 00:00 0
       +        bffff000-c0000000 rwxp 00000000 00:00 0
       +*/
       +
       +        file = nil;
       +        while((p = Brdline(b, '\n')) != nil){
       +                p[Blinelen(b)-1] = 0;
       +                memset(f, 0, sizeof f);
       +                if((nf = getfields(p, f, 6, 1, " ")) < 5)
       +                        continue;
       +                base = strtoul(f[0], &p, 16);
       +                if(*p != '-')
       +                        continue;
       +                end = strtoul(p+1, &p, 16);
       +                if(*p != 0)
       +                        continue;
       +                offset = strtoul(f[2], &p, 16);
       +                if(*p != 0)
       +                        continue;
       +                if(nf == 6)
       +                        file = f[5];
       +                zero = atoi(f[4]) == 0;
       +                print("%lux-%lux %lux %s %s\n", base, end, offset, zero ? "data" : "text", file ? file : "");
       +                s.base = base;
       +                s.size = end - base;
       +                s.offset = offset;
       +                s.name = zero ? "data" : "text";
       +                s.file = strdup(file);
       +                s.rw = ptracerw;
       +                s.pid = pid;
       +                if(addseg(map, s) < 0){
       +                        Bterm(b);
       +                        ptrace(PTRACE_DETACH, pid, 0, 0);
       +                        return -1;
       +                }
       +        }
       +        Bterm(b);
       +#endif
       +
   DIR diff --git a/src/libmach/Notes b/src/libmach/Notes
       t@@ -0,0 +1,13 @@
       +
       +TODO ===============
       +
       +Move 386 crap out of symdwarf.c, symstabs.c.
       +Implement line2pc in dwarf.c.
       +Parse ELF .dynamic section for a few more symbols.
       +
       +Add stabs support to acidtypes.
       +Handle multiple symbol files better in acid.
       +Write acid code to walk dynamic linking tables.
       +
       +Write lax command-line parsing code for acid, db.
       +
   DIR diff --git a/src/libmach/Notes.stab b/src/libmach/Notes.stab
       t@@ -0,0 +1,166 @@
       +stabs
       +
       +N_MAIN with name "main" to identify entry function
       +N_SO source file.  might be preceded by dir ending in /
       +        value is code ptr
       +        empty string means source done
       +N_SOL source include file, value = text addr of where this starts
       +N_SLINE start of source line
       +        no name
       +        desc = line number
       +        value = code addr for that line
       +
       +N_FUN (36) function def
       +        'F' global 'f' local
       +        value = addr
       +        desc = line number of def
       +        return type is number after :
       +
       +        nil name marks end of function
       +
       +constants
       +
       +        c= XXX p. 15
       +
       +N_LSYM (128) local variable
       +        :type-number
       +        value = offset from fp
       +        :ptype means parameter passed in reg but stored as variable
       +
       +N_GSYM (32) global variable
       +        addr not given (use external symbol)
       +        :type
       +
       +N_RSYM register value
       +
       +N_STSYM(38)/N_FUN/N_LCSYM(40) data/text/bss
       +        static varibale 'S' file static 'V' procedure static
       +        :Stype :Vtype
       +
       +N_PSYM (160) parameter 
       +        :ptype
       +        value=offset from fp
       +        desc = line number of decl
       +
       +        register params followed by an N_RSYM with same name and :rtype.
       +
       +skip types
       +
       +type (a,b) means a=file number b=type number
       +
       +N_BINCL/N_EINCL begin/end include
       +N_EXCL - same effect as earlier guy
       +
       +
       +
       +=============
       +
       +type crap
       +
       +
       +
       +        name:symbol_opt typeinfo
       +
       +typeinfo ::= typenum | typenum = attr* typedef
       +
       +typenum ::= integer | '(' integer ',' integer ')'
       +
       +attr ::= @ attrtext ;
       +
       +attrtext ::= 'a' integer         (alignment)
       +        | 'p' integer        (pointer class)
       +        | 'P'        (packed type)
       +        | 's' integer        (size of type in bits)
       +        | 'S'         (string instead of array of chars)
       +
       +typedef ::= typeinfo
       +        | 'b' ('u' | 's') 'c'? width; offset; nbits;                 (builtin, signed/unsigned, char/not, width in bytes, offset & nbits of type)
       +        | 'w'                (aix wide char type, not used)
       +        | 'R' fptype; bytes;                        (fptype 1=32-bit, 2=64-bit, 3=complex, 4=complex16, 5=complex32, 6=long double)
       +        | 'g' typeinfo ';' nbits                 (aix floating, not used)
       +        | 'c' typeinfo ';' nbits                (aix complex, not used)
       +        | -1                int32
       +        | -2                char8
       +        | -3                int16
       +        | -4                int32 (long)
       +        | -5                uchar8
       +        | -6                schar8
       +        | -7                uint16
       +        | -8                uint32
       +        | -9                uint32
       +        | -10                ulong32
       +        | -11                void
       +        | -12                float
       +        | -13                double
       +        | -14                long double
       +        | -15                int32
       +        | -16                bool32
       +        | -17                short real
       +        | -18                real
       +        | -19                stringptr
       +        | -20                character8
       +        | -21                logical*1 8
       +        | -22                logical*2 16
       +        | -23                logical*4 32
       +        | -24                logical 32
       +        | -25                complex (two single)
       +        | -26                complex (two double)
       +        | -27                integer*1 8 signed
       +        | -28                integer*2 16 signed
       +        | -29                integer*4 32 signed
       +        | -30                wchar 16 wide char
       +        | -31                int64
       +        | -32                uint64
       +        | -33                logical*8 64
       +        | -34                integer*8 64 signed
       +        | 'b' typeinfo ';' bytes                (ibm, no idea)
       +        | 'B' typeinfo                (volatile typref)
       +        | 'd' typeinfo                (file of typeref)
       +        | 'k' typeinfo                (const typeref)
       +        | 'M' typeinfo ';' length                (multiple instance type, fortran)
       +        | 'S' typeinfo                (set, typeref must have small number of values)
       +        | '*' typeinfo                (pointer to typeref)
       +        | 'x' ('s'|'u'|'e') name ':'        (struct, union, enum reference.  name can have '::' in it)
       +        | 'r' typeinfo ';' low ';' high ';'                (subrange.  typeref can be type being defined for base types!)
       +                        low and high are bounds
       +                        if bound is octal power of two, it's a big negative number
       +        | ('a'|'P') indextypedef arraytypeinfo         (array, index should be range type)
       +                                indextype is type definition not typeinfo (need not say typenum=)
       +                                P means packed array
       +        | 'A' arraytypeinfo                (open array (no index bounds))
       +        | 'D' dims ';' typeinfo                (dims-dimensional dynamic array)
       +        | 'E' dims ';' typeinfo                (subarray of N-dimensional array)
       +        | 'n' typeinfo ';' bytes                (max length string)
       +        | 'z' typeinfo ';' bytes                (no idea what difference is from 'n')
       +        | 'N'                                        (pascal stringptr)
       +        | 'e' (name ':' bigint ',')* ';'        (enum listing)
       +        | ('s'|'u') bytes (name ':' type ',' bitoffset ',' bitsize ';')* ';'                (struct/union defn)
       +                                                tag is given as name in stabs entry, with 'T' symbol
       +        | 'f' typeinfo ';'                         (function returning type)
       +        | 'f' rettypeinfo ',' paramcount ';' (typeinfo ',' (0|1) ';')* ';'
       +        | 'p' paramcount ';' (typeinfo ',' (0|1) ';')* ';'
       +        | 'F' rettypeinfo ',' paramcount ';' (name ':' typeinfo ',' (0|1) ';')* ';'
       +        | 'R' paramcount ';' (name ':' typeinfo ',' (0|1) ';')* ';'
       +                                                (the 0 or 1 is pass-by-reference vs pass-by-value)
       +                                                (the 0 or 1 is pass-by-reference vs pass-by-value)
       +
       +bound ::= 
       +        'A' offset                        (bound is on stack by ref at offset offset from arg list)
       +        | 'T' offset                        (bound is on stack by val at offset offset from arg list)
       +        | 'a' regnum                (bound passed by reference in register)
       +        | 't' regnum                (bound passed by value in register)
       +        | 'J'                                (no bound)
       +        | bigint
       +
       +bigint ::= '-'? decimal
       +        | 0 octal
       +        | -1
       +
       +C++
       +
       +symbol 'Tt' means typename + tag in one stab
       +
       +names can have ::, as in foo::bar::baz::t1
       +
       +t16 unknown type just like void
       +t17 vtable record type
   DIR diff --git a/src/libmach/crack.c b/src/libmach/crack.c
       t@@ -0,0 +1,91 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include <mach.h>
       +
       +static struct
       +{
       +        ulong magic;
       +        int (*fn)(int, Fhdr*);
       +} cracktab[] = {
       +        0x7F454C46,        crackelf,
       +        0xFEEDFACE,        crackmacho,
       +};
       +
       +Fhdr*
       +crackhdr(char *name, int mode)
       +{
       +        uchar buf[4];
       +        ulong magic;
       +        int i, fd;
       +        Fhdr *hdr;
       +
       +        if((fd = open(name, mode)) < 0)
       +                return nil;
       +
       +        if(seek(fd, 0, 0) < 0 || readn(fd, buf, 4) != 4){
       +                close(fd);
       +                return nil;
       +        }
       +
       +        hdr = mallocz(sizeof(Fhdr), 1);
       +        if(hdr == nil){
       +                close(fd);
       +                return nil;
       +        }
       +        hdr->filename = strdup(name);
       +        magic = beload4(buf);
       +        werrstr("magic doesn't match");
       +        for(i=0; i<nelem(cracktab); i++)
       +                if(cracktab[i].magic == magic && seek(fd, 0, 0) == 0 && cracktab[i].fn(fd, hdr) >= 0){
       +                        _addhdr(hdr);
       +                        return hdr;
       +                }
       +        werrstr("unknown file type: %r");
       +        free(hdr);
       +        close(fd);
       +        return nil;
       +}
       +
       +void
       +uncrackhdr(Fhdr *hdr)
       +{
       +        close(hdr->fd);
       +        _delhdr(hdr);
       +        free(hdr);
       +}
       +
       +int
       +mapfile(Fhdr *fp, ulong base, Map *map, Regs **regs)
       +{
       +        if(fp == nil){
       +                werrstr("no file");
       +                return -1;
       +        }
       +        if(map == nil){
       +                werrstr("no map");
       +                return -1;
       +        }
       +        if(fp->map == nil){
       +                werrstr("cannot load map for this file type");
       +                return -1;
       +        }
       +        return fp->map(fp, base, map, regs);
       +}
       +
       +void
       +unmapfile(Fhdr *fp, Map *map)
       +{
       +        int i;
       +
       +        if(map == nil || fp == nil)
       +                return;
       +
       +        for(i=0; i<map->nseg; i++){
       +                while(i<map->nseg && map->seg[i].fd == fp->fd){
       +                        map->nseg--;
       +                        memmove(&map->seg[i], &map->seg[i+1], 
       +                                (map->nseg-i)*sizeof(map->seg[0]));
       +                }
       +        }
       +}
   DIR diff --git a/src/libmach/crackelf.c b/src/libmach/crackelf.c
       t@@ -0,0 +1,342 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <mach.h>
       +#include "elf.h"
       +#include "dwarf.h"
       +
       +static int mapelf(Fhdr *fp, ulong base, Map *map, Regs**);
       +static int mapcoreregs(Fhdr *fp, Map *map, Regs**);
       +
       +static struct
       +{
       +        uint etype;
       +        uint mtype;
       +        Mach *mach;
       +        char *name;
       +} mtab[] = 
       +{        /* Font Tab 4 */
       +        ElfMachSparc,        MSPARC,                nil,                "sparc",
       +        ElfMach386,                M386,                &mach386,        "386",
       +        ElfMachMips,        MMIPS,                nil,                "mips",
       +        ElfMachArm,                MARM,                nil,                "arm",
       +        ElfMachPower,        MPOWER,                nil,                "powerpc",
       +        ElfMachPower64,        MNONE,                nil,                "powerpc64",
       +};
       +
       +static struct
       +{
       +        uint etype;
       +        uint atype;
       +        char *aname;
       +} atab[] = 
       +{        /* Font Tab 4 */
       +        ElfAbiSystemV,        ALINUX,                "linux",        /* [sic] */
       +        ElfAbiLinux,        ALINUX,                "linux",
       +        ElfAbiFreeBSD,        AFREEBSD,        "freebsd",
       +};
       +
       +static struct
       +{
       +        uint mtype;
       +        uint atype;
       +        int (*coreregs)(Elf*, ElfNote*, uchar**);
       +} ctab[] = 
       +{        /* Font Tab 4 */
       +        M386,                ALINUX,                coreregslinux386,
       +        M386,                ANONE,                coreregslinux386,        /* [sic] */
       +        M386,                AFREEBSD,        coreregsfreebsd386,
       +};
       +
       +int
       +crackelf(int fd, Fhdr *fp)
       +{
       +        int i, havetext, havedata;
       +        Elf *elf;
       +        ElfProg *p;
       +        ElfSect *s1, *s2;
       +
       +        if((elf = elfinit(fd)) == nil)
       +                return -1;
       +
       +        fp->fd = fd;
       +        fp->elf = elf;
       +        fp->dwarf = dwarfopen(elf);        /* okay to fail */
       +        fp->syminit = symelf;
       +
       +        if((s1 = elfsection(elf, ".stab")) != nil && s1->link!=0 && s1->link < elf->nsect){
       +                s2 = &elf->sect[s1->link];
       +                if(elfmap(elf, s1) >= 0 && elfmap(elf, s2) >= 0){
       +                        fp->stabs.stabbase = s1->base;
       +                        fp->stabs.stabsize = s1->size;
       +                        fp->stabs.strbase = s2->base;
       +                        fp->stabs.strsize = s2->size;
       +                        fp->stabs.e2 = elf->hdr.e2;
       +                        fp->stabs.e4 = elf->hdr.e4;
       +                }
       +        }
       +
       +        for(i=0; i<nelem(mtab); i++){
       +                if(elf->hdr.machine != mtab[i].etype)
       +                        continue;
       +                fp->mach = mtab[i].mach;
       +                fp->mname = mtab[i].name;
       +                fp->mtype = mtab[i].mtype;
       +                break;
       +        }
       +        if(i == nelem(mtab)){
       +                werrstr("unsupported machine type %d", elf->hdr.machine);
       +                goto err;
       +        }
       +
       +        if(mach == nil)
       +                mach = fp->mach;
       +
       +        fp->aname = "unknown";
       +        for(i=0; i<nelem(atab); i++){
       +                if(elf->hdr.abi != atab[i].etype)
       +                        continue;
       +                fp->atype = atab[i].atype;
       +                fp->aname = atab[i].aname;
       +                break;
       +        }
       +
       +        switch(elf->hdr.type){
       +        default:
       +                werrstr("unknown file type %d", elf->hdr.type);
       +                goto err;
       +        case ElfTypeExecutable:
       +                fp->ftype = FEXEC;
       +                fp->fname = "executable";
       +                break;
       +        case ElfTypeRelocatable:
       +                fp->ftype = FRELOC;
       +                fp->fname = "relocatable";
       +                break;
       +        case ElfTypeSharedObject:
       +                fp->ftype = FSHOBJ;
       +                fp->fname = "shared object";
       +                break;
       +        case ElfTypeCore:
       +                fp->ftype = FCORE;
       +                fp->fname = "core dump";
       +                break;
       +        }
       +
       +        fp->map = mapelf;
       +
       +        if(fp->ftype == FCORE){
       +                for(i=0; i<nelem(ctab); i++){
       +                        if(ctab[i].atype != fp->atype
       +                        || ctab[i].mtype != fp->mtype)
       +                                continue;
       +                        elf->coreregs = ctab[i].coreregs;
       +                        break;
       +                }
       +                return 0;
       +        }
       +
       +        fp->entry = elf->hdr.entry;
       +
       +        /* First r-x section we find is the text and initialized data */
       +        /* First rw- section we find is the r/w data */
       +        havetext = 0;
       +        havedata = 0;
       +        for(i=0; i<elf->nprog; i++){
       +                p = &elf->prog[i];
       +                if(p->type != ElfProgLoad)
       +                        continue;
       +                if(!havetext && p->flags == (ElfProgFlagRead|ElfProgFlagExec) && p->align >= mach->pgsize){
       +                        havetext = 1;
       +                        fp->txtaddr = p->vaddr;
       +                        fp->txtsz = p->memsz;
       +                        fp->txtoff = p->offset;
       +                }
       +                if(!havedata && p->flags == (ElfProgFlagRead|ElfProgFlagWrite) && p->align >= mach->pgsize){
       +                        havedata = 1;
       +                        fp->dataddr = p->vaddr;
       +                        fp->datsz = p->filesz;
       +                        fp->datoff = p->offset;
       +                        fp->bsssz = p->memsz - p->filesz;
       +                }
       +        }
       +        if(!havetext){
       +                werrstr("did not find text segment in elf binary");
       +                goto err;
       +        }
       +        if(!havedata){
       +                werrstr("did not find data segment in elf binary");
       +                goto err;
       +        }
       +        return 0;
       +
       +err:
       +        elfclose(elf);
       +        return -1;
       +}
       +
       +static int
       +mapelf(Fhdr *fp, ulong base, Map *map, Regs **regs)
       +{
       +        int i;
       +        Elf *elf;
       +        ElfProg *p;
       +        ulong sz;
       +        ulong lim;
       +        Seg s;
       +
       +        elf = fp->elf;
       +        if(elf == nil){
       +                werrstr("not an elf file");
       +                return -1;
       +        }
       +
       +        for(i=0; i<elf->nprog; i++){
       +                p = &elf->prog[i];
       +                if(p->type != ElfProgLoad)
       +                        continue;
       +                if(p->align < mach->pgsize)
       +                        continue;
       +                if(p->filesz){
       +                        memset(&s, 0, sizeof s);
       +                        s.file = fp->filename;
       +                        s.fd = fp->fd;
       +                        if(fp->ftype == FCORE)
       +                                s.name = "core";
       +                        else if(p->flags == 5)
       +                                s.name = "text";
       +                        else
       +                                s.name = "data";
       +                        s.base = base+p->vaddr;
       +                        s.size = p->filesz;
       +                        s.offset = p->offset;
       +                        if(addseg(map, s) < 0)
       +                                return -1;
       +                }
       +                /*
       +                 * If memsz > filesz, we're supposed to zero fill.
       +                 * Core files have zeroed sections where the pages
       +                 * can be filled in from the text file, so if this is a core
       +                 * we only fill in that which isn't yet mapped.
       +                 */
       +                if(fp->ftype == FCORE){
       +                        sz = p->filesz;
       +                        while(sz < p->memsz){
       +                                if(addrtoseg(map, base+p->vaddr+sz, &s) < 0){
       +                                        lim = base + p->vaddr + p->memsz;
       +                                        if(addrtosegafter(map, base+p->vaddr+sz, &s) >= 0 && s.base < lim)
       +                                                lim = s.base;
       +                                        memset(&s, 0, sizeof s);
       +                                        s.name = "zero";
       +                                        s.base = base + p->vaddr + sz;
       +                                        s.size = lim - s.base;
       +                                        s.offset = p->offset;
       +                                        if(addseg(map, s) < 0)
       +                                                return -1;
       +                                }else
       +                                        sz = (s.base+s.size) - (base + p->vaddr);
       +                        }
       +                }else{
       +                        if(p->filesz < p->memsz){
       +                                memset(&s, 0, sizeof s);
       +                                s.name = "zero";
       +                                s.base = base + p->vaddr + p->filesz;
       +                                s.size = p->memsz - p->filesz;
       +                                if(addseg(map, s) < 0)
       +                                        return -1;
       +                        }
       +                }                        
       +        }
       +
       +        if(fp->ftype == FCORE){
       +                if(mapcoreregs(fp, map, regs) < 0)
       +                        fprint(2, "warning: reading core regs: %r");
       +        }
       +
       +        return 0;        
       +}
       +
       +static int
       +unpacknote(Elf *elf, uchar *a, uchar *ea, ElfNote *note, uchar **pa)
       +{
       +        if(a+12 > ea)
       +                return -1;
       +        note->namesz = elf->hdr.e4(a);
       +        note->descsz = elf->hdr.e4(a+4);
       +        note->type = elf->hdr.e4(a+8);
       +        a += 12;
       +        note->name = (char*)a;
       +/* XXX fetch alignment constants from elsewhere */
       +        a += (note->namesz+3)&~3;
       +        note->desc = (uchar*)a;
       +        a += (note->descsz+3)&~3;
       +        if(a > ea)
       +                return -1;
       +        *pa = a;
       +        return 0;
       +}
       +
       +static int
       +mapcoreregs(Fhdr *fp, Map *map, Regs **rp)
       +{
       +        int i;
       +        uchar *a, *sa, *ea, *uregs;
       +        uint n;
       +        ElfNote note;
       +        ElfProg *p;
       +        Elf *elf;
       +        UregRegs *r;
       +
       +        elf = fp->elf;
       +        if(elf->coreregs == nil){
       +                werrstr("cannot parse %s %s cores", fp->mname, fp->aname);
       +                return -1;
       +        }
       +
       +        for(i=0; i<elf->nprog; i++){
       +                p = &elf->prog[i];
       +                if(p->type != ElfProgNote)
       +                        continue;
       +                n = p->filesz;
       +                a = malloc(n);
       +                if(a == nil)
       +                        return -1;
       +                if(seek(fp->fd, p->offset, 0) < 0 || readn(fp->fd, a, n) != n){
       +                        free(a);
       +                        continue;
       +                }
       +                sa = a;
       +                ea = a+n;
       +                while(a < ea){
       +                        note.offset = (a-sa) + p->offset;
       +                        if(unpacknote(elf, a, ea, &note, &a) < 0)
       +                                break;
       +                        switch(note.type){
       +                        case ElfNotePrStatus:
       +                                if((n = (*elf->coreregs)(elf, &note, &uregs)) < 0){
       +                                        free(sa);
       +                                        return -1;
       +                                }
       +                                free(sa);
       +                                if((r = mallocz(sizeof(*r), 1)) == nil){
       +                                        free(uregs);
       +                                        return -1;
       +                                }
       +                                r->r.rw = _uregrw;
       +                                r->ureg = uregs;
       +                                *rp = &r->r;
       +                                return 0;
       +                        case ElfNotePrFpreg:
       +                        case ElfNotePrPsinfo:
       +                        case ElfNotePrTaskstruct:
       +                        case ElfNotePrAuxv:
       +                        case ElfNotePrXfpreg:
       +                                break;
       +                        }
       +                //        fprint(2, "0x%lux note %s/%lud %p\n", note.offset, note.name, note.type, note.desc);
       +                }
       +                free(sa);
       +        }
       +        fprint(2, "could not find registers in core file\n");
       +        return -1;
       +}
       +
   DIR diff --git a/src/libmach/crackmacho.c b/src/libmach/crackmacho.c
       t@@ -0,0 +1,198 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <mach.h>
       +#include "macho.h"
       +
       +static int mapmacho(Fhdr *fp, ulong base, Map *map, Regs**);
       +
       +static struct
       +{
       +        uint etype;
       +        uint mtype;
       +        Mach *mach;
       +        char *name;
       +        int (*coreregs)(Macho*, uchar**);
       +} mtab[] = 
       +{
       +        MachoCpuPower,        MPOWER,                &machpower,                 "powerpc",        coreregsmachopower,
       +};
       +
       +static uchar*
       +load(int fd, ulong off, int size)
       +{
       +        uchar *a;
       +
       +        a = malloc(size);
       +        if(a == nil)
       +                return nil;
       +        if(seek(fd, off, 0) < 0 || readn(fd, a, size) != size){
       +                free(a);
       +                return nil;
       +        }
       +        return a;
       +}
       +
       +int
       +crackmacho(int fd, Fhdr *fp)
       +{
       +        int i;
       +        Macho *m;
       +
       +        if((m = machoinit(fd)) == nil)
       +                return -1;
       +
       +        fp->fd = fd;
       +        fp->macho = m;
       +
       +        for(i=0; i<nelem(mtab); i++){
       +                if(m->cputype != mtab[i].etype)
       +                        continue;
       +                fp->mach = mtab[i].mach;
       +                fp->mtype = mtab[i].mtype;
       +                fp->mname = mtab[i].name;
       +                m->coreregs = mtab[i].coreregs;
       +                break;
       +        }
       +        if(i == nelem(mtab)){
       +                werrstr("unsupported cpu type %ud", m->cputype);
       +                goto err;
       +        }
       +
       +        fp->atype = AMACH;
       +        fp->aname = "mach";
       +
       +        if(mach == nil)
       +                mach = fp->mach;
       +
       +        switch(m->filetype){
       +        default:
       +                werrstr("unsupported macho file type %lud", m->filetype);
       +                goto err;
       +        case MachoFileObject:
       +                fp->ftype = FOBJ;
       +                fp->fname = "object";
       +                break;
       +        case MachoFileExecutable:
       +                fp->ftype = FEXEC;
       +                fp->fname = "executable";
       +                break;
       +        case MachoFileFvmlib:
       +                fp->ftype = FSHLIB;
       +                fp->fname = "shared library";
       +                break;
       +        case MachoFileCore:
       +                fp->ftype = FCORE;
       +                fp->fname = "core";
       +                break;
       +        case MachoFilePreload:
       +                fp->ftype = FBOOT;
       +                fp->fname = "preloaded executable";
       +                break;
       +        }
       +
       +        fp->txtaddr = fp->dataddr = 0;
       +        fp->txtsz = fp->datsz = 0;
       +        for(i=0; i<m->ncmd; i++){
       +                if(m->cmd[i].type != MachoCmdSegment)
       +                        continue;
       +                if(strcmp(m->cmd[i].seg.name, "__TEXT") == 0){
       +                        fp->txtaddr = m->cmd[i].seg.vmaddr;
       +                        fp->txtsz = m->cmd[i].seg.vmsize;
       +                        fp->txtoff = m->cmd[i].seg.fileoff;
       +                }
       +                if(strcmp(m->cmd[i].seg.name, "__DATA") == 0){
       +                        fp->dataddr = m->cmd[i].seg.vmaddr;
       +                        fp->datsz = m->cmd[i].seg.filesz;
       +                        fp->datoff = m->cmd[i].seg.fileoff;
       +                        fp->bsssz = m->cmd[i].seg.vmsize - fp->datsz;
       +                }
       +        }
       +
       +        fp->map = mapmacho;
       +        fp->syminit = symmacho;
       +
       +        for(i=0; i<m->ncmd; i++)
       +                if(m->cmd[i].type == MachoCmdSymtab)
       +                        break;
       +        if(i < m->ncmd){
       +                fp->stabs.stabbase = load(fp->fd, m->cmd[i].sym.symoff, m->cmd[i].sym.nsyms*16);
       +                fp->stabs.stabsize = m->cmd[i].sym.nsyms*16;
       +                fp->stabs.strbase = load(fp->fd, m->cmd[i].sym.stroff, m->cmd[i].sym.strsize);
       +                if(fp->stabs.stabbase == nil || fp->stabs.strbase == nil){
       +                        fp->stabs.stabbase = nil;
       +                        fp->stabs.strbase = nil;
       +                }else{
       +                        fp->stabs.strsize = m->cmd[i].sym.strsize;
       +                        fp->stabs.e2 = (m->e4==beload4 ? beload2 : leload2);
       +                        fp->stabs.e4 = m->e4;
       +                }
       +        }
       +
       +        return 0;
       +
       +err:
       +        machoclose(m);
       +        return -1;
       +}
       +
       +static int
       +mapmacho(Fhdr *fp, ulong base, Map *map, Regs **rp)
       +{
       +        int i, n;
       +        uchar *u;
       +        Macho *m;
       +        MachoCmd *c;
       +        Seg s;
       +        UregRegs *r;
       +
       +        m = fp->macho;
       +        if(m == nil){
       +                werrstr("not a macho file");
       +                return -1;
       +        }
       +
       +        for(i=0; i<m->ncmd; i++){
       +                c = &m->cmd[i];
       +                if(c->type != MachoCmdSegment)
       +                        continue;
       +                if(c->seg.filesz){
       +                        memset(&s, 0, sizeof s);
       +                        s.file = fp->filename;
       +                        s.fd = fp->fd;
       +                        if(fp->ftype == FCORE)
       +                                s.name = "core";
       +                        else if(strcmp(c->seg.name, "__DATA") == 0)
       +                                s.name = "data";
       +                        else
       +                                s.name = "text";
       +                        s.base = base+c->seg.vmaddr;
       +                        s.size = c->seg.filesz;
       +                        s.offset = c->seg.fileoff;
       +                        if(addseg(map, s) < 0)
       +                                return -1;
       +                }
       +                if(c->seg.filesz < c->seg.vmsize){
       +                        memset(&s, 0, sizeof s);
       +                        s.name = "zero";
       +                        s.base = base + c->seg.vmaddr + c->seg.filesz;
       +                        s.size = c->seg.vmsize - c->seg.filesz;
       +                        if(addseg(map, s) < 0)
       +                                return -1;
       +                }
       +        }
       +
       +        if(fp->ftype == FCORE && m->coreregs){
       +                n = m->coreregs(m, &u);
       +                if(n < 0){
       +                        fprint(2, "mapping registers: %r\n");
       +                        goto noregs;
       +                }
       +                if((r = mallocz(sizeof *r, 1)) == nil)
       +                        return -1;
       +                r->r.rw = _uregrw;
       +                r->ureg = u;        
       +                *rp = &r->r;
       +        }
       +noregs:
       +        return 0;
       +}
   DIR diff --git a/src/libmach/dwarf.h b/src/libmach/dwarf.h
       t@@ -0,0 +1,460 @@
       +typedef struct Dwarf Dwarf;
       +typedef struct DwarfAttrs DwarfAttrs;
       +typedef struct DwarfBlock DwarfBlock;
       +typedef struct DwarfBuf DwarfBuf;
       +typedef struct DwarfExpr DwarfExpr;
       +typedef struct DwarfSym DwarfSym;
       +typedef union DwarfVal DwarfVal;
       +
       +enum
       +{
       +        TagArrayType = 0x01,
       +        TagClassType = 0x02,
       +        TagEntryPoint = 0x03,
       +        TagEnumerationType = 0x04,
       +        TagFormalParameter = 0x05,
       +        TagImportedDeclaration = 0x08,
       +        TagLabel = 0x0A,
       +        TagLexDwarfBlock = 0x0B,
       +        TagMember = 0x0D,
       +        TagPointerType = 0x0F,
       +        TagReferenceType = 0x10,
       +        TagCompileUnit = 0x11,
       +        TagStringType = 0x12,
       +        TagStructType = 0x13,
       +        TagSubroutineType = 0x15,
       +        TagTypedef = 0x16,
       +        TagUnionType = 0x17,
       +        TagUnspecifiedParameters = 0x18,
       +        TagVariant = 0x19,
       +        TagCommonDwarfBlock = 0x1A,
       +        TagCommonInclusion = 0x1B,
       +        TagInheritance = 0x1C,
       +        TagInlinedSubroutine = 0x1D,
       +        TagModule = 0x1E,
       +        TagPtrToMemberType = 0x1F,
       +        TagSetType = 0x20,
       +        TagSubrangeType = 0x21,
       +        TagWithStmt = 0x22,
       +        TagAccessDeclaration = 0x23,
       +        TagBaseType = 0x24,
       +        TagCatchDwarfBlock = 0x25,
       +        TagConstType = 0x26,
       +        TagConstant = 0x27,
       +        TagEnumerator = 0x28,
       +        TagFileType = 0x29,
       +        TagFriend = 0x2A,
       +        TagNamelist = 0x2B,
       +        TagNamelistItem = 0x2C,
       +        TagPackedType = 0x2D,
       +        TagSubprogram = 0x2E,
       +        TagTemplateTypeParameter = 0x2F,
       +        TagTemplateValueParameter = 0x30,
       +        TagThrownType = 0x31,
       +        TagTryDwarfBlock = 0x32,
       +        TagVariantPart = 0x33,
       +        TagVariable = 0x34,
       +        TagVolatileType = 0x35,
       +        TagDwarfProcedure = 0x36,
       +        TagRestrictType = 0x37,
       +        TagInterfaceType = 0x38,
       +        TagNamespace = 0x39,
       +        TagImportedModule = 0x3A,
       +        TagUnspecifiedType = 0x3B,
       +        TagPartialUnit = 0x3C,
       +        TagImportedUnit = 0x3D,
       +        TagMutableType = 0x3E,
       +
       +        TypeAddress = 0x01,
       +        TypeBoolean = 0x02,
       +        TypeComplexFloat = 0x03,
       +        TypeFloat = 0x04,
       +        TypeSigned = 0x05,
       +        TypeSignedChar = 0x06,
       +        TypeUnsigned = 0x07,
       +        TypeUnsignedChar = 0x08,
       +        TypeImaginaryFloat = 0x09,
       +
       +        AccessPublic = 0x01,
       +        AccessProtected = 0x02,
       +        AccessPrivate = 0x03,
       +
       +        VisLocal = 0x01,
       +        VisExported = 0x02,
       +        VisQualified = 0x03,
       +
       +        VirtNone = 0x00,
       +        VirtVirtual = 0x01,
       +        VirtPureVirtual = 0x02,
       +
       +        LangC89 = 0x0001,
       +        LangC = 0x0002,
       +        LangAda83 = 0x0003,
       +        LangCplusplus = 0x0004,
       +        LangCobol74 = 0x0005,
       +        LangCobol85 = 0x0006,
       +        LangFortran77 = 0x0007,
       +        LangFortran90 = 0x0008,
       +        LangPascal83 = 0x0009,
       +        LangModula2 = 0x000A,
       +        LangJava = 0x000B,
       +        LangC99 = 0x000C,
       +        LangAda95 = 0x000D,
       +        LangFortran95 = 0x000E,
       +        LangPLI = 0x000F,
       +        // 0x8000-0xFFFF reserved
       +
       +        IdCaseSensitive = 0x00,
       +        IdCaseUpper = 0x01,
       +        IdCaseLower = 0x02,
       +        IdCaseInsensitive = 0x03,
       +
       +        CallingNormal = 0x01,
       +        CallingProgram = 0x02,
       +        CallingNocall = 0x03,
       +        // 0x40-0xFF reserved
       +
       +        InNone = 0x00,
       +        InInlined = 0x01,
       +        InDeclaredNotInlined = 0x02,
       +        InDeclaredInlined = 0x03,
       +
       +        OrderRowMajor = 0x00,
       +        OrderColumnMajor = 0x01,
       +
       +        DiscLabel = 0x00,
       +        DiscRange = 0x01,
       +
       +        TReference = 1<<0,
       +        TBlock = 1<<1,
       +        TConstant = 1<<2,
       +        TString = 1<<3,
       +        TFlag = 1<<4,
       +        TAddress = 1<<5,
       +
       +        OpAddr = 0x03,        // 1 op, const addr
       +        OpDeref = 0x06,
       +        OpConst1u = 0x08,        // 1 op, 1 byte const
       +        OpConst1s = 0x09,        //        " signed
       +        OpConst2u = 0x0A,        // 1 op, 2 byte const 
       +        OpConst2s = 0x0B,        //        " signed
       +        OpConst4u = 0x0C,        // 1 op, 4 byte const
       +        OpConst4s = 0x0D,        //        " signed
       +        OpConst8u = 0x0E,        // 1 op, 8 byte const
       +        OpConst8s = 0x0F,        //        " signed
       +        OpConstu = 0x10,        // 1 op, LEB128 const
       +        OpConsts = 0x11,        //        " signed
       +        OpDup = 0x12,
       +        OpDrop = 0x13,
       +        OpOver = 0x14,
       +        OpPick = 0x15,                // 1 op, 1 byte stack index
       +        OpSwap = 0x16,
       +        OpRot = 0x17,
       +        OpXderef = 0x18,
       +        OpAbs = 0x19,
       +        OpAnd = 0x1A,
       +        OpDiv = 0x1B,
       +        OpMinus = 0x1C,
       +        OpMod = 0x1D,
       +        OpMul = 0x1E,
       +        OpNeg = 0x1F,
       +        OpNot = 0x20,
       +        OpOr = 0x21,
       +        OpPlus = 0x22,
       +        OpPlusUconst = 0x23,        // 1 op, ULEB128 addend
       +        OpShl = 0x24,
       +        OpShr = 0x25,
       +        OpShra = 0x26,
       +        OpXor = 0x27,
       +        OpSkip = 0x2F,                // 1 op, signed 2-byte constant
       +        OpBra = 0x28,                // 1 op, signed 2-byte constant
       +        OpEq = 0x29,
       +        OpGe = 0x2A,
       +        OpGt = 0x2B,
       +        OpLe = 0x2C,
       +        OpLt = 0x2D,
       +        OpNe = 0x2E,
       +        OpLit0 = 0x30,
       +                // OpLitN = OpLit0 + N for N = 0..31
       +        OpReg0 = 0x50,
       +                // OpRegN = OpReg0 + N for N = 0..31
       +        OpBreg0 = 0x70,        // 1 op, signed LEB128 constant
       +                // OpBregN = OpBreg0 + N for N = 0..31
       +        OpRegx = 0x90,        // 1 op, ULEB128 register
       +        OpFbreg = 0x91,        // 1 op, SLEB128 offset
       +        OpBregx = 0x92,        // 2 op, ULEB128 reg, SLEB128 off
       +        OpPiece = 0x93,        // 1 op, ULEB128 size of piece
       +        OpDerefSize = 0x94,        // 1-byte size of data retrieved
       +        OpXderefSize = 0x95,        // 1-byte size of data retrieved
       +        OpNop = 0x96,
       +        // next four new in Dwarf v3
       +        OpPushObjAddr = 0x97,
       +        OpCall2 = 0x98,        // 2-byte offset of DIE
       +        OpCall4 = 0x99,        // 4-byte offset of DIE
       +        OpCallRef = 0x9A,        // 4- or 8- byte offset of DIE
       +        // 0xE0-0xFF reserved for user-specific
       +};
       +
       +struct DwarfBlock
       +{
       +        uchar *data;
       +        ulong len;
       +};
       +
       +/* not for consumer use */
       +struct DwarfBuf
       +{
       +        Dwarf *d;
       +        uchar *p;
       +        uchar *ep;
       +        uint addrsize;
       +};
       +
       +union DwarfVal
       +{
       +        char *s;
       +        ulong c;
       +        ulong r;
       +        DwarfBlock b;
       +};
       +
       +struct DwarfAttrs
       +{
       +        ulong        tag;
       +        uchar        haskids;
       +
       +        /* whether we have it, along with type */
       +        struct {
       +                uchar        abstractorigin;
       +                uchar        accessibility;
       +                uchar        addrclass;
       +                uchar        basetypes;
       +                uchar        bitoffset;
       +                uchar        bitsize;
       +                uchar        bytesize;
       +                uchar        calling;
       +                uchar        commonref;
       +                uchar        compdir;
       +                uchar        constvalue;
       +                uchar        containingtype;
       +                uchar        count;
       +                uchar        datamemberloc;
       +                uchar        declcolumn;
       +                uchar        declfile;
       +                uchar        declline;
       +                uchar        defaultvalue;
       +                uchar        discr;
       +                uchar        discrlist;
       +                uchar        discrvalue;
       +                uchar        encoding;
       +                uchar        framebase;
       +                uchar        friend;
       +                uchar        highpc;
       +                uchar        identifiercase;
       +                uchar        import;
       +                uchar        inlined;
       +                uchar        isartificial;
       +                uchar        isdeclaration;
       +                uchar        isexternal;
       +                uchar        isoptional;
       +                uchar        isprototyped;
       +                uchar        isvarparam;
       +                uchar        language;
       +                uchar        location;
       +                uchar        lowerbound;
       +                uchar        lowpc;
       +                uchar        macroinfo;
       +                uchar        name;
       +                uchar        namelistitem;
       +                uchar        ordering;
       +                uchar        priority;
       +                uchar        producer;
       +                uchar        ranges;
       +                uchar        returnaddr;
       +                uchar        segment;
       +                uchar        sibling;
       +                uchar        specification;
       +                uchar        startscope;
       +                uchar        staticlink;
       +                uchar        stmtlist;
       +                uchar        stridesize;
       +                uchar        stringlength;
       +                uchar        type;
       +                uchar        upperbound;
       +                uchar        uselocation;
       +                uchar        virtuality;
       +                uchar        visibility;
       +                uchar        vtableelemloc;
       +        } have;
       +
       +        ulong        abstractorigin;
       +        ulong        accessibility;
       +        ulong        addrclass;
       +        ulong        basetypes;
       +        ulong        bitoffset;
       +        ulong        bitsize;
       +        ulong        bytesize;
       +        ulong        calling;
       +        ulong        commonref;
       +        char*        compdir;
       +        DwarfVal        constvalue;
       +        ulong        containingtype;
       +        ulong        count;
       +        DwarfVal        datamemberloc;
       +        ulong        declcolumn;
       +        ulong        declfile;
       +        ulong        declline;
       +        ulong        defaultvalue;
       +        ulong        discr;
       +        DwarfBlock        discrlist;
       +        ulong        discrvalue;
       +        ulong        encoding;
       +        DwarfVal        framebase;
       +        ulong        friend;
       +        ulong        highpc;
       +        ulong        identifiercase;
       +        ulong        import;
       +        ulong        inlined;
       +        uchar        isartificial;
       +        uchar        isdeclaration;
       +        uchar        isexternal;
       +        uchar        isoptional;
       +        uchar        isprototyped;
       +        uchar        isvarparam;
       +        ulong        language;
       +        DwarfVal        location;
       +        ulong        lowerbound;
       +        ulong        lowpc;
       +        ulong        macroinfo;
       +        char*        name;
       +        DwarfBlock        namelistitem;
       +        ulong        ordering;
       +        ulong        priority;
       +        char*        producer;
       +        ulong        ranges;
       +        DwarfVal        returnaddr;
       +        DwarfVal        segment;
       +        ulong        sibling;
       +        ulong        specification;
       +        ulong        startscope;
       +        DwarfVal        staticlink;
       +        ulong        stmtlist;
       +        ulong        stridesize;
       +        DwarfVal        stringlength;
       +        ulong        type;
       +        ulong        upperbound;
       +        DwarfVal        uselocation;
       +        ulong        virtuality;
       +        ulong        visibility;
       +        DwarfVal        vtableelemloc;
       +};
       +
       +enum
       +{
       +        RuleUndef,
       +        RuleSame,
       +        RuleCfaOffset,
       +        RuleRegister,
       +        RuleRegOff,
       +        RuleLocation,
       +};
       +struct DwarfExpr
       +{
       +        int type;
       +        long offset;
       +        ulong reg;
       +        DwarfBlock loc;
       +};
       +
       +struct DwarfSym
       +{
       +        DwarfAttrs attrs;
       +
       +/* not for consumer use... */
       +        DwarfBuf b;
       +        ulong unit;
       +        uint uoff;
       +        ulong aoff;
       +        int depth;
       +        int allunits;
       +        ulong nextunit;
       +};
       +
       +
       +Dwarf *dwarfopen(Elf *elf);
       +void dwarfclose(Dwarf*);
       +int dwarfaddrtounit(Dwarf*, ulong, ulong*);
       +int dwarflookupfn(Dwarf*, ulong, ulong, DwarfSym*);
       +int dwarflookupname(Dwarf*, char*, DwarfSym*);
       +int dwarflookupnameinunit(Dwarf*, ulong, char*, DwarfSym*);
       +int dwarflookupsubname(Dwarf*, DwarfSym*, char*, DwarfSym*);
       +int dwarflookuptag(Dwarf*, ulong, ulong, DwarfSym*);
       +int dwarfenumunit(Dwarf*, ulong, DwarfSym*);
       +int dwarfseeksym(Dwarf*, ulong, ulong, DwarfSym*);
       +int dwarfenum(Dwarf*, DwarfSym*);
       +int dwarfnextsym(Dwarf*, DwarfSym*, int);
       +int dwarfpctoline(Dwarf*, ulong, char**, char**, char**, ulong*, ulong*, ulong*);
       +int dwarfunwind(Dwarf*, ulong, DwarfExpr*, DwarfExpr*, DwarfExpr*, int);
       +ulong dwarfget1(DwarfBuf*);
       +ulong dwarfget2(DwarfBuf*);
       +ulong dwarfget4(DwarfBuf*);
       +uvlong dwarfget8(DwarfBuf*);
       +ulong dwarfget128(DwarfBuf*);
       +long dwarfget128s(DwarfBuf*);
       +ulong dwarfgetaddr(DwarfBuf*);
       +int dwarfgetn(DwarfBuf*, uchar*, int);
       +uchar *dwarfgetnref(DwarfBuf*, ulong);
       +char *dwarfgetstring(DwarfBuf*);
       +
       +
       +typedef struct DwarfAbbrev DwarfAbbrev;
       +typedef struct DwarfAttr DwarfAttr;
       +
       +struct DwarfAttr
       +{
       +        ulong name;
       +        ulong form;
       +};
       +
       +struct DwarfAbbrev
       +{
       +        ulong num;
       +        ulong tag;
       +        uchar haskids;
       +        DwarfAttr *attr;
       +        int nattr;
       +};
       +
       +struct Dwarf
       +{
       +        Elf *elf;
       +        int fd;
       +        char **reg;
       +        int nreg;
       +        int addrsize;
       +        DwarfBlock abbrev;
       +        DwarfBlock aranges;
       +        DwarfBlock frame;
       +        DwarfBlock info;
       +        DwarfBlock line;
       +        DwarfBlock pubnames;
       +        DwarfBlock pubtypes;
       +        DwarfBlock ranges;
       +        DwarfBlock str;
       +
       +        /* little cache */
       +        struct {
       +                DwarfAbbrev *a;
       +                int na;
       +                ulong off;
       +        } acache;
       +};
       +
       +DwarfAbbrev *dwarfgetabbrev(Dwarf*, ulong, ulong);
       +
       +int dwarfgetinfounit(Dwarf*, ulong, DwarfBlock*);
       +
       +extern int dwarf386nregs;
       +extern char *dwarf386regs[];
       +extern char *dwarf386fp;
       +
   DIR diff --git a/src/libmach/dwarf386.c b/src/libmach/dwarf386.c
       t@@ -0,0 +1,24 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <mach.h>
       +#include "elf.h"
       +#include "dwarf.h"
       +
       +char*
       +dwarf386regs[] = 
       +{
       +        "AX",
       +        "CX",
       +        "DX",
       +        "BX",
       +        "SP",
       +        "BP",
       +        "SI",
       +        "DI",
       +        "LR",
       +        "CFA",
       +};
       +
       +int dwarf386nregs = 10;
       +
       +
   DIR diff --git a/src/libmach/dwarfabbrev.c b/src/libmach/dwarfabbrev.c
       t@@ -0,0 +1,129 @@
       +/*
       + * Dwarf abbreviation parsing code.
       + *
       + * The convention here is that calling dwarfgetabbrevs relinquishes
       + * access to any abbrevs returned previously.  Will have to add 
       + * explicit reference counting if this turns out not to be acceptable.
       + */
       +
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include "elf.h"
       +#include "dwarf.h"
       +
       +static int parseabbrevs(Dwarf*, ulong, DwarfAbbrev*, DwarfAttr*, int*, int*);
       +DwarfAbbrev *dwarfgetabbrev(Dwarf*, ulong, ulong);
       +
       +static int
       +loadabbrevs(Dwarf *d, ulong off, DwarfAbbrev **aa)
       +{
       +        int nattr, nabbrev;
       +        DwarfAbbrev *abbrev;
       +        DwarfAttr *attr;
       +
       +        if(d->acache.off == off && d->acache.na){
       +                *aa = d->acache.a;
       +                return d->acache.na;
       +        }
       +
       +        /* two passes - once to count, then allocate, then a second to copy */
       +        if(parseabbrevs(d, off, nil, nil, &nabbrev, &nattr) < 0)
       +                return -1;
       +
       +        abbrev = malloc(nabbrev*sizeof(DwarfAbbrev) + nattr*sizeof(DwarfAttr));
       +        attr = (DwarfAttr*)(abbrev+nabbrev);
       +
       +        if(parseabbrevs(d, off, abbrev, attr, nil, nil) < 0){
       +                free(abbrev);
       +                return -1;
       +        }
       +
       +        free(d->acache.a);
       +        d->acache.a = abbrev;
       +        d->acache.na = nabbrev;
       +        d->acache.off = off;
       +
       +        *aa = abbrev;
       +        return nabbrev;
       +}
       +
       +static int
       +parseabbrevs(Dwarf *d, ulong off, DwarfAbbrev *abbrev, DwarfAttr *attr, int *pnabbrev, int *pnattr)
       +{
       +        int i, nabbrev, nattr, haskids;
       +        ulong num, tag, name, form;
       +        DwarfBuf b;
       +
       +        if(off >= d->abbrev.len){
       +                werrstr("bad abbrev section offset 0x%lux >= 0x%lux\n", off, d->abbrev.len);
       +                return -1;
       +        }
       +
       +        memset(&b, 0, sizeof b);
       +        b.p = d->abbrev.data + off;
       +        b.ep = d->abbrev.data + d->abbrev.len;
       +
       +        nabbrev = 0;
       +        nattr = 0;
       +        for(;;){
       +                if(b.p == nil){
       +                        werrstr("malformed abbrev data");
       +                        return -1;
       +                }
       +                num = dwarfget128(&b);
       +                if(num == 0)
       +                        break;
       +                tag = dwarfget128(&b);
       +                haskids = dwarfget1(&b);
       +                for(i=0;; i++){
       +                        name = dwarfget128(&b);
       +                        form = dwarfget128(&b);
       +                        if(name == 0 && form == 0)
       +                                break;
       +                        if(attr){
       +                                attr[i].name = name;
       +                                attr[i].form = form;
       +                        }
       +                }
       +                if(abbrev){
       +                        abbrev->num = num;
       +                        abbrev->tag = tag;
       +                        abbrev->haskids = haskids;
       +                        abbrev->attr = attr;
       +                        abbrev->nattr = i;
       +                        abbrev++;
       +                        attr += i;
       +                }
       +                nabbrev++;
       +                nattr += i;
       +        }
       +        if(pnabbrev)
       +                *pnabbrev = nabbrev;
       +        if(pnattr)
       +                *pnattr = nattr;
       +        return 0;
       +}
       +
       +static DwarfAbbrev*
       +findabbrev(DwarfAbbrev *a, int na, ulong num)
       +{
       +        int i;
       +
       +        for(i=0; i<na; i++)
       +                if(a[i].num == num)
       +                        return &a[i];
       +        return nil;
       +}
       +
       +DwarfAbbrev*
       +dwarfgetabbrev(Dwarf *d, ulong off, ulong num)
       +{
       +        DwarfAbbrev *a;
       +        int na;
       +
       +        if((na = loadabbrevs(d, off, &a)) < 0)
       +                return nil;
       +        return findabbrev(a, na, num);
       +}
       +
   DIR diff --git a/src/libmach/dwarfaranges.c b/src/libmach/dwarfaranges.c
       t@@ -0,0 +1,63 @@
       +/*
       + * Dwarf address ranges parsing code.
       + */
       +
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include "elf.h"
       +#include "dwarf.h"
       +
       +int
       +dwarfaddrtounit(Dwarf *d, ulong addr, ulong *unit)
       +{
       +        DwarfBuf b;
       +        int segsize, i;
       +        ulong len, id, off, base, size;
       +        uchar *start, *end;
       +
       +        memset(&b, 0, sizeof b);
       +        b.d = d;
       +        b.p = d->aranges.data;
       +        b.ep = b.p + d->aranges.len;
       +
       +        while(b.p < b.ep){
       +                start = b.p;
       +                len = dwarfget4(&b);
       +                if((id = dwarfget2(&b)) != 2){
       +                        if(b.p == nil){
       +                        underflow:
       +                                werrstr("buffer underflow reading address ranges header");
       +                        }else
       +                                werrstr("bad dwarf version 0x%lux in address ranges header", id);
       +                        return -1;
       +                }
       +                off = dwarfget4(&b);
       +                b.addrsize = dwarfget1(&b);
       +                if(d->addrsize == 0)
       +                        d->addrsize = b.addrsize;
       +                segsize = dwarfget1(&b);
       +                USED(segsize);        /* what am i supposed to do with this? */
       +                if(b.p == nil)
       +                        goto underflow;
       +                if((i = (b.p-start) % (2*b.addrsize)) != 0)
       +                        b.p += 2*b.addrsize - i;
       +                end = start+4+len;
       +                while(b.p!=nil && b.p<end){
       +                        base = dwarfgetaddr(&b);
       +                        size = dwarfgetaddr(&b);
       +                        if(b.p == nil)
       +                                goto underflow;
       +                        if(base <= addr && addr < base+size){
       +                                *unit = off;
       +                                return 0;
       +                        }
       +                }
       +                if(b.p == nil)
       +                        goto underflow;
       +                b.p = end;
       +        }
       +        werrstr("address 0x%lux is not listed in dwarf debugging symbols", addr);
       +        return -1;
       +}
       +
   DIR diff --git a/src/libmach/dwarfcfa.c b/src/libmach/dwarfcfa.c
       t@@ -0,0 +1,391 @@
       +/*
       + * Dwarf call frame unwinding.
       + *
       + * The call frame unwinding values are encoded using a state machine 
       + * like the pc<->line mapping, but it's a different machine.  
       + * The expressions to generate the old values are similar in function to the 
       + * ``dwarf expressions'' used for locations in the code, but of course not
       + * the same encoding.  
       + */
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include "elf.h"
       +#include "dwarf.h"
       +
       +#define trace 0
       +
       +typedef struct State State;
       +struct State
       +{
       +        ulong loc;
       +        ulong endloc;
       +        ulong iquantum;
       +        ulong dquantum;
       +        char *augmentation;
       +        int version;
       +        ulong rareg;
       +        DwarfBuf init;
       +        DwarfExpr *cfa;
       +        DwarfExpr *ra;
       +        DwarfExpr *r;
       +        DwarfExpr *initr;
       +        int nr;
       +        DwarfExpr **stack;
       +        int nstack;
       +};
       +
       +static int findfde(Dwarf*, ulong, State*, DwarfBuf*);
       +static int dexec(DwarfBuf*, State*, int);
       +
       +int
       +dwarfunwind(Dwarf *d, ulong pc, DwarfExpr *cfa, DwarfExpr *ra, DwarfExpr *r, int nr)
       +{
       +        int i, ret;
       +        DwarfBuf fde, b;
       +        DwarfExpr *initr;
       +        State s;
       +
       +        initr = mallocz(nr*sizeof(initr[0]), 1);
       +        if(initr == 0)
       +                return -1;
       +
       +        memset(&s, 0, sizeof s);
       +        s.loc = 0;
       +        s.cfa = cfa;
       +        s.ra = ra;
       +        s.r = r;
       +        s.nr = nr;
       +
       +        if(findfde(d, pc, &s, &fde) < 0){
       +                free(initr);
       +                return -1;
       +        }
       +
       +        memset(r, 0, nr*sizeof(r[0]));
       +        for(i=0; i<nr; i++)
       +                r[i].type = RuleSame;
       +        if(trace) fprint(2, "s.init %p-%p, fde %p-%p\n", s.init.p, s.init.ep, fde.p, fde.ep);
       +        b = s.init;
       +        if(dexec(&b, &s, 0) < 0)
       +                goto err;
       +
       +        s.initr = initr;
       +        memmove(initr, r, nr*sizeof(initr[0]));
       +
       +        if(trace) fprint(2, "s.loc 0x%lux pc 0x%lux\n", s.loc, pc);
       +        while(s.loc < pc){
       +                if(trace) fprint(2, "s.loc 0x%lux pc 0x%lux\n", s.loc, pc);
       +                if(dexec(&fde, &s, 1) < 0)
       +                        goto err;
       +        }
       +        *ra = s.r[s.rareg];
       +
       +        ret = 0;
       +        goto out;
       +
       +err:
       +        ret = -1;
       +out:
       +        free(initr);
       +        for(i=0; i<s.nstack; i++)
       +                free(s.stack[i]);
       +        free(s.stack);
       +        return ret;
       +}
       +
       +/*
       + * XXX This turns out to be much more expensive than the actual
       + * running of the machine in dexec.  It probably makes sense to
       + * cache the last 10 or so fde's we've found, since stack traces 
       + * will keep asking for the same info over and over.
       + */
       +static int
       +findfde(Dwarf *d, ulong pc, State *s, DwarfBuf *fde)
       +{
       +        static int nbad;
       +        char *aug;
       +        uchar *next;
       +        int i, vers;
       +        ulong len, id, base, size;
       +        DwarfBuf b;
       +
       +        b.d = d;
       +        b.p = d->frame.data;
       +        b.ep = b.p + d->frame.len;
       +        b.addrsize = d->addrsize;
       +        if(b.addrsize == 0)
       +                b.addrsize = 4;        /* where should i find this? */
       +
       +        for(; b.p < b.ep; b.p = next){
       +                if((i = (b.p - d->frame.data) % b.addrsize))
       +                        b.p += b.addrsize - i;
       +                len = dwarfget4(&b);
       +                if(len > b.ep-b.p){
       +                        werrstr("bad length in cie/fde header");
       +                        return -1;
       +                }
       +                next = b.p+len;
       +                id = dwarfget4(&b);
       +                if(id == 0xFFFFFFFF){        /* CIE */
       +                        vers = dwarfget1(&b);
       +                        if(vers != 1 && vers != 2 && vers != 3){
       +                                if(++nbad == 1)
       +                                        fprint(2, "unknown cie version %d (wanted 1-3)\n", vers);
       +                                continue;
       +                        }
       +                        aug = dwarfgetstring(&b);
       +                        if(aug && *aug){
       +                                if(++nbad == 1)
       +                                        fprint(2, "unknown augmentation: %s\n", aug);
       +                                continue;
       +                        }
       +                        s->iquantum = dwarfget128(&b);
       +                        s->dquantum = dwarfget128s(&b);
       +                        s->rareg = dwarfget128(&b);
       +                        if(s->rareg > s->nr){
       +                                werrstr("return address is register %d but only have %d registers",
       +                                        s->rareg, s->nr);
       +                                return -1;
       +                        }
       +                        s->init.p = b.p;
       +                        s->init.ep = next;
       +                }else{        /* FDE */
       +                        base = dwarfgetaddr(&b);
       +                        size = dwarfgetaddr(&b);
       +                        fde->p = b.p;
       +                        fde->ep = next;
       +                        s->loc = base;
       +                        s->endloc = base+size;
       +                        if(base <= pc && pc < base+size)
       +                                return 0;
       +                }
       +        }
       +        werrstr("cannot find call frame information for pc 0x%lux", pc);
       +        return -1;
       +                        
       +}
       +
       +static int
       +checkreg(State *s, long r)
       +{
       +        if(r < 0 || r >= s->nr){
       +                werrstr("bad register number 0x%lux", r);
       +                return -1;
       +        }
       +        return 0;
       +}
       +
       +static int
       +dexec(DwarfBuf *b, State *s, int locstop)
       +{
       +        int c;
       +        long arg1, arg2;
       +        DwarfExpr *e, **p;
       +
       +        for(;;){
       +                if(b->p == b->ep){
       +                        if(s->initr)
       +                                s->loc = s->endloc;
       +                        return 0;
       +                }
       +                c = dwarfget1(b);
       +                if(b->p == nil){
       +                        werrstr("ran out of instructions during cfa program");
       +                        if(trace) fprint(2, "%r\n");
       +                        return -1;
       +                }
       +                if(trace) fprint(2, "+ loc=0x%lux op 0x%ux ", s->loc, c);
       +                switch(c>>6){
       +                case 1:        /* advance location */
       +                        arg1 = c&0x3F;
       +                advance:
       +                        if(trace) fprint(2, "loc += %ld\n", arg1*s->iquantum);
       +                        s->loc += arg1 * s->iquantum;
       +                        if(locstop)
       +                                return 0;
       +                        continue;
       +                
       +                case 2:        /* offset rule */
       +                        arg1 = c&0x3F;
       +                        arg2 = dwarfget128(b);
       +                offset:
       +                        if(trace) fprint(2, "r%ld += %ld\n", arg1, arg2*s->dquantum);
       +                        if(checkreg(s, arg1) < 0)
       +                                return -1;
       +                        s->r[arg1].type = RuleCfaOffset;
       +                        s->r[arg1].offset = arg2 * s->dquantum;
       +                        continue;
       +
       +                case 3:        /* restore initial setting */
       +                        arg1 = c&0x3F;
       +                restore:
       +                        if(trace) fprint(2, "r%ld = init\n", arg1);
       +                        if(checkreg(s, arg1) < 0)
       +                                return -1;
       +                        s->r[arg1] = s->initr[arg1];
       +                        continue;
       +                }
       +
       +                switch(c){
       +                case 0:        /* nop */
       +                        if(trace) fprint(2, "nop\n");
       +                        continue;
       +
       +                case 0x01:        /* set location */
       +                        s->loc = dwarfgetaddr(b);
       +                        if(trace) fprint(2, "loc = 0x%lux\n", s->loc);
       +                        if(locstop)
       +                                return 0;
       +                        continue;
       +
       +                case 0x02:        /* advance loc1 */
       +                        arg1 = dwarfget1(b);
       +                        goto advance;
       +
       +                case 0x03:        /* advance loc2 */
       +                        arg1 = dwarfget2(b);
       +                        goto advance;
       +
       +                case 0x04:        /* advance loc4 */
       +                        arg1 = dwarfget4(b);
       +                        goto advance;
       +
       +                case 0x05:        /* offset extended */
       +                        arg1 = dwarfget128(b);
       +                        arg2 = dwarfget128(b);
       +                        goto offset;
       +
       +                case 0x06:        /* restore extended */
       +                        arg1 = dwarfget128(b);
       +                        goto restore;
       +
       +                case 0x07:        /* undefined */
       +                        arg1 = dwarfget128(b);
       +                        if(trace) fprint(2, "r%ld = undef\n", arg1);
       +                        if(checkreg(s, arg1) < 0)
       +                                return -1;
       +                        s->r[arg1].type = RuleUndef;
       +                        continue;
       +
       +                case 0x08:        /* same value */
       +                        arg1 = dwarfget128(b);
       +                        if(trace) fprint(2, "r%ld = same\n", arg1);
       +                        if(checkreg(s, arg1) < 0)
       +                                return -1;
       +                        s->r[arg1].type = RuleSame;
       +                        continue;
       +
       +                case 0x09:        /* register */
       +                        arg1 = dwarfget128(b);
       +                        arg2 = dwarfget128(b);
       +                        if(trace) fprint(2, "r%ld = r%ld\n", arg1, arg2);
       +                        if(checkreg(s, arg1) < 0 || checkreg(s, arg2) < 0)
       +                                return -1;
       +                        s->r[arg1].type = RuleRegister;
       +                        s->r[arg1].reg = arg2;
       +                        continue;
       +
       +                case 0x0A:        /* remember state */
       +                        e = malloc(s->nr*sizeof(e[0]));
       +                        if(trace) fprint(2, "push\n");
       +                        if(e == nil)
       +                                return -1;
       +                        p = realloc(s->stack, (s->nstack+1)*sizeof(s->stack[0]));
       +                        if(p == nil){
       +                                free(e);
       +                                return -1;
       +                        }
       +                        s->stack[s->nstack++] = e;
       +                        memmove(e, s->r, s->nr*sizeof(e[0]));
       +                        continue;
       +
       +                case 0x0B:        /* restore state */
       +                        if(trace) fprint(2, "pop\n");
       +                        if(s->nstack == 0){
       +                                werrstr("restore state underflow");
       +                                return -1;
       +                        }
       +                        e = s->stack[s->nstack-1];
       +                        memmove(s->r, e, s->nr*sizeof(e[0]));
       +                        p = realloc(s->stack, (s->nstack-1)*sizeof(s->stack[0]));
       +                        if(p == nil)
       +                                return -1;
       +                        free(e);
       +                        s->nstack--;
       +                        continue;
       +
       +                case 0x0C:        /* def cfa */
       +                        arg1 = dwarfget128(b);
       +                        arg2 = dwarfget128(b);
       +                defcfa:
       +                        if(trace) fprint(2, "cfa %ld(r%ld)\n", arg2, arg1);
       +                        if(checkreg(s, arg1) < 0)
       +                                return -1;
       +                        s->cfa->type = RuleRegOff;
       +                        s->cfa->reg = arg1;
       +                        s->cfa->offset = arg2;
       +                        continue;
       +
       +                case 0x0D:        /* def cfa register */        
       +                        arg1 = dwarfget128(b);
       +                        if(trace) fprint(2, "cfa reg r%ld\n", arg1);
       +                        if(s->cfa->type != RuleRegOff){
       +                                werrstr("change CFA register but CFA not in register+offset form");
       +                                return -1;        
       +                        }
       +                        if(checkreg(s, arg1) < 0)
       +                                return -1;
       +                        s->cfa->reg = arg1;
       +                        continue;
       +
       +                case 0x0E:        /* def cfa offset */
       +                        arg1 = dwarfget128(b);
       +                cfaoffset:
       +                        if(trace) fprint(2, "cfa off %ld\n", arg1);
       +                        if(s->cfa->type != RuleRegOff){
       +                                werrstr("change CFA offset but CFA not in register+offset form");
       +                                return -1;
       +                        }
       +                        s->cfa->offset = arg1;
       +                        continue;
       +
       +                case 0x0F:        /* def cfa expression */
       +                        if(trace) fprint(2, "cfa expr\n");
       +                        s->cfa->type = RuleLocation;
       +                        s->cfa->loc.len = dwarfget128(b);
       +                        s->cfa->loc.data = dwarfgetnref(b, s->cfa->loc.len);
       +                        continue;
       +
       +                case 0x10:        /* def reg expression */
       +                        arg1 = dwarfget128(b);
       +                        if(trace) fprint(2, "reg expr r%ld\n", arg1);
       +                        if(checkreg(s, arg1) < 0)
       +                                return -1;
       +                        s->r[arg1].type = RuleLocation;
       +                        s->r[arg1].loc.len = dwarfget128(b);
       +                        s->r[arg1].loc.data = dwarfgetnref(b, s->r[arg1].loc.len);
       +                        continue;
       +
       +                case 0x11:        /* offset extended */
       +                        arg1 = dwarfget128(b);
       +                        arg2 = dwarfget128s(b);
       +                        goto offset;
       +
       +                case 0x12:        /* cfa sf */
       +                        arg1 = dwarfget128(b);
       +                        arg2 = dwarfget128s(b);
       +                        goto defcfa;
       +
       +                case 0x13:        /* cfa offset sf */
       +                        arg1 = dwarfget128s(b);
       +                        goto cfaoffset;
       +
       +                default:        /* unknown */
       +                        werrstr("unknown opcode 0x%ux in cfa program", c);
       +                        return -1;
       +                }
       +        }
       +        return -1;                /* not reached */                
       +}
       +
   DIR diff --git a/src/libmach/dwarfdump.c b/src/libmach/dwarfdump.c
       t@@ -0,0 +1,138 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include "elf.h"
       +#include "dwarf.h"
       +
       +void printrules(Dwarf *d, ulong pc);
       +int exprfmt(Fmt*);
       +
       +void
       +usage(void)
       +{
       +        fprint(2, "usage: dwarfdump file\n");
       +        exits("usage");
       +}
       +
       +void
       +main(int argc, char **argv)
       +{
       +        int c;
       +        Elf *elf;
       +        Dwarf *d;
       +        DwarfSym s;
       +        char *cdir, *dir, *file;
       +        ulong line, mtime, length;
       +
       +        ARGBEGIN{
       +        default:
       +                usage();
       +        }ARGEND
       +
       +        if(argc != 1)
       +                usage();
       +
       +        fmtinstall('R', exprfmt);
       +        fmtinstall('H', encodefmt);
       +
       +        if((elf = elfopen(argv[0])) == nil)
       +                sysfatal("elfopen %s: %r", argv[0]);
       +        if((d=dwarfopen(elf)) == nil)
       +                sysfatal("dwarfopen: %r");
       +
       +        if(dwarfenum(d, &s) < 0)
       +                sysfatal("dwarfenumall: %r");
       +
       +        while(dwarfnextsym(d, &s, 1) == 1){
       +                switch(s.attrs.tag){
       +                case TagCompileUnit:
       +                        print("compileunit %s\n", s.attrs.name);
       +                        break;
       +                case TagSubprogram:
       +                        c = 't';
       +                        goto sym;
       +                case TagVariable:
       +                        c = 'd';
       +                        goto sym;
       +                case TagConstant:
       +                        c = 'c';
       +                        goto sym;
       +                case TagFormalParameter:
       +                        if(!s.attrs.name)
       +                                break;
       +                        c = 'p';
       +                sym:
       +                        if(s.attrs.isexternal)
       +                                c += 'A' - 'a';
       +                        print("%c %s", c, s.attrs.name);
       +                        if(s.attrs.have.lowpc)
       +                                print(" 0x%lux-0x%lux", s.attrs.lowpc, s.attrs.highpc);
       +                        switch(s.attrs.have.location){
       +                        case TBlock:
       +                                print(" @ %.*H", s.attrs.location.b.len, s.attrs.location.b.data);
       +                                break;
       +                        case TConstant:
       +                                print(" @ 0x%lux", s.attrs.location.c);
       +                                break;
       +                        }
       +                        if(s.attrs.have.ranges)
       +                                print(" ranges@0x%lux", s.attrs.ranges);
       +                        print("\n");
       +                        if(s.attrs.have.lowpc){
       +                                if(dwarfpctoline(d, s.attrs.lowpc, &cdir, &dir, &file, &line, &mtime, &length) < 0)
       +                                        print("\tcould not find source: %r\n");
       +                                else
       +                                        print("\t%s/%s/%s:%lud mtime=%lud length=%lud\n",
       +                                                cdir, dir, file, line, mtime, length);
       +
       +                                if(0) printrules(d, s.attrs.lowpc);
       +                                if(0) printrules(d, (s.attrs.lowpc+s.attrs.highpc)/2);
       +                        }
       +                        break;
       +                }
       +        }
       +        exits(0);
       +}
       +
       +void
       +printrules(Dwarf *d, ulong pc)
       +{
       +        int i;
       +        DwarfExpr r[10];
       +        DwarfExpr cfa, ra;
       +
       +        if(dwarfunwind(d, pc, &cfa, &ra, r, nelem(r)) < 0)
       +                print("\tcannot unwind from pc 0x%lux: %r\n", pc);
       +
       +        print("\tpc=0x%lux cfa=%R ra=%R", pc, &cfa, &ra);
       +        for(i=0; i<nelem(r); i++)
       +                if(r[i].type != RuleSame)
       +                        print(" r%d=%R", i, &r[i]);
       +        print("\n");
       +}
       +
       +int
       +exprfmt(Fmt *fmt)
       +{
       +        DwarfExpr *e;
       +
       +        if((e = va_arg(fmt->args, DwarfExpr*)) == nil)
       +                return fmtstrcpy(fmt, "<nil>");
       +
       +        switch(e->type){
       +        case RuleUndef:
       +                return fmtstrcpy(fmt, "undef");
       +        case RuleSame:
       +                return fmtstrcpy(fmt, "same");
       +        case RuleCfaOffset:
       +                return fmtprint(fmt, "%ld(cfa)", e->offset);
       +        case RuleRegister:
       +                return fmtprint(fmt, "r%ld", e->reg);
       +        case RuleRegOff:
       +                return fmtprint(fmt, "%ld(r%ld)", e->offset, e->reg);
       +        case RuleLocation:
       +                return fmtprint(fmt, "l.%.*H", e->loc.len, e->loc.data);
       +        default:
       +                return fmtprint(fmt, "?%d", e->type);
       +        }
       +}
   DIR diff --git a/src/libmach/dwarfeval.c b/src/libmach/dwarfeval.c
       t@@ -0,0 +1,62 @@
       +        OpAddr = 0x03,        // 1 op, const addr
       +        OpDeref = 0x06,
       +        OpConst1u = 0x08,        // 1 op, 1 byte const
       +        OpConst1s = 0x09,        //        " signed
       +        OpConst2u = 0x0A        // 1 op, 2 byte const 
       +        OpConst2s = 0x0B,        //        " signed
       +        OpConst4u = 0x0C,        // 1 op, 4 byte const
       +        OpConst4s = 0x0D,        //        " signed
       +        OpConst8u = 0x0E,        // 1 op, 8 byte const
       +        OpConst8s = 0x0F,        //        " signed
       +        OpConstu = 0x10,        // 1 op, LEB128 const
       +        OpConsts = 0x11,        //        " signed
       +        OpDup = 0x12,
       +        OpDrop = 0x13,
       +        OpOver = 0x14,
       +        OpPick = 0x15,                // 1 op, 1 byte stack index
       +        OpSwap = 0x16,
       +        OpRot = 0x17,
       +        OpXderef = 0x18,
       +        OpAbs = 0x19,
       +        OpAnd = 0x1A,
       +        OpDiv = 0x1B,
       +        OpMinus = 0x1C,
       +        OpMod = 0x1D,
       +        OpMul = 0x1E,
       +        OpNeg = 0x1F,
       +        OpNot = 0x20,
       +        OpOr = 0x21,
       +        OpPlus = 0x22,
       +        OpPlusUconst = 0x23,        // 1 op, ULEB128 addend
       +        OpShl = 0x24,
       +        OpShr = 0x25,
       +        OpShra = 0x26,
       +        OpXor = 0x27,
       +        OpSkip = 0x2F,                // 1 op, signed 2-byte constant
       +        OpBra = 0x28,                // 1 op, signed 2-byte constant
       +        OpEq = 0x29,
       +        OpGe = 0x2A,
       +        OpGt = 0x2B,
       +        OpLe = 0x2C,
       +        OpLt = 0x2D,
       +        OpNe = 0x2E,
       +        OpLit0 = 0x30,
       +                // OpLitN = OpLit0 + N for N = 0..31
       +        OpReg0 = 0x50,
       +                // OpRegN = OpReg0 + N for N = 0..31
       +        OpBreg0 = 0x70,        // 1 op, signed LEB128 constant
       +                // OpBregN = OpBreg0 + N for N = 0..31
       +        OpRegx = 0x90,        // 1 op, ULEB128 register
       +        OpFbreg = 0x91,        // 1 op, SLEB128 offset
       +        OpBregx = 0x92,        // 2 op, ULEB128 reg, SLEB128 off
       +        OpPiece = 0x93,        // 1 op, ULEB128 size of piece
       +        OpDerefSize = 0x94,        // 1-byte size of data retrieved
       +        OpXderefSize = 0x95,        // 1-byte size of data retrieved
       +        OpNop = 0x96,
       +        // next four new in Dwarf v3
       +        OpPushObjAddr = 0x97,
       +        OpCall2 = 0x98,        // 2-byte offset of DIE
       +        OpCall4 = 0x99,        // 4-byte offset of DIE
       +        OpCallRef = 0x9A,        // 4- or 8- byte offset of DIE
       +        // 0xE0-0xFF reserved for user-specific
       +
   DIR diff --git a/src/libmach/dwarfget.c b/src/libmach/dwarfget.c
       t@@ -0,0 +1,217 @@
       +/*
       + * Dwarf data format parsing routines.
       + */
       +
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include "elf.h"
       +#include "dwarf.h"
       +
       +ulong
       +dwarfget1(DwarfBuf *b)
       +{
       +        if(b->p==nil || b->p+1 > b->ep){
       +                b->p = nil;
       +                return 0;
       +        }
       +        return *b->p++;
       +}
       +
       +int
       +dwarfgetn(DwarfBuf *b, uchar *a, int n)
       +{
       +        if(b->p==nil || b->p+n > b->ep){
       +                b->p = nil;
       +                memset(a, 0, n);
       +                return -1;
       +        }
       +        memmove(a, b->p, n);
       +        b->p += n;
       +        return 0;
       +}
       +
       +uchar*
       +dwarfgetnref(DwarfBuf *b, ulong n)
       +{
       +        uchar *p;
       +
       +        if(b->p==nil || b->p+n > b->ep){
       +                b->p = nil;
       +                return nil;
       +        }
       +        p = b->p;
       +        b->p += n;
       +        return p;
       +}
       +
       +char*
       +dwarfgetstring(DwarfBuf *b)
       +{
       +        char *s;
       +
       +        if(b->p == nil)
       +                return nil;
       +        s = (char*)b->p;
       +        while(b->p < b->ep && *b->p)
       +                b->p++;
       +        if(b->p >= b->ep){
       +                b->p = nil;
       +                return nil;
       +        }
       +        b->p++;
       +        return s;
       +}
       +
       +void
       +dwarfskip(DwarfBuf *b, int n)
       +{
       +        if(b->p==nil || b->p+n > b->ep)
       +                b->p = nil;
       +        else
       +                b->p += n;
       +}
       +
       +ulong
       +dwarfget2(DwarfBuf *b)
       +{
       +        ulong v;
       +
       +        if(b->p==nil || b->p+2 > b->ep){
       +                b->p = nil;
       +                return 0;
       +        }
       +        v = b->d->elf->hdr.e2(b->p);
       +        b->p += 2;
       +        return v;
       +}
       +
       +ulong
       +dwarfget4(DwarfBuf *b)
       +{
       +        ulong v;
       +
       +        if(b->p==nil || b->p+4 > b->ep){
       +                b->p = nil;
       +                return 0;
       +        }
       +        v = b->d->elf->hdr.e4(b->p);
       +        b->p += 4;
       +        return v;
       +}
       +
       +uvlong
       +dwarfget8(DwarfBuf *b)
       +{
       +        uvlong v;
       +
       +        if(b->p==nil || b->p+8 > b->ep){
       +                b->p = nil;
       +                return 0;
       +        }
       +        v = b->d->elf->hdr.e8(b->p);
       +        b->p += 8;
       +        return v;
       +}
       +
       +ulong
       +dwarfgetaddr(DwarfBuf *b)
       +{
       +        static int nbad;
       +
       +        if(b->addrsize == 0)
       +                b->addrsize = b->d->addrsize;
       +
       +        switch(b->addrsize){
       +        case 1:
       +                return dwarfget1(b);
       +        case 2:
       +                return dwarfget2(b);
       +        case 4:
       +                return dwarfget4(b);
       +        case 8:
       +                return dwarfget8(b);
       +        default:
       +                if(++nbad == 1)
       +                        fprint(2, "dwarf: unexpected address size %lud in dwarfgetaddr\n", b->addrsize);
       +                b->p = nil;
       +                return 0;
       +        }
       +}
       +
       +int n1, n2, n3, n4, n5;
       +
       +/* An inline function picks off the calls to dwarfget128 for 1-byte encodings,
       + * more than by far the common case (99.999% on most binaries!). */
       +ulong
       +dwarfget128(DwarfBuf *b)
       +{
       +        static int nbad;
       +        ulong c, d;
       +
       +        if(b->p == nil)
       +                return 0;
       +        c = *b->p++;
       +        if(!(c&0x80))
       +{n1++;
       +                return c;
       +}
       +        d = *b->p++;
       +        c |= (d&0x7F)<<7;
       +        if(!(d&0x80))
       +{n2++;
       +                return c;
       +}
       +        d = *b->p++;
       +        c |= (d&0x7F)<<14;
       +        if(!(d&0x80))
       +{n3++;
       +                return c;
       +}
       +        d = *b->p++;
       +        c |= (d&0x7F)<<21;
       +        if(!(d&0x80))
       +{n4++;
       +                return c;
       +}
       +        d = *b->p++;
       +        c |= (d&0x7F)<<28;
       +        if(!(d&0x80))
       +{n5++;
       +                return c;
       +}
       +        while(b->p<b->ep && *b->p&0x80)
       +                b->p++;
       +        if(++nbad == 1)
       +                fprint(2, "dwarf: overflow during parsing of uleb128 integer\n");
       +        return c;
       +}
       +
       +long
       +dwarfget128s(DwarfBuf *b)
       +{
       +        int nb, c;
       +        ulong v;
       +        static int nbad;
       +
       +        v = 0;
       +        nb = 0;
       +        if(b->p==nil)
       +                return 0;
       +        while(b->p<b->ep){
       +                c = *b->p++;
       +                v |= (c & 0x7F)<<nb;
       +                nb += 7;
       +                if(!(c&0x80))
       +                        break;
       +        }
       +        if(v&(1<<(nb-1)))
       +                v |= ~(((ulong)1<<nb)-1);
       +        if(nb > 8*sizeof(ulong)){
       +                if(0)
       +                if(++nbad == 1)
       +                        fprint(2, "dwarf: overflow during parsing of sleb128 integer: got %d bits\n", nb);
       +        }
       +        return v;
       +}
       +
   DIR diff --git a/src/libmach/dwarfinfo.c b/src/libmach/dwarfinfo.c
       t@@ -0,0 +1,646 @@
       +/*
       + * Dwarf info parse and search.
       + */
       +
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include "elf.h"
       +#include "dwarf.h"
       +
       +enum
       +{
       +        DwarfAttrSibling = 0x01,
       +        DwarfAttrLocation = 0x02,
       +        DwarfAttrName = 0x03,
       +        DwarfAttrOrdering = 0x09,
       +        DwarfAttrByteSize = 0x0B,
       +        DwarfAttrBitOffset = 0x0C,
       +        DwarfAttrBitSize = 0x0D,
       +        DwarfAttrStmtList = 0x10,
       +        DwarfAttrLowpc = 0x11,
       +        DwarfAttrHighpc = 0x12,
       +        DwarfAttrLanguage = 0x13,
       +        DwarfAttrDiscr = 0x15,
       +        DwarfAttrDiscrValue = 0x16,
       +        DwarfAttrVisibility = 0x17,
       +        DwarfAttrImport = 0x18,
       +        DwarfAttrStringLength = 0x19,
       +        DwarfAttrCommonRef = 0x1A,
       +        DwarfAttrCompDir = 0x1B,
       +        DwarfAttrConstValue = 0x1C,
       +        DwarfAttrContainingType = 0x1D,
       +        DwarfAttrDefaultValue = 0x1E,
       +        DwarfAttrInline = 0x20,
       +        DwarfAttrIsOptional = 0x21,
       +        DwarfAttrLowerBound = 0x22,
       +        DwarfAttrProducer = 0x25,
       +        DwarfAttrPrototyped = 0x27,
       +        DwarfAttrReturnAddr = 0x2A,
       +        DwarfAttrStartScope = 0x2C,
       +        DwarfAttrStrideSize = 0x2E,
       +        DwarfAttrUpperBound = 0x2F,
       +        DwarfAttrAbstractOrigin = 0x31,
       +        DwarfAttrAccessibility = 0x32,
       +        DwarfAttrAddrClass = 0x33,
       +        DwarfAttrArtificial = 0x34,
       +        DwarfAttrBaseTypes = 0x35,
       +        DwarfAttrCalling = 0x36,
       +        DwarfAttrCount = 0x37,
       +        DwarfAttrDataMemberLoc = 0x38,
       +        DwarfAttrDeclColumn = 0x39,
       +        DwarfAttrDeclFile = 0x3A,
       +        DwarfAttrDeclLine = 0x3B,
       +        DwarfAttrDeclaration = 0x3C,
       +        DwarfAttrDiscrList = 0x3D,
       +        DwarfAttrEncoding = 0x3E,
       +        DwarfAttrExternal = 0x3F,
       +        DwarfAttrFrameBase = 0x40,
       +        DwarfAttrFriend = 0x41,
       +        DwarfAttrIdentifierCase = 0x42,
       +        DwarfAttrMacroInfo = 0x43,
       +        DwarfAttrNamelistItem = 0x44,
       +        DwarfAttrPriority = 0x45,
       +        DwarfAttrSegment = 0x46,
       +        DwarfAttrSpecification = 0x47,
       +        DwarfAttrStaticLink = 0x48,
       +        DwarfAttrType = 0x49,
       +        DwarfAttrUseLocation = 0x4A,
       +        DwarfAttrVarParam = 0x4B,
       +        DwarfAttrVirtuality = 0x4C,
       +        DwarfAttrVtableElemLoc = 0x4D,
       +        DwarfAttrAllocated = 0x4E,
       +        DwarfAttrAssociated = 0x4F,
       +        DwarfAttrDataLocation = 0x50,
       +        DwarfAttrStride = 0x51,
       +        DwarfAttrEntrypc = 0x52,
       +        DwarfAttrUseUTF8 = 0x53,
       +        DwarfAttrExtension = 0x54,
       +        DwarfAttrRanges = 0x55,
       +        DwarfAttrTrampoline = 0x56,
       +        DwarfAttrCallColumn = 0x57,
       +        DwarfAttrCallFile = 0x58,
       +        DwarfAttrCallLine = 0x59,
       +        DwarfAttrDescription = 0x5A,
       +        DwarfAttrMax,
       +
       +        FormAddr = 0x01,
       +        FormDwarfBlock2 = 0x03,
       +        FormDwarfBlock4 = 0x04,
       +        FormData2 = 0x05,
       +        FormData4 = 0x06,
       +        FormData8 = 0x07,
       +        FormString = 0x08,
       +        FormDwarfBlock = 0x09,
       +        FormDwarfBlock1 = 0x0A,
       +        FormData1 = 0x0B,
       +        FormFlag = 0x0C,
       +        FormSdata = 0x0D,
       +        FormStrp = 0x0E,
       +        FormUdata = 0x0F,
       +        FormRefAddr = 0x10,
       +        FormRef1 = 0x11,
       +        FormRef2 = 0x12,
       +        FormRef4 = 0x13,
       +        FormRef8 = 0x14,
       +        FormRefUdata = 0x15,
       +        FormIndirect = 0x16,
       +};
       +
       +static int parseattrs(DwarfBuf*, ulong, DwarfAbbrev*, DwarfAttrs*);
       +static int getulong(DwarfBuf*, int, ulong, ulong*, int*);
       +static int getuchar(DwarfBuf*, int, uchar*);
       +static int getstring(DwarfBuf*, int, char**);
       +static int getblock(DwarfBuf*, int, DwarfBlock*);
       +static int skipform(DwarfBuf*, int);
       +static int constblock(Dwarf*, DwarfBlock*, ulong*);
       +
       +int
       +dwarflookupnameinunit(Dwarf *d, ulong unit, char *name, DwarfSym *s)
       +{
       +        if(dwarfenumunit(d, unit, s) < 0)
       +                return -1;
       +
       +        dwarfnextsym(d, s, 1);        /* s is now the CompileUnit */
       +        if(dwarfnextsym(d, s, 1) == 1){        /* s is now the first child of the compile unit */
       +                do{
       +                        if(s->attrs.name && strcmp(s->attrs.name, name) == 0)
       +                                return 0;
       +                }while(dwarfnextsym(d, s, 0) == 1);
       +        } 
       +        werrstr("symbol '%s' not found", name);
       +        return -1;
       +}
       +        
       +
       +int
       +dwarflookupsubname(Dwarf *d, DwarfSym *parent, char *name, DwarfSym *s)
       +{
       +        *s = *parent;
       +        dwarfnextsym(d, s, 1);
       +        if(s->depth == parent->depth+1)
       +                do{
       +                        if(s->attrs.name && strcmp(s->attrs.name, name) == 0)
       +                                return 0;
       +                }while(dwarfnextsym(d, s, 0) == 1);
       +        werrstr("symbol '%s' not found", name);
       +        return -1;
       +}
       +
       +int
       +dwarflookuptag(Dwarf *d, ulong unit, ulong tag, DwarfSym *s)
       +{
       +        if(dwarfenumunit(d, unit, s) < 0)
       +                return -1;
       +
       +        dwarfnextsym(d, s, 1);        /* s is now the CompileUnit */
       +        if(s->attrs.tag == tag)
       +                return 0;
       +
       +        if(dwarfnextsym(d, s, 1) == 1){        /* s is now the first child of the compile unit */
       +                do{
       +                        if(s->attrs.tag == tag)
       +                                return 0;
       +                }while(dwarfnextsym(d, s, 0) == 1);
       +        } 
       +        werrstr("symbol with tag 0x%lux not found", tag);
       +        return -1;
       +}
       +
       +int
       +dwarfseeksym(Dwarf *d, ulong unit, ulong off, DwarfSym *s)
       +{
       +        if(dwarfenumunit(d, unit, s) < 0)
       +                return -1;
       +        s->b.p = d->info.data + unit + off;
       +        if(dwarfnextsym(d, s, 1) != 1)
       +                return -1;
       +        return 0;
       +}
       +
       +int
       +dwarflookupfn(Dwarf *d, ulong unit, ulong pc, DwarfSym *s)
       +{
       +        if(dwarfenumunit(d, unit, s) < 0)
       +                return -1;
       +
       +        if(dwarfnextsym(d, s, 1) != 1)
       +                return -1;
       +        /* s is now the CompileUnit */
       +
       +        if(dwarfnextsym(d, s, 1) == 1){        /* s is now the first child of the compile unit */
       +                do{
       +                        if(s->attrs.tag != TagSubprogram)
       +                                continue;
       +                        if(s->attrs.lowpc <= pc && pc < s->attrs.highpc)
       +                                return 0;
       +                }while(dwarfnextsym(d, s, 0) == 1);
       +        } 
       +        werrstr("fn containing pc 0x%lux not found", pc);
       +        return -1;
       +}
       +
       +int
       +dwarfenumunit(Dwarf *d, ulong unit, DwarfSym *s)
       +{
       +        int i;
       +        ulong aoff, len;
       +
       +        if(unit >= d->info.len){
       +                werrstr("dwarf unit address 0x%lux >= 0x%lux out of range", unit, d->info.len);
       +                return -1;
       +        }
       +        memset(s, 0, sizeof *s);
       +        memset(&s->b, 0, sizeof s->b);
       +        s->b.d = d;
       +        s->b.p = d->info.data + unit;
       +        s->b.ep = d->info.data + d->info.len;
       +        len = dwarfget4(&s->b);
       +        s->nextunit = unit + 4 + len;
       +
       +        if(s->b.ep - s->b.p < len){
       +        badheader:
       +                werrstr("bad dwarf unit header at unit 0x%lux", unit);
       +                return -1;
       +        }
       +        s->b.ep = s->b.p+len;
       +        if((i=dwarfget2(&s->b)) != 2)
       +                goto badheader;
       +        aoff = dwarfget4(&s->b);
       +        s->b.addrsize = dwarfget1(&s->b);
       +        if(d->addrsize == 0)
       +                d->addrsize = s->b.addrsize;
       +        if(s->b.p == nil)
       +                goto badheader;
       +
       +        s->aoff = aoff;
       +        s->unit = unit;
       +        s->depth = 0;
       +        return 0;
       +}
       +
       +int
       +dwarfenum(Dwarf *d, DwarfSym *s)
       +{
       +        if(dwarfenumunit(d, 0, s) < 0)
       +                return -1;
       +        s->allunits = 1;
       +        return 0;
       +}
       +
       +static int
       +_dwarfnextsym(Dwarf *d, DwarfSym *s)
       +{
       +        ulong num;
       +        DwarfAbbrev *a;
       +
       +        if(s->attrs.haskids)
       +                s->depth++;
       +top:
       +        if(s->b.p >= s->b.ep){
       +                if(s->allunits && s->nextunit < d->info.len){
       +                        if(dwarfenumunit(d, s->nextunit, s) < 0)
       +                                return -1;
       +                        s->allunits = 1;
       +                        goto top;
       +                }
       +                return 0;
       +        }
       +
       +        s->uoff = s->b.p - (d->info.data+s->unit);
       +        num = dwarfget128(&s->b);
       +        if(num == 0){
       +                if(s->depth == 0)
       +                        return 0;
       +                if(s->depth > 0)
       +                        s->depth--;
       +                goto top;
       +        }
       +
       +        a = dwarfgetabbrev(d, s->aoff, num);
       +        if(a == nil){
       +                fprint(2, "getabbrev %ud: %r\n", num);
       +                return -1;
       +        }
       +        if(parseattrs(&s->b, s->unit, a, &s->attrs) < 0)
       +                return -1;
       +        return 1;
       +}
       +
       +int
       +dwarfnextsym(Dwarf *d, DwarfSym *s, int recurse)
       +{
       +        int r;
       +        int depth;
       +        ulong sib;
       +
       +        if(recurse)
       +                return _dwarfnextsym(d, s);
       +
       +        depth = s->depth;
       +        if(s->attrs.have.sibling){
       +                sib = s->attrs.sibling;
       +                if(sib < d->info.len && d->info.data+sib >= s->b.p)
       +                        s->b.p = d->info.data+sib;
       +                s->attrs.haskids = 0;
       +        }
       +
       +        do{
       +                r = _dwarfnextsym(d, s);
       +                if(r <= 0)
       +                        return r;
       +        }while(s->depth != depth);
       +        if(s->depth < depth)
       +                return 0;
       +        return 1;
       +}
       +
       +typedef struct Parse Parse;
       +struct Parse {
       +        int name;
       +        int off;
       +        int haveoff;
       +        int type;
       +};
       +
       +#define OFFSET(x) offsetof(DwarfAttrs, x), offsetof(DwarfAttrs, have.x)
       +
       +static Parse plist[] = {        /* Font Tab 4 */
       +        DwarfAttrAbstractOrigin,        OFFSET(abstractorigin),                TReference,
       +        DwarfAttrAccessibility,        OFFSET(accessibility),                TConstant,
       +        DwarfAttrAddrClass,                 OFFSET(addrclass),                         TConstant,
       +        DwarfAttrArtificial,                OFFSET(isartificial),                 TFlag,
       +        DwarfAttrBaseTypes,                OFFSET(basetypes),                        TReference,
       +        DwarfAttrBitOffset,                OFFSET(bitoffset),                        TConstant,
       +        DwarfAttrBitSize,                OFFSET(bitsize),                        TConstant,
       +        DwarfAttrByteSize,                OFFSET(bytesize),                        TConstant,
       +        DwarfAttrCalling,                OFFSET(calling),                        TConstant,
       +        DwarfAttrCommonRef,                OFFSET(commonref),                        TReference,
       +        DwarfAttrCompDir,                OFFSET(compdir),                        TString,
       +        DwarfAttrConstValue,                OFFSET(constvalue),                        TString|TConstant|TBlock,
       +        DwarfAttrContainingType,        OFFSET(containingtype),                TReference,
       +        DwarfAttrCount,                        OFFSET(count),                                TConstant|TReference,
       +        DwarfAttrDataMemberLoc,        OFFSET(datamemberloc),                TBlock|TConstant|TReference,
       +        DwarfAttrDeclColumn,                OFFSET(declcolumn),                        TConstant,
       +        DwarfAttrDeclFile,                OFFSET(declfile),                        TConstant,
       +        DwarfAttrDeclLine,                OFFSET(declline),                        TConstant,
       +        DwarfAttrDeclaration,        OFFSET(isdeclaration),                TFlag,
       +        DwarfAttrDefaultValue,        OFFSET(defaultvalue),                TReference,
       +        DwarfAttrDiscr,                        OFFSET(discr),                                TReference,
       +        DwarfAttrDiscrList,                OFFSET(discrlist),                        TBlock,
       +        DwarfAttrDiscrValue,                OFFSET(discrvalue),                        TConstant,
       +        DwarfAttrEncoding,                OFFSET(encoding),                        TConstant,
       +        DwarfAttrExternal,                OFFSET(isexternal),                        TFlag,
       +        DwarfAttrFrameBase,                OFFSET(framebase),                        TBlock|TConstant,
       +        DwarfAttrFriend,                        OFFSET(friend),                                TReference,
       +        DwarfAttrHighpc,                        OFFSET(highpc),                                TAddress,
       +        DwarfAttrIdentifierCase,        OFFSET(identifiercase),                TConstant,
       +        DwarfAttrImport,                        OFFSET(import),                                TReference,
       +        DwarfAttrInline,                        OFFSET(inlined),                        TConstant,
       +        DwarfAttrIsOptional,                OFFSET(isoptional),                        TFlag,
       +        DwarfAttrLanguage,                OFFSET(language),                        TConstant,
       +        DwarfAttrLocation,                OFFSET(location),                        TBlock|TConstant,
       +        DwarfAttrLowerBound,                OFFSET(lowerbound),                        TConstant|TReference,
       +        DwarfAttrLowpc,                        OFFSET(lowpc),                                TAddress,
       +        DwarfAttrMacroInfo,                OFFSET(macroinfo),                        TConstant,
       +        DwarfAttrName,                        OFFSET(name),                                TString,
       +        DwarfAttrNamelistItem,        OFFSET(namelistitem),                TBlock,
       +        DwarfAttrOrdering,                 OFFSET(ordering),                        TConstant,
       +        DwarfAttrPriority,                OFFSET(priority),                        TReference,
       +        DwarfAttrProducer,                OFFSET(producer),                        TString,
       +        DwarfAttrPrototyped,                OFFSET(isprototyped),                TFlag,
       +        DwarfAttrRanges,                        OFFSET(ranges),                                TReference,
       +        DwarfAttrReturnAddr,                OFFSET(returnaddr),                        TBlock|TConstant,
       +        DwarfAttrSegment,                OFFSET(segment),                        TBlock|TConstant,
       +        DwarfAttrSibling,                OFFSET(sibling),                        TReference,
       +        DwarfAttrSpecification,        OFFSET(specification),                TReference,
       +        DwarfAttrStartScope,                OFFSET(startscope),                        TConstant,
       +        DwarfAttrStaticLink,                OFFSET(staticlink),                        TBlock|TConstant,
       +        DwarfAttrStmtList,                OFFSET(stmtlist),                        TConstant,
       +        DwarfAttrStrideSize,                OFFSET(stridesize),                        TConstant,
       +        DwarfAttrStringLength,        OFFSET(stringlength),                TBlock|TConstant,
       +        DwarfAttrType,                        OFFSET(type),                                TReference,
       +        DwarfAttrUpperBound,                OFFSET(upperbound),                        TConstant|TReference,
       +        DwarfAttrUseLocation,        OFFSET(uselocation),                TBlock|TConstant,
       +        DwarfAttrVarParam,                OFFSET(isvarparam),                        TFlag,
       +        DwarfAttrVirtuality,                OFFSET(virtuality),                        TConstant,
       +        DwarfAttrVisibility,                OFFSET(visibility),                        TConstant,
       +        DwarfAttrVtableElemLoc,        OFFSET(vtableelemloc),                TBlock|TReference,
       +};
       +
       +static Parse ptab[DwarfAttrMax];
       +
       +static int
       +parseattrs(DwarfBuf *b, ulong unit, DwarfAbbrev *a, DwarfAttrs *attrs)
       +{
       +        int i, f, n, got;
       +        static int nbad;
       +        void *v;
       +
       +        /* initialize ptab first time through for quick access */
       +        if(ptab[DwarfAttrName].name != DwarfAttrName)
       +                for(i=0; i<nelem(plist); i++)
       +                        ptab[plist[i].name] = plist[i];
       +
       +        memset(attrs, 0, sizeof *attrs);
       +        attrs->tag = a->tag;
       +        attrs->haskids = a->haskids;
       +
       +        for(i=0; i<a->nattr; i++){
       +                n = a->attr[i].name;
       +                f = a->attr[i].form;
       +                if(n < 0 || n >= nelem(ptab) || ptab[n].name==0){
       +                        if(++nbad == 1)
       +                                fprint(2, "dwarf parse attrs: unexpected attribute name 0x%ux\n", n);
       +                        return -1;
       +                }
       +                v = (char*)attrs + ptab[n].off;
       +                got = 0;
       +                if(f == FormIndirect)
       +                        f = dwarfget128(b);
       +                if((ptab[n].type&(TConstant|TReference|TAddress))
       +                && getulong(b, f, unit, v, &got) >= 0)
       +                        ;
       +                else if((ptab[n].type&TFlag) && getuchar(b, f, v) >= 0)
       +                        got = TFlag;
       +                else if((ptab[n].type&TString) && getstring(b, f, v) >= 0)
       +                        got = TString;
       +                else if((ptab[n].type&TBlock) && getblock(b, f, v) >= 0)
       +                        got = TBlock;
       +                else{
       +                        if(skipform(b, f) < 0){
       +                                if(++nbad == 1)
       +                                        fprint(2, "dwarf parse attrs: cannot skip form %d\n", f);
       +                                return -1;
       +                        }
       +                }
       +                if(got == TBlock && (ptab[n].type&TConstant))
       +                        got = constblock(b->d, v, v);
       +                *((uchar*)attrs+ptab[n].haveoff) = got;
       +        }
       +        return 0;
       +}
       +
       +static int
       +getulong(DwarfBuf *b, int form, ulong unit, ulong *u, int *type)
       +{
       +        static int nbad;
       +        uvlong uv;
       +
       +        switch(form){
       +        default:
       +                return -1;
       +
       +        /* addresses */
       +        case FormAddr:
       +                *type = TAddress;
       +                *u = dwarfgetaddr(b);
       +                return 0;
       +
       +        /* references */
       +        case FormRefAddr:
       +                /* absolute ref in .debug_info */
       +                *type = TReference;
       +                *u = dwarfgetaddr(b);
       +                return 0;
       +        case FormRef1:
       +                *u = dwarfget1(b);
       +                goto relativeref;
       +        case FormRef2:
       +                *u = dwarfget2(b);
       +                goto relativeref;
       +        case FormRef4:
       +                *u = dwarfget4(b);
       +                goto relativeref;
       +        case FormRef8:
       +                *u = dwarfget8(b);
       +                goto relativeref;
       +        case FormRefUdata:
       +                *u = dwarfget128(b);
       +        relativeref:
       +                *u += unit;
       +                *type = TReference;
       +                return 0;
       +
       +        /* constants */
       +        case FormData1:
       +                *u = dwarfget1(b);
       +                goto constant;
       +        case FormData2:
       +                *u = dwarfget2(b);
       +                goto constant;
       +        case FormData4:
       +                *u = dwarfget4(b);
       +                goto constant;
       +        case FormData8:
       +                uv = dwarfget8(b);
       +                *u = uv;
       +                if(uv != *u && ++nbad == 1)
       +                        fprint(2, "dwarf: truncating 64-bit attribute constants\n");
       +                goto constant;
       +        case FormSdata:
       +                *u = dwarfget128s(b);
       +                goto constant;
       +        case FormUdata:
       +                *u = dwarfget128(b);
       +        constant:
       +                *type = TConstant;
       +                return 0;
       +        }
       +}
       +
       +static int
       +getuchar(DwarfBuf *b, int form, uchar *u)
       +{
       +        switch(form){
       +        default:
       +                return -1;
       +
       +        case FormFlag:
       +                *u = dwarfget1(b);
       +                return 0;
       +        }
       +}
       +
       +static int
       +getstring(DwarfBuf *b, int form, char **s)
       +{
       +        static int nbad;
       +        ulong u;
       +
       +        switch(form){
       +        default:
       +                return -1;
       +
       +        case FormString:
       +                *s = dwarfgetstring(b);
       +                return 0;
       +
       +        case FormStrp:
       +                u = dwarfget4(b);
       +                if(u >= b->d->str.len){
       +                        if(++nbad == 1)
       +                                fprint(2, "dwarf: bad string pointer 0x%lux in attribute\n", u);
       +                        /* don't return error - maybe can proceed */
       +                        *s = nil;
       +                }else
       +                        *s = b->d->str.data + u;
       +                return 0;
       +
       +        }
       +}
       +
       +static int
       +getblock(DwarfBuf *b, int form, DwarfBlock *bl)
       +{
       +        ulong n;
       +
       +        switch(form){
       +        default:
       +                return -1;
       +        case FormDwarfBlock:
       +                n = dwarfget128(b);
       +                goto copyn;
       +        case FormDwarfBlock1:
       +                n = dwarfget1(b);
       +                goto copyn;
       +        case FormDwarfBlock2:
       +                n = dwarfget2(b);
       +                goto copyn;
       +        case FormDwarfBlock4:
       +                n = dwarfget4(b);
       +        copyn:
       +                bl->data = dwarfgetnref(b, n);
       +                bl->len = n;
       +                if(bl->data == nil)
       +                        return -1;
       +                return 0;
       +        }
       +}
       +
       +static int
       +constblock(Dwarf *d, DwarfBlock *bl, ulong *pval)
       +{
       +        DwarfBuf b;
       +
       +        memset(&b, 0, sizeof b);
       +        b.p = bl->data;
       +        b.ep = bl->data+bl->len;
       +        b.d = d;
       +
       +        switch(dwarfget1(&b)){
       +        case OpAddr:
       +                *pval = dwarfgetaddr(&b);
       +                return TConstant;
       +        case OpConst1u:
       +                *pval = dwarfget1(&b);
       +                return TConstant;
       +        case OpConst1s:
       +                *pval = (schar)dwarfget1(&b);
       +                return TConstant;
       +        case OpConst2u:
       +                *pval = dwarfget2(&b);
       +                return TConstant;
       +        case OpConst2s:
       +                *pval = (s16int)dwarfget2(&b);
       +                return TConstant;
       +        case OpConst4u:
       +                *pval = dwarfget4(&b);
       +                return TConstant;
       +        case OpConst4s:
       +                *pval = (s32int)dwarfget4(&b);
       +                return TConstant;
       +        case OpConst8u:
       +                *pval = (u64int)dwarfget8(&b);
       +                return TConstant;
       +        case OpConst8s:
       +                *pval = (s64int)dwarfget8(&b);
       +                return TConstant;
       +        case OpConstu:
       +                *pval = dwarfget128(&b);
       +                return TConstant;
       +        case OpConsts:
       +                *pval = dwarfget128s(&b);
       +                return TConstant;
       +        case OpPlusUconst:
       +                *pval = dwarfget128(&b);
       +                return TConstant;
       +        default:
       +                return TBlock;
       +        }
       +}
       +
       +/* last resort */
       +static int
       +skipform(DwarfBuf *b, int form)
       +{
       +        int type;
       +        DwarfVal val;
       +
       +        if(getulong(b, form, 0, &val.c, &type) < 0
       +        && getuchar(b, form, (uchar*)&val) < 0
       +        && getstring(b, form, &val.s) < 0
       +        && getblock(b, form, &val.b) < 0)
       +                return -1;
       +        return 0;
       +}
   DIR diff --git a/src/libmach/dwarfopen.c b/src/libmach/dwarfopen.c
       t@@ -0,0 +1,107 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include "elf.h"
       +#include "dwarf.h"
       +
       +static int
       +readblock(int fd, DwarfBlock *b, ulong off, ulong len)
       +{
       +        b->data = malloc(len);
       +        if(b->data == nil)
       +                return -1;
       +        if(seek(fd, off, 0) < 0 || readn(fd, b->data, len) != len){
       +                free(b->data);
       +                b->data = nil;
       +                return -1;
       +        }
       +        b->len = len;
       +        return 0;
       +}
       +
       +static int
       +findsection(Elf *elf, char *name, ulong *off, ulong *len)
       +{
       +        ElfSect *s;
       +
       +        if((s = elfsection(elf, name)) == nil)
       +                return -1;
       +        *off = s->offset;
       +        *len = s->size;
       +        return s - elf->sect;
       +}
       +        
       +static int
       +loadsection(Elf *elf, char *name, DwarfBlock *b)
       +{
       +        ulong off, len;
       +
       +        if(findsection(elf, name, &off, &len) < 0)
       +                return -1;
       +        return readblock(elf->fd, b, off, len);
       +}
       +
       +Dwarf*
       +dwarfopen(Elf *elf)
       +{
       +        Dwarf *d;
       +
       +        if(elf == nil){
       +                werrstr("nil elf passed to dwarfopen");
       +                return nil;
       +        }
       +
       +        d = mallocz(sizeof(Dwarf), 1);
       +        if(d == nil)
       +                return nil;
       +
       +        d->elf = elf;
       +        if(loadsection(elf, ".debug_abbrev", &d->abbrev) < 0
       +        || loadsection(elf, ".debug_aranges", &d->aranges) < 0
       +        || loadsection(elf, ".debug_frame", &d->frame) < 0
       +        || loadsection(elf, ".debug_line", &d->line) < 0
       +        || loadsection(elf, ".debug_pubnames", &d->pubnames) < 0
       +        || loadsection(elf, ".debug_ranges", &d->ranges) < 0
       +        || loadsection(elf, ".debug_str", &d->str) < 0
       +        || loadsection(elf, ".debug_info", &d->info) < 0)
       +                goto err;
       +
       +        /* make this a table once there are more */
       +        switch(d->elf->hdr.machine){
       +        case ElfMach386:
       +                d->reg = dwarf386regs;
       +                d->nreg = dwarf386nregs;
       +                break;
       +        default:
       +                werrstr("unsupported machine");
       +                goto err;
       +        }
       +
       +        return d;
       +
       +err:
       +        free(d->abbrev.data);
       +        free(d->aranges.data);
       +        free(d->frame.data);
       +        free(d->line.data);
       +        free(d->pubnames.data);
       +        free(d->ranges.data);
       +        free(d->str.data);
       +        free(d->info.data);
       +        free(d);
       +        return nil;
       +}
       +
       +void
       +dwarfclose(Dwarf *d)
       +{
       +        free(d->abbrev.data);
       +        free(d->aranges.data);
       +        free(d->frame.data);
       +        free(d->line.data);
       +        free(d->pubnames.data);
       +        free(d->ranges.data);
       +        free(d->str.data);
       +        free(d->info.data);
       +        free(d);
       +}
   DIR diff --git a/src/libmach/dwarfpc.c b/src/libmach/dwarfpc.c
       t@@ -0,0 +1,338 @@
       +/*
       + * Dwarf pc to source line conversion.
       + * 
       + * Maybe should do the reverse here, but what should the interface look like?
       + * One possibility is to use the Plan 9 line2addr interface:
       + *
       + *        long line2addr(ulong line, ulong basepc)
       + *
       + * which returns the smallest pc > basepc with line number line (ignoring file name).
       + *
       + * The encoding may be small, but it sure isn't simple!
       + */
       +
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include "elf.h"
       +#include "dwarf.h"
       +
       +#define trace 0
       +
       +enum
       +{
       +        Isstmt = 1<<0,
       +        BasicDwarfBlock = 1<<1,
       +        EndSequence = 1<<2,
       +        PrologueEnd = 1<<3,
       +        EpilogueBegin = 1<<4,
       +};
       +
       +typedef struct State State;
       +struct State
       +{
       +        ulong addr;
       +        ulong file;
       +        ulong line;
       +        ulong column;
       +        ulong flags;
       +        ulong isa;
       +};
       +
       +int
       +dwarfpctoline(Dwarf *d, ulong pc, char **cdir, char **dir, char **file, ulong *line, ulong *mtime, ulong *length)
       +{
       +        uchar *prog, *opcount, *end;
       +        ulong off, unit, len, vers, x, start;
       +        int i, first, op, a, l, quantum, isstmt, linebase, linerange, opcodebase, nf;
       +        char *files, *dirs, *s;
       +        DwarfBuf b;
       +        DwarfSym sym;
       +        State emit, cur, reset;
       +        uchar **f, **newf;
       +
       +        f = nil;
       +
       +        if(dwarfaddrtounit(d, pc, &unit) < 0
       +        || dwarflookuptag(d, unit, TagCompileUnit, &sym) < 0)
       +                return -1;
       +
       +        if(!sym.attrs.have.stmtlist){
       +                werrstr("no line mapping information for 0x%lux", pc);
       +                return -1;
       +        }
       +        off = sym.attrs.stmtlist;
       +        if(off >= d->line.len){
       +                fprint(2, "bad stmtlist\n");
       +                goto bad;
       +        }
       +
       +        if(trace) fprint(2, "unit 0x%lux stmtlist 0x%lux\n", unit, sym.attrs.stmtlist);
       +
       +        memset(&b, 0, sizeof b);
       +        b.d = d;
       +        b.p = d->line.data + off;
       +        b.ep = b.p + d->line.len;
       +        b.addrsize = sym.b.addrsize;        /* should i get this from somewhere else? */
       +
       +        len = dwarfget4(&b);
       +        if(b.p==nil || b.p+len > b.ep || b.p+len < b.p){
       +                fprint(2, "bad len\n");
       +                goto bad;
       +        }
       +
       +        b.ep = b.p+len;
       +        vers = dwarfget2(&b);
       +        if(vers != 2){
       +                werrstr("bad dwarf version 0x%lux", vers);
       +                return -1;
       +        }
       +
       +        len = dwarfget4(&b);
       +        if(b.p==nil || b.p+len > b.ep || b.p+len < b.p){
       +                fprint(2, "another bad len\n");
       +                goto bad;
       +        }
       +        prog = b.p+len;
       +
       +        quantum = dwarfget1(&b);
       +        isstmt = dwarfget1(&b);
       +        linebase = (schar)dwarfget1(&b);
       +        linerange = (schar)dwarfget1(&b);
       +        opcodebase = dwarfget1(&b);
       +
       +        opcount = b.p-1;
       +        dwarfgetnref(&b, opcodebase-1);
       +        if(b.p == nil){
       +                fprint(2, "bad opcode chart\n");
       +                goto bad;
       +        }
       +
       +        /* just skip the files and dirs for now; we'll come back */
       +        dirs = b.p;
       +        while(b.p!=nil && *b.p!=0)
       +                dwarfgetstring(&b);
       +        dwarfget1(&b);
       +
       +        files = b.p;
       +        while(b.p!=nil && *b.p!=0){
       +                dwarfgetstring(&b);
       +                dwarfget128(&b);
       +                dwarfget128(&b);
       +                dwarfget128(&b);
       +        }
       +        dwarfget1(&b);
       +
       +        /* move on to the program */
       +        if(b.p == nil || b.p > prog){
       +                fprint(2, "bad header\n");
       +                goto bad;
       +        }
       +        b.p = prog;
       +
       +        reset.addr = 0;
       +        reset.file = 1;
       +        reset.line = 1;
       +        reset.column = 0;
       +        reset.flags = isstmt ? Isstmt : 0;
       +        reset.isa = 0;
       +
       +        cur = reset;
       +        emit = reset;
       +        nf = 0;
       +        start = 0;
       +        if(trace) fprint(2, "program @ %lud ... %.*H opbase = %d\n", b.p - d->line.data, b.ep-b.p, b.p, opcodebase);
       +        first = 1;
       +        while(b.p != nil){
       +                op = dwarfget1(&b);
       +                if(trace) fprint(2, "\tline %lud, addr 0x%lux, op %d %.10H", cur.line, cur.addr, op, b.p);
       +                if(op >= opcodebase){
       +                        a = (op - opcodebase) / linerange;
       +                        l = (op - opcodebase) % linerange + linebase;
       +                        cur.line += l;
       +                        cur.addr += a * quantum;
       +                        if(trace) fprint(2, " +%d,%d\n", a, l);
       +                emit:
       +                        if(first){
       +                                if(cur.addr > pc){
       +                                        werrstr("found wrong line mapping 0x%lux for pc 0x%lux", cur.addr, pc);
       +                                        goto out;
       +                                }
       +                                first = 0;
       +                                start = cur.addr;
       +                        }
       +                        if(cur.addr > pc)
       +                                break;
       +                        if(b.p == nil){
       +                                werrstr("buffer underflow in line mapping");
       +                                goto out;
       +                        }
       +                        emit = cur;
       +                        if(emit.flags & EndSequence){
       +                                werrstr("found wrong line mapping 0x%lux-0x%lux for pc 0x%lux", start, cur.addr, pc);
       +                                goto out;
       +                        }
       +                        cur.flags &= ~(BasicDwarfBlock|PrologueEnd|EpilogueBegin);
       +                }else{
       +                        switch(op){
       +                        case 0:        /* extended op code */
       +                                if(trace) fprint(2, " ext");
       +                                len = dwarfget128(&b);
       +                                end = b.p+len;
       +                                if(b.p == nil || end > b.ep || end < b.p || len < 1)
       +                                        goto bad;
       +                                switch(dwarfget1(&b)){
       +                                case 1:        /* end sequence */
       +                                        if(trace) fprint(2, " end\n");
       +                                        cur.flags |= EndSequence;
       +                                        goto emit;
       +                                case 2:        /* set address */
       +                                        cur.addr = dwarfgetaddr(&b);
       +                                        if(trace) fprint(2, " set pc 0x%lux\n", cur.addr);
       +                                        break;
       +                                case 3:        /* define file */
       +                                        newf = realloc(f, (nf+1)*sizeof(f[0]));
       +                                        if(newf == nil)
       +                                                goto out;
       +                                        f[nf++] = b.p;
       +                                        s = dwarfgetstring(&b);
       +                                        dwarfget128(&b);
       +                                        dwarfget128(&b);
       +                                        dwarfget128(&b);
       +                                        if(trace) fprint(2, " def file %s\n", s);
       +                                        break;
       +                                }
       +                                if(b.p == nil || b.p > end)
       +                                        goto bad;
       +                                b.p = end;
       +                                break;
       +                        case 1:        /* emit */
       +                                if(trace) fprint(2, " emit\n");
       +                                goto emit;
       +                        case 2:        /* advance pc */
       +                                a = dwarfget128(&b);
       +                                if(trace) fprint(2, " advance pc + %lud\n", a*quantum);
       +                                cur.addr += a * quantum;
       +                                break;
       +                        case 3:        /* advance line */
       +                                l = dwarfget128s(&b);
       +                                if(trace) fprint(2, " advance line + %ld\n", l);
       +                                cur.line += l;
       +                                break;
       +                        case 4:        /* set file */
       +                                if(trace) fprint(2, " set file\n");
       +                                cur.file = dwarfget128s(&b);
       +                                break;
       +                        case 5:        /* set column */
       +                                if(trace) fprint(2, " set column\n");
       +                                cur.column = dwarfget128(&b);
       +                                break;
       +                        case 6:        /* negate stmt */
       +                                if(trace) fprint(2, " negate stmt\n");
       +                                cur.flags ^= Isstmt;
       +                                break;
       +                        case 7:        /* set basic block */
       +                                if(trace) fprint(2, " set basic block\n");
       +                                cur.flags |= BasicDwarfBlock;
       +                                break;
       +                        case 8:        /* const add pc */
       +                                a = (255 - opcodebase) / linerange * quantum;
       +                                if(trace) fprint(2, " const add pc + %d\n", a);
       +                                cur.addr += a;
       +                                break;
       +                        case 9:        /* fixed advance pc */
       +                                a = dwarfget2(&b);
       +                                if(trace) fprint(2, " fixed advance pc + %d\n", a);
       +                                cur.addr += a;
       +                                break;
       +                        case 10:        /* set prologue end */
       +                                if(trace) fprint(2, " set prologue end\n");
       +                                cur.flags |= PrologueEnd;
       +                                break;
       +                        case 11:        /* set epilogue begin */
       +                                if(trace) fprint(2, " set epilogue begin\n");
       +                                cur.flags |= EpilogueBegin;
       +                                break;
       +                        case 12:        /* set isa */
       +                                if(trace) fprint(2, " set isa\n");
       +                                cur.isa = dwarfget128(&b);
       +                                break;
       +                        default:        /* something new - skip it */
       +                                if(trace) fprint(2, " unknown %d\n", opcount[op]);
       +                                for(i=0; i<opcount[op]; i++)
       +                                        dwarfget128(&b);
       +                                break;
       +                        }
       +                }
       +        }
       +        if(b.p == nil)
       +                goto bad;
       +
       +        /* finally!  the data we seek is in "emit" */
       +
       +        if(emit.file == 0){
       +                werrstr("invalid file index in mapping data");
       +                goto out;
       +        }
       +        if(line)
       +                *line = emit.line;
       +
       +        /* skip over first emit.file-2 guys */
       +        b.p = files;
       +        for(i=emit.file-1; i > 0 && b.p!=nil && *b.p!=0; i--){
       +                dwarfgetstring(&b);
       +                dwarfget128(&b);
       +                dwarfget128(&b);
       +                dwarfget128(&b);
       +        }
       +        if(b.p == nil){
       +                werrstr("problem parsing file data second time (cannot happen)");
       +                goto bad;
       +        }
       +        if(*b.p == 0){
       +                if(i >= nf){
       +                        werrstr("bad file index in mapping data");
       +                        goto bad;
       +                }
       +                b.p = f[i];
       +        }
       +        s = dwarfgetstring(&b);
       +        if(file)
       +                *file = s;
       +        i = dwarfget128(&b);                /* directory */
       +        x = dwarfget128(&b);
       +        if(mtime)
       +                *mtime = x;
       +        x = dwarfget128(&b);
       +        if(length)
       +                *length = x;
       +
       +        /* fetch dir name */
       +        if(cdir)
       +                *cdir = sym.attrs.compdir;
       +
       +        if(dir){
       +                if(i == 0)
       +                        *dir = nil;
       +                else{
       +                        b.p = dirs;
       +                        for(i--; i>0 && b.p!=nil && *b.p!=0; i--)
       +                                dwarfgetstring(&b);
       +                        if(b.p==nil || *b.p==0){
       +                                werrstr("bad directory reference in line mapping");
       +                                goto out;                /* can only happen with bad dir index */
       +                        }
       +                        *dir = dwarfgetstring(&b);
       +                }
       +        }
       +
       +        /* free at last, free at last */
       +        free(f);
       +        return 0;
       +
       +bad:
       +        werrstr("corrupted line mapping for 0x%lux", pc);
       +out:
       +        free(f);
       +        return -1;
       +}
   DIR diff --git a/src/libmach/dwarfpubnames.c b/src/libmach/dwarfpubnames.c
       t@@ -0,0 +1,76 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include "elf.h"
       +#include "dwarf.h"
       +
       +static int
       +_dwarfnametounit(Dwarf *d, char *name, DwarfBlock *bl, DwarfSym *s)
       +{
       +        int vers;
       +        ulong len, unit, off;
       +        uchar *next;
       +        char *str;
       +        DwarfBuf b;
       +
       +        b.d = d;
       +        b.p = bl->data;
       +        b.ep = b.p + bl->len;
       +
       +        while(b.p < b.ep){
       +                len = dwarfget4(&b);
       +                if(len > b.ep-b.p){
       +                        werrstr("bad length in dwarf name header");
       +                        return -1;
       +                }
       +                next = b.p + len;
       +                vers = dwarfget2(&b);
       +                if(vers != 1 && vers != 2){
       +                        werrstr("bad version %d in dwarf name header", vers);
       +                        return -1;
       +                }
       +                unit = dwarfget4(&b);
       +                dwarfget4(&b);        /* unit length */
       +                while(b.p < next){
       +                        off = dwarfget4(&b);
       +                        if(off == 0)
       +                                break;
       +                        str = dwarfgetstring(&b);
       +                        if(strcmp(str, name) == 0){
       +                                if(dwarfenumunit(d, unit, s) < 0)
       +                                        return -1;
       +                                if(unit + off >= s->b.ep - d->info.data){
       +                                        werrstr("bad offset in name entry");
       +                                        return -1;
       +                                }
       +                                s->b.p = d->info.data + unit + off;
       +                                if(dwarfnextsym(d, s, 1) < 0)
       +                                        return -1;
       +                                if(s->attrs.name==nil || strcmp(s->attrs.name, name)!=0){
       +                                        werrstr("unexpected name %#q in lookup for %#q", s->attrs.name, name);
       +                                        return -1;
       +                                }
       +                                return 0;
       +                        }
       +                }
       +                b.p = next;
       +        }
       +        werrstr("unknown name '%s'", name);
       +        return -1;
       +}
       +
       +int
       +dwarflookupname(Dwarf *d, char *name, DwarfSym *sym)
       +{
       +        return _dwarfnametounit(d, name, &d->pubnames, sym);
       +}
       +
       +/*
       +
       +int
       +dwarflookuptype(Dwarf *d, char *name, DwarfSym *sym)
       +{
       +        return _dwarfnametounit(d, name, &d->pubtypes, sym);
       +}
       +
       + */
   DIR diff --git a/src/libmach/elf.c b/src/libmach/elf.c
       t@@ -0,0 +1,405 @@
       +/*
       + * Parse 32-bit ELF files.
       + * Copyright (c) 2004 Russ Cox.  See LICENSE.
       + */
       +
       +#include <u.h>
       +#include <libc.h>
       +#include <mach.h>
       +#include "elf.h"
       +
       +typedef struct ElfHdrBytes ElfHdrBytes;
       +typedef struct ElfSectBytes ElfSectBytes;
       +typedef struct ElfProgBytes ElfProgBytes;
       +typedef struct ElfSymBytes ElfSymBytes;
       +
       +struct ElfHdrBytes
       +{
       +        uchar        ident[16];
       +        uchar        type[2];
       +        uchar        machine[2];
       +        uchar        version[4];
       +        uchar        entry[4];
       +        uchar        phoff[4];
       +        uchar        shoff[4];
       +        uchar        flags[4];
       +        uchar        ehsize[2];
       +        uchar        phentsize[2];
       +        uchar        phnum[2];
       +        uchar        shentsize[2];
       +        uchar        shnum[2];
       +        uchar        shstrndx[2];
       +};
       +
       +struct ElfSectBytes
       +{
       +        uchar        name[4];
       +        uchar        type[4];
       +        uchar        flags[4];
       +        uchar        addr[4];
       +        uchar        offset[4];
       +        uchar        size[4];
       +        uchar        link[4];
       +        uchar        info[4];
       +        uchar        align[4];
       +        uchar        entsize[4];
       +};
       +
       +struct ElfSymBytes
       +{
       +        uchar        name[4];
       +        uchar        value[4];
       +        uchar        size[4];
       +        uchar        info;        /* top4: bind, bottom4: type */
       +        uchar        other;
       +        uchar        shndx[2];
       +};
       +
       +struct ElfProgBytes
       +{
       +        uchar        type[4];
       +        uchar        offset[4];
       +        uchar        vaddr[4];
       +        uchar        paddr[4];
       +        uchar        filesz[4];
       +        uchar        memsz[4];
       +        uchar        flags[4];
       +        uchar        align[4];
       +};
       +
       +uchar ElfMagic[4] = { 0x7F, 'E', 'L', 'F' };
       +
       +static void        unpackhdr(ElfHdr*, ElfHdrBytes*);
       +static void        unpackprog(ElfHdr*, ElfProg*, ElfProgBytes*);
       +static void        unpacksect(ElfHdr*, ElfSect*, ElfSectBytes*);
       +
       +static char *elftypes[] = {
       +        "none",
       +        "relocatable",
       +        "executable",
       +        "shared object",
       +        "core",
       +};
       +
       +char*
       +elftype(int t)
       +{
       +        if(t < 0 || t >= nelem(elftypes))
       +                return "unknown";
       +        return elftypes[t];
       +}
       +
       +static char *elfmachs[] = {
       +        "none",
       +        "32100",
       +        "sparc",
       +        "386",
       +        "68000",
       +        "88000",
       +        "486",
       +        "860",
       +        "MIPS",
       +};
       +
       +char*
       +elfmachine(int t)
       +{
       +        if(t < 0 || t >= nelem(elfmachs))
       +                return "unknown";
       +        return elfmachs[t];
       +}
       +
       +Elf*
       +elfopen(char *name)
       +{
       +        int fd;
       +        Elf *e;
       +
       +        if((fd = open(name, OREAD)) < 0)
       +                return nil;
       +        if((e = elfinit(fd)) == nil)
       +                close(fd);
       +        return e;
       +}
       +
       +Elf*
       +elfinit(int fd)
       +{
       +        int i;
       +        Elf *e;
       +        ElfHdr *h;
       +        ElfHdrBytes hdrb;
       +        ElfProgBytes progb;
       +        ElfSectBytes sectb;
       +        ElfSect *s;
       +
       +        e = mallocz(sizeof(Elf), 1);
       +        if(e == nil)
       +                return nil;
       +        e->fd = fd;
       +
       +        /*
       +         * parse header
       +         */
       +        seek(fd, 0, 0);
       +        if(readn(fd, &hdrb, sizeof hdrb) != sizeof hdrb)
       +                goto err;
       +        h = &e->hdr;
       +        unpackhdr(h, &hdrb);
       +        if(h->class != ElfClass32){
       +                werrstr("bad ELF class - not 32-bit");
       +                goto err;
       +        }
       +        if(h->encoding != ElfDataLsb && h->encoding != ElfDataMsb){
       +                werrstr("bad ELF encoding - not LSB, MSB");
       +                goto err;
       +        }
       +        if(hdrb.ident[6] != h->version){
       +                werrstr("bad ELF encoding - version mismatch %02ux and %08ux",
       +                        (uint)hdrb.ident[6], (uint)h->version);
       +                goto err;
       +        }
       +
       +        /*
       +         * the prog+section info is almost always small - just load it into memory.
       +         */
       +        e->nprog = h->phnum;
       +        e->prog = mallocz(sizeof(ElfProg)*e->nprog, 1);
       +        for(i=0; i<e->nprog; i++){
       +                if(seek(fd, h->phoff+i*h->phentsize, 0) < 0
       +                || readn(fd, &progb, sizeof progb) != sizeof progb)
       +                        goto err;
       +                unpackprog(h, &e->prog[i], &progb);
       +        }
       +
       +        e->nsect = h->shnum;
       +        if(e->nsect == 0)
       +                goto nosects;
       +        e->sect = mallocz(sizeof(ElfSect)*e->nsect, 1);
       +        for(i=0; i<e->nsect; i++){
       +                if(seek(fd, h->shoff+i*h->shentsize, 0) < 0
       +                || readn(fd, &sectb, sizeof sectb) != sizeof sectb)
       +                        goto err;
       +                unpacksect(h, &e->sect[i], &sectb);
       +        }
       +
       +        if(h->shstrndx >= e->nsect){
       +                fprint(2, "warning: bad string section index %d >= %d", h->shstrndx, e->nsect);
       +                h->shnum = 0;
       +                e->nsect = 0;
       +                goto nosects;
       +        }
       +        s = &e->sect[h->shstrndx];
       +        if(elfmap(e, s) < 0)
       +                goto err;
       +
       +        for(i=0; i<e->nsect; i++)
       +                if(e->sect[i].name)
       +                        e->sect[i].name = s->base + (ulong)e->sect[i].name;
       +
       +        e->symtab = elfsection(e, ".symtab");
       +        if(e->symtab){
       +                if(e->symtab->link >= e->nsect)
       +                        e->symtab = nil;
       +                else{
       +                        e->symstr = &e->sect[e->symtab->link];
       +                        e->nsymtab = e->symtab->size / sizeof(ElfSymBytes);
       +                }
       +        }
       +        e->dynsym = elfsection(e, ".dynsym");
       +        if(e->dynsym){
       +                if(e->dynsym->link >= e->nsect)
       +                        e->dynsym = nil;
       +                else{
       +                        e->dynstr = &e->sect[e->dynsym->link];
       +                        e->ndynsym = e->dynsym->size / sizeof(ElfSymBytes);
       +                }
       +        }
       +
       +        e->bss = elfsection(e, ".bss");
       +
       +nosects:
       +        return e;
       +
       +err:
       +        free(e->sect);
       +        free(e->prog);
       +        free(e->shstrtab);
       +        free(e);
       +        return nil;
       +}
       +
       +void
       +elfclose(Elf *elf)
       +{
       +        int i;
       +
       +        for(i=0; i<elf->nsect; i++)
       +                free(elf->sect[i].base);
       +        free(elf->sect);
       +        free(elf->prog);
       +        free(elf->shstrtab);
       +        free(elf);
       +}
       +
       +static void
       +unpackhdr(ElfHdr *h, ElfHdrBytes *b)
       +{
       +        u16int (*e2)(uchar*);
       +        u32int (*e4)(uchar*);
       +        u64int (*e8)(uchar*);
       +
       +        memmove(h->magic, b->ident, 4);
       +        h->class = b->ident[4];
       +        h->encoding = b->ident[5];
       +        switch(h->encoding){
       +        case ElfDataLsb:
       +                e2 = leload2;
       +                e4 = leload4;
       +                e8 = leload8;
       +                break;
       +        case ElfDataMsb:
       +                e2 = beload2;
       +                e4 = beload4;
       +                e8 = beload8;
       +                break;
       +        default:
       +                return;
       +        }
       +        h->abi = b->ident[7];
       +        h->abiversion = b->ident[8];
       +
       +        h->e2 = e2;
       +        h->e4 = e4;
       +        h->e8 = e8;
       +        
       +        h->type = e2(b->type);
       +        h->machine = e2(b->machine);
       +        h->version = e4(b->version);
       +        h->entry = e4(b->entry);
       +        h->phoff = e4(b->phoff);
       +        h->shoff = e4(b->shoff);
       +        h->flags = e4(b->flags);
       +        h->ehsize = e2(b->ehsize);
       +        h->phentsize = e2(b->phentsize);
       +        h->phnum = e2(b->phnum);
       +        h->shentsize = e2(b->shentsize);
       +        h->shnum = e2(b->shnum);
       +        h->shstrndx = e2(b->shstrndx);
       +}
       +
       +static void
       +unpackprog(ElfHdr *h, ElfProg *p, ElfProgBytes *b)
       +{
       +        u32int (*e4)(uchar*);
       +
       +        e4 = h->e4;
       +        p->type = e4(b->type);
       +        p->offset = e4(b->offset);
       +        p->vaddr = e4(b->vaddr);
       +        p->paddr = e4(b->paddr);
       +        p->filesz = e4(b->filesz);
       +        p->memsz = e4(b->memsz);
       +        p->flags = e4(b->flags);
       +        p->align = e4(b->align);
       +}
       +
       +static void
       +unpacksect(ElfHdr *h, ElfSect *s, ElfSectBytes *b)
       +{
       +        u32int (*e4)(uchar*);
       +
       +        e4 = h->e4;
       +        s->name = (char*)e4(b->name);
       +        s->type = e4(b->type);
       +        s->flags = e4(b->flags);
       +        s->addr = e4(b->addr);
       +        s->offset = e4(b->offset);
       +        s->size = e4(b->size);
       +        s->link = e4(b->link);
       +        s->info = e4(b->info);
       +        s->align = e4(b->align);
       +        s->entsize = e4(b->entsize);
       +}
       +
       +ElfSect*
       +elfsection(Elf *elf, char *name)
       +{
       +        int i;
       +
       +        for(i=0; i<elf->nsect; i++){
       +                if(elf->sect[i].name == name)
       +                        return &elf->sect[i];
       +                if(elf->sect[i].name && name
       +                && strcmp(elf->sect[i].name, name) == 0)
       +                        return &elf->sect[i];
       +        }
       +        werrstr("elf section '%s' not found", name);
       +        return nil;
       +}
       +
       +int
       +elfmap(Elf *elf, ElfSect *sect)
       +{
       +        if(sect->base)
       +                return 0;
       +        if((sect->base = malloc(sect->size)) == nil)
       +                return -1;
       +        werrstr("short read");
       +        if(seek(elf->fd, sect->offset, 0) < 0
       +        || readn(elf->fd, sect->base, sect->size) != sect->size){
       +                free(sect->base);
       +                sect->base = nil;
       +                return -1;
       +        }
       +        return 0;
       +}
       +
       +int
       +elfsym(Elf *elf, int i, ElfSym *sym)
       +{
       +        ElfSect *symtab, *strtab;
       +        uchar *p;
       +        char *s;
       +        ulong x;
       +
       +        if(i < 0){
       +                werrstr("bad index %d in elfsym", i);
       +                return -1;
       +        }
       +
       +        if(i < elf->nsymtab){
       +                symtab = elf->symtab;
       +                strtab = elf->symstr;
       +        extract:
       +                if(elfmap(elf, symtab) < 0 || elfmap(elf, strtab) < 0)
       +                        return -1;
       +                p = symtab->base + i * sizeof(ElfSymBytes);
       +                s = strtab->base;
       +                x = elf->hdr.e4(p);
       +                if(x >= strtab->size){
       +                        werrstr("bad symbol name offset 0x%lux", x);
       +                        return -1;
       +                }
       +                sym->name = s + x;
       +                sym->value = elf->hdr.e4(p+4);
       +                sym->size = elf->hdr.e4(p+8);
       +                x = p[12];
       +                sym->bind = x>>4;
       +                sym->type = x & 0xF;
       +                sym->other = p[13];
       +                sym->shndx = elf->hdr.e2(p+14);
       +                return 0;
       +        }
       +        i -= elf->nsymtab;
       +        if(i < elf->ndynsym){
       +                symtab = elf->dynsym;
       +                strtab = elf->dynstr;
       +                goto extract;
       +        }
       +        /* i -= elf->ndynsym */
       +
       +        werrstr("symbol index out of range");
       +        return -1;
       +}
       +
   DIR diff --git a/src/libmach/elf.h b/src/libmach/elf.h
       t@@ -0,0 +1,233 @@
       +/*
       + * Copyright (c) 2004 Russ Cox.  See LICENSE.
       + */
       +
       +/* /home/rsc/papers/elfXXelf.pdf */
       +
       +typedef struct Elf Elf;
       +typedef struct ElfHdr ElfHdr;
       +typedef struct ElfSect ElfSect;
       +typedef struct ElfProg ElfProg;
       +typedef struct ElfNote ElfNote;
       +typedef struct ElfSym ElfSym;
       +
       +enum
       +{
       +        ElfClassNone = 0,
       +        ElfClass32,
       +        ElfClass64,
       +
       +        ElfDataNone = 0,
       +        ElfDataLsb,
       +        ElfDataMsb,
       +
       +        ElfTypeNone = 0,
       +        ElfTypeRelocatable,
       +        ElfTypeExecutable,
       +        ElfTypeSharedObject,
       +        ElfTypeCore,
       +        /* 0xFF00 - 0xFFFF reserved for processor-specific types */
       +
       +        ElfMachNone = 0,
       +        ElfMach32100,                /* AT&T WE 32100 */
       +        ElfMachSparc,                /* SPARC */
       +        ElfMach386,                /* Intel 80386 */
       +        ElfMach68000,                /* Motorola 68000 */
       +        ElfMach88000,                /* Motorola 88000 */
       +        ElfMach486,                /* Intel 80486, no longer used */
       +        ElfMach860,                /* Intel 80860 */
       +        ElfMachMips,                /* MIPS RS3000 */
       +        ElfMachS370,                /* IBM System/370 */
       +        ElfMachMipsLe,        /* MIPS RS3000 LE */
       +        ElfMachParisc = 15,                /* HP PA RISC */
       +        ElfMachVpp500 = 17,        /* Fujitsu VPP500 */
       +        ElfMachSparc32Plus,        /* SPARC V8+ */
       +        ElfMach960,                /* Intel 80960 */
       +        ElfMachPower,                /* PowerPC */
       +        ElfMachPower64,        /* PowerPC 64 */
       +        ElfMachS390,                /* IBM System/390 */
       +        ElfMachV800 = 36,        /* NEC V800 */
       +        ElfMachFr20,                /* Fujitsu FR20 */
       +        ElfMachRh32,                /* TRW RH-32 */
       +        ElfMachRce,                /* Motorola RCE */
       +        ElfMachArm,                /* ARM */
       +        ElfMachAlpha,                /* Digital Alpha */
       +        ElfMachSH,                /* Hitachi SH */
       +        ElfMachSparc9,                /* SPARC V9 */
       +        /* and the list goes on... */
       +
       +        ElfAbiNone = 0,
       +        ElfAbiSystemV = 0,        /* [sic] */
       +        ElfAbiHPUX,
       +        ElfAbiNetBSD,
       +        ElfAbiLinux,
       +        ElfAbiSolaris = 6,
       +        ElfAbiAix,
       +        ElfAbiIrix,
       +        ElfAbiFreeBSD,
       +        ElfAbiTru64,
       +        ElfAbiModesto,
       +        ElfAbiOpenBSD,
       +        ElfAbiARM = 97,
       +        ElfAbiEmbedded = 255,
       +
       +        /* some of sections 0xFF00 - 0xFFFF reserved for various things */
       +        ElfSectNone = 0,
       +        ElfSectProgbits,
       +        ElfSectSymtab,
       +        ElfSectStrtab,
       +        ElfSectRela,
       +        ElfSectHash,
       +        ElfSectDynamic,
       +        ElfSectNote,
       +        ElfSectNobits,
       +        ElfSectRel,
       +        ElfSectShlib,
       +        ElfSectDynsym,
       +
       +        ElfSectFlagWrite = 0x1,
       +        ElfSectFlagAlloc = 0x2,
       +        ElfSectFlagExec = 0x4,
       +        /* 0xF0000000 are reserved for processor specific */
       +
       +        ElfSymBindLocal = 0,
       +        ElfSymBindGlobal,
       +        ElfSymBindWeak,
       +        /* 13-15 reserved */
       +
       +        ElfSymTypeNone = 0,
       +        ElfSymTypeObject,
       +        ElfSymTypeFunc,
       +        ElfSymTypeSection,
       +        ElfSymTypeFile,
       +        /* 13-15 reserved */
       +
       +        ElfSymShnNone = 0,
       +        ElfSymShnAbs = 0xFFF1,
       +        ElfSymShnCommon = 0xFFF2,
       +        /* 0xFF00-0xFF1F reserved for processors */
       +        /* 0xFF20-0xFF3F reserved for operating systems */
       +
       +        ElfProgNone = 0,
       +        ElfProgLoad,
       +        ElfProgDynamic,
       +        ElfProgInterp,
       +        ElfProgNote,
       +        ElfProgShlib,
       +        ElfProgPhdr,
       +
       +        ElfProgFlagExec = 0x1,
       +        ElfProgFlagWrite = 0x2,
       +        ElfProgFlagRead = 0x4,
       +
       +        ElfNotePrStatus = 1,
       +        ElfNotePrFpreg = 2,
       +        ElfNotePrPsinfo = 3,
       +        ElfNotePrTaskstruct = 4,
       +        ElfNotePrAuxv = 6,
       +        ElfNotePrXfpreg = 0x46e62b7f,        /* for gdb/386 */
       +};
       +
       +struct ElfHdr
       +{
       +        uchar        magic[4];
       +        uchar        class;
       +        uchar        encoding;
       +        uchar        version;
       +        uchar        abi;
       +        uchar        abiversion;
       +        u32int        type;
       +        u32int        machine;
       +        u32int        entry;
       +        u32int        phoff;
       +        u32int        shoff;
       +        u32int        flags;
       +        u32int        ehsize;
       +        u32int        phentsize;
       +        u32int        phnum;
       +        u32int        shentsize;
       +        u32int        shnum;
       +        u32int        shstrndx;
       +        u16int        (*e2)(uchar*);
       +        u32int        (*e4)(uchar*);
       +        u64int        (*e8)(uchar*);
       +};
       +
       +struct ElfSect
       +{
       +        char                *name;
       +        u32int        type;
       +        u32int        flags;
       +        u32int        addr;
       +        u32int        offset;
       +        u32int        size;
       +        u32int        link;
       +        u32int        info;
       +        u32int        align;
       +        u32int        entsize;
       +        uchar        *base;
       +};
       +
       +struct ElfProg
       +{
       +        u32int        type;
       +        u32int        offset;
       +        u32int        vaddr;
       +        u32int        paddr;
       +        u32int        filesz;
       +        u32int        memsz;
       +        u32int        flags;
       +        u32int        align;
       +};
       +
       +struct ElfNote
       +{
       +        u32int        namesz;
       +        u32int        descsz;
       +        u32int        type;
       +        char        *name;
       +        uchar        *desc;
       +        u32int        offset;        /* in-memory only */
       +};
       +
       +struct ElfSym
       +{
       +        char*        name;
       +        u32int        value;
       +        u32int        size;
       +        uchar        bind;
       +        uchar        type;
       +        uchar        other;
       +        u16int        shndx;
       +};
       +
       +struct Elf
       +{
       +        int                fd;
       +        ElfHdr        hdr;
       +        ElfSect        *sect;
       +        uint                nsect;
       +        ElfProg        *prog;
       +        uint                nprog;
       +        char                *shstrtab;
       +
       +        int                nsymtab;
       +        ElfSect        *symtab;
       +        ElfSect        *symstr;
       +        int                ndynsym;
       +        ElfSect        *dynsym;
       +        ElfSect        *dynstr;
       +        ElfSect        *bss;
       +
       +        int                (*coreregs)(Elf*, ElfNote*, uchar**);
       +};
       +
       +Elf*        elfopen(char*);
       +Elf*        elfinit(int);
       +ElfSect *elfsection(Elf*, char*);
       +void        elfclose(Elf*);
       +int        elfsym(Elf*, int, ElfSym*);
       +int        elfmap(Elf*, ElfSect*);
       +
       +int        coreregslinux386(Elf*, ElfNote*, uchar**);
       +int        coreregsfreebsd386(Elf*, ElfNote*, uchar**);
   DIR diff --git a/src/libmach/elfcore.h b/src/libmach/elfcore.h
       t@@ -0,0 +1,142 @@
       +/* Copyright (c) 2002, 2003 William Josephson */
       +
       +enum {
       +        CoremapMagic        = 0xba5eba11,
       +        CoremapMax        = 128,
       +};
       +#undef MAXCOMLEN
       +#define MAXCOMLEN 16
       +#define PRSTATUS_VERSION        1        /* Current version of prstatus_t */
       +#define PRPSINFO_VERSION        1        /* Current version of prpsinfo_t */
       +#define PRARGSZ                        80        /* Maximum argument bytes saved */
       +
       +
       +typedef struct Coremap Coremap;
       +typedef struct CoremapItem CoremapItem;
       +typedef struct CoremapHeader CoremapHeader;
       +typedef struct ElfNote ElfNote;
       +typedef struct Reg386 Reg386;
       +typedef struct PrStatus386 PrStatus386;
       +typedef struct PrPsinfo PrPsinfo;
       +
       +struct CoremapHeader {
       +        u32int        magic;
       +        u32int        counter;
       +        u32int        maxelem;
       +};
       +
       +struct CoremapItem {
       +        u32int        address;
       +        u32int        size;
       +};
       +
       +struct Coremap {
       +        CoremapHeader        header;
       +        CoremapItem        map[CoremapMax];
       +};
       +
       +struct ElfNote {
       +        u32int        namesz;
       +        u32int        descsz;
       +        u32int        type;
       +        char        *name;
       +        uchar        *desc;
       +        u32int        offset;        /* in-memory only */
       +};
       +
       +enum
       +{
       +        NotePrStatus = 1,
       +        NotePrFpreg = 2,
       +        NotePrPsinfo = 3,
       +        NotePrTaskstruct = 4,
       +        NotePrAuxv = 6,
       +        NotePrXfpreg = 0x46e62b7f,        /* according to gdb */
       +};
       +#if 0
       +struct Reg386
       +{
       +        u32int        fs;
       +        u32int        es;
       +        u32int        ds;
       +        u32int        edi;
       +        u32int        esi;
       +        u32int        ebp;
       +        u32int        isp;
       +        u32int        ebx;
       +        u32int        edx;
       +        u32int        ecx;
       +        u32int        eax;
       +        u32int        trapno;
       +        u32int        err;
       +        u32int        eip;
       +        u32int        cs;
       +        u32int        eflags;
       +        u32int        esp;
       +        u32int        ss;
       +        u32int        gs;
       +};
       +#endif
       +
       +struct Reg386
       +{
       +        u32int        ebx;
       +        u32int        ecx;
       +        u32int        edx;
       +        u32int        esi;
       +        u32int        edi;
       +        u32int        ebp;
       +        u32int        eax;
       +        u32int        ds;
       +        u32int        es;
       +        u32int        fs;
       +        u32int        gs;
       +        u32int        origeax;
       +        u32int        eip;
       +        u32int        cs;
       +        u32int        eflags;
       +        u32int        esp;
       +        u32int        ss;
       +};
       +
       +#if 0
       +struct PrStatus386
       +{
       +    u32int                version;        /* Version number of struct (1) */
       +    u32int                statussz;        /* sizeof(prstatus_t) (1) */
       +    u32int                gregsetsz;        /* sizeof(gregset_t) (1) */
       +    u32int                fpregsetsz;        /* sizeof(fpregset_t) (1) */
       +    int                        osreldate;        /* Kernel version (1) */
       +    int                        cursig;        /* Current signal (1) */
       +    pid_t                pid;                /* Process ID (1) */
       +    Reg386                reg;                /* General purpose registers (1) */
       +};
       +#endif
       +
       +struct PrPsinfo
       +{
       +    int                version;                /* Version number of struct (1) */
       +    u32int        psinfosz;                /* sizeof(prpsinfo_t) (1) */
       +    char        fname[MAXCOMLEN+1];        /* Command name, null terminated (1) */
       +    char        psargs[PRARGSZ+1];        /* Arguments, null terminated (1) */
       +};
       +
       +struct PrStatus386
       +{
       +        u32int        signo;
       +        u32int        code;
       +        u32int        errno;
       +        u32int        cursig;
       +        u32int        sigpend;
       +        u32int        sighold;
       +        u32int        pid;
       +        u32int        ppid;
       +        u32int        pgrp;
       +        u32int        sid;
       +        u32int        utime[2];
       +        u32int        stime[2];
       +        u32int        cutime[2];
       +        u32int        cstime[2];
       +        Reg386        reg;
       +        u32int        fpvalid;
       +};
   DIR diff --git a/src/libmach/elfcorefreebsd386.c b/src/libmach/elfcorefreebsd386.c
       t@@ -0,0 +1,89 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <mach.h>
       +#include "elf.h"
       +#include "ureg386.h"
       +
       +typedef struct Lreg Lreg;
       +typedef struct Status Status;
       +
       +struct Lreg
       +{
       +        u32int        fs;
       +        u32int        es;
       +        u32int        ds;
       +        u32int        edi;
       +        u32int        esi;
       +        u32int        ebp;
       +        u32int        isp;
       +        u32int        ebx;
       +        u32int        edx;
       +        u32int        ecx;
       +        u32int        eax;
       +        u32int        trapno;
       +        u32int        err;
       +        u32int        eip;
       +        u32int        cs;
       +        u32int        eflags;
       +        u32int        esp;
       +        u32int        ss;
       +        u32int        gs;
       +};
       +
       +struct Status
       +{
       +    u32int                version;        /* Version number of struct (1) */
       +    u32int                statussz;        /* sizeof(prstatus_t) (1) */
       +    u32int                gregsetsz;        /* sizeof(gregset_t) (1) */
       +    u32int                fpregsetsz;        /* sizeof(fpregset_t) (1) */
       +    u32int                osreldate;        /* Kernel version (1) */
       +    u32int                cursig;        /* Current signal (1) */
       +    u32int                pid;                /* Process ID (1) */
       +    Lreg                reg;                /* General purpose registers (1) */
       +};
       +
       +int
       +coreregsfreebsd386(Elf *elf, ElfNote *note, uchar **up)
       +{
       +        Status *s;
       +        Lreg *l;
       +        Ureg *u;
       +
       +        if(note->descsz < sizeof(Status)){
       +                werrstr("elf status note too small");
       +                return -1;
       +        }
       +        s = (Status*)note->desc;
       +        if(s->version != 1){
       +                werrstr("unknown status version %ud", (uint)s->version);
       +                return -1;
       +        }
       +        l = &s->reg;
       +        u = malloc(sizeof(Ureg));
       +        if(u == nil)
       +                return -1;
       +
       +        /* no byte order problems - just copying and rearranging */
       +        u->di = l->edi;
       +        u->si = l->esi;
       +        u->bp = l->ebp;
       +        u->nsp = l->esp;
       +        u->bx = l->ebx;
       +        u->dx = l->edx;
       +        u->cx = l->ecx;
       +        u->ax = l->eax;
       +        u->gs = l->gs;
       +        u->fs = l->fs;
       +        u->es = l->es;
       +        u->ds = l->ds;
       +        u->trap = l->trapno;
       +        u->ecode = l->err;
       +        u->pc = l->eip;
       +        u->cs = l->cs;
       +        u->flags = l->eflags;
       +        u->sp = l->esp;
       +        u->ss = l->ss;
       +        *up = (uchar*)u;
       +        return sizeof(Ureg);
       +}
       +
   DIR diff --git a/src/libmach/elfcorelinux386.c b/src/libmach/elfcorelinux386.c
       t@@ -0,0 +1,95 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <mach.h>
       +#include "elf.h"
       +#include "ureg386.h"
       +
       +typedef struct Lreg Lreg;
       +typedef struct Status Status;
       +
       +struct Lreg
       +{
       +        u32int        ebx;
       +        u32int        ecx;
       +        u32int        edx;
       +        u32int        esi;
       +        u32int        edi;
       +        u32int        ebp;
       +        u32int        eax;
       +        u32int        ds;
       +        u32int        es;
       +        u32int        fs;
       +        u32int        gs;
       +        u32int        origeax;
       +        u32int        eip;
       +        u32int        cs;
       +        u32int        eflags;
       +        u32int        esp;
       +        u32int        ss;
       +};
       +
       +/*
       + * Lreg is 64-bit aligned within status, so we shouldn't 
       + * have any packing problems. 
       + */
       +struct Status
       +{
       +        u32int        signo;
       +        u32int        code;
       +        u32int        errno;
       +        u32int        cursig;
       +        u32int        sigpend;
       +        u32int        sighold;
       +        u32int        pid;
       +        u32int        ppid;
       +        u32int        pgrp;
       +        u32int        sid;
       +        u32int        utime[2];
       +        u32int        stime[2];
       +        u32int        cutime[2];
       +        u32int        cstime[2];
       +        Lreg        reg;
       +        u32int        fpvalid;
       +};
       +
       +int
       +coreregslinux386(Elf *elf, ElfNote *note, uchar **up)
       +{
       +        Status *s;
       +        Lreg *l;
       +        Ureg *u;
       +
       +        if(note->descsz < sizeof(Status)){
       +                werrstr("elf status note too small");
       +                return -1;
       +        }
       +        s = (Status*)note->desc;
       +        l = &s->reg;
       +        u = malloc(sizeof(Ureg));
       +        if(u == nil)
       +                return -1;
       +
       +        /* no byte order problems - just copying and rearranging */
       +        u->di = l->edi;
       +        u->si = l->esi;
       +        u->bp = l->ebp;
       +        u->nsp = l->esp;
       +        u->bx = l->ebx;
       +        u->dx = l->edx;
       +        u->cx = l->ecx;
       +        u->ax = l->eax;
       +        u->gs = l->gs;
       +        u->fs = l->fs;
       +        u->es = l->es;
       +        u->ds = l->ds;
       +        u->trap = ~0; // l->trapno;
       +        u->ecode = ~0; // l->err;
       +        u->pc = l->eip;
       +        u->cs = l->cs;
       +        u->flags = l->eflags;
       +        u->sp = l->esp;
       +        u->ss = l->ss;
       +        *up = (uchar*)u;
       +        return sizeof(Ureg);
       +}
       +
   DIR diff --git a/src/libmach/elfdump.c b/src/libmach/elfdump.c
       t@@ -0,0 +1,133 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include <mach.h>
       +#include "elf.h"
       +#include "stabs.h"
       +
       +void
       +usage(void)
       +{
       +        fprint(2, "usage: elf file list\n");
       +        fprint(2, "        elf file syms\n");
       +        fprint(2, "        elf file prog n\n");
       +        fprint(2, "        elf file sect n\n");
       +        exits("usage");
       +}
       +
       +void
       +main(int argc, char **argv)
       +{
       +        int i, n, nn;
       +        char buf[512];
       +        ulong off, len;
       +        Elf *elf;
       +        ElfProg *p;
       +        ElfSect *s;
       +
       +        ARGBEGIN{
       +        default:
       +                usage();
       +        }ARGEND
       +
       +        if(argc < 2)
       +                usage();
       +
       +        if((elf = elfopen(argv[0])) == nil)
       +                sysfatal("elfopen %s: %r", argv[0]);
       +
       +        if(strcmp(argv[1], "syms") == 0){
       +                ElfSym sym;
       +                for(i=0; elfsym(elf, i, &sym) >= 0; i++){
       +                        print("%s 0x%lux +%lud bind %d type %d other %d shndx 0x%ux\n",
       +                                sym.name, (ulong)sym.value, (ulong)sym.size,
       +                                sym.bind, sym.type, sym.other, (uint)sym.shndx);
       +                }
       +        }
       +        else if(strcmp(argv[1], "stabs") == 0){
       +                ElfSect *s1, *s2;
       +                Stab stabs;
       +                StabSym sym;
       +
       +                if((s1 = elfsection(elf, ".stab")) == nil)
       +                        sysfatal("no stabs");
       +                if(s1->link==0 || s1->link >= elf->nsect)
       +                        sysfatal("bad stabstr %d", s1->link);
       +                s2 = &elf->sect[s1->link];
       +                if(elfmap(elf, s1) < 0 || elfmap(elf, s2) < 0)
       +                        sysfatal("elfmap");
       +                stabs.stabbase = s1->base;
       +                stabs.stabsize = s1->size;
       +                stabs.strbase = s2->base;
       +                stabs.strsize = s2->size;
       +                stabs.e2 = elf->hdr.e2;
       +                stabs.e4 = elf->hdr.e4;
       +                print("%ud %ud\n", stabs.stabsize, stabs.strsize);
       +                for(i=0; stabsym(&stabs, i, &sym) >= 0; i++)
       +                        print("%s type 0x%x other %d desc %d value 0x%lux\n",
       +                                sym.name, sym.type, sym.other, (int)sym.desc, (ulong)sym.value);
       +                fprint(2, "err at %d: %r\n", i);
       +        }
       +        else if(strcmp(argv[1], "list") == 0){
       +                if(argc != 2)
       +                        usage();
       +                print("elf %s %s v%d entry 0x%08lux phoff 0x%lux shoff 0x%lux flags 0x%lux\n",
       +                        elftype(elf->hdr.type), elfmachine(elf->hdr.machine),
       +                        elf->hdr.version, elf->hdr.entry, elf->hdr.phoff, elf->hdr.shoff,
       +                        elf->hdr.flags);
       +                print("\tehsize %d phentsize %d phnum %d shentsize %d shnum %d shstrndx %d\n",
       +                        elf->hdr.ehsize, elf->hdr.phentsize, elf->hdr.phnum, elf->hdr.shentsize,
       +                        elf->hdr.shnum, elf->hdr.shstrndx);
       +                for(i=0; i<elf->nprog; i++){
       +                        p = &elf->prog[i];
       +                        print("prog %d type %d offset 0x%08lux vaddr 0x%08lux paddr 0x%08lux filesz 0x%08lux memsz 0x%08lux flags 0x%08lux align 0x%08lux\n",
       +                                i, p->type, p->offset, p->vaddr, p->paddr,
       +                                p->filesz, p->memsz, p->flags, p->align);
       +                }
       +                for(i=0; i<elf->nsect; i++){
       +                        s = &elf->sect[i];
       +                        print("sect %d %s type %d flags 0x%lux addr 0x%08lux offset 0x%08lux size 0x%08lux link 0x%lux info 0x%lux align 0x%lux entsize 0x%lux\n",
       +                                i, s->name, s->type, s->flags, s->addr, s->offset, s->size, s->link, s->info,
       +                                s->align, s->entsize);
       +                }
       +        }
       +        else if(strcmp(argv[1], "prog") == 0){
       +                if(argc != 3)
       +                        usage();
       +                i = atoi(argv[2]);
       +                if(i < 0 || i >= elf->nprog)
       +                        sysfatal("bad prog number");
       +                off = elf->prog[i].offset;
       +                len = elf->prog[i].filesz;
       +                fprint(2, "prog %d offset 0x%lux size 0x%lux\n", i, off, len);
       +        copy:
       +                seek(elf->fd, off, 0);
       +                for(n=0; n<len; n+=nn){
       +                        nn = sizeof buf;
       +                        if(nn > len-n)
       +                                nn = len-n;
       +                        nn = read(elf->fd, buf, nn);
       +                        if(nn == 0)
       +                                break;
       +                        if(nn < 0)
       +                                sysfatal("read error");
       +                        write(1, buf, nn);
       +                }
       +                if(n < len)
       +                        fprint(2, "early eof\n");
       +        }
       +        else if(strcmp(argv[1], "sect") == 0){
       +                if(argc != 3)
       +                        usage();
       +                i = atoi(argv[2]);
       +                if(i < 0 || i >= elf->nsect)
       +                        sysfatal("bad section number");
       +                off = elf->sect[i].offset;
       +                len = elf->sect[i].size;
       +                fprint(2, "section %d offset 0x%lux size 0x%lux\n", i, off, len);
       +                goto copy;
       +        }
       +        else
       +                usage();
       +        exits(0);
       +}
   DIR diff --git a/src/libmach/elfdynsym.c b/src/libmach/elfdynsym.c
       t@@ -0,0 +1,6 @@
       +#include <u.h>
       +#include <libc.h>
       +#include "elf.h"
       +
       +int
       +elfsym(Elf *elf, ElfSect *symtab, ElfSect *strtab, int ndx, ElfSym *
       +\ No newline at end of file
   DIR diff --git a/src/libmach/fpformat.c b/src/libmach/fpformat.c
       t@@ -0,0 +1,65 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include <mach.h>
       +
       +/*
       + *        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, Regdesc *rp, char *buf, uint n, uint modif)
       +{
       +        char reg[12];
       +        u32int r;
       +
       +        switch(rp->format)
       +        {
       +        case 'X':
       +                if (get4(map, rp->offset, &r) < 0)
       +                        return -1;
       +                snprint(buf, n, "%lux", r);
       +                break;
       +        case 'F':        /* first reg of double reg pair */
       +                if (modif == 'F')
       +                if ((rp->format=='F') || (((rp+1)->flags&RFLT) && (rp+1)->format == 'f')) {
       +                        if (get1(map, rp->offset, (uchar *)reg, 8) < 0)
       +                                return -1;
       +                        mach->ftoa64(buf, n, reg);
       +                        if (rp->format == 'F')
       +                                return 1;
       +                        return 2;
       +                }        
       +                        /* treat it like 'f' */
       +                if (get1(map, rp->offset, (uchar *)reg, 4) < 0)
       +                        return -1;
       +                mach->ftoa32(buf, n, reg);
       +                break;
       +        case 'f':        /* 32 bit float */
       +                if (get1(map, rp->offset, (uchar *)reg, 4) < 0)
       +                        return -1;
       +                mach->ftoa32(buf, n, reg);
       +                break;
       +        case '3':        /* little endian ieee 80 with hole in bytes 8&9 */
       +                if (get1(map, rp->offset, (uchar *)reg, 10) < 0)
       +                        return -1;
       +                memmove(reg+10, reg+8, 2);        /* open hole */
       +                memset(reg+8, 0, 2);                /* fill it */
       +                leieeeftoa80(buf, n, reg);
       +                break;
       +        case '8':        /* big-endian ieee 80 */
       +                if (get1(map, rp->offset, (uchar *)reg, 10) < 0)
       +                        return -1;
       +                beieeeftoa80(buf, n, reg);
       +                break;
       +        default:        /* unknown */
       +                break;
       +        }
       +        return 1;
       +}
   DIR diff --git a/src/libmach/frame.c b/src/libmach/frame.c
       t@@ -0,0 +1,130 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include <mach.h>
       +
       +typedef struct LocRegs LocRegs;
       +struct LocRegs
       +{
       +        Regs r;
       +        Regs *oldregs;
       +        Map *map;
       +        ulong *val;
       +};
       +
       +static int
       +locregrw(Regs *regs, char *name, ulong *val, int isr)
       +{
       +        int i;
       +        LocRegs *lr;
       +
       +        lr = (LocRegs*)regs;
       +        i = windindex(name);
       +        if(i == -1)
       +                return lr->oldregs->rw(lr->oldregs, name, val, isr);
       +        if(isr){
       +                *val = lr->val[i];
       +                return 0;
       +        }else{
       +                werrstr("saved registers are immutable");
       +                return -1;
       +        }
       +}
       +
       +int
       +stacktrace(Map *map, Regs *regs, Tracer trace)
       +{
       +        char *rname;
       +        int i, ipc, ret;
       +        ulong nextpc, pc, v;
       +        ulong *cur, *next;
       +        LocRegs lr;
       +        Symbol s, *sp;
       +
       +        /*
       +         * Allocate location arrays.
       +         */
       +        ret = -1;
       +        cur = malloc(mach->nwindreg*sizeof(cur[0]));
       +        next = malloc(mach->nwindreg*sizeof(cur[0]));
       +        if(cur==nil || next==nil)
       +                goto out;
       +        
       +        /*
       +         * Initialize current registers using regs.
       +         */
       +        if(rget(regs, mach->pc, &pc) < 0){
       +                werrstr("cannot fetch initial pc: %r");
       +                goto out;        
       +        }
       +
       +        for(i=0; i<mach->nwindreg; i++){
       +                rname = mach->windreg[i];
       +                if(rget(regs, rname, &v) < 0)
       +                        v = ~(ulong)0;
       +                cur[i] = v;
       +        }
       +
       +        ipc = windindex(mach->pc);
       +        ret = 0;
       +
       +        /* set up cur[i]==next[i] for unwindframe */
       +        memmove(next, cur, mach->nwindreg*sizeof(next[0]));
       +        for(;;){
       +                sp = &s;
       +                if(findsym(locaddr(pc), CTEXT, &s) < 0)
       +                        sp = nil;
       +
       +                lr.r.rw = locregrw;
       +                lr.oldregs = regs;
       +                lr.val = cur;
       +                lr.map = map;
       +                if((i = unwindframe(map, &lr.r, next)) >= 0)
       +                        nextpc = next[ipc];
       +                else
       +                        nextpc = ~(ulong)0;
       +                if((*trace)(map, &lr.r, pc, nextpc, sp, ++ret) <= 0)
       +                        break;
       +                if(i < 0)
       +                        break;
       +                if(sp && strcmp(sp->name, "main") == 0)
       +                        break;
       +                pc = nextpc;
       +                memmove(cur, next, mach->nwindreg*sizeof(cur[0]));
       +        }
       +
       +out:
       +        free(cur);
       +        free(next);
       +        return ret;
       +}
       +
       +int
       +windindex(char *reg)
       +{
       +        char **p;
       +        int i;
       +
       +        p = mach->windreg;
       +        for(i=0; i<mach->nwindreg; i++)
       +                if(strcmp(p[i], reg) == 0)
       +                        return i;
       +        werrstr("%s is not a winding register", reg);
       +        return -1;
       +}
       +
       +Loc*
       +windreglocs(void)
       +{
       +        int i;
       +        Loc *loc;
       +
       +        loc = malloc(mach->nwindreg*sizeof(loc[0]));
       +        if(loc == nil)
       +                return nil;
       +        for(i=0; i<mach->nwindreg; i++){
       +                loc[i].type = LREG;
       +                loc[i].reg = mach->windreg[i];
       +        }
       +        return loc;
       +}
   DIR diff --git a/src/libmach/hexify.c b/src/libmach/hexify.c
       t@@ -0,0 +1,20 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include <mach.h>
       +
       +char *
       +_hexify(char *buf, ulong p, int zeros)
       +{
       +        ulong d;
       +
       +        d = p/16;
       +        if(d)
       +                buf = _hexify(buf, d, zeros-1);
       +        else
       +                while(zeros--)
       +                        *buf++ = '0';
       +        *buf++ = "0123456789abcdef"[p&0x0f];
       +        return buf;
       +}
       +
   DIR diff --git a/src/libmach/ieee.c b/src/libmach/ieee.c
       t@@ -0,0 +1,169 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include <mach.h>
       +
       +/*
       + * 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
       +ieeeftoa64(char *buf, uint n, u32int h, u32int l)
       +{
       +        double fr;
       +        int exp;
       +
       +        if (n <= 0)
       +                return 0;
       +
       +
       +        if(h & (1L<<31)){
       +                *buf++ = '-';
       +                h &= ~(1L<<31);
       +        }else
       +                *buf++ = ' ';
       +        n--;
       +        if(l == 0 && h == 0)
       +                return snprint(buf, n, "0.");
       +        exp = (h>>20) & ((1L<<11)-1L);
       +        if(exp == 0)
       +                return snprint(buf, n, "DeN(%.8lux%.8lux)", h, l);
       +        if(exp == ((1L<<11)-1L)){
       +                if(l==0 && (h&((1L<<20)-1L)) == 0)
       +                        return snprint(buf, n, "Inf");
       +                else
       +                        return snprint(buf, n, "NaN(%.8lux%.8lux)", h&((1L<<20)-1L), l);
       +        }
       +        exp -= (1L<<10) - 2L;
       +        fr = l & ((1L<<16)-1L);
       +        fr /= 1L<<16;
       +        fr += (l>>16) & ((1L<<16)-1L);
       +        fr /= 1L<<16;
       +        fr += (h & (1L<<20)-1L) | (1L<<20);
       +        fr /= 1L<<21;
       +        fr = ldexp(fr, exp);
       +        return snprint(buf, n, "%.18g", fr);
       +}
       +
       +int
       +ieeeftoa32(char *buf, uint n, u32int h)
       +{
       +        double fr;
       +        int exp;
       +
       +        if (n <= 0)
       +                return 0;
       +
       +        if(h & (1L<<31)){
       +                *buf++ = '-';
       +                h &= ~(1L<<31);
       +        }else
       +                *buf++ = ' ';
       +        n--;
       +        if(h == 0)
       +                return snprint(buf, n, "0.");
       +        exp = (h>>23) & ((1L<<8)-1L);
       +        if(exp == 0)
       +                return snprint(buf, n, "DeN(%.8lux)", h);
       +        if(exp == ((1L<<8)-1L)){
       +                if((h&((1L<<23)-1L)) == 0)
       +                        return snprint(buf, n, "Inf");
       +                else
       +                        return snprint(buf, n, "NaN(%.8lux)", h&((1L<<23)-1L));
       +        }
       +        exp -= (1L<<7) - 2L;
       +        fr = (h & ((1L<<23)-1L)) | (1L<<23);
       +        fr /= 1L<<24;
       +        fr = ldexp(fr, exp);
       +        return snprint(buf, n, "%.9g", fr);
       +}
       +
       +int
       +beieeeftoa32(char *buf, uint n, void *s)
       +{
       +        return ieeeftoa32(buf, n, beswap4(*(u32int*)s));
       +}
       +
       +int
       +beieeeftoa64(char *buf, uint n, void *s)
       +{
       +        return ieeeftoa64(buf, n, beswap4(*(u32int*)s), beswap4(((u32int*)(s))[1]));
       +}
       +
       +int
       +leieeeftoa32(char *buf, uint n, void *s)
       +{
       +        return ieeeftoa32(buf, n, leswap4(*(u32int*)s));
       +}
       +
       +int
       +leieeeftoa64(char *buf, uint n, void *s)
       +{
       +        return ieeeftoa64(buf, n, leswap4(((u32int*)(s))[1]), leswap4(*(u32int*)s));
       +}
       +
       +/* packed in 12 bytes, with s[2]==s[3]==0; mantissa starts at s[4]*/
       +int
       +beieeeftoa80(char *buf, uint n, void *s)
       +{
       +        uchar *reg = (uchar*)s;
       +        int i;
       +        ulong x;
       +        uchar ieee[8+8];        /* room for slop */
       +        uchar *p, *q;
       +
       +        memset(ieee, 0, sizeof(ieee));
       +        /* sign */
       +        if(reg[0] & 0x80)
       +                ieee[0] |= 0x80;
       +
       +        /* exponent */
       +        x = ((reg[0]&0x7F)<<8) | reg[1];
       +        if(x == 0)                /* number is ±0 */
       +                goto done;
       +        if(x == 0x7FFF){
       +                if(memcmp(reg+4, ieee+1, 8) == 0){ /* infinity */
       +                        x = 2047;
       +                }else{                                /* NaN */
       +                        x = 2047;
       +                        ieee[7] = 0x1;                /* make sure */
       +                }
       +                ieee[0] |= x>>4;
       +                ieee[1] |= (x&0xF)<<4;
       +                goto done;
       +        }
       +        x -= 0x3FFF;                /* exponent bias */
       +        x += 1023;
       +        if(x >= (1<<11) || ((reg[4]&0x80)==0 && x!=0))
       +                return snprint(buf, n, "not in range");
       +        ieee[0] |= x>>4;
       +        ieee[1] |= (x&0xF)<<4;
       +
       +        /* mantissa */
       +        p = reg+4;
       +        q = ieee+1;
       +        for(i=0; i<56; i+=8, p++, q++){        /* move one byte */
       +                x = (p[0]&0x7F) << 1;
       +                if(p[1] & 0x80)
       +                        x |= 1;
       +                q[0] |= x>>4;
       +                q[1] |= (x&0xF)<<4;
       +        }
       +    done:
       +        return beieeeftoa64(buf, n, (void*)ieee);
       +}
       +
       +
       +int
       +leieeeftoa80(char *buf, uint n, void *s)
       +{
       +        int i;
       +        char *cp;
       +        char b[12];
       +
       +        cp = (char*) s;
       +        for(i=0; i<12; i++)
       +                b[11-i] = *cp++;
       +        return beieeeftoa80(buf, n, b);
       +}
   DIR diff --git a/src/libmach/loc.c b/src/libmach/loc.c
       t@@ -0,0 +1,253 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include <mach.h>
       +
       +int
       +locfmt(Fmt *fmt)
       +{
       +        Loc l;
       +
       +        l = va_arg(fmt->args, Loc);
       +        switch(l.type){
       +        default:
       +                return fmtprint(fmt, "<loc%d>", l.type);
       +        case LCONST:
       +                return fmtprint(fmt, "0x%lux", l.addr);
       +        case LADDR:
       +                return fmtprint(fmt, "*0x%lux", l.addr);
       +        case LOFFSET:
       +                return fmtprint(fmt, "%ld(%s)", l.offset, l.reg);
       +        case LREG:
       +                return fmtprint(fmt, "%s", l.reg);
       +        }
       +}
       +
       +int
       +loccmp(Loc *a, Loc *b)
       +{
       +        int i;
       +
       +        if(a->type < b->type)
       +                return -1;
       +        if(a->type > b->type)
       +                return 1;
       +        switch(a->type){
       +        default:
       +                return 0;
       +        case LADDR:
       +                if(a->addr < b->addr)
       +                        return -1;
       +                if(a->addr > b->addr)
       +                        return 1;
       +                return 0;
       +        case LOFFSET:
       +                i = strcmp(a->reg, b->reg);
       +                if(i != 0)
       +                        return i;
       +                if(a->offset < b->offset)
       +                        return -1;
       +                if(a->offset > b->offset)
       +                        return 1;
       +                return 0;
       +        case LREG:
       +                return strcmp(a->reg, b->reg);
       +        }
       +}
       +
       +int
       +lget1(Map *map, Regs *regs, Loc loc, uchar *a, uint n)
       +{
       +        if(locsimplify(map, regs, loc, &loc) < 0)
       +                return -1;
       +        if(loc.type == LADDR)
       +                return get1(map, loc.addr, a, n);
       +        /* could do more here - i'm lazy */
       +        werrstr("bad location for lget1");
       +        return -1;
       +}
       +
       +int
       +lget2(Map *map, Regs *regs, Loc loc, u16int *u)
       +{
       +        ulong ul;
       +
       +        if(locsimplify(map, regs, loc, &loc) < 0)
       +                return -1;
       +        if(loc.type == LADDR)
       +                return get2(map, loc.addr, u);
       +        if(loc.type == LCONST){
       +                *u = loc.addr;
       +                return 0;
       +        }
       +        if(loc.type == LREG){
       +                if(rget(regs, loc.reg, &ul) < 0)
       +                        return -1;
       +                *u = ul;
       +                return 0;
       +        }
       +        werrstr("bad location for lget2");
       +        return -1;
       +}
       +
       +int
       +lget4(Map *map, Regs *regs, Loc loc, u32int *u)
       +{
       +        ulong ul;
       +
       +        if(locsimplify(map, regs, loc, &loc) < 0)
       +                return -1;
       +        if(loc.type == LADDR)
       +                return get4(map, loc.addr, u);
       +        if(loc.type == LCONST){
       +                *u = loc.addr;
       +                return 0;
       +        }
       +        if(loc.type == LREG){
       +                if(rget(regs, loc.reg, &ul) < 0)
       +                        return -1;
       +                *u = ul;
       +                return 0;
       +        }
       +        werrstr("bad location for lget4");
       +        return -1;
       +}
       +
       +int
       +lget8(Map *map, Regs *regs, Loc loc, u64int *u)
       +{
       +        ulong ul;
       +
       +        if(locsimplify(map, regs, loc, &loc) < 0)
       +                return -1;
       +        if(loc.type == LADDR)
       +                return get8(map, loc.addr, u);
       +        if(loc.type == LCONST){
       +                *u = loc.addr;
       +                return 0;
       +        }
       +        if(loc.type == LREG){
       +                if(rget(regs, loc.reg, &ul) < 0)
       +                        return -1;
       +                *u = ul;
       +                return 0;
       +        }
       +        werrstr("bad location for lget8");
       +        return -1;
       +}
       +
       +int
       +lput1(Map *map, Regs *regs, Loc loc, uchar *a, uint n)
       +{
       +        if(locsimplify(map, regs, loc, &loc) < 0)
       +                return -1;
       +        if(loc.type == LADDR)
       +                return put1(map, loc.addr, a, n);
       +        /* could do more here - i'm lazy */
       +        werrstr("bad location for lput1");
       +        return -1;
       +}
       +
       +int
       +lput2(Map *map, Regs *regs, Loc loc, u16int u)
       +{
       +        if(locsimplify(map, regs, loc, &loc) < 0)
       +                return -1;
       +        if(loc.type == LADDR)
       +                return put2(map, loc.addr, u);
       +        if(loc.type == LREG)
       +                return rput(regs, loc.reg, u);
       +        werrstr("bad location for lput2");
       +        return -1;
       +}
       +
       +int
       +lput4(Map *map, Regs *regs, Loc loc, u32int u)
       +{
       +        if(locsimplify(map, regs, loc, &loc) < 0)
       +                return -1;
       +        if(loc.type == LADDR)
       +                return put4(map, loc.addr, u);
       +        if(loc.type == LREG)
       +                return rput(regs, loc.reg, u);
       +        werrstr("bad location for lput4");
       +        return -1;
       +}
       +
       +int
       +lput8(Map *map, Regs *regs, Loc loc, u64int u)
       +{
       +        if(locsimplify(map, regs, loc, &loc) < 0)
       +                return -1;
       +        if(loc.type == LADDR)
       +                return put8(map, loc.addr, u);
       +        if(loc.type == LREG)
       +                return rput(regs, loc.reg, u);
       +        werrstr("bad location for lput8");
       +        return -1;
       +}
       +
       +Loc
       +locaddr(ulong addr)
       +{
       +        Loc l;
       +
       +        l.type = LADDR;
       +        l.addr = addr;
       +        return l;
       +}
       +
       +Loc
       +locindir(char *reg, long offset)
       +{
       +        Loc l;
       +
       +        l.type = LOFFSET;
       +        l.reg = reg;
       +        l.offset = offset;
       +        return l;
       +}
       +
       +Loc
       +locconst(ulong con)
       +{
       +        Loc l;
       +
       +        l.type = LCONST;
       +        l.addr = con;
       +        return l;
       +}
       +
       +Loc
       +locnone(void)
       +{
       +        Loc l;
       +
       +        l.type = LNONE;
       +        return l;
       +}
       +
       +Loc
       +locreg(char *reg)
       +{
       +        Loc l;
       +
       +        l.type = LREG;
       +        l.reg = reg;
       +        return l;
       +}
       +
       +int
       +locsimplify(Map *map, Regs *regs, Loc loc, Loc *newloc)
       +{
       +        ulong u;
       +
       +        if(loc.type == LOFFSET){
       +                if(rget(regs, loc.reg, &u) < 0)
       +                        return -1;
       +                *newloc = locaddr(u + loc.offset);
       +        }else
       +                *newloc = loc;
       +        return 0;
       +}
       +
   DIR diff --git a/src/libmach/localaddr.c b/src/libmach/localaddr.c
       t@@ -0,0 +1,56 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include <mach.h>
       +
       +/*
       + * XXX could remove the rock by hiding it in a special regs.
       + * That would still be sleazy but would be thread-safe.
       + */
       +
       +static struct {
       +        int found;
       +        int nframe;
       +        Loc l;
       +        char *fn;
       +        char *var;
       +} rock;
       +
       +static int
       +ltrace(Map *map, Regs *regs, ulong pc, ulong nextpc, Symbol *sym, int depth)
       +{
       +        ulong v;
       +        Symbol s1;
       +
       +        USED(pc);
       +        USED(nextpc);
       +        USED(depth);
       +
       +        if(sym==nil || strcmp(sym->name, rock.fn) != 0)
       +                return ++rock.nframe < 40;
       +        if(lookuplsym(sym, rock.var, &s1) < 0)
       +                return 0;
       +        if(locsimplify(map, regs, s1.loc, &rock.l) < 0)
       +                return 0;
       +        if(rock.l.type == LREG && rget(regs, rock.l.reg, &v) >= 0)
       +                rock.l = locconst(v);
       +        if(rock.l.type != LADDR && rock.l.type != LCONST)
       +                return 0;
       +        rock.found = 1;
       +        return 0;
       +}
       +
       +int
       +localaddr(Map *map, Regs *regs, char *fn, char *var, ulong *val)
       +{
       +        rock.found = 0;
       +        rock.nframe = 0;
       +        rock.fn = fn;
       +        rock.var = var;
       +        stacktrace(map, regs, ltrace);
       +        if(rock.found){
       +                *val = rock.l.addr;
       +                return 0;
       +        }
       +        return -1;
       +}
   DIR diff --git a/src/libmach/mach.c b/src/libmach/mach.c
       t@@ -0,0 +1,30 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include <mach.h>
       +
       +Mach *mach;
       +
       +extern Mach mach386;
       +extern Mach machpower;
       +
       +static Mach *machs[] = 
       +{
       +        &mach386,
       +        &machpower,
       +};
       +
       +Mach*
       +machbyname(char *name)
       +{
       +        int i;
       +
       +        for(i=0; i<nelem(machs); i++)
       +                if(strcmp(machs[i]->name, name) == 0){
       +                        mach = machs[i];
       +                        return machs[i];
       +                }
       +        werrstr("machine '%s' not found", name);
       +        return nil;
       +}
       +
   DIR diff --git a/src/libmach/mach386.c b/src/libmach/mach386.c
       t@@ -0,0 +1,1786 @@
       +/*
       + * 386 definition
       + */
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include <mach.h>
       +#include "ureg386.h"
       +
       +#define        REGOFF(x)        (ulong)(&((struct Ureg *) 0)->x)
       +
       +#define        REGSIZE                sizeof(struct Ureg)
       +#define        FP_CTL(x)                (REGSIZE+4*(x))
       +#define        FP_REG(x)                (FP_CTL(7)+10*(x))
       +#define        FPREGSIZE        (6*4+8*10)
       +
       +/*
       + * i386-specific debugger interface
       + */
       +
       +static        char        *i386excep(Map*, Regs*);
       +
       +/*
       +static        int        i386trace(Map*, ulong, ulong, ulong, Tracer);
       +static        ulong        i386frame(Map*, ulong, ulong, ulong, ulong);
       +*/
       +static        int        i386foll(Map*, Regs*, ulong, ulong*);
       +static        int        i386hexinst(Map*, ulong, char*, int);
       +static        int        i386das(Map*, ulong, char, char*, int);
       +static        int        i386instlen(Map*, ulong);
       +static        char        *i386windregs[];
       +static        int        i386unwind(Map*, Regs*, ulong*);
       +
       +static        Regdesc 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",                REGOFF(pc),                RINT, 'X'},
       +        {"CS",                REGOFF(cs),        RINT, 'X'},
       +        {"EFLAGS",        REGOFF(flags),        RINT, 'X'},
       +        {"SP",                REGOFF(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(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 mach386 =
       +{
       +        "386",
       +        M386,                /* 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 */
       +        "BP",                /* name of FP */
       +        0,                /* link register */
       +        "setSB",        /* static base register name (bogus anyways) */
       +        0,                /* static base register value */
       +        0x1000,                /* page size */
       +        0x80100000,        /* kernel base */
       +        0,                /* kernel text mask */
       +        1,                /* quantization of pc */
       +        4,                /* szaddr */
       +        4,                /* szreg */
       +        4,                /* szfloat */
       +        8,                /* szdouble */
       +
       +        i386windregs,        /* locations unwound in stack trace */
       +        9,
       +
       +        {0xCC, 0, 0, 0},        /* break point: INT 3 */
       +        1,                        /* break point size */
       +
       +        i386foll,                /* following addresses */
       +        i386excep,                /* print exception */
       +        i386unwind,                /* stack unwind */
       +
       +        leswap2,                        /* convert short to local byte order */
       +        leswap4,                        /* convert long to local byte order */
       +        leswap8,                        /* convert vlong to local byte order */
       +        leieeeftoa32,                /* single precision float pointer */
       +        leieeeftoa64,                /* double precision float pointer */
       +        leieeeftoa80,                /* long double precision floating point */
       +
       +        i386das,                /* dissembler */
       +        i386das,                /* plan9-format disassembler */
       +        0,                        /* commercial disassembler */
       +        i386hexinst,                /* print instruction */
       +        i386instlen,                /* instruction size calculation */
       +};
       +
       +static char *i386windregs[] = {
       +        "PC",
       +        "SP",
       +        "BP",
       +        "AX",
       +        "CX",
       +        "DX",
       +        "BX",
       +        "SI",
       +        "DI",
       +        0,
       +};
       +
       +static int
       +i386unwind(Map *map, Regs *regs, ulong *next)
       +{
       +        int isp, ipc, ibp;
       +        ulong bp;
       +        u32int v;
       +
       +        /* No symbol information, use frame pointer and do the best we can. */
       +        isp = windindex("SP");
       +        ipc = windindex("PC");
       +        ibp = windindex("BP");
       +        if(isp < 0 || ipc < 0 || ibp < 0){
       +                werrstr("i386unwind: cannot happen");
       +                return -1;
       +        }
       +
       +        bp = next[ibp];
       +
       +        if(get4(map, bp, &v) < 0)
       +                return -1;
       +        next[ibp] = v;
       +
       +        next[isp] = bp+4;
       +
       +        if(get4(map, bp+4, &v) < 0)
       +                return -1;
       +        next[ipc] = v;
       +
       +        return 0;        
       +}
       +
       +//static        char        STARTSYM[] =        "_main";
       +//static        char        PROFSYM[] =        "_mainp";
       +static        char        FRAMENAME[] =        ".frame";
       +static char *excname[] =
       +{
       +[0]        "divide error",
       +[1]        "debug exception",
       +[4]        "overflow",
       +[5]        "bounds check",
       +[6]        "invalid opcode",
       +[7]        "math coprocessor emulation",
       +[8]        "double fault",
       +[9]        "math coprocessor overrun",
       +[10]        "invalid TSS",
       +[11]        "segment not present",
       +[12]        "stack exception",
       +[13]        "general protection violation",
       +[14]        "page fault",
       +[16]        "math coprocessor error",
       +[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",
       +};
       +
       +static char*
       +i386excep(Map *map, Regs *regs)
       +{
       +        ulong c;
       +        ulong pc;
       +        static char buf[16];
       +
       +        if(rget(regs, "TRAP", &c) < 0)
       +                return "no trap register";
       +
       +        if(c > 64 || excname[c] == 0) {
       +                if (c == 3) {
       +                        if (rget(regs, "PC", &pc) >= 0)
       +                        if (get1(map, pc, (uchar*)buf, mach->bpsize) > 0)
       +                        if (memcmp(buf, mach->bpinst, mach->bpsize) == 0)
       +                                return "breakpoint";
       +                }
       +                sprint(buf, "exception %ld", c);
       +                return buf;
       +        } else
       +                return excname[c];
       +}
       +
       +        /* 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 */
       +        ulong        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 */
       +        char        osize;                /* 'W' or 'L' */
       +        char        asize;                /* address size 'W' or 'L' */
       +        uchar        mod;                /* bits 6-7 of mod r/m field */
       +        uchar        reg;                /* bits 3-5 of mod r/m field */
       +        char        ss;                /* bits 6-7 of SIB */
       +        char        index;                /* bits 3-5 of SIB */
       +        char        base;                /* bits 0-2 of SIB */
       +        short        seg;                /* segment of far address */
       +        ulong        disp;                /* displacement */
       +        ulong         imm;                /* immediate */
       +        ulong         imm2;                /* second immediate operand */
       +        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,
       +};
       +        /* 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')
       +%X        -        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
       +%x        -        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)*/
       +        Awd,                        /* Address offset */
       +        Iwds,                        /* Operand-sized immediate (sign extended) */
       +        RM,                        /* Word or long R/M field with register (/r) */
       +        RMB,                        /* Byte R/M field with register (/r) */
       +        RMOP,                        /* Word or long R/M field with op code (/digit) */
       +        RMOPB,                        /* Byte R/M field with op code (/digit) */
       +        RMR,                        /* R/M register only (mod = 11) */
       +        RMM,                        /* R/M memory only (mod = 0/1/2) */
       +        R0,                        /* Base reg of Mod R/M is literal 0x00 */
       +        R1,                        /* Base reg of Mod R/M is literal 0x01 */
       +        FRMOP,                        /* Floating point R/M field with opcode */
       +        FRMEX,                        /* Extended floating point R/M field with opcode */
       +        JUMP,                        /* Jump or Call flag - no operand */
       +        RET,                        /* Return flag - no operand */
       +        OA,                        /* literal 0x0a byte */
       +        PTR,                        /* Seg:Displacement addr (ptr16:16 or ptr16:32) */
       +        AUX,                        /* Multi-byte op code - Auxiliary table */
       +        PRE,                        /* Instr Prefix */
       +        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 */
       +};
       +
       +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 optab0F[256]=
       +{
       +[0x00]        RMOP,0,                optab0F00,
       +[0x01]        RMOP,0,                optab0F01,
       +[0x02]        RM,0,                "LAR        %e,%r",
       +[0x03]        RM,0,                "LSL        %e,%r",
       +[0x06]        0,0,                "CLTS",
       +[0x08]        0,0,                "INVD",
       +[0x09]        0,0,                "WBINVD",
       +[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",
       +[0x30]        0,0,                "WRMSR",
       +[0x31]        0,0,                "RDTSC",
       +[0x32]        0,0,                "RDMSR",
       +[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 */
       +[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",
       +};
       +
       +static Optable optab80[8]=
       +{
       +[0x00]        Ib,0,                "ADDB        %i,%e",
       +[0x01]        Ib,0,                "ORB        %i,%e",
       +[0x02]        Ib,0,                "ADCB        %i,%e",
       +[0x03]        Ib,0,                "SBBB        %i,%e",
       +[0x04]        Ib,0,                "ANDB        %i,%e",
       +[0x05]        Ib,0,                "SUBB        %i,%e",
       +[0x06]        Ib,0,                "XORB        %i,%e",
       +[0x07]        Ib,0,                "CMPB        %e,%i",
       +};
       +
       +static Optable optab81[8]=
       +{
       +[0x00]        Iwd,0,                "ADD%S        %i,%e",
       +[0x01]        Iwd,0,                "OR%S        %i,%e",
       +[0x02]        Iwd,0,                "ADC%S        %i,%e",
       +[0x03]        Iwd,0,                "SBB%S        %i,%e",
       +[0x04]        Iwd,0,                "AND%S        %i,%e",
       +[0x05]        Iwd,0,                "SUB%S        %i,%e",
       +[0x06]        Iwd,0,                "XOR%S        %i,%e",
       +[0x07]        Iwd,0,                "CMP%S        %e,%i",
       +};
       +
       +static Optable optab83[8]=
       +{
       +[0x00]        Ibs,0,                "ADD%S        %i,%e",
       +[0x01]        Ibs,0,                "OR%S        %i,%e",
       +[0x02]        Ibs,0,                "ADC%S        %i,%e",
       +[0x03]        Ibs,0,                "SBB%S        %i,%e",
       +[0x04]        Ibs,0,                "AND%S        %i,%e",
       +[0x05]        Ibs,0,                "SUB%S        %i,%e",
       +[0x06]        Ibs,0,                "XOR%S        %i,%e",
       +[0x07]        Ibs,0,                "CMP%S        %e,%i",
       +};
       +
       +static Optable optabC0[8] =
       +{
       +[0x00]        Ib,0,                "ROLB        %i,%e",
       +[0x01]        Ib,0,                "RORB        %i,%e",
       +[0x02]        Ib,0,                "RCLB        %i,%e",
       +[0x03]        Ib,0,                "RCRB        %i,%e",
       +[0x04]        Ib,0,                "SHLB        %i,%e",
       +[0x05]        Ib,0,                "SHRB        %i,%e",
       +[0x07]        Ib,0,                "SARB        %i,%e",
       +};
       +
       +static Optable optabC1[8] =
       +{
       +[0x00]        Ib,0,                "ROL%S        %i,%e",
       +[0x01]        Ib,0,                "ROR%S        %i,%e",
       +[0x02]        Ib,0,                "RCL%S        %i,%e",
       +[0x03]        Ib,0,                "RCR%S        %i,%e",
       +[0x04]        Ib,0,                "SHL%S        %i,%e",
       +[0x05]        Ib,0,                "SHR%S        %i,%e",
       +[0x07]        Ib,0,                "SAR%S        %i,%e",
       +};
       +
       +static Optable optabD0[8] =
       +{
       +[0x00]        0,0,                "ROLB        %e",
       +[0x01]        0,0,                "RORB        %e",
       +[0x02]        0,0,                "RCLB        %e",
       +[0x03]        0,0,                "RCRB        %e",
       +[0x04]        0,0,                "SHLB        %e",
       +[0x05]        0,0,                "SHRB        %e",
       +[0x07]        0,0,                "SARB        %e",
       +};
       +
       +static Optable optabD1[8] =
       +{
       +[0x00]        0,0,                "ROL%S        %e",
       +[0x01]        0,0,                "ROR%S        %e",
       +[0x02]        0,0,                "RCL%S        %e",
       +[0x03]        0,0,                "RCR%S        %e",
       +[0x04]        0,0,                "SHL%S        %e",
       +[0x05]        0,0,                "SHR%S        %e",
       +[0x07]        0,0,                "SAR%S        %e",
       +};
       +
       +static Optable optabD2[8] =
       +{
       +[0x00]        0,0,                "ROLB        CL,%e",
       +[0x01]        0,0,                "RORB        CL,%e",
       +[0x02]        0,0,                "RCLB        CL,%e",
       +[0x03]        0,0,                "RCRB        CL,%e",
       +[0x04]        0,0,                "SHLB        CL,%e",
       +[0x05]        0,0,                "SHRB        CL,%e",
       +[0x07]        0,0,                "SARB        CL,%e",
       +};
       +
       +static Optable optabD3[8] =
       +{
       +[0x00]        0,0,                "ROL%S        CL,%e",
       +[0x01]        0,0,                "ROR%S        CL,%e",
       +[0x02]        0,0,                "RCL%S        CL,%e",
       +[0x03]        0,0,                "RCR%S        CL,%e",
       +[0x04]        0,0,                "SHL%S        CL,%e",
       +[0x05]        0,0,                "SHR%S        CL,%e",
       +[0x07]        0,0,                "SAR%S        CL,%e",
       +};
       +
       +static Optable optabD8[8+8] =
       +{
       +[0x00]        0,0,                "FADDF        %e,F0",
       +[0x01]        0,0,                "FMULF        %e,F0",
       +[0x02]        0,0,                "FCOMF        %e,F0",
       +[0x03]        0,0,                "FCOMFP        %e,F0",
       +[0x04]        0,0,                "FSUBF        %e,F0",
       +[0x05]        0,0,                "FSUBRF        %e,F0",
       +[0x06]        0,0,                "FDIVF        %e,F0",
       +[0x07]        0,0,                "FDIVRF        %e,F0",
       +[0x08]        0,0,                "FADDD        %f,F0",
       +[0x09]        0,0,                "FMULD        %f,F0",
       +[0x0a]        0,0,                "FCOMD        %f,F0",
       +[0x0b]        0,0,                "FCOMPD        %f,F0",
       +[0x0c]        0,0,                "FSUBD        %f,F0",
       +[0x0d]        0,0,                "FSUBRD        %f,F0",
       +[0x0e]        0,0,                "FDIVD        %f,F0",
       +[0x0f]        0,0,                "FDIVRD        %f,F0",
       +};
       +/*
       + *        optabD9 and optabDB use the following encoding: 
       + *        if (0 <= modrm <= 2) instruction = optabDx[modrm&0x07];
       + *        else instruction = optabDx[(modrm&0x3f)+8];
       + *
       + *        the instructions for MOD == 3, follow the 8 instructions
       + *        for the other MOD values stored at the front of the table.
       + */
       +static Optable optabD9[64+8] =
       +{
       +[0x00]        0,0,                "FMOVF        %e,F0",
       +[0x02]        0,0,                "FMOVF        F0,%e",
       +[0x03]        0,0,                "FMOVFP        F0,%e",
       +[0x04]        0,0,                "FLDENV%S %e",
       +[0x05]        0,0,                "FLDCW        %e",
       +[0x06]        0,0,                "FSTENV%S %e",
       +[0x07]        0,0,                "FSTCW        %e",
       +[0x08]        0,0,                "FMOVD        F0,F0",                /* Mod R/M = 11xx xxxx*/
       +[0x09]        0,0,                "FMOVD        F1,F0",
       +[0x0a]        0,0,                "FMOVD        F2,F0",
       +[0x0b]        0,0,                "FMOVD        F3,F0",
       +[0x0c]        0,0,                "FMOVD        F4,F0",
       +[0x0d]        0,0,                "FMOVD        F5,F0",
       +[0x0e]        0,0,                "FMOVD        F6,F0",
       +[0x0f]        0,0,                "FMOVD        F7,F0",
       +[0x10]        0,0,                "FXCHD        F0,F0",
       +[0x11]        0,0,                "FXCHD        F1,F0",
       +[0x12]        0,0,                "FXCHD        F2,F0",
       +[0x13]        0,0,                "FXCHD        F3,F0",
       +[0x14]        0,0,                "FXCHD        F4,F0",
       +[0x15]        0,0,                "FXCHD        F5,F0",
       +[0x16]        0,0,                "FXCHD        F6,F0",
       +[0x17]        0,0,                "FXCHD        F7,F0",
       +[0x18]        0,0,                "FNOP",
       +[0x28]        0,0,                "FCHS",
       +[0x29]        0,0,                "FABS",
       +[0x2c]        0,0,                "FTST",
       +[0x2d]        0,0,                "FXAM",
       +[0x30]        0,0,                "FLD1",
       +[0x31]        0,0,                "FLDL2T",
       +[0x32]        0,0,                "FLDL2E",
       +[0x33]        0,0,                "FLDPI",
       +[0x34]        0,0,                "FLDLG2",
       +[0x35]        0,0,                "FLDLN2",
       +[0x36]        0,0,                "FLDZ",
       +[0x38]        0,0,                "F2XM1",
       +[0x39]        0,0,                "FYL2X",
       +[0x3a]        0,0,                "FPTAN",
       +[0x3b]        0,0,                "FPATAN",
       +[0x3c]        0,0,                "FXTRACT",
       +[0x3d]        0,0,                "FPREM1",
       +[0x3e]        0,0,                "FDECSTP",
       +[0x3f]        0,0,                "FNCSTP",
       +[0x40]        0,0,                "FPREM",
       +[0x41]        0,0,                "FYL2XP1",
       +[0x42]        0,0,                "FSQRT",
       +[0x43]        0,0,                "FSINCOS",
       +[0x44]        0,0,                "FRNDINT",
       +[0x45]        0,0,                "FSCALE",
       +[0x46]        0,0,                "FSIN",
       +[0x47]        0,0,                "FCOS",
       +};
       +
       +static Optable optabDA[8+8] =
       +{
       +[0x00]        0,0,                "FADDL        %e,F0",
       +[0x01]        0,0,                "FMULL        %e,F0",
       +[0x02]        0,0,                "FCOML        %e,F0",
       +[0x03]        0,0,                "FCOMLP        %e,F0",
       +[0x04]        0,0,                "FSUBL        %e,F0",
       +[0x05]        0,0,                "FSUBRL        %e,F0",
       +[0x06]        0,0,                "FDIVL        %e,F0",
       +[0x07]        0,0,                "FDIVRL        %e,F0",
       +[0x0d]        R1,0,                "FUCOMPP",
       +};
       +
       +static Optable optabDB[8+64] =
       +{
       +[0x00]        0,0,                "FMOVL        %e,F0",
       +[0x02]        0,0,                "FMOVL        F0,%e",
       +[0x03]        0,0,                "FMOVLP        F0,%e",
       +[0x05]        0,0,                "FMOVX        %e,F0",
       +[0x07]        0,0,                "FMOVXP        F0,%e",
       +[0x2a]        0,0,                "FCLEX",
       +[0x2b]        0,0,                "FINIT",
       +};
       +
       +static Optable optabDC[8+8] =
       +{
       +[0x00]        0,0,                "FADDD        %e,F0",
       +[0x01]        0,0,                "FMULD        %e,F0",
       +[0x02]        0,0,                "FCOMD        %e,F0",
       +[0x03]        0,0,                "FCOMDP        %e,F0",
       +[0x04]        0,0,                "FSUBD        %e,F0",
       +[0x05]        0,0,                "FSUBRD        %e,F0",
       +[0x06]        0,0,                "FDIVD        %e,F0",
       +[0x07]        0,0,                "FDIVRD        %e,F0",
       +[0x08]        0,0,                "FADDD        F0,%f",
       +[0x09]        0,0,                "FMULD        F0,%f",
       +[0x0c]        0,0,                "FSUBRD        F0,%f",
       +[0x0d]        0,0,                "FSUBD        F0,%f",
       +[0x0e]        0,0,                "FDIVRD        F0,%f",
       +[0x0f]        0,0,                "FDIVD        F0,%f",
       +};
       +
       +static Optable optabDD[8+8] =
       +{
       +[0x00]        0,0,                "FMOVD        %e,F0",
       +[0x02]        0,0,                "FMOVD        F0,%e",
       +[0x03]        0,0,                "FMOVDP        F0,%e",
       +[0x04]        0,0,                "FRSTOR%S %e",
       +[0x06]        0,0,                "FSAVE%S %e",
       +[0x07]        0,0,                "FSTSW        %e",
       +[0x08]        0,0,                "FFREED        %f",
       +[0x0a]        0,0,                "FMOVD        %f,F0",
       +[0x0b]        0,0,                "FMOVDP        %f,F0",
       +[0x0c]        0,0,                "FUCOMD        %f,F0",
       +[0x0d]        0,0,                "FUCOMDP %f,F0",
       +};
       +
       +static Optable optabDE[8+8] =
       +{
       +[0x00]        0,0,                "FADDW        %e,F0",
       +[0x01]        0,0,                "FMULW        %e,F0",
       +[0x02]        0,0,                "FCOMW        %e,F0",
       +[0x03]        0,0,                "FCOMWP        %e,F0",
       +[0x04]        0,0,                "FSUBW        %e,F0",
       +[0x05]        0,0,                "FSUBRW        %e,F0",
       +[0x06]        0,0,                "FDIVW        %e,F0",
       +[0x07]        0,0,                "FDIVRW        %e,F0",
       +[0x08]        0,0,                "FADDDP        F0,%f",
       +[0x09]        0,0,                "FMULDP        F0,%f",
       +[0x0b]        R1,0,                "FCOMPDP",
       +[0x0c]        0,0,                "FSUBRDP F0,%f",
       +[0x0d]        0,0,                "FSUBDP        F0,%f",
       +[0x0e]        0,0,                "FDIVRDP F0,%f",
       +[0x0f]        0,0,                "FDIVDP        F0,%f",
       +};
       +
       +static Optable optabDF[8+8] =
       +{
       +[0x00]        0,0,                "FMOVW        %e,F0",
       +[0x02]        0,0,                "FMOVW        F0,%e",
       +[0x03]        0,0,                "FMOVWP        F0,%e",
       +[0x04]        0,0,                "FBLD        %e",
       +[0x05]        0,0,                "FMOVL        %e,F0",
       +[0x06]        0,0,                "FBSTP        %e",
       +[0x07]        0,0,                "FMOVLP        F0,%e",
       +[0x0c]        R0,0,                "FSTSW        %OAX",
       +};
       +
       +static Optable optabF6[8] =
       +{
       +[0x00]        Ib,0,                "TESTB        %i,%e",
       +[0x02]        0,0,                "NOTB        %e",
       +[0x03]        0,0,                "NEGB        %e",
       +[0x04]        0,0,                "MULB        AL,%e",
       +[0x05]        0,0,                "IMULB        AL,%e",
       +[0x06]        0,0,                "DIVB        AL,%e",
       +[0x07]        0,0,                "IDIVB        AL,%e",
       +};
       +
       +static Optable optabF7[8] =
       +{
       +[0x00]        Iwd,0,                "TEST%S        %i,%e",
       +[0x02]        0,0,                "NOT%S        %e",
       +[0x03]        0,0,                "NEG%S        %e",
       +[0x04]        0,0,                "MUL%S        %OAX,%e",
       +[0x05]        0,0,                "IMUL%S        %OAX,%e",
       +[0x06]        0,0,                "DIV%S        %OAX,%e",
       +[0x07]        0,0,                "IDIV%S        %OAX,%e",
       +};
       +
       +static Optable optabFE[8] =
       +{
       +[0x00]        0,0,                "INCB        %e",
       +[0x01]        0,0,                "DECB        %e",
       +};
       +
       +static Optable optabFF[8] =
       +{
       +[0x00]        0,0,                "INC%S        %e",
       +[0x01]        0,0,                "DEC%S        %e",
       +[0x02]        JUMP,0,                "CALL*        %e",
       +[0x03]        JUMP,0,                "CALLF*        %e",
       +[0x04]        JUMP,0,                "JMP*        %e",
       +[0x05]        JUMP,0,                "JMPF*        %e",
       +[0x06]        0,0,                "PUSHL        %e",
       +};
       +
       +static Optable optable[256] =
       +{
       +[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]        AUX,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        %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,                "%X",                        /* miserable CBW or CWDE */
       +[0x99]        0,0,                "%x",                        /* 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]        Iwd,0,                "MOV%S        %i,%OAX",
       +[0xb9]        Iwd,0,                "MOV%S        %i,%OCX",
       +[0xba]        Iwd,0,                "MOV%S        %i,%ODX",
       +[0xbb]        Iwd,0,                "MOV%S        %i,%OBX",
       +[0xbc]        Iwd,0,                "MOV%S        %i,%OSP",
       +[0xbd]        Iwd,0,                "MOV%S        %i,%OBP",
       +[0xbe]        Iwd,0,                "MOV%S        %i,%OSI",
       +[0xbf]        Iwd,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]        PRE,0,                "REPNE",
       +[0xf3]        PRE,0,                "REP",
       +[0xf4]        0,0,                "HALT",
       +[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,
       +};
       +
       +/*
       + *  get a byte of the instruction
       + */
       +static int
       +igetc(Map * map, Instr *ip, uchar *c)
       +{
       +        if(ip->n+1 > sizeof(ip->mem)){
       +                werrstr("instruction too long");
       +                return -1;
       +        }
       +        if (get1(map, ip->addr+ip->n, c, 1) < 0) {
       +                werrstr("can't read instruction: %r");
       +                return -1;
       +        }
       +        ip->mem[ip->n++] = *c;
       +        return 1;
       +}
       +
       +/*
       + *  get two bytes of the instruction
       + */
       +static int
       +igets(Map *map, Instr *ip, ushort *sp)
       +{
       +        uchar        c;
       +        ushort s;
       +
       +        if (igetc(map, ip, &c) < 0)
       +                return -1;
       +        s = c;
       +        if (igetc(map, ip, &c) < 0)
       +                return -1;
       +        s |= (c<<8);
       +        *sp = s;
       +        return 1;
       +}
       +
       +/*
       + *  get 4 bytes of the instruction
       + */
       +static int
       +igetl(Map *map, Instr *ip, ulong *lp)
       +{
       +        ushort s;
       +        long        l;
       +
       +        if (igets(map, ip, &s) < 0)
       +                return -1;
       +        l = s;
       +        if (igets(map, ip, &s) < 0)
       +                return -1;
       +        l |= (s<<16);
       +        *lp = l;
       +        return 1;
       +}
       +
       +static int
       +getdisp(Map *map, Instr *ip, int mod, int rm, int code)
       +{
       +        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;
       +                } 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;
       +        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);
       +        }
       +        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);
       +        }
       +        return getdisp(map, ip, mod, rm, 5);
       +}
       +
       +static Optable *
       +mkinstr(Map *map, Instr *ip, ulong pc)
       +{
       +        int i, n;
       +        uchar c;
       +        ushort s;
       +        Optable *op, *obase;
       +        char buf[128];
       +
       +        memset(ip, 0, sizeof(*ip));
       +        ip->base = -1;
       +        ip->index = -1;
       +        if(0) /* asstype == AI8086) */
       +                ip->osize = 'W';
       +        else {
       +                ip->osize = 'L';
       +                ip->asize = 'E';
       +        }
       +        ip->addr = pc;
       +        if (igetc(map, ip, &c) < 0)
       +                return 0;
       +        obase = optable;
       +newop:
       +        op = &obase[c];
       +        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;
       +                        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->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;
       +                        break;
       +                case Iw:        /* 16-bit immediate -> imm */
       +                        if (igets(map, ip, &s) < 0)
       +                                return 0;
       +                        ip->imm = s&0xffff;
       +                        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)*/
       +                        if (ip->osize == 'L') {
       +                                if (igetl(map, ip, &ip->imm) < 0)
       +                                        return 0;
       +                        } 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;
       +                        } else {
       +                                if (igets(map, ip, &s)< 0)
       +                                        return 0;
       +                                ip->imm = s&0xffff;
       +                        }
       +                        break;
       +                case Iwds:        /* Operand-sized immediate (sign extended) */
       +                        if (ip->osize == 'L') {
       +                                if (igetl(map, ip, &ip->imm) < 0)
       +                                        return 0;
       +                        } else {
       +                                if (igets(map, ip, &s)< 0)
       +                                        return 0;
       +                                if (s&0x8000)
       +                                        ip->imm = s|0xffff0000;
       +                                else
       +                                        ip->imm = s&0xffff;
       +                        }
       +                        ip->jumptype = Iwds;
       +                        break;
       +                case OA:        /* literal 0x0a byte */
       +                        if (igetc(map, ip, &c) < 0)
       +                                return 0;
       +                        if (c != 0x0a)
       +                                goto badop;
       +                        break;
       +                case R0:        /* base register must be R0 */
       +                        if (ip->base != 0)
       +                                goto badop;
       +                        break;
       +                case R1:        /* base register must be R1 */
       +                        if (ip->base != 1)
       +                                goto badop;
       +                        break;
       +                case RMB:        /* R/M field with byte register (/r)*/
       +                        if (igetc(map, ip, &c) < 0)
       +                                return 0;
       +                        if (modrm(map, ip, c) < 0)
       +                                return 0;
       +                        ip->osize = 'B';
       +                        break;
       +                case RM:        /* R/M field with register (/r) */
       +                        if (igetc(map, ip, &c) < 0)
       +                                return 0;
       +                        if (modrm(map, ip, c) < 0)
       +                                return 0;
       +                        break;
       +                case RMOPB:        /* R/M field with op code (/digit) */
       +                        if (igetc(map, ip, &c) < 0)
       +                                return 0;
       +                        if (modrm(map, ip, c) < 0)
       +                                return 0;
       +                        c = ip->reg;                /* secondary op code */
       +                        obase = (Optable*)op->proto;
       +                        ip->osize = 'B';
       +                        goto newop;
       +                case RMOP:        /* R/M field with op code (/digit) */
       +                        if (igetc(map, ip, &c) < 0)
       +                                return 0;
       +                        if (modrm(map, ip, c) < 0)
       +                                return 0;
       +                        c = ip->reg;
       +                        obase = (Optable*)op->proto;
       +                        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 AUX:        /* Multi-byte op code - Auxiliary table */
       +                        obase = (Optable*)op->proto;
       +                        if (igetc(map, ip, &c) < 0)
       +                                return 0;
       +                        goto newop;
       +                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->osize = 'W';
       +                        if (igetc(map, ip, &c) < 0)
       +                                return 0;
       +                        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;
       +}
       +
       +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",
       +};
       +
       +static char *breg[] = { "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH" };
       +static char *sreg[] = { "ES", "CS", "SS", "DS", "FS", "GS" };
       +
       +static void
       +plocal(Instr *ip)
       +{
       +        Symbol s;
       +        char *name;
       +        Loc l, li;
       +
       +        l.type = LOFFSET;
       +        l.offset = ip->disp;
       +        if(ip->base == SP)
       +                l.reg = "SP";
       +        else
       +                l.reg = "BP";
       +
       +        li.type = LADDR;
       +        li.addr = ip->addr;
       +        if(findsym(li, CTEXT, &s) < 0)
       +                goto raw;
       +
       +        name = nil;
       +        if(ip->base==SP && lookuplsym(&s, FRAMENAME, &s) >= 0){
       +                /* translate stack offset to offset from plan 9 frame pointer */
       +                /* XXX not sure how to do this */
       +        }
       +
       +        if(name==nil && findlsym(&s, l, &s) >= 0)
       +                name = s.name;
       +
       +        if(name)
       +                bprint(ip, "%s+", name);
       +
       +raw:
       +        bprint(ip, "%lx(%s)", l.offset, l.reg);
       +}
       +
       +static int
       +isjmp(Instr *ip)
       +{
       +        switch(ip->jumptype){
       +        case Iwds:
       +        case Jbs:
       +        case JUMP:
       +                return 1;
       +        default:
       +                return 0;
       +        }
       +}
       +
       +/*
       + * This is too smart for its own good, but it really is nice
       + * to have accurate translations when debugging, and it
       + * helps us identify which code is different in binaries that
       + * are changed on sources.
       + */
       +static int
       +issymref(Instr *ip, Symbol *s, long w, long val)
       +{
       +        Symbol next, tmp;
       +        long isstring, size;
       +
       +        if (isjmp(ip))
       +                return 1;
       +        if (s->class==CTEXT && w==0)
       +                return 1;
       +        if (s->class==CDATA) {
       +                /* use first bss symbol (or "end") rather than edata */
       +                if (s->name[0]=='e' && strcmp(s->name, "edata") == 0){
       +                        if((indexsym(s->index+1, &tmp) && loccmp(&tmp.loc, &s->loc)==0)
       +                        || (indexsym(s->index-1, &tmp) && loccmp(&tmp.loc, &s->loc)==0))
       +                                *s = tmp;
       +                }
       +                if (w == 0)
       +                        return 1;
       +                for (next=*s; next.loc.addr==s->loc.addr; next=tmp)
       +                        if (!indexsym(next.index+1, &tmp))
       +                                break;
       +                size = next.loc.addr - s->loc.addr;
       +                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, long val)
       +{
       +        Symbol s;
       +        long w;
       +        Loc l;
       +
       +        l.type = LADDR;
       +        l.addr = val;
       +        if (findsym(l, CANY, &s) >= 0) {
       +                w = val - s.loc.addr;
       +                if (w < 0)
       +                        w = -w;
       +                if (issymref(ip, &s, w, val)) {
       +                        if (w)
       +                                bprint(ip, "%s+%lux(SB)", s.name, w);
       +                        else
       +                                bprint(ip, "%s(SB)", s.name);
       +                        return;
       +                }
       +                if (s.class==CDATA && indexsym(s.index+1, &s) >= 0) {
       +                        w = s.loc.addr - val;
       +                        if (w < 0)
       +                                w = -w;
       +                        if (w < 4096) {
       +                                bprint(ip, "%s-%lux(SB)", s.name, w);
       +                                return;
       +                        }
       +                }
       +        }
       +        bprint(ip, "%lux", val);
       +}
       +
       +static void
       +pea(Instr *ip)
       +{
       +        if (ip->mod == 3) {
       +                if (ip->osize == 'B')
       +                        bprint(ip, breg[(uchar)ip->base]);
       +                else
       +                        bprint(ip, "%s%s", ANAME(ip), reg[(uchar)ip->base]);
       +                return;
       +        }
       +        if (ip->segment)
       +                bprint(ip, ip->segment);
       +        if (ip->asize == 'E' && (ip->base == SP || ip->base == BP))
       +                plocal(ip);
       +        else {
       +                if (ip->base < 0)
       +                        immediate(ip, ip->disp);
       +                else
       +                        bprint(ip,"(%s%s)", ANAME(ip), reg[(uchar)ip->base]);
       +        }
       +        if (ip->index >= 0)
       +                bprint(ip,"(%s%s*%d)", ANAME(ip), reg[(uchar)ip->index], 1<<ip->ss);
       +}
       +
       +static void
       +prinstr(Instr *ip, char *fmt)
       +{
       +        if (ip->prefix)
       +                bprint(ip, "%s ", ip->prefix);
       +        for (; *fmt && ip->curr < ip->end; fmt++) {
       +                if (*fmt != '%')
       +                        *ip->curr++ = *fmt;
       +                else switch(*++fmt)
       +                {
       +                case '%':
       +                        *ip->curr++ = '%';
       +                        break;
       +                case 'A':
       +                        bprint(ip, "%s", ANAME(ip));
       +                        break;
       +                case 'C':
       +                        bprint(ip, "CR%d", ip->reg);
       +                        break;
       +                case 'D':
       +                        if (ip->reg < 4 || ip->reg == 6 || ip->reg == 7)
       +                                bprint(ip, "DR%d",ip->reg);
       +                        else
       +                                bprint(ip, "???");
       +                        break;
       +                case 'I':
       +                        bprint(ip, "$");
       +                        immediate(ip, ip->imm2);
       +                        break;
       +                case 'O':
       +                        bprint(ip,"%s", ONAME(ip));
       +                        break;
       +                case 'i':
       +                        bprint(ip, "$");
       +                        immediate(ip,ip->imm);
       +                        break;
       +                case 'R':
       +                        bprint(ip, "%s%s", ONAME(ip), reg[ip->reg]);
       +                        break;
       +                case 'S':
       +                        bprint(ip, "%c", ip->osize);
       +                        break;
       +                case 'T':
       +                        if (ip->reg == 6 || ip->reg == 7)
       +                                bprint(ip, "TR%d",ip->reg);
       +                        else
       +                                bprint(ip, "???");
       +                        break;
       +                case 'X':
       +                        if (ip->osize == 'L')
       +                                bprint(ip,"CWDE");
       +                        else
       +                                bprint(ip, "CBW");
       +                        break;
       +                case 'd':
       +                        bprint(ip,"%lux:%lux",ip->seg,ip->disp);
       +                        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':
       +                        immediate(ip, ip->imm+ip->addr+ip->n);
       +                        break;
       +                case 'r':
       +                        if (ip->osize == 'B')
       +                                bprint(ip,"%s",breg[ip->reg]);
       +                        else
       +                                bprint(ip, reg[ip->reg]);
       +                        break;
       +                case 'x':
       +                        if (ip->osize == 'L')
       +                                bprint(ip,"CDQ");
       +                        else
       +                                bprint(ip, "CWD");
       +                        break;
       +                default:
       +                        bprint(ip, "%%%c", *fmt);
       +                        break;
       +                }
       +        }
       +        *ip->curr = 0;                /* there's always room for 1 byte */
       +}
       +
       +static int
       +i386das(Map *map, ulong 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
       +i386hexinst(Map *map, ulong 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, ulong pc)
       +{
       +        Instr i;
       +
       +        if (mkinstr(map, &i, pc))
       +                return i.n;
       +        return -1;
       +}
       +
       +static int
       +i386foll(Map *map, Regs *regs, ulong pc, ulong *foll)
       +{
       +        Instr i;
       +        Optable *op;
       +        ushort s;
       +        ulong addr;
       +        u32int l;
       +        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 (lget4(map, regs, locindir("BP", 0), &l) < 0)
       +                                return -1;
       +                } else if (lget4(map, regs, locindir(mach->sp, 0), &l) < 0)
       +                        return -1;
       +                foll[0] = l;
       +                return 1;
       +        case Iwds:                /* pc relative JUMP or CALL*/
       +        case Jbs:                /* pc relative JUMP or CALL */
       +                foll[0] = pc+i.imm+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) {
       +                        if (rget(regs, reg[(uchar)i.base], &foll[0]) < 0)
       +                                return -1;
       +                        return 1;
       +                }
       +                        /* calculate the effective address */
       +                addr = i.disp;
       +                if (i.base >= 0) {
       +                        if (lget4(map, regs, locindir(reg[(uchar)i.base], 0), &l) < 0)
       +                                return -1;
       +                        addr += l;
       +                }
       +                if (i.index >= 0) {
       +                        if (lget4(map, regs, locindir(reg[(uchar)i.index], 0), &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 (get4(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;
       +}
   DIR diff --git a/src/libmach/macho.c b/src/libmach/macho.c
       t@@ -0,0 +1,128 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <mach.h>
       +#include "macho.h"
       +
       +/*
       +http://www.channelu.com/NeXT/NeXTStep/3.3/nd/DevTools/14_MachO/MachO.htmld/
       +*/
       +
       +Macho*
       +machoopen(char *name)
       +{
       +        int fd;
       +        Macho *m;
       +
       +        if((fd = open(name, OREAD)) < 0)
       +                return nil;
       +        m = machoinit(fd);
       +        if(m == nil)
       +                close(fd);
       +        return m;
       +}
       +
       +static int
       +unpackseg(uchar *p, Macho *m, MachoCmd *c, uint type, uint sz)
       +{
       +        u32int (*e4)(uchar*);
       +
       +        e4 = m->e4;
       +
       +        c->type = type;
       +        c->size = sz;
       +        switch(type){
       +        default:
       +                return -1;
       +        case MachoCmdSegment:
       +                if(sz < 56)
       +                        return -1;
       +                strecpy(c->seg.name, c->seg.name+sizeof c->seg.name, (char*)p+8);
       +                c->seg.vmaddr = e4(p+24);
       +                c->seg.vmsize = e4(p+28);
       +                c->seg.fileoff = e4(p+32);
       +                c->seg.filesz = e4(p+36);
       +                c->seg.maxprot = e4(p+40);
       +                c->seg.initprot = e4(p+44);
       +                c->seg.nsect = e4(p+48);
       +                c->seg.flags = e4(p+52);
       +                break;
       +        case MachoCmdSymtab:
       +                if(sz < 24)
       +                        return -1;
       +                c->sym.symoff = e4(p+8);
       +                c->sym.nsyms = e4(p+12);
       +                c->sym.stroff = e4(p+16);
       +                c->sym.strsize = e4(p+20);
       +                break;
       +        }
       +        return 0;
       +}
       +
       +
       +Macho*
       +machoinit(int fd)
       +{
       +        int i;
       +        uchar hdr[7*4], *cmdp;
       +        u32int (*e4)(uchar*);
       +        ulong ncmd, cmdsz, ty, sz, off;
       +        Macho *m;
       +
       +        if(seek(fd, 0, 0) < 0 || readn(fd, hdr, sizeof hdr) != sizeof hdr)
       +                return nil;
       +
       +        if(beload4(hdr) == 0xFEEDFACE)
       +                e4 = beload4;
       +        else if(leload4(hdr) == 0xFEEDFACE)
       +                e4 = leload4;
       +        else{
       +                werrstr("bad magic - not mach-o file");
       +                return nil;
       +        }
       +
       +        ncmd = e4(hdr+4*4);
       +        cmdsz = e4(hdr+5*4);
       +        if(ncmd > 0x10000 || cmdsz >= 0x01000000){
       +                werrstr("implausible mach-o header ncmd=%lud cmdsz=%lud", ncmd, cmdsz);
       +                return nil;
       +        }
       +
       +        m = mallocz(sizeof(*m)+ncmd*sizeof(MachoCmd)+cmdsz, 1);
       +        if(m == nil)
       +                return nil;
       +
       +        m->fd = fd;
       +        m->e4 = e4;
       +        m->cputype = e4(hdr+1*4);
       +        m->subcputype = e4(hdr+2*4);
       +        m->filetype = e4(hdr+3*4);
       +        m->ncmd = ncmd;
       +        m->flags = e4(hdr+6*4);
       +
       +        m->cmd = (MachoCmd*)(m+1);
       +        off = sizeof hdr;
       +        cmdp = (uchar*)(m->cmd+ncmd);
       +        if(readn(fd, cmdp, cmdsz) != cmdsz){
       +                werrstr("reading cmds: %r");
       +                free(m);
       +                return nil;
       +        }
       +
       +        for(i=0; i<ncmd; i++){
       +                ty = e4(cmdp);
       +                sz = e4(cmdp+4);
       +                m->cmd[i].off = off;
       +                unpackseg(cmdp, m, &m->cmd[i], ty, sz);
       +                cmdp += sz;
       +                off += sz;
       +        }
       +
       +        return m;
       +}
       +
       +void
       +machoclose(Macho *m)
       +{
       +        close(m->fd);
       +        free(m);
       +}
   DIR diff --git a/src/libmach/macho.h b/src/libmach/macho.h
       t@@ -0,0 +1,71 @@
       +typedef struct Macho Macho;
       +typedef struct MachoCmd MachoCmd;
       +
       +enum
       +{
       +        MachoCpuVax = 1,
       +        MachoCpu68000 = 6,
       +        MachoCpu386 = 7,
       +        MachoCpuMips = 8,
       +        MachoCpu98000 = 10,
       +        MachoCpuHppa = 11,
       +        MachoCpuArm = 12,
       +        MachoCpu88000 = 13,
       +        MachoCpuSparc = 14,
       +        MachoCpu860 = 15,
       +        MachoCpuAlpha = 16,
       +        MachoCpuPower = 18,
       +
       +        MachoCmdSegment = 1,
       +        MachoCmdSymtab = 2,
       +        MachoCmdSymseg = 3,
       +        MachoCmdThread = 4,
       +
       +        MachoFileObject = 1,
       +        MachoFileExecutable = 2,
       +        MachoFileFvmlib = 3,
       +        MachoFileCore = 4,
       +        MachoFilePreload = 5,
       +};
       +
       +struct MachoCmd
       +{
       +        int type;
       +        ulong off;
       +        ulong size;
       +        struct {
       +                char name[16+1];
       +                ulong vmaddr;
       +                ulong vmsize;
       +                ulong fileoff;
       +                ulong filesz;
       +                ulong maxprot;
       +                ulong initprot;
       +                ulong nsect;
       +                ulong flags;
       +        } seg;
       +        struct {
       +                ulong symoff;
       +                ulong nsyms;
       +                ulong stroff;
       +                ulong strsize;
       +        } sym;
       +};
       +
       +struct Macho
       +{
       +        int fd;
       +        uint cputype;
       +        uint subcputype;
       +        ulong filetype;
       +        ulong flags;
       +        MachoCmd *cmd;
       +        uint ncmd;
       +        u32int (*e4)(uchar*);
       +        int (*coreregs)(Macho*, uchar**);
       +};
       +
       +Macho *machoopen(char*);
       +Macho *machoinit(int);
       +void machoclose(Macho*);
       +int coreregsmachopower(Macho*, uchar**);
   DIR diff --git a/src/libmach/machocorepower.c b/src/libmach/machocorepower.c
       t@@ -0,0 +1,173 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <mach.h>
       +#include "macho.h"
       +#include "uregpower.h"
       +
       +enum
       +{
       +        ThreadState = 1,
       +        FloatState,
       +        ExceptionState,
       +        VectorState,
       +        ThreadState64,
       +        ExceptionState64,
       +        ThreadStateNone,
       +};
       +
       +typedef struct Lreg Lreg;
       +typedef struct Lflt Lflt;
       +typedef struct Lexc Lexc;
       +
       +struct Lreg
       +{
       +        u32int srr0;
       +        u32int srr1;
       +        u32int r0;
       +        u32int r1;
       +        u32int r2;
       +        u32int r3;
       +        u32int r4;
       +        u32int r5;
       +        u32int r6;
       +        u32int r7;
       +        u32int r8;
       +        u32int r9;
       +        u32int r10;
       +        u32int r11;
       +        u32int r12;
       +        u32int r13;
       +        u32int r14;
       +        u32int r15;
       +        u32int r16;
       +        u32int r17;
       +        u32int r18;
       +        u32int r19;
       +        u32int r20;
       +        u32int r21;
       +        u32int r22;
       +        u32int r23;
       +        u32int r24;
       +        u32int r25;
       +        u32int r26;
       +        u32int r27;
       +        u32int r28;
       +        u32int r29;
       +        u32int r30;
       +        u32int r31;
       +
       +        u32int cr;
       +        u32int xer;
       +        u32int lr;
       +        u32int ctr;
       +        u32int mq;
       +
       +        u32int vrsave;
       +};
       +
       +struct Lflt
       +{
       +        u32int fpregs[32*2];                /* 32 doubles */
       +        u32int fpscr[2];
       +
       +};
       +
       +struct Lexc
       +{
       +        u32int dar;
       +        u32int dsisr;
       +        u32int exception;
       +        u32int pad0;
       +        u32int pad1[4];
       +};
       +
       +static void
       +lreg2ureg(Lreg *l, Ureg *u)
       +{
       +        u->pc = l->srr0;
       +        u->srr1 = l->srr1;
       +        u->lr = l->lr;
       +        u->cr = l->cr;
       +        u->xer = l->xer;
       +        u->ctr = l->ctr;
       +        u->vrsave = l->vrsave;
       +        memmove(&u->r0, &l->r0, 32*4);
       +}
       +
       +static void
       +lexc2ureg(Lexc *l, Ureg *u)
       +{
       +        u->cause = l->exception;
       +        u->dar = l->dar;
       +        u->dsisr = l->dsisr;
       +}
       +
       +static uchar*
       +load(int fd, ulong off, int size)
       +{
       +        uchar *a;
       +
       +        a = malloc(size);
       +        if(a == nil)
       +                return nil;
       +        if(seek(fd, off, 0) < 0 || readn(fd, a, size) != size){
       +                free(a);
       +                return nil;
       +        }
       +        return a;
       +}
       +
       +int
       +coreregsmachopower(Macho *m, uchar **up)
       +{
       +        int i, havereg, haveexc;
       +        uchar *a, *p, *nextp;
       +        Ureg *u;
       +        ulong flavor, count;
       +        MachoCmd *c;
       +
       +        *up = nil;
       +        for(i=0; i<m->ncmd; i++)
       +                if(m->cmd[i].type == MachoCmdThread)
       +                        break;
       +        if(i == m->ncmd){
       +                werrstr("no registers found");
       +                return -1;
       +        }
       +
       +        c = &m->cmd[i];
       +        a = load(m->fd, c->off, c->size);
       +        if(a == nil)
       +                return -1;
       +
       +        if((u = mallocz(sizeof(Ureg), 1)) == nil){
       +                free(a);
       +                return -1;
       +        }
       +
       +        havereg = haveexc = 0;
       +        for(p=a+8; p<a+c->size; p=nextp){
       +                flavor = m->e4(p);
       +                count = m->e4(p+4);
       +                nextp = p+8+count*4;
       +                if(flavor == ThreadState && count*4 == sizeof(Lreg)){
       +                        havereg = 1;
       +                        lreg2ureg((Lreg*)(p+8), u);
       +                }
       +                if(flavor == ExceptionState && count*4 == sizeof(Lexc)){
       +                        haveexc = 1;
       +                        lexc2ureg((Lexc*)(p+8), u);
       +                }
       +        }
       +        free(a);
       +        if(!havereg){
       +                werrstr("no registers found");
       +                free(u);
       +                return -1;
       +        }
       +        if(!haveexc)
       +                fprint(2, "warning: no exception state in core file registers\n");
       +        *up = (uchar*)u;
       +        return sizeof(*u);
       +}
       +
   DIR diff --git a/src/libmach/machodump.c b/src/libmach/machodump.c
       t@@ -0,0 +1,93 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <mach.h>
       +#include "stabs.h"
       +#include "macho.h"
       +
       +void
       +usage(void)
       +{
       +        fprint(2, "usage: machodump file list\n");
       +        fprint(2, "        machodump file stabs\n");
       +        exits("usage");
       +}
       +
       +uchar*
       +load(int fd, ulong off, int size)
       +{
       +        uchar *a;
       +
       +        a = malloc(size);
       +print("malloc %d -> %p\n", size, a);
       +        if(a == nil)
       +                sysfatal("malloc: %r");
       +        if(seek(fd, off, 0) < 0)
       +                sysfatal("seek %lud: %r", off);
       +        if(readn(fd, a, size) != size)
       +                sysfatal("readn: %r");
       +        return a;
       +}
       +
       +void
       +main(int argc, char **argv)
       +{
       +        int i;
       +        Macho *m;
       +
       +        ARGBEGIN{
       +        default:
       +                usage();
       +        }ARGEND
       +
       +        if(argc < 2)
       +                usage();
       +
       +        if((m = machoopen(argv[0])) == nil)
       +                sysfatal("machoopen %s: %r", argv[0]);
       +
       +        if(strcmp(argv[1], "stabs") == 0){
       +                Stab stabs;
       +                StabSym sym;
       +
       +                for(i=0; i<m->ncmd; i++){
       +                        if(m->cmd[i].type == MachoCmdSymtab){
       +                                stabs.stabbase = load(m->fd, m->cmd[i].sym.symoff, m->cmd[i].sym.nsyms*16);
       +                                stabs.stabsize = m->cmd[i].sym.nsyms*16;
       +                                stabs.strbase = load(m->fd, m->cmd[i].sym.stroff, m->cmd[i].sym.strsize);
       +                                stabs.strsize = m->cmd[i].sym.strsize;
       +                                stabs.e4 = m->e4;
       +                                stabs.e2 = (m->e4 == beload4 ? beload2 : leload2);
       +                                print("cmd%d: %p %ud %p %ud\n", i, stabs.stabbase, stabs.stabsize, stabs.strbase, stabs.strsize);
       +                                for(i=0; stabsym(&stabs, i, &sym) >= 0; i++)
       +                                        print("%s type 0x%x other %d desc %d value 0x%lux\n",
       +                                                sym.name, sym.type, sym.other, (int)sym.desc, (ulong)sym.value);
       +                                print("err at %d: %r\n", i);
       +                        }
       +                }
       +        }
       +        else if(strcmp(argv[1], "list") == 0){
       +                print("macho cpu %ud sub %ud filetype %lud flags %lud\n",
       +                        m->cputype, m->subcputype, m->filetype, m->flags);
       +                for(i=0; i<m->ncmd; i++){
       +                        switch(m->cmd[i].type){
       +                        case MachoCmdSymtab:
       +                                print("cmd%d: symtab %lud+%lud %lud+%lud\n", i,
       +                                        m->cmd[i].sym.symoff, m->cmd[i].sym.nsyms,
       +                                        m->cmd[i].sym.stroff, m->cmd[i].sym.strsize);
       +                                break;
       +                        case MachoCmdSegment:
       +                                print("cmd%d: segment %s vm 0x%lux+0x%lux file 0x%lux+0x%lux prot 0x%lux/0x%lux ns %d flags 0x%lux\n", i,
       +                                        m->cmd[i].seg.name, m->cmd[i].seg.vmaddr, m->cmd[i].seg.vmsize,
       +                                        m->cmd[i].seg.fileoff, m->cmd[i].seg.filesz, m->cmd[i].seg.maxprot,
       +                                        m->cmd[i].seg.initprot, m->cmd[i].seg.nsect, m->cmd[i].seg.flags);
       +                                break;
       +                        default:
       +                                print("cmd%d: type %d offset %lud\n", i, m->cmd[i].type, m->cmd[i].off);
       +                                break;
       +                        }
       +                }
       +        }
       +        else
       +                usage();
       +        exits(0);
       +}
   DIR diff --git a/src/libmach/machpower.c b/src/libmach/machpower.c
       t@@ -0,0 +1,1409 @@
       +/*
       + * PowerPC definition
       + *        forsyth@plan9.cs.york.ac.uk
       + */
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include "uregpower.h"
       +#include <mach.h>
       +
       +/*
       + * PowerPC-specific debugger interface
       + *        forsyth@plan9.cs.york.ac.uk
       + */
       +
       +static        char        *powerexcep(Map*, Regs*);
       +static        int        powerfoll(Map*, Regs*, ulong, ulong*);
       +static        int        powerdas(Map*, ulong, char, char*, int);
       +static        int        powerinstlen(Map*, ulong);
       +static        int        powerhexinst(Map*, ulong, char*, int);
       +
       +static char *excname[] =
       +{
       +        "reserved 0",
       +        "system reset",
       +        "machine check",
       +        "data access",
       +        "instruction access",
       +        "external interrupt",
       +        "alignment",
       +        "program exception",
       +        "floating-point unavailable",
       +        "decrementer",
       +        "i/o controller interface error",
       +        "reserved B",
       +        "system call",
       +        "trace trap",
       +        "floating point assist",
       +        "reserved",
       +        "ITLB miss",
       +        "DTLB load miss",
       +        "DTLB store miss",
       +        "instruction address breakpoint"
       +        "SMI interrupt"
       +        "reserved 15",
       +        "reserved 16",
       +        "reserved 17",
       +        "reserved 18",
       +        "reserved 19",
       +        "reserved 1A",
       +        /* the following are made up on a program exception */
       +        "floating point exception",                /* FPEXC */
       +        "illegal instruction",
       +        "privileged instruction",
       +        "trap",
       +        "illegal operation",
       +};
       +
       +static char*
       +powerexcep(Map *map, Regs *regs)
       +{
       +        ulong c;
       +        static char buf[32];
       +
       +        if(rget(regs, "CAUSE", &c) < 0)
       +                return "no cause register";
       +        c >>= 8;
       +        if(c < nelem(excname))
       +                return excname[c];
       +        sprint(buf, "unknown trap #%lux", c);
       +        return buf;
       +}
       +
       +/*
       + * disassemble PowerPC opcodes
       + */
       +
       +#define        REGSP        1        /* should come from q.out.h, but there's a clash */
       +#define        REGSB        2
       +
       +//static        char FRAMENAME[] = ".frame";
       +
       +static Map *mymap;
       +
       +/*
       + * ibm conventions for these: bit 0 is top bit
       + *        from table 10-1
       + */
       +typedef struct {
       +        uchar        aa;                /* bit 30 */
       +        uchar        crba;                /* bits 11-15 */
       +        uchar        crbb;                /* bits 16-20 */
       +        long        bd;                /* bits 16-29 */
       +        uchar        crfd;                /* bits 6-8 */
       +        uchar        crfs;                /* bits 11-13 */
       +        uchar        bi;                /* bits 11-15 */
       +        uchar        bo;                /* bits 6-10 */
       +        uchar        crbd;                /* bits 6-10 */
       +        union {
       +                short        d;        /* bits 16-31 */
       +                short        simm;
       +                ushort        uimm;
       +        };
       +        uchar        fm;                /* bits 7-14 */
       +        uchar        fra;                /* bits 11-15 */
       +        uchar        frb;                /* bits 16-20 */
       +        uchar        frc;                /* bits 21-25 */
       +        uchar        frs;                /* bits 6-10 */
       +        uchar        frd;                /* bits 6-10 */
       +        uchar        crm;                /* bits 12-19 */
       +        long        li;                /* bits 6-29 || b'00' */
       +        uchar        lk;                /* bit 31 */
       +        uchar        mb;                /* bits 21-25 */
       +        uchar        me;                /* bits 26-30 */
       +        uchar        nb;                /* bits 16-20 */
       +        uchar        op;                /* bits 0-5 */
       +        uchar        oe;                /* bit 21 */
       +        uchar        ra;                /* bits 11-15 */
       +        uchar        rb;                /* bits 16-20 */
       +        uchar        rc;                /* bit 31 */
       +        union {
       +                uchar        rs;        /* bits 6-10 */
       +                uchar        rd;
       +        };
       +        uchar        sh;                /* bits 16-20 */
       +        ushort        spr;                /* bits 11-20 */
       +        uchar        to;                /* bits 6-10 */
       +        uchar        imm;                /* bits 16-19 */
       +        ushort        xo;                /* bits 21-30, 22-30, 26-30, or 30 (beware) */
       +        long        immediate;
       +        long w0;
       +        long w1;
       +        ulong        addr;                /* pc of instruction */
       +        short        target;
       +        char        *curr;                /* current fill level in output buffer */
       +        char        *end;                /* end of buffer */
       +        int         size;                /* number of longs in instr */
       +        char        *err;                /* errmsg */
       +} Instr;
       +
       +#define        IBF(v,a,b) (((ulong)(v)>>(32-(b)-1)) & ~(~0L<<(((b)-(a)+1))))
       +#define        IB(v,b) IBF((v),(b),(b))
       +
       +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
       +decode(ulong pc, Instr *i)
       +{
       +        u32int w;
       +
       +        if (get4(mymap, pc, &w) < 0) {
       +                werrstr("can't read instruction: %r");
       +                return -1;
       +        }
       +        i->aa = IB(w, 30);
       +        i->crba = IBF(w, 11, 15);
       +        i->crbb = IBF(w, 16, 20);
       +        i->bd = IBF(w, 16, 29)<<2;
       +        if(i->bd & 0x8000)
       +                i->bd |= ~0L<<16;
       +        i->crfd = IBF(w, 6, 8);
       +        i->crfs = IBF(w, 11, 13);
       +        i->bi = IBF(w, 11, 15);
       +        i->bo = IBF(w, 6, 10);
       +        i->crbd = IBF(w, 6, 10);
       +        i->uimm = IBF(w, 16, 31);        /* also d, simm */
       +        i->fm = IBF(w, 7, 14);
       +        i->fra = IBF(w, 11, 15);
       +        i->frb = IBF(w, 16, 20);
       +        i->frc = IBF(w, 21, 25);
       +        i->frs = IBF(w, 6, 10);
       +        i->frd = IBF(w, 6, 10);
       +        i->crm = IBF(w, 12, 19);
       +        i->li = IBF(w, 6, 29)<<2;
       +        if(IB(w, 6))
       +                i->li |= ~0<<25;
       +        i->lk = IB(w, 31);
       +        i->mb = IBF(w, 21, 25);
       +        i->me = IBF(w, 26, 30);
       +        i->nb = IBF(w, 16, 20);
       +        i->op = IBF(w, 0, 5);
       +        i->oe = IB(w, 21);
       +        i->ra = IBF(w, 11, 15);
       +        i->rb = IBF(w, 16, 20);
       +        i->rc = IB(w, 31);
       +        i->rs = IBF(w, 6, 10);        /* also rd */
       +        i->sh = IBF(w, 16, 20);
       +        i->spr = IBF(w, 11, 20);
       +        i->to = IBF(w, 6, 10);
       +        i->imm = IBF(w, 16, 19);
       +        i->xo = IBF(w, 21, 30);                /* bits 21-30, 22-30, 26-30, or 30 (beware) */
       +        i->immediate = i->simm;
       +        if(i->op == 15)
       +                i->immediate <<= 16;
       +        i->w0 = w;
       +        i->target = -1;
       +        i->addr = pc;
       +        i->size = 1;
       +        return 1;
       +}
       +
       +static int
       +mkinstr(ulong pc, Instr *i)
       +{
       +        Instr x;
       +
       +        if(decode(pc, i) < 0)
       +                return -1;
       +        /*
       +         * combine ADDIS/ORI (CAU/ORIL) into MOVW
       +         */
       +        if (i->op == 15 && i->ra==0) {
       +                if(decode(pc+4, &x) < 0)
       +                        return -1;
       +                if (x.op == 24 && x.rs == x.ra && x.ra == i->rd) {
       +                        i->immediate |= (x.immediate & 0xFFFF);
       +                        i->w1 = x.w0;
       +                        i->target = x.rd;
       +                        i->size++;
       +                        return 1;
       +                }
       +        }
       +        return 1;
       +}
       +
       +static int
       +plocal(Instr *i)
       +{
       +        Symbol s;
       +        Loc l, li;
       +
       +        l.type = LOFFSET;
       +        l.offset = i->immediate;
       +        l.reg = "SP";
       +
       +        li.type = LADDR;
       +        li.addr = i->addr;
       +        if (findsym(li, CTEXT, &s)<0 || findlsym(&s, l, &s)<0)
       +                return -1;
       +        bprint(i, "%s%+ld(SP)", s.name, (long)i->immediate);
       +        return 0;
       +}
       +
       +static int
       +pglobal(Instr *i, long off, int anyoff, char *reg)
       +{
       +        Symbol s, s2;
       +        u32int off1;
       +        Loc l;
       +
       +        l.type = LADDR;
       +        l.addr = off;
       +        if(findsym(l, CANY, &s)>=0 && s.loc.type==LADDR &&
       +           s.loc.addr-off < 4096 &&
       +           (s.class == CDATA || s.class == CTEXT)) {
       +                if(off==s.loc.addr && s.name[0]=='$'){
       +                        off1 = 0;
       +                        get4(mymap, s.loc.addr, &off1);
       +                        l.addr = off1;
       +                        if(off1 && findsym(l, CANY, &s2)>=0 && s2.loc.type==LADDR && s2.loc.addr == off1){
       +                                bprint(i, "$%s%s", s2.name, reg);
       +                                return 1;
       +                        }
       +                }
       +                bprint(i, "%s", s.name);
       +                if (s.loc.addr != off)
       +                        bprint(i, "+%lux", off-s.loc.addr);
       +                bprint(i, reg);
       +                return 1;
       +        }
       +        if(!anyoff)
       +                return 0;
       +        bprint(i, "%lux%s", off, reg);
       +        return 1;
       +}
       +
       +static void
       +address(Instr *i)
       +{
       +        if (i->ra == REGSP && plocal(i) >= 0)
       +                return;
       +        if (i->ra == REGSB && mach->sb && pglobal(i, mach->sb+i->immediate, 0, "(SB)") >= 0)
       +                return;
       +        if(i->simm < 0)
       +                bprint(i, "-%lx(R%d)", -i->simm, i->ra);
       +        else
       +                bprint(i, "%lux(R%d)", i->immediate, i->ra);
       +}
       +
       +static        char        *tcrbits[] = {"LT", "GT", "EQ", "VS"};
       +static        char        *fcrbits[] = {"GE", "LE", "NE", "VC"};
       +
       +typedef struct Opcode Opcode;
       +
       +struct Opcode {
       +        uchar        op;
       +        ushort        xo;
       +        ushort        xomask;
       +        char        *mnemonic;
       +        void        (*f)(Opcode *, Instr *);
       +        char        *ken;
       +        int        flags;
       +};
       +
       +static void format(char *, Instr *, char *);
       +
       +static void
       +branch(Opcode *o, Instr *i)
       +{
       +        char buf[8];
       +        int bo, bi;
       +
       +        bo = i->bo & ~1;        /* ignore prediction bit */
       +        if(bo==4 || bo==12 || bo==20) {        /* simple forms */
       +                if(bo != 20) {
       +                        bi = i->bi&3;
       +                        sprint(buf, "B%s%%L", bo==12? tcrbits[bi]: fcrbits[bi]);
       +                        format(buf, i, 0);
       +                        bprint(i, "\t");
       +                        if(i->bi > 4)
       +                                bprint(i, "CR(%d),", i->bi/4);
       +                } else
       +                        format("BR%L\t", i, 0);
       +                if(i->op == 16)
       +                        format(0, i, "%J");
       +                else if(i->op == 19 && i->xo == 528)
       +                        format(0, i, "(CTR)");
       +                else if(i->op == 19 && i->xo == 16)
       +                        format(0, i, "(LR)");
       +        } else
       +                format(o->mnemonic, i, o->ken);
       +}
       +
       +static void
       +addi(Opcode *o, Instr *i)
       +{
       +        if (i->op==14 && i->ra == 0)
       +                format("MOVW", i, "%i,R%d");
       +        else if (i->ra == REGSB) {
       +                bprint(i, "MOVW\t$");
       +                address(i);
       +                bprint(i, ",R%d", i->rd);
       +        } else if(i->op==14 && i->simm < 0) {
       +                bprint(i, "SUB\t$%d,R%d", -i->simm, i->ra);
       +                if(i->rd != i->ra)
       +                        bprint(i, ",R%d", i->rd);
       +        } else if(i->ra == i->rd) {
       +                format(o->mnemonic, i, "%i");
       +                bprint(i, ",R%d", i->rd);
       +        } else
       +                format(o->mnemonic, i, o->ken);
       +}
       +
       +static void
       +addis(Opcode *o, Instr *i)
       +{
       +        long v;
       +
       +        v = i->immediate;
       +        if (i->op==15 && i->ra == 0)
       +                bprint(i, "MOVW\t$%lux,R%d", v, i->rd);
       +        else if (i->op==15 && i->ra == REGSB) {
       +                bprint(i, "MOVW\t$");
       +                address(i);
       +                bprint(i, ",R%d", i->rd);
       +        } else if(i->op==15 && v < 0) {
       +                bprint(i, "SUB\t$%d,R%d", -v, i->ra);
       +                if(i->rd != i->ra)
       +                        bprint(i, ",R%d", i->rd);
       +        } else {
       +                format(o->mnemonic, i, 0);
       +                bprint(i, "\t$%ld,R%d", v, i->ra);
       +                if(i->rd != i->ra)
       +                        bprint(i, ",R%d", i->rd);
       +        }
       +}
       +
       +static void
       +andi(Opcode *o, Instr *i)
       +{
       +        if (i->ra == i->rs)
       +                format(o->mnemonic, i, "%I,R%d");
       +        else
       +                format(o->mnemonic, i, o->ken);
       +}
       +
       +static void
       +gencc(Opcode *o, Instr *i)
       +{
       +        format(o->mnemonic, i, o->ken);
       +}
       +
       +static void
       +gen(Opcode *o, Instr *i)
       +{
       +        format(o->mnemonic, i, o->ken);
       +        if (i->rc)
       +                bprint(i, " [illegal Rc]");
       +}
       +
       +static void
       +ldx(Opcode *o, Instr *i)
       +{
       +        if(i->ra == 0)
       +                format(o->mnemonic, i, "(R%b),R%d");
       +        else
       +                format(o->mnemonic, i, "(R%b+R%a),R%d");
       +        if(i->rc)
       +                bprint(i, " [illegal Rc]");
       +}
       +
       +static void
       +stx(Opcode *o, Instr *i)
       +{
       +        if(i->ra == 0)
       +                format(o->mnemonic, i, "R%d,(R%b)");
       +        else
       +                format(o->mnemonic, i, "R%d,(R%b+R%a)");
       +        if(i->rc && i->xo != 150)
       +                bprint(i, " [illegal Rc]");
       +}
       +
       +static void
       +fldx(Opcode *o, Instr *i)
       +{
       +        if(i->ra == 0)
       +                format(o->mnemonic, i, "(R%b),F%d");
       +        else
       +                format(o->mnemonic, i, "(R%b+R%a),F%d");
       +        if(i->rc)
       +                bprint(i, " [illegal Rc]");
       +}
       +
       +static void
       +fstx(Opcode *o, Instr *i)
       +{
       +        if(i->ra == 0)
       +                format(o->mnemonic, i, "F%d,(R%b)");
       +        else
       +                format(o->mnemonic, i, "F%d,(R%b+R%a)");
       +        if(i->rc)
       +                bprint(i, " [illegal Rc]");
       +}
       +
       +static void
       +dcb(Opcode *o, Instr *i)
       +{
       +        if(i->ra == 0)
       +                format(o->mnemonic, i, "(R%b)");
       +        else
       +                format(o->mnemonic, i, "(R%b+R%a)");
       +        if(i->rd)
       +                bprint(i, " [illegal Rd]");
       +        if(i->rc)
       +                bprint(i, " [illegal Rc]");
       +}
       +
       +static void
       +lw(Opcode *o, Instr *i, char r)
       +{
       +        bprint(i, "%s\t", o->mnemonic);
       +        address(i);
       +        bprint(i, ",%c%d", r, i->rd);
       +}
       +
       +static void
       +load(Opcode *o, Instr *i)
       +{
       +        lw(o, i, 'R');
       +}
       +
       +static void
       +fload(Opcode *o, Instr *i)
       +{
       +        lw(o, i, 'F');
       +}
       +
       +static void
       +sw(Opcode *o, Instr *i, char r)
       +{
       +        char *m;
       +        Symbol s;
       +        Loc l;
       +
       +        m = o->mnemonic;
       +        if (i->rs == REGSP) {
       +                l.type = LADDR;
       +                l.addr = i->addr;
       +                if (findsym(l, CTEXT, &s)>=0) {
       +                        l.type = LOFFSET;
       +                        l.reg = "SP";
       +                        l.offset = i->immediate;
       +                        if (findlsym(&s, l, &s) >= 0) {
       +                                bprint(i, "%s\t%c%d,%s-%d(SP)", m, r, i->rd,
       +                                        s.name, i->immediate);
       +                                return;
       +                        }
       +                }
       +        }
       +        if (i->rs == REGSB && mach->sb) {
       +                bprint(i, "%s\t%c%d,", m, r, i->rd);
       +                address(i);
       +                return;
       +        }
       +        if (r == 'F')
       +                format(m, i, "F%d,%l");
       +        else
       +                format(m, i, o->ken);
       +}
       +
       +static void
       +store(Opcode *o, Instr *i)
       +{
       +        sw(o, i, 'R');
       +}
       +
       +static void
       +fstore(Opcode *o, Instr *i)
       +{
       +        sw(o, i, 'F');
       +}
       +
       +static void
       +shifti(Opcode *o, Instr *i)
       +{
       +        if (i->ra == i->rs)
       +                format(o->mnemonic, i, "$%k,R%a");
       +        else
       +                format(o->mnemonic, i, o->ken);
       +}
       +
       +static void
       +shift(Opcode *o, Instr *i)
       +{
       +        if (i->ra == i->rs)
       +                format(o->mnemonic, i, "R%b,R%a");
       +        else
       +                format(o->mnemonic, i, o->ken);
       +}
       +
       +static void
       +add(Opcode *o, Instr *i)
       +{
       +        if (i->rd == i->ra)
       +                format(o->mnemonic, i, "R%b,R%d");
       +        else if (i->rd == i->rb)
       +                format(o->mnemonic, i, "R%a,R%d");
       +        else
       +                format(o->mnemonic, i, o->ken);
       +}
       +
       +static void
       +sub(Opcode *o, Instr *i)
       +{
       +        format(o->mnemonic, i, 0);
       +        bprint(i, "\t");
       +        if(i->op == 31) {
       +                bprint(i, "\tR%d,R%d", i->ra, i->rb);        /* subtract Ra from Rb */
       +                if(i->rd != i->rb)
       +                        bprint(i, ",R%d", i->rd);
       +        } else
       +                bprint(i, "\tR%d,$%d,R%d", i->ra, i->simm, i->rd);
       +}
       +
       +#define div qdiv
       +
       +static void
       +div(Opcode *o, Instr *i)
       +{
       +        format(o->mnemonic, i, 0);
       +        if(i->op == 31)
       +                bprint(i, "\tR%d,R%d", i->rb, i->ra);
       +        else
       +                bprint(i, "\t$%d,R%d", i->simm, i->ra);
       +        if(i->ra != i->rd)
       +                bprint(i, ",R%d", i->rd);
       +}
       +
       +static void
       +and(Opcode *o, Instr *i)
       +{
       +        if (i->op == 31) {
       +                /* Rb,Rs,Ra */
       +                if (i->ra == i->rs)
       +                        format(o->mnemonic, i, "R%b,R%a");
       +                else if (i->ra == i->rb)
       +                        format(o->mnemonic, i, "R%s,R%a");
       +                else
       +                        format(o->mnemonic, i, o->ken);
       +        } else {
       +                /* imm,Rs,Ra */
       +                if (i->ra == i->rs)
       +                        format(o->mnemonic, i, "%I,R%a");
       +                else
       +                        format(o->mnemonic, i, o->ken);
       +        }
       +}
       +
       +static void
       +or(Opcode *o, Instr *i)
       +{
       +        if (i->op == 31) {
       +                /* Rb,Rs,Ra */
       +                if (i->rs == 0 && i->ra == 0 && i->rb == 0)
       +                        format("NOP", i, 0);
       +                else if (i->rs == i->rb)
       +                        format("MOVW", i, "R%b,R%a");
       +                else
       +                        and(o, i);
       +        } else
       +                and(o, i);
       +}
       +
       +static void
       +shifted(Opcode *o, Instr *i)
       +{
       +        format(o->mnemonic, i, 0);
       +        bprint(i, "\t$%lux,", (ulong)i->uimm<<16);
       +        if (i->rs == i->ra)
       +                bprint(i, "R%d", i->ra);
       +        else
       +                bprint(i, "R%d,R%d", i->rs, i->ra);
       +}
       +
       +static void
       +neg(Opcode *o, Instr *i)
       +{
       +        if (i->rd == i->ra)
       +                format(o->mnemonic, i, "R%d");
       +        else
       +                format(o->mnemonic, i, o->ken);
       +}
       +
       +static        char        ir2[] = "R%a,R%d";                /* reverse of IBM order */
       +static        char        ir3[] = "R%b,R%a,R%d";
       +static        char        ir3r[] = "R%a,R%b,R%d";
       +static        char        il3[] = "R%b,R%s,R%a";
       +static        char        il2u[] = "%I,R%a,R%d";
       +static        char        il3s[] = "$%k,R%s,R%a";
       +static        char        il2[] = "R%s,R%a";
       +static        char        icmp3[] = "R%a,R%b,%D";
       +static        char        cr3op[] = "%b,%a,%d";
       +static        char        ir2i[] = "%i,R%a,R%d";
       +static        char        fp2[] = "F%b,F%d";
       +static        char        fp3[] = "F%b,F%a,F%d";
       +static        char        fp3c[] = "F%c,F%a,F%d";
       +static        char        fp4[] = "F%a,F%c,F%b,F%d";
       +static        char        fpcmp[] = "F%a,F%b,%D";
       +static        char        ldop[] = "%l,R%d";
       +static        char        stop[] = "R%d,%l";
       +static        char        fldop[] = "%l,F%d";
       +static        char        fstop[] = "F%d,%l";
       +static        char        rlim[] = "R%b,R%s,$%z,R%a";
       +static        char        rlimi[] = "$%k,R%s,$%z,R%a";
       +
       +#define        OEM        IBF(~0,22,30)
       +#define        FP4        IBF(~0,26,30)
       +#define        ALL        (~0)
       +/*
       +notes:
       +        10-26: crfD = rD>>2; rD&3 mbz
       +                also, L bit (bit 10) mbz or selects 64-bit operands
       +*/
       +
       +static Opcode opcodes[] = {
       +        {31,        360,        OEM,        "ABS%V%C",        0,        ir2},        /* POWER */
       +
       +        {31,        266,        OEM,        "ADD%V%C",        add,        ir3},
       +        {31,         10,        OEM,        "ADDC%V%C",        add,        ir3},
       +        {31,        138,        OEM,        "ADDE%V%C",        add,        ir3},
       +        {14,        0,        0,        "ADD",                addi,        ir2i},
       +        {12,        0,        0,        "ADDC",                addi,        ir2i},
       +        {13,        0,        0,        "ADDCCC",        addi,        ir2i},
       +        {15,        0,        0,        "ADD",                addis,        0},
       +        {31,        234,        OEM,        "ADDME%V%C",        gencc,        ir2},
       +        {31,        202,        OEM,        "ADDZE%V%C",        gencc,        ir2},
       +
       +        {31,        28,        ALL,        "AND%C",        and,        il3},
       +        {31,        60,        ALL,        "ANDN%C",        and,        il3},
       +        {28,        0,        0,        "ANDCC",                andi,        il2u},
       +        {29,        0,        0,        "ANDCC",                shifted, 0},
       +
       +        {18,        0,        0,        "B%L",                gencc,        "%j"},
       +        {16,        0,        0,        "BC%L",                branch,        "%d,%a,%J"},
       +        {19,        528,        ALL,        "BC%L",                branch,        "%d,%a,(CTR)"},
       +        {19,        16,        ALL,        "BC%L",                branch,        "%d,%a,(LR)"},
       +
       +        {31,        531,        ALL,        "CLCS",                gen,        ir2},        /* POWER */
       +
       +        {31,        0,        ALL,        "CMP",                0,        icmp3},
       +        {11,        0,        0,        "CMP",                0,        "R%a,%i,%D"},
       +        {31,        32,        ALL,        "CMPU",                0,        icmp3},
       +        {10,        0,        0,        "CMPU",                0,        "R%a,%I,%D"},
       +
       +        {31,        26,        ALL,        "CNTLZ%C",        gencc,        ir2},
       +
       +        {19,        257,        ALL,        "CRAND",        gen,        cr3op},
       +        {19,        129,        ALL,        "CRANDN",        gen,        cr3op},
       +        {19,        289,        ALL,        "CREQV",        gen,        cr3op},
       +        {19,        225,        ALL,        "CRNAND",        gen,        cr3op},
       +        {19,        33,        ALL,        "CRNOR",        gen,        cr3op},
       +        {19,        449,        ALL,        "CROR",                gen,        cr3op},
       +        {19,        417,        ALL,        "CRORN",        gen,        cr3op},
       +        {19,        193,        ALL,        "CRXOR",        gen,        cr3op},
       +
       +        {31,        86,        ALL,        "DCBF",                dcb,        0},
       +        {31,        470,        ALL,        "DCBI",                dcb,        0},
       +        {31,        54,        ALL,        "DCBST",        dcb,        0},
       +        {31,        278,        ALL,        "DCBT",                dcb,        0},
       +        {31,        246,        ALL,        "DCBTST",        dcb,        0},
       +        {31,        1014,        ALL,        "DCBZ",                dcb,        0},
       +
       +        {31,        331,        OEM,        "DIV%V%C",        div,        ir3},        /* POWER */
       +        {31,        363,        OEM,        "DIVS%V%C",        div,        ir3},        /* POWER */
       +        {31,        491,        OEM,        "DIVW%V%C",        div,        ir3},
       +        {31,        459,        OEM,        "DIVWU%V%C",        div,        ir3},
       +
       +        {31,        264,        OEM,        "DOZ%V%C",        gencc,        ir3r},        /* POWER */
       +        {9,        0,        0,        "DOZ",                gen,        ir2i},        /* POWER */
       +
       +        {31,        310,        ALL,        "ECIWX",        ldx,        0},
       +        {31,        438,        ALL,        "ECOWX",        stx,        0},
       +        {31,        854,        ALL,        "EIEIO",        gen,        0},
       +
       +        {31,        284,        ALL,        "EQV%C",        gencc,        il3},
       +
       +        {31,        954,        ALL,        "EXTSB%C",        gencc,        il2},
       +        {31,        922,        ALL,        "EXTSH%C",        gencc,        il2},
       +
       +        {63,        264,        ALL,        "FABS%C",        gencc,        fp2},
       +        {63,        21,        ALL,        "FADD%C",        gencc,        fp3},
       +        {59,        21,        ALL,        "FADDS%C",        gencc,        fp3},
       +        {63,        32,        ALL,        "FCMPO",        gen,        fpcmp},
       +        {63,        0,        ALL,        "FCMPU",        gen,        fpcmp},
       +        {63,        14,        ALL,        "FCTIW%C",        gencc,        fp2},
       +        {63,        15,        ALL,        "FCTIWZ%C",        gencc,        fp2},
       +        {63,        18,        ALL,        "FDIV%C",        gencc,        fp3},
       +        {59,        18,        ALL,        "FDIVS%C",        gencc,        fp3},
       +        {63,        29,        FP4,        "FMADD%C",        gencc,        fp4},
       +        {59,        29,        FP4,        "FMADDS%C",        gencc,        fp4},
       +        {63,        72,        ALL,        "FMOVD%C",        gencc,        fp2},
       +        {63,        28,        FP4,        "FMSUB%C",        gencc,        fp4},
       +        {59,        28,        FP4,        "FMSUBS%C",        gencc,        fp4},
       +        {63,        25,        FP4,        "FMUL%C",        gencc,        fp3c},
       +        {59,        25,        FP4,        "FMULS%C",        gencc,        fp3c},
       +        {63,        136,        ALL,        "FNABS%C",        gencc,        fp2},
       +        {63,        40,        ALL,        "FNEG%C",        gencc,        fp2},
       +        {63,        31,        FP4,        "FNMADD%C",        gencc,        fp4},
       +        {59,        31,        FP4,        "FNMADDS%C",        gencc,        fp4},
       +        {63,        30,        FP4,        "FNMSUB%C",        gencc,        fp4},
       +        {59,        30,        FP4,        "FNMSUBS%C",        gencc,        fp4},
       +        {63,        12,        ALL,        "FRSP%C",        gencc,        fp2},
       +        {63,        20,        FP4,        "FSUB%C",        gencc,        fp3},
       +        {59,        20,        FP4,        "FSUBS%C",        gencc,        fp3},
       +
       +        {31,        982,        ALL,        "ICBI",                dcb,        0},
       +        {19,        150,        ALL,        "ISYNC",        gen,        0},
       +
       +        {34,        0,        0,        "MOVBZ",        load,        ldop},
       +        {35,        0,        0,        "MOVBZU",        load,        ldop},
       +        {31,        119,        ALL,        "MOVBZU",        ldx,        0},
       +        {31,        87,        ALL,        "MOVBZ",        ldx,        0},
       +        {50,        0,        0,        "FMOVD",        fload,        fldop},
       +        {51,        0,        0,        "FMOVDU",        fload,        fldop},
       +        {31,        631,        ALL,        "FMOVDU",        fldx,        0},
       +        {31,        599,        ALL,        "FMOVD",        fldx,        0},
       +        {48,        0,        0,        "FMOVS",        load,        fldop},
       +        {49,        0,        0,        "FMOVSU",        load,        fldop},
       +        {31,        567,        ALL,        "FMOVSU",        fldx,        0},
       +        {31,        535,        ALL,        "FMOVS",        fldx,        0},
       +        {42,        0,        0,        "MOVH",                load,        ldop},
       +        {43,        0,        0,        "MOVHU",        load,        ldop},
       +        {31,        375,        ALL,        "MOVHU",        ldx,        0},
       +        {31,        343,        ALL,        "MOVH",                ldx,        0},
       +        {31,        790,        ALL,        "MOVHBR",        ldx,        0},
       +        {40,        0,        0,        "MOVHZ",        load,        ldop},
       +        {41,        0,        0,        "MOVHZU",        load,        ldop},
       +        {31,        311,        ALL,        "MOVHZU",        ldx,        0},
       +        {31,        279,        ALL,        "MOVHZ",        ldx,        0},
       +        {46,        0,        0,        "MOVMW",                load,        ldop},
       +        {31,        277,        ALL,        "LSCBX%C",        ldx,        0},        /* POWER */
       +        {31,        597,        ALL,        "LSW",                gen,        "(R%a),$%n,R%d"},
       +        {31,        533,        ALL,        "LSW",                ldx,        0},
       +        {31,        20,        ALL,        "LWAR",                ldx,        0},
       +        {31,        534,        ALL,        "MOVWBR",                ldx,        0},
       +        {32,        0,        0,        "MOVW",                load,        ldop},
       +        {33,        0,        0,        "MOVWU",        load,        ldop},
       +        {31,        55,        ALL,        "MOVWU",        ldx,        0},
       +        {31,        23,        ALL,        "MOVW",                ldx,        0},
       +
       +        {31,        29,        ALL,        "MASKG%C",        gencc,        "R%s:R%b,R%d"},        /* POWER */
       +        {31,        541,        ALL,        "MASKIR%C",        gencc,        "R%s,R%b,R%a"},        /* POWER */
       +
       +        {19,        0,        ALL,        "MOVFL",        gen,        "%S,%D"},
       +        {63,        64,        ALL,        "MOVCRFS",        gen,        "%S,%D"},
       +        {31,        512,        ALL,        "MOVW",        gen,        "XER,%D"},
       +        {31,        19,        ALL,        "MOVW",        gen,        "CR,R%d"},
       +
       +        {63,        583,        ALL,        "MOVW%C",        gen,        "FPSCR, F%d"},        /* mffs */
       +        {31,        83,        ALL,        "MOVW",                gen,        "MSR,R%d"},
       +        {31,        339,        ALL,        "MOVW",                gen,        "%P,R%d"},
       +        {31,        595,        ALL,        "MOVW",                gen,        "SEG(%a),R%d"},
       +        {31,        659,        ALL,        "MOVW",                gen,        "SEG(R%b),R%d"},
       +        {31,        144,        ALL,        "MOVFL",        gen,        "R%s,%m,CR"},
       +        {63,        70,        ALL,        "MTFSB0%C",        gencc,        "%D"},
       +        {63,        38,        ALL,        "MTFSB1%C",        gencc,        "%D"},
       +        {63,        711,        ALL,        "MOVFL%C",        gencc,        "F%b,%M,FPSCR"},        /* mtfsf */
       +        {63,        134,        ALL,        "MOVFL%C",        gencc,        "%K,%D"},
       +        {31,        146,        ALL,        "MOVW",                gen,        "R%s,MSR"},
       +        {31,        467,        ALL,        "MOVW",                gen,        "R%s,%P"},
       +        {31,        210,        ALL,        "MOVW",                gen,        "R%s,SEG(%a)"},
       +        {31,        242,        ALL,        "MOVW",                gen,        "R%s,SEG(R%b)"},
       +
       +        {31,        107,        OEM,        "MUL%V%C",        gencc,        ir3},        /* POWER */
       +        {31,        75,        ALL,        "MULHW%C",        gencc,        ir3},        /* POWER */
       +        {31,        11,        ALL,        "MULHWU%C",        gencc,        ir3},        /* POWER */
       +
       +        {31,        235,        OEM,        "MULLW%V%C",        gencc,        ir3},
       +        {7,        0,        0,        "MULLW",        div,        "%i,R%a,R%d"},
       +
       +        {31,        488,        OEM,        "NABS%V%C",        neg,        ir2},        /* POWER */
       +
       +        {31,        476,        ALL,        "NAND%C",        gencc,        il3},
       +        {31,        104,        OEM,        "NEG%V%C",        neg,        ir2},
       +        {31,        124,        ALL,        "NOR%C",        gencc,        il3},
       +        {31,        444,        ALL,        "OR%C",        or,        il3},
       +        {31,        412,        ALL,        "ORN%C",        or,        il3},
       +        {24,        0,        0,        "OR",                and,        "%I,R%d,R%a"},
       +        {25,        0,        0,        "OR",                shifted, 0},
       +
       +        {19,        50,        ALL,        "RFI",                gen,        0},
       +
       +        {22,        0,        0,        "RLMI%C",        gencc,        rlim},        /* POWER */
       +        {20,        0,        0,        "RLWMI%C",        gencc,        rlimi},
       +        {21,        0,        0,        "RLWNM%C",        gencc,        rlimi},
       +        {23,        0,        0,        "RLWNM%C",        gencc,        rlim},
       +
       +        {31,        537,        ALL,        "RRIB%C",        gencc,        il3},        /* POWER */
       +
       +        {17,        1,        ALL,        "SYSCALL",        gen,        0},
       +
       +        {31,        153,        ALL,        "SLE%C",        shift,        il3},        /* POWER */
       +        {31,        217,        ALL,        "SLEQ%C",        shift,        il3},        /* POWER */
       +        {31,        184,        ALL,        "SLQ%C",        shifti,        il3s},        /* POWER */
       +        {31,        248,        ALL,        "SLLQ%C",        shifti,        il3s},        /* POWER */
       +        {31,        216,        ALL,        "SLLQ%C",        shift,        il3},        /* POWER */
       +        {31,        152,        ALL,        "SLQ%C",        shift,        il3},        /* POWER */
       +
       +        {31,        24,        ALL,        "SLW%C",        shift,        il3},
       +
       +        {31,        920,        ALL,        "SRAQ%C",        shift,        il3},        /* POWER */
       +        {31,        952,        ALL,        "SRAQ%C",        shifti,        il3s},        /* POWER */
       +
       +        {31,        792,        ALL,        "SRAW%C",        shift,        il3},
       +        {31,        824,        ALL,        "SRAW%C",        shifti,        il3s},
       +
       +        {31,        665,        ALL,        "SRE%C",        shift,        il3},        /* POWER */
       +        {31,        921,        ALL,        "SREA%C",        shift,        il3},        /* POWER */
       +        {31,        729,        ALL,        "SREQ%C",        shift,        il3},        /* POWER */
       +        {31,        696,        ALL,        "SRQ%C",        shifti,        il3s},        /* POWER */
       +        {31,        760,        ALL,        "SRLQ%C",        shifti,        il3s},        /* POWER */
       +        {31,        728,        ALL,        "SRLQ%C",        shift,        il3},        /* POWER */
       +        {31,        664,        ALL,        "SRQ%C",        shift,        il3},        /* POWER */
       +
       +        {31,        536,        ALL,        "SRW%C",        shift,        il3},
       +
       +        {38,        0,        0,        "MOVB",                store,        stop},
       +        {39,        0,        0,        "MOVBU",        store,        stop},
       +        {31,        247,        ALL,        "MOVBU",        stx,        0},
       +        {31,        215,        ALL,        "MOVB",                stx,        0},
       +        {54,        0,        0,        "FMOVD",        fstore,        fstop},
       +        {55,        0,        0,        "FMOVDU",        fstore,        fstop},
       +        {31,        759,        ALL,        "FMOVDU",        fstx,        0},
       +        {31,        727,        ALL,        "FMOVD",        fstx,        0},
       +        {52,        0,        0,        "FMOVS",        fstore,        fstop},
       +        {53,        0,        0,        "FMOVSU",        fstore,        fstop},
       +        {31,        695,        ALL,        "FMOVSU",        fstx,        0},
       +        {31,        663,        ALL,        "FMOVS",        fstx,        0},
       +        {44,        0,        0,        "MOVH",                store,        stop},
       +        {31,        918,        ALL,        "MOVHBR",        stx,        0},
       +        {45,        0,        0,        "MOVHU",        store,        stop},
       +        {31,        439,        ALL,        "MOVHU",        stx,        0},
       +        {31,        407,        ALL,        "MOVH",                stx,        0},
       +        {47,        0,        0,        "MOVMW",                store,        stop},
       +        {31,        725,        ALL,        "STSW",                gen,        "R%d,$%n,(R%a)"},
       +        {31,        661,        ALL,        "STSW",                stx,        0},
       +        {36,        0,        0,        "MOVW",                store,        stop},
       +        {31,        662,        ALL,        "MOVWBR",        stx,        0},
       +        {31,        150,        ALL,        "STWCCC",                stx,        0},
       +        {37,        0,        0,        "MOVWU",        store,        stop},
       +        {31,        183,        ALL,        "MOVWU",        stx,        0},
       +        {31,        151,        ALL,        "MOVW",                stx,        0},
       +
       +        {31,        40,        OEM,        "SUB%V%C",        sub,        ir3},
       +        {31,        8,        OEM,        "SUBC%V%C",        sub,        ir3},
       +        {31,        136,        OEM,        "SUBE%V%C",        sub,        ir3},
       +        {8,        0,        0,        "SUBC",                gen,        "R%a,%i,R%d"},
       +        {31,        232,        OEM,        "SUBME%V%C",        sub,        ir2},
       +        {31,        200,        OEM,        "SUBZE%V%C",        sub,        ir2},
       +
       +        {31,        598,        ALL,        "SYNC",                gen,        0},
       +        {31,        370,        ALL,        "TLBIA",        gen,        0},
       +        {31,        306,        ALL,        "TLBIE",        gen,        "R%b"},
       +        {31,        1010,        ALL,        "TLBLI",        gen,        "R%b"},
       +        {31,        978,        ALL,        "TLBLD",        gen,        "R%b"},
       +        {31,        4,        ALL,        "TW",                gen,        "%d,R%a,R%b"},
       +        {3,        0,        0,        "TW",                gen,        "%d,R%a,%i"},
       +
       +        {31,        316,        ALL,        "XOR",                and,        il3},
       +        {26,        0,        0,        "XOR",                and,        il2u},
       +        {27,        0,        0,        "XOR",                shifted, 0},
       +
       +        {0},
       +};
       +
       +typedef struct Spr Spr;
       +struct Spr {
       +        int        n;
       +        char        *name;
       +};
       +
       +static        Spr        sprname[] = {
       +        {0, "MQ"},
       +        {1, "XER"},
       +        {268, "TBL"},
       +        {269, "TBU"},
       +        {8, "LR"},
       +        {9, "CTR"},
       +        {528, "IBAT0U"},
       +        {529, "IBAT0L"},
       +        {530, "IBAT1U"},
       +        {531, "IBAT1L"},
       +        {532, "IBAT2U"},
       +        {533, "IBAT2L"},
       +        {534, "IBAT3U"},
       +        {535, "IBAT3L"},
       +        {536, "DBAT0U"},
       +        {537, "DBAT0L"},
       +        {538, "DBAT1U"},
       +        {539, "DBAT1L"},
       +        {540, "DBAT2U"},
       +        {541, "DBAT2L"},
       +        {542, "DBAT3U"},
       +        {543, "DBAT3L"},
       +        {25, "SDR1"},
       +        {19, "DAR"},
       +        {272, "SPRG0"},
       +        {273, "SPRG1"},
       +        {274, "SPRG2"},
       +        {275, "SPRG3"},
       +        {18, "DSISR"},
       +        {26, "SRR0"},
       +        {27, "SRR1"},
       +        {284, "TBLW"},
       +        {285, "TBUW"},        
       +        {22, "DEC"},
       +        {282, "EAR"},
       +        {1008, "HID0"},
       +        {1009, "HID1"},
       +        {976, "DMISS"},
       +        {977, "DCMP"},
       +        {978, "HASH1"},
       +        {979, "HASH2"},
       +        {980, "IMISS"},
       +        {981, "ICMP"},
       +        {982, "RPA"},
       +        {1010, "IABR"},
       +        {0,0},
       +};
       +
       +static void
       +format(char *mnemonic, Instr *i, char *f)
       +{
       +        int n, s;
       +        ulong mask;
       +
       +        if (mnemonic)
       +                format(0, i, mnemonic);
       +        if (f == 0)
       +                return;
       +        if (mnemonic)
       +                bprint(i, "\t");
       +        for ( ; *f; f++) {
       +                if (*f != '%') {
       +                        bprint(i, "%c", *f);
       +                        continue;
       +                }
       +                switch (*++f) {
       +                case 'V':
       +                        if(i->oe)
       +                                bprint(i, "V");
       +                        break;
       +
       +                case 'C':
       +                        if(i->rc)
       +                                bprint(i, "CC");
       +                        break;
       +
       +                case 'a':
       +                        bprint(i, "%d", i->ra);
       +                        break;
       +
       +                case 'b':
       +                        bprint(i, "%d", i->rb);
       +                        break;
       +
       +                case 'c':
       +                        bprint(i, "%d", i->frc);
       +                        break;
       +
       +                case 'd':
       +                case 's':
       +                        bprint(i, "%d", i->rd);
       +                        break;
       +
       +                case 'S':
       +                        if(i->ra & 3)
       +                                bprint(i, "CR(INVAL:%d)", i->ra);
       +                        else if(i->op == 63)
       +                                bprint(i, "FPSCR(%d)", i->crfs);
       +                        else
       +                                bprint(i, "CR(%d)", i->crfs);
       +                        break;
       +
       +                case 'D':
       +                        if(i->rd & 3)
       +                                bprint(i, "CR(INVAL:%d)", i->rd);
       +                        else if(i->op == 63)
       +                                bprint(i, "FPSCR(%d)", i->crfd);
       +                        else
       +                                bprint(i, "CR(%d)", i->crfd);
       +                        break;
       +
       +                case 'l':
       +                        if(i->simm < 0)
       +                                bprint(i, "-%lx(R%d)", -i->simm, i->ra);
       +                        else
       +                                bprint(i, "%lx(R%d)", i->simm, i->ra);
       +                        break;
       +
       +                case 'i':
       +                        bprint(i, "$%ld", i->simm);
       +                        break;
       +
       +                case 'I':
       +                        bprint(i, "$%lx", i->uimm);
       +                        break;
       +
       +                case 'w':
       +                        bprint(i, "[%lux]", i->w0);
       +                        break;
       +
       +                case 'P':
       +                        n = ((i->spr&0x1f)<<5)|((i->spr>>5)&0x1f);
       +                        for(s=0; sprname[s].name; s++)
       +                                if(sprname[s].n == n)
       +                                        break;
       +                        if(sprname[s].name) {
       +                                if(s < 10)
       +                                        bprint(i, sprname[s].name);
       +                                else
       +                                        bprint(i, "SPR(%s)", sprname[s].name);
       +                        } else
       +                                bprint(i, "SPR(%d)", n);
       +                        break;
       +
       +                case 'n':
       +                        bprint(i, "%d", i->nb==0? 32: i->nb);        /* eg, pg 10-103 */
       +                        break;
       +
       +                case 'm':
       +                        bprint(i, "%lx", i->crm);
       +                        break;
       +
       +                case 'M':
       +                        bprint(i, "%lx", i->fm);
       +                        break;
       +
       +                case 'z':
       +                        if(i->mb <= i->me)
       +                                mask = ((ulong)~0L>>i->mb) & (~0L<<(31-i->me));
       +                        else
       +                                mask = ~(((ulong)~0L>>(i->me+1)) & (~0L<<(31-(i->mb-1))));
       +                        bprint(i, "%lux", mask);
       +                        break;
       +
       +                case 'k':
       +                        bprint(i, "%d", i->sh);
       +                        break;
       +
       +                case 'K':
       +                        bprint(i, "$%x", i->imm);
       +                        break;
       +
       +                case 'L':
       +                        if(i->lk)
       +                                bprint(i, "L");
       +                        break;
       +
       +                case 'j':
       +                        if(i->aa)
       +                                pglobal(i, i->li, 1, "(SB)");
       +                        else
       +                                pglobal(i, i->addr+i->li, 1, "");
       +                        break;
       +
       +                case 'J':
       +                        if(i->aa)
       +                                pglobal(i, i->bd, 1, "(SB)");
       +                        else
       +                                pglobal(i, i->addr+i->bd, 1, "");
       +                        break;
       +
       +                case '\0':
       +                        bprint(i, "%%");
       +                        return;
       +
       +                default:
       +                        bprint(i, "%%%c", *f);
       +                        break;
       +                }
       +        }
       +}
       +
       +static int
       +printins(Map *map, ulong pc, char *buf, int n)
       +{
       +        Instr i;
       +        Opcode *o;
       +
       +        mymap = map;
       +        memset(&i, 0, sizeof(i));
       +        i.curr = buf;
       +        i.end = buf+n-1;
       +        if(mkinstr(pc, &i) < 0)
       +                return -1;
       +        for(o = opcodes; o->mnemonic != 0; o++)
       +                if(i.op == o->op && (i.xo & o->xomask) == o->xo) {
       +                        if (o->f)
       +                                (*o->f)(o, &i);
       +                        else
       +                                format(o->mnemonic, &i, o->ken);
       +                        return i.size*4;
       +                }
       +        bprint(&i, "unknown %lux", i.w0);
       +        return i.size*4;
       +}
       +
       +static int
       +powerdas(Map *map, ulong pc, char modifier, char *buf, int n)
       +{
       +        USED(modifier);
       +        return printins(map, pc, buf, n);
       +}
       +
       +static int
       +powerhexinst(Map *map, ulong pc, char *buf, int n)
       +{
       +        Instr instr;
       +
       +        mymap = map;
       +        memset(&instr, 0, sizeof(instr));
       +        instr.curr = buf;
       +        instr.end = buf+n-1;
       +        if (mkinstr(pc, &instr) < 0)
       +                return -1;
       +        if (instr.end-instr.curr > 8)
       +                instr.curr = _hexify(instr.curr, instr.w0, 7);
       +        if (instr.end-instr.curr > 9 && instr.size == 2) {
       +                *instr.curr++ = ' ';
       +                instr.curr = _hexify(instr.curr, instr.w1, 7);
       +        }
       +        *instr.curr = 0;
       +        return instr.size*4;
       +}
       +
       +static int
       +powerinstlen(Map *map, ulong pc)
       +{
       +        Instr i;
       +
       +        mymap = map;
       +        if (mkinstr(pc, &i) < 0)
       +                return -1;
       +        return i.size*4;
       +}
       +
       +static int
       +powerfoll(Map *map, Regs *regs, ulong pc, ulong *foll)
       +{
       +        char *reg;
       +        Instr i;
       +
       +        mymap = map;
       +        if (mkinstr(pc, &i) < 0)
       +                return -1;
       +        foll[0] = pc+4;
       +        foll[1] = pc+4;
       +        switch(i.op) {
       +        default:
       +                return 1;
       +
       +        case 18:        /* branch */
       +                foll[0] = i.li;
       +                if(!i.aa)
       +                        foll[0] += pc;
       +                break;
       +                        
       +        case 16:        /* conditional branch */
       +                foll[0] = i.bd;
       +                if(!i.aa)
       +                        foll[0] += pc;
       +                break;
       +
       +        case 19:        /* conditional branch to register */
       +                if(i.xo == 528)
       +                        reg = "CTR";
       +                else if(i.xo == 16)
       +                        reg = "LR";
       +                else
       +                        return 1;        /* not a branch */
       +                if(rget(regs, reg, &foll[0]) < 0)
       +                        return -1;
       +                break;
       +        }
       +        if(i.lk)
       +                return 2;
       +        return 1;
       +}
       +
       +#define        REGOFF(x)        (ulong) (&((struct Ureg *) 0)->x)
       +
       +#define SP                REGOFF(r1)
       +#define PC                REGOFF(pc)
       +#define        R3                REGOFF(r3)        /* return reg */
       +#define        LR                REGOFF(lr)
       +#define R31                REGOFF(r31)
       +#define FP_REG(x)        (R31+4+8*(x))
       +
       +#define        REGSIZE                sizeof(struct Ureg)
       +#define        FPREGSIZE        (8*33)        
       +
       +Regdesc powerreglist[] =
       +{
       +        {"CAUSE",        REGOFF(cause),        RINT|RRDONLY,        'X'},
       +        {"SRR1",        REGOFF(srr1),        RINT|RRDONLY,        'X'},
       +        {"PC",                REGOFF(pc),        RINT,                'X'},
       +        {"LR",                REGOFF(lr),        RINT,                'X'},
       +        {"CR",                REGOFF(cr),        RINT,                'X'},
       +        {"XER",                REGOFF(xer),        RINT,                'X'},
       +        {"CTR",                REGOFF(ctr),        RINT,                'X'},
       +        {"PC",                PC,                RINT,                'X'},
       +        {"SP",                SP,                RINT,                'X'},
       +        {"R0",                REGOFF(r0),        RINT,                'X'},
       +        /* R1 is SP */
       +        {"R2",                REGOFF(r2),        RINT,                'X'},
       +        {"R3",                REGOFF(r3),        RINT,                'X'},
       +        {"R4",                REGOFF(r4),        RINT,                'X'},
       +        {"R5",                REGOFF(r5),        RINT,                'X'},
       +        {"R6",                REGOFF(r6),        RINT,                'X'},
       +        {"R7",                REGOFF(r7),        RINT,                'X'},
       +        {"R8",                REGOFF(r8),        RINT,                'X'},
       +        {"R9",                REGOFF(r9),        RINT,                'X'},
       +        {"R10",                REGOFF(r10),        RINT,                'X'},
       +        {"R11",                REGOFF(r11),        RINT,                'X'},
       +        {"R12",                REGOFF(r12),        RINT,                'X'},
       +        {"R13",                REGOFF(r13),        RINT,                'X'},
       +        {"R14",                REGOFF(r14),        RINT,                'X'},
       +        {"R15",                REGOFF(r15),        RINT,                'X'},
       +        {"R16",                REGOFF(r16),        RINT,                'X'},
       +        {"R17",                REGOFF(r17),        RINT,                'X'},
       +        {"R18",                REGOFF(r18),        RINT,                'X'},
       +        {"R19",                REGOFF(r19),        RINT,                'X'},
       +        {"R20",                REGOFF(r20),        RINT,                'X'},
       +        {"R21",                REGOFF(r21),        RINT,                'X'},
       +        {"R22",                REGOFF(r22),        RINT,                'X'},
       +        {"R23",                REGOFF(r23),        RINT,                'X'},
       +        {"R24",                REGOFF(r24),        RINT,                'X'},
       +        {"R25",                REGOFF(r25),        RINT,                'X'},
       +        {"R26",                REGOFF(r26),        RINT,                'X'},
       +        {"R27",                REGOFF(r27),        RINT,                'X'},
       +        {"R28",                REGOFF(r28),        RINT,                'X'},
       +        {"R29",                REGOFF(r29),        RINT,                'X'},
       +        {"R30",                REGOFF(r30),        RINT,                'X'},
       +        {"R31",                REGOFF(r31),        RINT,                'X'},
       +        {"VRSAVE",        REGOFF(vrsave),        RINT,        'X'},
       +        {"F0",                FP_REG(0),        RFLT,                'F'},
       +        {"F1",                FP_REG(1),        RFLT,                'F'},
       +        {"F2",                FP_REG(2),        RFLT,                'F'},
       +        {"F3",                FP_REG(3),        RFLT,                'F'},
       +        {"F4",                FP_REG(4),        RFLT,                'F'},
       +        {"F5",                FP_REG(5),        RFLT,                'F'},
       +        {"F6",                FP_REG(6),        RFLT,                'F'},
       +        {"F7",                FP_REG(7),        RFLT,                'F'},
       +        {"F8",                FP_REG(8),        RFLT,                'F'},
       +        {"F9",                FP_REG(9),        RFLT,                'F'},
       +        {"F10",                FP_REG(10),        RFLT,                'F'},
       +        {"F11",                FP_REG(11),        RFLT,                'F'},
       +        {"F12",                FP_REG(12),        RFLT,                'F'},
       +        {"F13",                FP_REG(13),        RFLT,                'F'},
       +        {"F14",                FP_REG(14),        RFLT,                'F'},
       +        {"F15",                FP_REG(15),        RFLT,                'F'},
       +        {"F16",                FP_REG(16),        RFLT,                'F'},
       +        {"F17",                FP_REG(17),        RFLT,                'F'},
       +        {"F18",                FP_REG(18),        RFLT,                'F'},
       +        {"F19",                FP_REG(19),        RFLT,                'F'},
       +        {"F20",                FP_REG(20),        RFLT,                'F'},
       +        {"F21",                FP_REG(21),        RFLT,                'F'},
       +        {"F22",                FP_REG(22),        RFLT,                'F'},
       +        {"F23",                FP_REG(23),        RFLT,                'F'},
       +        {"F24",                FP_REG(24),        RFLT,                'F'},
       +        {"F25",                FP_REG(25),        RFLT,                'F'},
       +        {"F26",                FP_REG(26),        RFLT,                'F'},
       +        {"F27",                FP_REG(27),        RFLT,                'F'},
       +        {"F28",                FP_REG(28),        RFLT,                'F'},
       +        {"F29",                FP_REG(29),        RFLT,                'F'},
       +        {"F30",                FP_REG(30),        RFLT,                'F'},
       +        {"F31",                FP_REG(31),        RFLT,                'F'},
       +        {"FPSCR",        FP_REG(32)+4,        RFLT,                'X'},
       +        {  0 }
       +};
       +
       +static char *powerwindregs[] = 
       +{
       +        "PC",
       +        "SP",
       +        "LR",
       +        0,
       +};
       +
       +static int
       +powerunwind(Map *map, Regs *regs, ulong *next)
       +{
       +        /*
       +         * This is tremendously hard.  The best we're going to
       +         * do without better debugger support is trace through
       +         * the stack frame links and pull the link registers out of 8(R1).
       +         * Anything more requires knowing which registers got saved,
       +         * and the compiler appears not to record that.  Gdb appears
       +         * to disassemble the function prologues in order to figure
       +         * this out.
       +         */
       +        ulong b[2];
       +
       +        // evaluate lr
       +        // if in this function, no good - go to saved one.
       +        // set next[sp] to *cur[sp]
       +        // set next[pc] to lr
       +        // set next[lr] to lr
       +        // 
       +        werrstr("powerunwind not implemented");
       +        return -1;
       +}
       +
       +        /* the machine description */
       +Mach machpower =
       +{
       +        "power",
       +        MPOWER,                /* machine type */
       +        powerreglist,        /* register set */
       +        REGSIZE,        /* number of bytes in register set */
       +        FPREGSIZE,        /* number of bytes in FP register set */
       +        "PC",                /* name of PC */
       +        "SP",                /* name of SP */
       +        0,                /* name of FP */
       +        "LR",                /* name of link register */
       +        "setSB",        /* static base register name */
       +        0,                /* value */
       +        0x1000,                /* page size */
       +        0x80000000,        /* kernel base */
       +        0,                /* kernel text mask */
       +        4,                /* quantization of pc */
       +        4,                /* szaddr */
       +        4,                /* szreg */
       +        4,                /* szfloat */
       +        8,                /* szdouble */
       +
       +        powerwindregs,        /* locations unwound in stack trace */
       +        3,
       +
       +        {0x02, 0x8F, 0xFF, 0xFF},        /* break point */ /* BUG */
       +        4,
       +
       +        powerfoll,                /* following addresses */
       +        powerexcep,                /* print exception */
       +        powerunwind,                /* stack unwind */
       +
       +        beswap2,                        /* convert short to local byte order */
       +        beswap4,                        /* convert long to local byte order */
       +        beswap8,                        /* convert vlong to local byte order */
       +        beieeeftoa32,                /* single precision float pointer */
       +        beieeeftoa64,                /* double precision float pointer */
       +        beieeeftoa80,                /* long double precision floating point */
       +
       +        powerdas,                /* dissembler */
       +        powerdas,                /* plan9-format disassembler */
       +        0,                        /* commercial disassembler */
       +        powerhexinst,                /* print instruction */
       +        powerinstlen,                /* instruction size calculation */
       +};
       +
   DIR diff --git a/src/libmach/map.c b/src/libmach/map.c
       t@@ -0,0 +1,306 @@
       +/*
       + * File map routines
       + */
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include <mach.h>
       +
       +static int fdrw(Map*, Seg*, ulong, void*, uint, int);
       +static int zerorw(Map*, Seg*, ulong, void*, uint, int);
       +static int mrw(Map*, ulong, void*, uint, int);
       +static int datarw(Map*, Seg*, ulong, void*, uint, int);
       +
       +Map*
       +allocmap(void)
       +{
       +        return mallocz(sizeof(Map), 1);
       +}
       +
       +void
       +freemap(Map *map)
       +{
       +        if(map == nil)
       +                return;
       +        free(map->seg);
       +        free(map);
       +}
       +
       +int
       +addseg(Map *map, Seg seg)
       +{
       +        Seg *ss;
       +
       +        if(map == 0){
       +                werrstr("invalid map");
       +                return -1;
       +        }
       +
       +        ss = realloc(map->seg, (map->nseg+1)*sizeof(ss[0]));
       +        if(ss == nil)
       +                return -1;
       +        map->seg = ss;
       +        if(seg.rw == nil){
       +                if(seg.name && strcmp(seg.name, "zero") == 0)
       +                        seg.rw = zerorw;
       +                else if(seg.p)
       +                        seg.rw = datarw;
       +                else
       +                        seg.rw = fdrw;
       +        }
       +        map->seg[map->nseg] = seg;
       +        return map->nseg++;
       +}
       +
       +int
       +findseg(Map *map, char *name, char *file)
       +{
       +        int i;
       +
       +        if(map == 0)
       +                return -1;
       +        for(i=0; i<map->nseg; i++){
       +                if(name && (!map->seg[i].name || strcmp(map->seg[i].name, name) != 0))
       +                        continue;
       +                if(file && (!map->seg[i].file || strcmp(map->seg[i].file, file) != 0))
       +                        continue;
       +                return i;
       +        }
       +        werrstr("segment %s in %s not found", name, file);
       +        return -1;
       +}
       +
       +int
       +addrtoseg(Map *map, ulong addr, Seg *sp)
       +{
       +        int i;
       +        Seg *s;
       +
       +        if(map == nil){
       +                werrstr("no map");
       +                return -1;
       +        }
       +        for(i=map->nseg-1; i>=0; i--){
       +                s = &map->seg[i];
       +                if(s->base <= addr && addr-s->base < s->size){
       +                        if(sp)
       +                                *sp = *s;
       +                        return i;
       +                }
       +        }
       +        werrstr("address 0x%lux is not mapped", addr);
       +        return -1;
       +}
       +
       +int
       +addrtosegafter(Map *map, ulong addr, Seg *sp)
       +{
       +        int i;
       +        Seg *s, *best;
       +        ulong bdist;
       +
       +        if(map == nil){
       +                werrstr("no map");
       +                return -1;
       +        }
       +
       +        /*
       +         * If segments were sorted this would be easier,
       +         * but since segments may overlap, sorting also
       +         * requires splitting and rejoining, and that's just
       +         * too complicated.
       +         */
       +        best = nil;
       +        bdist = 0;
       +        for(i=map->nseg-1; i>=0; i--){
       +                s = &map->seg[i];
       +                if(s->base > addr){
       +                        if(best==nil || s->base-addr < bdist){
       +                                bdist = s->base - addr;
       +                                best = s;
       +                        }
       +                }
       +        }
       +        if(best){
       +                if(sp)
       +                        *sp = *best;
       +                return best-map->seg;
       +        }
       +        werrstr("nothing mapped after address 0x%lux", addr);
       +        return -1;
       +}
       +
       +void
       +removeseg(Map *map, int i)
       +{
       +        if(map == nil)
       +                return;
       +        if(i < 0 || i >= map->nseg)
       +                return;
       +        memmove(&map->seg[i], &map->seg[i+1], (map->nseg-(i+1))*sizeof(Seg));
       +        map->nseg--;
       +}
       +
       +int
       +get1(Map *map, ulong addr, uchar *a, uint n)
       +{
       +        return mrw(map, addr, a, n, 1);
       +}
       +
       +int
       +get2(Map *map, ulong addr, u16int *u)
       +{
       +        u16int v;
       +
       +        if(mrw(map, addr, &v, 2, 1) < 0)
       +                return -1;
       +        *u = mach->swap2(v);
       +        return 2;
       +}
       +
       +int
       +get4(Map *map, ulong addr, u32int *u)
       +{
       +        u32int v;
       +
       +        if(mrw(map, addr, &v, 4, 1) < 0)
       +                return -1;
       +        *u = mach->swap4(v);
       +        return 4;
       +}
       +
       +int
       +get8(Map *map, ulong addr, u64int *u)
       +{
       +        u64int v;
       +
       +        if(mrw(map, addr, &v, 4, 1) < 0)
       +                return -1;
       +        *u = mach->swap8(v);
       +        return 8;
       +}
       +
       +int
       +put1(Map *map, ulong addr, uchar *a, uint n)
       +{
       +        return mrw(map, addr, a, n, 0);
       +}
       +
       +int
       +put2(Map *map, ulong addr, u16int u)
       +{
       +        u = mach->swap2(u);
       +        return mrw(map, addr, &u, 2, 0);
       +}
       +
       +int
       +put4(Map *map, ulong addr, u32int u)
       +{
       +        u = mach->swap4(u);
       +        return mrw(map, addr, &u, 4, 0);
       +}
       +
       +int
       +put8(Map *map, ulong addr, u64int u)
       +{
       +        u = mach->swap8(u);
       +        return mrw(map, addr, &u, 8, 0);
       +}
       +
       +static Seg*
       +reloc(Map *map, ulong addr, uint n, ulong *off, uint *nn)
       +{
       +        int i;
       +        ulong o;
       +
       +        if(map == nil){
       +                werrstr("invalid map");
       +                return nil;
       +        }
       +
       +        for(i=map->nseg-1; i>=0; i--){
       +                if(map->seg[i].base <= addr){
       +                        o = addr - map->seg[i].base;
       +                        if(o >= map->seg[i].size)
       +                                continue;
       +                        if(o+n > map->seg[i].size)
       +                                *nn = map->seg[i].size - o;
       +                        else
       +                                *nn = n;
       +                        *off = o;
       +                        return &map->seg[i];
       +                }
       +        }
       +        werrstr("address 0x%lux not mapped", addr);
       +        return nil;
       +}
       +
       +static int
       +mrw(Map *map, ulong addr, void *a, uint n, int r)
       +{
       +        uint nn;
       +        uint tot;
       +        Seg *s;
       +        ulong off;
       +
       +        for(tot=0; tot<n; tot+=nn){
       +                s = reloc(map, addr+tot, n-tot, &off, &nn);
       +                if(s == nil)
       +                        return -1;
       +                if(s->rw(map, s, off, a, nn, r) < 0)
       +                        return -1;
       +        }
       +        return 0;
       +}
       +
       +static int
       +fdrw(Map *map, Seg *seg, ulong addr, void *a, uint n, int r)
       +{
       +        int nn;
       +        uint tot;
       +        ulong off;
       +
       +        USED(map);
       +        off = seg->offset + addr;
       +        for(tot=0; tot<n; tot+=nn){
       +                if(r)
       +                        nn = pread(seg->fd, a, n-tot, off+tot);
       +                else
       +                        nn = pwrite(seg->fd, a, n-tot, off+tot);
       +                if(nn < 0)
       +                        return -1;        
       +                if(nn == 0){
       +                        werrstr("partial %s at address 0x%lux in %s",
       +                                r ? "read" : "write", off+tot, seg->file);
       +                        return -1;
       +                }
       +        }
       +        return 0;
       +}
       +
       +static int
       +zerorw(Map *map, Seg *seg, ulong addr, void *a, uint n, int r)
       +{
       +        USED(map);
       +        USED(seg);
       +        USED(addr);
       +
       +        if(r==0){
       +                werrstr("cannot write zero segment");
       +                return -1;
       +        }
       +        memset(a, 0, n);
       +        return 0;
       +}
       +
       +static int
       +datarw(Map *map, Seg *seg, ulong addr, void *a, uint n, int r)
       +{
       +        USED(map);
       +
       +        if(r)
       +                memmove(a, seg->p+addr, n);
       +        else
       +                memmove(seg->p+addr, a, n);
       +        return 0;
       +}
   DIR diff --git a/src/libmach/mkfile b/src/libmach/mkfile
       t@@ -0,0 +1,58 @@
       +<$PLAN9/src/mkhdr
       +
       +LIB=libmach.a
       +
       +OFILES=\
       +        $SYSNAME.$O\
       +        crack.$O\
       +        crackelf.$O\
       +        crackmacho.$O\
       +        dwarf386.$O\
       +        dwarfabbrev.$O\
       +        dwarfaranges.$O\
       +        dwarfcfa.$O\
       +        dwarfget.$O\
       +        dwarfinfo.$O\
       +        dwarfopen.$O\
       +        dwarfpc.$O\
       +        dwarfpubnames.$O\
       +        elf.$O\
       +        elfcorefreebsd386.$O\
       +        elfcorelinux386.$O\
       +        frame.$O\
       +        fpformat.$O\
       +        hexify.$O\
       +        ieee.$O\
       +        loc.$O\
       +        localaddr.$O\
       +        mach.$O\
       +        mach386.$O\
       +        macho.$O\
       +        machocorepower.$O\
       +        machpower.$O\
       +        map.$O\
       +        regs.$O\
       +        stabs.$O\
       +        swap.$O\
       +        sym.$O\
       +        symdwarf.$O\
       +        symelf.$O\
       +        symmacho.$O\
       +        symstabs.$O\
       +
       +HFILES=mach.h
       +
       +<$PLAN9/src/mksyslib
       +CFLAGS=$CFLAGS -I.
       +
       +elfdump: elfdump.o $LIBDIR/$LIB
       +        $LD -o $target $prereq -l9
       +
       +machodump: machodump.o $LIBDIR/$LIB
       +        $LD -o $target $prereq -l9
       +
       +dwarfdump: dwarfdump.o $LIBDIR/$LIB
       +        $LD -o $target $prereq -l9
       +
       +nm: nm.o $LIBDIR/$LIB
       +        $LD -o $target $prereq -l9
   DIR diff --git a/src/libmach/nm.c b/src/libmach/nm.c
       t@@ -0,0 +1,289 @@
       +/*
       + * nm.c -- drive nm
       + */
       +#include <u.h>
       +#include <libc.h>
       +#include <ar.h>
       +#include <bio.h>
       +#include <mach.h>
       +
       +enum{
       +        CHUNK        =        256        /* must be power of 2 */
       +};
       +
       +char        *errs;                        /* exit status */
       +char        *filename;                /* current file */
       +char        symname[]="__.SYMDEF";        /* table of contents file name */
       +int        multifile;                /* processing multiple files */
       +int        aflag;
       +int        gflag;
       +int        hflag;
       +int        nflag;
       +int        sflag;
       +int        uflag;
       +
       +Symbol        **fnames;                /* file path translation table */
       +Symbol        **symptr;
       +int        nsym;
       +Biobuf        bout;
       +
       +int        cmp(void*, void*);
       +void        error(char*, ...);
       +void        execsyms(int);
       +void        psym(Symbol*, void*);
       +void        printsyms(Symbol**, long);
       +void        doar(Biobuf*);
       +void        dofile(Biobuf*);
       +void        zenter(Symbol*);
       +
       +void
       +main(int argc, char *argv[])
       +{
       +        int i;
       +        Biobuf        *bin;
       +
       +        Binit(&bout, 1, OWRITE);
       +        argv0 = argv[0];
       +        ARGBEGIN {
       +        case 'a':        aflag = 1; break;
       +        case 'g':        gflag = 1; break;
       +        case 'h':        hflag = 1; break;
       +        case 'n':        nflag = 1; break;
       +        case 's':        sflag = 1; break;
       +        case 'u':        uflag = 1; break;
       +        } ARGEND
       +        if (argc > 1)
       +                multifile++;
       +        for(i=0; i<argc; i++){
       +                filename = argv[i];
       +                bin = Bopen(filename, OREAD);
       +                if(bin == 0){
       +                        error("cannot open %s", filename);
       +                        continue;
       +                }
       +                if (isar(bin))
       +                        doar(bin);
       +                else{
       +                        Bseek(bin, 0, 0);
       +                        dofile(bin);
       +                }
       +                Bterm(bin);
       +        }
       +        exits(errs);
       +}
       +
       +/*
       + * read an archive file,
       + * processing the symbols for each intermediate file in it.
       + */
       +void
       +doar(Biobuf *bp)
       +{
       +        int offset, size, obj;
       +        char membername[SARNAME];
       +
       +        multifile = 1;
       +        for (offset = Boffset(bp);;offset += size) {
       +                size = nextar(bp, offset, membername);
       +                if (size < 0) {
       +                        error("phase error on ar header %ld", offset);
       +                        return;
       +                }
       +                if (size == 0)
       +                        return;
       +                if (strcmp(membername, symname) == 0)
       +                        continue;
       +                obj = objtype(bp, 0);
       +                if (obj < 0) {
       +                        error("inconsistent file %s in %s",
       +                                        membername, filename);
       +                        return;
       +                }
       +                if (!readar(bp, obj, offset+size, 1)) {
       +                        error("invalid symbol reference in file %s",
       +                                        membername);
       +                        return;
       +                }
       +                filename = membername;
       +                nsym=0;
       +                objtraverse(psym, 0);
       +                printsyms(symptr, nsym);
       +        }
       +}
       +
       +/*
       + * process symbols in a file
       + */
       +void
       +dofile(Biobuf *bp)
       +{
       +        int obj;
       +
       +        obj = objtype(bp, 0);
       +        if (obj < 0)
       +                execsyms(Bfildes(bp));
       +        else
       +        if (readobj(bp, obj)) {
       +                nsym = 0;
       +                objtraverse(psym, 0);
       +                printsyms(symptr, nsym);
       +        }
       +}
       +
       +/*
       + * comparison routine for sorting the symbol table
       + *        this screws up on 'z' records when aflag == 1
       + */
       +int
       +cmp(void *vs, void *vt)
       +{
       +        Symbol **s, **t;
       +
       +        s = vs;
       +        t = vt;
       +        if(nflag)
       +                if((*s)->value < (*t)->value)
       +                        return -1;
       +                else
       +                        return (*s)->value > (*t)->value;
       +        return strcmp((*s)->name, (*t)->name);
       +}
       +/*
       + * enter a symbol in the table of filename elements
       + */
       +void
       +zenter(Symbol *s)
       +{
       +        static int maxf = 0;
       +
       +        if (s->value > maxf) {
       +                maxf = (s->value+CHUNK-1) &~ (CHUNK-1);
       +                fnames = realloc(fnames, (maxf+1)*sizeof(*fnames));
       +                if(fnames == 0) {
       +                        error("out of memory", argv0);
       +                        exits("memory");
       +                }
       +        }
       +        fnames[s->value] = s;
       +}
       +
       +/*
       + * get the symbol table from an executable file, if it has one
       + */
       +void
       +execsyms(int fd)
       +{
       +        Fhdr f;
       +        Symbol *s;
       +        long n;
       +
       +        seek(fd, 0, 0);
       +        if (crackhdr(fd, &f) == 0) {
       +                error("Can't read header for %s", filename);
       +                return;
       +        }
       +        if (syminit(fd, &f) < 0)
       +                return;
       +        s = symbase(&n);
       +        nsym = 0;
       +        while(n--)
       +                psym(s++, 0);
       +
       +        printsyms(symptr, nsym);
       +}
       +
       +void
       +psym(Symbol *s, void* p)
       +{
       +        USED(p);
       +        switch(s->type) {
       +        case 'T':
       +        case 'L':
       +        case 'D':
       +        case 'B':
       +                if (uflag)
       +                        return;
       +                if (!aflag && ((s->name[0] == '.' || s->name[0] == '$')))
       +                        return;
       +                break;
       +        case 'b':
       +        case 'd':
       +        case 'l':
       +        case 't':
       +                if (uflag || gflag)
       +                        return;
       +                if (!aflag && ((s->name[0] == '.' || s->name[0] == '$')))
       +                        return;
       +                break;
       +        case 'U':
       +                if (gflag)
       +                        return;
       +                break;
       +        case 'Z':
       +                if (!aflag)
       +                        return;
       +                break;
       +        case 'm':
       +        case 'f':        /* we only see a 'z' when the following is true*/
       +                if(!aflag || uflag || gflag)
       +                        return;
       +                if (strcmp(s->name, ".frame"))
       +                        zenter(s);
       +                break;
       +        case 'a':
       +        case 'p':
       +        case 'z':
       +        default:
       +                if(!aflag || uflag || gflag)
       +                        return;
       +                break;
       +        }
       +        symptr = realloc(symptr, (nsym+1)*sizeof(Sym*));
       +        if (symptr == 0) {
       +                error("out of memory");
       +                exits("memory");
       +        }
       +        symptr[nsym++] = s;
       +}
       +
       +void
       +printsyms(Symbol **symptr, long nsym)
       +{
       +        Symbol *s;
       +        char *cp;
       +        char path[512];
       +
       +        if(!sflag)
       +                qsort(symptr, nsym, sizeof(*symptr), cmp);
       +        while (nsym-- > 0) {
       +                s = *symptr++;
       +                if (multifile && !hflag)
       +                        Bprint(&bout, "%s:", filename);
       +                if (s->type == 'z') {
       +                        fileelem(fnames, (uchar *) s->name, path, 512);
       +                        cp = path;
       +                } else
       +                        cp = s->name;
       +                if (s->value || s->type == 'a' || s->type == 'p')
       +                        Bprint(&bout, "%8lux %c %s\n", s->value, s->type, cp);
       +                else
       +                        Bprint(&bout, "         %c %s\n", s->type, cp);
       +        }
       +}
       +
       +void
       +error(char *fmt, ...)
       +{
       +        Fmt f;
       +        char buf[128];
       +        va_list arg;
       +
       +        fmtfdinit(&f, 2, buf, sizeof buf);
       +        fmtprint(&f, "%s: ", argv0);
       +        va_start(arg, fmt);
       +        fmtvprint(&f, fmt, arg);
       +        va_end(arg);
       +        fmtprint(&f, "\n");
       +        fmtfdflush(&f);
       +        errs = "errors";
       +}
   DIR diff --git a/src/libmach/regs.c b/src/libmach/regs.c
       t@@ -0,0 +1,59 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <mach.h>
       +
       +int
       +rput(Regs *regs, char *name, ulong u)
       +{
       +        if(regs == nil){
       +                werrstr("registers not mapped");
       +                return -1;
       +        }
       +        return regs->rw(regs, name, &u, 0);
       +}
       +
       +int
       +rget(Regs *regs, char *name, ulong *u)
       +{
       +        if(regs == nil){
       +                *u = ~(ulong)0;
       +                werrstr("registers not mapped");
       +                return -1;
       +        }
       +        return regs->rw(regs, name, u, 1);
       +}
       +
       +int
       +_uregrw(Regs *regs, char *name, ulong *u, int isr)
       +{
       +        Regdesc *r;
       +        uchar *ureg;
       +
       +        if(!isr){
       +                werrstr("cannot write registers");
       +                return -1;
       +        }
       +
       +        if((r = regdesc(name)) == nil)
       +                return -1;
       +        ureg = ((UregRegs*)regs)->ureg + r->offset;
       +
       +        switch(r->format){
       +        default:
       +        case 'X':
       +                *u = mach->swap4(*(u32int*)ureg);
       +                return 0;
       +        }
       +}
       +
       +Regdesc*
       +regdesc(char *name)
       +{
       +        Regdesc *r;
       +
       +        for(r=mach->reglist; r->name; r++)
       +                if(strcmp(r->name, name) == 0)
       +                        return r;
       +        return nil;
       +}
       +
   DIR diff --git a/src/libmach/stabs.c b/src/libmach/stabs.c
       t@@ -0,0 +1,54 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <mach.h>
       +#include "stabs.h"
       +
       +/*
       +http://sources.redhat.com/gdb/onlinedocs/stabs.html
       +*/
       +
       +int
       +stabsym(Stab *stabs, int i, StabSym *sym)
       +{
       +        uchar *p;
       +        ulong x;
       +
       +        if(stabs == nil){
       +                werrstr("no stabs");
       +                return -1;
       +        }
       +        if(stabs->e2==nil || stabs->e4==nil){
       +                werrstr("no data extractors");
       +                return -1;
       +        }
       +
       +        if(i >= stabs->stabsize/12){
       +                werrstr("stabs index out of range");
       +                return -1;
       +        }
       +
       +        p = stabs->stabbase+i*12;
       +        x = stabs->e4(p);
       +        if(x == 0)
       +                sym->name = nil;
       +        else if(x < stabs->strsize)
       +                sym->name = stabs->strbase+x;
       +        else{
       +                werrstr("bad stabs string index");
       +                return -1;
       +        }
       +
       +        /*
       +         * In theory, if name ends with a backslash,
       +         * it continues into the next entry.  We could
       +         * rewrite these in place and then zero the next
       +         * few entries, but let's wait until we run across
       +         * some system that generates these.
       +         */
       +        sym->type = p[4];
       +        sym->other = p[5];
       +        sym->desc = stabs->e2(p+6);
       +        sym->value = stabs->e4(p+8);
       +        return 0;
       +}
       +
   DIR diff --git a/src/libmach/stabs.h b/src/libmach/stabs.h
       t@@ -0,0 +1,117 @@
       +typedef struct StabSym StabSym;
       +typedef struct Stab Stab;        /* defined in mach.h */
       +
       +struct StabSym
       +{
       +        char *name;
       +        uchar type;
       +        uchar other;
       +        u16int desc;
       +        u32int value;
       +};
       +
       +enum
       +{
       +        EXT = 0x01,
       +
       +        N_UNDEF = 0x00,
       +        N_ABS = 0x02,
       +        N_TEXT = 0x04,
       +        N_DATA = 0x06,
       +        N_BSS = 0x08,
       +        N_INDR = 0x0A,
       +        N_FN_SEQ = 0x0C,
       +        N_WEAKU = 0x0D,
       +        N_WEAKA = 0x0E,
       +        N_WEAKT = 0x0F,
       +        N_WEAKD = 0x10,
       +        N_WEAKB = 0x11,
       +        N_COMM = 0x12,
       +        N_SETA = 0x14,
       +        N_SETT = 0x16,
       +
       +        N_GSYM = 0x20,
       +        N_FNAME = 0x22,
       +        N_FUN = 0x24,
       +        N_STSYM = 0x26,
       +        N_LCSYM = 0x28,
       +        N_MAIN = 0x2A,
       +        N_ROSYM = 0x2C,
       +        N_PC = 0x30,
       +        N_NSYMS = 0x32,
       +        N_NOMAP = 0x34,
       +        N_OBJ = 0x38,
       +        N_OPT = 0x3C,
       +        N_RSYM = 0x40,
       +        N_M2C = 0x42,
       +        N_SLINE = 0x44,
       +        N_DSLINE = 0x46,
       +        N_BSLINE = 0x48,
       +        N_BROWS = 0x48,
       +        N_DEFD = 0x4A,
       +        N_FLINE = 0x4C,
       +        N_EHDECL = 0x50,
       +        N_MOD2 = 0x50,
       +        N_CATCH = 0x54,
       +        N_SSYM = 0x60,
       +        N_ENDM = 0x62,
       +        N_SO = 0x64,
       +        N_ALIAS = 0x6C,
       +        N_LSYM = 0x80,
       +        N_BINCL = 0x82,
       +        N_SOL = 0x84,
       +        N_PSYM = 0xA0,
       +        N_EINCL = 0xA2,
       +        N_ENTRY = 0xA4,
       +        N_LBRAC = 0xC0,
       +        N_EXCL = 0xC2,
       +        N_SCOPE = 0xC4,
       +        N_RBRAC = 0xE0,
       +        N_BCOMM = 0xE2,
       +        N_ECOMM = 0xE4,
       +        N_ECOML = 0xE8,
       +        N_WITH = 0xEA,
       +        N_LENG = 0xFE
       +};
       +
       +/*
       + symbol descriptors
       +
       +[(0-9\-]        variable on stack
       +:                C++ nested symbol
       +a                parameter by reference
       +b                based variable
       +c                constant
       +C                conformant array bound
       +                name of caught exception (N_CATCH)
       +d                fp register variable
       +D                fp parameter
       +f                file scope function
       +F                global function
       +G                global variable
       +i                register parameter?
       +I                nested procedure
       +J                nested function
       +L                label name
       +m                module
       +p                arg list parameter
       +pP
       +pF
       +P                register param (N_PSYM)
       +                proto of ref fun (N_FUN)
       +Q                static procedure
       +R                register param
       +r                register variable
       +S                file scope variable
       +s                local variable
       +t                type name
       +T                sue tag
       +v                param by reference
       +V                procedure scope static variable
       +x                conformant array
       +X                function return variable
       +
       +*/
       +
       +int stabsym(Stab*, int, StabSym*);
       +
   DIR diff --git a/src/libmach/swap.c b/src/libmach/swap.c
       t@@ -0,0 +1,118 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include <mach.h>
       +
       +/*
       + * big-endian short
       + */
       +u16int
       +beswap2(u16int s)
       +{
       +        uchar *p;
       +
       +        p = (uchar*)&s;
       +        return (p[0]<<8) | p[1];
       +}
       +
       +/*
       + * big-endian long
       + */
       +u32int
       +beswap4(u32int l)
       +{
       +        uchar *p;
       +
       +        p = (uchar*)&l;
       +        return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
       +}
       +
       +/*
       + * big-endian vlong
       + */
       +u64int
       +beswap8(u64int v)
       +{
       +        uchar *p;
       +
       +        p = (uchar*)&v;
       +        return ((u64int)p[0]<<56) | ((u64int)p[1]<<48) | ((u64int)p[2]<<40)
       +                                 | ((u64int)p[3]<<32) | ((u64int)p[4]<<24)
       +                                 | ((u64int)p[5]<<16) | ((u64int)p[6]<<8)
       +                                 | (u64int)p[7];
       +}
       +
       +/*
       + * little-endian short
       + */
       +u16int
       +leswap2(u16int s)
       +{
       +        uchar *p;
       +
       +        p = (uchar*)&s;
       +        return (p[1]<<8) | p[0];
       +}
       +
       +/*
       + * little-endian long
       + */
       +u32int
       +leswap4(u32int l)
       +{
       +        uchar *p;
       +
       +        p = (uchar*)&l;
       +        return (p[3]<<24) | (p[2]<<16) | (p[1]<<8) | p[0];
       +}
       +
       +/*
       + * little-endian vlong
       + */
       +u64int
       +leswap8(u64int v)
       +{
       +        uchar *p;
       +
       +        p = (uchar*)&v;
       +        return ((u64int)p[7]<<56) | ((u64int)p[6]<<48) | ((u64int)p[5]<<40)
       +                                 | ((u64int)p[4]<<32) | ((u64int)p[3]<<24)
       +                                 | ((u64int)p[2]<<16) | ((u64int)p[1]<<8)
       +                                 | (u64int)p[0];
       +}
       +
       +u16int
       +leload2(uchar *b)
       +{
       +        return b[0] | (b[1]<<8);
       +}
       +
       +u32int
       +leload4(uchar *b)
       +{
       +        return b[0] | (b[1]<<8) | (b[2]<<16) | (b[3]<<24);
       +}
       +
       +u64int
       +leload8(uchar *b)
       +{
       +        return leload4(b) | ((uvlong)leload4(b+4) << 32);
       +}
       +
       +u16int
       +beload2(uchar *b)
       +{
       +        return (b[0]<<8) | b[1];
       +}
       +
       +u32int
       +beload4(uchar *b)
       +{
       +        return (b[0]<<24) | (b[1]<<16) | (b[2]<<8) | b[3];
       +}
       +
       +u64int
       +beload8(uchar *b)
       +{
       +        return ((uvlong)beload4(b) << 32) | beload4(b+4);
       +}
   DIR diff --git a/src/libmach/sym.c b/src/libmach/sym.c
       t@@ -0,0 +1,478 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include <mach.h>
       +
       +int machdebug = 0;
       +
       +Fhdr *fhdrlist;
       +static Fhdr *last;
       +
       +static void
       +relocsym(Symbol *dst, Symbol *src, ulong base)
       +{
       +        if(dst != src)
       +                *dst = *src;
       +        if(dst->loc.type == LADDR)
       +                dst->loc.addr += base;
       +        if(dst->hiloc.type == LADDR)
       +                dst->hiloc.addr += base;
       +}
       +
       +void
       +_addhdr(Fhdr *h)
       +{
       +        h->next = nil;
       +        if(fhdrlist == nil){
       +                fhdrlist = h;
       +                last = h;
       +        }else{
       +                last->next = h;
       +                last = h;
       +        }
       +}
       +
       +void
       +_delhdr(Fhdr *h)
       +{
       +        Fhdr *p;
       +
       +        if(h == fhdrlist)
       +                fhdrlist = h->next;
       +        else{
       +                for(p=fhdrlist; p && p->next!=h; p=p->next)
       +                        ;
       +                if(p)
       +                        p->next = h->next;
       +                if(p->next == nil)
       +                        last = p;
       +        }
       +        h->next = nil;
       +}
       +
       +int
       +pc2file(ulong pc, char *file, uint nfile, ulong *line)
       +{
       +        Fhdr *p;
       +
       +        for(p=fhdrlist; p; p=p->next)
       +                if(p->pc2file && p->pc2file(p, pc-p->base, file, nfile, line) >= 0)
       +                        return 0;
       +        werrstr("no source file for 0x%lux", pc);
       +        return -1;
       +}
       +
       +int
       +pc2line(ulong pc, ulong *line)
       +{
       +        char tmp[10];        /* just in case */
       +        return pc2file(pc, tmp, sizeof tmp, line);
       +}
       +
       +int
       +file2pc(char *file, ulong line, ulong *addr)
       +{
       +        Fhdr *p;
       +
       +        for(p=fhdrlist; p; p=p->next)
       +                if(p->file2pc && p->file2pc(p, file, line, addr) >= 0){
       +                        *addr += p->base;
       +                        return 0;
       +                }
       +        werrstr("no instructions at %s:%lud", file, line);
       +        return -1;
       +}
       +
       +int
       +line2pc(ulong basepc, ulong line, ulong *pc)
       +{
       +        Fhdr *p;
       +
       +        for(p=fhdrlist; p; p=p->next)
       +                if(p->line2pc && p->line2pc(p, basepc-p->base, line, pc) >= 0){
       +                        *pc += p->base;
       +                        return 0;
       +                }
       +        werrstr("no instructions on line %lud", line);
       +        return -1;
       +}
       +
       +int
       +fnbound(ulong pc, ulong *bounds)
       +{
       +        Fhdr *p;
       +        Loc l;
       +        Symbol *s;
       +
       +        for(p=fhdrlist; p; p=p->next){
       +                l = locaddr(pc - p->base);
       +                if((s = ffindsym(p, l, CANY)) != nil){
       +                        if(s->loc.type != LADDR){
       +                                werrstr("function %s has weird location %L", s->name, s->loc);
       +                                return -1;
       +                        }
       +                        bounds[0] = s->loc.addr + p->base;
       +                        if(s->hiloc.type != LADDR){
       +                                werrstr("can't find upper bound for function %s", s->name);
       +                                return -1;
       +                        }
       +                        bounds[1] = s->hiloc.addr + p->base;
       +                        return 0;
       +                }
       +        }
       +        werrstr("no function contains 0x%lux", pc);
       +        return -1;
       +}
       +
       +int
       +fileline(ulong pc, char *a, uint n)
       +{
       +        ulong line;
       +
       +        if(pc2file(pc, a, n, &line) < 0)
       +                return -1;
       +        seprint(a+strlen(a), a+n, ":%lud", line);
       +        return 0;
       +}
       +
       +Symbol*
       +flookupsym(Fhdr *fhdr, char *name)
       +{
       +        Symbol **a, *t;
       +        uint n, m;
       +        int i;
       +
       +        a = fhdr->byname;
       +        n = fhdr->nsym;
       +        if(a == nil)
       +                return nil;
       +
       +        while(n > 0){
       +                m = n/2;
       +                t = a[m];
       +                i = strcmp(name, t->name);
       +                if(i < 0)
       +                        n = m;
       +                else if(i > 0){
       +                        n -= m+1;
       +                        a += m+1;
       +                }else{
       +                        /* found! */
       +                        m += a - fhdr->byname;
       +                        a = fhdr->byname;
       +                        assert(strcmp(name, a[m]->name) == 0);
       +                        while(m > 0 && strcmp(name, a[m-1]->name) == 0)
       +                                m--;
       +                        return a[m];
       +                }
       +        }
       +        return nil;
       +}
       +
       +int
       +lookupsym(char *fn, char *var, Symbol *s)
       +{
       +        Symbol *t, s1;
       +        Fhdr *p;
       +        char *nam;
       +
       +        nam = fn ? fn : var;
       +        if(nam == nil)
       +                return -1;
       +        t = nil;
       +        for(p=fhdrlist; p; p=p->next)
       +                if((t=flookupsym(p, nam)) != nil){
       +                        relocsym(&s1, t, p->base);
       +                        break;
       +                }
       +        if(t == nil)
       +                goto err;
       +        if(fn && var)
       +                return lookuplsym(&s1, var, s);
       +        *s = s1;
       +        return 0;
       +
       +err:
       +        werrstr("unknown symbol %s%s%s", fn ? fn : "",
       +                fn && var ? ":" : "", var ? var : "");
       +        return -1;
       +}
       +
       +int
       +findexsym(Fhdr *fp, uint i, Symbol *s)
       +{
       +        if(i >= fp->nsym)
       +                return -1;
       +        relocsym(s, &fp->sym[i], fp->base);
       +        return 0;
       +}
       +
       +int
       +indexsym(uint ndx, Symbol *s)
       +{
       +        uint t;
       +        Fhdr *p;
       +
       +        for(p=fhdrlist; p; p=p->next){
       +                t = p->nsym;
       +                if(t < ndx)
       +                        ndx -= t;
       +                else{
       +                        relocsym(s, &p->sym[ndx], p->base);
       +                        return 0;
       +                }
       +        }
       +        return -1;
       +}
       +
       +Symbol*
       +ffindsym(Fhdr *fhdr, Loc loc, uint class)
       +{
       +        Symbol *a, *t;
       +        int n, i, hi, lo;
       +        int cmp;
       +
       +        a = fhdr->sym;
       +        n = fhdr->nsym;
       +        if(a == nil || n <= 0)
       +                return nil;
       +
       +        /*
       +         * We have a list of possibly duplicate locations in a.
       +         * We want to find the largest index i such that
       +         * a[i] <= loc.  This cannot be done with a simple
       +         * binary search.  Instead we binary search to find
       +         * where the location should be. 
       +         */
       +        lo = 0;
       +        hi = n;
       +        while(lo < hi){
       +                i = (lo+hi)/2;
       +                cmp = loccmp(&loc, &a[i].loc);
       +                if(cmp < 0)        /* loc < a[i].loc */
       +                        hi = i;
       +                if(cmp > 0)        /* loc > a[i].loc */
       +                        lo = i+1;
       +                if(cmp == 0)
       +                        goto found;
       +        }
       +
       +        /* found position where value would go, but not there -- go back one */
       +        if(lo == 0)
       +                return nil;
       +        i = lo-1;
       +
       +found:
       +        /*
       +         * might be in a run of all-the-same -- go back to beginning of run.
       +         * if runs were long, could binary search for a[i].loc instead.
       +         */
       +        while(i > 0 && loccmp(&a[i-1].loc, &a[i].loc) == 0)
       +                i--;
       +
       +        t = &a[i];
       +        if(t->hiloc.type && loccmp(&loc, &t->hiloc) >= 0)
       +                return nil;
       +        if(class != CANY && class != t->class)
       +                return nil;
       +        return t;
       +}
       +
       +int
       +findsym(Loc loc, uint class, Symbol *s)
       +{
       +        Fhdr *p, *bestp;
       +        Symbol *t, *best;
       +        long bestd, d;
       +        Loc l;
       +
       +        l = loc;
       +        best = nil;
       +        bestp = nil;
       +        bestd = 0;
       +        for(p=fhdrlist; p; p=p->next){
       +                if(l.type == LADDR)
       +                        l.addr = loc.addr - p->base;
       +                if((t = ffindsym(p, l, CANY)) != nil){
       +                        d = l.addr - t->loc.addr;
       +                        if(d < 4096)
       +                        if(best == nil || d < bestd){
       +                                best = t;
       +                                bestp = p;
       +                                bestd = d;
       +                        }
       +                }
       +        }
       +        if(best){
       +                if(class != CANY && class != best->class)
       +                        goto err;
       +                relocsym(s, best, bestp->base);
       +                return 0;
       +        }
       +err:
       +        werrstr("could not find symbol at %L", loc);
       +        return -1;
       +}
       +
       +int
       +lookuplsym(Symbol *s1, char *name, Symbol *s2)
       +{
       +        Fhdr *p;
       +
       +        p = s1->fhdr;
       +        if(p->lookuplsym && p->lookuplsym(p, s1, name, s2) >= 0){
       +                relocsym(s2, s2, p->base);
       +                return 0;
       +        }
       +        return -1;
       +}
       +
       +int
       +indexlsym(Symbol *s1, uint ndx, Symbol *s2)
       +{
       +        Fhdr *p;
       +
       +        p = s1->fhdr;
       +        if(p->indexlsym && p->indexlsym(p, s1, ndx, s2) >= 0){
       +                relocsym(s2, s2, p->base);
       +                return 0;
       +        }
       +        return -1;
       +}
       +
       +int
       +findlsym(Symbol *s1, Loc loc, Symbol *s2)
       +{
       +        Fhdr *p;
       +
       +        p = s1->fhdr;
       +        if(p->findlsym && p->findlsym(p, s1, loc, s2) >= 0){
       +                relocsym(s2, s2, p->base);
       +                return 0;
       +        }
       +        return -1;
       +}
       +
       +int
       +unwindframe(Map *map, Regs *regs, ulong *next)
       +{
       +        Fhdr *p;
       +
       +        for(p=fhdrlist; p; p=p->next)
       +                if(p->unwind && p->unwind(p, map, regs, next) >= 0)
       +                        return 0;
       +        if(mach->unwind && mach->unwind(map, regs, next) >= 0)
       +                return 0;
       +        return -1;
       +}
       +
       +int
       +symoff(char *a, uint n, ulong addr, uint class)
       +{
       +        Loc l;
       +        Symbol s;
       +
       +        l.type = LADDR;
       +        l.addr = addr;
       +        if(findsym(l, class, &s) < 0 || addr-s.loc.addr >= 4096){
       +                snprint(a, n, "%lux", addr);
       +                return -1;
       +        }
       +        if(addr != s.loc.addr)
       +                snprint(a, n, "%s+%ld", s.name, addr-s.loc.addr);
       +        else
       +                snprint(a, n, "%s", s.name);
       +        return 0;
       +}
       +
       +/* location, class, name */
       +static int
       +byloccmp(const void *va, const void *vb)
       +{
       +        int i;
       +        Symbol *a, *b;
       +
       +        a = (Symbol*)va;
       +        b = (Symbol*)vb;
       +        i = loccmp(&a->loc, &b->loc);
       +        if(i != 0)
       +                return i;
       +        i = a->class - b->class;
       +        if(i != 0)
       +                return i;
       +        return strcmp(a->name, b->name);
       +}
       +
       +/* name, location, class */
       +static int
       +bynamecmp(const void *va, const void *vb)
       +{
       +        int i;
       +        Symbol *a, *b;
       +
       +        a = *(Symbol**)va;
       +        b = *(Symbol**)vb;
       +        i = strcmp(a->name, b->name);
       +        if(i != 0)
       +                return i;
       +        i = loccmp(&a->loc, &b->loc);
       +        if(i != 0)
       +                return i;
       +        return a->class - b->class;
       +}
       +
       +int
       +syminit(Fhdr *hdr)
       +{
       +        int i;
       +        Symbol *r, *w, *es;
       +
       +        if(hdr->syminit == nil){
       +                werrstr("no debugging symbols");
       +                return -1;
       +        }
       +        if(hdr->syminit(hdr) < 0)
       +                return -1;
       +
       +        qsort(hdr->sym, hdr->nsym, sizeof(hdr->sym[0]), byloccmp);
       +        es = hdr->sym+hdr->nsym;
       +        for(r=w=hdr->sym; r<es; r++){
       +                if(w > hdr->sym
       +                && strcmp((w-1)->name, r->name) ==0
       +                && loccmp(&(w-1)->loc, &r->loc) == 0){
       +                        /* skip it */
       +                }else
       +                        *w++ = *r;
       +        }
       +        hdr->nsym = w - hdr->sym;
       +
       +        hdr->byname = malloc(hdr->nsym*sizeof(hdr->byname[0]));
       +        if(hdr->byname == nil){
       +                fprint(2, "could not allocate table to sort by location\n");
       +        }else{
       +                for(i=0; i<hdr->nsym; i++)
       +                        hdr->byname[i] = &hdr->sym[i];
       +                qsort(hdr->byname, hdr->nsym, sizeof(hdr->byname[0]), bynamecmp);
       +        }
       +        return 0;
       +}
       +
       +Symbol*
       +addsym(Fhdr *fp, Symbol *sym)
       +{
       +        Symbol *s;
       +
       +        if(fp->nsym%128 == 0){
       +                s = realloc(fp->sym, (fp->nsym+128)*sizeof(fp->sym[0]));
       +                if(s == nil)
       +                        return nil;
       +                fp->sym = s;
       +        }
       +        if(machdebug)
       +                fprint(2, "sym %s %c %L\n", sym->name, sym->type, sym->loc);
       +        sym->fhdr = fp;
       +        s = &fp->sym[fp->nsym++];
       +        *s = *sym;
       +        return s;
       +}
       +
   DIR diff --git a/src/libmach/symdwarf.c b/src/libmach/symdwarf.c
       t@@ -0,0 +1,466 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <bio.h>
       +#include <mach.h>
       +#include "elf.h"
       +#include "dwarf.h"
       +
       +static void        dwarfsymclose(Fhdr*);
       +static int        dwarfpc2file(Fhdr*, ulong, char*, uint, ulong*);
       +static int        dwarfline2pc(Fhdr*, ulong, ulong, ulong*);
       +static int        dwarflookuplsym(Fhdr*, Symbol*, char*, Symbol*);
       +static int        dwarfindexlsym(Fhdr*, Symbol*, uint, Symbol*);
       +static int        dwarffindlsym(Fhdr*, Symbol*, Loc, Symbol*);
       +static void        dwarfsyminit(Fhdr*);
       +static int        dwarftosym(Fhdr*, Dwarf*, DwarfSym*, Symbol*, int);
       +static int        _dwarfunwind(Fhdr *fhdr, Map *map, Regs *regs, ulong *next);
       +
       +int
       +symdwarf(Fhdr *hdr)
       +{
       +        if(hdr->dwarf == nil){
       +                werrstr("no dwarf debugging symbols");
       +                return -1;
       +        }
       +
       +        hdr->symclose = dwarfsymclose;
       +        hdr->pc2file = dwarfpc2file;
       +        hdr->line2pc = dwarfline2pc;
       +        hdr->lookuplsym = dwarflookuplsym;
       +        hdr->indexlsym = dwarfindexlsym;
       +        hdr->findlsym = dwarffindlsym;
       +        hdr->unwind = _dwarfunwind;
       +        dwarfsyminit(hdr);
       +
       +        return 0;
       +}
       +
       +static void
       +dwarfsymclose(Fhdr *hdr)
       +{
       +        dwarfclose(hdr->dwarf);
       +        hdr->dwarf = nil;
       +}
       +
       +static int
       +dwarfpc2file(Fhdr *fhdr, ulong pc, char *buf, uint nbuf, ulong *line)
       +{
       +        char *cdir, *dir, *file;
       +
       +        if(dwarfpctoline(fhdr->dwarf, pc, &cdir, &dir, &file, line, nil, nil) < 0)
       +                return -1;
       +
       +        if(file[0] == '/' || (dir==nil && cdir==nil))
       +                strecpy(buf, buf+nbuf, file);
       +        else if((dir && dir[0] == '/') || cdir==nil)
       +                snprint(buf, nbuf, "%s/%s", dir, file);
       +        else
       +                snprint(buf, nbuf, "%s/%s/%s", cdir, dir ? dir : "", file);
       +        cleanname(buf);
       +        return 0;;
       +}
       +
       +static int
       +dwarfline2pc(Fhdr *fhdr, ulong basepc, ulong line, ulong *pc)
       +{
       +        werrstr("dwarf line2pc not implemented");
       +        return -1;
       +}
       +
       +static uint
       +typesize(Dwarf *dwarf, ulong unit, ulong tref, char *name)
       +{
       +        DwarfSym ds;
       +
       +top:
       +        if(dwarfseeksym(dwarf, unit, tref-unit, &ds) < 0){
       +        cannot:
       +                fprint(2, "warning: cannot compute size of parameter %s (%lud %lud: %r)\n",
       +                        name, unit, tref);
       +                return 0;
       +        }
       +        
       +        if(ds.attrs.have.bytesize)
       +                return ds.attrs.bytesize;
       +
       +        switch(ds.attrs.tag){
       +        case TagVolatileType:
       +        case TagRestrictType:
       +        case TagTypedef:
       +                if(ds.attrs.have.type != TReference)
       +                        goto cannot;
       +                tref = ds.attrs.type;
       +                goto top;
       +        }
       +
       +        goto cannot;
       +}
       +
       +static int
       +roundup(int s, int n)
       +{
       +        return (s+n-1)&~(n-1);
       +}
       +
       +static int
       +dwarflenum(Fhdr *fhdr, Symbol *p, char *name, uint j, Loc l, Symbol *s)
       +{
       +        int depth, bpoff;
       +        DwarfSym ds;
       +        Symbol s1;
       +
       +        if(p == nil)
       +                return -1;
       +
       +        if(dwarfseeksym(fhdr->dwarf, p->u.dwarf.unit, p->u.dwarf.uoff, &ds) < 0)
       +                return -1;
       +
       +        ds.depth = 1;
       +        depth = 1;
       +
       +        bpoff = 8;
       +        while(dwarfnextsym(fhdr->dwarf, &ds, 1) == 1 && depth < ds.depth){
       +                if(ds.attrs.tag != TagVariable){
       +                        if(ds.attrs.tag != TagFormalParameter
       +                        && ds.attrs.tag != TagUnspecifiedParameters)
       +                                continue;
       +                        if(ds.depth != depth+1)
       +                                continue;
       +                }
       +                if(dwarftosym(fhdr, fhdr->dwarf, &ds, &s1, 1) < 0)
       +                        continue;
       +                /* XXX move this out once there is another architecture */
       +                /*
       +                 * gcc tells us the registers where the parameters might be
       +                 * held for an instruction or two.  use the parameter list to
       +                 * recompute the actual stack locations.
       +                 */
       +                if(fhdr->mtype == M386)
       +                if(ds.attrs.tag==TagFormalParameter || ds.attrs.tag==TagUnspecifiedParameters){
       +                        if(s1.loc.type==LOFFSET
       +                        && strcmp(s1.loc.reg, "BP")==0
       +                        && s1.loc.offset >= 8)
       +                                bpoff = s1.loc.offset;
       +                        else{
       +                                s1.loc.type = LOFFSET;
       +                                s1.loc.reg = "BP";
       +                                s1.loc.offset = bpoff;
       +                        }
       +                        if(ds.attrs.tag == TagFormalParameter){
       +                                if(ds.attrs.have.type)
       +                                        bpoff += roundup(typesize(fhdr->dwarf, p->u.dwarf.unit, ds.attrs.type, s1.name), 4);
       +                                else
       +                                        fprint(2, "warning: cannot compute size of parameter %s\n", s1.name);
       +                        }
       +                }
       +                if(name){
       +                        if(strcmp(ds.attrs.name, name) != 0)
       +                                continue;
       +                }else if(l.type){
       +                        if(loccmp(&s1.loc, &l) != 0)
       +                                continue;
       +                }else{
       +                        if(j-- > 0)
       +                                continue;
       +                }
       +                *s = s1;
       +                return 0;
       +        }
       +        return -1;
       +}
       +
       +static Loc zl;
       +
       +static int
       +dwarflookuplsym(Fhdr *fhdr, Symbol *p, char *name, Symbol *s)
       +{
       +        return dwarflenum(fhdr, p, name, 0, zl, s);
       +}
       +
       +static int
       +dwarfindexlsym(Fhdr *fhdr, Symbol *p, uint i, Symbol *s)
       +{
       +        return dwarflenum(fhdr, p, nil, i, zl, s);
       +}
       +
       +static int
       +dwarffindlsym(Fhdr *fhdr, Symbol *p, Loc l, Symbol *s)
       +{
       +        return dwarflenum(fhdr, p, nil, 0, l, s);
       +}
       +
       +static void
       +dwarfsyminit(Fhdr *fp)
       +{
       +        Dwarf *d;
       +        DwarfSym s;
       +        Symbol sym;
       +
       +        d = fp->dwarf;
       +        if(dwarfenum(d, &s) < 0)
       +                return;
       +
       +        while(dwarfnextsym(d, &s, s.depth!=1) == 1){
       +                if(s.depth != 1)
       +                        continue;
       +                if(s.attrs.name == nil)
       +                        continue;
       +                switch(s.attrs.tag){
       +                case TagSubprogram:
       +                case TagVariable:
       +                        if(dwarftosym(fp, d, &s, &sym, 0) < 0)
       +                                continue;
       +                        addsym(fp, &sym);
       +                }
       +        }
       +}
       +
       +static char*
       +regname(Dwarf *d, int i)
       +{
       +        if(i < 0 || i >= d->nreg)
       +                return nil;
       +        return d->reg[i];
       +}
       +
       +static int
       +dwarftosym(Fhdr *fp, Dwarf *d, DwarfSym *ds, Symbol *s, int infn)
       +{
       +        DwarfBuf buf;
       +        DwarfBlock b;
       +        
       +        memset(s, 0, sizeof *s);
       +        s->u.dwarf.uoff = ds->uoff;
       +        s->u.dwarf.unit = ds->unit;
       +        switch(ds->attrs.tag){
       +        default:
       +                return -1;
       +        case TagUnspecifiedParameters:
       +                ds->attrs.name = "...";
       +                s->type = 'p';
       +                goto sym;
       +        case TagFormalParameter:
       +                s->type = 'p';
       +                s->class = CPARAM;
       +                goto sym;
       +        case TagSubprogram:
       +                s->type = 't';
       +                s->class = CTEXT;
       +                goto sym;
       +        case TagVariable:
       +                if(infn){
       +                        s->type = 'a';
       +                        s->class = CAUTO;
       +                }else{
       +                        s->type = 'd';
       +                        s->class = CDATA;
       +                }
       +        sym:
       +                s->name = ds->attrs.name;
       +                if(ds->attrs.have.lowpc){
       +                        s->loc.type = LADDR;
       +                        s->loc.addr = ds->attrs.lowpc;
       +                        if(ds->attrs.have.highpc){
       +                                s->hiloc.type = LADDR;
       +                                s->hiloc.addr = ds->attrs.highpc;
       +                        }
       +                }else if(ds->attrs.have.location == TConstant){
       +                        s->loc.type = LADDR;
       +                        s->loc.addr = ds->attrs.location.c;
       +                }else if(ds->attrs.have.location == TBlock){
       +                        b = ds->attrs.location.b;
       +                        if(b.len == 0)
       +                                return -1;
       +                        buf.p = b.data+1;
       +                        buf.ep = b.data+b.len;
       +                        buf.d = d;
       +                        buf.addrsize = 0;
       +                        if(b.data[0]==OpAddr){
       +                                if(b.len != 5)
       +                                        return -1;
       +                                s->loc.type = LADDR;
       +                                s->loc.addr = dwarfgetaddr(&buf);
       +                        }else if(OpReg0 <= b.data[0] && b.data[0] < OpReg0+0x20){
       +                                if(b.len != 1 || (s->loc.reg = regname(d, b.data[0]-OpReg0)) == nil)
       +                                        return -1;
       +                                s->loc.type = LREG;
       +                        }else if(OpBreg0 <= b.data[0] && b.data[0] < OpBreg0+0x20){
       +                                s->loc.type = LOFFSET;
       +                                s->loc.reg = regname(d, b.data[0]-0x70);
       +                                s->loc.offset = dwarfget128s(&buf);
       +                                if(s->loc.reg == nil)
       +                                        return -1;
       +                        }else if(b.data[0] == OpRegx){
       +                                s->loc.type = LREG;
       +                                s->loc.reg = regname(d, dwarfget128(&buf));
       +                                if(s->loc.reg == nil)
       +                                        return -1;
       +                        }else if(b.data[0] == OpFbreg){
       +                                s->loc.type = LOFFSET;
       +                                s->loc.reg = mach->fp;
       +                                s->loc.offset = dwarfget128s(&buf);
       +                        }else if(b.data[0] == OpBregx){
       +                                s->loc.type = LOFFSET;
       +                                s->loc.reg = regname(d, dwarfget128(&buf));
       +                                s->loc.offset = dwarfget128s(&buf);
       +                                if(s->loc.reg == nil)
       +                                        return -1;
       +                        }else
       +                                s->loc.type = LNONE;
       +                        if(buf.p != buf.ep)
       +                                s->loc.type = LNONE;
       +                }else
       +                        return -1;
       +                if(ds->attrs.isexternal)
       +                        s->type += 'A' - 'a';
       +                if(ds->attrs.tag==TagVariable && s->loc.type==LADDR && s->loc.addr>=fp->dataddr+fp->datsz)
       +                        s->type += 'b' - 'd';
       +                s->fhdr = fp;
       +                return 0;
       +        }
       +}
       +
       +static int
       +dwarfeval(Dwarf *d, Map *map, Regs *regs, ulong cfa, int rno, DwarfExpr e, ulong *u)
       +{
       +        int i;
       +        u32int u4;
       +        ulong uu;
       +
       +        switch(e.type){
       +        case RuleUndef:
       +                *u = 0;
       +                return 0;
       +        case RuleSame:
       +                if(rno == -1){
       +                        werrstr("pc cannot be `same'");
       +                        return -1;
       +                }
       +                return rget(regs, regname(d, rno), u);
       +        case RuleRegister:
       +                if((i = windindex(regname(d, e.reg))) < 0)
       +                        return -1;
       +                return rget(regs, regname(d, i), u);
       +        case RuleCfaOffset:
       +                if(cfa == 0){
       +                        werrstr("unknown cfa");
       +                        return -1;
       +                }
       +                if(get4(map, cfa + e.offset, &u4) < 0)
       +                        return -1;
       +                *u = u4;
       +                return 0;
       +        case RuleRegOff:
       +                if(rget(regs, regname(d, e.reg), &uu) < 0)
       +                        return -1;
       +                if(get4(map, uu+e.offset, &u4) < 0)
       +                        return -1;        
       +                *u = u4;
       +                return 0;
       +        case RuleLocation:
       +                werrstr("not evaluating dwarf loc expressions");
       +                return -1;
       +        }
       +        werrstr("not reached in dwarfeval");
       +        return -1;
       +}
       +
       +#if 0
       +static int
       +dwarfexprfmt(Fmt *fmt)
       +{
       +        DwarfExpr *e;
       +
       +        if((e = va_arg(fmt->args, DwarfExpr*)) == nil)
       +                return fmtstrcpy(fmt, "<nil>");
       +
       +        switch(e->type){
       +        case RuleUndef:
       +                return fmtstrcpy(fmt, "undef");
       +        case RuleSame:
       +                return fmtstrcpy(fmt, "same");
       +        case RuleCfaOffset:
       +                return fmtprint(fmt, "%ld(cfa)", e->offset);
       +        case RuleRegister:
       +                return fmtprint(fmt, "r%ld", e->reg);
       +        case RuleRegOff:
       +                return fmtprint(fmt, "%ld(r%ld)", e->offset, e->reg);
       +        case RuleLocation:
       +                return fmtprint(fmt, "l.%.*H", e->loc.len, e->loc.data);
       +        default:
       +                return fmtprint(fmt, "?%d", e->type);
       +        }
       +}
       +#endif
       +
       +static int
       +_dwarfunwind(Fhdr *fhdr, Map *map, Regs *regs, ulong *next)
       +{
       +        char *name;
       +        int i, j;
       +        ulong cfa, pc, u;
       +        Dwarf *d;
       +        DwarfExpr *e, epc, ecfa;
       +
       +
       +        /*
       +         * Use dwarfunwind to tell us what to do.
       +         */
       +        d = fhdr->dwarf;
       +        e = malloc(d->nreg*sizeof(e[0]));
       +        if(e == nil)
       +                return -1;
       +        if(rget(regs, mach->pc, &pc) < 0)
       +                goto err;
       +        if(dwarfunwind(d, pc, &ecfa, &epc, e, d->nreg) < 0)
       +                goto err;
       +
       +        /*
       +         * Compute CFA.
       +         */
       +        switch(ecfa.type){
       +        default:
       +                werrstr("invalid call-frame-address in _dwarfunwind");
       +                goto err;
       +        case RuleRegister:
       +                ecfa.offset = 0;
       +        case RuleRegOff:
       +                if((name = regname(d, ecfa.reg)) == nil){
       +                        werrstr("invalid call-frame-address register %d", (int)ecfa.reg);
       +                        goto err;
       +                }
       +                if(rget(regs, name, &cfa) < 0){
       +                        werrstr("fetching %s for call-frame-address: %r", name);
       +                        goto err;
       +                }
       +                cfa += ecfa.offset;
       +        }
       +
       +        /*
       +         * Compute registers.
       +         */
       +        for(i=0; i<d->nreg; i++){
       +                j = windindex(d->reg[i]);
       +                if(j == -1)
       +                        continue;
       +                if(dwarfeval(d, map, regs, cfa, i, e[i], &u) < 0)
       +                        u = ~(ulong)0;
       +                next[j] = u;
       +        }
       +
       +        /*
       +         * Compute caller pc
       +         */
       +        if(dwarfeval(d, map, regs, cfa, -1, epc, &u) < 0){
       +                werrstr("computing caller %s: %r", mach->pc);
       +                goto err;
       +        }
       +        next[windindex(mach->pc)] = u;
       +        free(e);
       +        return 0;
       +
       +err:
       +        free(e);
       +        return -1;
       +}
       +
   DIR diff --git a/src/libmach/symelf.c b/src/libmach/symelf.c
       t@@ -0,0 +1,103 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <mach.h>
       +#include "elf.h"
       +
       +static int
       +elfsyminit(Fhdr *fp)
       +{
       +        int i, onlyundef;
       +        Elf *elf;
       +        Symbol sym;
       +        ElfSym esym;
       +        ElfProg *p;
       +
       +        elf = fp->elf;
       +
       +        onlyundef = fp->nsym > 0;
       +        for(i=0; elfsym(elf, i, &esym) >= 0; i++){
       +                if(esym.name == nil)
       +                        continue;
       +                if(onlyundef && esym.shndx != ElfSymShnNone)
       +                        continue;
       +                if(esym.type != ElfSymTypeObject && esym.type != ElfSymTypeFunc)
       +                        continue;
       +                if(strchr(esym.name, '@'))
       +                        continue;
       +                memset(&sym, 0, sizeof sym);
       +                sym.name = esym.name;
       +                sym.loc.type = LADDR;
       +                sym.loc.addr = esym.value;
       +                if(esym.size){
       +                        sym.hiloc.type = LADDR;
       +                        sym.hiloc.addr = esym.value+esym.size;
       +                }
       +                sym.fhdr = fp;
       +                if(esym.type==ElfSymTypeObject){
       +                        sym.class = CDATA;
       +                        sym.type = 'D';
       +                        if(&elf->sect[esym.shndx] == elf->bss)
       +                                sym.type = 'B';
       +                }else if(esym.type==ElfSymTypeFunc){
       +                        sym.class = CTEXT;
       +                        sym.type = 'T';
       +                }
       +                if(esym.shndx == ElfSymShnNone)
       +                        sym.type = 'U';
       +                if(esym.bind==ElfSymBindLocal)
       +                        sym.type += 'a' - 'A';
       +                addsym(fp, &sym);
       +        }
       +
       +        for(i=0; i<elf->nprog; i++){
       +                p = &elf->prog[i];
       +                if(p->type != ElfProgDynamic)
       +                        continue;
       +                memset(&sym, 0, sizeof sym);
       +                sym.name = "_DYNAMIC";
       +                sym.loc = locaddr(p->vaddr);
       +                sym.hiloc = locaddr(p->vaddr+p->filesz);
       +                sym.type = 'D';
       +                sym.class = CDATA;
       +                addsym(fp, &sym);
       +        }
       +        return 0;
       +}
       +
       +int
       +symelf(Fhdr *fhdr)
       +{
       +        int ret;
       +
       +        ret = -1;
       +
       +        /* try dwarf */
       +        if(fhdr->dwarf){
       +                if(machdebug)
       +                        fprint(2, "dwarf symbols...\n");
       +                if(symdwarf(fhdr) < 0)
       +                        fprint(2, "initializing dwarf: %r");
       +                else
       +                        ret = 0;
       +        }
       +
       +        /* try stabs */
       +        if(fhdr->stabs.stabbase){
       +                if(machdebug)
       +                        fprint(2, "stabs symbols...\n");
       +                if(symstabs(fhdr) < 0)
       +                        fprint(2, "initializing stabs: %r");
       +                else
       +                        ret = 0;
       +        }
       +
       +        if(machdebug)
       +                fprint(2, "elf symbols...\n");
       +
       +        if(elfsyminit(fhdr) < 0)
       +                fprint(2, "initializing elf: %r");
       +        else
       +                ret = 0;
       +        return ret;
       +}
       +
   DIR diff --git a/src/libmach/symmacho.c b/src/libmach/symmacho.c
       t@@ -0,0 +1,50 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <mach.h>
       +#include "macho.h"
       +
       +#if 0
       +static int
       +machosyminit(Fhdr *fp)
       +{
       +        /* XXX should parse dynamic symbol table here */
       +        return 0;
       +}
       +#endif
       +
       +int
       +symmacho(Fhdr *fp)
       +{
       +        int ret;
       +        Macho *m;
       +
       +        m = fp->macho;
       +        if(m == nil){
       +                werrstr("not a macho");
       +                return -1;
       +        }
       +
       +        ret = -1;
       +
       +        if(machdebug)
       +                fprint(2, "macho symbols...\n");
       +
       +/*
       +        if(machosyminit(fp) < 0)
       +                fprint(2, "initializing macho symbols: %r\n");
       +        else
       +                ret = 0;
       +*/
       +
       +        if(fp->stabs.stabbase){
       +                if(machdebug)
       +                        fprint(2, "stabs symbols...\n");
       +
       +                if(symstabs(fp) < 0)
       +                        fprint(2, "initializing stabs: %r");
       +                else
       +                        ret = 0;
       +        }
       +        return ret;
       +}
       +
   DIR diff --git a/src/libmach/symstabs.c b/src/libmach/symstabs.c
       t@@ -0,0 +1,401 @@
       +#include <u.h>
       +#include <libc.h>
       +#include <mach.h>
       +#include "stabs.h"
       +
       +static int
       +strcmpcolon(char *a, char *bcolon)
       +{
       +        int i, len;
       +        char *p;
       +
       +        p = strchr(bcolon, ':');
       +        if(p == nil)
       +                return strcmp(a, bcolon);
       +        len = p-bcolon;
       +        i = strncmp(a, bcolon, len);
       +        if(i)
       +                return i;
       +        if(a[len] == 0)
       +                return 0;
       +        return 1;
       +}
       +
       +static int
       +stabcvtsym(StabSym *stab, Symbol *sym, char *dir, char *file, int i)
       +{
       +        char *p;
       +
       +        /*
       +         * Zero out the : to avoid allocating a new name string.
       +         * The type info can be found by looking past the NUL.
       +         * This is going to get us in trouble...
       +         */
       +        if((p = strchr(stab->name, ':')) != nil)
       +                *p++ = 0;
       +        else
       +                p = stab->name+strlen(stab->name)+1;
       +
       +        sym->name = stab->name;
       +        sym->u.stabs.dir = dir;
       +        sym->u.stabs.file = file;
       +        sym->u.stabs.i = i;
       +        switch(stab->type){
       +        default:
       +                return -1;
       +        case N_FUN:
       +                sym->class = CTEXT;
       +                switch(*p){
       +                default:
       +                        return -1;
       +                case 'F':        /* global function */
       +                        sym->type = 'T';
       +                        break;
       +                case 'Q':        /* static procedure */
       +                case 'f':        /* static function */
       +                case 'I':        /* nested procedure */
       +                case 'J':        /* nested function */
       +                        sym->type = 't';
       +                        break;
       +                }
       +                sym->loc.type = LADDR;
       +                sym->loc.addr = stab->value;
       +                break;
       +        case N_GSYM:
       +        case N_PSYM:
       +        case N_LSYM:
       +        case N_LCSYM:
       +                sym->class = CDATA;
       +                sym->loc.type = LADDR;
       +                sym->loc.addr = stab->value;
       +                switch(*p){
       +                default:
       +                        return -1;
       +                case 'S':        /* file-scope static variable */
       +                        sym->type = 'd';
       +                        break;
       +                case 'G':        /* global variable */
       +                        sym->type = 'D';
       +                        sym->loc.type = LNONE;
       +                        break;
       +                case 'r':        /* register variable */
       +                        sym->class = CAUTO;
       +                        sym->type = 'a';
       +                        sym->loc.type = LREG;
       +                        sym->loc.reg = "XXX";
       +                        break;
       +                case 's':        /* local variable */
       +                        sym->class = CAUTO;
       +                        sym->type = 'a';
       +                        sym->loc.type = LOFFSET;
       +                        sym->loc.offset = stab->value;
       +                        sym->loc.reg = "XXX";
       +                        break;
       +                case 'a':        /* by reference */
       +                case 'D':        /* f.p. parameter */
       +                case 'i':        /* register parameter */
       +                case 'p':        /* "normal" parameter */
       +                case 'P':        /* register parameter */
       +                case 'v':        /* by reference */
       +                case 'X':        /* function return variable */
       +                        sym->class = CPARAM;
       +                        sym->type = 'p';
       +                        if(*p == 'i'){
       +                                sym->loc.type = LREG;
       +                                sym->loc.reg = "XXX";
       +                        }else{
       +                                sym->loc.type = LOFFSET;
       +                                sym->loc.offset = stab->value;
       +                                sym->loc.reg = "XXX";
       +                        }
       +                        break;
       +                }
       +                break;
       +        }
       +        return 0;        
       +}
       +
       +static int
       +stabssyminit(Fhdr *fp)
       +{
       +        int i;
       +        char *dir, *file;
       +        Stab *stabs;
       +        StabSym sym, lastfun;
       +        Symbol s, *fun;
       +        char **inc, **xinc;
       +        int ninc, minc;
       +        int locals, autos, params;
       +
       +        stabs = &fp->stabs;
       +        if(stabs == nil){
       +                werrstr("no stabs info");
       +                return -1;
       +        }
       +
       +        dir = nil;
       +        file = nil;
       +        inc = nil;
       +        fun = nil;
       +        ninc = 0;
       +        minc = 0;
       +        locals = 0;
       +        params = 0;
       +        autos = 0;
       +        memset(&lastfun, 0, sizeof lastfun);
       +        for(i=0; stabsym(stabs, i, &sym)>=0; i++){
       +                switch(sym.type){
       +                case N_SO:
       +                        if(sym.name == nil || *sym.name == 0){
       +                                file = nil;
       +                                break;
       +                        }
       +                        if(sym.name[strlen(sym.name)-1] == '/')
       +                                dir = sym.name;
       +                        else
       +                                file = sym.name;
       +                        break;
       +                case N_BINCL:
       +                        if(ninc >= minc){
       +                                xinc = realloc(inc, (ninc+32)*sizeof(inc[0]));
       +                                if(xinc){
       +                                        memset(xinc+ninc, 0, 32*sizeof(inc[0]));
       +                                        inc = xinc;
       +                                }
       +                                ninc += 32;
       +                        }
       +                        if(ninc < minc)
       +                                inc[ninc] = sym.name;
       +                        ninc++;
       +                        break;
       +                case N_EINCL:
       +                        if(ninc > 0)
       +                                ninc--;
       +                        break;
       +                case N_EXCL:
       +                        /* condensed include - same effect as previous BINCL/EINCL pair */
       +                        break;
       +                case N_GSYM:        /* global variable */
       +                        /* only includes type, so useless for now */
       +                        break;
       +                case N_FUN:
       +                        if(sym.name == nil){
       +                                /* marks end of function */
       +                                if(fun){
       +                                        fun->hiloc.type = LADDR;
       +                                        fun->hiloc.addr = fun->loc.addr + sym.value;
       +                                }
       +                                break;
       +                        }
       +                        if(fun && lastfun.value==sym.value && lastfun.name==sym.name){
       +                                fun->u.stabs.locals = i;
       +                                break;
       +                        }
       +                        /* create new symbol, add it */
       +                        lastfun = sym;
       +                        fun = nil;
       +                        if(stabcvtsym(&sym, &s, dir, file, i) < 0)
       +                                continue;
       +                        if((fun = addsym(fp, &s)) == nil)
       +                                goto err;
       +                        locals = 0;
       +                        params = 0;
       +                        autos = 0;
       +                        break;
       +                case N_PSYM:
       +                case N_LSYM:
       +                case N_LCSYM:
       +                        if(fun){
       +                                if(fun->u.stabs.frameptr == -1){
       +                                        /*
       +                                         * Try to distinguish functions with a real frame pointer
       +                                          * from functions with a virtual frame pointer, based on 
       +                                         * whether the first parameter is in the right location and
       +                                         * whether the autos have negative offsets.  
       +                                         * 
       +                                         * This heuristic works most of the time.  On the 386, we
       +                                         * cannot distinguish between a v. function with no autos
       +                                         * but a frame of size 4 and a f.p. function with no autos and
       +                                         * no frame.   Anything else we'll get right.
       +                                         * 
       +                                         * Another way to go about this would be to have
       +                                         * mach-specific functions to inspect the function
       +                                         * prologues when we're not sure.  What we have
       +                                         * already should be enough, though.
       +                                         */
       +                                        if(params==0 && sym.type == N_PSYM){
       +                                                if(sym.value != 8 && sym.value >= 4){
       +                                                        /* XXX 386 specific, but let's find another system before generalizing */
       +                                                        fun->u.stabs.frameptr = 0;
       +                                                        fun->u.stabs.framesize = sym.value - 4;
       +                                                }
       +                                        }else if(sym.type == N_LSYM){
       +                                                if(sym.value >= 0){
       +                                                        fun->u.stabs.frameptr = 0;
       +                                                        if(params)
       +                                                                fun->u.stabs.framesize = 8 - 4;
       +                                                }else
       +                                                        fun->u.stabs.frameptr = 1;
       +                                        }
       +                                }
       +                                if(sym.type == N_PSYM)
       +                                        params++;
       +                                if(sym.type == N_LSYM)
       +                                        autos++;
       +                        }
       +                        break;
       +
       +                case N_STSYM:        /* static file-scope variable */
       +                        /* create new symbol, add it */
       +                        if(stabcvtsym(&sym, &s, dir, file, i) < 0)
       +                                continue;
       +                        if(addsym(fp, &s) < 0)
       +                                goto err;
       +                        break;
       +                }
       +        }
       +        free(inc);
       +        return 0;
       +
       +err:
       +        free(inc);
       +        return -1;
       +}
       +
       +static int
       +stabspc2file(Fhdr *fhdr, ulong pc, char *buf, uint nbuf, ulong *pline)
       +{
       +        int i;
       +        Symbol *s;
       +        StabSym ss;
       +        ulong line, basepc;
       +        Loc l;
       +
       +        l.type = LADDR;
       +        l.addr = pc;
       +        if((s = ffindsym(fhdr, l, CTEXT)) == nil
       +        || stabsym(&fhdr->stabs, s->u.stabs.i, &ss) < 0)
       +                return -1;
       +
       +        line = ss.desc;
       +        basepc = ss.value;
       +        for(i=s->u.stabs.i+1; stabsym(&fhdr->stabs, i, &ss) >= 0; i++){
       +                if(ss.type == N_FUN && ss.name == nil)
       +                        break;
       +                if(ss.type == N_SLINE){
       +                        if(basepc+ss.value > pc)
       +                                break;
       +                        else
       +                                line = ss.desc;
       +                }
       +        }
       +        *pline = line;
       +        if(s->u.stabs.dir)
       +                snprint(buf, nbuf, "%s%s", s->u.stabs.dir, s->u.stabs.file);
       +        else
       +                snprint(buf, nbuf, "%s", s->u.stabs.file);
       +        return 0;
       +}
       +
       +static int
       +stabsline2pc(Fhdr *fhdr, ulong startpc, ulong line, ulong *pc)
       +{
       +        int i, trigger;
       +        Symbol *s;
       +        StabSym ss;
       +        ulong basepc;
       +        Loc l;
       +
       +        l.type = LADDR;
       +        l.addr = startpc;
       +        if((s = ffindsym(fhdr, l, CTEXT)) == nil)
       +                return -1;
       +
       +        trigger = 0;
       +        line = ss.desc;
       +        basepc = ss.value;
       +        for(i=s->u.stabs.i+1; stabsym(&fhdr->stabs, i, &ss) >= 0; i++){
       +                if(ss.type == N_FUN)
       +                        basepc = ss.value;
       +                if(ss.type == N_SLINE){
       +                        if(basepc+ss.value >= startpc)
       +                                trigger = 1;
       +                        if(trigger && ss.desc >= line){
       +                                *pc = basepc+ss.value;
       +                                return 0;
       +                        }
       +                }
       +        }
       +        return -1;
       +}
       +
       +static int
       +stabslenum(Fhdr *fhdr, Symbol *p, char *name, uint j, Loc l, Symbol *s)
       +{
       +        int i;
       +        StabSym ss;
       +
       +        for(i=p->u.stabs.locals; stabsym(&fhdr->stabs, i, &ss)>=0; i++){
       +                if(ss.type == N_FUN && ss.name == nil)
       +                        break;
       +                switch(ss.type){
       +                case N_PSYM:
       +                case N_LSYM:
       +                case N_LCSYM:
       +                        if(name){
       +                                if(strcmpcolon(name, ss.name) != 0)
       +                                        break;
       +                        }else if(l.type){
       +                                /* wait for now */
       +                        }else{
       +                                if(j-- > 0)
       +                                        break;
       +                        }
       +                        if(stabcvtsym(&ss, s, p->u.stabs.dir, p->u.stabs.file, i) < 0)
       +                                return -1;
       +                        if(s->loc.type == LOFFSET){
       +                                if(p->u.stabs.frameptr == 0)
       +                                        s->loc.reg = mach->sp;
       +                                else
       +                                        s->loc.reg = mach->fp;
       +                        }
       +                        if(l.type && loccmp(&l, &s->loc) != 0)
       +                                break;
       +                        return 0;
       +                }
       +        }
       +        return -1;
       +}
       +
       +static Loc zl;
       +
       +static int
       +stabslookuplsym(Fhdr *fhdr, Symbol *p, char *name, Symbol *s)
       +{
       +        return stabslenum(fhdr, p, name, 0, zl, s);
       +}
       +
       +static int
       +stabsindexlsym(Fhdr *fhdr, Symbol *p, uint i, Symbol *s)
       +{
       +        return stabslenum(fhdr, p, nil, i, zl, s);
       +}
       +
       +static int
       +stabsfindlsym(Fhdr *fhdr, Symbol *p, Loc l, Symbol *s)
       +{
       +        return stabslenum(fhdr, p, nil, 0, l, s);
       +}
       +
       +int
       +symstabs(Fhdr *fp)
       +{
       +        if(stabssyminit(fp) < 0)
       +                return -1;
       +        fp->pc2file = stabspc2file;
       +        fp->line2pc = stabsline2pc;
       +        fp->lookuplsym = stabslookuplsym;
       +        fp->indexlsym = stabsindexlsym;
       +        fp->findlsym = stabsfindlsym;
       +        return 0;
       +}
   DIR diff --git a/src/libmach/ureg386.h b/src/libmach/ureg386.h
       t@@ -0,0 +1,45 @@
       +typedef struct Ureg Ureg;
       +struct Ureg
       +{
       +        ulong        di;                /* general registers */
       +        ulong        si;                /* ... */
       +        ulong        bp;                /* ... */
       +        ulong        nsp;
       +        ulong        bx;                /* ... */
       +        ulong        dx;                /* ... */
       +        ulong        cx;                /* ... */
       +        ulong        ax;                /* ... */
       +        ulong        gs;                /* data segments */
       +        ulong        fs;                /* ... */
       +        ulong        es;                /* ... */
       +        ulong        ds;                /* ... */
       +        ulong        trap;                /* trap type */
       +        ulong        ecode;                /* error code (or zero) */
       +        ulong        pc;                /* pc */
       +        ulong        cs;                /* old context */
       +        ulong        flags;                /* old flags */
       +        ulong        sp;
       +        ulong        ss;                /* old stack segment */
       +};
       +
       +typedef struct UregLinux386 UregLinux386;
       +struct UregLinux386
       +{
       +        ulong        ebx;
       +        ulong        ecx;
       +        ulong        edx;
       +        ulong        esi;
       +        ulong        ebp;
       +        ulong        eax;
       +        ulong        xds;
       +        ulong        xes;
       +        ulong        xfs;
       +        ulong        xgs;
       +        ulong        origeax;
       +        ulong        eip;
       +        ulong        xcs;
       +        ulong        eflags;
       +        ulong        esp;
       +        ulong        xss;
       +};
       +
   DIR diff --git a/src/libmach/uregpower.h b/src/libmach/uregpower.h
       t@@ -0,0 +1,54 @@
       +typedef struct Ureg Ureg;
       +
       +struct Ureg
       +{
       +/*  0*/        ulong        cause;
       +/*  4*/        ulong        srr1;        /* aka status */
       +/*  8*/        ulong        pc;        /* SRR0 */
       +/* 12*/        ulong        pad;
       +/* 16*/        ulong        lr;
       +/* 20*/        ulong        cr;
       +/* 24*/        ulong        xer;
       +/* 28*/        ulong        ctr;
       +/* 32*/        ulong        r0;
       +/* 36*/        ulong        r1;        /* aka sp */
       +/* 40*/        ulong        r2;
       +/* 44*/        ulong        r3;
       +/* 48*/        ulong        r4;
       +/* 52*/        ulong        r5;
       +/* 56*/        ulong        r6;
       +/* 60*/        ulong        r7;
       +/* 64*/        ulong        r8;
       +/* 68*/        ulong        r9;
       +/* 72*/        ulong        r10;
       +/* 76*/        ulong        r11;
       +/* 80*/        ulong        r12;
       +/* 84*/        ulong        r13;
       +/* 88*/        ulong        r14;
       +/* 92*/        ulong        r15;
       +/* 96*/        ulong        r16;
       +/*100*/        ulong        r17;
       +/*104*/        ulong        r18;
       +/*108*/        ulong        r19;
       +/*112*/        ulong        r20;
       +/*116*/        ulong        r21;
       +/*120*/        ulong        r22;
       +/*124*/        ulong        r23;
       +/*128*/        ulong        r24;
       +/*132*/        ulong        r25;
       +/*136*/        ulong        r26;
       +/*140*/        ulong        r27;
       +/*144*/        ulong        r28;
       +/*148*/        ulong        r29;
       +/*152*/        ulong        r30;
       +/*156*/        ulong        r31;
       +/*160*/        ulong        dcmp;
       +/*164*/        ulong        icmp;
       +/*168*/        ulong        dmiss;
       +/*172*/        ulong        imiss;
       +/*176*/        ulong        hash1;
       +/*180*/        ulong        hash2;
       +/*184*/        ulong        dar;
       +/*188*/        ulong        dsisr;
       +/*192*/        ulong        vrsave;
       +};