1 /* $NetBSD: pthread_dbg.c,v 1.39 2007/10/16 15:06:11 ad Exp $ */
4 * Copyright (c) 2002 Wasabi Systems, Inc.
7 * Written by Nathan J. Williams for Wasabi Systems, Inc.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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.
38 #include <sys/cdefs.h>
39 __RCSID("$NetBSD: pthread_dbg.c,v 1.39 2007/10/16 15:06:11 ad Exp $");
41 #define __EXPOSE_STACK 1
43 #include <sys/param.h>
44 #include <sys/types.h>
54 #include <machine/reg.h>
57 #include <pthread_int.h>
58 #include <pthread_dbg.h>
59 #include <pthread_dbg_int.h>
61 #define PT_STACKMASK (proc->stackmask)
63 /* Compensate for debuggers that want a zero ID to be a sentinel */
66 static int td__getthread(td_proc_t
*proc
, caddr_t addr
, td_thread_t
**threadp
);
69 td_open(struct td_proc_callbacks_t
*cb
, void *arg
, td_proc_t
**procp
)
76 proc
= malloc(sizeof(*proc
));
82 val
= LOOKUP(proc
, "pthread__dbg", &addr
);
84 if (val
== TD_ERR_NOSYM
)
90 val
= LOOKUP(proc
, "pthread__allqueue", &addr
);
92 if (val
== TD_ERR_NOSYM
)
96 proc
->allqaddr
= addr
;
98 val
= LOOKUP(proc
, "pthread__tsd_alloc", &addr
);
100 if (val
== TD_ERR_NOSYM
)
104 proc
->tsdallocaddr
= addr
;
106 val
= LOOKUP(proc
, "pthread__tsd_destructors", &addr
);
108 if (val
== TD_ERR_NOSYM
)
112 proc
->tsddestaddr
= addr
;
114 val
= READ(proc
, proc
->dbgaddr
, &dbg
, sizeof(int));
119 /* Another instance of libpthread_dbg is already attached. */
124 val
= LOOKUP(proc
, "pthread__stacksize_lg", &addr
);
126 proc
->stacksizeaddr
= addr
;
128 proc
->stacksizeaddr
= NULL
;
129 proc
->stacksizelg
= -1;
134 proc
->fpregbuf
= NULL
;
138 * If this fails it probably means we're debugging a core file and
140 * If it's something else we'll lose the next time we hit WRITE,
141 * but not before, and that's OK.
143 WRITE(proc
, proc
->dbgaddr
, &dbg
, sizeof(int));
145 PTQ_INIT(&proc
->threads
);
157 td_close(td_proc_t
*proc
)
160 td_thread_t
*t
, *next
;
164 * Error returns from this write are mot really a problem;
165 * the process doesn't exist any more.
167 WRITE(proc
, proc
->dbgaddr
, &dbg
, sizeof(int));
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
);
175 if (proc
->regbuf
!= NULL
) {
177 free(proc
->fpregbuf
);
186 td_thr_iter(td_proc_t
*proc
, int (*call
)(td_thread_t
*, void *), void *callarg
)
190 pthread_queue_t allq
;
193 val
= READ(proc
, proc
->allqaddr
, &allq
, sizeof(allq
));
197 next
= (void *)allq
.ptqh_first
;
198 while (next
!= NULL
) {
199 val
= td__getthread(proc
, next
, &thread
);
202 val
= (*call
)(thread
, callarg
);
207 next
+ offsetof(struct __pthread_st
, pt_allq
.ptqe_next
),
208 &next
, sizeof(next
));
216 td_thr_info(td_thread_t
*thread
, td_thread_info_t
*info
)
220 val
= READ(thread
->proc
, thread
->addr
, &tmp
, sizeof(tmp
));
225 return TD_ERR_BADTHREAD
;
227 info
->thread_addr
= thread
->addr
;
228 if ((val
= READ(thread
->proc
,
229 thread
->addr
+ offsetof(struct __pthread_st
, pt_state
),
230 &tmp
, sizeof(tmp
))) != 0)
233 case PT_STATE_RUNNING
:
234 info
->thread_state
= TD_STATE_RUNNING
;
237 case PT_STATE_SUSPENDED
:
238 info
->thread_state
= TD_STATE_SUSPENDED
;
241 case PT_STATE_ZOMBIE
:
242 info
->thread_state
= TD_STATE_ZOMBIE
;
245 info
->thread_state
= TD_STATE_UNKNOWN
;
248 info
->thread_type
= TD_TYPE_USER
;
250 if ((val
= READ(thread
->proc
,
251 thread
->addr
+ offsetof(struct __pthread_st
, pt_stack
),
252 &info
->thread_stack
, sizeof(stack_t
))) != 0)
255 if ((val
= READ(thread
->proc
,
256 thread
->addr
+ offsetof(struct __pthread_st
, pt_errno
),
257 &info
->thread_errno
, sizeof(info
->thread_errno
))) != 0)
260 if ((val
= READ(thread
->proc
,
261 thread
->addr
+ offsetof(struct __pthread_st
, pt_lid
),
262 &info
->thread_id
, sizeof(info
->thread_id
))) != 0)
265 info
->thread_id
+= TN_OFFSET
;
271 td_thr_getname(td_thread_t
*thread
, char *name
, int len
)
277 val
= READ(thread
->proc
, thread
->addr
, &tmp
, sizeof(tmp
));
282 return TD_ERR_BADTHREAD
;
284 if ((val
= READ(thread
->proc
,
285 thread
->addr
+ offsetof(struct __pthread_st
, pt_name
),
286 &nameaddr
, sizeof(nameaddr
))) != 0)
291 else if ((val
= READ(thread
->proc
, nameaddr
,
292 name
, (size_t)MIN(PTHREAD_MAX_NAMELEN_NP
, len
))) != 0)
299 td_thr_getregs(td_thread_t
*thread
, int regset
, void *buf
)
303 if ((val
= READ(thread
->proc
,
304 thread
->addr
+ offsetof(struct __pthread_st
, pt_state
),
305 &tmp
, sizeof(tmp
))) != 0)
309 case PT_STATE_RUNNING
:
311 * The register state of the thread is live in the
312 * inferior process's register state.
314 val
= GETREGS(thread
->proc
, regset
, thread
->lwp
, buf
);
318 case PT_STATE_ZOMBIE
:
320 return TD_ERR_BADTHREAD
;
327 td_thr_setregs(td_thread_t
*thread
, int regset
, void *buf
)
331 if ((val
= READ(thread
->proc
,
332 thread
->addr
+ offsetof(struct __pthread_st
, pt_state
),
333 &tmp
, sizeof(tmp
))) != 0)
337 case PT_STATE_RUNNING
:
339 * The register state of the thread is live in the
340 * inferior process's register state.
342 val
= SETREGS(thread
->proc
, regset
, thread
->lwp
, buf
);
346 case PT_STATE_ZOMBIE
:
348 return TD_ERR_BADTHREAD
;
355 td_map_pth2thr(td_proc_t
*proc
, pthread_t thread
, td_thread_t
**threadp
)
359 val
= READ(proc
, (void *)thread
, &magic
, sizeof(magic
));
363 if (magic
!= PT_MAGIC
)
366 val
= td__getthread(proc
, (void *)thread
, threadp
);
374 td_map_id2thr(td_proc_t
*proc
, int threadid
, td_thread_t
**threadp
)
378 pthread_queue_t allq
;
382 val
= READ(proc
, proc
->allqaddr
, &allq
, sizeof(allq
));
386 /* Correct for offset */
387 threadid
-= TN_OFFSET
;
388 next
= (void *)allq
.ptqh_first
;
389 while (next
!= NULL
) {
391 next
+ offsetof(struct __pthread_st
, pt_lid
),
398 next
+ offsetof(struct __pthread_st
, pt_allq
.ptqe_next
),
399 &next
, sizeof(next
));
405 /* A matching thread was not found. */
409 val
= td__getthread(proc
, next
, &thread
);
418 td_tsd_iter(td_proc_t
*proc
,
419 int (*call
)(pthread_key_t
, void (*)(void *), void *), void *arg
)
424 void (*destructor
)(void *);
426 for (i
= 0; i
< PTHREAD_KEYS_MAX
; i
++) {
427 val
= READ(proc
, proc
->tsdallocaddr
+ i
* sizeof(allocated
),
428 &allocated
, sizeof(allocated
));
432 if ((uintptr_t)allocated
) {
433 val
= READ(proc
, proc
->tsddestaddr
+
434 i
* sizeof(destructor
),
435 &destructor
, sizeof(destructor
));
439 val
= (call
)(i
, destructor
, arg
);
448 /* Suspend a thread from running */
450 td_thr_suspend(td_thread_t
*thread
)
454 /* validate the thread */
455 val
= READ(thread
->proc
, thread
->addr
, &tmp
, sizeof(tmp
));
459 return TD_ERR_BADTHREAD
;
461 val
= READ(thread
->proc
, thread
->addr
+
462 offsetof(struct __pthread_st
, pt_lid
),
467 /* XXXLWP continue the sucker */;
472 /* Restore a suspended thread to its previous state */
474 td_thr_resume(td_thread_t
*thread
)
478 /* validate the thread */
479 val
= READ(thread
->proc
, thread
->addr
, &tmp
, sizeof(tmp
));
483 return TD_ERR_BADTHREAD
;
485 val
= READ(thread
->proc
, thread
->addr
+
486 offsetof(struct __pthread_st
, pt_lid
),
491 /* XXXLWP continue the sucker */;
497 td__getthread(td_proc_t
*proc
, caddr_t addr
, td_thread_t
**threadp
)
502 * Check if we've allocated a descriptor for this thread.
503 * Sadly, this makes iterating over a set of threads O(N^2)
504 * in the number of threads. More sophisticated data structures
507 PTQ_FOREACH(thread
, &proc
->threads
, list
) {
508 if (thread
->addr
== addr
)
511 if (thread
== NULL
) {
512 thread
= malloc(sizeof(*thread
));
518 PTQ_INSERT_HEAD(&proc
->threads
, thread
, list
);
526 td_thr_tsd(td_thread_t
*thread
, pthread_key_t key
, void **value
)
530 val
= READ(thread
->proc
, thread
->addr
+
531 offsetof(struct __pthread_st
, pt_specific
) +
532 key
* sizeof(void *), value
, sizeof(*value
));