This commit is contained in:
rsc 2004-04-19 19:29:25 +00:00
parent 0e3cc9f456
commit a84cbb2a17
53 changed files with 12038 additions and 0 deletions

43
src/libmach/FreeBSD.c Normal file
View File

@ -0,0 +1,43 @@
/*
* process interface for FreeBSD
*/
#include <u.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <errno.h>
#include <libc.h>
#include <mach.h>
#include "ureg386.h"
void
unmapproc(Map*)
{
}
int
mapproc(int, Map*, Regs**)
{
}
int
detachproc(int)
{
}
int
procnotes(int, char***)
{
}
int
ctlproc(int, char*)
{
}
char*
proctextfile(int)
{
}

450
src/libmach/Linux.c Normal file
View File

@ -0,0 +1,450 @@
/*
* process interface for Linux.
*
* Uses ptrace for registers and data,
* /proc for some process status.
* There's not much point to worrying about
* byte order here -- using ptrace means
* we're running on the architecture we're debugging,
* unless truly weird stuff is going on.
*
* It is tempting to use /proc/%d/mem along with
* the sp and pc in the stat file to get a stack trace
* without attaching to the program, but unfortunately
* you can't read the mem file unless you've attached.
*/
#include <u.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <errno.h>
#include <libc.h>
#include <mach.h>
#include "ureg386.h"
Mach *machcpu = &mach386;
typedef struct PtraceRegs PtraceRegs;
struct PtraceRegs
{
Regs r;
int pid;
};
static int ptracerw(Map*, Seg*, ulong, void*, uint, int);
static int ptraceregrw(Regs*, char*, ulong*, int);
void
unmapproc(Map *map)
{
int i;
if(map == nil)
return;
for(i=0; i<map->nseg; i++)
while(i<map->nseg && map->seg[i].pid){
map->nseg--;
memmove(&map->seg[i], &map->seg[i+1],
(map->nseg-i)*sizeof(map->seg[0]));
}
}
int
mapproc(int pid, Map *map, Regs **rp)
{
Seg s;
PtraceRegs *r;
if(ptrace(PTRACE_ATTACH, pid, 0, 0) < 0)
if(ptrace(PTRACE_PEEKUSER, pid, 0, 0) < 0)
if(ptrace(PTRACE_ATTACH, pid, 0, 0) < 0){
werrstr("ptrace attach %d: %r", pid);
return -1;
}
if(ctlproc(pid, "waitstop") < 0){
ptrace(PTRACE_DETACH, pid, 0, 0);
return -1;
}
memset(&s, 0, sizeof s);
s.base = 0;
s.size = 0xFFFFFFFF;
s.offset = 0;
s.name = "data";
s.file = nil;
s.rw = ptracerw;
s.pid = pid;
if(addseg(map, s) < 0)
return -1;
if((r = mallocz(sizeof(PtraceRegs), 1)) == nil)
return -1;
r->r.rw = ptraceregrw;
r->pid = pid;
*rp = (Regs*)r;
return 0;
}
int
detachproc(int pid)
{
return ptrace(PTRACE_DETACH, pid, 0, 0);
}
static int
ptracerw(Map *map, Seg *seg, ulong addr, void *v, uint n, int isr)
{
int i;
u32int u;
uchar buf[4];
addr += seg->base;
for(i=0; i<n; i+=4){
if(isr){
errno = 0;
u = ptrace(PTRACE_PEEKDATA, seg->pid, addr+i, 0);
if(errno)
goto ptraceerr;
if(n-i >= 4)
*(u32int*)((char*)v+i) = u;
else{
*(u32int*)buf = u;
memmove((char*)v+i, buf, n-i);
}
}else{
if(n-i >= 4)
u = *(u32int*)((char*)v+i);
else{
errno = 0;
u = ptrace(PTRACE_PEEKDATA, seg->pid, addr+i, 0);
if(errno)
return -1;
*(u32int*)buf = u;
memmove(buf, (char*)v+i, n-i);
u = *(u32int*)buf;
}
if(ptrace(PTRACE_POKEDATA, seg->pid, addr+i, &u) < 0)
goto ptraceerr;
}
}
return 0;
ptraceerr:
werrstr("ptrace: %r");
return -1;
}
static char* linuxregs[] = {
"BX",
"CX",
"DX",
"SI",
"DI",
"BP",
"AX",
"DS",
"ES",
"FS",
"GS",
"OAX",
"PC",
"CS",
"EFLAGS",
"SP",
"SS",
};
static ulong
reg2linux(char *reg)
{
int i;
for(i=0; i<nelem(linuxregs); i++)
if(strcmp(linuxregs[i], reg) == 0)
return 4*i;
return ~(ulong)0;
}
static int
ptraceregrw(Regs *regs, char *name, ulong *val, int isr)
{
int pid;
ulong addr;
u32int u;
pid = ((PtraceRegs*)regs)->pid;
addr = reg2linux(name);
if(~addr == 0){
if(isr){
*val = ~(ulong)0;
return 0;
}
werrstr("register not available");
return -1;
}
if(isr){
errno = 0;
u = ptrace(PTRACE_PEEKUSER, pid, addr, 0);
if(errno)
goto ptraceerr;
*val = u;
}else{
u = *val;
if(ptrace(PTRACE_POKEUSER, pid, addr, &u) < 0)
goto ptraceerr;
}
return 0;
ptraceerr:
werrstr("ptrace: %r");
return -1;
}
static int
isstopped(int pid)
{
char buf[1024];
int fd, n;
char *p;
snprint(buf, sizeof buf, "/proc/%d/stat", pid);
if((fd = open(buf, OREAD)) < 0)
return 0;
n = read(fd, buf, sizeof buf-1);
close(fd);
if(n <= 0)
return 0;
buf[n] = 0;
/* command name is in parens, no parens afterward */
p = strrchr(buf, ')');
if(p == nil || *++p != ' ')
return 0;
++p;
/* next is state - T is stopped for tracing */
return *p == 'T';
}
/* /proc/pid/stat contains
pid
command in parens
0. state
1. ppid
2. pgrp
3. session
4. tty_nr
5. tpgid
6. flags (math=4, traced=10)
7. minflt
8. cminflt
9. majflt
10. cmajflt
11. utime
12. stime
13. cutime
14. cstime
15. priority
16. nice
17. 0
18. itrealvalue
19. starttime
20. vsize
21. rss
22. rlim
23. startcode
24. endcode
25. startstack
26. kstkesp
27. kstkeip
28. pending signal bitmap
29. blocked signal bitmap
30. ignored signal bitmap
31. caught signal bitmap
32. wchan
33. nswap
34. cnswap
35. exit_signal
36. processor
*/
int
procnotes(int pid, char ***pnotes)
{
char buf[1024], *f[40];
int fd, i, n, nf;
char *p, *s, **notes;
ulong sigs;
extern char *_p9sigstr(int, char*);
*pnotes = nil;
snprint(buf, sizeof buf, "/proc/%d/stat", pid);
if((fd = open(buf, OREAD)) < 0){
fprint(2, "open %s: %r\n", buf);
return -1;
}
n = read(fd, buf, sizeof buf-1);
close(fd);
if(n <= 0){
fprint(2, "read %s: %r\n", buf);
return -1;
}
buf[n] = 0;
/* command name is in parens, no parens afterward */
p = strrchr(buf, ')');
if(p == nil || *++p != ' '){
fprint(2, "bad format in /proc/%d/stat\n", pid);
return -1;
}
++p;
nf = tokenize(p, f, nelem(f));
if(0) print("code 0x%lux-0x%lux stack 0x%lux kstk 0x%lux keip 0x%lux pending 0x%lux\n",
strtoul(f[23], 0, 0), strtoul(f[24], 0, 0), strtoul(f[25], 0, 0),
strtoul(f[26], 0, 0), strtoul(f[27], 0, 0), strtoul(f[28], 0, 0));
if(nf <= 28)
return -1;
sigs = strtoul(f[28], 0, 0) & ~(1<<SIGCONT);
if(sigs == 0){
*pnotes = nil;
return 0;
}
notes = mallocz(32*sizeof(char*), 0);
if(notes == nil)
return -1;
n = 0;
for(i=0; i<32; i++){
if((sigs&(1<<i)) == 0)
continue;
if((s = _p9sigstr(i, nil)) == nil)
continue;
notes[n++] = s;
}
*pnotes = notes;
return n;
}
#undef waitpid
int
ctlproc(int pid, char *msg)
{
int p, status;
if(strcmp(msg, "hang") == 0){
if(pid == getpid())
return ptrace(PTRACE_TRACEME, 0, 0, 0);
werrstr("can only hang self");
return -1;
}
if(strcmp(msg, "kill") == 0)
return ptrace(PTRACE_KILL, pid, 0, 0);
if(strcmp(msg, "startstop") == 0){
if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
return -1;
goto waitstop;
}
if(strcmp(msg, "sysstop") == 0){
if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
return -1;
goto waitstop;
}
if(strcmp(msg, "stop") == 0){
if(kill(pid, SIGSTOP) < 0)
return -1;
goto waitstop;
}
if(strcmp(msg, "waitstop") == 0){
waitstop:
if(isstopped(pid))
return 0;
for(;;){
p = waitpid(pid, &status, WUNTRACED);
if(p <= 0)
return -1;
if(WIFEXITED(status) || WIFSTOPPED(status))
return 0;
}
}
if(strcmp(msg, "start") == 0)
return ptrace(PTRACE_CONT, pid, 0, 0);
werrstr("unknown control message '%s'", msg);
return -1;
}
char*
proctextfile(int pid)
{
static char buf[1024], pbuf[128];
snprint(pbuf, sizeof pbuf, "/proc/%d/exe", pid);
if(readlink(pbuf, buf, sizeof buf) >= 0)
return buf;
if(access(pbuf, AEXIST) >= 0)
return pbuf;
return nil;
}
#if 0
snprint(buf, sizeof buf, "/proc/%d/maps", pid);
if((b = Bopen(buf, OREAD)) == nil){
werrstr("open %s: %r", buf);
return -1;
}
/*
08048000-08056000 r-xp 00000000 03:0c 64593 /usr/sbin/gpm
08056000-08058000 rw-p 0000d000 03:0c 64593 /usr/sbin/gpm
08058000-0805b000 rwxp 00000000 00:00 0
40000000-40013000 r-xp 00000000 03:0c 4165 /lib/ld-2.2.4.so
40013000-40015000 rw-p 00012000 03:0c 4165 /lib/ld-2.2.4.so
4001f000-40135000 r-xp 00000000 03:0c 45494 /lib/libc-2.2.4.so
40135000-4013e000 rw-p 00115000 03:0c 45494 /lib/libc-2.2.4.so
4013e000-40142000 rw-p 00000000 00:00 0
bffff000-c0000000 rwxp 00000000 00:00 0
*/
file = nil;
while((p = Brdline(b, '\n')) != nil){
p[Blinelen(b)-1] = 0;
memset(f, 0, sizeof f);
if((nf = getfields(p, f, 6, 1, " ")) < 5)
continue;
base = strtoul(f[0], &p, 16);
if(*p != '-')
continue;
end = strtoul(p+1, &p, 16);
if(*p != 0)
continue;
offset = strtoul(f[2], &p, 16);
if(*p != 0)
continue;
if(nf == 6)
file = f[5];
zero = atoi(f[4]) == 0;
print("%lux-%lux %lux %s %s\n", base, end, offset, zero ? "data" : "text", file ? file : "");
s.base = base;
s.size = end - base;
s.offset = offset;
s.name = zero ? "data" : "text";
s.file = strdup(file);
s.rw = ptracerw;
s.pid = pid;
if(addseg(map, s) < 0){
Bterm(b);
ptrace(PTRACE_DETACH, pid, 0, 0);
return -1;
}
}
Bterm(b);
#endif

13
src/libmach/Notes Normal file
View File

@ -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.

166
src/libmach/Notes.stab Normal file
View File

@ -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

91
src/libmach/crack.c Normal file
View File

@ -0,0 +1,91 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <mach.h>
static struct
{
ulong magic;
int (*fn)(int, Fhdr*);
} cracktab[] = {
0x7F454C46, crackelf,
0xFEEDFACE, crackmacho,
};
Fhdr*
crackhdr(char *name, int mode)
{
uchar buf[4];
ulong magic;
int i, fd;
Fhdr *hdr;
if((fd = open(name, mode)) < 0)
return nil;
if(seek(fd, 0, 0) < 0 || readn(fd, buf, 4) != 4){
close(fd);
return nil;
}
hdr = mallocz(sizeof(Fhdr), 1);
if(hdr == nil){
close(fd);
return nil;
}
hdr->filename = strdup(name);
magic = beload4(buf);
werrstr("magic doesn't match");
for(i=0; i<nelem(cracktab); i++)
if(cracktab[i].magic == magic && seek(fd, 0, 0) == 0 && cracktab[i].fn(fd, hdr) >= 0){
_addhdr(hdr);
return hdr;
}
werrstr("unknown file type: %r");
free(hdr);
close(fd);
return nil;
}
void
uncrackhdr(Fhdr *hdr)
{
close(hdr->fd);
_delhdr(hdr);
free(hdr);
}
int
mapfile(Fhdr *fp, ulong base, Map *map, Regs **regs)
{
if(fp == nil){
werrstr("no file");
return -1;
}
if(map == nil){
werrstr("no map");
return -1;
}
if(fp->map == nil){
werrstr("cannot load map for this file type");
return -1;
}
return fp->map(fp, base, map, regs);
}
void
unmapfile(Fhdr *fp, Map *map)
{
int i;
if(map == nil || fp == nil)
return;
for(i=0; i<map->nseg; i++){
while(i<map->nseg && map->seg[i].fd == fp->fd){
map->nseg--;
memmove(&map->seg[i], &map->seg[i+1],
(map->nseg-i)*sizeof(map->seg[0]));
}
}
}

342
src/libmach/crackelf.c Normal file
View File

@ -0,0 +1,342 @@
#include <u.h>
#include <libc.h>
#include <mach.h>
#include "elf.h"
#include "dwarf.h"
static int mapelf(Fhdr *fp, ulong base, Map *map, Regs**);
static int mapcoreregs(Fhdr *fp, Map *map, Regs**);
static struct
{
uint etype;
uint mtype;
Mach *mach;
char *name;
} mtab[] =
{ /* Font Tab 4 */
ElfMachSparc, MSPARC, nil, "sparc",
ElfMach386, M386, &mach386, "386",
ElfMachMips, MMIPS, nil, "mips",
ElfMachArm, MARM, nil, "arm",
ElfMachPower, MPOWER, nil, "powerpc",
ElfMachPower64, MNONE, nil, "powerpc64",
};
static struct
{
uint etype;
uint atype;
char *aname;
} atab[] =
{ /* Font Tab 4 */
ElfAbiSystemV, ALINUX, "linux", /* [sic] */
ElfAbiLinux, ALINUX, "linux",
ElfAbiFreeBSD, AFREEBSD, "freebsd",
};
static struct
{
uint mtype;
uint atype;
int (*coreregs)(Elf*, ElfNote*, uchar**);
} ctab[] =
{ /* Font Tab 4 */
M386, ALINUX, coreregslinux386,
M386, ANONE, coreregslinux386, /* [sic] */
M386, AFREEBSD, coreregsfreebsd386,
};
int
crackelf(int fd, Fhdr *fp)
{
int i, havetext, havedata;
Elf *elf;
ElfProg *p;
ElfSect *s1, *s2;
if((elf = elfinit(fd)) == nil)
return -1;
fp->fd = fd;
fp->elf = elf;
fp->dwarf = dwarfopen(elf); /* okay to fail */
fp->syminit = symelf;
if((s1 = elfsection(elf, ".stab")) != nil && s1->link!=0 && s1->link < elf->nsect){
s2 = &elf->sect[s1->link];
if(elfmap(elf, s1) >= 0 && elfmap(elf, s2) >= 0){
fp->stabs.stabbase = s1->base;
fp->stabs.stabsize = s1->size;
fp->stabs.strbase = s2->base;
fp->stabs.strsize = s2->size;
fp->stabs.e2 = elf->hdr.e2;
fp->stabs.e4 = elf->hdr.e4;
}
}
for(i=0; i<nelem(mtab); i++){
if(elf->hdr.machine != mtab[i].etype)
continue;
fp->mach = mtab[i].mach;
fp->mname = mtab[i].name;
fp->mtype = mtab[i].mtype;
break;
}
if(i == nelem(mtab)){
werrstr("unsupported machine type %d", elf->hdr.machine);
goto err;
}
if(mach == nil)
mach = fp->mach;
fp->aname = "unknown";
for(i=0; i<nelem(atab); i++){
if(elf->hdr.abi != atab[i].etype)
continue;
fp->atype = atab[i].atype;
fp->aname = atab[i].aname;
break;
}
switch(elf->hdr.type){
default:
werrstr("unknown file type %d", elf->hdr.type);
goto err;
case ElfTypeExecutable:
fp->ftype = FEXEC;
fp->fname = "executable";
break;
case ElfTypeRelocatable:
fp->ftype = FRELOC;
fp->fname = "relocatable";
break;
case ElfTypeSharedObject:
fp->ftype = FSHOBJ;
fp->fname = "shared object";
break;
case ElfTypeCore:
fp->ftype = FCORE;
fp->fname = "core dump";
break;
}
fp->map = mapelf;
if(fp->ftype == FCORE){
for(i=0; i<nelem(ctab); i++){
if(ctab[i].atype != fp->atype
|| ctab[i].mtype != fp->mtype)
continue;
elf->coreregs = ctab[i].coreregs;
break;
}
return 0;
}
fp->entry = elf->hdr.entry;
/* First r-x section we find is the text and initialized data */
/* First rw- section we find is the r/w data */
havetext = 0;
havedata = 0;
for(i=0; i<elf->nprog; i++){
p = &elf->prog[i];
if(p->type != ElfProgLoad)
continue;
if(!havetext && p->flags == (ElfProgFlagRead|ElfProgFlagExec) && p->align >= mach->pgsize){
havetext = 1;
fp->txtaddr = p->vaddr;
fp->txtsz = p->memsz;
fp->txtoff = p->offset;
}
if(!havedata && p->flags == (ElfProgFlagRead|ElfProgFlagWrite) && p->align >= mach->pgsize){
havedata = 1;
fp->dataddr = p->vaddr;
fp->datsz = p->filesz;
fp->datoff = p->offset;
fp->bsssz = p->memsz - p->filesz;
}
}
if(!havetext){
werrstr("did not find text segment in elf binary");
goto err;
}
if(!havedata){
werrstr("did not find data segment in elf binary");
goto err;
}
return 0;
err:
elfclose(elf);
return -1;
}
static int
mapelf(Fhdr *fp, ulong base, Map *map, Regs **regs)
{
int i;
Elf *elf;
ElfProg *p;
ulong sz;
ulong lim;
Seg s;
elf = fp->elf;
if(elf == nil){
werrstr("not an elf file");
return -1;
}
for(i=0; i<elf->nprog; i++){
p = &elf->prog[i];
if(p->type != ElfProgLoad)
continue;
if(p->align < mach->pgsize)
continue;
if(p->filesz){
memset(&s, 0, sizeof s);
s.file = fp->filename;
s.fd = fp->fd;
if(fp->ftype == FCORE)
s.name = "core";
else if(p->flags == 5)
s.name = "text";
else
s.name = "data";
s.base = base+p->vaddr;
s.size = p->filesz;
s.offset = p->offset;
if(addseg(map, s) < 0)
return -1;
}
/*
* If memsz > filesz, we're supposed to zero fill.
* Core files have zeroed sections where the pages
* can be filled in from the text file, so if this is a core
* we only fill in that which isn't yet mapped.
*/
if(fp->ftype == FCORE){
sz = p->filesz;
while(sz < p->memsz){
if(addrtoseg(map, base+p->vaddr+sz, &s) < 0){
lim = base + p->vaddr + p->memsz;
if(addrtosegafter(map, base+p->vaddr+sz, &s) >= 0 && s.base < lim)
lim = s.base;
memset(&s, 0, sizeof s);
s.name = "zero";
s.base = base + p->vaddr + sz;
s.size = lim - s.base;
s.offset = p->offset;
if(addseg(map, s) < 0)
return -1;
}else
sz = (s.base+s.size) - (base + p->vaddr);
}
}else{
if(p->filesz < p->memsz){
memset(&s, 0, sizeof s);
s.name = "zero";
s.base = base + p->vaddr + p->filesz;
s.size = p->memsz - p->filesz;
if(addseg(map, s) < 0)
return -1;
}
}
}
if(fp->ftype == FCORE){
if(mapcoreregs(fp, map, regs) < 0)
fprint(2, "warning: reading core regs: %r");
}
return 0;
}
static int
unpacknote(Elf *elf, uchar *a, uchar *ea, ElfNote *note, uchar **pa)
{
if(a+12 > ea)
return -1;
note->namesz = elf->hdr.e4(a);
note->descsz = elf->hdr.e4(a+4);
note->type = elf->hdr.e4(a+8);
a += 12;
note->name = (char*)a;
/* XXX fetch alignment constants from elsewhere */
a += (note->namesz+3)&~3;
note->desc = (uchar*)a;
a += (note->descsz+3)&~3;
if(a > ea)
return -1;
*pa = a;
return 0;
}
static int
mapcoreregs(Fhdr *fp, Map *map, Regs **rp)
{
int i;
uchar *a, *sa, *ea, *uregs;
uint n;
ElfNote note;
ElfProg *p;
Elf *elf;
UregRegs *r;
elf = fp->elf;
if(elf->coreregs == nil){
werrstr("cannot parse %s %s cores", fp->mname, fp->aname);
return -1;
}
for(i=0; i<elf->nprog; i++){
p = &elf->prog[i];
if(p->type != ElfProgNote)
continue;
n = p->filesz;
a = malloc(n);
if(a == nil)
return -1;
if(seek(fp->fd, p->offset, 0) < 0 || readn(fp->fd, a, n) != n){
free(a);
continue;
}
sa = a;
ea = a+n;
while(a < ea){
note.offset = (a-sa) + p->offset;
if(unpacknote(elf, a, ea, &note, &a) < 0)
break;
switch(note.type){
case ElfNotePrStatus:
if((n = (*elf->coreregs)(elf, &note, &uregs)) < 0){
free(sa);
return -1;
}
free(sa);
if((r = mallocz(sizeof(*r), 1)) == nil){
free(uregs);
return -1;
}
r->r.rw = _uregrw;
r->ureg = uregs;
*rp = &r->r;
return 0;
case ElfNotePrFpreg:
case ElfNotePrPsinfo:
case ElfNotePrTaskstruct:
case ElfNotePrAuxv:
case ElfNotePrXfpreg:
break;
}
// fprint(2, "0x%lux note %s/%lud %p\n", note.offset, note.name, note.type, note.desc);
}
free(sa);
}
fprint(2, "could not find registers in core file\n");
return -1;
}

198
src/libmach/crackmacho.c Normal file
View File

@ -0,0 +1,198 @@
#include <u.h>
#include <libc.h>
#include <mach.h>
#include "macho.h"
static int mapmacho(Fhdr *fp, ulong base, Map *map, Regs**);
static struct
{
uint etype;
uint mtype;
Mach *mach;
char *name;
int (*coreregs)(Macho*, uchar**);
} mtab[] =
{
MachoCpuPower, MPOWER, &machpower, "powerpc", coreregsmachopower,
};
static uchar*
load(int fd, ulong off, int size)
{
uchar *a;
a = malloc(size);
if(a == nil)
return nil;
if(seek(fd, off, 0) < 0 || readn(fd, a, size) != size){
free(a);
return nil;
}
return a;
}
int
crackmacho(int fd, Fhdr *fp)
{
int i;
Macho *m;
if((m = machoinit(fd)) == nil)
return -1;
fp->fd = fd;
fp->macho = m;
for(i=0; i<nelem(mtab); i++){
if(m->cputype != mtab[i].etype)
continue;
fp->mach = mtab[i].mach;
fp->mtype = mtab[i].mtype;
fp->mname = mtab[i].name;
m->coreregs = mtab[i].coreregs;
break;
}
if(i == nelem(mtab)){
werrstr("unsupported cpu type %ud", m->cputype);
goto err;
}
fp->atype = AMACH;
fp->aname = "mach";
if(mach == nil)
mach = fp->mach;
switch(m->filetype){
default:
werrstr("unsupported macho file type %lud", m->filetype);
goto err;
case MachoFileObject:
fp->ftype = FOBJ;
fp->fname = "object";
break;
case MachoFileExecutable:
fp->ftype = FEXEC;
fp->fname = "executable";
break;
case MachoFileFvmlib:
fp->ftype = FSHLIB;
fp->fname = "shared library";
break;
case MachoFileCore:
fp->ftype = FCORE;
fp->fname = "core";
break;
case MachoFilePreload:
fp->ftype = FBOOT;
fp->fname = "preloaded executable";
break;
}
fp->txtaddr = fp->dataddr = 0;
fp->txtsz = fp->datsz = 0;
for(i=0; i<m->ncmd; i++){
if(m->cmd[i].type != MachoCmdSegment)
continue;
if(strcmp(m->cmd[i].seg.name, "__TEXT") == 0){
fp->txtaddr = m->cmd[i].seg.vmaddr;
fp->txtsz = m->cmd[i].seg.vmsize;
fp->txtoff = m->cmd[i].seg.fileoff;
}
if(strcmp(m->cmd[i].seg.name, "__DATA") == 0){
fp->dataddr = m->cmd[i].seg.vmaddr;
fp->datsz = m->cmd[i].seg.filesz;
fp->datoff = m->cmd[i].seg.fileoff;
fp->bsssz = m->cmd[i].seg.vmsize - fp->datsz;
}
}
fp->map = mapmacho;
fp->syminit = symmacho;
for(i=0; i<m->ncmd; i++)
if(m->cmd[i].type == MachoCmdSymtab)
break;
if(i < m->ncmd){
fp->stabs.stabbase = load(fp->fd, m->cmd[i].sym.symoff, m->cmd[i].sym.nsyms*16);
fp->stabs.stabsize = m->cmd[i].sym.nsyms*16;
fp->stabs.strbase = load(fp->fd, m->cmd[i].sym.stroff, m->cmd[i].sym.strsize);
if(fp->stabs.stabbase == nil || fp->stabs.strbase == nil){
fp->stabs.stabbase = nil;
fp->stabs.strbase = nil;
}else{
fp->stabs.strsize = m->cmd[i].sym.strsize;
fp->stabs.e2 = (m->e4==beload4 ? beload2 : leload2);
fp->stabs.e4 = m->e4;
}
}
return 0;
err:
machoclose(m);
return -1;
}
static int
mapmacho(Fhdr *fp, ulong base, Map *map, Regs **rp)
{
int i, n;
uchar *u;
Macho *m;
MachoCmd *c;
Seg s;
UregRegs *r;
m = fp->macho;
if(m == nil){
werrstr("not a macho file");
return -1;
}
for(i=0; i<m->ncmd; i++){
c = &m->cmd[i];
if(c->type != MachoCmdSegment)
continue;
if(c->seg.filesz){
memset(&s, 0, sizeof s);
s.file = fp->filename;
s.fd = fp->fd;
if(fp->ftype == FCORE)
s.name = "core";
else if(strcmp(c->seg.name, "__DATA") == 0)
s.name = "data";
else
s.name = "text";
s.base = base+c->seg.vmaddr;
s.size = c->seg.filesz;
s.offset = c->seg.fileoff;
if(addseg(map, s) < 0)
return -1;
}
if(c->seg.filesz < c->seg.vmsize){
memset(&s, 0, sizeof s);
s.name = "zero";
s.base = base + c->seg.vmaddr + c->seg.filesz;
s.size = c->seg.vmsize - c->seg.filesz;
if(addseg(map, s) < 0)
return -1;
}
}
if(fp->ftype == FCORE && m->coreregs){
n = m->coreregs(m, &u);
if(n < 0){
fprint(2, "mapping registers: %r\n");
goto noregs;
}
if((r = mallocz(sizeof *r, 1)) == nil)
return -1;
r->r.rw = _uregrw;
r->ureg = u;
*rp = &r->r;
}
noregs:
return 0;
}

460
src/libmach/dwarf.h Normal file
View File

@ -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;

24
src/libmach/dwarf386.c Normal file
View File

@ -0,0 +1,24 @@
#include <u.h>
#include <libc.h>
#include <mach.h>
#include "elf.h"
#include "dwarf.h"
char*
dwarf386regs[] =
{
"AX",
"CX",
"DX",
"BX",
"SP",
"BP",
"SI",
"DI",
"LR",
"CFA",
};
int dwarf386nregs = 10;

129
src/libmach/dwarfabbrev.c Normal file
View File

@ -0,0 +1,129 @@
/*
* Dwarf abbreviation parsing code.
*
* The convention here is that calling dwarfgetabbrevs relinquishes
* access to any abbrevs returned previously. Will have to add
* explicit reference counting if this turns out not to be acceptable.
*/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "elf.h"
#include "dwarf.h"
static int parseabbrevs(Dwarf*, ulong, DwarfAbbrev*, DwarfAttr*, int*, int*);
DwarfAbbrev *dwarfgetabbrev(Dwarf*, ulong, ulong);
static int
loadabbrevs(Dwarf *d, ulong off, DwarfAbbrev **aa)
{
int nattr, nabbrev;
DwarfAbbrev *abbrev;
DwarfAttr *attr;
if(d->acache.off == off && d->acache.na){
*aa = d->acache.a;
return d->acache.na;
}
/* two passes - once to count, then allocate, then a second to copy */
if(parseabbrevs(d, off, nil, nil, &nabbrev, &nattr) < 0)
return -1;
abbrev = malloc(nabbrev*sizeof(DwarfAbbrev) + nattr*sizeof(DwarfAttr));
attr = (DwarfAttr*)(abbrev+nabbrev);
if(parseabbrevs(d, off, abbrev, attr, nil, nil) < 0){
free(abbrev);
return -1;
}
free(d->acache.a);
d->acache.a = abbrev;
d->acache.na = nabbrev;
d->acache.off = off;
*aa = abbrev;
return nabbrev;
}
static int
parseabbrevs(Dwarf *d, ulong off, DwarfAbbrev *abbrev, DwarfAttr *attr, int *pnabbrev, int *pnattr)
{
int i, nabbrev, nattr, haskids;
ulong num, tag, name, form;
DwarfBuf b;
if(off >= d->abbrev.len){
werrstr("bad abbrev section offset 0x%lux >= 0x%lux\n", off, d->abbrev.len);
return -1;
}
memset(&b, 0, sizeof b);
b.p = d->abbrev.data + off;
b.ep = d->abbrev.data + d->abbrev.len;
nabbrev = 0;
nattr = 0;
for(;;){
if(b.p == nil){
werrstr("malformed abbrev data");
return -1;
}
num = dwarfget128(&b);
if(num == 0)
break;
tag = dwarfget128(&b);
haskids = dwarfget1(&b);
for(i=0;; i++){
name = dwarfget128(&b);
form = dwarfget128(&b);
if(name == 0 && form == 0)
break;
if(attr){
attr[i].name = name;
attr[i].form = form;
}
}
if(abbrev){
abbrev->num = num;
abbrev->tag = tag;
abbrev->haskids = haskids;
abbrev->attr = attr;
abbrev->nattr = i;
abbrev++;
attr += i;
}
nabbrev++;
nattr += i;
}
if(pnabbrev)
*pnabbrev = nabbrev;
if(pnattr)
*pnattr = nattr;
return 0;
}
static DwarfAbbrev*
findabbrev(DwarfAbbrev *a, int na, ulong num)
{
int i;
for(i=0; i<na; i++)
if(a[i].num == num)
return &a[i];
return nil;
}
DwarfAbbrev*
dwarfgetabbrev(Dwarf *d, ulong off, ulong num)
{
DwarfAbbrev *a;
int na;
if((na = loadabbrevs(d, off, &a)) < 0)
return nil;
return findabbrev(a, na, num);
}

View File

@ -0,0 +1,63 @@
/*
* Dwarf address ranges parsing code.
*/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "elf.h"
#include "dwarf.h"
int
dwarfaddrtounit(Dwarf *d, ulong addr, ulong *unit)
{
DwarfBuf b;
int segsize, i;
ulong len, id, off, base, size;
uchar *start, *end;
memset(&b, 0, sizeof b);
b.d = d;
b.p = d->aranges.data;
b.ep = b.p + d->aranges.len;
while(b.p < b.ep){
start = b.p;
len = dwarfget4(&b);
if((id = dwarfget2(&b)) != 2){
if(b.p == nil){
underflow:
werrstr("buffer underflow reading address ranges header");
}else
werrstr("bad dwarf version 0x%lux in address ranges header", id);
return -1;
}
off = dwarfget4(&b);
b.addrsize = dwarfget1(&b);
if(d->addrsize == 0)
d->addrsize = b.addrsize;
segsize = dwarfget1(&b);
USED(segsize); /* what am i supposed to do with this? */
if(b.p == nil)
goto underflow;
if((i = (b.p-start) % (2*b.addrsize)) != 0)
b.p += 2*b.addrsize - i;
end = start+4+len;
while(b.p!=nil && b.p<end){
base = dwarfgetaddr(&b);
size = dwarfgetaddr(&b);
if(b.p == nil)
goto underflow;
if(base <= addr && addr < base+size){
*unit = off;
return 0;
}
}
if(b.p == nil)
goto underflow;
b.p = end;
}
werrstr("address 0x%lux is not listed in dwarf debugging symbols", addr);
return -1;
}

391
src/libmach/dwarfcfa.c Normal file
View File

@ -0,0 +1,391 @@
/*
* Dwarf call frame unwinding.
*
* The call frame unwinding values are encoded using a state machine
* like the pc<->line mapping, but it's a different machine.
* The expressions to generate the old values are similar in function to the
* ``dwarf expressions'' used for locations in the code, but of course not
* the same encoding.
*/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "elf.h"
#include "dwarf.h"
#define trace 0
typedef struct State State;
struct State
{
ulong loc;
ulong endloc;
ulong iquantum;
ulong dquantum;
char *augmentation;
int version;
ulong rareg;
DwarfBuf init;
DwarfExpr *cfa;
DwarfExpr *ra;
DwarfExpr *r;
DwarfExpr *initr;
int nr;
DwarfExpr **stack;
int nstack;
};
static int findfde(Dwarf*, ulong, State*, DwarfBuf*);
static int dexec(DwarfBuf*, State*, int);
int
dwarfunwind(Dwarf *d, ulong pc, DwarfExpr *cfa, DwarfExpr *ra, DwarfExpr *r, int nr)
{
int i, ret;
DwarfBuf fde, b;
DwarfExpr *initr;
State s;
initr = mallocz(nr*sizeof(initr[0]), 1);
if(initr == 0)
return -1;
memset(&s, 0, sizeof s);
s.loc = 0;
s.cfa = cfa;
s.ra = ra;
s.r = r;
s.nr = nr;
if(findfde(d, pc, &s, &fde) < 0){
free(initr);
return -1;
}
memset(r, 0, nr*sizeof(r[0]));
for(i=0; i<nr; i++)
r[i].type = RuleSame;
if(trace) fprint(2, "s.init %p-%p, fde %p-%p\n", s.init.p, s.init.ep, fde.p, fde.ep);
b = s.init;
if(dexec(&b, &s, 0) < 0)
goto err;
s.initr = initr;
memmove(initr, r, nr*sizeof(initr[0]));
if(trace) fprint(2, "s.loc 0x%lux pc 0x%lux\n", s.loc, pc);
while(s.loc < pc){
if(trace) fprint(2, "s.loc 0x%lux pc 0x%lux\n", s.loc, pc);
if(dexec(&fde, &s, 1) < 0)
goto err;
}
*ra = s.r[s.rareg];
ret = 0;
goto out;
err:
ret = -1;
out:
free(initr);
for(i=0; i<s.nstack; i++)
free(s.stack[i]);
free(s.stack);
return ret;
}
/*
* XXX This turns out to be much more expensive than the actual
* running of the machine in dexec. It probably makes sense to
* cache the last 10 or so fde's we've found, since stack traces
* will keep asking for the same info over and over.
*/
static int
findfde(Dwarf *d, ulong pc, State *s, DwarfBuf *fde)
{
static int nbad;
char *aug;
uchar *next;
int i, vers;
ulong len, id, base, size;
DwarfBuf b;
b.d = d;
b.p = d->frame.data;
b.ep = b.p + d->frame.len;
b.addrsize = d->addrsize;
if(b.addrsize == 0)
b.addrsize = 4; /* where should i find this? */
for(; b.p < b.ep; b.p = next){
if((i = (b.p - d->frame.data) % b.addrsize))
b.p += b.addrsize - i;
len = dwarfget4(&b);
if(len > b.ep-b.p){
werrstr("bad length in cie/fde header");
return -1;
}
next = b.p+len;
id = dwarfget4(&b);
if(id == 0xFFFFFFFF){ /* CIE */
vers = dwarfget1(&b);
if(vers != 1 && vers != 2 && vers != 3){
if(++nbad == 1)
fprint(2, "unknown cie version %d (wanted 1-3)\n", vers);
continue;
}
aug = dwarfgetstring(&b);
if(aug && *aug){
if(++nbad == 1)
fprint(2, "unknown augmentation: %s\n", aug);
continue;
}
s->iquantum = dwarfget128(&b);
s->dquantum = dwarfget128s(&b);
s->rareg = dwarfget128(&b);
if(s->rareg > s->nr){
werrstr("return address is register %d but only have %d registers",
s->rareg, s->nr);
return -1;
}
s->init.p = b.p;
s->init.ep = next;
}else{ /* FDE */
base = dwarfgetaddr(&b);
size = dwarfgetaddr(&b);
fde->p = b.p;
fde->ep = next;
s->loc = base;
s->endloc = base+size;
if(base <= pc && pc < base+size)
return 0;
}
}
werrstr("cannot find call frame information for pc 0x%lux", pc);
return -1;
}
static int
checkreg(State *s, long r)
{
if(r < 0 || r >= s->nr){
werrstr("bad register number 0x%lux", r);
return -1;
}
return 0;
}
static int
dexec(DwarfBuf *b, State *s, int locstop)
{
int c;
long arg1, arg2;
DwarfExpr *e, **p;
for(;;){
if(b->p == b->ep){
if(s->initr)
s->loc = s->endloc;
return 0;
}
c = dwarfget1(b);
if(b->p == nil){
werrstr("ran out of instructions during cfa program");
if(trace) fprint(2, "%r\n");
return -1;
}
if(trace) fprint(2, "+ loc=0x%lux op 0x%ux ", s->loc, c);
switch(c>>6){
case 1: /* advance location */
arg1 = c&0x3F;
advance:
if(trace) fprint(2, "loc += %ld\n", arg1*s->iquantum);
s->loc += arg1 * s->iquantum;
if(locstop)
return 0;
continue;
case 2: /* offset rule */
arg1 = c&0x3F;
arg2 = dwarfget128(b);
offset:
if(trace) fprint(2, "r%ld += %ld\n", arg1, arg2*s->dquantum);
if(checkreg(s, arg1) < 0)
return -1;
s->r[arg1].type = RuleCfaOffset;
s->r[arg1].offset = arg2 * s->dquantum;
continue;
case 3: /* restore initial setting */
arg1 = c&0x3F;
restore:
if(trace) fprint(2, "r%ld = init\n", arg1);
if(checkreg(s, arg1) < 0)
return -1;
s->r[arg1] = s->initr[arg1];
continue;
}
switch(c){
case 0: /* nop */
if(trace) fprint(2, "nop\n");
continue;
case 0x01: /* set location */
s->loc = dwarfgetaddr(b);
if(trace) fprint(2, "loc = 0x%lux\n", s->loc);
if(locstop)
return 0;
continue;
case 0x02: /* advance loc1 */
arg1 = dwarfget1(b);
goto advance;
case 0x03: /* advance loc2 */
arg1 = dwarfget2(b);
goto advance;
case 0x04: /* advance loc4 */
arg1 = dwarfget4(b);
goto advance;
case 0x05: /* offset extended */
arg1 = dwarfget128(b);
arg2 = dwarfget128(b);
goto offset;
case 0x06: /* restore extended */
arg1 = dwarfget128(b);
goto restore;
case 0x07: /* undefined */
arg1 = dwarfget128(b);
if(trace) fprint(2, "r%ld = undef\n", arg1);
if(checkreg(s, arg1) < 0)
return -1;
s->r[arg1].type = RuleUndef;
continue;
case 0x08: /* same value */
arg1 = dwarfget128(b);
if(trace) fprint(2, "r%ld = same\n", arg1);
if(checkreg(s, arg1) < 0)
return -1;
s->r[arg1].type = RuleSame;
continue;
case 0x09: /* register */
arg1 = dwarfget128(b);
arg2 = dwarfget128(b);
if(trace) fprint(2, "r%ld = r%ld\n", arg1, arg2);
if(checkreg(s, arg1) < 0 || checkreg(s, arg2) < 0)
return -1;
s->r[arg1].type = RuleRegister;
s->r[arg1].reg = arg2;
continue;
case 0x0A: /* remember state */
e = malloc(s->nr*sizeof(e[0]));
if(trace) fprint(2, "push\n");
if(e == nil)
return -1;
p = realloc(s->stack, (s->nstack+1)*sizeof(s->stack[0]));
if(p == nil){
free(e);
return -1;
}
s->stack[s->nstack++] = e;
memmove(e, s->r, s->nr*sizeof(e[0]));
continue;
case 0x0B: /* restore state */
if(trace) fprint(2, "pop\n");
if(s->nstack == 0){
werrstr("restore state underflow");
return -1;
}
e = s->stack[s->nstack-1];
memmove(s->r, e, s->nr*sizeof(e[0]));
p = realloc(s->stack, (s->nstack-1)*sizeof(s->stack[0]));
if(p == nil)
return -1;
free(e);
s->nstack--;
continue;
case 0x0C: /* def cfa */
arg1 = dwarfget128(b);
arg2 = dwarfget128(b);
defcfa:
if(trace) fprint(2, "cfa %ld(r%ld)\n", arg2, arg1);
if(checkreg(s, arg1) < 0)
return -1;
s->cfa->type = RuleRegOff;
s->cfa->reg = arg1;
s->cfa->offset = arg2;
continue;
case 0x0D: /* def cfa register */
arg1 = dwarfget128(b);
if(trace) fprint(2, "cfa reg r%ld\n", arg1);
if(s->cfa->type != RuleRegOff){
werrstr("change CFA register but CFA not in register+offset form");
return -1;
}
if(checkreg(s, arg1) < 0)
return -1;
s->cfa->reg = arg1;
continue;
case 0x0E: /* def cfa offset */
arg1 = dwarfget128(b);
cfaoffset:
if(trace) fprint(2, "cfa off %ld\n", arg1);
if(s->cfa->type != RuleRegOff){
werrstr("change CFA offset but CFA not in register+offset form");
return -1;
}
s->cfa->offset = arg1;
continue;
case 0x0F: /* def cfa expression */
if(trace) fprint(2, "cfa expr\n");
s->cfa->type = RuleLocation;
s->cfa->loc.len = dwarfget128(b);
s->cfa->loc.data = dwarfgetnref(b, s->cfa->loc.len);
continue;
case 0x10: /* def reg expression */
arg1 = dwarfget128(b);
if(trace) fprint(2, "reg expr r%ld\n", arg1);
if(checkreg(s, arg1) < 0)
return -1;
s->r[arg1].type = RuleLocation;
s->r[arg1].loc.len = dwarfget128(b);
s->r[arg1].loc.data = dwarfgetnref(b, s->r[arg1].loc.len);
continue;
case 0x11: /* offset extended */
arg1 = dwarfget128(b);
arg2 = dwarfget128s(b);
goto offset;
case 0x12: /* cfa sf */
arg1 = dwarfget128(b);
arg2 = dwarfget128s(b);
goto defcfa;
case 0x13: /* cfa offset sf */
arg1 = dwarfget128s(b);
goto cfaoffset;
default: /* unknown */
werrstr("unknown opcode 0x%ux in cfa program", c);
return -1;
}
}
return -1; /* not reached */
}

138
src/libmach/dwarfdump.c Normal file
View File

@ -0,0 +1,138 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "elf.h"
#include "dwarf.h"
void printrules(Dwarf *d, ulong pc);
int exprfmt(Fmt*);
void
usage(void)
{
fprint(2, "usage: dwarfdump file\n");
exits("usage");
}
void
main(int argc, char **argv)
{
int c;
Elf *elf;
Dwarf *d;
DwarfSym s;
char *cdir, *dir, *file;
ulong line, mtime, length;
ARGBEGIN{
default:
usage();
}ARGEND
if(argc != 1)
usage();
fmtinstall('R', exprfmt);
fmtinstall('H', encodefmt);
if((elf = elfopen(argv[0])) == nil)
sysfatal("elfopen %s: %r", argv[0]);
if((d=dwarfopen(elf)) == nil)
sysfatal("dwarfopen: %r");
if(dwarfenum(d, &s) < 0)
sysfatal("dwarfenumall: %r");
while(dwarfnextsym(d, &s, 1) == 1){
switch(s.attrs.tag){
case TagCompileUnit:
print("compileunit %s\n", s.attrs.name);
break;
case TagSubprogram:
c = 't';
goto sym;
case TagVariable:
c = 'd';
goto sym;
case TagConstant:
c = 'c';
goto sym;
case TagFormalParameter:
if(!s.attrs.name)
break;
c = 'p';
sym:
if(s.attrs.isexternal)
c += 'A' - 'a';
print("%c %s", c, s.attrs.name);
if(s.attrs.have.lowpc)
print(" 0x%lux-0x%lux", s.attrs.lowpc, s.attrs.highpc);
switch(s.attrs.have.location){
case TBlock:
print(" @ %.*H", s.attrs.location.b.len, s.attrs.location.b.data);
break;
case TConstant:
print(" @ 0x%lux", s.attrs.location.c);
break;
}
if(s.attrs.have.ranges)
print(" ranges@0x%lux", s.attrs.ranges);
print("\n");
if(s.attrs.have.lowpc){
if(dwarfpctoline(d, s.attrs.lowpc, &cdir, &dir, &file, &line, &mtime, &length) < 0)
print("\tcould not find source: %r\n");
else
print("\t%s/%s/%s:%lud mtime=%lud length=%lud\n",
cdir, dir, file, line, mtime, length);
if(0) printrules(d, s.attrs.lowpc);
if(0) printrules(d, (s.attrs.lowpc+s.attrs.highpc)/2);
}
break;
}
}
exits(0);
}
void
printrules(Dwarf *d, ulong pc)
{
int i;
DwarfExpr r[10];
DwarfExpr cfa, ra;
if(dwarfunwind(d, pc, &cfa, &ra, r, nelem(r)) < 0)
print("\tcannot unwind from pc 0x%lux: %r\n", pc);
print("\tpc=0x%lux cfa=%R ra=%R", pc, &cfa, &ra);
for(i=0; i<nelem(r); i++)
if(r[i].type != RuleSame)
print(" r%d=%R", i, &r[i]);
print("\n");
}
int
exprfmt(Fmt *fmt)
{
DwarfExpr *e;
if((e = va_arg(fmt->args, DwarfExpr*)) == nil)
return fmtstrcpy(fmt, "<nil>");
switch(e->type){
case RuleUndef:
return fmtstrcpy(fmt, "undef");
case RuleSame:
return fmtstrcpy(fmt, "same");
case RuleCfaOffset:
return fmtprint(fmt, "%ld(cfa)", e->offset);
case RuleRegister:
return fmtprint(fmt, "r%ld", e->reg);
case RuleRegOff:
return fmtprint(fmt, "%ld(r%ld)", e->offset, e->reg);
case RuleLocation:
return fmtprint(fmt, "l.%.*H", e->loc.len, e->loc.data);
default:
return fmtprint(fmt, "?%d", e->type);
}
}

62
src/libmach/dwarfeval.c Normal file
View File

@ -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

217
src/libmach/dwarfget.c Normal file
View File

@ -0,0 +1,217 @@
/*
* Dwarf data format parsing routines.
*/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "elf.h"
#include "dwarf.h"
ulong
dwarfget1(DwarfBuf *b)
{
if(b->p==nil || b->p+1 > b->ep){
b->p = nil;
return 0;
}
return *b->p++;
}
int
dwarfgetn(DwarfBuf *b, uchar *a, int n)
{
if(b->p==nil || b->p+n > b->ep){
b->p = nil;
memset(a, 0, n);
return -1;
}
memmove(a, b->p, n);
b->p += n;
return 0;
}
uchar*
dwarfgetnref(DwarfBuf *b, ulong n)
{
uchar *p;
if(b->p==nil || b->p+n > b->ep){
b->p = nil;
return nil;
}
p = b->p;
b->p += n;
return p;
}
char*
dwarfgetstring(DwarfBuf *b)
{
char *s;
if(b->p == nil)
return nil;
s = (char*)b->p;
while(b->p < b->ep && *b->p)
b->p++;
if(b->p >= b->ep){
b->p = nil;
return nil;
}
b->p++;
return s;
}
void
dwarfskip(DwarfBuf *b, int n)
{
if(b->p==nil || b->p+n > b->ep)
b->p = nil;
else
b->p += n;
}
ulong
dwarfget2(DwarfBuf *b)
{
ulong v;
if(b->p==nil || b->p+2 > b->ep){
b->p = nil;
return 0;
}
v = b->d->elf->hdr.e2(b->p);
b->p += 2;
return v;
}
ulong
dwarfget4(DwarfBuf *b)
{
ulong v;
if(b->p==nil || b->p+4 > b->ep){
b->p = nil;
return 0;
}
v = b->d->elf->hdr.e4(b->p);
b->p += 4;
return v;
}
uvlong
dwarfget8(DwarfBuf *b)
{
uvlong v;
if(b->p==nil || b->p+8 > b->ep){
b->p = nil;
return 0;
}
v = b->d->elf->hdr.e8(b->p);
b->p += 8;
return v;
}
ulong
dwarfgetaddr(DwarfBuf *b)
{
static int nbad;
if(b->addrsize == 0)
b->addrsize = b->d->addrsize;
switch(b->addrsize){
case 1:
return dwarfget1(b);
case 2:
return dwarfget2(b);
case 4:
return dwarfget4(b);
case 8:
return dwarfget8(b);
default:
if(++nbad == 1)
fprint(2, "dwarf: unexpected address size %lud in dwarfgetaddr\n", b->addrsize);
b->p = nil;
return 0;
}
}
int n1, n2, n3, n4, n5;
/* An inline function picks off the calls to dwarfget128 for 1-byte encodings,
* more than by far the common case (99.999% on most binaries!). */
ulong
dwarfget128(DwarfBuf *b)
{
static int nbad;
ulong c, d;
if(b->p == nil)
return 0;
c = *b->p++;
if(!(c&0x80))
{n1++;
return c;
}
d = *b->p++;
c |= (d&0x7F)<<7;
if(!(d&0x80))
{n2++;
return c;
}
d = *b->p++;
c |= (d&0x7F)<<14;
if(!(d&0x80))
{n3++;
return c;
}
d = *b->p++;
c |= (d&0x7F)<<21;
if(!(d&0x80))
{n4++;
return c;
}
d = *b->p++;
c |= (d&0x7F)<<28;
if(!(d&0x80))
{n5++;
return c;
}
while(b->p<b->ep && *b->p&0x80)
b->p++;
if(++nbad == 1)
fprint(2, "dwarf: overflow during parsing of uleb128 integer\n");
return c;
}
long
dwarfget128s(DwarfBuf *b)
{
int nb, c;
ulong v;
static int nbad;
v = 0;
nb = 0;
if(b->p==nil)
return 0;
while(b->p<b->ep){
c = *b->p++;
v |= (c & 0x7F)<<nb;
nb += 7;
if(!(c&0x80))
break;
}
if(v&(1<<(nb-1)))
v |= ~(((ulong)1<<nb)-1);
if(nb > 8*sizeof(ulong)){
if(0)
if(++nbad == 1)
fprint(2, "dwarf: overflow during parsing of sleb128 integer: got %d bits\n", nb);
}
return v;
}

646
src/libmach/dwarfinfo.c Normal file
View File

@ -0,0 +1,646 @@
/*
* Dwarf info parse and search.
*/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "elf.h"
#include "dwarf.h"
enum
{
DwarfAttrSibling = 0x01,
DwarfAttrLocation = 0x02,
DwarfAttrName = 0x03,
DwarfAttrOrdering = 0x09,
DwarfAttrByteSize = 0x0B,
DwarfAttrBitOffset = 0x0C,
DwarfAttrBitSize = 0x0D,
DwarfAttrStmtList = 0x10,
DwarfAttrLowpc = 0x11,
DwarfAttrHighpc = 0x12,
DwarfAttrLanguage = 0x13,
DwarfAttrDiscr = 0x15,
DwarfAttrDiscrValue = 0x16,
DwarfAttrVisibility = 0x17,
DwarfAttrImport = 0x18,
DwarfAttrStringLength = 0x19,
DwarfAttrCommonRef = 0x1A,
DwarfAttrCompDir = 0x1B,
DwarfAttrConstValue = 0x1C,
DwarfAttrContainingType = 0x1D,
DwarfAttrDefaultValue = 0x1E,
DwarfAttrInline = 0x20,
DwarfAttrIsOptional = 0x21,
DwarfAttrLowerBound = 0x22,
DwarfAttrProducer = 0x25,
DwarfAttrPrototyped = 0x27,
DwarfAttrReturnAddr = 0x2A,
DwarfAttrStartScope = 0x2C,
DwarfAttrStrideSize = 0x2E,
DwarfAttrUpperBound = 0x2F,
DwarfAttrAbstractOrigin = 0x31,
DwarfAttrAccessibility = 0x32,
DwarfAttrAddrClass = 0x33,
DwarfAttrArtificial = 0x34,
DwarfAttrBaseTypes = 0x35,
DwarfAttrCalling = 0x36,
DwarfAttrCount = 0x37,
DwarfAttrDataMemberLoc = 0x38,
DwarfAttrDeclColumn = 0x39,
DwarfAttrDeclFile = 0x3A,
DwarfAttrDeclLine = 0x3B,
DwarfAttrDeclaration = 0x3C,
DwarfAttrDiscrList = 0x3D,
DwarfAttrEncoding = 0x3E,
DwarfAttrExternal = 0x3F,
DwarfAttrFrameBase = 0x40,
DwarfAttrFriend = 0x41,
DwarfAttrIdentifierCase = 0x42,
DwarfAttrMacroInfo = 0x43,
DwarfAttrNamelistItem = 0x44,
DwarfAttrPriority = 0x45,
DwarfAttrSegment = 0x46,
DwarfAttrSpecification = 0x47,
DwarfAttrStaticLink = 0x48,
DwarfAttrType = 0x49,
DwarfAttrUseLocation = 0x4A,
DwarfAttrVarParam = 0x4B,
DwarfAttrVirtuality = 0x4C,
DwarfAttrVtableElemLoc = 0x4D,
DwarfAttrAllocated = 0x4E,
DwarfAttrAssociated = 0x4F,
DwarfAttrDataLocation = 0x50,
DwarfAttrStride = 0x51,
DwarfAttrEntrypc = 0x52,
DwarfAttrUseUTF8 = 0x53,
DwarfAttrExtension = 0x54,
DwarfAttrRanges = 0x55,
DwarfAttrTrampoline = 0x56,
DwarfAttrCallColumn = 0x57,
DwarfAttrCallFile = 0x58,
DwarfAttrCallLine = 0x59,
DwarfAttrDescription = 0x5A,
DwarfAttrMax,
FormAddr = 0x01,
FormDwarfBlock2 = 0x03,
FormDwarfBlock4 = 0x04,
FormData2 = 0x05,
FormData4 = 0x06,
FormData8 = 0x07,
FormString = 0x08,
FormDwarfBlock = 0x09,
FormDwarfBlock1 = 0x0A,
FormData1 = 0x0B,
FormFlag = 0x0C,
FormSdata = 0x0D,
FormStrp = 0x0E,
FormUdata = 0x0F,
FormRefAddr = 0x10,
FormRef1 = 0x11,
FormRef2 = 0x12,
FormRef4 = 0x13,
FormRef8 = 0x14,
FormRefUdata = 0x15,
FormIndirect = 0x16,
};
static int parseattrs(DwarfBuf*, ulong, DwarfAbbrev*, DwarfAttrs*);
static int getulong(DwarfBuf*, int, ulong, ulong*, int*);
static int getuchar(DwarfBuf*, int, uchar*);
static int getstring(DwarfBuf*, int, char**);
static int getblock(DwarfBuf*, int, DwarfBlock*);
static int skipform(DwarfBuf*, int);
static int constblock(Dwarf*, DwarfBlock*, ulong*);
int
dwarflookupnameinunit(Dwarf *d, ulong unit, char *name, DwarfSym *s)
{
if(dwarfenumunit(d, unit, s) < 0)
return -1;
dwarfnextsym(d, s, 1); /* s is now the CompileUnit */
if(dwarfnextsym(d, s, 1) == 1){ /* s is now the first child of the compile unit */
do{
if(s->attrs.name && strcmp(s->attrs.name, name) == 0)
return 0;
}while(dwarfnextsym(d, s, 0) == 1);
}
werrstr("symbol '%s' not found", name);
return -1;
}
int
dwarflookupsubname(Dwarf *d, DwarfSym *parent, char *name, DwarfSym *s)
{
*s = *parent;
dwarfnextsym(d, s, 1);
if(s->depth == parent->depth+1)
do{
if(s->attrs.name && strcmp(s->attrs.name, name) == 0)
return 0;
}while(dwarfnextsym(d, s, 0) == 1);
werrstr("symbol '%s' not found", name);
return -1;
}
int
dwarflookuptag(Dwarf *d, ulong unit, ulong tag, DwarfSym *s)
{
if(dwarfenumunit(d, unit, s) < 0)
return -1;
dwarfnextsym(d, s, 1); /* s is now the CompileUnit */
if(s->attrs.tag == tag)
return 0;
if(dwarfnextsym(d, s, 1) == 1){ /* s is now the first child of the compile unit */
do{
if(s->attrs.tag == tag)
return 0;
}while(dwarfnextsym(d, s, 0) == 1);
}
werrstr("symbol with tag 0x%lux not found", tag);
return -1;
}
int
dwarfseeksym(Dwarf *d, ulong unit, ulong off, DwarfSym *s)
{
if(dwarfenumunit(d, unit, s) < 0)
return -1;
s->b.p = d->info.data + unit + off;
if(dwarfnextsym(d, s, 1) != 1)
return -1;
return 0;
}
int
dwarflookupfn(Dwarf *d, ulong unit, ulong pc, DwarfSym *s)
{
if(dwarfenumunit(d, unit, s) < 0)
return -1;
if(dwarfnextsym(d, s, 1) != 1)
return -1;
/* s is now the CompileUnit */
if(dwarfnextsym(d, s, 1) == 1){ /* s is now the first child of the compile unit */
do{
if(s->attrs.tag != TagSubprogram)
continue;
if(s->attrs.lowpc <= pc && pc < s->attrs.highpc)
return 0;
}while(dwarfnextsym(d, s, 0) == 1);
}
werrstr("fn containing pc 0x%lux not found", pc);
return -1;
}
int
dwarfenumunit(Dwarf *d, ulong unit, DwarfSym *s)
{
int i;
ulong aoff, len;
if(unit >= d->info.len){
werrstr("dwarf unit address 0x%lux >= 0x%lux out of range", unit, d->info.len);
return -1;
}
memset(s, 0, sizeof *s);
memset(&s->b, 0, sizeof s->b);
s->b.d = d;
s->b.p = d->info.data + unit;
s->b.ep = d->info.data + d->info.len;
len = dwarfget4(&s->b);
s->nextunit = unit + 4 + len;
if(s->b.ep - s->b.p < len){
badheader:
werrstr("bad dwarf unit header at unit 0x%lux", unit);
return -1;
}
s->b.ep = s->b.p+len;
if((i=dwarfget2(&s->b)) != 2)
goto badheader;
aoff = dwarfget4(&s->b);
s->b.addrsize = dwarfget1(&s->b);
if(d->addrsize == 0)
d->addrsize = s->b.addrsize;
if(s->b.p == nil)
goto badheader;
s->aoff = aoff;
s->unit = unit;
s->depth = 0;
return 0;
}
int
dwarfenum(Dwarf *d, DwarfSym *s)
{
if(dwarfenumunit(d, 0, s) < 0)
return -1;
s->allunits = 1;
return 0;
}
static int
_dwarfnextsym(Dwarf *d, DwarfSym *s)
{
ulong num;
DwarfAbbrev *a;
if(s->attrs.haskids)
s->depth++;
top:
if(s->b.p >= s->b.ep){
if(s->allunits && s->nextunit < d->info.len){
if(dwarfenumunit(d, s->nextunit, s) < 0)
return -1;
s->allunits = 1;
goto top;
}
return 0;
}
s->uoff = s->b.p - (d->info.data+s->unit);
num = dwarfget128(&s->b);
if(num == 0){
if(s->depth == 0)
return 0;
if(s->depth > 0)
s->depth--;
goto top;
}
a = dwarfgetabbrev(d, s->aoff, num);
if(a == nil){
fprint(2, "getabbrev %ud: %r\n", num);
return -1;
}
if(parseattrs(&s->b, s->unit, a, &s->attrs) < 0)
return -1;
return 1;
}
int
dwarfnextsym(Dwarf *d, DwarfSym *s, int recurse)
{
int r;
int depth;
ulong sib;
if(recurse)
return _dwarfnextsym(d, s);
depth = s->depth;
if(s->attrs.have.sibling){
sib = s->attrs.sibling;
if(sib < d->info.len && d->info.data+sib >= s->b.p)
s->b.p = d->info.data+sib;
s->attrs.haskids = 0;
}
do{
r = _dwarfnextsym(d, s);
if(r <= 0)
return r;
}while(s->depth != depth);
if(s->depth < depth)
return 0;
return 1;
}
typedef struct Parse Parse;
struct Parse {
int name;
int off;
int haveoff;
int type;
};
#define OFFSET(x) offsetof(DwarfAttrs, x), offsetof(DwarfAttrs, have.x)
static Parse plist[] = { /* Font Tab 4 */
DwarfAttrAbstractOrigin, OFFSET(abstractorigin), TReference,
DwarfAttrAccessibility, OFFSET(accessibility), TConstant,
DwarfAttrAddrClass, OFFSET(addrclass), TConstant,
DwarfAttrArtificial, OFFSET(isartificial), TFlag,
DwarfAttrBaseTypes, OFFSET(basetypes), TReference,
DwarfAttrBitOffset, OFFSET(bitoffset), TConstant,
DwarfAttrBitSize, OFFSET(bitsize), TConstant,
DwarfAttrByteSize, OFFSET(bytesize), TConstant,
DwarfAttrCalling, OFFSET(calling), TConstant,
DwarfAttrCommonRef, OFFSET(commonref), TReference,
DwarfAttrCompDir, OFFSET(compdir), TString,
DwarfAttrConstValue, OFFSET(constvalue), TString|TConstant|TBlock,
DwarfAttrContainingType, OFFSET(containingtype), TReference,
DwarfAttrCount, OFFSET(count), TConstant|TReference,
DwarfAttrDataMemberLoc, OFFSET(datamemberloc), TBlock|TConstant|TReference,
DwarfAttrDeclColumn, OFFSET(declcolumn), TConstant,
DwarfAttrDeclFile, OFFSET(declfile), TConstant,
DwarfAttrDeclLine, OFFSET(declline), TConstant,
DwarfAttrDeclaration, OFFSET(isdeclaration), TFlag,
DwarfAttrDefaultValue, OFFSET(defaultvalue), TReference,
DwarfAttrDiscr, OFFSET(discr), TReference,
DwarfAttrDiscrList, OFFSET(discrlist), TBlock,
DwarfAttrDiscrValue, OFFSET(discrvalue), TConstant,
DwarfAttrEncoding, OFFSET(encoding), TConstant,
DwarfAttrExternal, OFFSET(isexternal), TFlag,
DwarfAttrFrameBase, OFFSET(framebase), TBlock|TConstant,
DwarfAttrFriend, OFFSET(friend), TReference,
DwarfAttrHighpc, OFFSET(highpc), TAddress,
DwarfAttrIdentifierCase, OFFSET(identifiercase), TConstant,
DwarfAttrImport, OFFSET(import), TReference,
DwarfAttrInline, OFFSET(inlined), TConstant,
DwarfAttrIsOptional, OFFSET(isoptional), TFlag,
DwarfAttrLanguage, OFFSET(language), TConstant,
DwarfAttrLocation, OFFSET(location), TBlock|TConstant,
DwarfAttrLowerBound, OFFSET(lowerbound), TConstant|TReference,
DwarfAttrLowpc, OFFSET(lowpc), TAddress,
DwarfAttrMacroInfo, OFFSET(macroinfo), TConstant,
DwarfAttrName, OFFSET(name), TString,
DwarfAttrNamelistItem, OFFSET(namelistitem), TBlock,
DwarfAttrOrdering, OFFSET(ordering), TConstant,
DwarfAttrPriority, OFFSET(priority), TReference,
DwarfAttrProducer, OFFSET(producer), TString,
DwarfAttrPrototyped, OFFSET(isprototyped), TFlag,
DwarfAttrRanges, OFFSET(ranges), TReference,
DwarfAttrReturnAddr, OFFSET(returnaddr), TBlock|TConstant,
DwarfAttrSegment, OFFSET(segment), TBlock|TConstant,
DwarfAttrSibling, OFFSET(sibling), TReference,
DwarfAttrSpecification, OFFSET(specification), TReference,
DwarfAttrStartScope, OFFSET(startscope), TConstant,
DwarfAttrStaticLink, OFFSET(staticlink), TBlock|TConstant,
DwarfAttrStmtList, OFFSET(stmtlist), TConstant,
DwarfAttrStrideSize, OFFSET(stridesize), TConstant,
DwarfAttrStringLength, OFFSET(stringlength), TBlock|TConstant,
DwarfAttrType, OFFSET(type), TReference,
DwarfAttrUpperBound, OFFSET(upperbound), TConstant|TReference,
DwarfAttrUseLocation, OFFSET(uselocation), TBlock|TConstant,
DwarfAttrVarParam, OFFSET(isvarparam), TFlag,
DwarfAttrVirtuality, OFFSET(virtuality), TConstant,
DwarfAttrVisibility, OFFSET(visibility), TConstant,
DwarfAttrVtableElemLoc, OFFSET(vtableelemloc), TBlock|TReference,
};
static Parse ptab[DwarfAttrMax];
static int
parseattrs(DwarfBuf *b, ulong unit, DwarfAbbrev *a, DwarfAttrs *attrs)
{
int i, f, n, got;
static int nbad;
void *v;
/* initialize ptab first time through for quick access */
if(ptab[DwarfAttrName].name != DwarfAttrName)
for(i=0; i<nelem(plist); i++)
ptab[plist[i].name] = plist[i];
memset(attrs, 0, sizeof *attrs);
attrs->tag = a->tag;
attrs->haskids = a->haskids;
for(i=0; i<a->nattr; i++){
n = a->attr[i].name;
f = a->attr[i].form;
if(n < 0 || n >= nelem(ptab) || ptab[n].name==0){
if(++nbad == 1)
fprint(2, "dwarf parse attrs: unexpected attribute name 0x%ux\n", n);
return -1;
}
v = (char*)attrs + ptab[n].off;
got = 0;
if(f == FormIndirect)
f = dwarfget128(b);
if((ptab[n].type&(TConstant|TReference|TAddress))
&& getulong(b, f, unit, v, &got) >= 0)
;
else if((ptab[n].type&TFlag) && getuchar(b, f, v) >= 0)
got = TFlag;
else if((ptab[n].type&TString) && getstring(b, f, v) >= 0)
got = TString;
else if((ptab[n].type&TBlock) && getblock(b, f, v) >= 0)
got = TBlock;
else{
if(skipform(b, f) < 0){
if(++nbad == 1)
fprint(2, "dwarf parse attrs: cannot skip form %d\n", f);
return -1;
}
}
if(got == TBlock && (ptab[n].type&TConstant))
got = constblock(b->d, v, v);
*((uchar*)attrs+ptab[n].haveoff) = got;
}
return 0;
}
static int
getulong(DwarfBuf *b, int form, ulong unit, ulong *u, int *type)
{
static int nbad;
uvlong uv;
switch(form){
default:
return -1;
/* addresses */
case FormAddr:
*type = TAddress;
*u = dwarfgetaddr(b);
return 0;
/* references */
case FormRefAddr:
/* absolute ref in .debug_info */
*type = TReference;
*u = dwarfgetaddr(b);
return 0;
case FormRef1:
*u = dwarfget1(b);
goto relativeref;
case FormRef2:
*u = dwarfget2(b);
goto relativeref;
case FormRef4:
*u = dwarfget4(b);
goto relativeref;
case FormRef8:
*u = dwarfget8(b);
goto relativeref;
case FormRefUdata:
*u = dwarfget128(b);
relativeref:
*u += unit;
*type = TReference;
return 0;
/* constants */
case FormData1:
*u = dwarfget1(b);
goto constant;
case FormData2:
*u = dwarfget2(b);
goto constant;
case FormData4:
*u = dwarfget4(b);
goto constant;
case FormData8:
uv = dwarfget8(b);
*u = uv;
if(uv != *u && ++nbad == 1)
fprint(2, "dwarf: truncating 64-bit attribute constants\n");
goto constant;
case FormSdata:
*u = dwarfget128s(b);
goto constant;
case FormUdata:
*u = dwarfget128(b);
constant:
*type = TConstant;
return 0;
}
}
static int
getuchar(DwarfBuf *b, int form, uchar *u)
{
switch(form){
default:
return -1;
case FormFlag:
*u = dwarfget1(b);
return 0;
}
}
static int
getstring(DwarfBuf *b, int form, char **s)
{
static int nbad;
ulong u;
switch(form){
default:
return -1;
case FormString:
*s = dwarfgetstring(b);
return 0;
case FormStrp:
u = dwarfget4(b);
if(u >= b->d->str.len){
if(++nbad == 1)
fprint(2, "dwarf: bad string pointer 0x%lux in attribute\n", u);
/* don't return error - maybe can proceed */
*s = nil;
}else
*s = b->d->str.data + u;
return 0;
}
}
static int
getblock(DwarfBuf *b, int form, DwarfBlock *bl)
{
ulong n;
switch(form){
default:
return -1;
case FormDwarfBlock:
n = dwarfget128(b);
goto copyn;
case FormDwarfBlock1:
n = dwarfget1(b);
goto copyn;
case FormDwarfBlock2:
n = dwarfget2(b);
goto copyn;
case FormDwarfBlock4:
n = dwarfget4(b);
copyn:
bl->data = dwarfgetnref(b, n);
bl->len = n;
if(bl->data == nil)
return -1;
return 0;
}
}
static int
constblock(Dwarf *d, DwarfBlock *bl, ulong *pval)
{
DwarfBuf b;
memset(&b, 0, sizeof b);
b.p = bl->data;
b.ep = bl->data+bl->len;
b.d = d;
switch(dwarfget1(&b)){
case OpAddr:
*pval = dwarfgetaddr(&b);
return TConstant;
case OpConst1u:
*pval = dwarfget1(&b);
return TConstant;
case OpConst1s:
*pval = (schar)dwarfget1(&b);
return TConstant;
case OpConst2u:
*pval = dwarfget2(&b);
return TConstant;
case OpConst2s:
*pval = (s16int)dwarfget2(&b);
return TConstant;
case OpConst4u:
*pval = dwarfget4(&b);
return TConstant;
case OpConst4s:
*pval = (s32int)dwarfget4(&b);
return TConstant;
case OpConst8u:
*pval = (u64int)dwarfget8(&b);
return TConstant;
case OpConst8s:
*pval = (s64int)dwarfget8(&b);
return TConstant;
case OpConstu:
*pval = dwarfget128(&b);
return TConstant;
case OpConsts:
*pval = dwarfget128s(&b);
return TConstant;
case OpPlusUconst:
*pval = dwarfget128(&b);
return TConstant;
default:
return TBlock;
}
}
/* last resort */
static int
skipform(DwarfBuf *b, int form)
{
int type;
DwarfVal val;
if(getulong(b, form, 0, &val.c, &type) < 0
&& getuchar(b, form, (uchar*)&val) < 0
&& getstring(b, form, &val.s) < 0
&& getblock(b, form, &val.b) < 0)
return -1;
return 0;
}

107
src/libmach/dwarfopen.c Normal file
View File

@ -0,0 +1,107 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "elf.h"
#include "dwarf.h"
static int
readblock(int fd, DwarfBlock *b, ulong off, ulong len)
{
b->data = malloc(len);
if(b->data == nil)
return -1;
if(seek(fd, off, 0) < 0 || readn(fd, b->data, len) != len){
free(b->data);
b->data = nil;
return -1;
}
b->len = len;
return 0;
}
static int
findsection(Elf *elf, char *name, ulong *off, ulong *len)
{
ElfSect *s;
if((s = elfsection(elf, name)) == nil)
return -1;
*off = s->offset;
*len = s->size;
return s - elf->sect;
}
static int
loadsection(Elf *elf, char *name, DwarfBlock *b)
{
ulong off, len;
if(findsection(elf, name, &off, &len) < 0)
return -1;
return readblock(elf->fd, b, off, len);
}
Dwarf*
dwarfopen(Elf *elf)
{
Dwarf *d;
if(elf == nil){
werrstr("nil elf passed to dwarfopen");
return nil;
}
d = mallocz(sizeof(Dwarf), 1);
if(d == nil)
return nil;
d->elf = elf;
if(loadsection(elf, ".debug_abbrev", &d->abbrev) < 0
|| loadsection(elf, ".debug_aranges", &d->aranges) < 0
|| loadsection(elf, ".debug_frame", &d->frame) < 0
|| loadsection(elf, ".debug_line", &d->line) < 0
|| loadsection(elf, ".debug_pubnames", &d->pubnames) < 0
|| loadsection(elf, ".debug_ranges", &d->ranges) < 0
|| loadsection(elf, ".debug_str", &d->str) < 0
|| loadsection(elf, ".debug_info", &d->info) < 0)
goto err;
/* make this a table once there are more */
switch(d->elf->hdr.machine){
case ElfMach386:
d->reg = dwarf386regs;
d->nreg = dwarf386nregs;
break;
default:
werrstr("unsupported machine");
goto err;
}
return d;
err:
free(d->abbrev.data);
free(d->aranges.data);
free(d->frame.data);
free(d->line.data);
free(d->pubnames.data);
free(d->ranges.data);
free(d->str.data);
free(d->info.data);
free(d);
return nil;
}
void
dwarfclose(Dwarf *d)
{
free(d->abbrev.data);
free(d->aranges.data);
free(d->frame.data);
free(d->line.data);
free(d->pubnames.data);
free(d->ranges.data);
free(d->str.data);
free(d->info.data);
free(d);
}

338
src/libmach/dwarfpc.c Normal file
View File

@ -0,0 +1,338 @@
/*
* Dwarf pc to source line conversion.
*
* Maybe should do the reverse here, but what should the interface look like?
* One possibility is to use the Plan 9 line2addr interface:
*
* long line2addr(ulong line, ulong basepc)
*
* which returns the smallest pc > basepc with line number line (ignoring file name).
*
* The encoding may be small, but it sure isn't simple!
*/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "elf.h"
#include "dwarf.h"
#define trace 0
enum
{
Isstmt = 1<<0,
BasicDwarfBlock = 1<<1,
EndSequence = 1<<2,
PrologueEnd = 1<<3,
EpilogueBegin = 1<<4,
};
typedef struct State State;
struct State
{
ulong addr;
ulong file;
ulong line;
ulong column;
ulong flags;
ulong isa;
};
int
dwarfpctoline(Dwarf *d, ulong pc, char **cdir, char **dir, char **file, ulong *line, ulong *mtime, ulong *length)
{
uchar *prog, *opcount, *end;
ulong off, unit, len, vers, x, start;
int i, first, op, a, l, quantum, isstmt, linebase, linerange, opcodebase, nf;
char *files, *dirs, *s;
DwarfBuf b;
DwarfSym sym;
State emit, cur, reset;
uchar **f, **newf;
f = nil;
if(dwarfaddrtounit(d, pc, &unit) < 0
|| dwarflookuptag(d, unit, TagCompileUnit, &sym) < 0)
return -1;
if(!sym.attrs.have.stmtlist){
werrstr("no line mapping information for 0x%lux", pc);
return -1;
}
off = sym.attrs.stmtlist;
if(off >= d->line.len){
fprint(2, "bad stmtlist\n");
goto bad;
}
if(trace) fprint(2, "unit 0x%lux stmtlist 0x%lux\n", unit, sym.attrs.stmtlist);
memset(&b, 0, sizeof b);
b.d = d;
b.p = d->line.data + off;
b.ep = b.p + d->line.len;
b.addrsize = sym.b.addrsize; /* should i get this from somewhere else? */
len = dwarfget4(&b);
if(b.p==nil || b.p+len > b.ep || b.p+len < b.p){
fprint(2, "bad len\n");
goto bad;
}
b.ep = b.p+len;
vers = dwarfget2(&b);
if(vers != 2){
werrstr("bad dwarf version 0x%lux", vers);
return -1;
}
len = dwarfget4(&b);
if(b.p==nil || b.p+len > b.ep || b.p+len < b.p){
fprint(2, "another bad len\n");
goto bad;
}
prog = b.p+len;
quantum = dwarfget1(&b);
isstmt = dwarfget1(&b);
linebase = (schar)dwarfget1(&b);
linerange = (schar)dwarfget1(&b);
opcodebase = dwarfget1(&b);
opcount = b.p-1;
dwarfgetnref(&b, opcodebase-1);
if(b.p == nil){
fprint(2, "bad opcode chart\n");
goto bad;
}
/* just skip the files and dirs for now; we'll come back */
dirs = b.p;
while(b.p!=nil && *b.p!=0)
dwarfgetstring(&b);
dwarfget1(&b);
files = b.p;
while(b.p!=nil && *b.p!=0){
dwarfgetstring(&b);
dwarfget128(&b);
dwarfget128(&b);
dwarfget128(&b);
}
dwarfget1(&b);
/* move on to the program */
if(b.p == nil || b.p > prog){
fprint(2, "bad header\n");
goto bad;
}
b.p = prog;
reset.addr = 0;
reset.file = 1;
reset.line = 1;
reset.column = 0;
reset.flags = isstmt ? Isstmt : 0;
reset.isa = 0;
cur = reset;
emit = reset;
nf = 0;
start = 0;
if(trace) fprint(2, "program @ %lud ... %.*H opbase = %d\n", b.p - d->line.data, b.ep-b.p, b.p, opcodebase);
first = 1;
while(b.p != nil){
op = dwarfget1(&b);
if(trace) fprint(2, "\tline %lud, addr 0x%lux, op %d %.10H", cur.line, cur.addr, op, b.p);
if(op >= opcodebase){
a = (op - opcodebase) / linerange;
l = (op - opcodebase) % linerange + linebase;
cur.line += l;
cur.addr += a * quantum;
if(trace) fprint(2, " +%d,%d\n", a, l);
emit:
if(first){
if(cur.addr > pc){
werrstr("found wrong line mapping 0x%lux for pc 0x%lux", cur.addr, pc);
goto out;
}
first = 0;
start = cur.addr;
}
if(cur.addr > pc)
break;
if(b.p == nil){
werrstr("buffer underflow in line mapping");
goto out;
}
emit = cur;
if(emit.flags & EndSequence){
werrstr("found wrong line mapping 0x%lux-0x%lux for pc 0x%lux", start, cur.addr, pc);
goto out;
}
cur.flags &= ~(BasicDwarfBlock|PrologueEnd|EpilogueBegin);
}else{
switch(op){
case 0: /* extended op code */
if(trace) fprint(2, " ext");
len = dwarfget128(&b);
end = b.p+len;
if(b.p == nil || end > b.ep || end < b.p || len < 1)
goto bad;
switch(dwarfget1(&b)){
case 1: /* end sequence */
if(trace) fprint(2, " end\n");
cur.flags |= EndSequence;
goto emit;
case 2: /* set address */
cur.addr = dwarfgetaddr(&b);
if(trace) fprint(2, " set pc 0x%lux\n", cur.addr);
break;
case 3: /* define file */
newf = realloc(f, (nf+1)*sizeof(f[0]));
if(newf == nil)
goto out;
f[nf++] = b.p;
s = dwarfgetstring(&b);
dwarfget128(&b);
dwarfget128(&b);
dwarfget128(&b);
if(trace) fprint(2, " def file %s\n", s);
break;
}
if(b.p == nil || b.p > end)
goto bad;
b.p = end;
break;
case 1: /* emit */
if(trace) fprint(2, " emit\n");
goto emit;
case 2: /* advance pc */
a = dwarfget128(&b);
if(trace) fprint(2, " advance pc + %lud\n", a*quantum);
cur.addr += a * quantum;
break;
case 3: /* advance line */
l = dwarfget128s(&b);
if(trace) fprint(2, " advance line + %ld\n", l);
cur.line += l;
break;
case 4: /* set file */
if(trace) fprint(2, " set file\n");
cur.file = dwarfget128s(&b);
break;
case 5: /* set column */
if(trace) fprint(2, " set column\n");
cur.column = dwarfget128(&b);
break;
case 6: /* negate stmt */
if(trace) fprint(2, " negate stmt\n");
cur.flags ^= Isstmt;
break;
case 7: /* set basic block */
if(trace) fprint(2, " set basic block\n");
cur.flags |= BasicDwarfBlock;
break;
case 8: /* const add pc */
a = (255 - opcodebase) / linerange * quantum;
if(trace) fprint(2, " const add pc + %d\n", a);
cur.addr += a;
break;
case 9: /* fixed advance pc */
a = dwarfget2(&b);
if(trace) fprint(2, " fixed advance pc + %d\n", a);
cur.addr += a;
break;
case 10: /* set prologue end */
if(trace) fprint(2, " set prologue end\n");
cur.flags |= PrologueEnd;
break;
case 11: /* set epilogue begin */
if(trace) fprint(2, " set epilogue begin\n");
cur.flags |= EpilogueBegin;
break;
case 12: /* set isa */
if(trace) fprint(2, " set isa\n");
cur.isa = dwarfget128(&b);
break;
default: /* something new - skip it */
if(trace) fprint(2, " unknown %d\n", opcount[op]);
for(i=0; i<opcount[op]; i++)
dwarfget128(&b);
break;
}
}
}
if(b.p == nil)
goto bad;
/* finally! the data we seek is in "emit" */
if(emit.file == 0){
werrstr("invalid file index in mapping data");
goto out;
}
if(line)
*line = emit.line;
/* skip over first emit.file-2 guys */
b.p = files;
for(i=emit.file-1; i > 0 && b.p!=nil && *b.p!=0; i--){
dwarfgetstring(&b);
dwarfget128(&b);
dwarfget128(&b);
dwarfget128(&b);
}
if(b.p == nil){
werrstr("problem parsing file data second time (cannot happen)");
goto bad;
}
if(*b.p == 0){
if(i >= nf){
werrstr("bad file index in mapping data");
goto bad;
}
b.p = f[i];
}
s = dwarfgetstring(&b);
if(file)
*file = s;
i = dwarfget128(&b); /* directory */
x = dwarfget128(&b);
if(mtime)
*mtime = x;
x = dwarfget128(&b);
if(length)
*length = x;
/* fetch dir name */
if(cdir)
*cdir = sym.attrs.compdir;
if(dir){
if(i == 0)
*dir = nil;
else{
b.p = dirs;
for(i--; i>0 && b.p!=nil && *b.p!=0; i--)
dwarfgetstring(&b);
if(b.p==nil || *b.p==0){
werrstr("bad directory reference in line mapping");
goto out; /* can only happen with bad dir index */
}
*dir = dwarfgetstring(&b);
}
}
/* free at last, free at last */
free(f);
return 0;
bad:
werrstr("corrupted line mapping for 0x%lux", pc);
out:
free(f);
return -1;
}

View File

@ -0,0 +1,76 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "elf.h"
#include "dwarf.h"
static int
_dwarfnametounit(Dwarf *d, char *name, DwarfBlock *bl, DwarfSym *s)
{
int vers;
ulong len, unit, off;
uchar *next;
char *str;
DwarfBuf b;
b.d = d;
b.p = bl->data;
b.ep = b.p + bl->len;
while(b.p < b.ep){
len = dwarfget4(&b);
if(len > b.ep-b.p){
werrstr("bad length in dwarf name header");
return -1;
}
next = b.p + len;
vers = dwarfget2(&b);
if(vers != 1 && vers != 2){
werrstr("bad version %d in dwarf name header", vers);
return -1;
}
unit = dwarfget4(&b);
dwarfget4(&b); /* unit length */
while(b.p < next){
off = dwarfget4(&b);
if(off == 0)
break;
str = dwarfgetstring(&b);
if(strcmp(str, name) == 0){
if(dwarfenumunit(d, unit, s) < 0)
return -1;
if(unit + off >= s->b.ep - d->info.data){
werrstr("bad offset in name entry");
return -1;
}
s->b.p = d->info.data + unit + off;
if(dwarfnextsym(d, s, 1) < 0)
return -1;
if(s->attrs.name==nil || strcmp(s->attrs.name, name)!=0){
werrstr("unexpected name %#q in lookup for %#q", s->attrs.name, name);
return -1;
}
return 0;
}
}
b.p = next;
}
werrstr("unknown name '%s'", name);
return -1;
}
int
dwarflookupname(Dwarf *d, char *name, DwarfSym *sym)
{
return _dwarfnametounit(d, name, &d->pubnames, sym);
}
/*
int
dwarflookuptype(Dwarf *d, char *name, DwarfSym *sym)
{
return _dwarfnametounit(d, name, &d->pubtypes, sym);
}
*/

405
src/libmach/elf.c Normal file
View File

@ -0,0 +1,405 @@
/*
* Parse 32-bit ELF files.
* Copyright (c) 2004 Russ Cox. See LICENSE.
*/
#include <u.h>
#include <libc.h>
#include <mach.h>
#include "elf.h"
typedef struct ElfHdrBytes ElfHdrBytes;
typedef struct ElfSectBytes ElfSectBytes;
typedef struct ElfProgBytes ElfProgBytes;
typedef struct ElfSymBytes ElfSymBytes;
struct ElfHdrBytes
{
uchar ident[16];
uchar type[2];
uchar machine[2];
uchar version[4];
uchar entry[4];
uchar phoff[4];
uchar shoff[4];
uchar flags[4];
uchar ehsize[2];
uchar phentsize[2];
uchar phnum[2];
uchar shentsize[2];
uchar shnum[2];
uchar shstrndx[2];
};
struct ElfSectBytes
{
uchar name[4];
uchar type[4];
uchar flags[4];
uchar addr[4];
uchar offset[4];
uchar size[4];
uchar link[4];
uchar info[4];
uchar align[4];
uchar entsize[4];
};
struct ElfSymBytes
{
uchar name[4];
uchar value[4];
uchar size[4];
uchar info; /* top4: bind, bottom4: type */
uchar other;
uchar shndx[2];
};
struct ElfProgBytes
{
uchar type[4];
uchar offset[4];
uchar vaddr[4];
uchar paddr[4];
uchar filesz[4];
uchar memsz[4];
uchar flags[4];
uchar align[4];
};
uchar ElfMagic[4] = { 0x7F, 'E', 'L', 'F' };
static void unpackhdr(ElfHdr*, ElfHdrBytes*);
static void unpackprog(ElfHdr*, ElfProg*, ElfProgBytes*);
static void unpacksect(ElfHdr*, ElfSect*, ElfSectBytes*);
static char *elftypes[] = {
"none",
"relocatable",
"executable",
"shared object",
"core",
};
char*
elftype(int t)
{
if(t < 0 || t >= nelem(elftypes))
return "unknown";
return elftypes[t];
}
static char *elfmachs[] = {
"none",
"32100",
"sparc",
"386",
"68000",
"88000",
"486",
"860",
"MIPS",
};
char*
elfmachine(int t)
{
if(t < 0 || t >= nelem(elfmachs))
return "unknown";
return elfmachs[t];
}
Elf*
elfopen(char *name)
{
int fd;
Elf *e;
if((fd = open(name, OREAD)) < 0)
return nil;
if((e = elfinit(fd)) == nil)
close(fd);
return e;
}
Elf*
elfinit(int fd)
{
int i;
Elf *e;
ElfHdr *h;
ElfHdrBytes hdrb;
ElfProgBytes progb;
ElfSectBytes sectb;
ElfSect *s;
e = mallocz(sizeof(Elf), 1);
if(e == nil)
return nil;
e->fd = fd;
/*
* parse header
*/
seek(fd, 0, 0);
if(readn(fd, &hdrb, sizeof hdrb) != sizeof hdrb)
goto err;
h = &e->hdr;
unpackhdr(h, &hdrb);
if(h->class != ElfClass32){
werrstr("bad ELF class - not 32-bit");
goto err;
}
if(h->encoding != ElfDataLsb && h->encoding != ElfDataMsb){
werrstr("bad ELF encoding - not LSB, MSB");
goto err;
}
if(hdrb.ident[6] != h->version){
werrstr("bad ELF encoding - version mismatch %02ux and %08ux",
(uint)hdrb.ident[6], (uint)h->version);
goto err;
}
/*
* the prog+section info is almost always small - just load it into memory.
*/
e->nprog = h->phnum;
e->prog = mallocz(sizeof(ElfProg)*e->nprog, 1);
for(i=0; i<e->nprog; i++){
if(seek(fd, h->phoff+i*h->phentsize, 0) < 0
|| readn(fd, &progb, sizeof progb) != sizeof progb)
goto err;
unpackprog(h, &e->prog[i], &progb);
}
e->nsect = h->shnum;
if(e->nsect == 0)
goto nosects;
e->sect = mallocz(sizeof(ElfSect)*e->nsect, 1);
for(i=0; i<e->nsect; i++){
if(seek(fd, h->shoff+i*h->shentsize, 0) < 0
|| readn(fd, &sectb, sizeof sectb) != sizeof sectb)
goto err;
unpacksect(h, &e->sect[i], &sectb);
}
if(h->shstrndx >= e->nsect){
fprint(2, "warning: bad string section index %d >= %d", h->shstrndx, e->nsect);
h->shnum = 0;
e->nsect = 0;
goto nosects;
}
s = &e->sect[h->shstrndx];
if(elfmap(e, s) < 0)
goto err;
for(i=0; i<e->nsect; i++)
if(e->sect[i].name)
e->sect[i].name = s->base + (ulong)e->sect[i].name;
e->symtab = elfsection(e, ".symtab");
if(e->symtab){
if(e->symtab->link >= e->nsect)
e->symtab = nil;
else{
e->symstr = &e->sect[e->symtab->link];
e->nsymtab = e->symtab->size / sizeof(ElfSymBytes);
}
}
e->dynsym = elfsection(e, ".dynsym");
if(e->dynsym){
if(e->dynsym->link >= e->nsect)
e->dynsym = nil;
else{
e->dynstr = &e->sect[e->dynsym->link];
e->ndynsym = e->dynsym->size / sizeof(ElfSymBytes);
}
}
e->bss = elfsection(e, ".bss");
nosects:
return e;
err:
free(e->sect);
free(e->prog);
free(e->shstrtab);
free(e);
return nil;
}
void
elfclose(Elf *elf)
{
int i;
for(i=0; i<elf->nsect; i++)
free(elf->sect[i].base);
free(elf->sect);
free(elf->prog);
free(elf->shstrtab);
free(elf);
}
static void
unpackhdr(ElfHdr *h, ElfHdrBytes *b)
{
u16int (*e2)(uchar*);
u32int (*e4)(uchar*);
u64int (*e8)(uchar*);
memmove(h->magic, b->ident, 4);
h->class = b->ident[4];
h->encoding = b->ident[5];
switch(h->encoding){
case ElfDataLsb:
e2 = leload2;
e4 = leload4;
e8 = leload8;
break;
case ElfDataMsb:
e2 = beload2;
e4 = beload4;
e8 = beload8;
break;
default:
return;
}
h->abi = b->ident[7];
h->abiversion = b->ident[8];
h->e2 = e2;
h->e4 = e4;
h->e8 = e8;
h->type = e2(b->type);
h->machine = e2(b->machine);
h->version = e4(b->version);
h->entry = e4(b->entry);
h->phoff = e4(b->phoff);
h->shoff = e4(b->shoff);
h->flags = e4(b->flags);
h->ehsize = e2(b->ehsize);
h->phentsize = e2(b->phentsize);
h->phnum = e2(b->phnum);
h->shentsize = e2(b->shentsize);
h->shnum = e2(b->shnum);
h->shstrndx = e2(b->shstrndx);
}
static void
unpackprog(ElfHdr *h, ElfProg *p, ElfProgBytes *b)
{
u32int (*e4)(uchar*);
e4 = h->e4;
p->type = e4(b->type);
p->offset = e4(b->offset);
p->vaddr = e4(b->vaddr);
p->paddr = e4(b->paddr);
p->filesz = e4(b->filesz);
p->memsz = e4(b->memsz);
p->flags = e4(b->flags);
p->align = e4(b->align);
}
static void
unpacksect(ElfHdr *h, ElfSect *s, ElfSectBytes *b)
{
u32int (*e4)(uchar*);
e4 = h->e4;
s->name = (char*)e4(b->name);
s->type = e4(b->type);
s->flags = e4(b->flags);
s->addr = e4(b->addr);
s->offset = e4(b->offset);
s->size = e4(b->size);
s->link = e4(b->link);
s->info = e4(b->info);
s->align = e4(b->align);
s->entsize = e4(b->entsize);
}
ElfSect*
elfsection(Elf *elf, char *name)
{
int i;
for(i=0; i<elf->nsect; i++){
if(elf->sect[i].name == name)
return &elf->sect[i];
if(elf->sect[i].name && name
&& strcmp(elf->sect[i].name, name) == 0)
return &elf->sect[i];
}
werrstr("elf section '%s' not found", name);
return nil;
}
int
elfmap(Elf *elf, ElfSect *sect)
{
if(sect->base)
return 0;
if((sect->base = malloc(sect->size)) == nil)
return -1;
werrstr("short read");
if(seek(elf->fd, sect->offset, 0) < 0
|| readn(elf->fd, sect->base, sect->size) != sect->size){
free(sect->base);
sect->base = nil;
return -1;
}
return 0;
}
int
elfsym(Elf *elf, int i, ElfSym *sym)
{
ElfSect *symtab, *strtab;
uchar *p;
char *s;
ulong x;
if(i < 0){
werrstr("bad index %d in elfsym", i);
return -1;
}
if(i < elf->nsymtab){
symtab = elf->symtab;
strtab = elf->symstr;
extract:
if(elfmap(elf, symtab) < 0 || elfmap(elf, strtab) < 0)
return -1;
p = symtab->base + i * sizeof(ElfSymBytes);
s = strtab->base;
x = elf->hdr.e4(p);
if(x >= strtab->size){
werrstr("bad symbol name offset 0x%lux", x);
return -1;
}
sym->name = s + x;
sym->value = elf->hdr.e4(p+4);
sym->size = elf->hdr.e4(p+8);
x = p[12];
sym->bind = x>>4;
sym->type = x & 0xF;
sym->other = p[13];
sym->shndx = elf->hdr.e2(p+14);
return 0;
}
i -= elf->nsymtab;
if(i < elf->ndynsym){
symtab = elf->dynsym;
strtab = elf->dynstr;
goto extract;
}
/* i -= elf->ndynsym */
werrstr("symbol index out of range");
return -1;
}

233
src/libmach/elf.h Normal file
View File

@ -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**);

142
src/libmach/elfcore.h Normal file
View File

@ -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;
};

View File

@ -0,0 +1,89 @@
#include <u.h>
#include <libc.h>
#include <mach.h>
#include "elf.h"
#include "ureg386.h"
typedef struct Lreg Lreg;
typedef struct Status Status;
struct Lreg
{
u32int fs;
u32int es;
u32int ds;
u32int edi;
u32int esi;
u32int ebp;
u32int isp;
u32int ebx;
u32int edx;
u32int ecx;
u32int eax;
u32int trapno;
u32int err;
u32int eip;
u32int cs;
u32int eflags;
u32int esp;
u32int ss;
u32int gs;
};
struct Status
{
u32int version; /* Version number of struct (1) */
u32int statussz; /* sizeof(prstatus_t) (1) */
u32int gregsetsz; /* sizeof(gregset_t) (1) */
u32int fpregsetsz; /* sizeof(fpregset_t) (1) */
u32int osreldate; /* Kernel version (1) */
u32int cursig; /* Current signal (1) */
u32int pid; /* Process ID (1) */
Lreg reg; /* General purpose registers (1) */
};
int
coreregsfreebsd386(Elf *elf, ElfNote *note, uchar **up)
{
Status *s;
Lreg *l;
Ureg *u;
if(note->descsz < sizeof(Status)){
werrstr("elf status note too small");
return -1;
}
s = (Status*)note->desc;
if(s->version != 1){
werrstr("unknown status version %ud", (uint)s->version);
return -1;
}
l = &s->reg;
u = malloc(sizeof(Ureg));
if(u == nil)
return -1;
/* no byte order problems - just copying and rearranging */
u->di = l->edi;
u->si = l->esi;
u->bp = l->ebp;
u->nsp = l->esp;
u->bx = l->ebx;
u->dx = l->edx;
u->cx = l->ecx;
u->ax = l->eax;
u->gs = l->gs;
u->fs = l->fs;
u->es = l->es;
u->ds = l->ds;
u->trap = l->trapno;
u->ecode = l->err;
u->pc = l->eip;
u->cs = l->cs;
u->flags = l->eflags;
u->sp = l->esp;
u->ss = l->ss;
*up = (uchar*)u;
return sizeof(Ureg);
}

View File

@ -0,0 +1,95 @@
#include <u.h>
#include <libc.h>
#include <mach.h>
#include "elf.h"
#include "ureg386.h"
typedef struct Lreg Lreg;
typedef struct Status Status;
struct Lreg
{
u32int ebx;
u32int ecx;
u32int edx;
u32int esi;
u32int edi;
u32int ebp;
u32int eax;
u32int ds;
u32int es;
u32int fs;
u32int gs;
u32int origeax;
u32int eip;
u32int cs;
u32int eflags;
u32int esp;
u32int ss;
};
/*
* Lreg is 64-bit aligned within status, so we shouldn't
* have any packing problems.
*/
struct Status
{
u32int signo;
u32int code;
u32int errno;
u32int cursig;
u32int sigpend;
u32int sighold;
u32int pid;
u32int ppid;
u32int pgrp;
u32int sid;
u32int utime[2];
u32int stime[2];
u32int cutime[2];
u32int cstime[2];
Lreg reg;
u32int fpvalid;
};
int
coreregslinux386(Elf *elf, ElfNote *note, uchar **up)
{
Status *s;
Lreg *l;
Ureg *u;
if(note->descsz < sizeof(Status)){
werrstr("elf status note too small");
return -1;
}
s = (Status*)note->desc;
l = &s->reg;
u = malloc(sizeof(Ureg));
if(u == nil)
return -1;
/* no byte order problems - just copying and rearranging */
u->di = l->edi;
u->si = l->esi;
u->bp = l->ebp;
u->nsp = l->esp;
u->bx = l->ebx;
u->dx = l->edx;
u->cx = l->ecx;
u->ax = l->eax;
u->gs = l->gs;
u->fs = l->fs;
u->es = l->es;
u->ds = l->ds;
u->trap = ~0; // l->trapno;
u->ecode = ~0; // l->err;
u->pc = l->eip;
u->cs = l->cs;
u->flags = l->eflags;
u->sp = l->esp;
u->ss = l->ss;
*up = (uchar*)u;
return sizeof(Ureg);
}

133
src/libmach/elfdump.c Normal file
View File

@ -0,0 +1,133 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <mach.h>
#include "elf.h"
#include "stabs.h"
void
usage(void)
{
fprint(2, "usage: elf file list\n");
fprint(2, " elf file syms\n");
fprint(2, " elf file prog n\n");
fprint(2, " elf file sect n\n");
exits("usage");
}
void
main(int argc, char **argv)
{
int i, n, nn;
char buf[512];
ulong off, len;
Elf *elf;
ElfProg *p;
ElfSect *s;
ARGBEGIN{
default:
usage();
}ARGEND
if(argc < 2)
usage();
if((elf = elfopen(argv[0])) == nil)
sysfatal("elfopen %s: %r", argv[0]);
if(strcmp(argv[1], "syms") == 0){
ElfSym sym;
for(i=0; elfsym(elf, i, &sym) >= 0; i++){
print("%s 0x%lux +%lud bind %d type %d other %d shndx 0x%ux\n",
sym.name, (ulong)sym.value, (ulong)sym.size,
sym.bind, sym.type, sym.other, (uint)sym.shndx);
}
}
else if(strcmp(argv[1], "stabs") == 0){
ElfSect *s1, *s2;
Stab stabs;
StabSym sym;
if((s1 = elfsection(elf, ".stab")) == nil)
sysfatal("no stabs");
if(s1->link==0 || s1->link >= elf->nsect)
sysfatal("bad stabstr %d", s1->link);
s2 = &elf->sect[s1->link];
if(elfmap(elf, s1) < 0 || elfmap(elf, s2) < 0)
sysfatal("elfmap");
stabs.stabbase = s1->base;
stabs.stabsize = s1->size;
stabs.strbase = s2->base;
stabs.strsize = s2->size;
stabs.e2 = elf->hdr.e2;
stabs.e4 = elf->hdr.e4;
print("%ud %ud\n", stabs.stabsize, stabs.strsize);
for(i=0; stabsym(&stabs, i, &sym) >= 0; i++)
print("%s type 0x%x other %d desc %d value 0x%lux\n",
sym.name, sym.type, sym.other, (int)sym.desc, (ulong)sym.value);
fprint(2, "err at %d: %r\n", i);
}
else if(strcmp(argv[1], "list") == 0){
if(argc != 2)
usage();
print("elf %s %s v%d entry 0x%08lux phoff 0x%lux shoff 0x%lux flags 0x%lux\n",
elftype(elf->hdr.type), elfmachine(elf->hdr.machine),
elf->hdr.version, elf->hdr.entry, elf->hdr.phoff, elf->hdr.shoff,
elf->hdr.flags);
print("\tehsize %d phentsize %d phnum %d shentsize %d shnum %d shstrndx %d\n",
elf->hdr.ehsize, elf->hdr.phentsize, elf->hdr.phnum, elf->hdr.shentsize,
elf->hdr.shnum, elf->hdr.shstrndx);
for(i=0; i<elf->nprog; i++){
p = &elf->prog[i];
print("prog %d type %d offset 0x%08lux vaddr 0x%08lux paddr 0x%08lux filesz 0x%08lux memsz 0x%08lux flags 0x%08lux align 0x%08lux\n",
i, p->type, p->offset, p->vaddr, p->paddr,
p->filesz, p->memsz, p->flags, p->align);
}
for(i=0; i<elf->nsect; i++){
s = &elf->sect[i];
print("sect %d %s type %d flags 0x%lux addr 0x%08lux offset 0x%08lux size 0x%08lux link 0x%lux info 0x%lux align 0x%lux entsize 0x%lux\n",
i, s->name, s->type, s->flags, s->addr, s->offset, s->size, s->link, s->info,
s->align, s->entsize);
}
}
else if(strcmp(argv[1], "prog") == 0){
if(argc != 3)
usage();
i = atoi(argv[2]);
if(i < 0 || i >= elf->nprog)
sysfatal("bad prog number");
off = elf->prog[i].offset;
len = elf->prog[i].filesz;
fprint(2, "prog %d offset 0x%lux size 0x%lux\n", i, off, len);
copy:
seek(elf->fd, off, 0);
for(n=0; n<len; n+=nn){
nn = sizeof buf;
if(nn > len-n)
nn = len-n;
nn = read(elf->fd, buf, nn);
if(nn == 0)
break;
if(nn < 0)
sysfatal("read error");
write(1, buf, nn);
}
if(n < len)
fprint(2, "early eof\n");
}
else if(strcmp(argv[1], "sect") == 0){
if(argc != 3)
usage();
i = atoi(argv[2]);
if(i < 0 || i >= elf->nsect)
sysfatal("bad section number");
off = elf->sect[i].offset;
len = elf->sect[i].size;
fprint(2, "section %d offset 0x%lux size 0x%lux\n", i, off, len);
goto copy;
}
else
usage();
exits(0);
}

6
src/libmach/elfdynsym.c Normal file
View File

@ -0,0 +1,6 @@
#include <u.h>
#include <libc.h>
#include "elf.h"
int
elfsym(Elf *elf, ElfSect *symtab, ElfSect *strtab, int ndx, ElfSym *

65
src/libmach/fpformat.c Normal file
View File

@ -0,0 +1,65 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <mach.h>
/*
* Format floating point registers
*
* Register codes in format field:
* 'X' - print as 32-bit hexadecimal value
* 'F' - 64-bit double register when modif == 'F'; else 32-bit single reg
* 'f' - 32-bit ieee float
* '8' - big endian 80-bit ieee extended float
* '3' - little endian 80-bit ieee extended float with hole in bytes 8&9
*/
int
fpformat(Map *map, Regdesc *rp, char *buf, uint n, uint modif)
{
char reg[12];
u32int r;
switch(rp->format)
{
case 'X':
if (get4(map, rp->offset, &r) < 0)
return -1;
snprint(buf, n, "%lux", r);
break;
case 'F': /* first reg of double reg pair */
if (modif == 'F')
if ((rp->format=='F') || (((rp+1)->flags&RFLT) && (rp+1)->format == 'f')) {
if (get1(map, rp->offset, (uchar *)reg, 8) < 0)
return -1;
mach->ftoa64(buf, n, reg);
if (rp->format == 'F')
return 1;
return 2;
}
/* treat it like 'f' */
if (get1(map, rp->offset, (uchar *)reg, 4) < 0)
return -1;
mach->ftoa32(buf, n, reg);
break;
case 'f': /* 32 bit float */
if (get1(map, rp->offset, (uchar *)reg, 4) < 0)
return -1;
mach->ftoa32(buf, n, reg);
break;
case '3': /* little endian ieee 80 with hole in bytes 8&9 */
if (get1(map, rp->offset, (uchar *)reg, 10) < 0)
return -1;
memmove(reg+10, reg+8, 2); /* open hole */
memset(reg+8, 0, 2); /* fill it */
leieeeftoa80(buf, n, reg);
break;
case '8': /* big-endian ieee 80 */
if (get1(map, rp->offset, (uchar *)reg, 10) < 0)
return -1;
beieeeftoa80(buf, n, reg);
break;
default: /* unknown */
break;
}
return 1;
}

130
src/libmach/frame.c Normal file
View File

@ -0,0 +1,130 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <mach.h>
typedef struct LocRegs LocRegs;
struct LocRegs
{
Regs r;
Regs *oldregs;
Map *map;
ulong *val;
};
static int
locregrw(Regs *regs, char *name, ulong *val, int isr)
{
int i;
LocRegs *lr;
lr = (LocRegs*)regs;
i = windindex(name);
if(i == -1)
return lr->oldregs->rw(lr->oldregs, name, val, isr);
if(isr){
*val = lr->val[i];
return 0;
}else{
werrstr("saved registers are immutable");
return -1;
}
}
int
stacktrace(Map *map, Regs *regs, Tracer trace)
{
char *rname;
int i, ipc, ret;
ulong nextpc, pc, v;
ulong *cur, *next;
LocRegs lr;
Symbol s, *sp;
/*
* Allocate location arrays.
*/
ret = -1;
cur = malloc(mach->nwindreg*sizeof(cur[0]));
next = malloc(mach->nwindreg*sizeof(cur[0]));
if(cur==nil || next==nil)
goto out;
/*
* Initialize current registers using regs.
*/
if(rget(regs, mach->pc, &pc) < 0){
werrstr("cannot fetch initial pc: %r");
goto out;
}
for(i=0; i<mach->nwindreg; i++){
rname = mach->windreg[i];
if(rget(regs, rname, &v) < 0)
v = ~(ulong)0;
cur[i] = v;
}
ipc = windindex(mach->pc);
ret = 0;
/* set up cur[i]==next[i] for unwindframe */
memmove(next, cur, mach->nwindreg*sizeof(next[0]));
for(;;){
sp = &s;
if(findsym(locaddr(pc), CTEXT, &s) < 0)
sp = nil;
lr.r.rw = locregrw;
lr.oldregs = regs;
lr.val = cur;
lr.map = map;
if((i = unwindframe(map, &lr.r, next)) >= 0)
nextpc = next[ipc];
else
nextpc = ~(ulong)0;
if((*trace)(map, &lr.r, pc, nextpc, sp, ++ret) <= 0)
break;
if(i < 0)
break;
if(sp && strcmp(sp->name, "main") == 0)
break;
pc = nextpc;
memmove(cur, next, mach->nwindreg*sizeof(cur[0]));
}
out:
free(cur);
free(next);
return ret;
}
int
windindex(char *reg)
{
char **p;
int i;
p = mach->windreg;
for(i=0; i<mach->nwindreg; i++)
if(strcmp(p[i], reg) == 0)
return i;
werrstr("%s is not a winding register", reg);
return -1;
}
Loc*
windreglocs(void)
{
int i;
Loc *loc;
loc = malloc(mach->nwindreg*sizeof(loc[0]));
if(loc == nil)
return nil;
for(i=0; i<mach->nwindreg; i++){
loc[i].type = LREG;
loc[i].reg = mach->windreg[i];
}
return loc;
}

20
src/libmach/hexify.c Normal file
View File

@ -0,0 +1,20 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <mach.h>
char *
_hexify(char *buf, ulong p, int zeros)
{
ulong d;
d = p/16;
if(d)
buf = _hexify(buf, d, zeros-1);
else
while(zeros--)
*buf++ = '0';
*buf++ = "0123456789abcdef"[p&0x0f];
return buf;
}

169
src/libmach/ieee.c Normal file
View File

@ -0,0 +1,169 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <mach.h>
/*
* These routines assume that if the number is representable
* in IEEE floating point, it will be representable in the native
* double format. Naive but workable, probably.
*/
int
ieeeftoa64(char *buf, uint n, u32int h, u32int l)
{
double fr;
int exp;
if (n <= 0)
return 0;
if(h & (1L<<31)){
*buf++ = '-';
h &= ~(1L<<31);
}else
*buf++ = ' ';
n--;
if(l == 0 && h == 0)
return snprint(buf, n, "0.");
exp = (h>>20) & ((1L<<11)-1L);
if(exp == 0)
return snprint(buf, n, "DeN(%.8lux%.8lux)", h, l);
if(exp == ((1L<<11)-1L)){
if(l==0 && (h&((1L<<20)-1L)) == 0)
return snprint(buf, n, "Inf");
else
return snprint(buf, n, "NaN(%.8lux%.8lux)", h&((1L<<20)-1L), l);
}
exp -= (1L<<10) - 2L;
fr = l & ((1L<<16)-1L);
fr /= 1L<<16;
fr += (l>>16) & ((1L<<16)-1L);
fr /= 1L<<16;
fr += (h & (1L<<20)-1L) | (1L<<20);
fr /= 1L<<21;
fr = ldexp(fr, exp);
return snprint(buf, n, "%.18g", fr);
}
int
ieeeftoa32(char *buf, uint n, u32int h)
{
double fr;
int exp;
if (n <= 0)
return 0;
if(h & (1L<<31)){
*buf++ = '-';
h &= ~(1L<<31);
}else
*buf++ = ' ';
n--;
if(h == 0)
return snprint(buf, n, "0.");
exp = (h>>23) & ((1L<<8)-1L);
if(exp == 0)
return snprint(buf, n, "DeN(%.8lux)", h);
if(exp == ((1L<<8)-1L)){
if((h&((1L<<23)-1L)) == 0)
return snprint(buf, n, "Inf");
else
return snprint(buf, n, "NaN(%.8lux)", h&((1L<<23)-1L));
}
exp -= (1L<<7) - 2L;
fr = (h & ((1L<<23)-1L)) | (1L<<23);
fr /= 1L<<24;
fr = ldexp(fr, exp);
return snprint(buf, n, "%.9g", fr);
}
int
beieeeftoa32(char *buf, uint n, void *s)
{
return ieeeftoa32(buf, n, beswap4(*(u32int*)s));
}
int
beieeeftoa64(char *buf, uint n, void *s)
{
return ieeeftoa64(buf, n, beswap4(*(u32int*)s), beswap4(((u32int*)(s))[1]));
}
int
leieeeftoa32(char *buf, uint n, void *s)
{
return ieeeftoa32(buf, n, leswap4(*(u32int*)s));
}
int
leieeeftoa64(char *buf, uint n, void *s)
{
return ieeeftoa64(buf, n, leswap4(((u32int*)(s))[1]), leswap4(*(u32int*)s));
}
/* packed in 12 bytes, with s[2]==s[3]==0; mantissa starts at s[4]*/
int
beieeeftoa80(char *buf, uint n, void *s)
{
uchar *reg = (uchar*)s;
int i;
ulong x;
uchar ieee[8+8]; /* room for slop */
uchar *p, *q;
memset(ieee, 0, sizeof(ieee));
/* sign */
if(reg[0] & 0x80)
ieee[0] |= 0x80;
/* exponent */
x = ((reg[0]&0x7F)<<8) | reg[1];
if(x == 0) /* number is ±0 */
goto done;
if(x == 0x7FFF){
if(memcmp(reg+4, ieee+1, 8) == 0){ /* infinity */
x = 2047;
}else{ /* NaN */
x = 2047;
ieee[7] = 0x1; /* make sure */
}
ieee[0] |= x>>4;
ieee[1] |= (x&0xF)<<4;
goto done;
}
x -= 0x3FFF; /* exponent bias */
x += 1023;
if(x >= (1<<11) || ((reg[4]&0x80)==0 && x!=0))
return snprint(buf, n, "not in range");
ieee[0] |= x>>4;
ieee[1] |= (x&0xF)<<4;
/* mantissa */
p = reg+4;
q = ieee+1;
for(i=0; i<56; i+=8, p++, q++){ /* move one byte */
x = (p[0]&0x7F) << 1;
if(p[1] & 0x80)
x |= 1;
q[0] |= x>>4;
q[1] |= (x&0xF)<<4;
}
done:
return beieeeftoa64(buf, n, (void*)ieee);
}
int
leieeeftoa80(char *buf, uint n, void *s)
{
int i;
char *cp;
char b[12];
cp = (char*) s;
for(i=0; i<12; i++)
b[11-i] = *cp++;
return beieeeftoa80(buf, n, b);
}

253
src/libmach/loc.c Normal file
View File

@ -0,0 +1,253 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <mach.h>
int
locfmt(Fmt *fmt)
{
Loc l;
l = va_arg(fmt->args, Loc);
switch(l.type){
default:
return fmtprint(fmt, "<loc%d>", l.type);
case LCONST:
return fmtprint(fmt, "0x%lux", l.addr);
case LADDR:
return fmtprint(fmt, "*0x%lux", l.addr);
case LOFFSET:
return fmtprint(fmt, "%ld(%s)", l.offset, l.reg);
case LREG:
return fmtprint(fmt, "%s", l.reg);
}
}
int
loccmp(Loc *a, Loc *b)
{
int i;
if(a->type < b->type)
return -1;
if(a->type > b->type)
return 1;
switch(a->type){
default:
return 0;
case LADDR:
if(a->addr < b->addr)
return -1;
if(a->addr > b->addr)
return 1;
return 0;
case LOFFSET:
i = strcmp(a->reg, b->reg);
if(i != 0)
return i;
if(a->offset < b->offset)
return -1;
if(a->offset > b->offset)
return 1;
return 0;
case LREG:
return strcmp(a->reg, b->reg);
}
}
int
lget1(Map *map, Regs *regs, Loc loc, uchar *a, uint n)
{
if(locsimplify(map, regs, loc, &loc) < 0)
return -1;
if(loc.type == LADDR)
return get1(map, loc.addr, a, n);
/* could do more here - i'm lazy */
werrstr("bad location for lget1");
return -1;
}
int
lget2(Map *map, Regs *regs, Loc loc, u16int *u)
{
ulong ul;
if(locsimplify(map, regs, loc, &loc) < 0)
return -1;
if(loc.type == LADDR)
return get2(map, loc.addr, u);
if(loc.type == LCONST){
*u = loc.addr;
return 0;
}
if(loc.type == LREG){
if(rget(regs, loc.reg, &ul) < 0)
return -1;
*u = ul;
return 0;
}
werrstr("bad location for lget2");
return -1;
}
int
lget4(Map *map, Regs *regs, Loc loc, u32int *u)
{
ulong ul;
if(locsimplify(map, regs, loc, &loc) < 0)
return -1;
if(loc.type == LADDR)
return get4(map, loc.addr, u);
if(loc.type == LCONST){
*u = loc.addr;
return 0;
}
if(loc.type == LREG){
if(rget(regs, loc.reg, &ul) < 0)
return -1;
*u = ul;
return 0;
}
werrstr("bad location for lget4");
return -1;
}
int
lget8(Map *map, Regs *regs, Loc loc, u64int *u)
{
ulong ul;
if(locsimplify(map, regs, loc, &loc) < 0)
return -1;
if(loc.type == LADDR)
return get8(map, loc.addr, u);
if(loc.type == LCONST){
*u = loc.addr;
return 0;
}
if(loc.type == LREG){
if(rget(regs, loc.reg, &ul) < 0)
return -1;
*u = ul;
return 0;
}
werrstr("bad location for lget8");
return -1;
}
int
lput1(Map *map, Regs *regs, Loc loc, uchar *a, uint n)
{
if(locsimplify(map, regs, loc, &loc) < 0)
return -1;
if(loc.type == LADDR)
return put1(map, loc.addr, a, n);
/* could do more here - i'm lazy */
werrstr("bad location for lput1");
return -1;
}
int
lput2(Map *map, Regs *regs, Loc loc, u16int u)
{
if(locsimplify(map, regs, loc, &loc) < 0)
return -1;
if(loc.type == LADDR)
return put2(map, loc.addr, u);
if(loc.type == LREG)
return rput(regs, loc.reg, u);
werrstr("bad location for lput2");
return -1;
}
int
lput4(Map *map, Regs *regs, Loc loc, u32int u)
{
if(locsimplify(map, regs, loc, &loc) < 0)
return -1;
if(loc.type == LADDR)
return put4(map, loc.addr, u);
if(loc.type == LREG)
return rput(regs, loc.reg, u);
werrstr("bad location for lput4");
return -1;
}
int
lput8(Map *map, Regs *regs, Loc loc, u64int u)
{
if(locsimplify(map, regs, loc, &loc) < 0)
return -1;
if(loc.type == LADDR)
return put8(map, loc.addr, u);
if(loc.type == LREG)
return rput(regs, loc.reg, u);
werrstr("bad location for lput8");
return -1;
}
Loc
locaddr(ulong addr)
{
Loc l;
l.type = LADDR;
l.addr = addr;
return l;
}
Loc
locindir(char *reg, long offset)
{
Loc l;
l.type = LOFFSET;
l.reg = reg;
l.offset = offset;
return l;
}
Loc
locconst(ulong con)
{
Loc l;
l.type = LCONST;
l.addr = con;
return l;
}
Loc
locnone(void)
{
Loc l;
l.type = LNONE;
return l;
}
Loc
locreg(char *reg)
{
Loc l;
l.type = LREG;
l.reg = reg;
return l;
}
int
locsimplify(Map *map, Regs *regs, Loc loc, Loc *newloc)
{
ulong u;
if(loc.type == LOFFSET){
if(rget(regs, loc.reg, &u) < 0)
return -1;
*newloc = locaddr(u + loc.offset);
}else
*newloc = loc;
return 0;
}

56
src/libmach/localaddr.c Normal file
View File

@ -0,0 +1,56 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <mach.h>
/*
* XXX could remove the rock by hiding it in a special regs.
* That would still be sleazy but would be thread-safe.
*/
static struct {
int found;
int nframe;
Loc l;
char *fn;
char *var;
} rock;
static int
ltrace(Map *map, Regs *regs, ulong pc, ulong nextpc, Symbol *sym, int depth)
{
ulong v;
Symbol s1;
USED(pc);
USED(nextpc);
USED(depth);
if(sym==nil || strcmp(sym->name, rock.fn) != 0)
return ++rock.nframe < 40;
if(lookuplsym(sym, rock.var, &s1) < 0)
return 0;
if(locsimplify(map, regs, s1.loc, &rock.l) < 0)
return 0;
if(rock.l.type == LREG && rget(regs, rock.l.reg, &v) >= 0)
rock.l = locconst(v);
if(rock.l.type != LADDR && rock.l.type != LCONST)
return 0;
rock.found = 1;
return 0;
}
int
localaddr(Map *map, Regs *regs, char *fn, char *var, ulong *val)
{
rock.found = 0;
rock.nframe = 0;
rock.fn = fn;
rock.var = var;
stacktrace(map, regs, ltrace);
if(rock.found){
*val = rock.l.addr;
return 0;
}
return -1;
}

30
src/libmach/mach.c Normal file
View File

@ -0,0 +1,30 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <mach.h>
Mach *mach;
extern Mach mach386;
extern Mach machpower;
static Mach *machs[] =
{
&mach386,
&machpower,
};
Mach*
machbyname(char *name)
{
int i;
for(i=0; i<nelem(machs); i++)
if(strcmp(machs[i]->name, name) == 0){
mach = machs[i];
return machs[i];
}
werrstr("machine '%s' not found", name);
return nil;
}

1786
src/libmach/mach386.c Normal file

File diff suppressed because it is too large Load Diff

128
src/libmach/macho.c Normal file
View File

@ -0,0 +1,128 @@
#include <u.h>
#include <libc.h>
#include <mach.h>
#include "macho.h"
/*
http://www.channelu.com/NeXT/NeXTStep/3.3/nd/DevTools/14_MachO/MachO.htmld/
*/
Macho*
machoopen(char *name)
{
int fd;
Macho *m;
if((fd = open(name, OREAD)) < 0)
return nil;
m = machoinit(fd);
if(m == nil)
close(fd);
return m;
}
static int
unpackseg(uchar *p, Macho *m, MachoCmd *c, uint type, uint sz)
{
u32int (*e4)(uchar*);
e4 = m->e4;
c->type = type;
c->size = sz;
switch(type){
default:
return -1;
case MachoCmdSegment:
if(sz < 56)
return -1;
strecpy(c->seg.name, c->seg.name+sizeof c->seg.name, (char*)p+8);
c->seg.vmaddr = e4(p+24);
c->seg.vmsize = e4(p+28);
c->seg.fileoff = e4(p+32);
c->seg.filesz = e4(p+36);
c->seg.maxprot = e4(p+40);
c->seg.initprot = e4(p+44);
c->seg.nsect = e4(p+48);
c->seg.flags = e4(p+52);
break;
case MachoCmdSymtab:
if(sz < 24)
return -1;
c->sym.symoff = e4(p+8);
c->sym.nsyms = e4(p+12);
c->sym.stroff = e4(p+16);
c->sym.strsize = e4(p+20);
break;
}
return 0;
}
Macho*
machoinit(int fd)
{
int i;
uchar hdr[7*4], *cmdp;
u32int (*e4)(uchar*);
ulong ncmd, cmdsz, ty, sz, off;
Macho *m;
if(seek(fd, 0, 0) < 0 || readn(fd, hdr, sizeof hdr) != sizeof hdr)
return nil;
if(beload4(hdr) == 0xFEEDFACE)
e4 = beload4;
else if(leload4(hdr) == 0xFEEDFACE)
e4 = leload4;
else{
werrstr("bad magic - not mach-o file");
return nil;
}
ncmd = e4(hdr+4*4);
cmdsz = e4(hdr+5*4);
if(ncmd > 0x10000 || cmdsz >= 0x01000000){
werrstr("implausible mach-o header ncmd=%lud cmdsz=%lud", ncmd, cmdsz);
return nil;
}
m = mallocz(sizeof(*m)+ncmd*sizeof(MachoCmd)+cmdsz, 1);
if(m == nil)
return nil;
m->fd = fd;
m->e4 = e4;
m->cputype = e4(hdr+1*4);
m->subcputype = e4(hdr+2*4);
m->filetype = e4(hdr+3*4);
m->ncmd = ncmd;
m->flags = e4(hdr+6*4);
m->cmd = (MachoCmd*)(m+1);
off = sizeof hdr;
cmdp = (uchar*)(m->cmd+ncmd);
if(readn(fd, cmdp, cmdsz) != cmdsz){
werrstr("reading cmds: %r");
free(m);
return nil;
}
for(i=0; i<ncmd; i++){
ty = e4(cmdp);
sz = e4(cmdp+4);
m->cmd[i].off = off;
unpackseg(cmdp, m, &m->cmd[i], ty, sz);
cmdp += sz;
off += sz;
}
return m;
}
void
machoclose(Macho *m)
{
close(m->fd);
free(m);
}

71
src/libmach/macho.h Normal file
View File

@ -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**);

View File

@ -0,0 +1,173 @@
#include <u.h>
#include <libc.h>
#include <mach.h>
#include "macho.h"
#include "uregpower.h"
enum
{
ThreadState = 1,
FloatState,
ExceptionState,
VectorState,
ThreadState64,
ExceptionState64,
ThreadStateNone,
};
typedef struct Lreg Lreg;
typedef struct Lflt Lflt;
typedef struct Lexc Lexc;
struct Lreg
{
u32int srr0;
u32int srr1;
u32int r0;
u32int r1;
u32int r2;
u32int r3;
u32int r4;
u32int r5;
u32int r6;
u32int r7;
u32int r8;
u32int r9;
u32int r10;
u32int r11;
u32int r12;
u32int r13;
u32int r14;
u32int r15;
u32int r16;
u32int r17;
u32int r18;
u32int r19;
u32int r20;
u32int r21;
u32int r22;
u32int r23;
u32int r24;
u32int r25;
u32int r26;
u32int r27;
u32int r28;
u32int r29;
u32int r30;
u32int r31;
u32int cr;
u32int xer;
u32int lr;
u32int ctr;
u32int mq;
u32int vrsave;
};
struct Lflt
{
u32int fpregs[32*2]; /* 32 doubles */
u32int fpscr[2];
};
struct Lexc
{
u32int dar;
u32int dsisr;
u32int exception;
u32int pad0;
u32int pad1[4];
};
static void
lreg2ureg(Lreg *l, Ureg *u)
{
u->pc = l->srr0;
u->srr1 = l->srr1;
u->lr = l->lr;
u->cr = l->cr;
u->xer = l->xer;
u->ctr = l->ctr;
u->vrsave = l->vrsave;
memmove(&u->r0, &l->r0, 32*4);
}
static void
lexc2ureg(Lexc *l, Ureg *u)
{
u->cause = l->exception;
u->dar = l->dar;
u->dsisr = l->dsisr;
}
static uchar*
load(int fd, ulong off, int size)
{
uchar *a;
a = malloc(size);
if(a == nil)
return nil;
if(seek(fd, off, 0) < 0 || readn(fd, a, size) != size){
free(a);
return nil;
}
return a;
}
int
coreregsmachopower(Macho *m, uchar **up)
{
int i, havereg, haveexc;
uchar *a, *p, *nextp;
Ureg *u;
ulong flavor, count;
MachoCmd *c;
*up = nil;
for(i=0; i<m->ncmd; i++)
if(m->cmd[i].type == MachoCmdThread)
break;
if(i == m->ncmd){
werrstr("no registers found");
return -1;
}
c = &m->cmd[i];
a = load(m->fd, c->off, c->size);
if(a == nil)
return -1;
if((u = mallocz(sizeof(Ureg), 1)) == nil){
free(a);
return -1;
}
havereg = haveexc = 0;
for(p=a+8; p<a+c->size; p=nextp){
flavor = m->e4(p);
count = m->e4(p+4);
nextp = p+8+count*4;
if(flavor == ThreadState && count*4 == sizeof(Lreg)){
havereg = 1;
lreg2ureg((Lreg*)(p+8), u);
}
if(flavor == ExceptionState && count*4 == sizeof(Lexc)){
haveexc = 1;
lexc2ureg((Lexc*)(p+8), u);
}
}
free(a);
if(!havereg){
werrstr("no registers found");
free(u);
return -1;
}
if(!haveexc)
fprint(2, "warning: no exception state in core file registers\n");
*up = (uchar*)u;
return sizeof(*u);
}

93
src/libmach/machodump.c Normal file
View File

@ -0,0 +1,93 @@
#include <u.h>
#include <libc.h>
#include <mach.h>
#include "stabs.h"
#include "macho.h"
void
usage(void)
{
fprint(2, "usage: machodump file list\n");
fprint(2, " machodump file stabs\n");
exits("usage");
}
uchar*
load(int fd, ulong off, int size)
{
uchar *a;
a = malloc(size);
print("malloc %d -> %p\n", size, a);
if(a == nil)
sysfatal("malloc: %r");
if(seek(fd, off, 0) < 0)
sysfatal("seek %lud: %r", off);
if(readn(fd, a, size) != size)
sysfatal("readn: %r");
return a;
}
void
main(int argc, char **argv)
{
int i;
Macho *m;
ARGBEGIN{
default:
usage();
}ARGEND
if(argc < 2)
usage();
if((m = machoopen(argv[0])) == nil)
sysfatal("machoopen %s: %r", argv[0]);
if(strcmp(argv[1], "stabs") == 0){
Stab stabs;
StabSym sym;
for(i=0; i<m->ncmd; i++){
if(m->cmd[i].type == MachoCmdSymtab){
stabs.stabbase = load(m->fd, m->cmd[i].sym.symoff, m->cmd[i].sym.nsyms*16);
stabs.stabsize = m->cmd[i].sym.nsyms*16;
stabs.strbase = load(m->fd, m->cmd[i].sym.stroff, m->cmd[i].sym.strsize);
stabs.strsize = m->cmd[i].sym.strsize;
stabs.e4 = m->e4;
stabs.e2 = (m->e4 == beload4 ? beload2 : leload2);
print("cmd%d: %p %ud %p %ud\n", i, stabs.stabbase, stabs.stabsize, stabs.strbase, stabs.strsize);
for(i=0; stabsym(&stabs, i, &sym) >= 0; i++)
print("%s type 0x%x other %d desc %d value 0x%lux\n",
sym.name, sym.type, sym.other, (int)sym.desc, (ulong)sym.value);
print("err at %d: %r\n", i);
}
}
}
else if(strcmp(argv[1], "list") == 0){
print("macho cpu %ud sub %ud filetype %lud flags %lud\n",
m->cputype, m->subcputype, m->filetype, m->flags);
for(i=0; i<m->ncmd; i++){
switch(m->cmd[i].type){
case MachoCmdSymtab:
print("cmd%d: symtab %lud+%lud %lud+%lud\n", i,
m->cmd[i].sym.symoff, m->cmd[i].sym.nsyms,
m->cmd[i].sym.stroff, m->cmd[i].sym.strsize);
break;
case MachoCmdSegment:
print("cmd%d: segment %s vm 0x%lux+0x%lux file 0x%lux+0x%lux prot 0x%lux/0x%lux ns %d flags 0x%lux\n", i,
m->cmd[i].seg.name, m->cmd[i].seg.vmaddr, m->cmd[i].seg.vmsize,
m->cmd[i].seg.fileoff, m->cmd[i].seg.filesz, m->cmd[i].seg.maxprot,
m->cmd[i].seg.initprot, m->cmd[i].seg.nsect, m->cmd[i].seg.flags);
break;
default:
print("cmd%d: type %d offset %lud\n", i, m->cmd[i].type, m->cmd[i].off);
break;
}
}
}
else
usage();
exits(0);
}

1409
src/libmach/machpower.c Normal file

File diff suppressed because it is too large Load Diff

306
src/libmach/map.c Normal file
View File

@ -0,0 +1,306 @@
/*
* File map routines
*/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <mach.h>
static int fdrw(Map*, Seg*, ulong, void*, uint, int);
static int zerorw(Map*, Seg*, ulong, void*, uint, int);
static int mrw(Map*, ulong, void*, uint, int);
static int datarw(Map*, Seg*, ulong, void*, uint, int);
Map*
allocmap(void)
{
return mallocz(sizeof(Map), 1);
}
void
freemap(Map *map)
{
if(map == nil)
return;
free(map->seg);
free(map);
}
int
addseg(Map *map, Seg seg)
{
Seg *ss;
if(map == 0){
werrstr("invalid map");
return -1;
}
ss = realloc(map->seg, (map->nseg+1)*sizeof(ss[0]));
if(ss == nil)
return -1;
map->seg = ss;
if(seg.rw == nil){
if(seg.name && strcmp(seg.name, "zero") == 0)
seg.rw = zerorw;
else if(seg.p)
seg.rw = datarw;
else
seg.rw = fdrw;
}
map->seg[map->nseg] = seg;
return map->nseg++;
}
int
findseg(Map *map, char *name, char *file)
{
int i;
if(map == 0)
return -1;
for(i=0; i<map->nseg; i++){
if(name && (!map->seg[i].name || strcmp(map->seg[i].name, name) != 0))
continue;
if(file && (!map->seg[i].file || strcmp(map->seg[i].file, file) != 0))
continue;
return i;
}
werrstr("segment %s in %s not found", name, file);
return -1;
}
int
addrtoseg(Map *map, ulong addr, Seg *sp)
{
int i;
Seg *s;
if(map == nil){
werrstr("no map");
return -1;
}
for(i=map->nseg-1; i>=0; i--){
s = &map->seg[i];
if(s->base <= addr && addr-s->base < s->size){
if(sp)
*sp = *s;
return i;
}
}
werrstr("address 0x%lux is not mapped", addr);
return -1;
}
int
addrtosegafter(Map *map, ulong addr, Seg *sp)
{
int i;
Seg *s, *best;
ulong bdist;
if(map == nil){
werrstr("no map");
return -1;
}
/*
* If segments were sorted this would be easier,
* but since segments may overlap, sorting also
* requires splitting and rejoining, and that's just
* too complicated.
*/
best = nil;
bdist = 0;
for(i=map->nseg-1; i>=0; i--){
s = &map->seg[i];
if(s->base > addr){
if(best==nil || s->base-addr < bdist){
bdist = s->base - addr;
best = s;
}
}
}
if(best){
if(sp)
*sp = *best;
return best-map->seg;
}
werrstr("nothing mapped after address 0x%lux", addr);
return -1;
}
void
removeseg(Map *map, int i)
{
if(map == nil)
return;
if(i < 0 || i >= map->nseg)
return;
memmove(&map->seg[i], &map->seg[i+1], (map->nseg-(i+1))*sizeof(Seg));
map->nseg--;
}
int
get1(Map *map, ulong addr, uchar *a, uint n)
{
return mrw(map, addr, a, n, 1);
}
int
get2(Map *map, ulong addr, u16int *u)
{
u16int v;
if(mrw(map, addr, &v, 2, 1) < 0)
return -1;
*u = mach->swap2(v);
return 2;
}
int
get4(Map *map, ulong addr, u32int *u)
{
u32int v;
if(mrw(map, addr, &v, 4, 1) < 0)
return -1;
*u = mach->swap4(v);
return 4;
}
int
get8(Map *map, ulong addr, u64int *u)
{
u64int v;
if(mrw(map, addr, &v, 4, 1) < 0)
return -1;
*u = mach->swap8(v);
return 8;
}
int
put1(Map *map, ulong addr, uchar *a, uint n)
{
return mrw(map, addr, a, n, 0);
}
int
put2(Map *map, ulong addr, u16int u)
{
u = mach->swap2(u);
return mrw(map, addr, &u, 2, 0);
}
int
put4(Map *map, ulong addr, u32int u)
{
u = mach->swap4(u);
return mrw(map, addr, &u, 4, 0);
}
int
put8(Map *map, ulong addr, u64int u)
{
u = mach->swap8(u);
return mrw(map, addr, &u, 8, 0);
}
static Seg*
reloc(Map *map, ulong addr, uint n, ulong *off, uint *nn)
{
int i;
ulong o;
if(map == nil){
werrstr("invalid map");
return nil;
}
for(i=map->nseg-1; i>=0; i--){
if(map->seg[i].base <= addr){
o = addr - map->seg[i].base;
if(o >= map->seg[i].size)
continue;
if(o+n > map->seg[i].size)
*nn = map->seg[i].size - o;
else
*nn = n;
*off = o;
return &map->seg[i];
}
}
werrstr("address 0x%lux not mapped", addr);
return nil;
}
static int
mrw(Map *map, ulong addr, void *a, uint n, int r)
{
uint nn;
uint tot;
Seg *s;
ulong off;
for(tot=0; tot<n; tot+=nn){
s = reloc(map, addr+tot, n-tot, &off, &nn);
if(s == nil)
return -1;
if(s->rw(map, s, off, a, nn, r) < 0)
return -1;
}
return 0;
}
static int
fdrw(Map *map, Seg *seg, ulong addr, void *a, uint n, int r)
{
int nn;
uint tot;
ulong off;
USED(map);
off = seg->offset + addr;
for(tot=0; tot<n; tot+=nn){
if(r)
nn = pread(seg->fd, a, n-tot, off+tot);
else
nn = pwrite(seg->fd, a, n-tot, off+tot);
if(nn < 0)
return -1;
if(nn == 0){
werrstr("partial %s at address 0x%lux in %s",
r ? "read" : "write", off+tot, seg->file);
return -1;
}
}
return 0;
}
static int
zerorw(Map *map, Seg *seg, ulong addr, void *a, uint n, int r)
{
USED(map);
USED(seg);
USED(addr);
if(r==0){
werrstr("cannot write zero segment");
return -1;
}
memset(a, 0, n);
return 0;
}
static int
datarw(Map *map, Seg *seg, ulong addr, void *a, uint n, int r)
{
USED(map);
if(r)
memmove(a, seg->p+addr, n);
else
memmove(seg->p+addr, a, n);
return 0;
}

58
src/libmach/mkfile Normal file
View File

@ -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

289
src/libmach/nm.c Normal file
View File

@ -0,0 +1,289 @@
/*
* nm.c -- drive nm
*/
#include <u.h>
#include <libc.h>
#include <ar.h>
#include <bio.h>
#include <mach.h>
enum{
CHUNK = 256 /* must be power of 2 */
};
char *errs; /* exit status */
char *filename; /* current file */
char symname[]="__.SYMDEF"; /* table of contents file name */
int multifile; /* processing multiple files */
int aflag;
int gflag;
int hflag;
int nflag;
int sflag;
int uflag;
Symbol **fnames; /* file path translation table */
Symbol **symptr;
int nsym;
Biobuf bout;
int cmp(void*, void*);
void error(char*, ...);
void execsyms(int);
void psym(Symbol*, void*);
void printsyms(Symbol**, long);
void doar(Biobuf*);
void dofile(Biobuf*);
void zenter(Symbol*);
void
main(int argc, char *argv[])
{
int i;
Biobuf *bin;
Binit(&bout, 1, OWRITE);
argv0 = argv[0];
ARGBEGIN {
case 'a': aflag = 1; break;
case 'g': gflag = 1; break;
case 'h': hflag = 1; break;
case 'n': nflag = 1; break;
case 's': sflag = 1; break;
case 'u': uflag = 1; break;
} ARGEND
if (argc > 1)
multifile++;
for(i=0; i<argc; i++){
filename = argv[i];
bin = Bopen(filename, OREAD);
if(bin == 0){
error("cannot open %s", filename);
continue;
}
if (isar(bin))
doar(bin);
else{
Bseek(bin, 0, 0);
dofile(bin);
}
Bterm(bin);
}
exits(errs);
}
/*
* read an archive file,
* processing the symbols for each intermediate file in it.
*/
void
doar(Biobuf *bp)
{
int offset, size, obj;
char membername[SARNAME];
multifile = 1;
for (offset = Boffset(bp);;offset += size) {
size = nextar(bp, offset, membername);
if (size < 0) {
error("phase error on ar header %ld", offset);
return;
}
if (size == 0)
return;
if (strcmp(membername, symname) == 0)
continue;
obj = objtype(bp, 0);
if (obj < 0) {
error("inconsistent file %s in %s",
membername, filename);
return;
}
if (!readar(bp, obj, offset+size, 1)) {
error("invalid symbol reference in file %s",
membername);
return;
}
filename = membername;
nsym=0;
objtraverse(psym, 0);
printsyms(symptr, nsym);
}
}
/*
* process symbols in a file
*/
void
dofile(Biobuf *bp)
{
int obj;
obj = objtype(bp, 0);
if (obj < 0)
execsyms(Bfildes(bp));
else
if (readobj(bp, obj)) {
nsym = 0;
objtraverse(psym, 0);
printsyms(symptr, nsym);
}
}
/*
* comparison routine for sorting the symbol table
* this screws up on 'z' records when aflag == 1
*/
int
cmp(void *vs, void *vt)
{
Symbol **s, **t;
s = vs;
t = vt;
if(nflag)
if((*s)->value < (*t)->value)
return -1;
else
return (*s)->value > (*t)->value;
return strcmp((*s)->name, (*t)->name);
}
/*
* enter a symbol in the table of filename elements
*/
void
zenter(Symbol *s)
{
static int maxf = 0;
if (s->value > maxf) {
maxf = (s->value+CHUNK-1) &~ (CHUNK-1);
fnames = realloc(fnames, (maxf+1)*sizeof(*fnames));
if(fnames == 0) {
error("out of memory", argv0);
exits("memory");
}
}
fnames[s->value] = s;
}
/*
* get the symbol table from an executable file, if it has one
*/
void
execsyms(int fd)
{
Fhdr f;
Symbol *s;
long n;
seek(fd, 0, 0);
if (crackhdr(fd, &f) == 0) {
error("Can't read header for %s", filename);
return;
}
if (syminit(fd, &f) < 0)
return;
s = symbase(&n);
nsym = 0;
while(n--)
psym(s++, 0);
printsyms(symptr, nsym);
}
void
psym(Symbol *s, void* p)
{
USED(p);
switch(s->type) {
case 'T':
case 'L':
case 'D':
case 'B':
if (uflag)
return;
if (!aflag && ((s->name[0] == '.' || s->name[0] == '$')))
return;
break;
case 'b':
case 'd':
case 'l':
case 't':
if (uflag || gflag)
return;
if (!aflag && ((s->name[0] == '.' || s->name[0] == '$')))
return;
break;
case 'U':
if (gflag)
return;
break;
case 'Z':
if (!aflag)
return;
break;
case 'm':
case 'f': /* we only see a 'z' when the following is true*/
if(!aflag || uflag || gflag)
return;
if (strcmp(s->name, ".frame"))
zenter(s);
break;
case 'a':
case 'p':
case 'z':
default:
if(!aflag || uflag || gflag)
return;
break;
}
symptr = realloc(symptr, (nsym+1)*sizeof(Sym*));
if (symptr == 0) {
error("out of memory");
exits("memory");
}
symptr[nsym++] = s;
}
void
printsyms(Symbol **symptr, long nsym)
{
Symbol *s;
char *cp;
char path[512];
if(!sflag)
qsort(symptr, nsym, sizeof(*symptr), cmp);
while (nsym-- > 0) {
s = *symptr++;
if (multifile && !hflag)
Bprint(&bout, "%s:", filename);
if (s->type == 'z') {
fileelem(fnames, (uchar *) s->name, path, 512);
cp = path;
} else
cp = s->name;
if (s->value || s->type == 'a' || s->type == 'p')
Bprint(&bout, "%8lux %c %s\n", s->value, s->type, cp);
else
Bprint(&bout, " %c %s\n", s->type, cp);
}
}
void
error(char *fmt, ...)
{
Fmt f;
char buf[128];
va_list arg;
fmtfdinit(&f, 2, buf, sizeof buf);
fmtprint(&f, "%s: ", argv0);
va_start(arg, fmt);
fmtvprint(&f, fmt, arg);
va_end(arg);
fmtprint(&f, "\n");
fmtfdflush(&f);
errs = "errors";
}

59
src/libmach/regs.c Normal file
View File

@ -0,0 +1,59 @@
#include <u.h>
#include <libc.h>
#include <mach.h>
int
rput(Regs *regs, char *name, ulong u)
{
if(regs == nil){
werrstr("registers not mapped");
return -1;
}
return regs->rw(regs, name, &u, 0);
}
int
rget(Regs *regs, char *name, ulong *u)
{
if(regs == nil){
*u = ~(ulong)0;
werrstr("registers not mapped");
return -1;
}
return regs->rw(regs, name, u, 1);
}
int
_uregrw(Regs *regs, char *name, ulong *u, int isr)
{
Regdesc *r;
uchar *ureg;
if(!isr){
werrstr("cannot write registers");
return -1;
}
if((r = regdesc(name)) == nil)
return -1;
ureg = ((UregRegs*)regs)->ureg + r->offset;
switch(r->format){
default:
case 'X':
*u = mach->swap4(*(u32int*)ureg);
return 0;
}
}
Regdesc*
regdesc(char *name)
{
Regdesc *r;
for(r=mach->reglist; r->name; r++)
if(strcmp(r->name, name) == 0)
return r;
return nil;
}

54
src/libmach/stabs.c Normal file
View File

@ -0,0 +1,54 @@
#include <u.h>
#include <libc.h>
#include <mach.h>
#include "stabs.h"
/*
http://sources.redhat.com/gdb/onlinedocs/stabs.html
*/
int
stabsym(Stab *stabs, int i, StabSym *sym)
{
uchar *p;
ulong x;
if(stabs == nil){
werrstr("no stabs");
return -1;
}
if(stabs->e2==nil || stabs->e4==nil){
werrstr("no data extractors");
return -1;
}
if(i >= stabs->stabsize/12){
werrstr("stabs index out of range");
return -1;
}
p = stabs->stabbase+i*12;
x = stabs->e4(p);
if(x == 0)
sym->name = nil;
else if(x < stabs->strsize)
sym->name = stabs->strbase+x;
else{
werrstr("bad stabs string index");
return -1;
}
/*
* In theory, if name ends with a backslash,
* it continues into the next entry. We could
* rewrite these in place and then zero the next
* few entries, but let's wait until we run across
* some system that generates these.
*/
sym->type = p[4];
sym->other = p[5];
sym->desc = stabs->e2(p+6);
sym->value = stabs->e4(p+8);
return 0;
}

117
src/libmach/stabs.h Normal file
View File

@ -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*);

118
src/libmach/swap.c Normal file
View File

@ -0,0 +1,118 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <mach.h>
/*
* big-endian short
*/
u16int
beswap2(u16int s)
{
uchar *p;
p = (uchar*)&s;
return (p[0]<<8) | p[1];
}
/*
* big-endian long
*/
u32int
beswap4(u32int l)
{
uchar *p;
p = (uchar*)&l;
return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
}
/*
* big-endian vlong
*/
u64int
beswap8(u64int v)
{
uchar *p;
p = (uchar*)&v;
return ((u64int)p[0]<<56) | ((u64int)p[1]<<48) | ((u64int)p[2]<<40)
| ((u64int)p[3]<<32) | ((u64int)p[4]<<24)
| ((u64int)p[5]<<16) | ((u64int)p[6]<<8)
| (u64int)p[7];
}
/*
* little-endian short
*/
u16int
leswap2(u16int s)
{
uchar *p;
p = (uchar*)&s;
return (p[1]<<8) | p[0];
}
/*
* little-endian long
*/
u32int
leswap4(u32int l)
{
uchar *p;
p = (uchar*)&l;
return (p[3]<<24) | (p[2]<<16) | (p[1]<<8) | p[0];
}
/*
* little-endian vlong
*/
u64int
leswap8(u64int v)
{
uchar *p;
p = (uchar*)&v;
return ((u64int)p[7]<<56) | ((u64int)p[6]<<48) | ((u64int)p[5]<<40)
| ((u64int)p[4]<<32) | ((u64int)p[3]<<24)
| ((u64int)p[2]<<16) | ((u64int)p[1]<<8)
| (u64int)p[0];
}
u16int
leload2(uchar *b)
{
return b[0] | (b[1]<<8);
}
u32int
leload4(uchar *b)
{
return b[0] | (b[1]<<8) | (b[2]<<16) | (b[3]<<24);
}
u64int
leload8(uchar *b)
{
return leload4(b) | ((uvlong)leload4(b+4) << 32);
}
u16int
beload2(uchar *b)
{
return (b[0]<<8) | b[1];
}
u32int
beload4(uchar *b)
{
return (b[0]<<24) | (b[1]<<16) | (b[2]<<8) | b[3];
}
u64int
beload8(uchar *b)
{
return ((uvlong)beload4(b) << 32) | beload4(b+4);
}

478
src/libmach/sym.c Normal file
View File

@ -0,0 +1,478 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <mach.h>
int machdebug = 0;
Fhdr *fhdrlist;
static Fhdr *last;
static void
relocsym(Symbol *dst, Symbol *src, ulong base)
{
if(dst != src)
*dst = *src;
if(dst->loc.type == LADDR)
dst->loc.addr += base;
if(dst->hiloc.type == LADDR)
dst->hiloc.addr += base;
}
void
_addhdr(Fhdr *h)
{
h->next = nil;
if(fhdrlist == nil){
fhdrlist = h;
last = h;
}else{
last->next = h;
last = h;
}
}
void
_delhdr(Fhdr *h)
{
Fhdr *p;
if(h == fhdrlist)
fhdrlist = h->next;
else{
for(p=fhdrlist; p && p->next!=h; p=p->next)
;
if(p)
p->next = h->next;
if(p->next == nil)
last = p;
}
h->next = nil;
}
int
pc2file(ulong pc, char *file, uint nfile, ulong *line)
{
Fhdr *p;
for(p=fhdrlist; p; p=p->next)
if(p->pc2file && p->pc2file(p, pc-p->base, file, nfile, line) >= 0)
return 0;
werrstr("no source file for 0x%lux", pc);
return -1;
}
int
pc2line(ulong pc, ulong *line)
{
char tmp[10]; /* just in case */
return pc2file(pc, tmp, sizeof tmp, line);
}
int
file2pc(char *file, ulong line, ulong *addr)
{
Fhdr *p;
for(p=fhdrlist; p; p=p->next)
if(p->file2pc && p->file2pc(p, file, line, addr) >= 0){
*addr += p->base;
return 0;
}
werrstr("no instructions at %s:%lud", file, line);
return -1;
}
int
line2pc(ulong basepc, ulong line, ulong *pc)
{
Fhdr *p;
for(p=fhdrlist; p; p=p->next)
if(p->line2pc && p->line2pc(p, basepc-p->base, line, pc) >= 0){
*pc += p->base;
return 0;
}
werrstr("no instructions on line %lud", line);
return -1;
}
int
fnbound(ulong pc, ulong *bounds)
{
Fhdr *p;
Loc l;
Symbol *s;
for(p=fhdrlist; p; p=p->next){
l = locaddr(pc - p->base);
if((s = ffindsym(p, l, CANY)) != nil){
if(s->loc.type != LADDR){
werrstr("function %s has weird location %L", s->name, s->loc);
return -1;
}
bounds[0] = s->loc.addr + p->base;
if(s->hiloc.type != LADDR){
werrstr("can't find upper bound for function %s", s->name);
return -1;
}
bounds[1] = s->hiloc.addr + p->base;
return 0;
}
}
werrstr("no function contains 0x%lux", pc);
return -1;
}
int
fileline(ulong pc, char *a, uint n)
{
ulong line;
if(pc2file(pc, a, n, &line) < 0)
return -1;
seprint(a+strlen(a), a+n, ":%lud", line);
return 0;
}
Symbol*
flookupsym(Fhdr *fhdr, char *name)
{
Symbol **a, *t;
uint n, m;
int i;
a = fhdr->byname;
n = fhdr->nsym;
if(a == nil)
return nil;
while(n > 0){
m = n/2;
t = a[m];
i = strcmp(name, t->name);
if(i < 0)
n = m;
else if(i > 0){
n -= m+1;
a += m+1;
}else{
/* found! */
m += a - fhdr->byname;
a = fhdr->byname;
assert(strcmp(name, a[m]->name) == 0);
while(m > 0 && strcmp(name, a[m-1]->name) == 0)
m--;
return a[m];
}
}
return nil;
}
int
lookupsym(char *fn, char *var, Symbol *s)
{
Symbol *t, s1;
Fhdr *p;
char *nam;
nam = fn ? fn : var;
if(nam == nil)
return -1;
t = nil;
for(p=fhdrlist; p; p=p->next)
if((t=flookupsym(p, nam)) != nil){
relocsym(&s1, t, p->base);
break;
}
if(t == nil)
goto err;
if(fn && var)
return lookuplsym(&s1, var, s);
*s = s1;
return 0;
err:
werrstr("unknown symbol %s%s%s", fn ? fn : "",
fn && var ? ":" : "", var ? var : "");
return -1;
}
int
findexsym(Fhdr *fp, uint i, Symbol *s)
{
if(i >= fp->nsym)
return -1;
relocsym(s, &fp->sym[i], fp->base);
return 0;
}
int
indexsym(uint ndx, Symbol *s)
{
uint t;
Fhdr *p;
for(p=fhdrlist; p; p=p->next){
t = p->nsym;
if(t < ndx)
ndx -= t;
else{
relocsym(s, &p->sym[ndx], p->base);
return 0;
}
}
return -1;
}
Symbol*
ffindsym(Fhdr *fhdr, Loc loc, uint class)
{
Symbol *a, *t;
int n, i, hi, lo;
int cmp;
a = fhdr->sym;
n = fhdr->nsym;
if(a == nil || n <= 0)
return nil;
/*
* We have a list of possibly duplicate locations in a.
* We want to find the largest index i such that
* a[i] <= loc. This cannot be done with a simple
* binary search. Instead we binary search to find
* where the location should be.
*/
lo = 0;
hi = n;
while(lo < hi){
i = (lo+hi)/2;
cmp = loccmp(&loc, &a[i].loc);
if(cmp < 0) /* loc < a[i].loc */
hi = i;
if(cmp > 0) /* loc > a[i].loc */
lo = i+1;
if(cmp == 0)
goto found;
}
/* found position where value would go, but not there -- go back one */
if(lo == 0)
return nil;
i = lo-1;
found:
/*
* might be in a run of all-the-same -- go back to beginning of run.
* if runs were long, could binary search for a[i].loc instead.
*/
while(i > 0 && loccmp(&a[i-1].loc, &a[i].loc) == 0)
i--;
t = &a[i];
if(t->hiloc.type && loccmp(&loc, &t->hiloc) >= 0)
return nil;
if(class != CANY && class != t->class)
return nil;
return t;
}
int
findsym(Loc loc, uint class, Symbol *s)
{
Fhdr *p, *bestp;
Symbol *t, *best;
long bestd, d;
Loc l;
l = loc;
best = nil;
bestp = nil;
bestd = 0;
for(p=fhdrlist; p; p=p->next){
if(l.type == LADDR)
l.addr = loc.addr - p->base;
if((t = ffindsym(p, l, CANY)) != nil){
d = l.addr - t->loc.addr;
if(d < 4096)
if(best == nil || d < bestd){
best = t;
bestp = p;
bestd = d;
}
}
}
if(best){
if(class != CANY && class != best->class)
goto err;
relocsym(s, best, bestp->base);
return 0;
}
err:
werrstr("could not find symbol at %L", loc);
return -1;
}
int
lookuplsym(Symbol *s1, char *name, Symbol *s2)
{
Fhdr *p;
p = s1->fhdr;
if(p->lookuplsym && p->lookuplsym(p, s1, name, s2) >= 0){
relocsym(s2, s2, p->base);
return 0;
}
return -1;
}
int
indexlsym(Symbol *s1, uint ndx, Symbol *s2)
{
Fhdr *p;
p = s1->fhdr;
if(p->indexlsym && p->indexlsym(p, s1, ndx, s2) >= 0){
relocsym(s2, s2, p->base);
return 0;
}
return -1;
}
int
findlsym(Symbol *s1, Loc loc, Symbol *s2)
{
Fhdr *p;
p = s1->fhdr;
if(p->findlsym && p->findlsym(p, s1, loc, s2) >= 0){
relocsym(s2, s2, p->base);
return 0;
}
return -1;
}
int
unwindframe(Map *map, Regs *regs, ulong *next)
{
Fhdr *p;
for(p=fhdrlist; p; p=p->next)
if(p->unwind && p->unwind(p, map, regs, next) >= 0)
return 0;
if(mach->unwind && mach->unwind(map, regs, next) >= 0)
return 0;
return -1;
}
int
symoff(char *a, uint n, ulong addr, uint class)
{
Loc l;
Symbol s;
l.type = LADDR;
l.addr = addr;
if(findsym(l, class, &s) < 0 || addr-s.loc.addr >= 4096){
snprint(a, n, "%lux", addr);
return -1;
}
if(addr != s.loc.addr)
snprint(a, n, "%s+%ld", s.name, addr-s.loc.addr);
else
snprint(a, n, "%s", s.name);
return 0;
}
/* location, class, name */
static int
byloccmp(const void *va, const void *vb)
{
int i;
Symbol *a, *b;
a = (Symbol*)va;
b = (Symbol*)vb;
i = loccmp(&a->loc, &b->loc);
if(i != 0)
return i;
i = a->class - b->class;
if(i != 0)
return i;
return strcmp(a->name, b->name);
}
/* name, location, class */
static int
bynamecmp(const void *va, const void *vb)
{
int i;
Symbol *a, *b;
a = *(Symbol**)va;
b = *(Symbol**)vb;
i = strcmp(a->name, b->name);
if(i != 0)
return i;
i = loccmp(&a->loc, &b->loc);
if(i != 0)
return i;
return a->class - b->class;
}
int
syminit(Fhdr *hdr)
{
int i;
Symbol *r, *w, *es;
if(hdr->syminit == nil){
werrstr("no debugging symbols");
return -1;
}
if(hdr->syminit(hdr) < 0)
return -1;
qsort(hdr->sym, hdr->nsym, sizeof(hdr->sym[0]), byloccmp);
es = hdr->sym+hdr->nsym;
for(r=w=hdr->sym; r<es; r++){
if(w > hdr->sym
&& strcmp((w-1)->name, r->name) ==0
&& loccmp(&(w-1)->loc, &r->loc) == 0){
/* skip it */
}else
*w++ = *r;
}
hdr->nsym = w - hdr->sym;
hdr->byname = malloc(hdr->nsym*sizeof(hdr->byname[0]));
if(hdr->byname == nil){
fprint(2, "could not allocate table to sort by location\n");
}else{
for(i=0; i<hdr->nsym; i++)
hdr->byname[i] = &hdr->sym[i];
qsort(hdr->byname, hdr->nsym, sizeof(hdr->byname[0]), bynamecmp);
}
return 0;
}
Symbol*
addsym(Fhdr *fp, Symbol *sym)
{
Symbol *s;
if(fp->nsym%128 == 0){
s = realloc(fp->sym, (fp->nsym+128)*sizeof(fp->sym[0]));
if(s == nil)
return nil;
fp->sym = s;
}
if(machdebug)
fprint(2, "sym %s %c %L\n", sym->name, sym->type, sym->loc);
sym->fhdr = fp;
s = &fp->sym[fp->nsym++];
*s = *sym;
return s;
}

466
src/libmach/symdwarf.c Normal file
View File

@ -0,0 +1,466 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <mach.h>
#include "elf.h"
#include "dwarf.h"
static void dwarfsymclose(Fhdr*);
static int dwarfpc2file(Fhdr*, ulong, char*, uint, ulong*);
static int dwarfline2pc(Fhdr*, ulong, ulong, ulong*);
static int dwarflookuplsym(Fhdr*, Symbol*, char*, Symbol*);
static int dwarfindexlsym(Fhdr*, Symbol*, uint, Symbol*);
static int dwarffindlsym(Fhdr*, Symbol*, Loc, Symbol*);
static void dwarfsyminit(Fhdr*);
static int dwarftosym(Fhdr*, Dwarf*, DwarfSym*, Symbol*, int);
static int _dwarfunwind(Fhdr *fhdr, Map *map, Regs *regs, ulong *next);
int
symdwarf(Fhdr *hdr)
{
if(hdr->dwarf == nil){
werrstr("no dwarf debugging symbols");
return -1;
}
hdr->symclose = dwarfsymclose;
hdr->pc2file = dwarfpc2file;
hdr->line2pc = dwarfline2pc;
hdr->lookuplsym = dwarflookuplsym;
hdr->indexlsym = dwarfindexlsym;
hdr->findlsym = dwarffindlsym;
hdr->unwind = _dwarfunwind;
dwarfsyminit(hdr);
return 0;
}
static void
dwarfsymclose(Fhdr *hdr)
{
dwarfclose(hdr->dwarf);
hdr->dwarf = nil;
}
static int
dwarfpc2file(Fhdr *fhdr, ulong pc, char *buf, uint nbuf, ulong *line)
{
char *cdir, *dir, *file;
if(dwarfpctoline(fhdr->dwarf, pc, &cdir, &dir, &file, line, nil, nil) < 0)
return -1;
if(file[0] == '/' || (dir==nil && cdir==nil))
strecpy(buf, buf+nbuf, file);
else if((dir && dir[0] == '/') || cdir==nil)
snprint(buf, nbuf, "%s/%s", dir, file);
else
snprint(buf, nbuf, "%s/%s/%s", cdir, dir ? dir : "", file);
cleanname(buf);
return 0;;
}
static int
dwarfline2pc(Fhdr *fhdr, ulong basepc, ulong line, ulong *pc)
{
werrstr("dwarf line2pc not implemented");
return -1;
}
static uint
typesize(Dwarf *dwarf, ulong unit, ulong tref, char *name)
{
DwarfSym ds;
top:
if(dwarfseeksym(dwarf, unit, tref-unit, &ds) < 0){
cannot:
fprint(2, "warning: cannot compute size of parameter %s (%lud %lud: %r)\n",
name, unit, tref);
return 0;
}
if(ds.attrs.have.bytesize)
return ds.attrs.bytesize;
switch(ds.attrs.tag){
case TagVolatileType:
case TagRestrictType:
case TagTypedef:
if(ds.attrs.have.type != TReference)
goto cannot;
tref = ds.attrs.type;
goto top;
}
goto cannot;
}
static int
roundup(int s, int n)
{
return (s+n-1)&~(n-1);
}
static int
dwarflenum(Fhdr *fhdr, Symbol *p, char *name, uint j, Loc l, Symbol *s)
{
int depth, bpoff;
DwarfSym ds;
Symbol s1;
if(p == nil)
return -1;
if(dwarfseeksym(fhdr->dwarf, p->u.dwarf.unit, p->u.dwarf.uoff, &ds) < 0)
return -1;
ds.depth = 1;
depth = 1;
bpoff = 8;
while(dwarfnextsym(fhdr->dwarf, &ds, 1) == 1 && depth < ds.depth){
if(ds.attrs.tag != TagVariable){
if(ds.attrs.tag != TagFormalParameter
&& ds.attrs.tag != TagUnspecifiedParameters)
continue;
if(ds.depth != depth+1)
continue;
}
if(dwarftosym(fhdr, fhdr->dwarf, &ds, &s1, 1) < 0)
continue;
/* XXX move this out once there is another architecture */
/*
* gcc tells us the registers where the parameters might be
* held for an instruction or two. use the parameter list to
* recompute the actual stack locations.
*/
if(fhdr->mtype == M386)
if(ds.attrs.tag==TagFormalParameter || ds.attrs.tag==TagUnspecifiedParameters){
if(s1.loc.type==LOFFSET
&& strcmp(s1.loc.reg, "BP")==0
&& s1.loc.offset >= 8)
bpoff = s1.loc.offset;
else{
s1.loc.type = LOFFSET;
s1.loc.reg = "BP";
s1.loc.offset = bpoff;
}
if(ds.attrs.tag == TagFormalParameter){
if(ds.attrs.have.type)
bpoff += roundup(typesize(fhdr->dwarf, p->u.dwarf.unit, ds.attrs.type, s1.name), 4);
else
fprint(2, "warning: cannot compute size of parameter %s\n", s1.name);
}
}
if(name){
if(strcmp(ds.attrs.name, name) != 0)
continue;
}else if(l.type){
if(loccmp(&s1.loc, &l) != 0)
continue;
}else{
if(j-- > 0)
continue;
}
*s = s1;
return 0;
}
return -1;
}
static Loc zl;
static int
dwarflookuplsym(Fhdr *fhdr, Symbol *p, char *name, Symbol *s)
{
return dwarflenum(fhdr, p, name, 0, zl, s);
}
static int
dwarfindexlsym(Fhdr *fhdr, Symbol *p, uint i, Symbol *s)
{
return dwarflenum(fhdr, p, nil, i, zl, s);
}
static int
dwarffindlsym(Fhdr *fhdr, Symbol *p, Loc l, Symbol *s)
{
return dwarflenum(fhdr, p, nil, 0, l, s);
}
static void
dwarfsyminit(Fhdr *fp)
{
Dwarf *d;
DwarfSym s;
Symbol sym;
d = fp->dwarf;
if(dwarfenum(d, &s) < 0)
return;
while(dwarfnextsym(d, &s, s.depth!=1) == 1){
if(s.depth != 1)
continue;
if(s.attrs.name == nil)
continue;
switch(s.attrs.tag){
case TagSubprogram:
case TagVariable:
if(dwarftosym(fp, d, &s, &sym, 0) < 0)
continue;
addsym(fp, &sym);
}
}
}
static char*
regname(Dwarf *d, int i)
{
if(i < 0 || i >= d->nreg)
return nil;
return d->reg[i];
}
static int
dwarftosym(Fhdr *fp, Dwarf *d, DwarfSym *ds, Symbol *s, int infn)
{
DwarfBuf buf;
DwarfBlock b;
memset(s, 0, sizeof *s);
s->u.dwarf.uoff = ds->uoff;
s->u.dwarf.unit = ds->unit;
switch(ds->attrs.tag){
default:
return -1;
case TagUnspecifiedParameters:
ds->attrs.name = "...";
s->type = 'p';
goto sym;
case TagFormalParameter:
s->type = 'p';
s->class = CPARAM;
goto sym;
case TagSubprogram:
s->type = 't';
s->class = CTEXT;
goto sym;
case TagVariable:
if(infn){
s->type = 'a';
s->class = CAUTO;
}else{
s->type = 'd';
s->class = CDATA;
}
sym:
s->name = ds->attrs.name;
if(ds->attrs.have.lowpc){
s->loc.type = LADDR;
s->loc.addr = ds->attrs.lowpc;
if(ds->attrs.have.highpc){
s->hiloc.type = LADDR;
s->hiloc.addr = ds->attrs.highpc;
}
}else if(ds->attrs.have.location == TConstant){
s->loc.type = LADDR;
s->loc.addr = ds->attrs.location.c;
}else if(ds->attrs.have.location == TBlock){
b = ds->attrs.location.b;
if(b.len == 0)
return -1;
buf.p = b.data+1;
buf.ep = b.data+b.len;
buf.d = d;
buf.addrsize = 0;
if(b.data[0]==OpAddr){
if(b.len != 5)
return -1;
s->loc.type = LADDR;
s->loc.addr = dwarfgetaddr(&buf);
}else if(OpReg0 <= b.data[0] && b.data[0] < OpReg0+0x20){
if(b.len != 1 || (s->loc.reg = regname(d, b.data[0]-OpReg0)) == nil)
return -1;
s->loc.type = LREG;
}else if(OpBreg0 <= b.data[0] && b.data[0] < OpBreg0+0x20){
s->loc.type = LOFFSET;
s->loc.reg = regname(d, b.data[0]-0x70);
s->loc.offset = dwarfget128s(&buf);
if(s->loc.reg == nil)
return -1;
}else if(b.data[0] == OpRegx){
s->loc.type = LREG;
s->loc.reg = regname(d, dwarfget128(&buf));
if(s->loc.reg == nil)
return -1;
}else if(b.data[0] == OpFbreg){
s->loc.type = LOFFSET;
s->loc.reg = mach->fp;
s->loc.offset = dwarfget128s(&buf);
}else if(b.data[0] == OpBregx){
s->loc.type = LOFFSET;
s->loc.reg = regname(d, dwarfget128(&buf));
s->loc.offset = dwarfget128s(&buf);
if(s->loc.reg == nil)
return -1;
}else
s->loc.type = LNONE;
if(buf.p != buf.ep)
s->loc.type = LNONE;
}else
return -1;
if(ds->attrs.isexternal)
s->type += 'A' - 'a';
if(ds->attrs.tag==TagVariable && s->loc.type==LADDR && s->loc.addr>=fp->dataddr+fp->datsz)
s->type += 'b' - 'd';
s->fhdr = fp;
return 0;
}
}
static int
dwarfeval(Dwarf *d, Map *map, Regs *regs, ulong cfa, int rno, DwarfExpr e, ulong *u)
{
int i;
u32int u4;
ulong uu;
switch(e.type){
case RuleUndef:
*u = 0;
return 0;
case RuleSame:
if(rno == -1){
werrstr("pc cannot be `same'");
return -1;
}
return rget(regs, regname(d, rno), u);
case RuleRegister:
if((i = windindex(regname(d, e.reg))) < 0)
return -1;
return rget(regs, regname(d, i), u);
case RuleCfaOffset:
if(cfa == 0){
werrstr("unknown cfa");
return -1;
}
if(get4(map, cfa + e.offset, &u4) < 0)
return -1;
*u = u4;
return 0;
case RuleRegOff:
if(rget(regs, regname(d, e.reg), &uu) < 0)
return -1;
if(get4(map, uu+e.offset, &u4) < 0)
return -1;
*u = u4;
return 0;
case RuleLocation:
werrstr("not evaluating dwarf loc expressions");
return -1;
}
werrstr("not reached in dwarfeval");
return -1;
}
#if 0
static int
dwarfexprfmt(Fmt *fmt)
{
DwarfExpr *e;
if((e = va_arg(fmt->args, DwarfExpr*)) == nil)
return fmtstrcpy(fmt, "<nil>");
switch(e->type){
case RuleUndef:
return fmtstrcpy(fmt, "undef");
case RuleSame:
return fmtstrcpy(fmt, "same");
case RuleCfaOffset:
return fmtprint(fmt, "%ld(cfa)", e->offset);
case RuleRegister:
return fmtprint(fmt, "r%ld", e->reg);
case RuleRegOff:
return fmtprint(fmt, "%ld(r%ld)", e->offset, e->reg);
case RuleLocation:
return fmtprint(fmt, "l.%.*H", e->loc.len, e->loc.data);
default:
return fmtprint(fmt, "?%d", e->type);
}
}
#endif
static int
_dwarfunwind(Fhdr *fhdr, Map *map, Regs *regs, ulong *next)
{
char *name;
int i, j;
ulong cfa, pc, u;
Dwarf *d;
DwarfExpr *e, epc, ecfa;
/*
* Use dwarfunwind to tell us what to do.
*/
d = fhdr->dwarf;
e = malloc(d->nreg*sizeof(e[0]));
if(e == nil)
return -1;
if(rget(regs, mach->pc, &pc) < 0)
goto err;
if(dwarfunwind(d, pc, &ecfa, &epc, e, d->nreg) < 0)
goto err;
/*
* Compute CFA.
*/
switch(ecfa.type){
default:
werrstr("invalid call-frame-address in _dwarfunwind");
goto err;
case RuleRegister:
ecfa.offset = 0;
case RuleRegOff:
if((name = regname(d, ecfa.reg)) == nil){
werrstr("invalid call-frame-address register %d", (int)ecfa.reg);
goto err;
}
if(rget(regs, name, &cfa) < 0){
werrstr("fetching %s for call-frame-address: %r", name);
goto err;
}
cfa += ecfa.offset;
}
/*
* Compute registers.
*/
for(i=0; i<d->nreg; i++){
j = windindex(d->reg[i]);
if(j == -1)
continue;
if(dwarfeval(d, map, regs, cfa, i, e[i], &u) < 0)
u = ~(ulong)0;
next[j] = u;
}
/*
* Compute caller pc
*/
if(dwarfeval(d, map, regs, cfa, -1, epc, &u) < 0){
werrstr("computing caller %s: %r", mach->pc);
goto err;
}
next[windindex(mach->pc)] = u;
free(e);
return 0;
err:
free(e);
return -1;
}

103
src/libmach/symelf.c Normal file
View File

@ -0,0 +1,103 @@
#include <u.h>
#include <libc.h>
#include <mach.h>
#include "elf.h"
static int
elfsyminit(Fhdr *fp)
{
int i, onlyundef;
Elf *elf;
Symbol sym;
ElfSym esym;
ElfProg *p;
elf = fp->elf;
onlyundef = fp->nsym > 0;
for(i=0; elfsym(elf, i, &esym) >= 0; i++){
if(esym.name == nil)
continue;
if(onlyundef && esym.shndx != ElfSymShnNone)
continue;
if(esym.type != ElfSymTypeObject && esym.type != ElfSymTypeFunc)
continue;
if(strchr(esym.name, '@'))
continue;
memset(&sym, 0, sizeof sym);
sym.name = esym.name;
sym.loc.type = LADDR;
sym.loc.addr = esym.value;
if(esym.size){
sym.hiloc.type = LADDR;
sym.hiloc.addr = esym.value+esym.size;
}
sym.fhdr = fp;
if(esym.type==ElfSymTypeObject){
sym.class = CDATA;
sym.type = 'D';
if(&elf->sect[esym.shndx] == elf->bss)
sym.type = 'B';
}else if(esym.type==ElfSymTypeFunc){
sym.class = CTEXT;
sym.type = 'T';
}
if(esym.shndx == ElfSymShnNone)
sym.type = 'U';
if(esym.bind==ElfSymBindLocal)
sym.type += 'a' - 'A';
addsym(fp, &sym);
}
for(i=0; i<elf->nprog; i++){
p = &elf->prog[i];
if(p->type != ElfProgDynamic)
continue;
memset(&sym, 0, sizeof sym);
sym.name = "_DYNAMIC";
sym.loc = locaddr(p->vaddr);
sym.hiloc = locaddr(p->vaddr+p->filesz);
sym.type = 'D';
sym.class = CDATA;
addsym(fp, &sym);
}
return 0;
}
int
symelf(Fhdr *fhdr)
{
int ret;
ret = -1;
/* try dwarf */
if(fhdr->dwarf){
if(machdebug)
fprint(2, "dwarf symbols...\n");
if(symdwarf(fhdr) < 0)
fprint(2, "initializing dwarf: %r");
else
ret = 0;
}
/* try stabs */
if(fhdr->stabs.stabbase){
if(machdebug)
fprint(2, "stabs symbols...\n");
if(symstabs(fhdr) < 0)
fprint(2, "initializing stabs: %r");
else
ret = 0;
}
if(machdebug)
fprint(2, "elf symbols...\n");
if(elfsyminit(fhdr) < 0)
fprint(2, "initializing elf: %r");
else
ret = 0;
return ret;
}

50
src/libmach/symmacho.c Normal file
View File

@ -0,0 +1,50 @@
#include <u.h>
#include <libc.h>
#include <mach.h>
#include "macho.h"
#if 0
static int
machosyminit(Fhdr *fp)
{
/* XXX should parse dynamic symbol table here */
return 0;
}
#endif
int
symmacho(Fhdr *fp)
{
int ret;
Macho *m;
m = fp->macho;
if(m == nil){
werrstr("not a macho");
return -1;
}
ret = -1;
if(machdebug)
fprint(2, "macho symbols...\n");
/*
if(machosyminit(fp) < 0)
fprint(2, "initializing macho symbols: %r\n");
else
ret = 0;
*/
if(fp->stabs.stabbase){
if(machdebug)
fprint(2, "stabs symbols...\n");
if(symstabs(fp) < 0)
fprint(2, "initializing stabs: %r");
else
ret = 0;
}
return ret;
}

401
src/libmach/symstabs.c Normal file
View File

@ -0,0 +1,401 @@
#include <u.h>
#include <libc.h>
#include <mach.h>
#include "stabs.h"
static int
strcmpcolon(char *a, char *bcolon)
{
int i, len;
char *p;
p = strchr(bcolon, ':');
if(p == nil)
return strcmp(a, bcolon);
len = p-bcolon;
i = strncmp(a, bcolon, len);
if(i)
return i;
if(a[len] == 0)
return 0;
return 1;
}
static int
stabcvtsym(StabSym *stab, Symbol *sym, char *dir, char *file, int i)
{
char *p;
/*
* Zero out the : to avoid allocating a new name string.
* The type info can be found by looking past the NUL.
* This is going to get us in trouble...
*/
if((p = strchr(stab->name, ':')) != nil)
*p++ = 0;
else
p = stab->name+strlen(stab->name)+1;
sym->name = stab->name;
sym->u.stabs.dir = dir;
sym->u.stabs.file = file;
sym->u.stabs.i = i;
switch(stab->type){
default:
return -1;
case N_FUN:
sym->class = CTEXT;
switch(*p){
default:
return -1;
case 'F': /* global function */
sym->type = 'T';
break;
case 'Q': /* static procedure */
case 'f': /* static function */
case 'I': /* nested procedure */
case 'J': /* nested function */
sym->type = 't';
break;
}
sym->loc.type = LADDR;
sym->loc.addr = stab->value;
break;
case N_GSYM:
case N_PSYM:
case N_LSYM:
case N_LCSYM:
sym->class = CDATA;
sym->loc.type = LADDR;
sym->loc.addr = stab->value;
switch(*p){
default:
return -1;
case 'S': /* file-scope static variable */
sym->type = 'd';
break;
case 'G': /* global variable */
sym->type = 'D';
sym->loc.type = LNONE;
break;
case 'r': /* register variable */
sym->class = CAUTO;
sym->type = 'a';
sym->loc.type = LREG;
sym->loc.reg = "XXX";
break;
case 's': /* local variable */
sym->class = CAUTO;
sym->type = 'a';
sym->loc.type = LOFFSET;
sym->loc.offset = stab->value;
sym->loc.reg = "XXX";
break;
case 'a': /* by reference */
case 'D': /* f.p. parameter */
case 'i': /* register parameter */
case 'p': /* "normal" parameter */
case 'P': /* register parameter */
case 'v': /* by reference */
case 'X': /* function return variable */
sym->class = CPARAM;
sym->type = 'p';
if(*p == 'i'){
sym->loc.type = LREG;
sym->loc.reg = "XXX";
}else{
sym->loc.type = LOFFSET;
sym->loc.offset = stab->value;
sym->loc.reg = "XXX";
}
break;
}
break;
}
return 0;
}
static int
stabssyminit(Fhdr *fp)
{
int i;
char *dir, *file;
Stab *stabs;
StabSym sym, lastfun;
Symbol s, *fun;
char **inc, **xinc;
int ninc, minc;
int locals, autos, params;
stabs = &fp->stabs;
if(stabs == nil){
werrstr("no stabs info");
return -1;
}
dir = nil;
file = nil;
inc = nil;
fun = nil;
ninc = 0;
minc = 0;
locals = 0;
params = 0;
autos = 0;
memset(&lastfun, 0, sizeof lastfun);
for(i=0; stabsym(stabs, i, &sym)>=0; i++){
switch(sym.type){
case N_SO:
if(sym.name == nil || *sym.name == 0){
file = nil;
break;
}
if(sym.name[strlen(sym.name)-1] == '/')
dir = sym.name;
else
file = sym.name;
break;
case N_BINCL:
if(ninc >= minc){
xinc = realloc(inc, (ninc+32)*sizeof(inc[0]));
if(xinc){
memset(xinc+ninc, 0, 32*sizeof(inc[0]));
inc = xinc;
}
ninc += 32;
}
if(ninc < minc)
inc[ninc] = sym.name;
ninc++;
break;
case N_EINCL:
if(ninc > 0)
ninc--;
break;
case N_EXCL:
/* condensed include - same effect as previous BINCL/EINCL pair */
break;
case N_GSYM: /* global variable */
/* only includes type, so useless for now */
break;
case N_FUN:
if(sym.name == nil){
/* marks end of function */
if(fun){
fun->hiloc.type = LADDR;
fun->hiloc.addr = fun->loc.addr + sym.value;
}
break;
}
if(fun && lastfun.value==sym.value && lastfun.name==sym.name){
fun->u.stabs.locals = i;
break;
}
/* create new symbol, add it */
lastfun = sym;
fun = nil;
if(stabcvtsym(&sym, &s, dir, file, i) < 0)
continue;
if((fun = addsym(fp, &s)) == nil)
goto err;
locals = 0;
params = 0;
autos = 0;
break;
case N_PSYM:
case N_LSYM:
case N_LCSYM:
if(fun){
if(fun->u.stabs.frameptr == -1){
/*
* Try to distinguish functions with a real frame pointer
* from functions with a virtual frame pointer, based on
* whether the first parameter is in the right location and
* whether the autos have negative offsets.
*
* This heuristic works most of the time. On the 386, we
* cannot distinguish between a v. function with no autos
* but a frame of size 4 and a f.p. function with no autos and
* no frame. Anything else we'll get right.
*
* Another way to go about this would be to have
* mach-specific functions to inspect the function
* prologues when we're not sure. What we have
* already should be enough, though.
*/
if(params==0 && sym.type == N_PSYM){
if(sym.value != 8 && sym.value >= 4){
/* XXX 386 specific, but let's find another system before generalizing */
fun->u.stabs.frameptr = 0;
fun->u.stabs.framesize = sym.value - 4;
}
}else if(sym.type == N_LSYM){
if(sym.value >= 0){
fun->u.stabs.frameptr = 0;
if(params)
fun->u.stabs.framesize = 8 - 4;
}else
fun->u.stabs.frameptr = 1;
}
}
if(sym.type == N_PSYM)
params++;
if(sym.type == N_LSYM)
autos++;
}
break;
case N_STSYM: /* static file-scope variable */
/* create new symbol, add it */
if(stabcvtsym(&sym, &s, dir, file, i) < 0)
continue;
if(addsym(fp, &s) < 0)
goto err;
break;
}
}
free(inc);
return 0;
err:
free(inc);
return -1;
}
static int
stabspc2file(Fhdr *fhdr, ulong pc, char *buf, uint nbuf, ulong *pline)
{
int i;
Symbol *s;
StabSym ss;
ulong line, basepc;
Loc l;
l.type = LADDR;
l.addr = pc;
if((s = ffindsym(fhdr, l, CTEXT)) == nil
|| stabsym(&fhdr->stabs, s->u.stabs.i, &ss) < 0)
return -1;
line = ss.desc;
basepc = ss.value;
for(i=s->u.stabs.i+1; stabsym(&fhdr->stabs, i, &ss) >= 0; i++){
if(ss.type == N_FUN && ss.name == nil)
break;
if(ss.type == N_SLINE){
if(basepc+ss.value > pc)
break;
else
line = ss.desc;
}
}
*pline = line;
if(s->u.stabs.dir)
snprint(buf, nbuf, "%s%s", s->u.stabs.dir, s->u.stabs.file);
else
snprint(buf, nbuf, "%s", s->u.stabs.file);
return 0;
}
static int
stabsline2pc(Fhdr *fhdr, ulong startpc, ulong line, ulong *pc)
{
int i, trigger;
Symbol *s;
StabSym ss;
ulong basepc;
Loc l;
l.type = LADDR;
l.addr = startpc;
if((s = ffindsym(fhdr, l, CTEXT)) == nil)
return -1;
trigger = 0;
line = ss.desc;
basepc = ss.value;
for(i=s->u.stabs.i+1; stabsym(&fhdr->stabs, i, &ss) >= 0; i++){
if(ss.type == N_FUN)
basepc = ss.value;
if(ss.type == N_SLINE){
if(basepc+ss.value >= startpc)
trigger = 1;
if(trigger && ss.desc >= line){
*pc = basepc+ss.value;
return 0;
}
}
}
return -1;
}
static int
stabslenum(Fhdr *fhdr, Symbol *p, char *name, uint j, Loc l, Symbol *s)
{
int i;
StabSym ss;
for(i=p->u.stabs.locals; stabsym(&fhdr->stabs, i, &ss)>=0; i++){
if(ss.type == N_FUN && ss.name == nil)
break;
switch(ss.type){
case N_PSYM:
case N_LSYM:
case N_LCSYM:
if(name){
if(strcmpcolon(name, ss.name) != 0)
break;
}else if(l.type){
/* wait for now */
}else{
if(j-- > 0)
break;
}
if(stabcvtsym(&ss, s, p->u.stabs.dir, p->u.stabs.file, i) < 0)
return -1;
if(s->loc.type == LOFFSET){
if(p->u.stabs.frameptr == 0)
s->loc.reg = mach->sp;
else
s->loc.reg = mach->fp;
}
if(l.type && loccmp(&l, &s->loc) != 0)
break;
return 0;
}
}
return -1;
}
static Loc zl;
static int
stabslookuplsym(Fhdr *fhdr, Symbol *p, char *name, Symbol *s)
{
return stabslenum(fhdr, p, name, 0, zl, s);
}
static int
stabsindexlsym(Fhdr *fhdr, Symbol *p, uint i, Symbol *s)
{
return stabslenum(fhdr, p, nil, i, zl, s);
}
static int
stabsfindlsym(Fhdr *fhdr, Symbol *p, Loc l, Symbol *s)
{
return stabslenum(fhdr, p, nil, 0, l, s);
}
int
symstabs(Fhdr *fp)
{
if(stabssyminit(fp) < 0)
return -1;
fp->pc2file = stabspc2file;
fp->line2pc = stabsline2pc;
fp->lookuplsym = stabslookuplsym;
fp->indexlsym = stabsindexlsym;
fp->findlsym = stabsfindlsym;
return 0;
}

45
src/libmach/ureg386.h Normal file
View File

@ -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;
};

54
src/libmach/uregpower.h Normal file
View File

@ -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;
};