commit a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46 from: rsc date: Mon Apr 19 19:29:25 2004 UTC libmach commit - 0e3cc9f456ea49919459bf1164d0c8309a6134fa commit + a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46 blob - /dev/null blob + 2838b392b01b5b92934293b71763d1f539ff57f6 (mode 644) --- /dev/null +++ src/libmach/FreeBSD.c @@ -0,0 +1,43 @@ +/* + * process interface for FreeBSD + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#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) +{ +} blob - /dev/null blob + 62796adbce1b346fede9efadda2ff75cd642010b (mode 644) --- /dev/null +++ src/libmach/Linux.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#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; inseg; i++) + while(inseg && 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; ipid, 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; ipid; + 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<= 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 + blob - /dev/null blob + ea8a808cd82d49985ff9a8143e8bc05b164df7dc (mode 644) --- /dev/null +++ src/libmach/Notes @@ -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. + blob - /dev/null blob + 78046f5007de7850b10c22115cb04bf8b8508f22 (mode 644) --- /dev/null +++ src/libmach/Notes.stab @@ -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 blob - /dev/null blob + 756518971e3d07ff818fec62e862f6d513227fc1 (mode 644) --- /dev/null +++ src/libmach/crack.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include + +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= 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; inseg; i++){ + while(inseg && map->seg[i].fd == fp->fd){ + map->nseg--; + memmove(&map->seg[i], &map->seg[i+1], + (map->nseg-i)*sizeof(map->seg[0])); + } + } +} blob - /dev/null blob + 0d15804bb7a43e2e558ca2d367f3d07e2d150a82 (mode 644) --- /dev/null +++ src/libmach/crackelf.c @@ -0,0 +1,342 @@ +#include +#include +#include +#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; ihdr.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; ihdr.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; iatype + || 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; inprog; 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; inprog; 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; inprog; 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, ¬e, &a) < 0) + break; + switch(note.type){ + case ElfNotePrStatus: + if((n = (*elf->coreregs)(elf, ¬e, &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; +} + blob - /dev/null blob + bfc0fd6211f63588c50e90023411333625019afd (mode 644) --- /dev/null +++ src/libmach/crackmacho.c @@ -0,0 +1,198 @@ +#include +#include +#include +#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; icputype != 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; incmd; 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; incmd; 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; incmd; 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; +} blob - /dev/null blob + 0836523930951a40a383002be9b2aff438c4fa9e (mode 644) --- /dev/null +++ src/libmach/dwarf.h @@ -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; + blob - /dev/null blob + d5cc9b7113a4b8002fd5c520cd875ff2536ec297 (mode 644) --- /dev/null +++ src/libmach/dwarf386.c @@ -0,0 +1,24 @@ +#include +#include +#include +#include "elf.h" +#include "dwarf.h" + +char* +dwarf386regs[] = +{ + "AX", + "CX", + "DX", + "BX", + "SP", + "BP", + "SI", + "DI", + "LR", + "CFA", +}; + +int dwarf386nregs = 10; + + blob - /dev/null blob + 2db418ddb852364c99e64ed1029145c7ad9e62dc (mode 644) --- /dev/null +++ src/libmach/dwarfabbrev.c @@ -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 +#include +#include +#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 +#include +#include +#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.pline 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 +#include +#include +#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; iframe.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 */ +} + blob - /dev/null blob + 47c38c378c6239726c223bb2905785f49320440e (mode 644) --- /dev/null +++ src/libmach/dwarfdump.c @@ -0,0 +1,138 @@ +#include +#include +#include +#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; iargs, DwarfExpr*)) == nil) + return fmtstrcpy(fmt, ""); + + 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); + } +} blob - /dev/null blob + 0da7273a11fbd6c35a593872c6e060e6dfb935c2 (mode 644) --- /dev/null +++ src/libmach/dwarfeval.c @@ -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 + blob - /dev/null blob + da8558c4b741376f9f6cffc348ab266275e7f13b (mode 644) --- /dev/null +++ src/libmach/dwarfget.c @@ -0,0 +1,217 @@ +/* + * Dwarf data format parsing routines. + */ + +#include +#include +#include +#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->pep && *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->pep){ + c = *b->p++; + v |= (c & 0x7F)< 8*sizeof(ulong)){ + if(0) + if(++nbad == 1) + fprint(2, "dwarf: overflow during parsing of sleb128 integer: got %d bits\n", nb); + } + return v; +} + blob - /dev/null blob + 79065bba7e80b7f52504e4c4076d58aa59e471f9 (mode 644) --- /dev/null +++ src/libmach/dwarfinfo.c @@ -0,0 +1,646 @@ +/* + * Dwarf info parse and search. + */ + +#include +#include +#include +#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; itag = a->tag; + attrs->haskids = a->haskids; + + for(i=0; inattr; 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; +} blob - /dev/null blob + 6122ae683c887f471fa6fa84449a1749812a1f4e (mode 644) --- /dev/null +++ src/libmach/dwarfopen.c @@ -0,0 +1,107 @@ +#include +#include +#include +#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); +} blob - /dev/null blob + 165b3aa017727d1befc65f9e01f1ec49fc9d86d9 (mode 644) --- /dev/null +++ src/libmach/dwarfpc.c @@ -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 +#include +#include +#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 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; +} blob - /dev/null blob + b09d2866dea642e8f679d85259ee3a62967a93d8 (mode 644) --- /dev/null +++ src/libmach/dwarfpubnames.c @@ -0,0 +1,76 @@ +#include +#include +#include +#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); +} + + */ blob - /dev/null blob + 6a387fd3bb2d2444782d108e96567e48a8f7aef3 (mode 644) --- /dev/null +++ src/libmach/elf.c @@ -0,0 +1,405 @@ +/* + * Parse 32-bit ELF files. + * Copyright (c) 2004 Russ Cox. See LICENSE. + */ + +#include +#include +#include +#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; inprog; 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; insect; i++){ + if(seek(fd, h->shoff+i*h->shentsize, 0) < 0 + || readn(fd, §b, sizeof sectb) != sizeof sectb) + goto err; + unpacksect(h, &e->sect[i], §b); + } + + 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; insect; 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; insect; 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; insect; 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; +} + blob - /dev/null blob + 6ed239bc2ce4ba9d2d6ccdfa51a296832423182d (mode 644) --- /dev/null +++ src/libmach/elf.h @@ -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**); blob - /dev/null blob + f1e953fbef91237c7c92474c942456b24ac8259d (mode 644) --- /dev/null +++ src/libmach/elfcore.h @@ -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; +}; blob - /dev/null blob + 2ff746dee42843fa39c6604fb527172662975961 (mode 644) --- /dev/null +++ src/libmach/elfcorefreebsd386.c @@ -0,0 +1,89 @@ +#include +#include +#include +#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); +} + blob - /dev/null blob + f6a0234c64263db6aa4e2d6497d4b503a8a4c91b (mode 644) --- /dev/null +++ src/libmach/elfcorelinux386.c @@ -0,0 +1,95 @@ +#include +#include +#include +#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); +} + blob - /dev/null blob + e96f818d310d032401f0dda129ba629db06ef884 (mode 644) --- /dev/null +++ src/libmach/elfdump.c @@ -0,0 +1,133 @@ +#include +#include +#include +#include +#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; inprog; 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; insect; 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 = 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); +} blob - /dev/null blob + 06bb41a63fb6cf85b97c58b0961068574d028d68 (mode 644) --- /dev/null +++ src/libmach/elfdynsym.c @@ -0,0 +1,6 @@ +#include +#include +#include "elf.h" + +int +elfsym(Elf *elf, ElfSect *symtab, ElfSect *strtab, int ndx, ElfSym * \ No newline at end of file blob - /dev/null blob + a94a096a95bccd29de1f9a79496fa3696ccd9466 (mode 644) --- /dev/null +++ src/libmach/fpformat.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include + +/* + * 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; +} blob - /dev/null blob + 6e4485190b3a7eb03a4f5101a7c7870ce00dc7cc (mode 644) --- /dev/null +++ src/libmach/frame.c @@ -0,0 +1,130 @@ +#include +#include +#include +#include + +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; inwindreg; 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; inwindreg; 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; inwindreg; i++){ + loc[i].type = LREG; + loc[i].reg = mach->windreg[i]; + } + return loc; +} blob - /dev/null blob + 5f3ed50e10689e14807f9372874b3712fe8f3d76 (mode 644) --- /dev/null +++ src/libmach/hexify.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +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; +} + blob - /dev/null blob + 0d756d212086412fa509a6a8250fe20ee3e23d06 (mode 644) --- /dev/null +++ src/libmach/ieee.c @@ -0,0 +1,169 @@ +#include +#include +#include +#include + +/* + * 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); +} blob - /dev/null blob + 47bcf3d960f500f39bba14e203c452c89758df8e (mode 644) --- /dev/null +++ src/libmach/loc.c @@ -0,0 +1,253 @@ +#include +#include +#include +#include + +int +locfmt(Fmt *fmt) +{ + Loc l; + + l = va_arg(fmt->args, Loc); + switch(l.type){ + default: + return fmtprint(fmt, "", 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; +} + blob - /dev/null blob + 1b1dea73f7247ee862c96f650d397bc395779de9 (mode 644) --- /dev/null +++ src/libmach/localaddr.c @@ -0,0 +1,56 @@ +#include +#include +#include +#include + +/* + * 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; +} blob - /dev/null blob + 89a88f160d6e755b142c98f732b1ccea1d0cef7e (mode 644) --- /dev/null +++ src/libmach/mach.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include + +Mach *mach; + +extern Mach mach386; +extern Mach machpower; + +static Mach *machs[] = +{ + &mach386, + &machpower, +}; + +Mach* +machbyname(char *name) +{ + int i; + + for(i=0; iname, name) == 0){ + mach = machs[i]; + return machs[i]; + } + werrstr("machine '%s' not found", name); + return nil; +} + blob - /dev/null blob + 5f336ce7a0946991367a4a64695b5de8c4c27471 (mode 644) --- /dev/null +++ src/libmach/mach386.c @@ -0,0 +1,1786 @@ +/* + * 386 definition + */ +#include +#include +#include +#include +#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<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<proto,"JMP", 3) == 0 || strncmp(op->proto,"CALL", 4) == 0) + return 1; + foll[n++] = pc+i.n; + return n; +} blob - /dev/null blob + 641db598c9732ed2875ce2bc076c117929e9bc37 (mode 644) --- /dev/null +++ src/libmach/macho.c @@ -0,0 +1,128 @@ +#include +#include +#include +#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; icmd[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); +} blob - /dev/null blob + 377e0d2b85dacc16d26e501ab6b5c3da4edf0207 (mode 644) --- /dev/null +++ src/libmach/macho.h @@ -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**); blob - /dev/null blob + 0eb3761d18d65922d4d8510bc7024ff93db31016 (mode 644) --- /dev/null +++ src/libmach/machocorepower.c @@ -0,0 +1,173 @@ +#include +#include +#include +#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; incmd; 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; psize; 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); +} + blob - /dev/null blob + 181061aa7d7d269986d25f4058584e1e42d835df (mode 644) --- /dev/null +++ src/libmach/machodump.c @@ -0,0 +1,93 @@ +#include +#include +#include +#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; incmd; 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; incmd; 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); +} blob - /dev/null blob + d223f4f56546b2a9cf169e8a6c5f8824e1e13d42 (mode 644) --- /dev/null +++ src/libmach/machpower.c @@ -0,0 +1,1409 @@ +/* + * PowerPC definition + * forsyth@plan9.cs.york.ac.uk + */ +#include +#include +#include +#include "uregpower.h" +#include + +/* + * 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 */ +}; + blob - /dev/null blob + 144b7042ccaa1947172b0536930120a3ef8cc67f (mode 644) --- /dev/null +++ src/libmach/map.c @@ -0,0 +1,306 @@ +/* + * File map routines + */ +#include +#include +#include +#include + +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; inseg; 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; totrw(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; totfd, 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; +} blob - /dev/null blob + a690a0005e4f6e7face674a51956bff423ca2da5 (mode 644) --- /dev/null +++ src/libmach/mkfile @@ -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 blob - /dev/null blob + b5e369cb39584e5577a950a77f62b7015c462821 (mode 644) --- /dev/null +++ src/libmach/nm.c @@ -0,0 +1,289 @@ +/* + * nm.c -- drive nm + */ +#include +#include +#include +#include +#include + +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; ivalue < (*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"; +} blob - /dev/null blob + 43c04786c7ebc176595aa3728c8d391b6d09ca7b (mode 644) --- /dev/null +++ src/libmach/regs.c @@ -0,0 +1,59 @@ +#include +#include +#include + +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; +} + blob - /dev/null blob + d34bb864362fd93f2d20bc5eaeec2c843fa438c4 (mode 644) --- /dev/null +++ src/libmach/stabs.c @@ -0,0 +1,54 @@ +#include +#include +#include +#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; +} + blob - /dev/null blob + ad67cfe648162d58a0b604f11fcb2b3ddfb18c1f (mode 644) --- /dev/null +++ src/libmach/stabs.h @@ -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*); + blob - /dev/null blob + b6558234cdbb806b7273795979d2a404d0254c25 (mode 644) --- /dev/null +++ src/libmach/swap.c @@ -0,0 +1,118 @@ +#include +#include +#include +#include + +/* + * 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); +} blob - /dev/null blob + 7953019b41936345a4123d0af6bfa6b58f638db8 (mode 644) --- /dev/null +++ src/libmach/sym.c @@ -0,0 +1,478 @@ +#include +#include +#include +#include + +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 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; insym; 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; +} + blob - /dev/null blob + 8ced09f4478e83933dbe52fc1e2166db3f701789 (mode 644) --- /dev/null +++ src/libmach/symdwarf.c @@ -0,0 +1,466 @@ +#include +#include +#include +#include +#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, ""); + + 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; inreg; 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; +} + blob - /dev/null blob + 7babbd496997724635fa29c7c29951b6a8e26eb5 (mode 644) --- /dev/null +++ src/libmach/symelf.c @@ -0,0 +1,103 @@ +#include +#include +#include +#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; inprog; 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; +} + blob - /dev/null blob + 674190ffe4e0c63e596bf6476b17a30182344a6d (mode 644) --- /dev/null +++ src/libmach/symmacho.c @@ -0,0 +1,50 @@ +#include +#include +#include +#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; +} + blob - /dev/null blob + 8c1ddac8d84ca5dcb5fb6ef0d73360db7030bcfb (mode 644) --- /dev/null +++ src/libmach/symstabs.c @@ -0,0 +1,401 @@ +#include +#include +#include +#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; +} blob - /dev/null blob + 961ef6d093d7b18d1c04e721dfdfbde3294a6c72 (mode 644) --- /dev/null +++ src/libmach/ureg386.h @@ -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; +}; + blob - /dev/null blob + 0e98d19d6817a83ebdea9b08153db79d533c721c (mode 644) --- /dev/null +++ src/libmach/uregpower.h @@ -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; +};