more features

This commit is contained in:
rsc 2004-12-27 17:01:23 +00:00
parent 2189e55cde
commit e8a7b96999
5 changed files with 676 additions and 0 deletions

187
src/libmach/cmdline.c Normal file
View file

@ -0,0 +1,187 @@
#include <u.h>
#include <libc.h>
#include <mach.h>
Fhdr *symhdr;
Fhdr *corhdr;
char *symfil;
char *corfil;
int corpid;
Regs *correg;
Map *symmap;
Map *cormap;
int
alldigs(char *s)
{
while(*s){
if(*s<'0' || '9'<*s)
return 0;
s++;
}
return 1;
}
/*
* attach to arguments in argc, argv
*/
int
attachargs(int argc, char **argv, int omode)
{
int i;
Fhdr *hdr;
char *s;
symhdr = nil;
corhdr = nil;
symfil = nil;
corfil = nil;
corpid = 0;
correg = nil;
for(i=0; i<argc; i++){
if(alldigs(argv[i])){
if(corpid){
fprint(2, "already have corpid %d; ignoring corpid %d\n", corpid, argv[i]);
continue;
}
if(corhdr){
fprint(2, "already have core %s; ignoring corpid %d\n", corfil, corpid);
continue;
}
corpid = atoi(argv[i]);
continue;
}
if((hdr = crackhdr(argv[i], omode)) == nil){
fprint(2, "crackhdr %s: %r\n", argv[i]);
continue;
}
fprint(2, "%s: %s %s %s\n", argv[i], hdr->aname, hdr->mname, hdr->fname);
if(hdr->ftype == FCORE){
if(corpid){
fprint(2, "already have corpid %d; ignoring core %s\n", corpid, argv[i]);
uncrackhdr(hdr);
continue;
}
if(corhdr){
fprint(2, "already have core %s; ignoring core %s\n", corfil, argv[i]);
uncrackhdr(hdr);
continue;
}
corhdr = hdr;
corfil = argv[i];
}else{
if(symhdr){
fprint(2, "already have text %s; ignoring text %s\n", symfil, argv[i]);
uncrackhdr(hdr);
continue;
}
symhdr = hdr;
symfil = argv[i];
}
}
if(symhdr == nil){
symfil = "a.out"; /* default */
if(corpid){ /* try from corpid */
if((s = proctextfile(corpid)) != nil){
fprint(2, "corpid %d: text %s\n", corpid, s);
symfil = s;
}
}
if(corhdr){ /* try from core */
if(corhdr->txtfil != nil){
fprint(2, "core %s: text %s\n", corfil, corhdr->txtfil);
symfil = corhdr->txtfil;
}
}
if((symhdr = crackhdr(symfil, omode)) == nil){
fprint(2, "crackhdr %s: %r\n", symfil);
symfil = nil;
}
}
if(symhdr)
syminit(symhdr);
if(!mach)
mach = machcpu;
/*
* Set up maps
*/
symmap = allocmap();
cormap = allocmap();
if(symmap == nil || cormap == nil)
sysfatal("allocating maps: %r");
if(symhdr){
if(mapfile(symhdr, 0, symmap, nil) < 0)
fprint(2, "mapfile %s: %r\n", symfil);
mapfile(symhdr, 0, cormap, nil);
}
if(corpid)
attachproc(corpid);
if(corhdr)
attachcore(corhdr);
return 0;
}
static int thecorpid;
static Fhdr *thecorhdr;
static void
unattach(void)
{
unmapproc(cormap);
unmapfile(corhdr, cormap);
free(correg);
correg = nil;
thecorpid = 0;
thecorhdr = nil;
corpid = 0;
corhdr = nil;
corfil = nil;
}
int
attachproc(int pid)
{
unattach();
if(pid == 0)
return 0;
if(mapproc(pid, cormap, &correg) < 0){
fprint(2, "attachproc %d: %r\n", pid);
return -1;
}
thecorpid = pid;
corpid = pid;
return 0;
}
int
attachcore(Fhdr *hdr)
{
unattach();
if(corhdr == nil)
return 0;
if(mapfile(hdr, 0, cormap, &correg) < 0){
fprint(2, "attachcore %s: %r\n", hdr->filename);
return -1;
}
thecorhdr = hdr;
corhdr = hdr;
corfil = hdr->filename;
return 0;
}
int
attachdynamic(void)
{
elfdl386mapdl();
return 0;
}

133
src/libmach/elfdl386.c Normal file
View file

@ -0,0 +1,133 @@
#include <u.h>
#include <libc.h>
#include <mach.h>
#include "elf.h"
/*
aggr Linkdebug
{
'X' 0 version;
'X' 4 map;
};
aggr Linkmap
{
'X' 0 addr;
'X' 4 name;
'X' 8 dynsect;
'X' 12 next;
'X' 16 prev;
};
*/
enum
{
DT_NULL = 0,
DT_NEEDED,
DT_PLTRRELSZ,
DT_PLTGOT,
DT_HASH,
DT_STRTAB,
DT_SYMTAB,
DT_RELA,
DT_RELASZ = 8,
DT_RELAENT,
DT_STSZ,
DT_SYMENT,
DT_INIT,
DT_FINI,
DT_SONAME,
DT_RPATH,
DT_SYMBOLIC = 16,
DT_REL,
DT_RELSZ,
DT_RELENT,
DT_PLTREL,
DT_DEBUG,
DT_TEXTREL,
DT_JMPREL,
};
static int
getstr(Map *map, ulong addr, char *buf, uint nbuf)
{
int i;
for(i=0; i<nbuf; i++){
if(get1(map, addr+i, buf+i, 1) < 0)
return -1;
if(buf[i] == 0)
return 0;
}
return -1; /* no nul */
}
static ulong
dyninfo(Fhdr *hdr, int x)
{
u32int addr, u;
if(hdr == nil || (addr = ((Elf*)hdr->elf)->dynamic) == 0){
fprint(2, "no hdr/dynamic %p\n", hdr);
return 0;
}
addr += hdr->base;
while(addr != 0){
if(get4(cormap, addr, &u) < 0)
return 0;
if(u == x){
if(get4(cormap, addr+4, &u) < 0)
return 0;
return u;
}
addr += 8;
}
return 0;
}
void
elfdl386mapdl(void)
{
int i;
Fhdr *hdr;
u32int linkdebug, linkmap, name, addr;
char buf[1024];
print("elfdl386mapdl\n");
if((linkdebug = dyninfo(symhdr, DT_DEBUG)) == 0){
fprint(2, "no dt_debug section\n");
return;
}
if(get4(cormap, linkdebug+4, &linkmap) < 0){
fprint(2, "get4 linkdebug+4 (0x%lux) failed\n", linkdebug);
return;
}
for(i=0; i<100 && linkmap != 0; i++){
if(get4(cormap, linkmap, &addr) < 0
|| get4(cormap, linkmap+4, &name) < 0
|| get4(cormap, linkmap+12, &linkmap) < 0)
break;
if(name
&& getstr(cormap, name, buf, sizeof buf) >= 0
&& buf[0]
&& access(buf, AEXIST) >= 0){
if((hdr = crackhdr(buf, OREAD)) == nil)
fprint(2, "crackhdr %s: %r\n", buf);
else{
fprint(2, "%s: %s %s %s\n", buf, hdr->aname, hdr->mname, hdr->fname);
hdr->base = addr;
if(mapfile(hdr, addr, symmap, nil) < 0)
fprint(2, "mapfile %s: %r\n", buf);
if(corhdr){
unmapfile(corhdr, cormap);
mapfile(hdr, addr, cormap, nil);
}
if(syminit(hdr) < 0)
fprint(2, "syminit %s: %\r", buf);
}
}
}
}

38
src/libmach/elfnm.c Normal file
View file

@ -0,0 +1,38 @@
#include <u.h>
#include <libc.h>
#include <mach.h>
#include <elf.h>
void
usage(void)
{
fprint(2, "usage: elfnm file...\n");
exits("usage");
}
void
main(int argc, char **argv)
{
ElfSym esym;
Fhdr *fp;
int i, j;
ARGBEGIN{
default:
usage();
}ARGEND
if(argc == 0)
usage();
for(i=0; i<argc; i++){
if((fp = crackhdr(argv[i], OREAD)) == nil){
fprint(2, "%s: %r\n", argv[i]);
continue;
}
for(j=0; elfsym(fp->elf, j, &esym)>=0; j++)
print("%s 0x%lux\n", esym.name, esym.value);
uncrackhdr(fp);
}
exits(0);
}

49
src/libmach/pthread.c Normal file
View file

@ -0,0 +1,49 @@
#include <u.h>
#include <thread_db.h>
#include <sys/ptrace.h>
#include <errno.h>
#include <sys/procfs.h> /* psaddr_t */
#include <libc.h>
#include <mach.h>
static char *tderrstr[] =
{
[TD_OK] "no error",
[TD_ERR] "some error",
[TD_NOTHR] "no matching thread found",
[TD_NOSV] "no matching synchronization handle found",
[TD_NOLWP] "no matching light-weight process found",
[TD_BADPH] "invalid process handle",
[TD_BADTH] "invalid thread handle",
[TD_BADSH] "invalid synchronization handle",
[TD_BADTA] "invalid thread agent",
[TD_BADKEY] "invalid key",
[TD_NOMSG] "no event available",
[TD_NOFPREGS] "no floating-point register content available",
[TD_NOLIBTHREAD] "application not linked with thread library",
[TD_NOEVENT] "requested event is not supported",
[TD_NOEVENT] "requested event is not supported",
[TD_NOCAPAB] "capability not available",
[TD_DBERR] "internal debug library error",
[TD_NOAPLIC] "operation is not applicable",
[TD_NOTSD] "no thread-specific data available",
[TD_MALLOC] "out of memory",
[TD_PARTIALREG] "not entire register set was read or written",
[TD_NOXREGS] "X register set not available for given threads",
[TD_TLSDEFER] "thread has not yet allocated TLS for given module",
[TD_VERSION] "version mismatch twixt libpthread and libthread_db",
[TD_NOTLS] "there is no TLS segment in the given module",
};
static char*
terr(int e)
{
static char buf[50];
if(e < 0 || e >= nelem(tderrstr) || tderrstr[e] == nil){
snprint(buf, sizeof buf, "thread err %d", e);
return buf;
}
return tderrstr[e];
}

269
src/libmach/t.c Normal file
View file

@ -0,0 +1,269 @@
#include <u.h>
#include <thread_db.h>
#include <sys/ptrace.h>
#include <errno.h>
#include <sys/procfs.h> /* psaddr_t */
#include <libc.h>
#include <mach.h>
#include "ureg386.h"
int td_get_allthreads(td_thragent_t *ta, td_thrhandle_t **pall);
static char *tderrstr[] =
{
[TD_OK] "no error",
[TD_ERR] "some error",
[TD_NOTHR] "no matching thread found",
[TD_NOSV] "no matching synchronization handle found",
[TD_NOLWP] "no matching light-weight process found",
[TD_BADPH] "invalid process handle",
[TD_BADTH] "invalid thread handle",
[TD_BADSH] "invalid synchronization handle",
[TD_BADTA] "invalid thread agent",
[TD_BADKEY] "invalid key",
[TD_NOMSG] "no event available",
[TD_NOFPREGS] "no floating-point register content available",
[TD_NOLIBTHREAD] "application not linked with thread library",
[TD_NOEVENT] "requested event is not supported",
[TD_NOEVENT] "requested event is not supported",
[TD_NOCAPAB] "capability not available",
[TD_DBERR] "internal debug library error",
[TD_NOAPLIC] "operation is not applicable",
[TD_NOTSD] "no thread-specific data available",
[TD_MALLOC] "out of memory",
[TD_PARTIALREG] "not entire register set was read or written",
[TD_NOXREGS] "X register set not available for given threads",
[TD_TLSDEFER] "thread has not yet allocated TLS for given module",
[TD_VERSION] "version mismatch twixt libpthread and libthread_db",
[TD_NOTLS] "there is no TLS segment in the given module",
};
static char*
terr(int e)
{
static char buf[50];
if(e < 0 || e >= nelem(tderrstr) || tderrstr[e] == nil){
snprint(buf, sizeof buf, "thread err %d", e);
return buf;
}
return tderrstr[e];
}
void
usage(void)
{
fprint(2, "usage: t pid\n");
exits("usage");
}
#define STRINGSZ 128
/*
* print the value of dot as file:line
*/
void
printsource(long dot)
{
char str[STRINGSZ];
if (fileline(dot, str, STRINGSZ) >= 0)
print("%s", str);
}
void
printlocals(Symbol *fn, Regs *regs)
{
int i;
u32int v;
Symbol s;
for (i = 0; indexlsym(fn, i, &s)>=0; i++) {
if (s.class != CAUTO)
continue;
if(lget4(cormap, regs, s.loc, &v) >= 0)
print("\t%s.%s/\t%#lux\n", fn->name, s.name, v);
else
print("\t%s.%s/\t?\n", fn->name, s.name);
}
}
void
printparams(Symbol *fn, Regs *regs)
{
int i;
Symbol s;
u32int v;
int first = 0;
ulong pc, sp, bp;
if(0) print("pc=%lux sp=%lux bp=%lux ",
(rget(regs, "PC", &pc), pc),
(rget(regs, "SP", &sp), sp),
(rget(regs, "BP", &bp), bp));
for (i = 0; indexlsym(fn, i, &s)>=0; i++) {
if (s.class != CPARAM)
continue;
if (first++)
print(", ");
if(0) print("(%d.%s.%ux.%x)", s.loc.type, s.loc.reg, s.loc.addr, s.loc.offset);
if(lget4(cormap, regs, s.loc, &v) >= 0)
print("%s=%#lux", s.name, v);
else
print("%s=?", s.name);
}
}
/*
* callback on stack trace
*/
static int
xtrace(Map *map, Regs *regs, ulong pc, ulong nextpc, Symbol *sym, int depth)
{
char buf[512];
USED(map);
print("\t");
if(sym){
print("%s(", sym->name);
printparams(sym, regs);
print(")+0x%ux ", pc-sym->loc.addr);
}else
print("%#lux ", pc);
printsource(pc);
print(" called from ");
symoff(buf, 512, nextpc, CTEXT);
print("%s ", buf);
/* printsource(nextpc); */
print("\n");
if(sym)
printlocals(sym, regs);
return depth<40;
}
void
main(int argc, char **argv)
{
struct ps_prochandle p;
prgregset_t regs;
int e;
td_thragent_t *ta;
td_thrhandle_t *ts;
td_thrinfo_t info;
int i, n;
Ureg *u;
UregRegs r;
ARGBEGIN{
default:
usage();
}ARGEND
attachargs(argc, argv, OREAD);
attachdynamic();
if(!corpid && !corhdr)
sysfatal("could not attach to process");
p.pid = corpid;
if((e = td_ta_new(&p, &ta)) != TD_OK)
sysfatal("td_ta_new: %s", terr(e));
if((e = td_ta_get_nthreads(ta, &n)) != TD_OK)
sysfatal("td_ta_get_nthreads: %s", terr(e));
print("%d threads\n", n);
if((n = td_get_allthreads(ta, &ts)) < 0)
sysfatal("td_get_allthreads: %r");
print("%d threads - regs = %p\n", n, regs);
for(i=0; i<n; i++){
if((e = td_thr_get_info(&ts[i], &info)) != TD_OK)
sysfatal("td_thr_get_info: %s", terr(e));
print("%d: startfunc=%lux stkbase=%lux pc=%lux sp=%lux lid=%d\n",
i, info.ti_startfunc, info.ti_stkbase, info.ti_pc, info.ti_sp, info.ti_lid);
if((e = td_thr_getgregs(&ts[i], regs)) != TD_OK)
sysfatal("td_thr_getregs: %s", terr(e));
print("%d: pc=%lux sp=%lux gs=%lux\n", i, regs[12], regs[15], regs[10]);
if((u = _linux2ureg386((UregLinux386*)regs)) == nil)
sysfatal("%r");
r.r.rw = _uregrw;
r.ureg = (uchar*)u;
stacktrace(cormap, &r.r, xtrace);
}
exits(0);
}
typedef struct AllThread AllThread;
struct AllThread
{
td_thrhandle_t *a;
int n;
int err;
};
static int
thritercb(const td_thrhandle_t *th, void *cb)
{
td_thrhandle_t **p;
AllThread *a;
int n;
a = cb;
if((a->n&(a->n-1)) == 0){
if(a->n == 0)
n = 1;
else
n = a->n<<1;
if((p = realloc(a->a, n*sizeof a->a[0])) == 0){
a->err = -1;
return -1; /* stop iteration */
}
a->a = p;
}
a->a[a->n++] = *th;
return 0;
}
int
td_get_allthreads(td_thragent_t *ta, td_thrhandle_t **pall)
{
int e;
AllThread a;
a.a = nil;
a.n = 0;
a.err = 0;
if((e = td_ta_thr_iter(ta, thritercb, &a,
TD_THR_ANY_STATE,
TD_THR_LOWEST_PRIORITY,
TD_SIGNO_MASK,
TD_THR_ANY_USER_FLAGS)) != TD_OK){
werrstr("%s", terr(e));
return -1;
}
if(a.err){
free(a.a);
return -1;
}
*pall = a.a;
return a.n;
}
/*
td_err_e td_ta_map_id2thr(const td_thragent_t *ta_p, thread_t tid,td_thrhandle_t *th_p);
*/
/*
int
threadregs(int tid, Regs **rp)
{
check pid
look up tid (td_ta_map_id2thr)
create Regs with thr handle inside
rw function calls thr_getregs and then
pulls out the desired register
}
*/