plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

t.c (5664B)


      1 #include <u.h>
      2 #include <thread_db.h>
      3 #include <sys/ptrace.h>
      4 #include <errno.h>
      5 #include <sys/procfs.h>	/* psaddr_t */
      6 #include <libc.h>
      7 #include <mach.h>
      8 #include "ureg386.h"
      9 
     10 int td_get_allthreads(td_thragent_t *ta, td_thrhandle_t **pall);
     11 
     12 static char *tderrstr[] =
     13 {
     14 [TD_OK]			"no error",
     15 [TD_ERR]		"some error",
     16 [TD_NOTHR]		"no matching thread found",
     17 [TD_NOSV]		"no matching synchronization handle found",
     18 [TD_NOLWP]		"no matching light-weight process found",
     19 [TD_BADPH]		"invalid process handle",
     20 [TD_BADTH]		"invalid thread handle",
     21 [TD_BADSH]		"invalid synchronization handle",
     22 [TD_BADTA]		"invalid thread agent",
     23 [TD_BADKEY]		"invalid key",
     24 [TD_NOMSG]		"no event available",
     25 [TD_NOFPREGS]	"no floating-point register content available",
     26 [TD_NOLIBTHREAD]	"application not linked with thread library",
     27 [TD_NOEVENT]	"requested event is not supported",
     28 [TD_NOEVENT]	"requested event is not supported",
     29 [TD_NOCAPAB]	"capability not available",
     30 [TD_DBERR]		"internal debug library error",
     31 [TD_NOAPLIC]	"operation is not applicable",
     32 [TD_NOTSD]		"no thread-specific data available",
     33 [TD_MALLOC]		"out of memory",
     34 [TD_PARTIALREG]	"not entire register set was read or written",
     35 [TD_NOXREGS]	"X register set not available for given threads",
     36 [TD_TLSDEFER]	"thread has not yet allocated TLS for given module",
     37 [TD_VERSION]	"version mismatch twixt libpthread and libthread_db",
     38 [TD_NOTLS]		"there is no TLS segment in the given module",
     39 };
     40 
     41 static char*
     42 terr(int e)
     43 {
     44 	static char buf[50];
     45 
     46 	if(e < 0 || e >= nelem(tderrstr) || tderrstr[e] == nil){
     47 		snprint(buf, sizeof buf, "thread err %d", e);
     48 		return buf;
     49 	}
     50 	return tderrstr[e];
     51 }
     52 
     53 void
     54 usage(void)
     55 {
     56 	fprint(2, "usage: t pid\n");
     57 	exits("usage");
     58 }
     59 
     60 #define	STRINGSZ	128
     61 
     62 /*
     63  *	print the value of dot as file:line
     64  */
     65 void
     66 printsource(long dot)
     67 {
     68 	char str[STRINGSZ];
     69 
     70 	if (fileline(dot, str, STRINGSZ) >= 0)
     71 		print("%s", str);
     72 }
     73 
     74 void
     75 printlocals(Symbol *fn, Regs *regs)
     76 {
     77 	int i;
     78 	u32int v;
     79 	Symbol s;
     80 
     81 	for (i = 0; indexlsym(fn, i, &s)>=0; i++) {
     82 		if (s.class != CAUTO)
     83 			continue;
     84 		if(lget4(cormap, regs, s.loc, &v) >= 0)
     85 			print("\t%s.%s/\t%#lux\n", fn->name, s.name, v);
     86 		else
     87 			print("\t%s.%s/\t?\n", fn->name, s.name);
     88 	}
     89 }
     90 
     91 void
     92 printparams(Symbol *fn, Regs *regs)
     93 {
     94 	int i;
     95 	Symbol s;
     96 	u32int v;
     97 	int first = 0;
     98 	ulong pc, sp, bp;
     99 
    100 	if(0) print("pc=%lux sp=%lux bp=%lux ",
    101 		(rget(regs, "PC", &pc), pc),
    102 		(rget(regs, "SP", &sp), sp),
    103 		(rget(regs, "BP", &bp), bp));
    104 	for (i = 0; indexlsym(fn, i, &s)>=0; i++) {
    105 		if (s.class != CPARAM)
    106 			continue;
    107 		if (first++)
    108 			print(", ");
    109 		if(0) print("(%d.%s.%ux.%x)", s.loc.type, s.loc.reg, s.loc.addr, s.loc.offset);
    110 		if(lget4(cormap, regs, s.loc, &v) >= 0)
    111 			print("%s=%#lux", s.name, v);
    112 		else
    113 			print("%s=?", s.name);
    114 	}
    115 }
    116 
    117 /*
    118  *	callback on stack trace
    119  */
    120 static int
    121 xtrace(Map *map, Regs *regs, ulong pc, ulong nextpc, Symbol *sym, int depth)
    122 {
    123 	char buf[512];
    124 
    125 	USED(map);
    126 	print("\t");
    127 	if(sym){
    128 		print("%s(", sym->name);
    129 		printparams(sym, regs);
    130 		print(")+0x%ux ", pc-sym->loc.addr);
    131 	}else
    132 		print("%#lux ", pc);
    133 	printsource(pc);
    134 
    135 	print(" called from ");
    136 	symoff(buf, 512, nextpc, CTEXT);
    137 	print("%s ", buf);
    138 /*	printsource(nextpc); */
    139 	print("\n");
    140 	if(sym)
    141 		printlocals(sym, regs);
    142 	return depth<40;
    143 }
    144 
    145 void
    146 main(int argc, char **argv)
    147 {
    148 	struct ps_prochandle p;
    149 	prgregset_t regs;
    150 	int e;
    151 	td_thragent_t *ta;
    152 	td_thrhandle_t *ts;
    153 	td_thrinfo_t info;
    154 	int i, n;
    155 	Ureg *u;
    156 	UregRegs r;
    157 
    158 	ARGBEGIN{
    159 	default:
    160 		usage();
    161 	}ARGEND
    162 
    163 	attachargs(argc, argv, OREAD);
    164 	attachdynamic();
    165 
    166 /*	if(!corpid && !corhdr) */
    167 /*		sysfatal("could not attach to process"); */
    168 /* */
    169 	p.pid = corpid;
    170 	if((e = td_ta_new(&p, &ta)) != TD_OK)
    171 		sysfatal("td_ta_new: %s", terr(e));
    172 	if((e = td_ta_get_nthreads(ta, &n)) != TD_OK)
    173 		sysfatal("td_ta_get_nthreads: %s", terr(e));
    174 	print("%d threads\n", n);
    175 
    176 	if((n = td_get_allthreads(ta, &ts)) < 0)
    177 		sysfatal("td_get_allthreads: %r");
    178 	print("%d threads - regs = %p\n", n, regs);
    179 	for(i=0; i<n; i++){
    180 		if((e = td_thr_get_info(&ts[i], &info)) != TD_OK)
    181 			sysfatal("td_thr_get_info: %s", terr(e));
    182 		print("%d: startfunc=%lux stkbase=%lux pc=%lux sp=%lux lid=%d\n",
    183 			i, info.ti_startfunc, info.ti_stkbase, info.ti_pc, info.ti_sp, info.ti_lid);
    184 		if((e = td_thr_getgregs(&ts[i], regs)) != TD_OK)
    185 			sysfatal("td_thr_getregs: %s", terr(e));
    186 		print("%d: pc=%lux sp=%lux gs=%lux\n", i, regs[12], regs[15], regs[10]);
    187 		if((u = _linux2ureg386((UregLinux386*)regs)) == nil)
    188 			sysfatal("%r");
    189 		r.r.rw = _uregrw;
    190 		r.ureg = (uchar*)u;
    191 		stacktrace(cormap, &r.r, xtrace);
    192 	}
    193 	exits(0);
    194 }
    195 
    196 typedef struct AllThread AllThread;
    197 struct AllThread
    198 {
    199 	td_thrhandle_t *a;
    200 	int n;
    201 	int err;
    202 };
    203 
    204 static int
    205 thritercb(const td_thrhandle_t *th, void *cb)
    206 {
    207 	td_thrhandle_t **p;
    208 	AllThread *a;
    209 	int n;
    210 
    211 	a = cb;
    212 	if((a->n&(a->n-1)) == 0){
    213 		if(a->n == 0)
    214 			n = 1;
    215 		else
    216 			n = a->n<<1;
    217 		if((p = realloc(a->a, n*sizeof a->a[0])) == 0){
    218 			a->err = -1;
    219 			return -1;	/* stop iteration */
    220 		}
    221 		a->a = p;
    222 	}
    223 	a->a[a->n++] = *th;
    224 	return 0;
    225 }
    226 
    227 int
    228 td_get_allthreads(td_thragent_t *ta, td_thrhandle_t **pall)
    229 {
    230 	int e;
    231 	AllThread a;
    232 
    233 	a.a = nil;
    234 	a.n = 0;
    235 	a.err = 0;
    236 	if((e = td_ta_thr_iter(ta, thritercb, &a,
    237 		TD_THR_ANY_STATE,
    238 		TD_THR_LOWEST_PRIORITY,
    239 		TD_SIGNO_MASK,
    240 		TD_THR_ANY_USER_FLAGS)) != TD_OK){
    241 		werrstr("%s", terr(e));
    242 		return -1;
    243 	}
    244 
    245 	if(a.err){
    246 		free(a.a);
    247 		return -1;
    248 	}
    249 
    250 	*pall = a.a;
    251 	return a.n;
    252 }
    253 
    254 /*
    255 td_err_e td_ta_map_id2thr(const td_thragent_t *ta_p, thread_t tid,td_thrhandle_t *th_p);
    256 */
    257 
    258 /*
    259 int
    260 threadregs(int tid, Regs **rp)
    261 {
    262 	check pid
    263 	look up tid (td_ta_map_id2thr)
    264 	create Regs with thr handle inside
    265 	rw function calls thr_getregs and then
    266 		pulls out the desired register
    267 }
    268 
    269 */