1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-29 11:41:21 +03:00

* sysdeps/unix/sysv/linux/speed.c

(cfsetospeed): Only set c_ospeed under [_HAVE_STRUCT_TERMIOS_C_OSPEED].
	(cfsetispeed): Only set c_ispeed under [_HAVE_STRUCT_TERMIOS_C_ISPEED].
	* sysdeps/unix/sysv/linux/bits/termios.h
	(_HAVE_STRUCT_TERMIOS_C_ISPEED, _HAVE_STRUCT_TERMIOS_C_OSPEED): Define.
	* sysdeps/unix/sysv/linux/alpha/bits/termios.h: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/bits/termios.h: Likewise.
This commit is contained in:
Roland McGrath
2003-09-09 07:01:01 +00:00
parent 416be7f049
commit 7f08f55a9f
52 changed files with 1702 additions and 1004 deletions

View File

@ -1,3 +1,13 @@
2003-09-08 Roland McGrath <roland@frob.com>
* sysdeps/unix/sysv/linux/speed.c
(cfsetospeed): Only set c_ospeed under [_HAVE_STRUCT_TERMIOS_C_OSPEED].
(cfsetispeed): Only set c_ispeed under [_HAVE_STRUCT_TERMIOS_C_ISPEED].
* sysdeps/unix/sysv/linux/bits/termios.h
(_HAVE_STRUCT_TERMIOS_C_ISPEED, _HAVE_STRUCT_TERMIOS_C_OSPEED): Define.
* sysdeps/unix/sysv/linux/alpha/bits/termios.h: Likewise.
* sysdeps/unix/sysv/linux/powerpc/bits/termios.h: Likewise.
2003-09-08 Ulrich Drepper <drepper@redhat.com> 2003-09-08 Ulrich Drepper <drepper@redhat.com>
* sysdeps/unix/sysv/linux/x86_64/register-dump.h: Undo last change. * sysdeps/unix/sysv/linux/x86_64/register-dump.h: Undo last change.

View File

@ -1,3 +1,27 @@
2003-09-05 Roland McGrath <roland@redhat.com>
* pthread_create.c (__pthread_pthread_sizeof_descr): Removed.
Instead, include ../nptl_db/db_info.c to do its magic.
* pthread_key_create.c (__pthread_pthread_keys_max): Removed.
(__pthread_pthread_key_2ndlevel_size): Likewise.
* sysdeps/alpha/tls.h (DB_THREAD_SELF): New macro.
* sysdeps/i386/tls.h (DB_THREAD_SELF): New macro.
* sysdeps/ia64/tls.h (DB_THREAD_SELF): New macro.
* sysdeps/powerpc/tls.h (DB_THREAD_SELF): New macro.
* sysdeps/s390/tls.h (DB_THREAD_SELF): New macro.
* sysdeps/sh/tls.h (DB_THREAD_SELF): New macro.
* sysdeps/sparc/tls.h (DB_THREAD_SELF): New macro.
* sysdeps/x86_64/tls.h (DB_THREAD_SELF): New macro.
* sysdeps/alpha/td_ta_map_lwp2thr.c: File removed.
* sysdeps/generic/td_ta_map_lwp2thr.c: File removed.
* sysdeps/i386/td_ta_map_lwp2thr.c: File removed.
* sysdeps/ia64/td_ta_map_lwp2thr.c: File removed.
* sysdeps/powerpc/td_ta_map_lwp2thr.c: File removed.
* sysdeps/s390/td_ta_map_lwp2thr.c: File removed.
* sysdeps/sh/td_ta_map_lwp2thr.c: File removed.
* sysdeps/sparc/td_ta_map_lwp2thr.c: File removed.
* sysdeps/x86_64/td_ta_map_lwp2thr.c: File removed.
2003-09-08 Ulrich Drepper <drepper@redhat.com> 2003-09-08 Ulrich Drepper <drepper@redhat.com>
* sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Change type * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Change type

View File

@ -60,9 +60,6 @@ struct pthread_key_struct __pthread_keys[PTHREAD_KEYS_MAX]
__attribute__ ((nocommon)); __attribute__ ((nocommon));
hidden_data_def (__pthread_keys) hidden_data_def (__pthread_keys)
/* This is for libthread_db only. */
const int __pthread_pthread_sizeof_descr = sizeof (struct pthread);
struct pthread * struct pthread *
internal_function internal_function
__find_in_stack_list (pd) __find_in_stack_list (pd)
@ -475,3 +472,7 @@ __pthread_create_2_0 (newthread, attr, start_routine, arg)
compat_symbol (libpthread, __pthread_create_2_0, pthread_create, compat_symbol (libpthread, __pthread_create_2_0, pthread_create,
GLIBC_2_0); GLIBC_2_0);
#endif #endif
/* Information for libthread_db. */
#include "../nptl_db/db_info.c"

View File

@ -24,12 +24,6 @@
/* Internal mutex for __pthread_keys table handling. */ /* Internal mutex for __pthread_keys table handling. */
lll_lock_t __pthread_keys_lock = LLL_LOCK_INITIALIZER; lll_lock_t __pthread_keys_lock = LLL_LOCK_INITIALIZER;
/* For debugging purposes put the maximum number of keys in a variable. */
const int __pthread_pthread_keys_max = PTHREAD_KEYS_MAX;
const int __pthread_pthread_key_2ndlevel_size = PTHREAD_KEY_2NDLEVEL_SIZE;
int int
__pthread_key_create (key, destr) __pthread_key_create (key, destr)
pthread_key_t *key; pthread_key_t *key;

View File

@ -1,46 +0,0 @@
/* Which thread is running on an LWP? PowerPC version.
Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include "thread_dbP.h"
#include <tls.h>
td_err_e
td_ta_map_lwp2thr (const td_thragent_t *ta, lwpid_t lwpid, td_thrhandle_t *th)
{
LOG ("td_ta_map_lwp2thr");
/* Test whether the TA parameter is ok. */
if (! ta_ok (ta))
return TD_BADTA;
prgregset_t regs;
if (ps_lgetregs (ta->ph, lwpid, regs) != PS_OK)
return TD_ERR;
/* The uniq value is stored in slot 33 in recent gdb; it isn't stored
anywhere otherwise. */
th->th_unique = ((void *) regs[32]
- TLS_TCB_OFFSET - TLS_TCB_SIZE - TLS_PRE_TCB_SIZE);
/* Found it. Now complete the `td_thrhandle_t' object. */
th->th_ta_p = (td_thragent_t *) ta;
return TD_OK;
}

View File

@ -118,6 +118,10 @@ typedef struct
((struct pthread *) (__builtin_thread_pointer () \ ((struct pthread *) (__builtin_thread_pointer () \
- TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)) - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE))
/* Magic for libthread_db to know how to do THREAD_SELF. */
# define DB_THREAD_SELF \
REGISTER (64, 32 * 8, - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)
/* Identifier for the current thread. THREAD_SELF is usable but /* Identifier for the current thread. THREAD_SELF is usable but
sometimes more expensive than necessary as in this case. */ sometimes more expensive than necessary as in this case. */
# define THREAD_ID (__builtin_thread_pointer ()) # define THREAD_ID (__builtin_thread_pointer ())

View File

@ -1,45 +0,0 @@
/* Which thread is running on an LWP? Stub version.
Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include "thread_dbP.h"
#include <tls.h>
#include <sys/reg.h>
td_err_e
td_ta_map_lwp2thr (const td_thragent_t *ta, lwpid_t lwpid, td_thrhandle_t *th)
{
LOG ("td_ta_map_lwp2thr");
/* Test whether the TA parameter is ok. */
if (! ta_ok (ta))
return TD_BADTA;
prgregset_t regs;
if (ps_lgetregs (ta->ph, lwpid, regs) != PS_OK)
return TD_ERR;
# error port this file
// th->th_unique = thread register;
/* Found it. Now complete the `td_thrhandle_t' object. */
th->th_ta_p = (td_thragent_t *) ta;
return TD_OK;
}

View File

@ -1,48 +0,0 @@
/* Which thread is running on an LWP? i386 version.
Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include "thread_dbP.h"
#include <tls.h>
#include <sys/reg.h>
td_err_e
td_ta_map_lwp2thr (const td_thragent_t *ta, lwpid_t lwpid, td_thrhandle_t *th)
{
LOG ("td_ta_map_lwp2thr");
/* Test whether the TA parameter is ok. */
if (! ta_ok (ta))
return TD_BADTA;
prgregset_t regs;
if (ps_lgetregs (ta->ph, lwpid, regs) != PS_OK)
return TD_ERR;
/* Get the thread area for the addressed thread. */
if (ps_get_thread_area (ta->ph, lwpid, regs[GS] >> 3, &th->th_unique)
!= PS_OK)
return TD_ERR; /* XXX Other error value? */
/* Found it. Now complete the `td_thrhandle_t' object. */
th->th_ta_p = (td_thragent_t *) ta;
return TD_OK;
}

View File

@ -251,6 +251,11 @@ union user_desc_init
: "i" (offsetof (struct pthread, header.self))); \ : "i" (offsetof (struct pthread, header.self))); \
__self;}) __self;})
/* Magic for libthread_db to know how to do THREAD_SELF. */
# define DB_THREAD_SELF \
REGISTER_THREAD_AREA (32, offsetof (struct user_regs_struct, xgs), 3) \
REGISTER_THREAD_AREA (64, 26 * 8, 3) /* x86-64's user_regs_struct->gs */
/* Read member of the thread descriptor directly. */ /* Read member of the thread descriptor directly. */
# define THREAD_GETMEM(descr, member) \ # define THREAD_GETMEM(descr, member) \

View File

@ -1,44 +0,0 @@
/* Which thread is running on an LWP? IA-64 version.
Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include "thread_dbP.h"
#include <tls.h>
td_err_e
td_ta_map_lwp2thr (const td_thragent_t *ta, lwpid_t lwpid, td_thrhandle_t *th)
{
LOG ("td_ta_map_lwp2thr");
/* Test whether the TA parameter is ok. */
if (! ta_ok (ta))
return TD_BADTA;
prgregset_t regs;
if (ps_lgetregs (ta->ph, lwpid, regs) != PS_OK)
return TD_ERR;
/* IA-64 thread register is r13. */
th->th_unique = (void *) (((struct pthread *) regs[13]) - 1);
/* Found it. Now complete the `td_thrhandle_t' object. */
th->th_ta_p = (td_thragent_t *) ta;
return TD_OK;
}

View File

@ -113,6 +113,9 @@ register struct pthread *__thread_self __asm__("r13");
/* Return the thread descriptor for the current thread. */ /* Return the thread descriptor for the current thread. */
# define THREAD_SELF (__thread_self - 1) # define THREAD_SELF (__thread_self - 1)
/* Magic for libthread_db to know how to do THREAD_SELF. */
# define DB_THREAD_SELF REGISTER (64, 13 * 8, -sizeof (struct pthread))
/* Access to data in the thread descriptor is easy. */ /* Access to data in the thread descriptor is easy. */
#define THREAD_GETMEM(descr, member) \ #define THREAD_GETMEM(descr, member) \
descr->member descr->member

View File

@ -1,44 +0,0 @@
/* Which thread is running on an LWP? PowerPC version.
Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include "thread_dbP.h"
#include <tls.h>
td_err_e
td_ta_map_lwp2thr (const td_thragent_t *ta, lwpid_t lwpid, td_thrhandle_t *th)
{
LOG ("td_ta_map_lwp2thr");
/* Test whether the TA parameter is ok. */
if (! ta_ok (ta))
return TD_BADTA;
prgregset_t regs;
if (ps_lgetregs (ta->ph, lwpid, regs) != PS_OK)
return TD_ERR;
th->th_unique = ((void *) regs[PT_THREAD_POINTER]
- TLS_TCB_OFFSET - TLS_TCB_SIZE - TLS_PRE_TCB_SIZE);
/* Found it. Now complete the `td_thrhandle_t' object. */
th->th_ta_p = (td_thragent_t *) ta;
return TD_OK;
}

View File

@ -129,6 +129,13 @@ register void *__thread_register __asm__ ("r13");
((struct pthread *) (__thread_register \ ((struct pthread *) (__thread_register \
- TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)) - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE))
/* Magic for libthread_db to know how to do THREAD_SELF. */
# define DB_THREAD_SELF \
REGISTER (32, PT_THREAD_POINTER * 4, \
- TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE) \
REGISTER (64, PT_THREAD_POINTER * 8, \
- TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)
/* Read member of the thread descriptor directly. */ /* Read member of the thread descriptor directly. */
# define THREAD_GETMEM(descr, member) ((void)(descr), (THREAD_SELF)->member) # define THREAD_GETMEM(descr, member) ((void)(descr), (THREAD_SELF)->member)

View File

@ -1,45 +0,0 @@
/* Which thread is running on an LWP? i386 version.
Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include "thread_dbP.h"
#include <tls.h>
td_err_e
td_ta_map_lwp2thr (const td_thragent_t *ta, lwpid_t lwpid, td_thrhandle_t *th)
{
LOG ("td_ta_map_lwp2thr");
/* Test whether the TA parameter is ok. */
if (! ta_ok (ta))
return TD_BADTA;
prgregset_t regs;
if (ps_lgetregs (ta->ph, lwpid, regs) != PS_OK)
return TD_ERR;
/* S390 thread register is ACR0, aka register 18. */
th->th_unique = (void *) regs[18];
/* Found it. Now complete the `td_thrhandle_t' object. */
th->th_ta_p = (td_thragent_t *) ta;
return TD_OK;
}

View File

@ -137,6 +137,9 @@ typedef struct
/* Return the thread descriptor for the current thread. */ /* Return the thread descriptor for the current thread. */
# define THREAD_SELF ((struct pthread *) __builtin_thread_pointer ()) # define THREAD_SELF ((struct pthread *) __builtin_thread_pointer ())
/* Magic for libthread_db to know how to do THREAD_SELF. */
# define DB_THREAD_SELF REGISTER (32, 18 * 4, 0) REGISTER (64, 18 * 8, 0)
/* Access to data in the thread descriptor is easy. */ /* Access to data in the thread descriptor is easy. */
#define THREAD_GETMEM(descr, member) \ #define THREAD_GETMEM(descr, member) \
descr->member descr->member

View File

@ -1,44 +0,0 @@
/* Which thread is running on an LWP? Stub version.
Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include "thread_dbP.h"
#include <tls.h>
#include <sys/reg.h>
td_err_e
td_ta_map_lwp2thr (const td_thragent_t *ta, lwpid_t lwpid, td_thrhandle_t *th)
{
LOG ("td_ta_map_lwp2thr");
/* Test whether the TA parameter is ok. */
if (! ta_ok (ta))
return TD_BADTA;
prgregset_t regs;
if (ps_lgetregs (ta->ph, lwpid, regs) != PS_OK)
return TD_ERR;
th->th_unique = regs[REG_GBR];
/* Found it. Now complete the `td_thrhandle_t' object. */
th->th_ta_p = (td_thragent_t *) ta;
return TD_OK;
}

View File

@ -117,6 +117,9 @@ typedef struct
__asm ("stc gbr,%0" : "=r" (__self)); \ __asm ("stc gbr,%0" : "=r" (__self)); \
__self - 1;}) __self - 1;})
/* Magic for libthread_db to know how to do THREAD_SELF. */
# define DB_THREAD_SELF REGISTER (32, REG_GBR * 4, 0)
/* Read member of the thread descriptor directly. */ /* Read member of the thread descriptor directly. */
# define THREAD_GETMEM(descr, member) (descr->member) # define THREAD_GETMEM(descr, member) (descr->member)

View File

@ -1,44 +0,0 @@
/* Which thread is running on an LWP? SPARC version.
Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include "thread_dbP.h"
#include <tls.h>
td_err_e
td_ta_map_lwp2thr (const td_thragent_t *ta, lwpid_t lwpid, td_thrhandle_t *th)
{
LOG ("td_ta_map_lwp2thr");
/* Test whether the TA parameter is ok. */
if (! ta_ok (ta))
return TD_BADTA;
prgregset_t regs;
if (ps_lgetregs (ta->ph, lwpid, regs) != PS_OK)
return TD_ERR;
/* SPARC thread register is %g7. */
th->th_unique = (void *) regs[7];
/* Found it. Now complete the `td_thrhandle_t' object. */
th->th_ta_p = (td_thragent_t *) ta;
return TD_OK;
}

View File

@ -104,6 +104,11 @@ register struct pthread *__thread_self __asm__("%g7");
/* Return the thread descriptor for the current thread. */ /* Return the thread descriptor for the current thread. */
#define THREAD_SELF __thread_self #define THREAD_SELF __thread_self
/* Magic for libthread_db to know how to do THREAD_SELF. */
# define DB_THREAD_SELF_INCLUDE <sys/ucontext.h>
# define DB_THREAD_SELF \
REGISTER (32, REG_G7 * 4, 0) REGISTER (64, REG_G7 * 8, 0)
/* Access to data in the thread descriptor is easy. */ /* Access to data in the thread descriptor is easy. */
#define THREAD_GETMEM(descr, member) \ #define THREAD_GETMEM(descr, member) \
descr->member descr->member

View File

@ -1,43 +0,0 @@
/* Which thread is running on an LWP? x86-64 version.
Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include "thread_dbP.h"
#include <tls.h>
#include <sys/reg.h>
td_err_e
td_ta_map_lwp2thr (const td_thragent_t *ta, lwpid_t lwpid, td_thrhandle_t *th)
{
LOG ("td_ta_map_lwp2thr");
/* Test whether the TA parameter is ok. */
if (! ta_ok (ta))
return TD_BADTA;
/* Get the %fs segment register base address for the addressed thread. */
if (ps_get_thread_area (ta->ph, lwpid, FS, &th->th_unique) != PS_OK)
return TD_ERR; /* XXX Other error value? */
/* Found it. Now complete the `td_thrhandle_t' object. */
th->th_ta_p = (td_thragent_t *) ta;
return TD_OK;
}

View File

@ -161,6 +161,9 @@ typedef struct
: "i" (offsetof (struct pthread, header.self))); \ : "i" (offsetof (struct pthread, header.self))); \
__self;}) __self;})
/* Magic for libthread_db to know how to do THREAD_SELF. */
# define DB_THREAD_SELF_INCLUDE <sys/reg.h> /* For the FS constant. */
# define DB_THREAD_SELF CONST_THREAD_AREA (64, FS)
/* Read member of the thread descriptor directly. */ /* Read member of the thread descriptor directly. */
# define THREAD_GETMEM(descr, member) \ # define THREAD_GETMEM(descr, member) \

View File

@ -1,3 +1,64 @@
2003-09-08 Roland McGrath <roland@redhat.com>
* td_thr_get_info.c (td_thr_get_info): Cast th_unique to thread_t.
2003-08-22 Roland McGrath <roland@redhat.com>
* fetch-value.c (_td_check_sizeof, _td_locate_field): Return
TD_NOCAPAB for PS_NOSYM, instead of vanilla TD_ERR.
* td_thr_tls_get_addr.c (td_thr_tls_get_addr): Return TD_NOAPLIC when
DB_GET_FIELD returns TD_NOCAPAB.
* thread_db.h (td_thr_tls_get_addr): Use psaddr_t in signature.
* structs.def [USE_TLS]: Add DB_STRUCT_FIELD (link_map, l_tls_modid).
* db_info.c (link_map): Typedef it.
* td_thr_tls_get_addr.c (td_thr_tls_get_addr): Rewritten.
2003-08-14 Roland McGrath <roland@redhat.com>
* thread_dbP.h: Mostly rewritten with many new macros and decls.
* td_ta_new.c (td_ta_new): Don't cache a lot of symbol values.
* structs.def: New file.
* db_info.c: New file.
* td_symbol_list.c (symbol_list_arr): Define with structs.def macros.
* td_ta_clear_event.c: Rewritten.
* td_ta_event_addr.c: Rewritten.
* td_ta_event_getmsg.c: Rewritten.
* td_ta_get_nthreads.c: Rewritten.
* td_ta_map_lwp2thr.c: New file.
* td_ta_set_event.c: Rewritten.
* td_ta_thr_iter.c: Rewritten.
* td_ta_tsd_iter.c: Rewritten.
* td_thr_clear_event.c: Rewritten.
* td_thr_event_enable.c: Rewritten.
* td_thr_event_getmsg.c: Rewritten.
* td_thr_get_info.c: Rewritten.
* td_thr_getfpregs.c: Rewritten.
* td_thr_getgregs.c: Rewritten.
* td_thr_set_event.c: Rewritten.
* td_thr_setfpregs.c: Rewritten.
* td_thr_setgregs.c: Rewritten.
* td_thr_tlsbase.c: Rewritten.
* td_thr_tsd.c: Rewritten.
* td_thr_validate.c: Rewritten.
* Makefile (distribute): Add them.
* fetch-value.c: New file.
* Makefile (libthread_db-routines): Add it.
* thread_db.h (td_err_e): Comment fix.
2003-08-05 Roland McGrath <roland@redhat.com>
* thread_dbP.h (td_lookup): Add attribute_hidden to decl.
2003-08-04 Roland McGrath <roland@redhat.com>
* td_ta_clear_event.c (td_ta_clear_event): Fix sizes in ps_* calls.
2003-06-23 Roland McGrath <roland@redhat.com>
* proc_service.h: Cosmetic and comment fixes.
2003-06-19 Roland McGrath <roland@redhat.com> 2003-06-19 Roland McGrath <roland@redhat.com>
* td_thr_event_enable.c (td_thr_event_enable): Use proper type `bool' * td_thr_event_enable.c (td_thr_event_enable): Use proper type `bool'

View File

@ -42,14 +42,15 @@ libthread_db-routines = td_init td_log td_ta_new td_ta_delete \
td_thr_clear_event td_thr_event_getmsg \ td_thr_clear_event td_thr_event_getmsg \
td_ta_set_event td_ta_event_getmsg \ td_ta_set_event td_ta_event_getmsg \
td_ta_clear_event td_symbol_list \ td_ta_clear_event td_symbol_list \
td_thr_tlsbase td_thr_tls_get_addr td_thr_tlsbase td_thr_tls_get_addr \
fetch-value
libthread_db-inhibit-o = $(filter-out .os,$(object-suffixes)) libthread_db-inhibit-o = $(filter-out .os,$(object-suffixes))
# The ps_* callback functions are not defined. # The ps_* callback functions are not defined.
libthread_db.so-no-z-defs = yes libthread_db.so-no-z-defs = yes
distribute = thread_dbP.h shlib-versions proc_service.h distribute = thread_dbP.h shlib-versions proc_service.h db_info.c structs.def
include ../Rules include ../Rules
# Depend on libc.so so a DT_NEEDED is generated in the shared objects. # Depend on libc.so so a DT_NEEDED is generated in the shared objects.

98
nptl_db/db_info.c Normal file
View File

@ -0,0 +1,98 @@
/* This file is included by pthread_create.c to define in libpthread
all the magic symbols required by libthread_db.
Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include "thread_dbP.h"
#include <tls.h>
typedef struct pthread pthread;
typedef struct pthread_key_struct pthread_key_struct;
typedef struct pthread_key_data pthread_key_data;
typedef struct
{
struct pthread_key_data data[PTHREAD_KEY_2NDLEVEL_SIZE];
}
pthread_key_data_level2;
typedef struct
{
union dtv dtv[UINT32_MAX / 2 / sizeof (union dtv)]; /* No constant bound. */
} dtv;
typedef struct link_map link_map;
#define schedparam_sched_priority schedparam.sched_priority
#define eventbuf_eventmask eventbuf.eventmask
#define eventbuf_eventmask_event_bits eventbuf.eventmask.event_bits
#define DESC(name, offset, obj) \
DB_DEFINE_DESC (name, 8 * sizeof (obj), 1, offset);
#define ARRAY_DESC(name, offset, obj) \
DB_DEFINE_DESC (name, \
8 * sizeof (obj)[0], sizeof (obj) / sizeof (obj)[0], \
offset);
#if TLS_TCB_AT_TP
# define dtvp header.dtv
#elif TLS_DTV_AT_TP
/* Special case hack. */
DESC (_thread_db_pthread_dtvp,
TLS_PRE_TCB_SIZE + offsetof (tcbhead_t, dtv), union dtv)
#endif
#define DB_STRUCT(type) \
const uint32_t _thread_db_sizeof_##type = sizeof (type);
#define DB_STRUCT_FIELD(type, field) \
DESC (_thread_db_##type##_##field, \
offsetof (type, field), ((type *) 0)->field)
#define DB_STRUCT_ARRAY_FIELD(type, field) \
ARRAY_DESC (_thread_db_##type##_##field, \
offsetof (type, field), ((type *) 0)->field)
#define DB_VARIABLE(name) DESC (_thread_db_##name, 0, name)
#define DB_ARRAY_VARIABLE(name) ARRAY_DESC (_thread_db_##name, 0, name)
#define DB_SYMBOL(name) /* Nothing. */
#include "structs.def"
#undef DB_STRUCT
#undef DB_STRUCT_FIELD
#undef DB_SYMBOL
#undef DB_VARIABLE
#undef DESC
#ifdef DB_THREAD_SELF
# ifdef DB_THREAD_SELF_INCLUDE
# include DB_THREAD_SELF_INCLUDE
# endif
/* This macro is defined in the machine's tls.h using the three below. */
# define CONST_THREAD_AREA(bits, value) \
const uint32_t _thread_db_const_thread_area = (value);
# define REGISTER_THREAD_AREA(bits, regofs, scale) \
DB_DEFINE_DESC (_thread_db_register##bits##_thread_area, \
bits, (scale), (regofs));
# define REGISTER(bits, regofs, bias) \
DB_DEFINE_DESC (_thread_db_register##bits, bits, (uint32_t)(bias), (regofs));
DB_THREAD_SELF
#endif

283
nptl_db/fetch-value.c Normal file
View File

@ -0,0 +1,283 @@
/* Helper routines for libthread_db.
Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include "thread_dbP.h"
#include <byteswap.h>
#include <assert.h>
td_err_e
_td_check_sizeof (td_thragent_t *ta, uint32_t *sizep, int sizep_name)
{
if (*sizep == 0)
{
psaddr_t descptr;
ps_err_e err = td_lookup (ta->ph, sizep_name, &descptr);
if (err == PS_NOSYM)
return TD_NOCAPAB;
if (err == PS_OK)
err = ps_pdread (ta->ph, descptr, sizep, sizeof *sizep);
if (err != PS_OK)
return TD_ERR;
if (*sizep & 0xff000000U)
*sizep = bswap_32 (*sizep);
}
return TD_OK;
}
td_err_e
_td_locate_field (td_thragent_t *ta,
db_desc_t desc, int descriptor_name,
psaddr_t idx, psaddr_t *address)
{
uint32_t elemsize;
if (DB_DESC_SIZE (desc) == 0)
{
/* Read the information about this field from the inferior. */
psaddr_t descptr;
ps_err_e err = td_lookup (ta->ph, descriptor_name, &descptr);
if (err == PS_NOSYM)
return TD_NOCAPAB;
if (err == PS_OK)
err = ps_pdread (ta->ph, descptr, desc, DB_SIZEOF_DESC);
if (err != PS_OK)
return TD_ERR;
if (DB_DESC_SIZE (desc) == 0)
return TD_DBERR;
if (DB_DESC_SIZE (desc) & 0xff000000U)
{
/* Byte-swap these words, though we leave the size word
in native order as the handy way to distinguish. */
DB_DESC_OFFSET (desc) = bswap_32 (DB_DESC_OFFSET (desc));
DB_DESC_NELEM (desc) = bswap_32 (DB_DESC_NELEM (desc));
}
}
if (idx != 0 && idx - (psaddr_t) 0 > DB_DESC_NELEM (desc))
/* This is an internal indicator to callers with nonzero IDX
that the IDX value is too big. */
return TD_NOAPLIC;
elemsize = DB_DESC_SIZE (desc);
if (elemsize & 0xff000000U)
elemsize = bswap_32 (elemsize);
*address += DB_DESC_OFFSET (desc) + (elemsize / 8 * (idx - (psaddr_t) 0));
return TD_OK;
}
td_err_e
_td_fetch_value (td_thragent_t *ta,
db_desc_t desc, int descriptor_name,
psaddr_t idx, psaddr_t address,
psaddr_t *result)
{
ps_err_e err;
td_err_e terr = _td_locate_field (ta, desc, descriptor_name, idx, &address);
if (terr != TD_OK)
return terr;
if (DB_DESC_SIZE (desc) == 8 || DB_DESC_SIZE (desc) == bswap_32 (8))
{
uint8_t value;
err = ps_pdread (ta->ph, address, &value, sizeof value);
*result = (psaddr_t) 0 + value;
}
else if (DB_DESC_SIZE (desc) == 32)
{
uint32_t value;
err = ps_pdread (ta->ph, address, &value, sizeof value);
*result = (psaddr_t) 0 + value;
}
else if (DB_DESC_SIZE (desc) == 64)
{
uint64_t value;
if (sizeof (psaddr_t) < 8)
return TD_NOCAPAB;
err = ps_pdread (ta->ph, address, &value, sizeof value);
*result = (psaddr_t) 0 + value;
}
else if (DB_DESC_SIZE (desc) == bswap_32 (32))
{
uint32_t value;
err = ps_pdread (ta->ph, address, &value, sizeof value);
value = bswap_32 (value);
*result = (psaddr_t) 0 + value;
}
else if (DB_DESC_SIZE (desc) == bswap_32 (64))
{
uint64_t value;
if (sizeof (psaddr_t) < 8)
return TD_NOCAPAB;
err = ps_pdread (ta->ph, address, &value, sizeof value);
value = bswap_64 (value);
*result = (psaddr_t) 0 + value;
}
else
return TD_DBERR;
return err == PS_OK ? TD_OK : TD_ERR;
}
td_err_e
_td_store_value (td_thragent_t *ta,
uint32_t desc[2], int descriptor_name, psaddr_t idx,
psaddr_t address, psaddr_t widened_value)
{
ps_err_e err;
td_err_e terr = _td_locate_field (ta, desc, descriptor_name, idx, &address);
if (terr != TD_OK)
return terr;
if (DB_DESC_SIZE (desc) == 8 || DB_DESC_SIZE (desc) == bswap_32 (8))
{
uint8_t value = widened_value - (psaddr_t) 0;
err = ps_pdwrite (ta->ph, address, &value, sizeof value);
}
else if (DB_DESC_SIZE (desc) == 32)
{
uint32_t value = widened_value - (psaddr_t) 0;
err = ps_pdwrite (ta->ph, address, &value, sizeof value);
}
else if (DB_DESC_SIZE (desc) == 64)
{
uint64_t value = widened_value - (psaddr_t) 0;
if (sizeof (psaddr_t) < 8)
return TD_NOCAPAB;
err = ps_pdwrite (ta->ph, address, &value, sizeof value);
}
else if (DB_DESC_SIZE (desc) == bswap_32 (32))
{
uint32_t value = widened_value - (psaddr_t) 0;
value = bswap_32 (value);
err = ps_pdwrite (ta->ph, address, &value, sizeof value);
}
else if (DB_DESC_SIZE (desc) == bswap_32 (64))
{
uint64_t value = widened_value - (psaddr_t) 0;
if (sizeof (psaddr_t) < 8)
return TD_NOCAPAB;
value = bswap_64 (value);
err = ps_pdwrite (ta->ph, address, &value, sizeof value);
}
else
return TD_DBERR;
return err == PS_OK ? TD_OK : TD_ERR;
}
td_err_e
_td_fetch_value_local (td_thragent_t *ta,
db_desc_t desc, int descriptor_name, psaddr_t idx,
void *address,
psaddr_t *result)
{
td_err_e terr = _td_locate_field (ta, desc, descriptor_name, idx, &address);
if (terr != TD_OK)
return terr;
if (DB_DESC_SIZE (desc) == 8 || DB_DESC_SIZE (desc) == bswap_32 (8))
{
uint8_t value;
memcpy (&value, address, sizeof value);
*result = (psaddr_t) 0 + value;
}
else if (DB_DESC_SIZE (desc) == 32)
{
uint32_t value;
memcpy (&value, address, sizeof value);
*result = (psaddr_t) 0 + value;
}
else if (DB_DESC_SIZE (desc) == 64)
{
uint64_t value;
if (sizeof (psaddr_t) < 8)
return TD_NOCAPAB;
memcpy (&value, address, sizeof value);
*result = (psaddr_t) 0 + value;
}
else if (DB_DESC_SIZE (desc) == bswap_32 (32))
{
uint32_t value;
memcpy (&value, address, sizeof value);
value = bswap_32 (value);
*result = (psaddr_t) 0 + value;
}
else if (DB_DESC_SIZE (desc) == bswap_32 (64))
{
uint64_t value;
if (sizeof (psaddr_t) < 8)
return TD_NOCAPAB;
memcpy (&value, address, sizeof value);
value = bswap_64 (value);
*result = (psaddr_t) 0 + value;
}
else
return TD_DBERR;
return TD_OK;
}
td_err_e
_td_store_value_local (td_thragent_t *ta,
uint32_t desc[2], int descriptor_name, psaddr_t idx,
void *address, psaddr_t widened_value)
{
td_err_e terr = _td_locate_field (ta, desc, descriptor_name, idx, &address);
if (terr != TD_OK)
return terr;
if (DB_DESC_SIZE (desc) == 8 || DB_DESC_SIZE (desc) == bswap_32 (8))
{
uint8_t value = widened_value - (psaddr_t) 0;
memcpy (address, &value, sizeof value);
}
else if (DB_DESC_SIZE (desc) == 32)
{
uint32_t value = widened_value - (psaddr_t) 0;
memcpy (address, &value, sizeof value);
}
else if (DB_DESC_SIZE (desc) == 64)
{
uint64_t value = widened_value - (psaddr_t) 0;
if (sizeof (psaddr_t) < 8)
return TD_NOCAPAB;
memcpy (address, &value, sizeof value);
}
else if (DB_DESC_SIZE (desc) == bswap_32 (32))
{
uint32_t value = widened_value - (psaddr_t) 0;
value = bswap_32 (value);
memcpy (address, &value, sizeof value);
}
else if (DB_DESC_SIZE (desc) == bswap_32 (64))
{
uint64_t value = widened_value - (psaddr_t) 0;
if (sizeof (psaddr_t) < 8)
return TD_NOCAPAB;
value = bswap_64 (value);
memcpy (address, &value, sizeof value);
}
else
return TD_DBERR;
return TD_OK;
}

View File

@ -1,4 +1,5 @@
/* Copyright (C) 1999, 2002 Free Software Foundation, Inc. /* Callback interface for libthread_db, functions users must define.
Copyright (C) 1999,2002,2003 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or The GNU C Library is free software; you can redistribute it and/or
@ -19,55 +20,68 @@
/* The definitions in this file must correspond to those in the debugger. */ /* The definitions in this file must correspond to those in the debugger. */
#include <sys/procfs.h> #include <sys/procfs.h>
/* Functions in this interface return one of these status codes. */
typedef enum typedef enum
{ {
PS_OK, /* generic "call succeeded" */ PS_OK, /* Generic "call succeeded". */
PS_ERR, /* generic. */ PS_ERR, /* Generic error. */
PS_BADPID, /* bad process handle */ PS_BADPID, /* Bad process handle. */
PS_BADLID, /* bad lwp identifier */ PS_BADLID, /* Bad LWP identifier. */
PS_BADADDR, /* bad address */ PS_BADADDR, /* Bad address. */
PS_NOSYM, /* p_lookup() could not find given symbol */ PS_NOSYM, /* Could not find given symbol. */
PS_NOFREGS PS_NOFREGS /* FPU register set not available for given LWP. */
/* } ps_err_e;
* FPU register set not available for given
* lwp
*/
} ps_err_e;
struct ps_prochandle; /* user defined. */ /* This type is opaque in this interface.
It's defined by the user of libthread_db. */
struct ps_prochandle;
extern ps_err_e ps_pdread(struct ps_prochandle *, /* Read or write process memory at the given address. */
psaddr_t, void *, size_t); extern ps_err_e ps_pdread (struct ps_prochandle *,
extern ps_err_e ps_pdwrite(struct ps_prochandle *, psaddr_t, void *, size_t);
psaddr_t, const void *, size_t); extern ps_err_e ps_pdwrite (struct ps_prochandle *,
extern ps_err_e ps_ptread(struct ps_prochandle *, psaddr_t, const void *, size_t);
psaddr_t, void *, size_t); extern ps_err_e ps_ptread (struct ps_prochandle *,
extern ps_err_e ps_ptwrite(struct ps_prochandle *, psaddr_t, void *, size_t);
psaddr_t, const void *, size_t); extern ps_err_e ps_ptwrite (struct ps_prochandle *,
psaddr_t, const void *, size_t);
extern ps_err_e ps_pglobal_lookup(struct ps_prochandle *,
const char *object_name, const char *sym_name, psaddr_t *sym_addr);
extern ps_err_e ps_lgetregs(struct ps_prochandle *, /* Get and set the given LWP's general or FPU register set. */
lwpid_t, prgregset_t); extern ps_err_e ps_lgetregs (struct ps_prochandle *,
extern ps_err_e ps_lsetregs(struct ps_prochandle *, lwpid_t, prgregset_t);
lwpid_t, const prgregset_t); extern ps_err_e ps_lsetregs (struct ps_prochandle *,
extern ps_err_e ps_lgetfpregs(struct ps_prochandle *, lwpid_t, const prgregset_t);
lwpid_t, prfpregset_t *); extern ps_err_e ps_lgetfpregs (struct ps_prochandle *,
extern ps_err_e ps_lsetfpregs(struct ps_prochandle *, lwpid_t, prfpregset_t *);
lwpid_t, const prfpregset_t *); extern ps_err_e ps_lsetfpregs (struct ps_prochandle *,
lwpid_t, const prfpregset_t *);
/* Return the PID of the process. */
extern pid_t ps_getpid (struct ps_prochandle *); extern pid_t ps_getpid (struct ps_prochandle *);
/* Fetch the special per-thread address associated with the given LWP.
This call is only used on a few platforms (most use a normal register).
The meaning of the `int' parameter is machine-dependent. */
extern ps_err_e ps_get_thread_area (const struct ps_prochandle *,
lwpid_t, int, psaddr_t *);
/* Look up the named symbol in the named DSO in the symbol tables
associated with the process being debugged, filling in *SYM_ADDR
with the corresponding run-time address. */
extern ps_err_e ps_pglobal_lookup (struct ps_prochandle *,
const char *object_name,
const char *sym_name,
psaddr_t *sym_addr);
/* Stop or continue the entire process. */
extern ps_err_e ps_pstop (const struct ps_prochandle *); extern ps_err_e ps_pstop (const struct ps_prochandle *);
extern ps_err_e ps_pcontinue (const struct ps_prochandle *); extern ps_err_e ps_pcontinue (const struct ps_prochandle *);
/* Stop or continue the given LWP alone. */
extern ps_err_e ps_lstop (const struct ps_prochandle *, lwpid_t); extern ps_err_e ps_lstop (const struct ps_prochandle *, lwpid_t);
extern ps_err_e ps_lcontinue (const struct ps_prochandle *, lwpid_t); extern ps_err_e ps_lcontinue (const struct ps_prochandle *, lwpid_t);
extern ps_err_e ps_get_thread_area (const struct ps_prochandle *, lwpid_t,
int, psaddr_t *);

86
nptl_db/structs.def Normal file
View File

@ -0,0 +1,86 @@
/* List of types and symbols in libpthread examined by libthread_db.
Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#ifndef DB_STRUCT_ARRAY_FIELD
# define DB_STRUCT_ARRAY_FIELD(type, field) DB_STRUCT_FIELD (type, field)
# define DB_ARRAY_VARIABLE(name) DB_VARIABLE (name)
# define STRUCTS_DEF_DEFAULTS 1
#endif
DB_STRUCT (pthread)
DB_STRUCT_FIELD (pthread, list)
DB_STRUCT_FIELD (pthread, report_events)
DB_STRUCT_FIELD (pthread, tid)
DB_STRUCT_FIELD (pthread, start_routine)
DB_STRUCT_FIELD (pthread, cancelhandling)
DB_STRUCT_FIELD (pthread, schedpolicy)
DB_STRUCT_FIELD (pthread, schedparam_sched_priority)
DB_STRUCT_FIELD (pthread, specific)
DB_STRUCT_FIELD (pthread, eventbuf)
DB_STRUCT_FIELD (pthread, eventbuf_eventmask)
DB_STRUCT_ARRAY_FIELD (pthread, eventbuf_eventmask_event_bits)
DB_STRUCT_FIELD (pthread, nextevent)
DB_STRUCT (list_t)
DB_STRUCT_FIELD (list_t, next)
DB_STRUCT_FIELD (list_t, prev)
DB_STRUCT (td_thr_events_t)
DB_STRUCT_ARRAY_FIELD (td_thr_events_t, event_bits)
DB_STRUCT (td_eventbuf_t)
DB_STRUCT_FIELD (td_eventbuf_t, eventnum)
DB_STRUCT_FIELD (td_eventbuf_t, eventdata)
DB_SYMBOL (stack_used)
DB_SYMBOL (__stack_user)
DB_SYMBOL (nptl_version)
DB_SYMBOL (__nptl_create_event)
DB_SYMBOL (__nptl_death_event)
DB_SYMBOL (__nptl_threads_events)
DB_VARIABLE (__nptl_nthreads)
DB_VARIABLE (__nptl_last_event)
DB_ARRAY_VARIABLE (__pthread_keys)
DB_STRUCT (pthread_key_struct)
DB_STRUCT_FIELD (pthread_key_struct, seq)
DB_STRUCT_FIELD (pthread_key_struct, destr)
DB_STRUCT (pthread_key_data)
DB_STRUCT_FIELD (pthread_key_data, seq)
DB_STRUCT_FIELD (pthread_key_data, data)
DB_STRUCT (pthread_key_data_level2)
DB_STRUCT_ARRAY_FIELD (pthread_key_data_level2, data)
#if USE_TLS
DB_STRUCT_FIELD (link_map, l_tls_modid)
#endif
#if !defined IS_IN_libpthread || USE_TLS
DB_STRUCT_ARRAY_FIELD (dtv, dtv)
#endif
#if !defined IS_IN_libpthread || TLS_TCB_AT_TP
DB_STRUCT_FIELD (pthread, dtvp)
#endif
#ifdef STRUCTS_DEF_DEFAULTS
# undef DB_STRUCT_ARRAY_FIELD
# undef DB_ARRAY_VARIABLE
# undef STRUCTS_DEF_DEFAULTS
#endif

View File

@ -25,17 +25,26 @@
static const char *symbol_list_arr[] = static const char *symbol_list_arr[] =
{ {
[SYM_PTHREAD_THREADS_EVENTS] = "__nptl_threads_events", # define DB_STRUCT(type) \
[SYM_PTHREAD_LAST_EVENT] = "__nptl_last_event", [SYM_SIZEOF_##type] = "_thread_db_sizeof_" #type,
[SYM_PTHREAD_NTHREADS] = "__nptl_nthreads", # define DB_STRUCT_FIELD(type, field) \
[SYM_PTHREAD_STACK_USED] = "stack_used", [SYM_##type##_FIELD_##field] = "_thread_db_" #type "_" #field,
[SYM_PTHREAD_STACK_USER] = "__stack_user", # define DB_SYMBOL(name) \
[SYM_PTHREAD_KEYS] = "__pthread_keys", [SYM_##name] = #name,
[SYM_PTHREAD_KEYS_MAX] = "__pthread_pthread_keys_max", # define DB_VARIABLE(name) \
[SYM_PTHREAD_SIZEOF_DESCR] = "__pthread_pthread_sizeof_descr", [SYM_##name] = #name, \
[SYM_PTHREAD_CREATE_EVENT] = "__nptl_create_event", [SYM_DESC_##name] = "_thread_db_" #name,
[SYM_PTHREAD_DEATH_EVENT] = "__nptl_death_event", # include "structs.def"
[SYM_PTHREAD_VERSION] = "nptl_version", # undef DB_STRUCT
# undef DB_SYMBOL
# undef DB_VARIABLE
[SYM_TH_UNIQUE_CONST_THREAD_AREA] = "_thread_db_const_thread_area",
[SYM_TH_UNIQUE_REGISTER64] = "_thread_db_register64",
[SYM_TH_UNIQUE_REGISTER32] = "_thread_db_register32",
[SYM_TH_UNIQUE_REGISTER32_THREAD_AREA] = "_thread_db_register32_thread_area",
[SYM_TH_UNIQUE_REGISTER64_THREAD_AREA] = "_thread_db_register64_thread_area",
[SYM_NUM_MESSAGES] = NULL [SYM_NUM_MESSAGES] = NULL
}; };
@ -47,7 +56,7 @@ td_symbol_list (void)
} }
int ps_err_e
td_lookup (struct ps_prochandle *ps, int idx, psaddr_t *sym_addr) td_lookup (struct ps_prochandle *ps, int idx, psaddr_t *sym_addr)
{ {
assert (idx >= 0 && idx < SYM_NUM_MESSAGES); assert (idx >= 0 && idx < SYM_NUM_MESSAGES);

View File

@ -1,5 +1,5 @@
/* Globally disable events. /* Globally disable events.
Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
@ -22,31 +22,58 @@
td_err_e td_err_e
td_ta_clear_event (ta, event) td_ta_clear_event (ta_arg, event)
const td_thragent_t *ta; const td_thragent_t *ta_arg;
td_thr_events_t *event; td_thr_events_t *event;
{ {
td_thragent_t *const ta = (td_thragent_t *) ta_arg;
td_err_e err;
psaddr_t eventmask;
void *copy;
LOG ("td_ta_clear_event"); LOG ("td_ta_clear_event");
/* Test whether the TA parameter is ok. */ /* Test whether the TA parameter is ok. */
if (! ta_ok (ta)) if (! ta_ok (ta))
return TD_BADTA; return TD_BADTA;
/* Write the new value into the thread data structure. */ /* Fetch the old event mask from the inferior and modify it in place. */
td_thr_events_t old_event; err = DB_GET_SYMBOL (eventmask, ta, __nptl_threads_events);
if (ps_pdread (ta->ph, ta->pthread_threads_eventsp, if (err == TD_OK)
&old_event, sizeof (td_thrhandle_t)) != PS_OK) err = DB_GET_STRUCT (copy, ta, eventmask, td_thr_events_t);
return TD_ERR; /* XXX Other error value? */ if (err == TD_OK)
{
uint32_t idx;
for (idx = 0; idx < TD_EVENTSIZE; ++idx)
{
psaddr_t word;
uint32_t mask;
err = DB_GET_FIELD_LOCAL (word, ta, copy,
td_thr_events_t, event_bits, idx);
if (err != TD_OK)
break;
mask = (uintptr_t) word;
mask &= ~event->event_bits[idx];
word = (psaddr_t) (uintptr_t) mask;
err = DB_PUT_FIELD_LOCAL (ta, copy,
td_thr_events_t, event_bits, idx, word);
if (err != TD_OK)
break;
}
if (err == TD_NOAPLIC)
{
err = TD_OK;
while (idx < TD_EVENTSIZE)
if (event->event_bits[idx++] != 0)
{
err = TD_NOEVENT;
break;
}
}
if (err == TD_OK)
/* Now write it back to the inferior. */
err = DB_PUT_STRUCT (ta, eventmask, td_thr_events_t, copy);
}
/* Remove the set bits in. */ return err;
int i;
for (i = 0; i < TD_EVENTSIZE; ++i)
old_event.event_bits[i] &= ~event->event_bits[i];
/* Write the new value into the thread data structure. */
if (ps_pdwrite (ta->ph, ta->pthread_threads_eventsp,
&old_event, sizeof (td_thrhandle_t)) != PS_OK)
return TD_ERR; /* XXX Other error value? */
return TD_OK;
} }

View File

@ -1,5 +1,5 @@
/* Get event address. /* Get event address.
Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
@ -22,10 +22,12 @@
td_err_e td_err_e
td_ta_event_addr (const td_thragent_t *ta, td_event_e event, td_notify_t *addr) td_ta_event_addr (const td_thragent_t *ta_arg,
td_event_e event, td_notify_t *addr)
{ {
td_err_e res = TD_NOEVENT; td_thragent_t *const ta = (td_thragent_t *) ta_arg;
int idx = -1; td_err_e err;
psaddr_t taddr;
LOG ("td_ta_event_addr"); LOG ("td_ta_event_addr");
@ -36,34 +38,24 @@ td_ta_event_addr (const td_thragent_t *ta, td_event_e event, td_notify_t *addr)
switch (event) switch (event)
{ {
case TD_CREATE: case TD_CREATE:
idx = SYM_PTHREAD_CREATE_EVENT; err = DB_GET_SYMBOL (taddr, ta, __nptl_create_event);
break; break;
case TD_DEATH: case TD_DEATH:
idx = SYM_PTHREAD_DEATH_EVENT; err = DB_GET_SYMBOL (taddr, ta, __nptl_death_event);
break; break;
default: default:
/* Event cannot be handled. */ /* Event cannot be handled. */
break; return TD_NOEVENT;
} }
/* Now get the address. */ if (err == TD_OK)
if (idx != -1)
{ {
psaddr_t taddr; /* Success, we got the address. */
addr->type = NOTIFY_BPT;
if (td_lookup (ta->ph, idx, &taddr) == PS_OK) addr->u.bptaddr = taddr;
{
/* Success, we got the address. */
addr->type = NOTIFY_BPT;
addr->u.bptaddr = taddr;
res = TD_OK;
}
else
res = TD_ERR;
} }
return res; return err;
} }

View File

@ -25,76 +25,81 @@
td_err_e td_err_e
td_ta_event_getmsg (const td_thragent_t *ta, td_event_msg_t *msg) td_ta_event_getmsg (const td_thragent_t *ta_arg, td_event_msg_t *msg)
{ {
td_thragent_t *const ta = (td_thragent_t *) ta_arg;
td_err_e err;
psaddr_t eventbuf, eventnum, eventdata;
psaddr_t thp, next;
void *copy;
/* XXX I cannot think of another way but using a static variable. */ /* XXX I cannot think of another way but using a static variable. */
/* XXX Use at least __thread once it is possible. */ /* XXX Use at least __thread once it is possible. */
static td_thrhandle_t th; static td_thrhandle_t th;
LOG ("td_ta_event_getmsg"); LOG ("td_thr_event_getmsg");
/* Test whether the TA parameter is ok. */ /* Test whether the TA parameter is ok. */
if (! ta_ok (ta)) if (! ta_ok (ta))
return TD_BADTA; return TD_BADTA;
/* Get the pointer to the thread descriptor with the last event. */ /* Get the pointer to the thread descriptor with the last event. */
psaddr_t addr; err = DB_GET_VALUE (thp, ta, __nptl_last_event, 0);
if (ps_pdread (ta->ph, ta->pthread_last_event, if (err != TD_OK)
&addr, sizeof (struct pthread *)) != PS_OK) return err;
return TD_ERR; /* XXX Other error value? */
if (addr == 0) if (thp == 0)
/* Nothing waiting. */ /* Nothing waiting. */
return TD_NOMSG; return TD_NOMSG;
/* Read the event structure from the target. */ /* Copy the event message buffer in from the inferior. */
td_eventbuf_t event; err = DB_GET_FIELD_ADDRESS (eventbuf, ta, thp, pthread, eventbuf, 0);
if (ps_pdread (ta->ph, (char *) addr + offsetof (struct pthread, eventbuf), if (err == TD_OK)
&event, sizeof (td_eventbuf_t)) != PS_OK) err = DB_GET_STRUCT (copy, ta, eventbuf, td_eventbuf_t);
return TD_ERR; /* XXX Other error value? */ if (err != TD_OK)
return err;
/* Read the event details from the target thread. */
err = DB_GET_FIELD_LOCAL (eventnum, ta, copy, td_eventbuf_t, eventnum, 0);
if (err != TD_OK)
return err;
/* If the structure is on the list there better be an event recorded. */ /* If the structure is on the list there better be an event recorded. */
if (event.eventnum == TD_EVENT_NONE) if ((int) (uintptr_t) eventnum == TD_EVENT_NONE)
return TD_DBERR; return TD_DBERR;
/* Fill the user's data structure. */
err = DB_GET_FIELD_LOCAL (eventdata, ta, copy, td_eventbuf_t, eventdata, 0);
if (err != TD_OK)
return err;
/* Generate the thread descriptor. */ /* Generate the thread descriptor. */
th.th_ta_p = (td_thragent_t *) ta; th.th_ta_p = (td_thragent_t *) ta;
th.th_unique = addr; th.th_unique = thp;
/* Fill the user's data structure. */ /* Fill the user's data structure. */
msg->event = event.eventnum; msg->msg.data = (uintptr_t) eventdata;
msg->event = (uintptr_t) eventnum;
msg->th_p = &th; msg->th_p = &th;
msg->msg.data = (uintptr_t) event.eventdata;
/* And clear the event message in the target. */ /* And clear the event message in the target. */
memset (&event, '\0', sizeof (td_eventbuf_t)); memset (copy, 0, ta->ta_sizeof_td_eventbuf_t);
if (ps_pdwrite (ta->ph, (char *) addr + offsetof (struct pthread, eventbuf), err = DB_PUT_STRUCT (ta, eventbuf, td_eventbuf_t, copy);
&event, sizeof (td_eventbuf_t)) != PS_OK) if (err != TD_OK)
return TD_ERR; /* XXX Other error value? */ return err;
/* Get the pointer to the next descriptor with an event. */ /* Get the pointer to the next descriptor with an event. */
psaddr_t next; err = DB_GET_FIELD (next, ta, thp, pthread, nextevent, 0);
if (ps_pdread (ta->ph, (char *) addr + offsetof (struct pthread, nextevent), if (err != TD_OK)
&next, sizeof (struct pthread *)) != PS_OK) return err;
return TD_ERR; /* XXX Other error value? */
if (next == addr)
return TD_DBERR;
/* Store the pointer in the list head variable. */ /* Store the pointer in the list head variable. */
if (ps_pdwrite (ta->ph, ta->pthread_last_event, err = DB_PUT_VALUE (ta, __nptl_last_event, 0, next);
&next, sizeof (struct pthread *)) != PS_OK) if (err != TD_OK)
return TD_ERR; /* XXX Other error value? */ return err;
if (next != NULL) if (next != 0)
{ /* Clear the next pointer in the current descriptor. */
/* Clear the next pointer in the current descriptor. */ err = DB_PUT_FIELD (ta, thp, pthread, nextevent, 0, 0);
next = NULL;
if (ps_pdwrite (ta->ph,
(char *) addr + offsetof (struct pthread, nextevent),
&next, sizeof (struct pthread *)) != PS_OK)
return TD_ERR; /* XXX Other error value? */
}
return TD_OK; return err;
} }

View File

@ -1,5 +1,5 @@
/* Get the number of threads in the process. /* Get the number of threads in the process.
Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
@ -21,21 +21,22 @@
#include "thread_dbP.h" #include "thread_dbP.h"
td_err_e td_err_e
td_ta_get_nthreads (const td_thragent_t *ta, int *np) td_ta_get_nthreads (const td_thragent_t *ta_arg, int *np)
{ {
td_thragent_t *const ta = (td_thragent_t *) ta_arg;
td_err_e err;
psaddr_t n;
LOG ("td_ta_get_nthreads"); LOG ("td_ta_get_nthreads");
/* Test whether the TA parameter is ok. */ /* Test whether the TA parameter is ok. */
if (! ta_ok (ta)) if (! ta_ok (ta))
return TD_BADTA; return TD_BADTA;
/* Access the variable `__pthread_handles_num'. */ /* Access the variable in the inferior that tells us. */
psaddr_t addr; err = DB_GET_VALUE (n, ta, __nptl_nthreads, 0);
if (td_lookup (ta->ph, SYM_PTHREAD_NTHREADS, &addr) != PS_OK) if (err == TD_OK)
return TD_ERR; /* XXX Other error value? */ *np = (uintptr_t) n;
if (ps_pdread (ta->ph, addr, np, sizeof (int)) != PS_OK) return err;
return TD_ERR; /* XXX Other error value? */
return TD_OK;
} }

179
nptl_db/td_ta_map_lwp2thr.c Normal file
View File

@ -0,0 +1,179 @@
/* Which thread is running on an LWP?
Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include "thread_dbP.h"
#include <stdlib.h>
#include <byteswap.h>
#include <sys/procfs.h>
td_err_e
td_ta_map_lwp2thr (const td_thragent_t *ta_arg,
lwpid_t lwpid, td_thrhandle_t *th)
{
td_thragent_t *const ta = (td_thragent_t *) ta_arg;
ps_err_e err;
td_err_e terr;
prgregset_t regs;
psaddr_t addr;
LOG ("td_ta_map_lwp2thr");
/* Test whether the TA parameter is ok. */
if (! ta_ok (ta))
return TD_BADTA;
if (ta->ta_howto == ta_howto_unknown)
{
/* We need to read in from the inferior the instructions what to do. */
psaddr_t howto;
err = td_lookup (ta->ph, SYM_TH_UNIQUE_CONST_THREAD_AREA, &howto);
if (err == PS_OK)
{
err = ps_pdread (ta->ph, howto,
&ta->ta_howto_data.const_thread_area,
sizeof ta->ta_howto_data.const_thread_area);
if (err != PS_OK)
return TD_ERR;
ta->ta_howto = ta_howto_const_thread_area;
if (ta->ta_howto_data.const_thread_area & 0xff000000U)
ta->ta_howto_data.const_thread_area
= bswap_32 (ta->ta_howto_data.const_thread_area);
}
else
{
switch (sizeof (regs[0]))
{
case 8:
err = td_lookup (ta->ph, SYM_TH_UNIQUE_REGISTER64, &howto);
if (err == PS_OK)
ta->ta_howto = ta_howto_reg;
else if (err == PS_NOSYM)
{
err = td_lookup (ta->ph,
SYM_TH_UNIQUE_REGISTER64_THREAD_AREA,
&howto);
if (err == PS_OK)
ta->ta_howto = ta_howto_reg_thread_area;
}
break;
case 4:
err = td_lookup (ta->ph, SYM_TH_UNIQUE_REGISTER32, &howto);
if (err == PS_OK)
ta->ta_howto = ta_howto_reg;
else if (err == PS_NOSYM)
{
err = td_lookup (ta->ph,
SYM_TH_UNIQUE_REGISTER32_THREAD_AREA,
&howto);
if (err == PS_OK)
ta->ta_howto = ta_howto_reg_thread_area;
}
break;
default:
abort ();
return TD_DBERR;
}
if (err != PS_OK)
return TD_DBERR;
/* For either of these methods we read in the same descriptor. */
err = ps_pdread (ta->ph, howto,
ta->ta_howto_data.reg, DB_SIZEOF_DESC);
if (err != PS_OK)
return TD_ERR;
if (DB_DESC_SIZE (ta->ta_howto_data.reg) == 0)
return TD_DBERR;
if (DB_DESC_SIZE (ta->ta_howto_data.reg) & 0xff000000U)
{
/* Byte-swap these words, though we leave the size word
in native order as the handy way to distinguish. */
DB_DESC_OFFSET (ta->ta_howto_data.reg)
= bswap_32 (DB_DESC_OFFSET (ta->ta_howto_data.reg));
DB_DESC_NELEM (ta->ta_howto_data.reg)
= bswap_32 (DB_DESC_NELEM (ta->ta_howto_data.reg));
}
}
}
switch (ta->ta_howto)
{
case ta_howto_unknown:
return TD_DBERR;
default:
abort ();
return TD_DBERR;
case ta_howto_reg:
/* On most machines, we are just looking at a register. */
if (ps_lgetregs (ta->ph, lwpid, regs) != PS_OK)
return TD_ERR;
terr = _td_fetch_value_local (ta, ta->ta_howto_data.reg, -1,
0, regs, &addr);
if (terr != TD_OK)
return terr;
/* In this descriptor the nelem word is overloaded as the bias. */
addr += (int32_t) DB_DESC_NELEM (ta->ta_howto_data.reg);
th->th_unique = addr;
break;
case ta_howto_const_thread_area:
/* Some hosts don't have this call and this case won't be used. */
# pragma weak ps_get_thread_area
if (&ps_get_thread_area == NULL)
return TD_NOCAPAB;
/* A la x86-64, there is a constant magic index for get_thread_area. */
if (ps_get_thread_area (ta->ph, lwpid,
ta->ta_howto_data.const_thread_area,
&th->th_unique) != PS_OK)
return TD_ERR; /* XXX Other error value? */
break;
case ta_howto_reg_thread_area:
if (&ps_get_thread_area == NULL)
return TD_NOCAPAB;
/* A la i386, there is a register with an index for get_thread_area. */
if (ps_lgetregs (ta->ph, lwpid, regs) != PS_OK)
return TD_ERR;
terr = _td_fetch_value_local (ta, ta->ta_howto_data.reg_thread_area, -1,
0, regs, &addr);
if (terr != TD_OK)
return terr;
/* In this descriptor the nelem word is overloaded as scale factor. */
if (ps_get_thread_area
(ta->ph, lwpid,
((addr - (psaddr_t) 0)
>> DB_DESC_NELEM (ta->ta_howto_data.reg_thread_area)),
&th->th_unique) != PS_OK)
return TD_ERR; /* XXX Other error value? */
break;
}
/* Found it. Now complete the `td_thrhandle_t' object. */
th->th_ta_p = (td_thragent_t *) ta;
return TD_OK;
}

View File

@ -1,5 +1,5 @@
/* Attach to target process. /* Attach to target process.
Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
@ -34,30 +34,23 @@ LIST_HEAD (__td_agent_list);
td_err_e td_err_e
td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta) td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta)
{ {
psaddr_t addr;
psaddr_t versaddr; psaddr_t versaddr;
char versbuf[sizeof (VERSION)]; char versbuf[sizeof (VERSION)];
LOG ("td_ta_new"); LOG ("td_ta_new");
/* Get the global event mask. This is one of the variables which
are new in the thread library to enable debugging. If it is
not available we cannot debug. */
if (td_lookup (ps, SYM_PTHREAD_THREADS_EVENTS, &addr) != PS_OK)
return TD_NOLIBTHREAD;
/* Check whether the versions match. */ /* Check whether the versions match. */
if (td_lookup (ps, SYM_PTHREAD_VERSION, &versaddr) != PS_OK) if (td_lookup (ps, SYM_nptl_version, &versaddr) != PS_OK)
return TD_VERSION; return TD_NOLIBTHREAD;
if (ps_pdread (ps, versaddr, versbuf, sizeof (versbuf)) != PS_OK) if (ps_pdread (ps, versaddr, versbuf, sizeof (versbuf)) != PS_OK)
return TD_ERR; return TD_ERR;
if (versbuf[sizeof (versbuf) - 1] != '\0' || strcmp (versbuf, VERSION) != 0) if (memcmp (versbuf, VERSION, sizeof VERSION) != 0)
/* Not the right version. */ /* Not the right version. */
return TD_VERSION; return TD_VERSION;
/* Fill in the appropriate information. */ /* Fill in the appropriate information. */
*ta = (td_thragent_t *) malloc (sizeof (td_thragent_t)); *ta = (td_thragent_t *) calloc (1, sizeof (td_thragent_t));
if (*ta == NULL) if (*ta == NULL)
return TD_MALLOC; return TD_MALLOC;
@ -65,49 +58,6 @@ td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta)
back into the debugger. */ back into the debugger. */
(*ta)->ph = ps; (*ta)->ph = ps;
/* Remember the address. */
(*ta)->pthread_threads_eventsp = (td_thr_events_t *) addr;
/* Get the pointer to the variable pointing to the thread descriptor
with the last event. */
if (td_lookup (ps, SYM_PTHREAD_LAST_EVENT, &(*ta)->pthread_last_event)
!= PS_OK)
{
free_return:
free (*ta);
return TD_ERR;
}
if (td_lookup (ps, SYM_PTHREAD_STACK_USER, &addr) != PS_OK)
goto free_return;
/* Cast to the right type. */
(*ta)->stack_user = (list_t *) addr;
if (td_lookup (ps, SYM_PTHREAD_STACK_USED, &addr) != PS_OK)
goto free_return;
/* Cast to the right type. */
(*ta)->stack_used = (list_t *) addr;
if (td_lookup (ps, SYM_PTHREAD_KEYS, &addr) != PS_OK)
goto free_return;
/* Cast to the right type. */
(*ta)->keys = (struct pthread_key_struct *) addr;
/* Similarly for the maximum number of thread local data keys. */
if (td_lookup (ps, SYM_PTHREAD_KEYS_MAX, &addr) != PS_OK
|| ps_pdread (ps, addr, &(*ta)->pthread_keys_max, sizeof (int)) != PS_OK)
goto free_return;
/* And for the size of the second level arrays for the keys. */
if (td_lookup (ps, SYM_PTHREAD_SIZEOF_DESCR, &addr) != PS_OK
|| ps_pdread (ps, addr, &(*ta)->sizeof_descr, sizeof (int)) != PS_OK)
goto free_return;
/* Now add the new agent descriptor to the list. */ /* Now add the new agent descriptor to the list. */
list_add (&(*ta)->list, &__td_agent_list); list_add (&(*ta)->list, &__td_agent_list);

View File

@ -1,5 +1,5 @@
/* Globally enable events. /* Globally enable events.
Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
@ -22,31 +22,58 @@
td_err_e td_err_e
td_ta_set_event (ta, event) td_ta_set_event (ta_arg, event)
const td_thragent_t *ta; const td_thragent_t *ta_arg;
td_thr_events_t *event; td_thr_events_t *event;
{ {
td_thragent_t *const ta = (td_thragent_t *) ta_arg;
td_err_e err;
psaddr_t eventmask;
void *copy;
LOG ("td_ta_set_event"); LOG ("td_ta_set_event");
/* Test whether the TA parameter is ok. */ /* Test whether the TA parameter is ok. */
if (! ta_ok (ta)) if (! ta_ok (ta))
return TD_BADTA; return TD_BADTA;
/* Write the new value into the thread data structure. */ /* Fetch the old event mask from the inferior and modify it in place. */
td_thr_events_t old_event; err = DB_GET_SYMBOL (eventmask, ta, __nptl_threads_events);
if (ps_pdread (ta->ph, ta->pthread_threads_eventsp, if (err == TD_OK)
&old_event, sizeof (td_thrhandle_t)) != PS_OK) err = DB_GET_STRUCT (copy, ta, eventmask, td_thr_events_t);
return TD_ERR; /* XXX Other error value? */ if (err == TD_OK)
{
uint32_t idx;
for (idx = 0; idx < TD_EVENTSIZE; ++idx)
{
psaddr_t word;
uint32_t mask;
err = DB_GET_FIELD_LOCAL (word, ta, copy,
td_thr_events_t, event_bits, idx);
if (err != TD_OK)
break;
mask = (uintptr_t) word;
mask |= event->event_bits[idx];
word = (psaddr_t) (uintptr_t) mask;
err = DB_PUT_FIELD_LOCAL (ta, copy,
td_thr_events_t, event_bits, idx, word);
if (err != TD_OK)
break;
}
if (err == TD_NOAPLIC)
{
err = TD_OK;
while (idx < TD_EVENTSIZE)
if (event->event_bits[idx++] != 0)
{
err = TD_NOEVENT;
break;
}
}
if (err == TD_OK)
/* Now write it back to the inferior. */
err = DB_PUT_STRUCT (ta, eventmask, td_thr_events_t, copy);
}
/* Or the new bits in. */ return err;
int i;
for (i = 0; i < TD_EVENTSIZE; ++i)
old_event.event_bits[i] |= event->event_bits[i];
/* Write the new value into the thread data structure. */
if (ps_pdwrite (ta->ph, ta->pthread_threads_eventsp,
&old_event, sizeof (td_thrhandle_t)) != PS_OK)
return TD_ERR; /* XXX Other error value? */
return TD_OK;
} }

View File

@ -19,102 +19,108 @@
02111-1307 USA. */ 02111-1307 USA. */
#include "thread_dbP.h" #include "thread_dbP.h"
#include <nptl/descr.h>
static td_err_e static td_err_e
iterate_thread_list (const td_thragent_t *ta, td_thr_iter_f *callback, iterate_thread_list (td_thragent_t *ta, td_thr_iter_f *callback,
void *cbdata_p, td_thr_state_e state, int ti_pri, void *cbdata_p, td_thr_state_e state, int ti_pri,
psaddr_t head) psaddr_t head, int fake_empty)
{ {
list_t list; td_err_e err;
td_err_e result = TD_OK; psaddr_t next, ofs;
void *copy;
/* Test the state. /* Test the state.
XXX This is incomplete. Normally this test should be in the loop. */ XXX This is incomplete. Normally this test should be in the loop. */
if (state != TD_THR_ANY_STATE) if (state != TD_THR_ANY_STATE)
return TD_OK; return TD_OK;
if (ps_pdread (ta->ph, head, &list, sizeof (list_t)) != PS_OK) err = DB_GET_FIELD (next, ta, head, list_t, next, 0);
return TD_ERR; /* XXX Other error value? */ if (err != TD_OK)
return err;
if (list.next == 0 && list.prev == 0 && head == ta->stack_user) if (next == 0 && fake_empty)
{ {
/* __pthread_initialize_minimal has not run. /* __pthread_initialize_minimal has not run.
There is just the main thread to return. */ There is just the main thread to return. */
td_thrhandle_t th; td_thrhandle_t th;
td_err_e err = td_ta_map_lwp2thr (ta, ps_getpid (ta->ph), &th); err = td_ta_map_lwp2thr (ta, ps_getpid (ta->ph), &th);
return (err != TD_OK ? err if (err == TD_OK)
: callback (&th, cbdata_p) != 0 ? TD_DBERR : TD_OK); err = callback (&th, cbdata_p) != 0 ? TD_DBERR : TD_OK;
return err;
} }
while (list.next != head) /* Cache the offset from struct pthread to its list_t member. */
err = DB_GET_FIELD_ADDRESS (ofs, ta, 0, pthread, list, 0);
if (err != TD_OK)
return err;
if (ta->ta_sizeof_pthread == 0)
{ {
psaddr_t addr = ((psaddr_t) list.next - offsetof (struct pthread, list)); err = _td_check_sizeof (ta, &ta->ta_sizeof_pthread, SYM_SIZEOF_pthread);
if (err != TD_OK)
return err;
}
copy = __alloca (ta->ta_sizeof_pthread);
int schedpolicy; while (next != head)
if (ps_pdread (ta->ph, &((struct pthread *) addr)->schedpolicy, {
&schedpolicy, sizeof (int)) != PS_OK) psaddr_t addr, schedpolicy, schedprio;
{
result = TD_ERR; /* XXX Other error value? */
break;
}
struct sched_param schedparam; addr = next - (ofs - (psaddr_t) 0);
if (ps_pdread (ta->ph, &((struct pthread *) addr)->schedparam, if (next == 0 || addr == 0) /* Sanity check. */
&schedparam, sizeof (struct sched_param)) != PS_OK) return TD_DBERR;
{
result = TD_ERR; /* XXX Other error value? */
break;
}
/* Now test whether this thread matches the specified /* Copy the whole descriptor in once so we can access the several
conditions. */ fields locally. Excess copying in one go is much better than
multiple ps_pdread calls. */
if (ps_pdread (ta->ph, addr, copy, ta->ta_sizeof_pthread) != PS_OK)
return TD_ERR;
err = DB_GET_FIELD_LOCAL (schedpolicy, ta, copy, pthread,
schedpolicy, 0);
if (err != TD_OK)
break;
err = DB_GET_FIELD_LOCAL (schedprio, ta, copy, pthread,
schedparam_sched_priority, 0);
if (err != TD_OK)
break;
/* Now test whether this thread matches the specified conditions. */
/* Only if the priority level is as high or higher. */ /* Only if the priority level is as high or higher. */
int descr_pri = (schedpolicy == SCHED_OTHER int descr_pri = ((uintptr_t) schedpolicy == SCHED_OTHER
? 0 : schedparam.sched_priority); ? 0 : (uintptr_t) schedprio);
if (descr_pri >= ti_pri) if (descr_pri >= ti_pri)
{ {
/* XXX For now we ignore threads which are not running anymore. /* Yep, it matches. Call the callback function. */
The reason is that gdb tries to get the registers and fails. td_thrhandle_t th;
In future we should have a special mode of the thread library th.th_ta_p = (td_thragent_t *) ta;
in which we keep the process around until the actual join th.th_unique = addr;
operation happened. */ if (callback (&th, cbdata_p) != 0)
int cancelhandling; return TD_DBERR;
if (ps_pdread (ta->ph, &((struct pthread *) addr)->cancelhandling,
&cancelhandling, sizeof (int)) != PS_OK)
{
result = TD_ERR; /* XXX Other error value? */
break;
}
if ((cancelhandling & TERMINATED_BITMASK) == 0)
{
/* Yep, it matches. Call the callback function. */
td_thrhandle_t th;
th.th_ta_p = (td_thragent_t *) ta;
th.th_unique = addr;
if (callback (&th, cbdata_p) != 0)
return TD_DBERR;
}
} }
/* Get the pointer to the next element. */ /* Get the pointer to the next element. */
if (ps_pdread (ta->ph, &((struct pthread *) addr)->list, err = DB_GET_FIELD_LOCAL (next, ta, copy + (ofs - (psaddr_t) 0), list_t,
&list, sizeof (list_t)) != PS_OK) next, 0);
return TD_ERR; /* XXX Other error value? */ if (err != TD_OK)
break;
} }
return result; return err;
} }
td_err_e td_err_e
td_ta_thr_iter (const td_thragent_t *ta, td_thr_iter_f *callback, td_ta_thr_iter (const td_thragent_t *ta_arg, td_thr_iter_f *callback,
void *cbdata_p, td_thr_state_e state, int ti_pri, void *cbdata_p, td_thr_state_e state, int ti_pri,
sigset_t *ti_sigmask_p, unsigned int ti_user_flags) sigset_t *ti_sigmask_p, unsigned int ti_user_flags)
{ {
td_thragent_t *const ta = (td_thragent_t *) ta_arg;
td_err_e err;
psaddr_t list;
LOG ("td_ta_thr_iter"); LOG ("td_ta_thr_iter");
/* Test whether the TA parameter is ok. */ /* Test whether the TA parameter is ok. */
@ -127,13 +133,16 @@ td_ta_thr_iter (const td_thragent_t *ta, td_thr_iter_f *callback,
threads for which the thread library allocated the stacks. We threads for which the thread library allocated the stacks. We
have to iterate over both lists separately. We start with the have to iterate over both lists separately. We start with the
list of threads with user-defined stacks. */ list of threads with user-defined stacks. */
td_err_e result = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri,
ta->stack_user); err = DB_GET_SYMBOL (list, ta, __stack_user);
if (err == TD_OK)
err = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri, list, 1);
/* And the threads with stacks allocated by the implementation. */ /* And the threads with stacks allocated by the implementation. */
if (result == TD_OK) if (err == TD_OK)
result = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri, err = DB_GET_SYMBOL (list, ta, stack_used);
ta->stack_used); if (err == TD_OK)
err = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri, list, 0);
return result; return err;
} }

View File

@ -1,5 +1,5 @@
/* Iterate over a process's thread-specific data. /* Iterate over a process's thread-specific data.
Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. Copyright (C) 1999,2000,2001,2002,2003 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
@ -22,32 +22,60 @@
#include <alloca.h> #include <alloca.h>
td_err_e td_err_e
td_ta_tsd_iter (const td_thragent_t *ta, td_key_iter_f *callback, td_ta_tsd_iter (const td_thragent_t *ta_arg, td_key_iter_f *callback,
void *cbdata_p) void *cbdata_p)
{ {
td_thragent_t *const ta = (td_thragent_t *) ta_arg;
td_err_e err;
void *keys;
size_t keys_nb, keys_elemsize;
psaddr_t addr;
uint32_t idx;
LOG ("td_ta_tsd_iter"); LOG ("td_ta_tsd_iter");
/* Test whether the TA parameter is ok. */ /* Test whether the TA parameter is ok. */
if (! ta_ok (ta)) if (! ta_ok (ta))
return TD_BADTA; return TD_BADTA;
int pthread_keys_max = ta->pthread_keys_max; /* This makes sure we have the size information on hand. */
struct pthread_key_struct *keys; addr = 0;
keys = (struct pthread_key_struct *) alloca (sizeof (keys[0]) err = _td_locate_field (ta,
* pthread_keys_max); ta->ta_var___pthread_keys, SYM_DESC___pthread_keys,
(psaddr_t) 0 + 1, &addr);
if (err != TD_OK)
return err;
/* Read all the information about the keys. */ /* Now copy in the entire array of key descriptors. */
if (ps_pdread (ta->ph, ta->keys, keys, keys_elemsize = (addr - (psaddr_t) 0) / 8;
sizeof (keys[0]) * pthread_keys_max) != PS_OK) keys_nb = keys_elemsize * DB_DESC_NELEM (ta->ta_var___pthread_keys);
return TD_ERR; /* XXX Other error value? */ keys = __alloca (keys_nb);
err = DB_GET_SYMBOL (addr, ta, __pthread_keys);
if (err != TD_OK)
return err;
if (ps_pdread (ta->ph, addr, keys, keys_nb) != PS_OK)
return TD_ERR;
/* Now get all descriptors, one after the other. */ /* Now get all descriptors, one after the other. */
int cnt; for (idx = 0; idx < DB_DESC_NELEM (ta->ta_var___pthread_keys); ++idx)
for (cnt = 0; cnt < pthread_keys_max; ++cnt) {
if (!KEY_UNUSED (keys[cnt].seq) psaddr_t seq, destr;
/* Return with an error if the callback returns a nonzero value. */ err = DB_GET_FIELD_LOCAL (seq, ta, keys, pthread_key_struct, seq, 0);
&& callback (cnt, keys[cnt].destr, cbdata_p) != 0) if (err != TD_OK)
return TD_DBERR; return err;
if (((uintptr_t) seq) & 1)
{
err = DB_GET_FIELD_LOCAL (destr, ta, keys, pthread_key_struct,
destr, 0);
if (err != TD_OK)
return err;
/* Return with an error if the callback returns a nonzero value. */
if (callback ((thread_key_t) idx, destr, cbdata_p) != 0)
return TD_DBERR;
}
/* Advance to the next element in the copied array. */
keys += keys_elemsize;
}
return TD_OK; return TD_OK;
} }

View File

@ -1,5 +1,5 @@
/* Disable specific event for thread. /* Disable specific event for thread.
Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
@ -28,27 +28,50 @@ td_thr_clear_event (th, event)
const td_thrhandle_t *th; const td_thrhandle_t *th;
td_thr_events_t *event; td_thr_events_t *event;
{ {
td_err_e err;
psaddr_t eventmask;
void *copy;
LOG ("td_thr_clear_event"); LOG ("td_thr_clear_event");
/* Write the new value into the thread data structure. */ /* Fetch the old event mask from the inferior and modify it in place. */
td_thr_events_t old_event; err = DB_GET_FIELD_ADDRESS (eventmask, th->th_ta_p,
if (ps_pdread (th->th_ta_p->ph, th->th_unique, pthread, eventbuf_eventmask, 0);
((char *) th->th_unique if (err == TD_OK)
+ offsetof (struct pthread, eventbuf.eventmask)), err = DB_GET_STRUCT (copy, th->th_ta_p, eventmask, td_thr_events_t);
&old_event, sizeof (td_thrhandle_t)) != PS_OK) if (err == TD_OK)
return TD_ERR; /* XXX Other error value? */ {
uint32_t idx;
for (idx = 0; idx < TD_EVENTSIZE; ++idx)
{
psaddr_t word;
uint32_t mask;
err = DB_GET_FIELD_LOCAL (word, th->th_ta_p, copy,
td_thr_events_t, event_bits, idx);
if (err != TD_OK)
break;
mask = (uintptr_t) word;
mask &= ~event->event_bits[idx];
word = (psaddr_t) (uintptr_t) mask;
err = DB_PUT_FIELD_LOCAL (th->th_ta_p, copy,
td_thr_events_t, event_bits, idx, word);
if (err != TD_OK)
break;
}
if (err == TD_NOAPLIC)
{
err = TD_OK;
while (idx < TD_EVENTSIZE)
if (event->event_bits[idx++] != 0)
{
err = TD_NOEVENT;
break;
}
}
if (err == TD_OK)
/* Now write it back to the inferior. */
err = DB_PUT_STRUCT (th->th_ta_p, eventmask, td_thr_events_t, copy);
}
/* Remove the set bits in. */ return err;
int i;
for (i = 0; i < TD_EVENTSIZE; ++i)
old_event.event_bits[i] &= ~event->event_bits[i];
/* Write the new value into the thread data structure. */
if (ps_pdwrite (th->th_ta_p->ph,
((char *) th->th_unique
+ offsetof (struct pthread, eventbuf.eventmask)),
&old_event, sizeof (td_thrhandle_t)) != PS_OK)
return TD_ERR; /* XXX Other error value? */
return TD_OK;
} }

View File

@ -18,8 +18,6 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */ 02111-1307 USA. */
#include <stddef.h>
#include "thread_dbP.h" #include "thread_dbP.h"
@ -31,12 +29,6 @@ td_thr_event_enable (th, onoff)
LOG ("td_thr_event_enable"); LOG ("td_thr_event_enable");
/* Write the new value into the thread data structure. */ /* Write the new value into the thread data structure. */
const bool value = onoff != 0; return DB_PUT_FIELD (th->th_ta_p, th->th_unique, pthread, report_events, 0,
if (ps_pdwrite (th->th_ta_p->ph, (psaddr_t) 0 + (onoff != 0));
((char *) th->th_unique
+ offsetof (struct pthread, report_events)),
&value, sizeof value) != PS_OK)
return TD_ERR; /* XXX Other error value? */
return TD_OK;
} }

View File

@ -18,60 +18,71 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */ 02111-1307 USA. */
#include <stddef.h>
#include <string.h>
#include "thread_dbP.h" #include "thread_dbP.h"
#include <assert.h>
td_err_e td_err_e
td_thr_event_getmsg (const td_thrhandle_t *th, td_event_msg_t *msg) td_thr_event_getmsg (const td_thrhandle_t *th, td_event_msg_t *msg)
{ {
td_eventbuf_t event; td_err_e err;
psaddr_t eventbuf, eventnum, eventdata;
psaddr_t thp, prevp;
void *copy;
LOG ("td_thr_event_getmsg"); LOG ("td_thr_event_getmsg");
/* Read the event structure from the target. */ /* Copy the event message buffer in from the inferior. */
if (ps_pdread (th->th_ta_p->ph, err = DB_GET_FIELD_ADDRESS (eventbuf, th->th_ta_p, th->th_unique, pthread,
((char *) th->th_unique eventbuf, 0);
+ offsetof (struct pthread, eventbuf)), if (err == TD_OK)
&event, sizeof (td_eventbuf_t)) != PS_OK) err = DB_GET_STRUCT (copy, th->th_ta_p, eventbuf, td_eventbuf_t);
return TD_ERR; /* XXX Other error value? */ if (err != TD_OK)
return err;
/* Check whether an event occurred. */ /* Check whether an event occurred. */
if (event.eventnum == TD_EVENT_NONE) err = DB_GET_FIELD_LOCAL (eventnum, th->th_ta_p, copy,
td_eventbuf_t, eventnum, 0);
if (err != TD_OK)
return err;
if ((int) (uintptr_t) eventnum == TD_EVENT_NONE)
/* Nothing. */ /* Nothing. */
return TD_NOMSG; return TD_NOMSG;
/* Fill the user's data structure. */ /* Fill the user's data structure. */
msg->event = event.eventnum; err = DB_GET_FIELD_LOCAL (eventdata, th->th_ta_p, copy,
td_eventbuf_t, eventdata, 0);
if (err != TD_OK)
return err;
msg->msg.data = (uintptr_t) eventdata;
msg->event = (uintptr_t) eventnum;
msg->th_p = th; msg->th_p = th;
msg->msg.data = (uintptr_t) event.eventdata;
/* And clear the event message in the target. */ /* And clear the event message in the target. */
memset (&event, '\0', sizeof (td_eventbuf_t)); memset (copy, 0, th->th_ta_p->ta_sizeof_td_eventbuf_t);
if (ps_pdwrite (th->th_ta_p->ph, err = DB_PUT_STRUCT (th->th_ta_p, eventbuf, td_eventbuf_t, copy);
((char *) th->th_unique if (err != TD_OK)
+ offsetof (struct pthread, eventbuf)), return err;
&event, sizeof (td_eventbuf_t)) != PS_OK)
return TD_ERR; /* XXX Other error value? */
/* Get the pointer to the thread descriptor with the last event. /* Get the pointer to the thread descriptor with the last event.
If it doesn't match TH, then walk down the list until we find it. If it doesn't match TH, then walk down the list until we find it.
We must splice it out of the list so that there is no dangling We must splice it out of the list so that there is no dangling
pointer to it later when it dies. */ pointer to it later when it dies. */
psaddr_t thp, prevp = th->th_ta_p->pthread_last_event; err = DB_GET_SYMBOL (prevp, th->th_ta_p, __nptl_last_event);
if (ps_pdread (th->th_ta_p->ph, if (err != TD_OK)
prevp, &thp, sizeof (struct pthread *)) != PS_OK) return err;
return TD_ERR; /* XXX Other error value? */ err = DB_GET_VALUE (thp, th->th_ta_p, __nptl_last_event, 0);
if (err != TD_OK)
return err;
psaddr_t next;
while (thp != 0) while (thp != 0)
{ {
if (ps_pdread (th->th_ta_p->ph, psaddr_t next;
(char *) thp + offsetof (struct pthread, nextevent), err = DB_GET_FIELD (next, th->th_ta_p, th->th_unique, pthread,
&next, sizeof (struct pthread *)) != PS_OK) nextevent, 0);
return TD_ERR; /* XXX Other error value? */ if (err != TD_OK)
return err;
if (next == thp) if (next == thp)
return TD_DBERR; return TD_DBERR;
@ -79,24 +90,27 @@ td_thr_event_getmsg (const td_thrhandle_t *th, td_event_msg_t *msg)
if (thp == th->th_unique) if (thp == th->th_unique)
{ {
/* PREVP points at this thread, splice it out. */ /* PREVP points at this thread, splice it out. */
if (prevp == (char *) next + offsetof (struct pthread, nextevent)) psaddr_t next_nextp;
err = DB_GET_FIELD_ADDRESS (next_nextp, th->th_ta_p, next, pthread,
nextevent, 0);
assert (err == TD_OK); /* We used this field before. */
if (prevp == next_nextp)
return TD_DBERR; return TD_DBERR;
if (ps_pdwrite (th->th_ta_p->ph, prevp, &next, sizeof next) != PS_OK) err = _td_store_value (th->th_ta_p,
return TD_ERR; /* XXX Other error value? */ th->th_ta_p->ta_var___nptl_last_event, -1,
0, prevp, next);
if (err != TD_OK)
return err;
/* Now clear this thread's own next pointer so it's not dangling /* Now clear this thread's own next pointer so it's not dangling
when the thread resumes and then chains on for its next event. */ when the thread resumes and then chains on for its next event. */
next = NULL; return DB_PUT_FIELD (th->th_ta_p, thp, pthread, nextevent, 0, 0);
if (ps_pdwrite (th->th_ta_p->ph,
(char *) thp + offsetof (struct pthread, nextevent),
&next, sizeof next) != PS_OK)
return TD_ERR; /* XXX Other error value? */
return TD_OK;
} }
prevp = (char *) thp + offsetof (struct pthread, nextevent); err = DB_GET_FIELD_ADDRESS (prevp, th->th_ta_p, thp, pthread,
nextevent, 0);
assert (err == TD_OK); /* We used this field before. */
thp = next; thp = next;
} }

View File

@ -26,39 +26,85 @@
td_err_e td_err_e
td_thr_get_info (const td_thrhandle_t *th, td_thrinfo_t *infop) td_thr_get_info (const td_thrhandle_t *th, td_thrinfo_t *infop)
{ {
td_err_e err;
void *copy;
psaddr_t tls, schedpolicy, schedprio, cancelhandling, tid, report_events;
LOG ("td_thr_get_info"); LOG ("td_thr_get_info");
/* Get the thread descriptor. */ /* Copy the whole descriptor in once so we can access the several
struct pthread pds; fields locally. Excess copying in one go is much better than
if (ps_pdread (th->th_ta_p->ph, th->th_unique, &pds, multiple ps_pdread calls. */
sizeof (struct pthread)) != PS_OK) err = DB_GET_STRUCT (copy, th->th_ta_p, th->th_unique, pthread);
return TD_ERR; /* XXX Other error value? */ if (err != TD_OK)
return err;
err = DB_GET_FIELD_ADDRESS (tls, th->th_ta_p, th->th_unique,
pthread, specific, 0);
if (err != TD_OK)
return err;
err = DB_GET_FIELD_LOCAL (schedpolicy, th->th_ta_p, copy, pthread,
schedpolicy, 0);
if (err != TD_OK)
return err;
err = DB_GET_FIELD_LOCAL (schedprio, th->th_ta_p, copy, pthread,
schedparam_sched_priority, 0);
if (err != TD_OK)
return err;
err = DB_GET_FIELD_LOCAL (tid, th->th_ta_p, copy, pthread, tid, 0);
if (err != TD_OK)
return err;
err = DB_GET_FIELD_LOCAL (cancelhandling, th->th_ta_p, copy, pthread,
cancelhandling, 0);
if (err != TD_OK)
return err;
err = DB_GET_FIELD_LOCAL (report_events, th->th_ta_p, copy, pthread,
report_events, 0);
if (err != TD_OK)
return err;
/* Fill in information. Clear first to provide reproducable /* Fill in information. Clear first to provide reproducable
results for the fields we do not fill in. */ results for the fields we do not fill in. */
memset (infop, '\0', sizeof (td_thrinfo_t)); memset (infop, '\0', sizeof (td_thrinfo_t));
infop->ti_tid = th->th_unique; infop->ti_tid = (thread_t) th->th_unique;
infop->ti_tls = (char *) pds.specific; infop->ti_tls = (char *) tls;
infop->ti_pri = (pds.schedpolicy == SCHED_OTHER infop->ti_pri = ((uintptr_t) schedpolicy == SCHED_OTHER
? 0 : pds.schedparam.sched_priority); ? 0 : (uintptr_t) schedprio);
infop->ti_type = TD_THR_USER; infop->ti_type = TD_THR_USER;
if ((pds.cancelhandling & EXITING_BITMASK) == 0) if ((((int) (uintptr_t) cancelhandling) & EXITING_BITMASK) == 0)
/* XXX For now there is no way to get more information. */ /* XXX For now there is no way to get more information. */
infop->ti_state = TD_THR_ACTIVE; infop->ti_state = TD_THR_ACTIVE;
else if ((pds.cancelhandling & TERMINATED_BITMASK) == 0) else if ((((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK) == 0)
infop->ti_state = TD_THR_ZOMBIE; infop->ti_state = TD_THR_ZOMBIE;
else else
infop->ti_state = TD_THR_UNKNOWN; infop->ti_state = TD_THR_UNKNOWN;
/* Initialization which are the same in both cases. */ /* Initialization which are the same in both cases. */
infop->ti_lid = pds.tid ?: ps_getpid (th->th_ta_p->ph);
infop->ti_ta_p = th->th_ta_p; infop->ti_ta_p = th->th_ta_p;
infop->ti_startfunc = pds.start_routine; infop->ti_lid = tid == 0 ? ps_getpid (th->th_ta_p->ph) : (uintptr_t) tid;
memcpy (&infop->ti_events, &pds.eventbuf.eventmask, infop->ti_traceme = report_events != 0;
sizeof (td_thr_events_t));
infop->ti_traceme = pds.report_events != false;
return TD_OK; err = DB_GET_FIELD_LOCAL (infop->ti_startfunc, th->th_ta_p, copy, pthread,
start_routine, 0);
if (err == TD_OK)
{
uint32_t idx;
for (idx = 0; idx < TD_EVENTSIZE; ++idx)
{
psaddr_t word;
err = DB_GET_FIELD_LOCAL (word, th->th_ta_p, copy, pthread,
eventbuf_eventmask_event_bits, idx);
if (err != TD_OK)
break;
infop->ti_events.event_bits[idx] = (uintptr_t) word;
}
if (err == TD_NOAPLIC)
memset (&infop->ti_events.event_bits[idx], 0,
(TD_EVENTSIZE - idx) * sizeof infop->ti_events.event_bits[0]);
}
return err;
} }

View File

@ -24,27 +24,28 @@
td_err_e td_err_e
td_thr_getfpregs (const td_thrhandle_t *th, prfpregset_t *regset) td_thr_getfpregs (const td_thrhandle_t *th, prfpregset_t *regset)
{ {
psaddr_t cancelhandling, tid;
td_err_e err;
LOG ("td_thr_getfpregs"); LOG ("td_thr_getfpregs");
/* We have to get the state and the PID for this thread. */ /* We have to get the state and the PID for this thread. */
int cancelhandling; err = DB_GET_FIELD (cancelhandling, th->th_ta_p, th->th_unique, pthread,
if (ps_pdread (th->th_ta_p->ph, cancelhandling, 0);
&((struct pthread *) th->th_unique)->cancelhandling, if (err != TD_OK)
&cancelhandling, sizeof (int)) != PS_OK) return err;
return TD_ERR;
/* If the thread already terminated we return all zeroes. */ /* If the thread already terminated we return all zeroes. */
if (cancelhandling & TERMINATED_BITMASK) if (((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK)
memset (regset, '\0', sizeof (*regset)); memset (regset, '\0', sizeof (*regset));
/* Otherwise get the register content through the callback. */ /* Otherwise get the register content through the callback. */
else else
{ {
pid_t tid; err = DB_GET_FIELD (tid, th->th_ta_p, th->th_unique, pthread, tid, 0);
if (err != TD_OK)
return err;
if (ps_pdread (th->th_ta_p->ph, if (ps_lgetfpregs (th->th_ta_p->ph, (uintptr_t) tid, regset) != PS_OK)
&((struct pthread *) th->th_unique)->tid,
&tid, sizeof (pid_t)) != PS_OK
|| ps_lgetfpregs (th->th_ta_p->ph, tid, regset) != PS_OK)
return TD_ERR; return TD_ERR;
} }

View File

@ -22,29 +22,30 @@
td_err_e td_err_e
td_thr_getgregs (const td_thrhandle_t *th, prgregset_t gregs) td_thr_getgregs (const td_thrhandle_t *th, prgregset_t regset)
{ {
psaddr_t cancelhandling, tid;
td_err_e err;
LOG ("td_thr_getgregs"); LOG ("td_thr_getgregs");
/* We have to get the state and the PID for this thread. */ /* We have to get the state and the PID for this thread. */
int cancelhandling; err = DB_GET_FIELD (cancelhandling, th->th_ta_p, th->th_unique, pthread,
if (ps_pdread (th->th_ta_p->ph, cancelhandling, 0);
&((struct pthread *) th->th_unique)->cancelhandling, if (err != TD_OK)
&cancelhandling, sizeof (int)) != PS_OK) return err;
return TD_ERR;
/* If the thread already terminated we return all zeroes. */ /* If the thread already terminated we return all zeroes. */
if (cancelhandling & TERMINATED_BITMASK) if (((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK)
memset (gregs, '\0', sizeof (prgregset_t)); memset (regset, '\0', sizeof (*regset));
/* Otherwise get the register content through the callback. */ /* Otherwise get the register content through the callback. */
else else
{ {
pid_t tid; err = DB_GET_FIELD (tid, th->th_ta_p, th->th_unique, pthread, tid, 0);
if (err != TD_OK)
return err;
if (ps_pdread (th->th_ta_p->ph, if (ps_lgetregs (th->th_ta_p->ph, (uintptr_t) tid, regset) != PS_OK)
&((struct pthread *) th->th_unique)->tid,
&tid, sizeof (pid_t)) != PS_OK
|| ps_lgetregs (th->th_ta_p->ph, tid, gregs) != PS_OK)
return TD_ERR; return TD_ERR;
} }

View File

@ -1,5 +1,5 @@
/* Enable specific event for thread. /* Enable specific event for thread.
Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
@ -28,27 +28,50 @@ td_thr_set_event (th, event)
const td_thrhandle_t *th; const td_thrhandle_t *th;
td_thr_events_t *event; td_thr_events_t *event;
{ {
td_err_e err;
psaddr_t eventmask;
void *copy;
LOG ("td_thr_set_event"); LOG ("td_thr_set_event");
/* Write the new value into the thread data structure. */ /* Fetch the old event mask from the inferior and modify it in place. */
td_thr_events_t old_event; err = DB_GET_FIELD_ADDRESS (eventmask, th->th_ta_p,
if (ps_pdread (th->th_ta_p->ph, th->th_unique, pthread, eventbuf_eventmask, 0);
((char *) th->th_unique if (err == TD_OK)
+ offsetof (struct pthread, eventbuf.eventmask)), err = DB_GET_STRUCT (copy, th->th_ta_p, eventmask, td_thr_events_t);
&old_event, sizeof (td_thrhandle_t)) != PS_OK) if (err == TD_OK)
return TD_ERR; /* XXX Other error value? */ {
uint32_t idx;
for (idx = 0; idx < TD_EVENTSIZE; ++idx)
{
psaddr_t word;
uint32_t mask;
err = DB_GET_FIELD_LOCAL (word, th->th_ta_p, copy,
td_thr_events_t, event_bits, idx);
if (err != TD_OK)
break;
mask = (uintptr_t) word;
mask |= event->event_bits[idx];
word = (psaddr_t) (uintptr_t) mask;
err = DB_PUT_FIELD_LOCAL (th->th_ta_p, copy,
td_thr_events_t, event_bits, idx, word);
if (err != TD_OK)
break;
}
if (err == TD_NOAPLIC)
{
err = TD_OK;
while (idx < TD_EVENTSIZE)
if (event->event_bits[idx++] != 0)
{
err = TD_NOEVENT;
break;
}
}
if (err == TD_OK)
/* Now write it back to the inferior. */
err = DB_PUT_STRUCT (th->th_ta_p, eventmask, td_thr_events_t, copy);
}
/* Or the new bits in. */ return err;
int i;
for (i = 0; i < TD_EVENTSIZE; ++i)
old_event.event_bits[i] |= event->event_bits[i];
/* Write the new value into the thread data structure. */
if (ps_pdwrite (th->th_ta_p->ph,
((char *) th->th_unique
+ offsetof (struct pthread, eventbuf.eventmask)),
&old_event, sizeof (td_thrhandle_t)) != PS_OK)
return TD_ERR; /* XXX Other error value? */
return TD_OK;
} }

View File

@ -24,24 +24,25 @@
td_err_e td_err_e
td_thr_setfpregs (const td_thrhandle_t *th, const prfpregset_t *fpregs) td_thr_setfpregs (const td_thrhandle_t *th, const prfpregset_t *fpregs)
{ {
psaddr_t cancelhandling, tid;
td_err_e err;
LOG ("td_thr_setfpregs"); LOG ("td_thr_setfpregs");
/* We have to get the state and the PID for this thread. */ /* We have to get the state and the PID for this thread. */
int cancelhandling; err = DB_GET_FIELD (cancelhandling, th->th_ta_p, th->th_unique, pthread,
if (ps_pdread (th->th_ta_p->ph, cancelhandling, 0);
&((struct pthread *) th->th_unique)->cancelhandling, if (err != TD_OK)
&cancelhandling, sizeof (int)) != PS_OK) return err;
return TD_ERR;
/* Only set the registers if the thread hasn't yet terminated. */ /* Only set the registers if the thread hasn't yet terminated. */
if ((cancelhandling & TERMINATED_BITMASK) == 0) if ((((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK) == 0)
{ {
pid_t tid; err = DB_GET_FIELD (tid, th->th_ta_p, th->th_unique, pthread, tid, 0);
if (err != TD_OK)
return err;
if (ps_pdread (th->th_ta_p->ph, if (ps_lsetfpregs (th->th_ta_p->ph, (uintptr_t) tid, fpregs) != PS_OK)
&((struct pthread *) th->th_unique)->tid,
&tid, sizeof (pid_t)) != PS_OK
|| ps_lsetfpregs (th->th_ta_p->ph, tid, fpregs) != PS_OK)
return TD_ERR; return TD_ERR;
} }

View File

@ -24,24 +24,25 @@
td_err_e td_err_e
td_thr_setgregs (const td_thrhandle_t *th, prgregset_t gregs) td_thr_setgregs (const td_thrhandle_t *th, prgregset_t gregs)
{ {
psaddr_t cancelhandling, tid;
td_err_e err;
LOG ("td_thr_setgregs"); LOG ("td_thr_setgregs");
/* We have to get the state and the PID for this thread. */ /* We have to get the state and the PID for this thread. */
int cancelhandling; err = DB_GET_FIELD (cancelhandling, th->th_ta_p, th->th_unique, pthread,
if (ps_pdread (th->th_ta_p->ph, cancelhandling, 0);
&((struct pthread *) th->th_unique)->cancelhandling, if (err != TD_OK)
&cancelhandling, sizeof (int)) != PS_OK) return err;
return TD_ERR;
/* Only set the registers if the thread hasn't yet terminated. */ /* Only set the registers if the thread hasn't yet terminated. */
if ((cancelhandling & TERMINATED_BITMASK) == 0) if ((((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK) == 0)
{ {
pid_t tid; err = DB_GET_FIELD (tid, th->th_ta_p, th->th_unique, pthread, tid, 0);
if (err != TD_OK)
return err;
if (ps_pdread (th->th_ta_p->ph, if (ps_lsetregs (th->th_ta_p->ph, tid - (psaddr_t) 0, gregs) != PS_OK)
&((struct pthread *) th->th_unique)->tid,
&tid, sizeof (pid_t)) != PS_OK
|| ps_lsetregs (th->th_ta_p->ph, tid, gregs) != PS_OK)
return TD_ERR; return TD_ERR;
} }

View File

@ -22,24 +22,22 @@
#include "thread_dbP.h" #include "thread_dbP.h"
td_err_e td_err_e
td_thr_tls_get_addr (const td_thrhandle_t *th __attribute__ ((unused)), td_thr_tls_get_addr (const td_thrhandle_t *th,
void *map_address __attribute__ ((unused)), psaddr_t map_address, size_t offset, psaddr_t *address)
size_t offset __attribute__ ((unused)),
void **address __attribute__ ((unused)))
{ {
#if USE_TLS td_err_e err;
/* Read the module ID from the link_map. */ psaddr_t modid;
size_t modid;
if (ps_pdread (th->th_ta_p->ph,
&((struct link_map *) map_address)->l_tls_modid,
&modid, sizeof modid) != PS_OK)
return TD_ERR; /* XXX Other error value? */
td_err_e result = td_thr_tlsbase (th, modid, address); /* Get the TLS module ID from the `struct link_map' in the inferior. */
if (result == TD_OK) err = DB_GET_FIELD (modid, th->th_ta_p, map_address, link_map,
*address += offset; l_tls_modid, 0);
return result; if (err == TD_NOCAPAB)
#else return TD_NOAPLIC;
return TD_ERR; if (err == TD_OK)
#endif {
err = td_thr_tlsbase (th, (uintptr_t) modid, address);
if (err == TD_OK)
*address += offset;
}
return err;
} }

View File

@ -19,49 +19,32 @@
#include "thread_dbP.h" #include "thread_dbP.h"
/* Value used for dtv entries for which the allocation is delayed. */
# define TLS_DTV_UNALLOCATED ((void *) -1l)
td_err_e td_err_e
td_thr_tlsbase (const td_thrhandle_t *th, td_thr_tlsbase (const td_thrhandle_t *th,
unsigned long int modid, unsigned long int modid,
psaddr_t *base) psaddr_t *base)
{ {
td_err_e err;
psaddr_t dtv, dtvptr;
if (modid < 1) if (modid < 1)
return TD_NOTLS; return TD_NOTLS;
#if USE_TLS
union dtv pdtv, *dtvp;
LOG ("td_thr_tlsbase");
psaddr_t dtvpp = th->th_unique;
#if TLS_TCB_AT_TP
dtvpp += offsetof (struct pthread, header.dtv);
#elif TLS_DTV_AT_TP
dtvpp += TLS_PRE_TCB_SIZE + offsetof (tcbhead_t, dtv);
#else
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined."
#endif
/* Get the DTV pointer from the thread descriptor. */ /* Get the DTV pointer from the thread descriptor. */
if (ps_pdread (th->th_ta_p->ph, dtvpp, &dtvp, sizeof dtvp) != PS_OK) err = DB_GET_FIELD (dtv, th->th_ta_p, th->th_unique, pthread, dtvp, 0);
return TD_ERR; /* XXX Other error value? */ if (err != TD_OK)
return err;
/* Get the corresponding entry in the DTV. */ /* Get the corresponding entry in the DTV. */
if (ps_pdread (th->th_ta_p->ph, dtvp + modid, err = DB_GET_FIELD (dtvptr, th->th_ta_p, dtv, dtv, dtv, modid);
&pdtv, sizeof (union dtv)) != PS_OK) if (err != TD_OK)
return TD_ERR; /* XXX Other error value? */ return err;
/* It could be that the memory for this module is not allocated for /* It could be that the memory for this module is not allocated for
the given thread. */ the given thread. */
if (pdtv.pointer == TLS_DTV_UNALLOCATED) if ((uintptr_t) dtvptr & 1)
return TD_TLSDEFER; return TD_TLSDEFER;
*base = (char *) pdtv.pointer; *base = dtvptr;
return TD_OK; return TD_OK;
#else
return TD_ERR;
#endif
} }

View File

@ -1,5 +1,5 @@
/* Get a thread-specific data pointer for a thread. /* Get a thread-specific data pointer for a thread.
Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. Copyright (C) 1999,2001,2002,2003 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 1999. Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
@ -24,48 +24,73 @@
td_err_e td_err_e
td_thr_tsd (const td_thrhandle_t *th, const thread_key_t tk, void **data) td_thr_tsd (const td_thrhandle_t *th, const thread_key_t tk, void **data)
{ {
td_err_e err;
psaddr_t tk_seq, level1, level2, seq, value;
void *copy;
uint32_t pthread_key_2ndlevel_size, idx1st, idx2nd;
LOG ("td_thr_tsd"); LOG ("td_thr_tsd");
/* Check correct value of key. */
if (tk >= th->th_ta_p->pthread_keys_max)
return TD_BADKEY;
/* Get the key entry. */ /* Get the key entry. */
uintptr_t seq; err = DB_GET_VALUE (tk_seq, th->th_ta_p, __pthread_keys, tk);
if (ps_pdread (th->th_ta_p->ph, &th->th_ta_p->keys[tk].seq, &seq, if (err == TD_NOAPLIC)
sizeof (uintptr_t)) != PS_OK) return TD_BADKEY;
return TD_ERR; /* XXX Other error value? */ if (err != TD_OK)
return err;
/* Fail if this key is not at all used. */ /* Fail if this key is not at all used. */
if (KEY_UNUSED (seq)) if (((uintptr_t) tk_seq & 1) == 0)
return TD_BADKEY; return TD_BADKEY;
/* Compute the indeces. */ /* This makes sure we have the size information on hand. */
int pthread_key_2ndlevel_size = th->th_ta_p->pthread_key_2ndlevel_size; err = DB_GET_FIELD_ADDRESS (level2, th->th_ta_p, 0, pthread_key_data_level2,
unsigned int idx1st = tk / pthread_key_2ndlevel_size; data, 1);
unsigned int idx2nd = tk % pthread_key_2ndlevel_size; if (err != TD_OK)
return err;
struct pthread_key_data *level1; /* Compute the indeces. */
if (ps_pdread (th->th_ta_p->ph, pthread_key_2ndlevel_size
&((struct pthread *) th->th_unique)->specific[idx1st], = DB_DESC_NELEM (th->th_ta_p->ta_field_pthread_key_data_level2_data);
&level1, sizeof (level1)) != PS_OK) idx1st = tk / pthread_key_2ndlevel_size;
return TD_ERR; /* XXX Other error value? */ idx2nd = tk % pthread_key_2ndlevel_size;
/* Now fetch the first level pointer. */
err = DB_GET_FIELD (level1, th->th_ta_p, th->th_unique, pthread,
specific, idx1st);
if (err == TD_NOAPLIC)
return TD_DBERR;
if (err != TD_OK)
return err;
/* Check the pointer to the second level array. */ /* Check the pointer to the second level array. */
if (level1 == NULL) if (level1 == 0)
return TD_NOTSD; return TD_NOTSD;
struct pthread_key_data level2; /* Locate the element within the second level array. */
if (ps_pdread (th->th_ta_p->ph, &level1[idx2nd], &level2, err = DB_GET_FIELD_ADDRESS (level2, th->th_ta_p,
sizeof (level2)) != PS_OK) level1, pthread_key_data_level2, data, idx2nd);
return TD_ERR; /* XXX Other error value? */ if (err == TD_NOAPLIC)
return TD_DBERR;
if (err != TD_OK)
return err;
/* Now copy in that whole structure. */
err = DB_GET_STRUCT (copy, th->th_ta_p, level2, pthread_key_data);
if (err != TD_OK)
return err;
/* Check whether the data is valid. */ /* Check whether the data is valid. */
if (level2.seq != seq) err = DB_GET_FIELD_LOCAL (seq, th->th_ta_p, copy, pthread_key_data, seq, 0);
if (err != TD_OK)
return err;
if (seq != tk_seq)
return TD_NOTSD; return TD_NOTSD;
if (level2.data != NULL) /* Finally, fetch the value. */
*data = level2.data; err = DB_GET_FIELD_LOCAL (value, th->th_ta_p, copy, pthread_key_data,
data, 0);
if (err == TD_OK)
*data = value;
return TD_OK; return err;
} }

View File

@ -24,43 +24,53 @@
static td_err_e static td_err_e
check_thread_list (const td_thrhandle_t *th, psaddr_t head) check_thread_list (const td_thrhandle_t *th, psaddr_t head)
{ {
list_t list; td_err_e err;
td_err_e result = TD_NOTHR; psaddr_t next, ofs;
if (ps_pdread (th->th_ta_p->ph, head, &list.next, sizeof (list.next)) err = DB_GET_FIELD (next, th->th_ta_p, head, list_t, next, 0);
!= PS_OK) if (err == TD_OK)
return TD_ERR; /* XXX Other error value? */ {
if (next == 0)
return TD_NOTHR;
err = DB_GET_FIELD_ADDRESS (ofs, th->th_ta_p, 0, pthread, list, 0);
}
while (list.next != head) while (err == TD_OK)
if ((psaddr_t) list.next - offsetof (struct pthread, list) {
== th->th_unique) if (next == head)
{ return TD_NOTHR;
result = TD_OK;
break;
}
else if (ps_pdread (th->th_ta_p->ph, list.next, &list.next,
sizeof (list.next)) != PS_OK)
{
result = TD_ERR; /* XXX Other error value? */
break;
}
return result; if (next - (ofs - (psaddr_t) 0) == th->th_unique)
return TD_OK;
err = DB_GET_FIELD (next, th->th_ta_p, next, list_t, next, 0);
}
return err;
} }
td_err_e td_err_e
td_thr_validate (const td_thrhandle_t *th) td_thr_validate (const td_thrhandle_t *th)
{ {
td_err_e err;
psaddr_t list;
LOG ("td_thr_validate"); LOG ("td_thr_validate");
/* First check the list with threads using user allocated stacks. */ /* First check the list with threads using user allocated stacks. */
td_err_e result = check_thread_list (th, th->th_ta_p->stack_user); err = DB_GET_SYMBOL (list, th->th_ta_p, __stack_user);
if (err == TD_OK)
err = check_thread_list (th, list);
/* If our thread is not on this list search the list with stack /* If our thread is not on this list search the list with stack
using implementation allocated stacks. */ using implementation allocated stacks. */
if (result == TD_NOTHR) if (err == TD_NOTHR)
result = check_thread_list (th, th->th_ta_p->stack_used); {
err = DB_GET_SYMBOL (list, th->th_ta_p, stack_used);
if (err == TD_OK)
err = check_thread_list (th, list);
}
return result; return err;
} }

View File

@ -56,7 +56,7 @@ typedef enum
TD_TLSDEFER, /* Thread has not yet allocated TLS for given module. */ TD_TLSDEFER, /* Thread has not yet allocated TLS for given module. */
TD_NOTALLOC = TD_TLSDEFER, TD_NOTALLOC = TD_TLSDEFER,
TD_VERSION, /* Version if libpthread and libthread_db do not match. */ TD_VERSION, /* Version if libpthread and libthread_db do not match. */
TD_NOTLS /* There is TLS segment in the given module. */ TD_NOTLS /* There is no TLS segment in the given module. */
} td_err_e; } td_err_e;
@ -412,8 +412,8 @@ extern td_err_e td_thr_tlsbase (const td_thrhandle_t *__th,
/* Get address of thread local variable. */ /* Get address of thread local variable. */
extern td_err_e td_thr_tls_get_addr (const td_thrhandle_t *__th, extern td_err_e td_thr_tls_get_addr (const td_thrhandle_t *__th,
void *__map_address, size_t __offset, psaddr_t __map_address, size_t __offset,
void **__address); psaddr_t *__address);
/* Enable reporting for EVENT for thread TH. */ /* Enable reporting for EVENT for thread TH. */

View File

@ -1,30 +1,54 @@
/* Private header for thread debug library. */ /* Private header for thread debug library
Copyright (C) 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#ifndef _THREAD_DBP_H #ifndef _THREAD_DBP_H
#define _THREAD_DBP_H 1 #define _THREAD_DBP_H 1
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#include <string.h> #include <string.h>
#include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <assert.h>
#include "proc_service.h" #include "proc_service.h"
#include "thread_db.h" #include "thread_db.h"
#include "../nptl/pthreadP.h" #include "../nptl/pthreadP.h" /* This is for *_BITMASK only. */
#include <list.h>
/* Indeces for the symbol names. */ /* Indeces for the symbol names. */
enum enum
{ {
SYM_PTHREAD_THREADS_EVENTS = 0, # define DB_STRUCT(type) SYM_SIZEOF_##type,
SYM_PTHREAD_LAST_EVENT, # define DB_STRUCT_FIELD(type, field) SYM_##type##_FIELD_##field,
SYM_PTHREAD_NTHREADS, # define DB_SYMBOL(name) SYM_##name,
SYM_PTHREAD_STACK_USED, # define DB_VARIABLE(name) SYM_##name, SYM_DESC_##name,
SYM_PTHREAD_STACK_USER, # include "structs.def"
SYM_PTHREAD_KEYS, # undef DB_STRUCT
SYM_PTHREAD_KEYS_MAX, # undef DB_STRUCT_FIELD
SYM_PTHREAD_SIZEOF_DESCR, # undef DB_SYMBOL
SYM_PTHREAD_CREATE_EVENT, # undef DB_VARIABLE
SYM_PTHREAD_DEATH_EVENT,
SYM_PTHREAD_VERSION, SYM_TH_UNIQUE_CONST_THREAD_AREA,
SYM_TH_UNIQUE_REGISTER64,
SYM_TH_UNIQUE_REGISTER32,
SYM_TH_UNIQUE_REGISTER64_THREAD_AREA,
SYM_TH_UNIQUE_REGISTER32_THREAD_AREA,
SYM_NUM_MESSAGES SYM_NUM_MESSAGES
}; };
@ -32,50 +56,68 @@ enum
/* Comment out the following for less verbose output. */ /* Comment out the following for less verbose output. */
#ifndef NDEBUG #ifndef NDEBUG
# define LOG(c) if (__td_debug) __libc_write (2, c "\n", strlen (c "\n")) # define LOG(c) if (__td_debug) __libc_write (2, c "\n", strlen (c "\n"))
extern int __td_debug; extern int __td_debug attribute_hidden;
#else #else
# define LOG(c) # define LOG(c)
#endif #endif
#define DB_DESC_SIZE(desc) ((desc)[0])
#define DB_DESC_NELEM(desc) ((desc)[1])
#define DB_DESC_OFFSET(desc) ((int32_t) (desc)[2])
#define DB_SIZEOF_DESC (3 * sizeof (uint32_t))
#define DB_DEFINE_DESC(name, size, nelem, offset) \
const uint32_t name[3] = { (size), (nelem), (offset) }
typedef uint32_t db_desc_t[3];
/* Handle for a process. This type is opaque. */ /* Handle for a process. This type is opaque. */
struct td_thragent struct td_thragent
{ {
/* Chain on the list of all agent structures. */
list_t list;
/* Delivered by the debugger and we have to pass it back in the /* Delivered by the debugger and we have to pass it back in the
proc callbacks. */ proc callbacks. */
struct ps_prochandle *ph; struct ps_prochandle *ph;
/* Some cached information. */ /* Cached values read from the inferior. */
# define DB_STRUCT(type) \
uint32_t ta_sizeof_##type;
# define DB_STRUCT_FIELD(type, field) \
db_desc_t ta_field_##type##_##field;
# define DB_SYMBOL(name) \
psaddr_t ta_addr_##name;
# define DB_VARIABLE(name) \
psaddr_t ta_addr_##name; \
db_desc_t ta_var_##name;
# include "structs.def"
# undef DB_STRUCT
# undef DB_STRUCT_FIELD
# undef DB_SYMBOL
# undef DB_VARIABLE
/* Lists of running threads. */ /* The method of locating a thread's th_unique value. */
psaddr_t stack_used; enum
psaddr_t stack_user; {
ta_howto_unknown,
/* Address of the `pthread_keys' array. */ ta_howto_reg,
struct pthread_key_struct *keys; ta_howto_reg_thread_area,
ta_howto_const_thread_area
/* Maximum number of thread-local data keys. */ } ta_howto;
int pthread_keys_max; union
{
/* Size of 2nd level array for thread-local data keys. */ uint32_t const_thread_area; /* Constant argument to ps_get_thread_area. */
int pthread_key_2ndlevel_size; /* These are as if the descriptor of the field in prregset_t,
but DB_DESC_NELEM is overloaded as follows: */
/* Sizeof struct _pthread_descr_struct. */ db_desc_t reg; /* Signed bias applied to register value. */
int sizeof_descr; db_desc_t reg_thread_area; /* Bits to scale down register value. */
} ta_howto_data;
/* Pointer to the `__pthread_threads_events' variable in the target. */
psaddr_t pthread_threads_eventsp;
/* Pointer to the `__pthread_last_event' variable in the target. */
psaddr_t pthread_last_event;
/* List head the queue agent structures. */
list_t list;
}; };
/* List of all known descriptors. */ /* List of all known descriptors. */
extern list_t __td_agent_list; extern list_t __td_agent_list attribute_hidden;
/* Function used to test for correct thread agent pointer. */ /* Function used to test for correct thread agent pointer. */
@ -93,6 +135,115 @@ ta_ok (const td_thragent_t *ta)
/* Internal wrapper around ps_pglobal_lookup. */ /* Internal wrapper around ps_pglobal_lookup. */
extern int td_lookup (struct ps_prochandle *ps, int idx, psaddr_t *sym_addr); extern ps_err_e td_lookup (struct ps_prochandle *ps,
int idx, psaddr_t *sym_addr) attribute_hidden;
/* Store in psaddr_t VAR the address of inferior's symbol NAME. */
#define DB_GET_SYMBOL(var, ta, name) \
(((ta)->ta_addr_##name == 0 \
&& td_lookup ((ta)->ph, SYM_##name, &(ta)->ta_addr_##name) != PS_OK) \
? TD_ERR : ((var) = (ta)->ta_addr_##name, TD_OK))
/* Store in psaddr_t VAR the value of ((TYPE) PTR)->FIELD[IDX] in the inferior.
A target field smaller than psaddr_t is zero-extended. */
#define DB_GET_FIELD(var, ta, ptr, type, field, idx) \
_td_fetch_value ((ta), (ta)->ta_field_##type##_##field, \
SYM_##type##_FIELD_##field, \
(psaddr_t) 0 + (idx), (ptr), &(var))
#define DB_GET_FIELD_ADDRESS(var, ta, ptr, type, field, idx) \
((var) = (ptr), _td_locate_field ((ta), (ta)->ta_field_##type##_##field, \
SYM_##type##_FIELD_##field, \
(psaddr_t) 0 + (idx), &(var)))
extern td_err_e _td_locate_field (td_thragent_t *ta,
db_desc_t desc, int descriptor_name,
psaddr_t idx,
psaddr_t *address) attribute_hidden;
/* Like DB_GET_FIELD, but PTR is a local pointer to a structure that
has already been copied in from the inferior. */
#define DB_GET_FIELD_LOCAL(var, ta, ptr, type, field, idx) \
_td_fetch_value_local ((ta), (ta)->ta_field_##type##_##field, \
SYM_##type##_FIELD_##field, \
(psaddr_t) 0 + (idx), (ptr), &(var))
/* Store in psaddr_t VAR the value of variable NAME[IDX] in the inferior.
A target value smaller than psaddr_t is zero-extended. */
#define DB_GET_VALUE(var, ta, name, idx) \
(((ta)->ta_addr_##name == 0 \
&& td_lookup ((ta)->ph, SYM_##name, &(ta)->ta_addr_##name) != PS_OK) \
? TD_ERR \
: _td_fetch_value ((ta), (ta)->ta_var_##name, SYM_DESC_##name, \
(psaddr_t) 0 + (idx), (ta)->ta_addr_##name, &(var)))
/* Helper functions for those. */
extern td_err_e _td_fetch_value (td_thragent_t *ta,
db_desc_t field, int descriptor_name,
psaddr_t idx, psaddr_t address,
psaddr_t *result) attribute_hidden;
extern td_err_e _td_fetch_value_local (td_thragent_t *ta,
db_desc_t field,
int descriptor_name,
psaddr_t idx, void *address,
psaddr_t *result) attribute_hidden;
/* Store psaddr_t VALUE in ((TYPE) PTR)->FIELD[IDX] in the inferior.
A target field smaller than psaddr_t is zero-extended. */
#define DB_PUT_FIELD(ta, ptr, type, field, idx, value) \
_td_store_value ((ta), (ta)->ta_field_##type##_##field, \
SYM_##type##_FIELD_##field, \
(psaddr_t) 0 + (idx), (ptr), (value))
#define DB_PUT_FIELD_LOCAL(ta, ptr, type, field, idx, value) \
_td_store_value_local ((ta), (ta)->ta_field_##type##_##field, \
SYM_##type##_FIELD_##field, \
(psaddr_t) 0 + (idx), (ptr), (value))
/* Store psaddr_t VALUE in variable NAME[IDX] in the inferior.
A target field smaller than psaddr_t is zero-extended. */
#define DB_PUT_VALUE(ta, name, idx, value) \
(((ta)->ta_addr_##name == 0 \
&& td_lookup ((ta)->ph, SYM_##name, &(ta)->ta_addr_##name) != PS_OK) \
? TD_ERR \
: _td_store_value ((ta), (ta)->ta_var_##name, SYM_DESC_##name, \
(psaddr_t) 0 + (idx), (ta)->ta_addr_##name, (value)))
/* Helper functions for those. */
extern td_err_e _td_store_value (td_thragent_t *ta,
db_desc_t field, int descriptor_name,
psaddr_t idx, psaddr_t address,
psaddr_t value) attribute_hidden;
extern td_err_e _td_store_value_local (td_thragent_t *ta,
db_desc_t field, int descriptor_name,
psaddr_t idx, void *address,
psaddr_t value) attribute_hidden;
#define DB_GET_STRUCT(var, ta, ptr, type) \
({ td_err_e _err = TD_OK; \
if ((ta)->ta_sizeof_##type == 0) \
_err = _td_check_sizeof ((ta), &(ta)->ta_sizeof_##type, \
SYM_SIZEOF_##type); \
if (_err == TD_OK) \
_err = ps_pdread ((ta)->ph, (ptr), \
(var) = __alloca ((ta)->ta_sizeof_##type), \
(ta)->ta_sizeof_##type) \
== PS_OK ? TD_OK : TD_ERR; \
else \
(var) = NULL; \
_err; \
})
#define DB_PUT_STRUCT(ta, ptr, type, copy) \
({ assert ((ta)->ta_sizeof_##type != 0); \
ps_pdwrite ((ta)->ph, (ptr), (copy), (ta)->ta_sizeof_##type) \
== PS_OK ? TD_OK : TD_ERR; \
})
extern td_err_e _td_check_sizeof (td_thragent_t *ta, uint32_t *sizep,
int sizep_name) attribute_hidden;
#endif /* thread_dbP.h */ #endif /* thread_dbP.h */