libmach
This commit is contained in:
parent
0e3cc9f456
commit
a84cbb2a17
43
src/libmach/FreeBSD.c
Normal file
43
src/libmach/FreeBSD.c
Normal 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
450
src/libmach/Linux.c
Normal 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
13
src/libmach/Notes
Normal 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
166
src/libmach/Notes.stab
Normal 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
91
src/libmach/crack.c
Normal 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
342
src/libmach/crackelf.c
Normal 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, ¬e, &a) < 0)
|
||||
break;
|
||||
switch(note.type){
|
||||
case ElfNotePrStatus:
|
||||
if((n = (*elf->coreregs)(elf, ¬e, &uregs)) < 0){
|
||||
free(sa);
|
||||
return -1;
|
||||
}
|
||||
free(sa);
|
||||
if((r = mallocz(sizeof(*r), 1)) == nil){
|
||||
free(uregs);
|
||||
return -1;
|
||||
}
|
||||
r->r.rw = _uregrw;
|
||||
r->ureg = uregs;
|
||||
*rp = &r->r;
|
||||
return 0;
|
||||
case ElfNotePrFpreg:
|
||||
case ElfNotePrPsinfo:
|
||||
case ElfNotePrTaskstruct:
|
||||
case ElfNotePrAuxv:
|
||||
case ElfNotePrXfpreg:
|
||||
break;
|
||||
}
|
||||
// fprint(2, "0x%lux note %s/%lud %p\n", note.offset, note.name, note.type, note.desc);
|
||||
}
|
||||
free(sa);
|
||||
}
|
||||
fprint(2, "could not find registers in core file\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
198
src/libmach/crackmacho.c
Normal file
198
src/libmach/crackmacho.c
Normal 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
460
src/libmach/dwarf.h
Normal 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
24
src/libmach/dwarf386.c
Normal 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
129
src/libmach/dwarfabbrev.c
Normal 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);
|
||||
}
|
||||
|
||||
63
src/libmach/dwarfaranges.c
Normal file
63
src/libmach/dwarfaranges.c
Normal 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
391
src/libmach/dwarfcfa.c
Normal 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
138
src/libmach/dwarfdump.c
Normal 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
62
src/libmach/dwarfeval.c
Normal 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
217
src/libmach/dwarfget.c
Normal 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
646
src/libmach/dwarfinfo.c
Normal 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
107
src/libmach/dwarfopen.c
Normal 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
338
src/libmach/dwarfpc.c
Normal 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;
|
||||
}
|
||||
76
src/libmach/dwarfpubnames.c
Normal file
76
src/libmach/dwarfpubnames.c
Normal 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
405
src/libmach/elf.c
Normal 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, §b, sizeof sectb) != sizeof sectb)
|
||||
goto err;
|
||||
unpacksect(h, &e->sect[i], §b);
|
||||
}
|
||||
|
||||
if(h->shstrndx >= e->nsect){
|
||||
fprint(2, "warning: bad string section index %d >= %d", h->shstrndx, e->nsect);
|
||||
h->shnum = 0;
|
||||
e->nsect = 0;
|
||||
goto nosects;
|
||||
}
|
||||
s = &e->sect[h->shstrndx];
|
||||
if(elfmap(e, s) < 0)
|
||||
goto err;
|
||||
|
||||
for(i=0; 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
233
src/libmach/elf.h
Normal 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
142
src/libmach/elfcore.h
Normal 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;
|
||||
};
|
||||
89
src/libmach/elfcorefreebsd386.c
Normal file
89
src/libmach/elfcorefreebsd386.c
Normal 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);
|
||||
}
|
||||
|
||||
95
src/libmach/elfcorelinux386.c
Normal file
95
src/libmach/elfcorelinux386.c
Normal 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
133
src/libmach/elfdump.c
Normal 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
6
src/libmach/elfdynsym.c
Normal 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
65
src/libmach/fpformat.c
Normal 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
130
src/libmach/frame.c
Normal 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
20
src/libmach/hexify.c
Normal 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
169
src/libmach/ieee.c
Normal 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
253
src/libmach/loc.c
Normal 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
56
src/libmach/localaddr.c
Normal 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
30
src/libmach/mach.c
Normal 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
1786
src/libmach/mach386.c
Normal file
File diff suppressed because it is too large
Load Diff
128
src/libmach/macho.c
Normal file
128
src/libmach/macho.c
Normal 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
71
src/libmach/macho.h
Normal 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**);
|
||||
173
src/libmach/machocorepower.c
Normal file
173
src/libmach/machocorepower.c
Normal 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
93
src/libmach/machodump.c
Normal 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
1409
src/libmach/machpower.c
Normal file
File diff suppressed because it is too large
Load Diff
306
src/libmach/map.c
Normal file
306
src/libmach/map.c
Normal 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
58
src/libmach/mkfile
Normal 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
289
src/libmach/nm.c
Normal 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
59
src/libmach/regs.c
Normal 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
54
src/libmach/stabs.c
Normal 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
117
src/libmach/stabs.h
Normal 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
118
src/libmach/swap.c
Normal 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
478
src/libmach/sym.c
Normal 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
466
src/libmach/symdwarf.c
Normal 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
103
src/libmach/symelf.c
Normal 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
50
src/libmach/symmacho.c
Normal 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
401
src/libmach/symstabs.c
Normal 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
45
src/libmach/ureg386.h
Normal 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
54
src/libmach/uregpower.h
Normal 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;
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user