diff options
author | rsc <devnull@localhost> | 2004-12-27 17:01:23 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2004-12-27 17:01:23 +0000 |
commit | e8a7b9699925f3f650593d07eb382155e9374ae6 (patch) | |
tree | e176a9718772daf961668100479c9b19e618e65c /src/libmach/t.c | |
parent | 2189e55cde473b2a81492759526f824b0ecd227e (diff) | |
download | plan9port-e8a7b9699925f3f650593d07eb382155e9374ae6.tar.gz plan9port-e8a7b9699925f3f650593d07eb382155e9374ae6.tar.bz2 plan9port-e8a7b9699925f3f650593d07eb382155e9374ae6.zip |
more features
Diffstat (limited to 'src/libmach/t.c')
-rw-r--r-- | src/libmach/t.c | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/src/libmach/t.c b/src/libmach/t.c new file mode 100644 index 00000000..d11cb7dd --- /dev/null +++ b/src/libmach/t.c @@ -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 +} + +*/ |