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 */