aboutsummaryrefslogtreecommitdiff
path: root/src/libmach/t.c
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2004-12-27 17:01:23 +0000
committerrsc <devnull@localhost>2004-12-27 17:01:23 +0000
commite8a7b9699925f3f650593d07eb382155e9374ae6 (patch)
treee176a9718772daf961668100479c9b19e618e65c /src/libmach/t.c
parent2189e55cde473b2a81492759526f824b0ecd227e (diff)
downloadplan9port-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.c269
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
+}
+
+*/