tt.c - plan9port - [fork] Plan 9 from user space
(HTM) git clone git://src.adamsgaard.dk/plan9port
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
tt.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 */