Annotation of src/lib/libpthread_dbg/pthread_dbg.c, Revision 1.41
1.41 ! christos 1: /* $NetBSD: pthread_dbg.c,v 1.40 2008/03/07 22:27:07 ad Exp $ */
1.2 thorpej 2:
3: /*-
4: * Copyright (c) 2002 Wasabi Systems, Inc.
5: * All rights reserved.
6: *
7: * Written by Nathan J. Williams for Wasabi Systems, Inc.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. All advertising materials mentioning features or use of this software
18: * must display the following acknowledgement:
19: * This product includes software developed for the NetBSD Project by
20: * Wasabi Systems, Inc.
21: * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22: * or promote products derived from this software without specific
23: * prior written permission.
24: *
25: * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35: * POSSIBILITY OF SUCH DAMAGE.
36: */
1.5 lukem 37:
38: #include <sys/cdefs.h>
1.41 ! christos 39: __RCSID("$NetBSD: pthread_dbg.c,v 1.40 2008/03/07 22:27:07 ad Exp $");
1.2 thorpej 40:
1.29 chs 41: #define __EXPOSE_STACK 1
1.34 ad 42:
1.29 chs 43: #include <sys/param.h>
1.34 ad 44: #include <sys/types.h>
1.38 skrll 45: #include <sys/lock.h>
1.34 ad 46:
1.2 thorpej 47: #include <stddef.h>
48: #include <stdlib.h>
49: #include <string.h>
50: #include <errno.h>
51: #include <unistd.h>
1.34 ad 52: #include <lwp.h>
1.2 thorpej 53:
1.24 martin 54: #include <machine/reg.h>
55:
1.2 thorpej 56: #include <pthread.h>
57: #include <pthread_int.h>
58: #include <pthread_dbg.h>
59: #include <pthread_dbg_int.h>
60:
1.12 nathanw 61: #define PT_STACKMASK (proc->stackmask)
62:
1.20 nathanw 63: /* Compensate for debuggers that want a zero ID to be a sentinel */
64: #define TN_OFFSET 1
65:
1.2 thorpej 66: static int td__getthread(td_proc_t *proc, caddr_t addr, td_thread_t **threadp);
1.10 cl 67:
1.2 thorpej 68: int
69: td_open(struct td_proc_callbacks_t *cb, void *arg, td_proc_t **procp)
70: {
71: td_proc_t *proc;
1.12 nathanw 72: caddr_t addr;
1.2 thorpej 73: int dbg;
74: int val;
75:
76: proc = malloc(sizeof(*proc));
77: if (proc == NULL)
78: return TD_ERR_NOMEM;
79: proc->cb = cb;
80: proc->arg = arg;
81:
1.12 nathanw 82: val = LOOKUP(proc, "pthread__dbg", &addr);
83: if (val != 0) {
84: if (val == TD_ERR_NOSYM)
85: val = TD_ERR_NOLIB;
86: goto error;
87: }
88: proc->dbgaddr = addr;
89:
90: val = LOOKUP(proc, "pthread__allqueue", &addr);
91: if (val != 0) {
92: if (val == TD_ERR_NOSYM)
93: val = TD_ERR_NOLIB;
94: goto error;
95: }
96: proc->allqaddr = addr;
97:
1.41 ! christos 98: val = LOOKUP(proc, "pthread__tsd_list", &addr);
1.2 thorpej 99: if (val != 0) {
100: if (val == TD_ERR_NOSYM)
101: val = TD_ERR_NOLIB;
102: goto error;
103: }
1.41 ! christos 104: proc->tsdlistaddr = addr;
1.2 thorpej 105:
1.12 nathanw 106: val = LOOKUP(proc, "pthread__tsd_destructors", &addr);
107: if (val != 0) {
108: if (val == TD_ERR_NOSYM)
109: val = TD_ERR_NOLIB;
110: goto error;
111: }
112: proc->tsddestaddr = addr;
113:
1.16 cl 114: val = READ(proc, proc->dbgaddr, &dbg, sizeof(int));
1.2 thorpej 115: if (val != 0)
116: goto error;
117:
118: if (dbg != 0) {
119: /* Another instance of libpthread_dbg is already attached. */
120: val = TD_ERR_INUSE;
121: goto error;
122: }
123:
1.37 ad 124: val = LOOKUP(proc, "pthread__stacksize_lg", &addr);
1.12 nathanw 125: if (val == 0)
126: proc->stacksizeaddr = addr;
127: else
128: proc->stacksizeaddr = NULL;
129: proc->stacksizelg = -1;
130: proc->stacksize = 0;
131: proc->stackmask = 0;
132:
1.23 nathanw 133: proc->regbuf = NULL;
134: proc->fpregbuf = NULL;
135:
1.2 thorpej 136: dbg = getpid();
137: /*
138: * If this fails it probably means we're debugging a core file and
139: * can't write to it.
140: * If it's something else we'll lose the next time we hit WRITE,
141: * but not before, and that's OK.
142: */
1.12 nathanw 143: WRITE(proc, proc->dbgaddr, &dbg, sizeof(int));
1.2 thorpej 144:
145: PTQ_INIT(&proc->threads);
146:
147: *procp = proc;
148:
149: return 0;
150:
151: error:
152: free(proc);
153: return val;
154: }
155:
156: int
157: td_close(td_proc_t *proc)
158: {
159: int dbg;
160: td_thread_t *t, *next;
161:
162: dbg = 0;
163: /*
164: * Error returns from this write are mot really a problem;
165: * the process doesn't exist any more.
166: */
1.12 nathanw 167: WRITE(proc, proc->dbgaddr, &dbg, sizeof(int));
1.2 thorpej 168:
169: /* Deallocate the list of thread structures */
170: for (t = PTQ_FIRST(&proc->threads); t; t = next) {
171: next = PTQ_NEXT(t, list);
172: PTQ_REMOVE(&proc->threads, t, list);
173: free(t);
174: }
1.23 nathanw 175: if (proc->regbuf != NULL) {
176: free(proc->regbuf);
177: free(proc->fpregbuf);
178: }
179:
1.2 thorpej 180: free(proc);
181: return 0;
182: }
183:
184:
185: int
186: td_thr_iter(td_proc_t *proc, int (*call)(td_thread_t *, void *), void *callarg)
187: {
188: int val;
1.12 nathanw 189: caddr_t next;
1.36 ad 190: pthread_queue_t allq;
1.2 thorpej 191: td_thread_t *thread;
192:
1.12 nathanw 193: val = READ(proc, proc->allqaddr, &allq, sizeof(allq));
1.2 thorpej 194: if (val != 0)
195: return val;
196:
1.3 christos 197: next = (void *)allq.ptqh_first;
198: while (next != NULL) {
1.2 thorpej 199: val = td__getthread(proc, next, &thread);
200: if (val != 0)
201: return val;
202: val = (*call)(thread, callarg);
203: if (val != 0)
204: return 0;
205:
206: val = READ(proc,
1.8 nathanw 207: next + offsetof(struct __pthread_st, pt_allq.ptqe_next),
1.2 thorpej 208: &next, sizeof(next));
209: if (val != 0)
210: return val;
211: }
212: return 0;
213: }
214:
215: int
216: td_thr_info(td_thread_t *thread, td_thread_info_t *info)
217: {
1.33 ad 218: int tmp, val;
1.2 thorpej 219:
220: val = READ(thread->proc, thread->addr, &tmp, sizeof(tmp));
221: if (val != 0)
222: return val;
223:
224: if (tmp != PT_MAGIC)
225: return TD_ERR_BADTHREAD;
226:
227: info->thread_addr = thread->addr;
1.33 ad 228: if ((val = READ(thread->proc,
1.11 cl 229: thread->addr + offsetof(struct __pthread_st, pt_state),
230: &tmp, sizeof(tmp))) != 0)
231: return val;
1.2 thorpej 232: switch (tmp) {
233: case PT_STATE_RUNNING:
234: info->thread_state = TD_STATE_RUNNING;
235: break;
1.34 ad 236: #ifdef XXXLWP
1.19 nathanw 237: case PT_STATE_SUSPENDED:
238: info->thread_state = TD_STATE_SUSPENDED;
239: break;
1.32 christos 240: #endif
1.2 thorpej 241: case PT_STATE_ZOMBIE:
242: info->thread_state = TD_STATE_ZOMBIE;
243: break;
244: default:
245: info->thread_state = TD_STATE_UNKNOWN;
246: }
247:
1.34 ad 248: info->thread_type = TD_TYPE_USER;
1.2 thorpej 249:
250: if ((val = READ(thread->proc,
1.8 nathanw 251: thread->addr + offsetof(struct __pthread_st, pt_stack),
1.2 thorpej 252: &info->thread_stack, sizeof(stack_t))) != 0)
253: return val;
254:
255: if ((val = READ(thread->proc,
1.8 nathanw 256: thread->addr + offsetof(struct __pthread_st, pt_errno),
1.2 thorpej 257: &info->thread_errno, sizeof(info->thread_errno))) != 0)
258: return val;
259:
260: if ((val = READ(thread->proc,
1.39 ad 261: thread->addr + offsetof(struct __pthread_st, pt_lid),
1.6 nathanw 262: &info->thread_id, sizeof(info->thread_id))) != 0)
1.2 thorpej 263: return val;
264:
1.20 nathanw 265: info->thread_id += TN_OFFSET;
1.2 thorpej 266:
267: return 0;
268: }
269:
270: int
1.4 nathanw 271: td_thr_getname(td_thread_t *thread, char *name, int len)
272: {
273: int val, tmp;
274: caddr_t nameaddr;
275:
276:
277: val = READ(thread->proc, thread->addr, &tmp, sizeof(tmp));
278: if (val != 0)
279: return val;
280:
281: if (tmp != PT_MAGIC)
282: return TD_ERR_BADTHREAD;
283:
284: if ((val = READ(thread->proc,
1.8 nathanw 285: thread->addr + offsetof(struct __pthread_st, pt_name),
1.4 nathanw 286: &nameaddr, sizeof(nameaddr))) != 0)
287: return val;
288:
289: if (nameaddr == 0)
290: name[0] = '\0';
291: else if ((val = READ(thread->proc, nameaddr,
1.9 christos 292: name, (size_t)MIN(PTHREAD_MAX_NAMELEN_NP, len))) != 0)
1.4 nathanw 293: return val;
294:
295: return 0;
296: }
297:
298: int
1.2 thorpej 299: td_thr_getregs(td_thread_t *thread, int regset, void *buf)
300: {
1.33 ad 301: int tmp, val;
1.2 thorpej 302:
1.11 cl 303: if ((val = READ(thread->proc,
304: thread->addr + offsetof(struct __pthread_st, pt_state),
305: &tmp, sizeof(tmp))) != 0)
1.2 thorpej 306: return val;
307:
308: switch (tmp) {
309: case PT_STATE_RUNNING:
310: /*
311: * The register state of the thread is live in the
312: * inferior process's register state.
313: */
314: val = GETREGS(thread->proc, regset, thread->lwp, buf);
315: if (val != 0)
316: return val;
317: break;
318: case PT_STATE_ZOMBIE:
319: default:
320: return TD_ERR_BADTHREAD;
321: }
322:
323: return 0;
324: }
325:
326: int
327: td_thr_setregs(td_thread_t *thread, int regset, void *buf)
328: {
1.33 ad 329: int val, tmp;
1.2 thorpej 330:
1.11 cl 331: if ((val = READ(thread->proc,
332: thread->addr + offsetof(struct __pthread_st, pt_state),
333: &tmp, sizeof(tmp))) != 0)
1.2 thorpej 334: return val;
335:
336: switch (tmp) {
337: case PT_STATE_RUNNING:
338: /*
339: * The register state of the thread is live in the
340: * inferior process's register state.
341: */
342: val = SETREGS(thread->proc, regset, thread->lwp, buf);
343: if (val != 0)
344: return val;
345: break;
346: case PT_STATE_ZOMBIE:
347: default:
348: return TD_ERR_BADTHREAD;
349: }
350:
351: return 0;
352: }
353:
354: int
355: td_map_pth2thr(td_proc_t *proc, pthread_t thread, td_thread_t **threadp)
356: {
357: int magic, val;
358:
1.3 christos 359: val = READ(proc, (void *)thread, &magic, sizeof(magic));
1.2 thorpej 360: if (val != 0)
361: return val;
362:
363: if (magic != PT_MAGIC)
364: return TD_ERR_NOOBJ;
365:
1.3 christos 366: val = td__getthread(proc, (void *)thread, threadp);
1.2 thorpej 367: if (val != 0)
368: return val;
369:
370: return 0;
371: }
372:
373: int
374: td_map_id2thr(td_proc_t *proc, int threadid, td_thread_t **threadp)
375: {
376: int val, num;
1.12 nathanw 377: caddr_t next;
1.36 ad 378: pthread_queue_t allq;
1.2 thorpej 379: td_thread_t *thread;
380:
381:
1.12 nathanw 382: val = READ(proc, proc->allqaddr, &allq, sizeof(allq));
1.2 thorpej 383: if (val != 0)
384: return val;
385:
1.20 nathanw 386: /* Correct for offset */
387: threadid -= TN_OFFSET;
1.3 christos 388: next = (void *)allq.ptqh_first;
389: while (next != NULL) {
1.2 thorpej 390: val = READ(proc,
1.39 ad 391: next + offsetof(struct __pthread_st, pt_lid),
1.2 thorpej 392: &num, sizeof(num));
393:
394: if (num == threadid)
395: break;
396:
397: val = READ(proc,
1.8 nathanw 398: next + offsetof(struct __pthread_st, pt_allq.ptqe_next),
1.2 thorpej 399: &next, sizeof(next));
400: if (val != 0)
401: return val;
402: }
403:
404: if (next == 0) {
405: /* A matching thread was not found. */
406: return TD_ERR_NOOBJ;
407: }
408:
409: val = td__getthread(proc, next, &thread);
410: if (val != 0)
411: return val;
412: *threadp = thread;
413:
414: return 0;
415: }
416:
417: int
418: td_tsd_iter(td_proc_t *proc,
419: int (*call)(pthread_key_t, void (*)(void *), void *), void *arg)
420: {
1.41 ! christos 421: #ifdef notyet
1.2 thorpej 422: int val;
1.40 ad 423: int i;
424: void *allocated;
1.2 thorpej 425: void (*destructor)(void *);
426:
427: for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
1.41 ! christos 428: val = READ(proc, proc->tsdlistaddr + i * sizeof(allocated),
1.6 nathanw 429: &allocated, sizeof(allocated));
1.2 thorpej 430: if (val != 0)
431: return val;
432:
1.40 ad 433: if ((uintptr_t)allocated) {
1.12 nathanw 434: val = READ(proc, proc->tsddestaddr +
435: i * sizeof(destructor),
1.2 thorpej 436: &destructor, sizeof(destructor));
437: if (val != 0)
438: return val;
439:
440: val = (call)(i, destructor, arg);
441: if (val != 0)
442: return val;
443: }
444: }
1.41 ! christos 445: #else
! 446: abort();
! 447: #endif
1.2 thorpej 448:
449: return 0;
450: }
1.17 nathanw 451:
452: /* Suspend a thread from running */
453: int
454: td_thr_suspend(td_thread_t *thread)
455: {
1.33 ad 456: int tmp, val;
1.17 nathanw 457:
458: /* validate the thread */
459: val = READ(thread->proc, thread->addr, &tmp, sizeof(tmp));
460: if (val != 0)
461: return val;
462: if (tmp != PT_MAGIC)
463: return TD_ERR_BADTHREAD;
464:
1.39 ad 465: val = READ(thread->proc, thread->addr +
466: offsetof(struct __pthread_st, pt_lid),
467: &tmp, sizeof(tmp));
468: if (val != 0)
469: return val;
470:
471: /* XXXLWP continue the sucker */;
472:
1.17 nathanw 473: return 0;
474: }
475:
476: /* Restore a suspended thread to its previous state */
477: int
478: td_thr_resume(td_thread_t *thread)
479: {
1.33 ad 480: int tmp, val;
1.17 nathanw 481:
482: /* validate the thread */
483: val = READ(thread->proc, thread->addr, &tmp, sizeof(tmp));
484: if (val != 0)
485: return val;
486: if (tmp != PT_MAGIC)
487: return TD_ERR_BADTHREAD;
488:
489: val = READ(thread->proc, thread->addr +
1.39 ad 490: offsetof(struct __pthread_st, pt_lid),
1.17 nathanw 491: &tmp, sizeof(tmp));
492: if (val != 0)
493: return val;
494:
1.39 ad 495: /* XXXLWP continue the sucker */;
1.34 ad 496:
1.17 nathanw 497: return 0;
498: }
1.2 thorpej 499:
500: static int
501: td__getthread(td_proc_t *proc, caddr_t addr, td_thread_t **threadp)
502: {
503: td_thread_t *thread;
504:
505: /*
506: * Check if we've allocated a descriptor for this thread.
507: * Sadly, this makes iterating over a set of threads O(N^2)
508: * in the number of threads. More sophisticated data structures
509: * can wait.
510: */
511: PTQ_FOREACH(thread, &proc->threads, list) {
512: if (thread->addr == addr)
513: break;
514: }
515: if (thread == NULL) {
516: thread = malloc(sizeof(*thread));
517: if (thread == NULL)
518: return TD_ERR_NOMEM;
519: thread->proc = proc;
520: thread->addr = addr;
521: thread->lwp = 0;
522: PTQ_INSERT_HEAD(&proc->threads, thread, list);
523: }
524:
525: *threadp = thread;
526: return 0;
527: }
528:
529: int
530: td_thr_tsd(td_thread_t *thread, pthread_key_t key, void **value)
531: {
532: int val;
533:
534: val = READ(thread->proc, thread->addr +
1.8 nathanw 535: offsetof(struct __pthread_st, pt_specific) +
1.6 nathanw 536: key * sizeof(void *), value, sizeof(*value));
1.2 thorpej 537:
538: return val;
539: }
CVSweb <webmaster@jp.NetBSD.org>