Annotation of src/lib/libpthread_dbg/pthread_dbg.c, Revision 1.50
1.50 ! kamil 1: /* $NetBSD: pthread_dbg.c,v 1.49 2016/11/21 03:02:34 kamil 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.50 ! kamil 39: __RCSID("$NetBSD: pthread_dbg.c,v 1.49 2016/11/21 03:02:34 kamil 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)
1.44 christos 62: #define OFFSET(thread, field) \
63: (((char *)(thread)->addr) + offsetof(struct __pthread_st, field))
1.12 nathanw 64:
1.20 nathanw 65: /* Compensate for debuggers that want a zero ID to be a sentinel */
66: #define TN_OFFSET 1
67:
1.2 thorpej 68: static int td__getthread(td_proc_t *proc, caddr_t addr, td_thread_t **threadp);
1.10 cl 69:
1.2 thorpej 70: int
71: td_open(struct td_proc_callbacks_t *cb, void *arg, td_proc_t **procp)
72: {
73: td_proc_t *proc;
1.12 nathanw 74: caddr_t addr;
1.2 thorpej 75: int dbg;
76: int val;
77:
78: proc = malloc(sizeof(*proc));
79: if (proc == NULL)
80: return TD_ERR_NOMEM;
81: proc->cb = cb;
82: proc->arg = arg;
83:
1.12 nathanw 84: val = LOOKUP(proc, "pthread__dbg", &addr);
85: if (val != 0) {
86: if (val == TD_ERR_NOSYM)
87: val = TD_ERR_NOLIB;
88: goto error;
89: }
90: proc->dbgaddr = addr;
91:
92: val = LOOKUP(proc, "pthread__allqueue", &addr);
1.42 christos 93: if (val != 0)
1.12 nathanw 94: goto error;
95: proc->allqaddr = addr;
96:
1.41 christos 97: val = LOOKUP(proc, "pthread__tsd_list", &addr);
1.42 christos 98: if (val != 0)
1.2 thorpej 99: goto error;
1.41 christos 100: proc->tsdlistaddr = addr;
1.2 thorpej 101:
1.12 nathanw 102: val = LOOKUP(proc, "pthread__tsd_destructors", &addr);
1.42 christos 103: if (val != 0)
1.12 nathanw 104: goto error;
105: proc->tsddestaddr = addr;
106:
1.16 cl 107: val = READ(proc, proc->dbgaddr, &dbg, sizeof(int));
1.2 thorpej 108: if (val != 0)
109: goto error;
110:
111: if (dbg != 0) {
112: /* Another instance of libpthread_dbg is already attached. */
113: val = TD_ERR_INUSE;
114: goto error;
115: }
116:
1.37 ad 117: val = LOOKUP(proc, "pthread__stacksize_lg", &addr);
1.12 nathanw 118: if (val == 0)
119: proc->stacksizeaddr = addr;
120: else
121: proc->stacksizeaddr = NULL;
122: proc->stacksizelg = -1;
123: proc->stacksize = 0;
124: proc->stackmask = 0;
125:
1.23 nathanw 126: proc->regbuf = NULL;
127: proc->fpregbuf = NULL;
128:
1.2 thorpej 129: dbg = getpid();
130: /*
131: * If this fails it probably means we're debugging a core file and
132: * can't write to it.
133: * If it's something else we'll lose the next time we hit WRITE,
134: * but not before, and that's OK.
135: */
1.12 nathanw 136: WRITE(proc, proc->dbgaddr, &dbg, sizeof(int));
1.2 thorpej 137:
138: PTQ_INIT(&proc->threads);
139:
140: *procp = proc;
141:
142: return 0;
143:
144: error:
145: free(proc);
146: return val;
147: }
148:
149: int
150: td_close(td_proc_t *proc)
151: {
152: int dbg;
153: td_thread_t *t, *next;
154:
155: dbg = 0;
156: /*
157: * Error returns from this write are mot really a problem;
158: * the process doesn't exist any more.
159: */
1.12 nathanw 160: WRITE(proc, proc->dbgaddr, &dbg, sizeof(int));
1.2 thorpej 161:
162: /* Deallocate the list of thread structures */
163: for (t = PTQ_FIRST(&proc->threads); t; t = next) {
164: next = PTQ_NEXT(t, list);
165: PTQ_REMOVE(&proc->threads, t, list);
166: free(t);
167: }
1.23 nathanw 168: if (proc->regbuf != NULL) {
169: free(proc->regbuf);
170: free(proc->fpregbuf);
171: }
172:
1.2 thorpej 173: free(proc);
174: return 0;
175: }
176:
177:
178: int
179: td_thr_iter(td_proc_t *proc, int (*call)(td_thread_t *, void *), void *callarg)
180: {
181: int val;
1.12 nathanw 182: caddr_t next;
1.36 ad 183: pthread_queue_t allq;
1.2 thorpej 184: td_thread_t *thread;
185:
1.12 nathanw 186: val = READ(proc, proc->allqaddr, &allq, sizeof(allq));
1.2 thorpej 187: if (val != 0)
188: return val;
189:
1.3 christos 190: next = (void *)allq.ptqh_first;
191: while (next != NULL) {
1.2 thorpej 192: val = td__getthread(proc, next, &thread);
193: if (val != 0)
194: return val;
195: val = (*call)(thread, callarg);
196: if (val != 0)
197: return 0;
198:
199: val = READ(proc,
1.8 nathanw 200: next + offsetof(struct __pthread_st, pt_allq.ptqe_next),
1.2 thorpej 201: &next, sizeof(next));
202: if (val != 0)
203: return val;
204: }
205: return 0;
206: }
207:
208: int
209: td_thr_info(td_thread_t *thread, td_thread_info_t *info)
210: {
1.33 ad 211: int tmp, val;
1.2 thorpej 212:
1.45 kamil 213: val = READ(thread->proc, OFFSET(thread, pt_magic), &tmp, sizeof(tmp));
1.2 thorpej 214: if (val != 0)
215: return val;
216:
217: if (tmp != PT_MAGIC)
218: return TD_ERR_BADTHREAD;
219:
220: info->thread_addr = thread->addr;
1.44 christos 221: if ((val = READ(thread->proc,
222: OFFSET(thread, pt_state), &tmp, sizeof(tmp))) != 0)
1.11 cl 223: return val;
1.2 thorpej 224: switch (tmp) {
225: case PT_STATE_RUNNING:
226: info->thread_state = TD_STATE_RUNNING;
227: break;
228: case PT_STATE_ZOMBIE:
229: info->thread_state = TD_STATE_ZOMBIE;
230: break;
1.49 kamil 231: case PT_STATE_DEAD:
232: info->thread_state = TD_STATE_DEAD;
233: break;
1.2 thorpej 234: default:
235: info->thread_state = TD_STATE_UNKNOWN;
236: }
237:
1.34 ad 238: info->thread_type = TD_TYPE_USER;
1.2 thorpej 239:
1.44 christos 240: if ((val = READ(thread->proc, OFFSET(thread, pt_stack),
1.2 thorpej 241: &info->thread_stack, sizeof(stack_t))) != 0)
242: return val;
243:
1.44 christos 244: if ((val = READ(thread->proc, OFFSET(thread, pt_errno),
1.2 thorpej 245: &info->thread_errno, sizeof(info->thread_errno))) != 0)
246: return val;
247:
1.44 christos 248: if ((val = READ(thread->proc, OFFSET(thread, pt_lid),
1.6 nathanw 249: &info->thread_id, sizeof(info->thread_id))) != 0)
1.2 thorpej 250: return val;
251:
1.20 nathanw 252: info->thread_id += TN_OFFSET;
1.2 thorpej 253:
254: return 0;
255: }
256:
257: int
1.4 nathanw 258: td_thr_getname(td_thread_t *thread, char *name, int len)
259: {
260: int val, tmp;
261: caddr_t nameaddr;
262:
263:
1.46 kamil 264: val = READ(thread->proc, OFFSET(thread, pt_magic), &tmp, sizeof(tmp));
1.4 nathanw 265: if (val != 0)
266: return val;
267:
268: if (tmp != PT_MAGIC)
269: return TD_ERR_BADTHREAD;
270:
1.44 christos 271: if ((val = READ(thread->proc, OFFSET(thread, pt_name),
1.4 nathanw 272: &nameaddr, sizeof(nameaddr))) != 0)
273: return val;
274:
275: if (nameaddr == 0)
276: name[0] = '\0';
277: else if ((val = READ(thread->proc, nameaddr,
1.9 christos 278: name, (size_t)MIN(PTHREAD_MAX_NAMELEN_NP, len))) != 0)
1.4 nathanw 279: return val;
280:
1.48 kamil 281: if (len < PTHREAD_MAX_NAMELEN_NP)
282: name[len - 1] = '\0';
283:
1.4 nathanw 284: return 0;
285: }
286:
287: int
1.2 thorpej 288: td_thr_getregs(td_thread_t *thread, int regset, void *buf)
289: {
1.33 ad 290: int tmp, val;
1.2 thorpej 291:
1.44 christos 292: if ((val = READ(thread->proc, OFFSET(thread, pt_state),
293: &tmp, sizeof(tmp))) != 0)
1.2 thorpej 294: return val;
295:
296: switch (tmp) {
297: case PT_STATE_RUNNING:
298: /*
299: * The register state of the thread is live in the
300: * inferior process's register state.
301: */
302: val = GETREGS(thread->proc, regset, thread->lwp, buf);
303: if (val != 0)
304: return val;
305: break;
306: case PT_STATE_ZOMBIE:
1.49 kamil 307: case PT_STATE_DEAD:
1.2 thorpej 308: default:
309: return TD_ERR_BADTHREAD;
310: }
311:
312: return 0;
313: }
314:
315: int
316: td_thr_setregs(td_thread_t *thread, int regset, void *buf)
317: {
1.33 ad 318: int val, tmp;
1.2 thorpej 319:
1.44 christos 320: if ((val = READ(thread->proc, OFFSET(thread, pt_state),
321: &tmp, sizeof(tmp))) != 0)
1.2 thorpej 322: return val;
323:
324: switch (tmp) {
325: case PT_STATE_RUNNING:
326: /*
327: * The register state of the thread is live in the
328: * inferior process's register state.
329: */
330: val = SETREGS(thread->proc, regset, thread->lwp, buf);
331: if (val != 0)
332: return val;
333: break;
334: case PT_STATE_ZOMBIE:
1.49 kamil 335: case PT_STATE_DEAD:
1.2 thorpej 336: default:
337: return TD_ERR_BADTHREAD;
338: }
339:
340: return 0;
341: }
342:
343: int
344: td_map_pth2thr(td_proc_t *proc, pthread_t thread, td_thread_t **threadp)
345: {
346: int magic, val;
347:
1.50 ! kamil 348: val = READ(proc, (caddr_t)&thread->pt_magic, &magic, sizeof(magic));
1.2 thorpej 349: if (val != 0)
350: return val;
351:
352: if (magic != PT_MAGIC)
353: return TD_ERR_NOOBJ;
354:
1.3 christos 355: val = td__getthread(proc, (void *)thread, threadp);
1.2 thorpej 356: if (val != 0)
357: return val;
358:
359: return 0;
360: }
361:
362: int
363: td_map_id2thr(td_proc_t *proc, int threadid, td_thread_t **threadp)
364: {
365: int val, num;
1.12 nathanw 366: caddr_t next;
1.36 ad 367: pthread_queue_t allq;
1.2 thorpej 368: td_thread_t *thread;
369:
370:
1.12 nathanw 371: val = READ(proc, proc->allqaddr, &allq, sizeof(allq));
1.2 thorpej 372: if (val != 0)
373: return val;
374:
1.20 nathanw 375: /* Correct for offset */
376: threadid -= TN_OFFSET;
1.3 christos 377: next = (void *)allq.ptqh_first;
378: while (next != NULL) {
1.44 christos 379: val = READ(proc, next + offsetof(struct __pthread_st, pt_lid),
1.2 thorpej 380: &num, sizeof(num));
381:
382: if (num == threadid)
383: break;
384:
385: val = READ(proc,
1.8 nathanw 386: next + offsetof(struct __pthread_st, pt_allq.ptqe_next),
1.2 thorpej 387: &next, sizeof(next));
388: if (val != 0)
389: return val;
390: }
391:
392: if (next == 0) {
393: /* A matching thread was not found. */
394: return TD_ERR_NOOBJ;
395: }
396:
397: val = td__getthread(proc, next, &thread);
398: if (val != 0)
399: return val;
400: *threadp = thread;
401:
402: return 0;
403: }
404:
405: int
406: td_tsd_iter(td_proc_t *proc,
407: int (*call)(pthread_key_t, void (*)(void *), void *), void *arg)
408: {
1.41 christos 409: #ifdef notyet
1.2 thorpej 410: int val;
1.40 ad 411: int i;
412: void *allocated;
1.2 thorpej 413: void (*destructor)(void *);
414:
1.43 manu 415: for (i = 0; i < pthread_keys_max; i++) {
1.41 christos 416: val = READ(proc, proc->tsdlistaddr + i * sizeof(allocated),
1.6 nathanw 417: &allocated, sizeof(allocated));
1.2 thorpej 418: if (val != 0)
419: return val;
420:
1.40 ad 421: if ((uintptr_t)allocated) {
1.12 nathanw 422: val = READ(proc, proc->tsddestaddr +
423: i * sizeof(destructor),
1.2 thorpej 424: &destructor, sizeof(destructor));
425: if (val != 0)
426: return val;
427:
428: val = (call)(i, destructor, arg);
429: if (val != 0)
430: return val;
431: }
432: }
1.41 christos 433: #else
434: abort();
435: #endif
1.2 thorpej 436:
437: return 0;
438: }
1.17 nathanw 439:
440: /* Suspend a thread from running */
441: int
442: td_thr_suspend(td_thread_t *thread)
443: {
1.33 ad 444: int tmp, val;
1.17 nathanw 445:
446: /* validate the thread */
1.46 kamil 447: val = READ(thread->proc, OFFSET(thread, pt_magic), &tmp, sizeof(tmp));
1.17 nathanw 448: if (val != 0)
449: return val;
450: if (tmp != PT_MAGIC)
451: return TD_ERR_BADTHREAD;
452:
1.44 christos 453: val = READ(thread->proc, OFFSET(thread, pt_lid), &tmp, sizeof(tmp));
1.39 ad 454: if (val != 0)
455: return val;
456:
457: /* XXXLWP continue the sucker */;
458:
1.17 nathanw 459: return 0;
460: }
461:
462: /* Restore a suspended thread to its previous state */
463: int
464: td_thr_resume(td_thread_t *thread)
465: {
1.33 ad 466: int tmp, val;
1.17 nathanw 467:
468: /* validate the thread */
1.46 kamil 469: val = READ(thread->proc, OFFSET(thread, pt_magic), &tmp, sizeof(tmp));
1.17 nathanw 470: if (val != 0)
471: return val;
472: if (tmp != PT_MAGIC)
473: return TD_ERR_BADTHREAD;
474:
1.44 christos 475: val = READ(thread->proc, OFFSET(thread, pt_lid), &tmp, sizeof(tmp));
1.17 nathanw 476: if (val != 0)
477: return val;
478:
1.39 ad 479: /* XXXLWP continue the sucker */;
1.34 ad 480:
1.17 nathanw 481: return 0;
482: }
1.2 thorpej 483:
484: static int
485: td__getthread(td_proc_t *proc, caddr_t addr, td_thread_t **threadp)
486: {
487: td_thread_t *thread;
488:
489: /*
490: * Check if we've allocated a descriptor for this thread.
491: * Sadly, this makes iterating over a set of threads O(N^2)
492: * in the number of threads. More sophisticated data structures
493: * can wait.
494: */
495: PTQ_FOREACH(thread, &proc->threads, list) {
496: if (thread->addr == addr)
497: break;
498: }
499: if (thread == NULL) {
500: thread = malloc(sizeof(*thread));
501: if (thread == NULL)
502: return TD_ERR_NOMEM;
503: thread->proc = proc;
504: thread->addr = addr;
505: thread->lwp = 0;
506: PTQ_INSERT_HEAD(&proc->threads, thread, list);
507: }
508:
509: *threadp = thread;
510: return 0;
511: }
512:
513: int
514: td_thr_tsd(td_thread_t *thread, pthread_key_t key, void **value)
515: {
516: int val;
517:
1.44 christos 518: val = READ(thread->proc, OFFSET(thread, pt_specific) +
1.6 nathanw 519: key * sizeof(void *), value, sizeof(*value));
1.2 thorpej 520:
521: return val;
522: }
CVSweb <webmaster@jp.NetBSD.org>