* 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:
parent
416be7f049
commit
7f08f55a9f
10
ChangeLog
10
ChangeLog
@ -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>
|
||||
|
||||
* sysdeps/unix/sysv/linux/x86_64/register-dump.h: Undo last change.
|
||||
|
@ -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>
|
||||
|
||||
* sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Change type
|
||||
|
@ -60,9 +60,6 @@ struct pthread_key_struct __pthread_keys[PTHREAD_KEYS_MAX]
|
||||
__attribute__ ((nocommon));
|
||||
hidden_data_def (__pthread_keys)
|
||||
|
||||
/* This is for libthread_db only. */
|
||||
const int __pthread_pthread_sizeof_descr = sizeof (struct pthread);
|
||||
|
||||
struct pthread *
|
||||
internal_function
|
||||
__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,
|
||||
GLIBC_2_0);
|
||||
#endif
|
||||
|
||||
/* Information for libthread_db. */
|
||||
|
||||
#include "../nptl_db/db_info.c"
|
||||
|
@ -24,12 +24,6 @@
|
||||
/* Internal mutex for __pthread_keys table handling. */
|
||||
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
|
||||
__pthread_key_create (key, destr)
|
||||
pthread_key_t *key;
|
||||
|
@ -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;
|
||||
}
|
@ -118,6 +118,10 @@ typedef struct
|
||||
((struct pthread *) (__builtin_thread_pointer () \
|
||||
- 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
|
||||
sometimes more expensive than necessary as in this case. */
|
||||
# define THREAD_ID (__builtin_thread_pointer ())
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -251,6 +251,11 @@ union user_desc_init
|
||||
: "i" (offsetof (struct pthread, header.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. */
|
||||
# define THREAD_GETMEM(descr, member) \
|
||||
|
@ -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;
|
||||
}
|
@ -113,6 +113,9 @@ register struct pthread *__thread_self __asm__("r13");
|
||||
/* Return the thread descriptor for the current thread. */
|
||||
# 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. */
|
||||
#define THREAD_GETMEM(descr, member) \
|
||||
descr->member
|
||||
|
@ -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;
|
||||
}
|
@ -129,6 +129,13 @@ register void *__thread_register __asm__ ("r13");
|
||||
((struct pthread *) (__thread_register \
|
||||
- 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. */
|
||||
# define THREAD_GETMEM(descr, member) ((void)(descr), (THREAD_SELF)->member)
|
||||
|
||||
|
@ -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;
|
||||
}
|
@ -137,6 +137,9 @@ typedef struct
|
||||
/* Return the thread descriptor for the current thread. */
|
||||
# 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. */
|
||||
#define THREAD_GETMEM(descr, member) \
|
||||
descr->member
|
||||
|
@ -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;
|
||||
}
|
@ -117,6 +117,9 @@ typedef struct
|
||||
__asm ("stc gbr,%0" : "=r" (__self)); \
|
||||
__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. */
|
||||
# define THREAD_GETMEM(descr, member) (descr->member)
|
||||
|
||||
|
@ -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;
|
||||
}
|
@ -104,6 +104,11 @@ register struct pthread *__thread_self __asm__("%g7");
|
||||
/* Return the thread descriptor for the current thread. */
|
||||
#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. */
|
||||
#define THREAD_GETMEM(descr, member) \
|
||||
descr->member
|
||||
|
@ -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;
|
||||
}
|
@ -161,6 +161,9 @@ typedef struct
|
||||
: "i" (offsetof (struct pthread, header.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. */
|
||||
# define THREAD_GETMEM(descr, member) \
|
||||
|
@ -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>
|
||||
|
||||
* td_thr_event_enable.c (td_thr_event_enable): Use proper type `bool'
|
||||
|
@ -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_ta_set_event td_ta_event_getmsg \
|
||||
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))
|
||||
|
||||
# The ps_* callback functions are not defined.
|
||||
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
|
||||
|
||||
# Depend on libc.so so a DT_NEEDED is generated in the shared objects.
|
||||
|
98
nptl_db/db_info.c
Normal file
98
nptl_db/db_info.c
Normal 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
283
nptl_db/fetch-value.c
Normal 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;
|
||||
}
|
@ -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.
|
||||
|
||||
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. */
|
||||
#include <sys/procfs.h>
|
||||
|
||||
/* Functions in this interface return one of these status codes. */
|
||||
typedef enum
|
||||
{
|
||||
PS_OK, /* generic "call succeeded" */
|
||||
PS_ERR, /* generic. */
|
||||
PS_BADPID, /* bad process handle */
|
||||
PS_BADLID, /* bad lwp identifier */
|
||||
PS_BADADDR, /* bad address */
|
||||
PS_NOSYM, /* p_lookup() could not find given symbol */
|
||||
PS_NOFREGS
|
||||
/*
|
||||
* FPU register set not available for given
|
||||
* lwp
|
||||
*/
|
||||
} ps_err_e;
|
||||
PS_OK, /* Generic "call succeeded". */
|
||||
PS_ERR, /* Generic error. */
|
||||
PS_BADPID, /* Bad process handle. */
|
||||
PS_BADLID, /* Bad LWP identifier. */
|
||||
PS_BADADDR, /* Bad address. */
|
||||
PS_NOSYM, /* Could not find given symbol. */
|
||||
PS_NOFREGS /* 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 *,
|
||||
psaddr_t, void *, size_t);
|
||||
extern ps_err_e ps_pdwrite(struct ps_prochandle *,
|
||||
psaddr_t, const void *, size_t);
|
||||
extern ps_err_e ps_ptread(struct ps_prochandle *,
|
||||
psaddr_t, 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);
|
||||
/* Read or write process memory at the given address. */
|
||||
extern ps_err_e ps_pdread (struct ps_prochandle *,
|
||||
psaddr_t, void *, size_t);
|
||||
extern ps_err_e ps_pdwrite (struct ps_prochandle *,
|
||||
psaddr_t, const void *, size_t);
|
||||
extern ps_err_e ps_ptread (struct ps_prochandle *,
|
||||
psaddr_t, void *, size_t);
|
||||
extern ps_err_e ps_ptwrite (struct ps_prochandle *,
|
||||
psaddr_t, const void *, size_t);
|
||||
|
||||
|
||||
extern ps_err_e ps_lgetregs(struct ps_prochandle *,
|
||||
lwpid_t, prgregset_t);
|
||||
extern ps_err_e ps_lsetregs(struct ps_prochandle *,
|
||||
lwpid_t, const prgregset_t);
|
||||
extern ps_err_e ps_lgetfpregs(struct ps_prochandle *,
|
||||
lwpid_t, prfpregset_t *);
|
||||
extern ps_err_e ps_lsetfpregs(struct ps_prochandle *,
|
||||
lwpid_t, const prfpregset_t *);
|
||||
/* Get and set the given LWP's general or FPU register set. */
|
||||
extern ps_err_e ps_lgetregs (struct ps_prochandle *,
|
||||
lwpid_t, prgregset_t);
|
||||
extern ps_err_e ps_lsetregs (struct ps_prochandle *,
|
||||
lwpid_t, const prgregset_t);
|
||||
extern ps_err_e ps_lgetfpregs (struct ps_prochandle *,
|
||||
lwpid_t, 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 *);
|
||||
|
||||
/* 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_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_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
86
nptl_db/structs.def
Normal 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
|
@ -25,17 +25,26 @@
|
||||
|
||||
static const char *symbol_list_arr[] =
|
||||
{
|
||||
[SYM_PTHREAD_THREADS_EVENTS] = "__nptl_threads_events",
|
||||
[SYM_PTHREAD_LAST_EVENT] = "__nptl_last_event",
|
||||
[SYM_PTHREAD_NTHREADS] = "__nptl_nthreads",
|
||||
[SYM_PTHREAD_STACK_USED] = "stack_used",
|
||||
[SYM_PTHREAD_STACK_USER] = "__stack_user",
|
||||
[SYM_PTHREAD_KEYS] = "__pthread_keys",
|
||||
[SYM_PTHREAD_KEYS_MAX] = "__pthread_pthread_keys_max",
|
||||
[SYM_PTHREAD_SIZEOF_DESCR] = "__pthread_pthread_sizeof_descr",
|
||||
[SYM_PTHREAD_CREATE_EVENT] = "__nptl_create_event",
|
||||
[SYM_PTHREAD_DEATH_EVENT] = "__nptl_death_event",
|
||||
[SYM_PTHREAD_VERSION] = "nptl_version",
|
||||
# define DB_STRUCT(type) \
|
||||
[SYM_SIZEOF_##type] = "_thread_db_sizeof_" #type,
|
||||
# define DB_STRUCT_FIELD(type, field) \
|
||||
[SYM_##type##_FIELD_##field] = "_thread_db_" #type "_" #field,
|
||||
# define DB_SYMBOL(name) \
|
||||
[SYM_##name] = #name,
|
||||
# define DB_VARIABLE(name) \
|
||||
[SYM_##name] = #name, \
|
||||
[SYM_DESC_##name] = "_thread_db_" #name,
|
||||
# include "structs.def"
|
||||
# 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
|
||||
};
|
||||
|
||||
@ -47,7 +56,7 @@ td_symbol_list (void)
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ps_err_e
|
||||
td_lookup (struct ps_prochandle *ps, int idx, psaddr_t *sym_addr)
|
||||
{
|
||||
assert (idx >= 0 && idx < SYM_NUM_MESSAGES);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* 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.
|
||||
Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
|
||||
|
||||
@ -22,31 +22,58 @@
|
||||
|
||||
|
||||
td_err_e
|
||||
td_ta_clear_event (ta, event)
|
||||
const td_thragent_t *ta;
|
||||
td_ta_clear_event (ta_arg, event)
|
||||
const td_thragent_t *ta_arg;
|
||||
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");
|
||||
|
||||
/* Test whether the TA parameter is ok. */
|
||||
if (! ta_ok (ta))
|
||||
return TD_BADTA;
|
||||
|
||||
/* Write the new value into the thread data structure. */
|
||||
td_thr_events_t old_event;
|
||||
if (ps_pdread (ta->ph, ta->pthread_threads_eventsp,
|
||||
&old_event, sizeof (td_thrhandle_t)) != PS_OK)
|
||||
return TD_ERR; /* XXX Other error value? */
|
||||
/* Fetch the old event mask from the inferior and modify it in place. */
|
||||
err = DB_GET_SYMBOL (eventmask, ta, __nptl_threads_events);
|
||||
if (err == TD_OK)
|
||||
err = DB_GET_STRUCT (copy, ta, eventmask, td_thr_events_t);
|
||||
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. */
|
||||
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;
|
||||
return err;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* 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.
|
||||
Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
|
||||
|
||||
@ -22,10 +22,12 @@
|
||||
|
||||
|
||||
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;
|
||||
int idx = -1;
|
||||
td_thragent_t *const ta = (td_thragent_t *) ta_arg;
|
||||
td_err_e err;
|
||||
psaddr_t taddr;
|
||||
|
||||
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)
|
||||
{
|
||||
case TD_CREATE:
|
||||
idx = SYM_PTHREAD_CREATE_EVENT;
|
||||
err = DB_GET_SYMBOL (taddr, ta, __nptl_create_event);
|
||||
break;
|
||||
|
||||
case TD_DEATH:
|
||||
idx = SYM_PTHREAD_DEATH_EVENT;
|
||||
err = DB_GET_SYMBOL (taddr, ta, __nptl_death_event);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Event cannot be handled. */
|
||||
break;
|
||||
return TD_NOEVENT;
|
||||
}
|
||||
|
||||
/* Now get the address. */
|
||||
if (idx != -1)
|
||||
if (err == TD_OK)
|
||||
{
|
||||
psaddr_t taddr;
|
||||
|
||||
if (td_lookup (ta->ph, idx, &taddr) == PS_OK)
|
||||
{
|
||||
/* Success, we got the address. */
|
||||
addr->type = NOTIFY_BPT;
|
||||
addr->u.bptaddr = taddr;
|
||||
|
||||
res = TD_OK;
|
||||
}
|
||||
else
|
||||
res = TD_ERR;
|
||||
/* Success, we got the address. */
|
||||
addr->type = NOTIFY_BPT;
|
||||
addr->u.bptaddr = taddr;
|
||||
}
|
||||
|
||||
return res;
|
||||
return err;
|
||||
}
|
||||
|
@ -25,76 +25,81 @@
|
||||
|
||||
|
||||
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 Use at least __thread once it is possible. */
|
||||
static td_thrhandle_t th;
|
||||
|
||||
LOG ("td_ta_event_getmsg");
|
||||
LOG ("td_thr_event_getmsg");
|
||||
|
||||
/* Test whether the TA parameter is ok. */
|
||||
if (! ta_ok (ta))
|
||||
return TD_BADTA;
|
||||
|
||||
/* Get the pointer to the thread descriptor with the last event. */
|
||||
psaddr_t addr;
|
||||
if (ps_pdread (ta->ph, ta->pthread_last_event,
|
||||
&addr, sizeof (struct pthread *)) != PS_OK)
|
||||
return TD_ERR; /* XXX Other error value? */
|
||||
err = DB_GET_VALUE (thp, ta, __nptl_last_event, 0);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
|
||||
if (addr == 0)
|
||||
if (thp == 0)
|
||||
/* Nothing waiting. */
|
||||
return TD_NOMSG;
|
||||
|
||||
/* Read the event structure from the target. */
|
||||
td_eventbuf_t event;
|
||||
if (ps_pdread (ta->ph, (char *) addr + offsetof (struct pthread, eventbuf),
|
||||
&event, sizeof (td_eventbuf_t)) != PS_OK)
|
||||
return TD_ERR; /* XXX Other error value? */
|
||||
/* Copy the event message buffer in from the inferior. */
|
||||
err = DB_GET_FIELD_ADDRESS (eventbuf, ta, thp, pthread, eventbuf, 0);
|
||||
if (err == TD_OK)
|
||||
err = DB_GET_STRUCT (copy, ta, eventbuf, td_eventbuf_t);
|
||||
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 (event.eventnum == TD_EVENT_NONE)
|
||||
if ((int) (uintptr_t) eventnum == TD_EVENT_NONE)
|
||||
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. */
|
||||
th.th_ta_p = (td_thragent_t *) ta;
|
||||
th.th_unique = addr;
|
||||
th.th_unique = thp;
|
||||
|
||||
/* 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->msg.data = (uintptr_t) event.eventdata;
|
||||
|
||||
/* And clear the event message in the target. */
|
||||
memset (&event, '\0', sizeof (td_eventbuf_t));
|
||||
if (ps_pdwrite (ta->ph, (char *) addr + offsetof (struct pthread, eventbuf),
|
||||
&event, sizeof (td_eventbuf_t)) != PS_OK)
|
||||
return TD_ERR; /* XXX Other error value? */
|
||||
memset (copy, 0, ta->ta_sizeof_td_eventbuf_t);
|
||||
err = DB_PUT_STRUCT (ta, eventbuf, td_eventbuf_t, copy);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
|
||||
/* Get the pointer to the next descriptor with an event. */
|
||||
psaddr_t next;
|
||||
if (ps_pdread (ta->ph, (char *) addr + offsetof (struct pthread, nextevent),
|
||||
&next, sizeof (struct pthread *)) != PS_OK)
|
||||
return TD_ERR; /* XXX Other error value? */
|
||||
|
||||
if (next == addr)
|
||||
return TD_DBERR;
|
||||
err = DB_GET_FIELD (next, ta, thp, pthread, nextevent, 0);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
|
||||
/* Store the pointer in the list head variable. */
|
||||
if (ps_pdwrite (ta->ph, ta->pthread_last_event,
|
||||
&next, sizeof (struct pthread *)) != PS_OK)
|
||||
return TD_ERR; /* XXX Other error value? */
|
||||
err = DB_PUT_VALUE (ta, __nptl_last_event, 0, next);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
|
||||
if (next != NULL)
|
||||
{
|
||||
/* Clear the next pointer in the current descriptor. */
|
||||
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? */
|
||||
}
|
||||
if (next != 0)
|
||||
/* Clear the next pointer in the current descriptor. */
|
||||
err = DB_PUT_FIELD (ta, thp, pthread, nextevent, 0, 0);
|
||||
|
||||
return TD_OK;
|
||||
return err;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* 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.
|
||||
Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
|
||||
|
||||
@ -21,21 +21,22 @@
|
||||
#include "thread_dbP.h"
|
||||
|
||||
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");
|
||||
|
||||
/* Test whether the TA parameter is ok. */
|
||||
if (! ta_ok (ta))
|
||||
return TD_BADTA;
|
||||
|
||||
/* Access the variable `__pthread_handles_num'. */
|
||||
psaddr_t addr;
|
||||
if (td_lookup (ta->ph, SYM_PTHREAD_NTHREADS, &addr) != PS_OK)
|
||||
return TD_ERR; /* XXX Other error value? */
|
||||
/* Access the variable in the inferior that tells us. */
|
||||
err = DB_GET_VALUE (n, ta, __nptl_nthreads, 0);
|
||||
if (err == TD_OK)
|
||||
*np = (uintptr_t) n;
|
||||
|
||||
if (ps_pdread (ta->ph, addr, np, sizeof (int)) != PS_OK)
|
||||
return TD_ERR; /* XXX Other error value? */
|
||||
|
||||
return TD_OK;
|
||||
return err;
|
||||
}
|
||||
|
179
nptl_db/td_ta_map_lwp2thr.c
Normal file
179
nptl_db/td_ta_map_lwp2thr.c
Normal 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;
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/* 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.
|
||||
Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
|
||||
|
||||
@ -34,30 +34,23 @@ LIST_HEAD (__td_agent_list);
|
||||
td_err_e
|
||||
td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta)
|
||||
{
|
||||
psaddr_t addr;
|
||||
psaddr_t versaddr;
|
||||
char versbuf[sizeof (VERSION)];
|
||||
|
||||
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. */
|
||||
if (td_lookup (ps, SYM_PTHREAD_VERSION, &versaddr) != PS_OK)
|
||||
return TD_VERSION;
|
||||
if (td_lookup (ps, SYM_nptl_version, &versaddr) != PS_OK)
|
||||
return TD_NOLIBTHREAD;
|
||||
if (ps_pdread (ps, versaddr, versbuf, sizeof (versbuf)) != PS_OK)
|
||||
return TD_ERR;
|
||||
|
||||
if (versbuf[sizeof (versbuf) - 1] != '\0' || strcmp (versbuf, VERSION) != 0)
|
||||
if (memcmp (versbuf, VERSION, sizeof VERSION) != 0)
|
||||
/* Not the right version. */
|
||||
return TD_VERSION;
|
||||
|
||||
/* 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)
|
||||
return TD_MALLOC;
|
||||
|
||||
@ -65,49 +58,6 @@ td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta)
|
||||
back into the debugger. */
|
||||
(*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. */
|
||||
list_add (&(*ta)->list, &__td_agent_list);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* 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.
|
||||
Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
|
||||
|
||||
@ -22,31 +22,58 @@
|
||||
|
||||
|
||||
td_err_e
|
||||
td_ta_set_event (ta, event)
|
||||
const td_thragent_t *ta;
|
||||
td_ta_set_event (ta_arg, event)
|
||||
const td_thragent_t *ta_arg;
|
||||
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");
|
||||
|
||||
/* Test whether the TA parameter is ok. */
|
||||
if (! ta_ok (ta))
|
||||
return TD_BADTA;
|
||||
|
||||
/* Write the new value into the thread data structure. */
|
||||
td_thr_events_t old_event;
|
||||
if (ps_pdread (ta->ph, ta->pthread_threads_eventsp,
|
||||
&old_event, sizeof (td_thrhandle_t)) != PS_OK)
|
||||
return TD_ERR; /* XXX Other error value? */
|
||||
/* Fetch the old event mask from the inferior and modify it in place. */
|
||||
err = DB_GET_SYMBOL (eventmask, ta, __nptl_threads_events);
|
||||
if (err == TD_OK)
|
||||
err = DB_GET_STRUCT (copy, ta, eventmask, td_thr_events_t);
|
||||
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. */
|
||||
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;
|
||||
return err;
|
||||
}
|
||||
|
@ -19,102 +19,108 @@
|
||||
02111-1307 USA. */
|
||||
|
||||
#include "thread_dbP.h"
|
||||
#include <nptl/descr.h>
|
||||
|
||||
|
||||
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,
|
||||
psaddr_t head)
|
||||
psaddr_t head, int fake_empty)
|
||||
{
|
||||
list_t list;
|
||||
td_err_e result = TD_OK;
|
||||
td_err_e err;
|
||||
psaddr_t next, ofs;
|
||||
void *copy;
|
||||
|
||||
/* Test the state.
|
||||
XXX This is incomplete. Normally this test should be in the loop. */
|
||||
if (state != TD_THR_ANY_STATE)
|
||||
return TD_OK;
|
||||
|
||||
if (ps_pdread (ta->ph, head, &list, sizeof (list_t)) != PS_OK)
|
||||
return TD_ERR; /* XXX Other error value? */
|
||||
err = DB_GET_FIELD (next, ta, head, list_t, next, 0);
|
||||
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.
|
||||
There is just the main thread to return. */
|
||||
td_thrhandle_t th;
|
||||
td_err_e err = td_ta_map_lwp2thr (ta, ps_getpid (ta->ph), &th);
|
||||
return (err != TD_OK ? err
|
||||
: callback (&th, cbdata_p) != 0 ? TD_DBERR : TD_OK);
|
||||
err = td_ta_map_lwp2thr (ta, ps_getpid (ta->ph), &th);
|
||||
if (err == 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;
|
||||
if (ps_pdread (ta->ph, &((struct pthread *) addr)->schedpolicy,
|
||||
&schedpolicy, sizeof (int)) != PS_OK)
|
||||
{
|
||||
result = TD_ERR; /* XXX Other error value? */
|
||||
break;
|
||||
}
|
||||
while (next != head)
|
||||
{
|
||||
psaddr_t addr, schedpolicy, schedprio;
|
||||
|
||||
struct sched_param schedparam;
|
||||
if (ps_pdread (ta->ph, &((struct pthread *) addr)->schedparam,
|
||||
&schedparam, sizeof (struct sched_param)) != PS_OK)
|
||||
{
|
||||
result = TD_ERR; /* XXX Other error value? */
|
||||
break;
|
||||
}
|
||||
addr = next - (ofs - (psaddr_t) 0);
|
||||
if (next == 0 || addr == 0) /* Sanity check. */
|
||||
return TD_DBERR;
|
||||
|
||||
/* Now test whether this thread matches the specified
|
||||
conditions. */
|
||||
/* Copy the whole descriptor in once so we can access the several
|
||||
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. */
|
||||
int descr_pri = (schedpolicy == SCHED_OTHER
|
||||
? 0 : schedparam.sched_priority);
|
||||
int descr_pri = ((uintptr_t) schedpolicy == SCHED_OTHER
|
||||
? 0 : (uintptr_t) schedprio);
|
||||
if (descr_pri >= ti_pri)
|
||||
{
|
||||
/* XXX For now we ignore threads which are not running anymore.
|
||||
The reason is that gdb tries to get the registers and fails.
|
||||
In future we should have a special mode of the thread library
|
||||
in which we keep the process around until the actual join
|
||||
operation happened. */
|
||||
int cancelhandling;
|
||||
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;
|
||||
}
|
||||
/* 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. */
|
||||
if (ps_pdread (ta->ph, &((struct pthread *) addr)->list,
|
||||
&list, sizeof (list_t)) != PS_OK)
|
||||
return TD_ERR; /* XXX Other error value? */
|
||||
err = DB_GET_FIELD_LOCAL (next, ta, copy + (ofs - (psaddr_t) 0), list_t,
|
||||
next, 0);
|
||||
if (err != TD_OK)
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
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");
|
||||
|
||||
/* 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
|
||||
have to iterate over both lists separately. We start with the
|
||||
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. */
|
||||
if (result == TD_OK)
|
||||
result = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri,
|
||||
ta->stack_used);
|
||||
if (err == TD_OK)
|
||||
err = DB_GET_SYMBOL (list, ta, stack_used);
|
||||
if (err == TD_OK)
|
||||
err = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri, list, 0);
|
||||
|
||||
return result;
|
||||
return err;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* 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.
|
||||
Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
|
||||
|
||||
@ -22,32 +22,60 @@
|
||||
#include <alloca.h>
|
||||
|
||||
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)
|
||||
{
|
||||
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");
|
||||
|
||||
/* Test whether the TA parameter is ok. */
|
||||
if (! ta_ok (ta))
|
||||
return TD_BADTA;
|
||||
|
||||
int pthread_keys_max = ta->pthread_keys_max;
|
||||
struct pthread_key_struct *keys;
|
||||
keys = (struct pthread_key_struct *) alloca (sizeof (keys[0])
|
||||
* pthread_keys_max);
|
||||
/* This makes sure we have the size information on hand. */
|
||||
addr = 0;
|
||||
err = _td_locate_field (ta,
|
||||
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. */
|
||||
if (ps_pdread (ta->ph, ta->keys, keys,
|
||||
sizeof (keys[0]) * pthread_keys_max) != PS_OK)
|
||||
return TD_ERR; /* XXX Other error value? */
|
||||
/* Now copy in the entire array of key descriptors. */
|
||||
keys_elemsize = (addr - (psaddr_t) 0) / 8;
|
||||
keys_nb = keys_elemsize * DB_DESC_NELEM (ta->ta_var___pthread_keys);
|
||||
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. */
|
||||
int cnt;
|
||||
for (cnt = 0; cnt < pthread_keys_max; ++cnt)
|
||||
if (!KEY_UNUSED (keys[cnt].seq)
|
||||
/* Return with an error if the callback returns a nonzero value. */
|
||||
&& callback (cnt, keys[cnt].destr, cbdata_p) != 0)
|
||||
return TD_DBERR;
|
||||
for (idx = 0; idx < DB_DESC_NELEM (ta->ta_var___pthread_keys); ++idx)
|
||||
{
|
||||
psaddr_t seq, destr;
|
||||
err = DB_GET_FIELD_LOCAL (seq, ta, keys, pthread_key_struct, seq, 0);
|
||||
if (err != TD_OK)
|
||||
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;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* 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.
|
||||
Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
|
||||
|
||||
@ -28,27 +28,50 @@ td_thr_clear_event (th, event)
|
||||
const td_thrhandle_t *th;
|
||||
td_thr_events_t *event;
|
||||
{
|
||||
td_err_e err;
|
||||
psaddr_t eventmask;
|
||||
void *copy;
|
||||
|
||||
LOG ("td_thr_clear_event");
|
||||
|
||||
/* Write the new value into the thread data structure. */
|
||||
td_thr_events_t old_event;
|
||||
if (ps_pdread (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? */
|
||||
/* Fetch the old event mask from the inferior and modify it in place. */
|
||||
err = DB_GET_FIELD_ADDRESS (eventmask, th->th_ta_p,
|
||||
th->th_unique, pthread, eventbuf_eventmask, 0);
|
||||
if (err == TD_OK)
|
||||
err = DB_GET_STRUCT (copy, th->th_ta_p, eventmask, td_thr_events_t);
|
||||
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, 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. */
|
||||
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;
|
||||
return err;
|
||||
}
|
||||
|
@ -18,8 +18,6 @@
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA. */
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "thread_dbP.h"
|
||||
|
||||
|
||||
@ -31,12 +29,6 @@ td_thr_event_enable (th, onoff)
|
||||
LOG ("td_thr_event_enable");
|
||||
|
||||
/* Write the new value into the thread data structure. */
|
||||
const bool value = onoff != 0;
|
||||
if (ps_pdwrite (th->th_ta_p->ph,
|
||||
((char *) th->th_unique
|
||||
+ offsetof (struct pthread, report_events)),
|
||||
&value, sizeof value) != PS_OK)
|
||||
return TD_ERR; /* XXX Other error value? */
|
||||
|
||||
return TD_OK;
|
||||
return DB_PUT_FIELD (th->th_ta_p, th->th_unique, pthread, report_events, 0,
|
||||
(psaddr_t) 0 + (onoff != 0));
|
||||
}
|
||||
|
@ -18,60 +18,71 @@
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA. */
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "thread_dbP.h"
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
td_err_e
|
||||
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");
|
||||
|
||||
/* Read the event structure from the target. */
|
||||
if (ps_pdread (th->th_ta_p->ph,
|
||||
((char *) th->th_unique
|
||||
+ offsetof (struct pthread, eventbuf)),
|
||||
&event, sizeof (td_eventbuf_t)) != PS_OK)
|
||||
return TD_ERR; /* XXX Other error value? */
|
||||
/* Copy the event message buffer in from the inferior. */
|
||||
err = DB_GET_FIELD_ADDRESS (eventbuf, th->th_ta_p, th->th_unique, pthread,
|
||||
eventbuf, 0);
|
||||
if (err == TD_OK)
|
||||
err = DB_GET_STRUCT (copy, th->th_ta_p, eventbuf, td_eventbuf_t);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
|
||||
/* 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. */
|
||||
return TD_NOMSG;
|
||||
|
||||
/* 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->msg.data = (uintptr_t) event.eventdata;
|
||||
|
||||
/* And clear the event message in the target. */
|
||||
memset (&event, '\0', sizeof (td_eventbuf_t));
|
||||
if (ps_pdwrite (th->th_ta_p->ph,
|
||||
((char *) th->th_unique
|
||||
+ offsetof (struct pthread, eventbuf)),
|
||||
&event, sizeof (td_eventbuf_t)) != PS_OK)
|
||||
return TD_ERR; /* XXX Other error value? */
|
||||
memset (copy, 0, th->th_ta_p->ta_sizeof_td_eventbuf_t);
|
||||
err = DB_PUT_STRUCT (th->th_ta_p, eventbuf, td_eventbuf_t, copy);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
|
||||
/* 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.
|
||||
We must splice it out of the list so that there is no dangling
|
||||
pointer to it later when it dies. */
|
||||
psaddr_t thp, prevp = th->th_ta_p->pthread_last_event;
|
||||
if (ps_pdread (th->th_ta_p->ph,
|
||||
prevp, &thp, sizeof (struct pthread *)) != PS_OK)
|
||||
return TD_ERR; /* XXX Other error value? */
|
||||
err = DB_GET_SYMBOL (prevp, th->th_ta_p, __nptl_last_event);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
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)
|
||||
{
|
||||
if (ps_pdread (th->th_ta_p->ph,
|
||||
(char *) thp + offsetof (struct pthread, nextevent),
|
||||
&next, sizeof (struct pthread *)) != PS_OK)
|
||||
return TD_ERR; /* XXX Other error value? */
|
||||
psaddr_t next;
|
||||
err = DB_GET_FIELD (next, th->th_ta_p, th->th_unique, pthread,
|
||||
nextevent, 0);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
|
||||
if (next == thp)
|
||||
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)
|
||||
{
|
||||
/* 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;
|
||||
|
||||
if (ps_pdwrite (th->th_ta_p->ph, prevp, &next, sizeof next) != PS_OK)
|
||||
return TD_ERR; /* XXX Other error value? */
|
||||
err = _td_store_value (th->th_ta_p,
|
||||
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
|
||||
when the thread resumes and then chains on for its next event. */
|
||||
next = NULL;
|
||||
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;
|
||||
return DB_PUT_FIELD (th->th_ta_p, thp, pthread, nextevent, 0, 0);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -26,39 +26,85 @@
|
||||
td_err_e
|
||||
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");
|
||||
|
||||
/* Get the thread descriptor. */
|
||||
struct pthread pds;
|
||||
if (ps_pdread (th->th_ta_p->ph, th->th_unique, &pds,
|
||||
sizeof (struct pthread)) != PS_OK)
|
||||
return TD_ERR; /* XXX Other error value? */
|
||||
/* Copy the whole descriptor in once so we can access the several
|
||||
fields locally. Excess copying in one go is much better than
|
||||
multiple ps_pdread calls. */
|
||||
err = DB_GET_STRUCT (copy, th->th_ta_p, th->th_unique, pthread);
|
||||
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
|
||||
results for the fields we do not fill in. */
|
||||
memset (infop, '\0', sizeof (td_thrinfo_t));
|
||||
|
||||
infop->ti_tid = th->th_unique;
|
||||
infop->ti_tls = (char *) pds.specific;
|
||||
infop->ti_pri = (pds.schedpolicy == SCHED_OTHER
|
||||
? 0 : pds.schedparam.sched_priority);
|
||||
infop->ti_tid = (thread_t) th->th_unique;
|
||||
infop->ti_tls = (char *) tls;
|
||||
infop->ti_pri = ((uintptr_t) schedpolicy == SCHED_OTHER
|
||||
? 0 : (uintptr_t) schedprio);
|
||||
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. */
|
||||
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;
|
||||
else
|
||||
infop->ti_state = TD_THR_UNKNOWN;
|
||||
|
||||
/* 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_startfunc = pds.start_routine;
|
||||
memcpy (&infop->ti_events, &pds.eventbuf.eventmask,
|
||||
sizeof (td_thr_events_t));
|
||||
infop->ti_traceme = pds.report_events != false;
|
||||
infop->ti_lid = tid == 0 ? ps_getpid (th->th_ta_p->ph) : (uintptr_t) tid;
|
||||
infop->ti_traceme = report_events != 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -24,27 +24,28 @@
|
||||
td_err_e
|
||||
td_thr_getfpregs (const td_thrhandle_t *th, prfpregset_t *regset)
|
||||
{
|
||||
psaddr_t cancelhandling, tid;
|
||||
td_err_e err;
|
||||
|
||||
LOG ("td_thr_getfpregs");
|
||||
|
||||
/* We have to get the state and the PID for this thread. */
|
||||
int cancelhandling;
|
||||
if (ps_pdread (th->th_ta_p->ph,
|
||||
&((struct pthread *) th->th_unique)->cancelhandling,
|
||||
&cancelhandling, sizeof (int)) != PS_OK)
|
||||
return TD_ERR;
|
||||
err = DB_GET_FIELD (cancelhandling, th->th_ta_p, th->th_unique, pthread,
|
||||
cancelhandling, 0);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
|
||||
/* 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));
|
||||
/* Otherwise get the register content through the callback. */
|
||||
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,
|
||||
&((struct pthread *) th->th_unique)->tid,
|
||||
&tid, sizeof (pid_t)) != PS_OK
|
||||
|| ps_lgetfpregs (th->th_ta_p->ph, tid, regset) != PS_OK)
|
||||
if (ps_lgetfpregs (th->th_ta_p->ph, (uintptr_t) tid, regset) != PS_OK)
|
||||
return TD_ERR;
|
||||
}
|
||||
|
||||
|
@ -22,29 +22,30 @@
|
||||
|
||||
|
||||
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");
|
||||
|
||||
/* We have to get the state and the PID for this thread. */
|
||||
int cancelhandling;
|
||||
if (ps_pdread (th->th_ta_p->ph,
|
||||
&((struct pthread *) th->th_unique)->cancelhandling,
|
||||
&cancelhandling, sizeof (int)) != PS_OK)
|
||||
return TD_ERR;
|
||||
err = DB_GET_FIELD (cancelhandling, th->th_ta_p, th->th_unique, pthread,
|
||||
cancelhandling, 0);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
|
||||
/* If the thread already terminated we return all zeroes. */
|
||||
if (cancelhandling & TERMINATED_BITMASK)
|
||||
memset (gregs, '\0', sizeof (prgregset_t));
|
||||
if (((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK)
|
||||
memset (regset, '\0', sizeof (*regset));
|
||||
/* Otherwise get the register content through the callback. */
|
||||
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,
|
||||
&((struct pthread *) th->th_unique)->tid,
|
||||
&tid, sizeof (pid_t)) != PS_OK
|
||||
|| ps_lgetregs (th->th_ta_p->ph, tid, gregs) != PS_OK)
|
||||
if (ps_lgetregs (th->th_ta_p->ph, (uintptr_t) tid, regset) != PS_OK)
|
||||
return TD_ERR;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* 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.
|
||||
Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
|
||||
|
||||
@ -28,27 +28,50 @@ td_thr_set_event (th, event)
|
||||
const td_thrhandle_t *th;
|
||||
td_thr_events_t *event;
|
||||
{
|
||||
td_err_e err;
|
||||
psaddr_t eventmask;
|
||||
void *copy;
|
||||
|
||||
LOG ("td_thr_set_event");
|
||||
|
||||
/* Write the new value into the thread data structure. */
|
||||
td_thr_events_t old_event;
|
||||
if (ps_pdread (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? */
|
||||
/* Fetch the old event mask from the inferior and modify it in place. */
|
||||
err = DB_GET_FIELD_ADDRESS (eventmask, th->th_ta_p,
|
||||
th->th_unique, pthread, eventbuf_eventmask, 0);
|
||||
if (err == TD_OK)
|
||||
err = DB_GET_STRUCT (copy, th->th_ta_p, eventmask, td_thr_events_t);
|
||||
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, 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. */
|
||||
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;
|
||||
return err;
|
||||
}
|
||||
|
@ -24,24 +24,25 @@
|
||||
td_err_e
|
||||
td_thr_setfpregs (const td_thrhandle_t *th, const prfpregset_t *fpregs)
|
||||
{
|
||||
psaddr_t cancelhandling, tid;
|
||||
td_err_e err;
|
||||
|
||||
LOG ("td_thr_setfpregs");
|
||||
|
||||
/* We have to get the state and the PID for this thread. */
|
||||
int cancelhandling;
|
||||
if (ps_pdread (th->th_ta_p->ph,
|
||||
&((struct pthread *) th->th_unique)->cancelhandling,
|
||||
&cancelhandling, sizeof (int)) != PS_OK)
|
||||
return TD_ERR;
|
||||
err = DB_GET_FIELD (cancelhandling, th->th_ta_p, th->th_unique, pthread,
|
||||
cancelhandling, 0);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
|
||||
/* 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,
|
||||
&((struct pthread *) th->th_unique)->tid,
|
||||
&tid, sizeof (pid_t)) != PS_OK
|
||||
|| ps_lsetfpregs (th->th_ta_p->ph, tid, fpregs) != PS_OK)
|
||||
if (ps_lsetfpregs (th->th_ta_p->ph, (uintptr_t) tid, fpregs) != PS_OK)
|
||||
return TD_ERR;
|
||||
}
|
||||
|
||||
|
@ -24,24 +24,25 @@
|
||||
td_err_e
|
||||
td_thr_setgregs (const td_thrhandle_t *th, prgregset_t gregs)
|
||||
{
|
||||
psaddr_t cancelhandling, tid;
|
||||
td_err_e err;
|
||||
|
||||
LOG ("td_thr_setgregs");
|
||||
|
||||
/* We have to get the state and the PID for this thread. */
|
||||
int cancelhandling;
|
||||
if (ps_pdread (th->th_ta_p->ph,
|
||||
&((struct pthread *) th->th_unique)->cancelhandling,
|
||||
&cancelhandling, sizeof (int)) != PS_OK)
|
||||
return TD_ERR;
|
||||
err = DB_GET_FIELD (cancelhandling, th->th_ta_p, th->th_unique, pthread,
|
||||
cancelhandling, 0);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
|
||||
/* 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,
|
||||
&((struct pthread *) th->th_unique)->tid,
|
||||
&tid, sizeof (pid_t)) != PS_OK
|
||||
|| ps_lsetregs (th->th_ta_p->ph, tid, gregs) != PS_OK)
|
||||
if (ps_lsetregs (th->th_ta_p->ph, tid - (psaddr_t) 0, gregs) != PS_OK)
|
||||
return TD_ERR;
|
||||
}
|
||||
|
||||
|
@ -22,24 +22,22 @@
|
||||
#include "thread_dbP.h"
|
||||
|
||||
td_err_e
|
||||
td_thr_tls_get_addr (const td_thrhandle_t *th __attribute__ ((unused)),
|
||||
void *map_address __attribute__ ((unused)),
|
||||
size_t offset __attribute__ ((unused)),
|
||||
void **address __attribute__ ((unused)))
|
||||
td_thr_tls_get_addr (const td_thrhandle_t *th,
|
||||
psaddr_t map_address, size_t offset, psaddr_t *address)
|
||||
{
|
||||
#if USE_TLS
|
||||
/* Read the module ID from the link_map. */
|
||||
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 err;
|
||||
psaddr_t modid;
|
||||
|
||||
td_err_e result = td_thr_tlsbase (th, modid, address);
|
||||
if (result == TD_OK)
|
||||
*address += offset;
|
||||
return result;
|
||||
#else
|
||||
return TD_ERR;
|
||||
#endif
|
||||
/* Get the TLS module ID from the `struct link_map' in the inferior. */
|
||||
err = DB_GET_FIELD (modid, th->th_ta_p, map_address, link_map,
|
||||
l_tls_modid, 0);
|
||||
if (err == TD_NOCAPAB)
|
||||
return TD_NOAPLIC;
|
||||
if (err == TD_OK)
|
||||
{
|
||||
err = td_thr_tlsbase (th, (uintptr_t) modid, address);
|
||||
if (err == TD_OK)
|
||||
*address += offset;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
@ -19,49 +19,32 @@
|
||||
|
||||
#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_thr_tlsbase (const td_thrhandle_t *th,
|
||||
unsigned long int modid,
|
||||
psaddr_t *base)
|
||||
{
|
||||
td_err_e err;
|
||||
psaddr_t dtv, dtvptr;
|
||||
|
||||
if (modid < 1)
|
||||
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. */
|
||||
if (ps_pdread (th->th_ta_p->ph, dtvpp, &dtvp, sizeof dtvp) != PS_OK)
|
||||
return TD_ERR; /* XXX Other error value? */
|
||||
err = DB_GET_FIELD (dtv, th->th_ta_p, th->th_unique, pthread, dtvp, 0);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
|
||||
/* Get the corresponding entry in the DTV. */
|
||||
if (ps_pdread (th->th_ta_p->ph, dtvp + modid,
|
||||
&pdtv, sizeof (union dtv)) != PS_OK)
|
||||
return TD_ERR; /* XXX Other error value? */
|
||||
err = DB_GET_FIELD (dtvptr, th->th_ta_p, dtv, dtv, dtv, modid);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
|
||||
/* It could be that the memory for this module is not allocated for
|
||||
the given thread. */
|
||||
if (pdtv.pointer == TLS_DTV_UNALLOCATED)
|
||||
if ((uintptr_t) dtvptr & 1)
|
||||
return TD_TLSDEFER;
|
||||
|
||||
*base = (char *) pdtv.pointer;
|
||||
|
||||
*base = dtvptr;
|
||||
return TD_OK;
|
||||
#else
|
||||
return TD_ERR;
|
||||
#endif
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* 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.
|
||||
Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
|
||||
|
||||
@ -24,48 +24,73 @@
|
||||
td_err_e
|
||||
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");
|
||||
|
||||
/* Check correct value of key. */
|
||||
if (tk >= th->th_ta_p->pthread_keys_max)
|
||||
return TD_BADKEY;
|
||||
|
||||
/* Get the key entry. */
|
||||
uintptr_t seq;
|
||||
if (ps_pdread (th->th_ta_p->ph, &th->th_ta_p->keys[tk].seq, &seq,
|
||||
sizeof (uintptr_t)) != PS_OK)
|
||||
return TD_ERR; /* XXX Other error value? */
|
||||
err = DB_GET_VALUE (tk_seq, th->th_ta_p, __pthread_keys, tk);
|
||||
if (err == TD_NOAPLIC)
|
||||
return TD_BADKEY;
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
|
||||
/* Fail if this key is not at all used. */
|
||||
if (KEY_UNUSED (seq))
|
||||
if (((uintptr_t) tk_seq & 1) == 0)
|
||||
return TD_BADKEY;
|
||||
|
||||
/* Compute the indeces. */
|
||||
int pthread_key_2ndlevel_size = th->th_ta_p->pthread_key_2ndlevel_size;
|
||||
unsigned int idx1st = tk / pthread_key_2ndlevel_size;
|
||||
unsigned int idx2nd = tk % pthread_key_2ndlevel_size;
|
||||
/* This makes sure we have the size information on hand. */
|
||||
err = DB_GET_FIELD_ADDRESS (level2, th->th_ta_p, 0, pthread_key_data_level2,
|
||||
data, 1);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
|
||||
struct pthread_key_data *level1;
|
||||
if (ps_pdread (th->th_ta_p->ph,
|
||||
&((struct pthread *) th->th_unique)->specific[idx1st],
|
||||
&level1, sizeof (level1)) != PS_OK)
|
||||
return TD_ERR; /* XXX Other error value? */
|
||||
/* Compute the indeces. */
|
||||
pthread_key_2ndlevel_size
|
||||
= DB_DESC_NELEM (th->th_ta_p->ta_field_pthread_key_data_level2_data);
|
||||
idx1st = tk / pthread_key_2ndlevel_size;
|
||||
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. */
|
||||
if (level1 == NULL)
|
||||
if (level1 == 0)
|
||||
return TD_NOTSD;
|
||||
|
||||
struct pthread_key_data level2;
|
||||
if (ps_pdread (th->th_ta_p->ph, &level1[idx2nd], &level2,
|
||||
sizeof (level2)) != PS_OK)
|
||||
return TD_ERR; /* XXX Other error value? */
|
||||
/* Locate the element within the second level array. */
|
||||
err = DB_GET_FIELD_ADDRESS (level2, th->th_ta_p,
|
||||
level1, pthread_key_data_level2, data, idx2nd);
|
||||
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. */
|
||||
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;
|
||||
|
||||
if (level2.data != NULL)
|
||||
*data = level2.data;
|
||||
/* Finally, fetch the value. */
|
||||
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;
|
||||
}
|
||||
|
@ -24,43 +24,53 @@
|
||||
static td_err_e
|
||||
check_thread_list (const td_thrhandle_t *th, psaddr_t head)
|
||||
{
|
||||
list_t list;
|
||||
td_err_e result = TD_NOTHR;
|
||||
td_err_e err;
|
||||
psaddr_t next, ofs;
|
||||
|
||||
if (ps_pdread (th->th_ta_p->ph, head, &list.next, sizeof (list.next))
|
||||
!= PS_OK)
|
||||
return TD_ERR; /* XXX Other error value? */
|
||||
err = DB_GET_FIELD (next, th->th_ta_p, head, list_t, next, 0);
|
||||
if (err == TD_OK)
|
||||
{
|
||||
if (next == 0)
|
||||
return TD_NOTHR;
|
||||
err = DB_GET_FIELD_ADDRESS (ofs, th->th_ta_p, 0, pthread, list, 0);
|
||||
}
|
||||
|
||||
while (list.next != head)
|
||||
if ((psaddr_t) list.next - offsetof (struct pthread, list)
|
||||
== th->th_unique)
|
||||
{
|
||||
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;
|
||||
}
|
||||
while (err == TD_OK)
|
||||
{
|
||||
if (next == head)
|
||||
return TD_NOTHR;
|
||||
|
||||
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_thr_validate (const td_thrhandle_t *th)
|
||||
{
|
||||
td_err_e err;
|
||||
psaddr_t list;
|
||||
|
||||
LOG ("td_thr_validate");
|
||||
|
||||
/* 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
|
||||
using implementation allocated stacks. */
|
||||
if (result == TD_NOTHR)
|
||||
result = check_thread_list (th, th->th_ta_p->stack_used);
|
||||
if (err == TD_NOTHR)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ typedef enum
|
||||
TD_TLSDEFER, /* Thread has not yet allocated TLS for given module. */
|
||||
TD_NOTALLOC = TD_TLSDEFER,
|
||||
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;
|
||||
|
||||
|
||||
@ -412,8 +412,8 @@ extern td_err_e td_thr_tlsbase (const td_thrhandle_t *__th,
|
||||
|
||||
/* Get address of thread local variable. */
|
||||
extern td_err_e td_thr_tls_get_addr (const td_thrhandle_t *__th,
|
||||
void *__map_address, size_t __offset,
|
||||
void **__address);
|
||||
psaddr_t __map_address, size_t __offset,
|
||||
psaddr_t *__address);
|
||||
|
||||
|
||||
/* Enable reporting for EVENT for thread TH. */
|
||||
|
@ -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
|
||||
#define _THREAD_DBP_H 1
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include "proc_service.h"
|
||||
#include "thread_db.h"
|
||||
#include "../nptl/pthreadP.h"
|
||||
#include <list.h>
|
||||
|
||||
#include "../nptl/pthreadP.h" /* This is for *_BITMASK only. */
|
||||
|
||||
/* Indeces for the symbol names. */
|
||||
enum
|
||||
{
|
||||
SYM_PTHREAD_THREADS_EVENTS = 0,
|
||||
SYM_PTHREAD_LAST_EVENT,
|
||||
SYM_PTHREAD_NTHREADS,
|
||||
SYM_PTHREAD_STACK_USED,
|
||||
SYM_PTHREAD_STACK_USER,
|
||||
SYM_PTHREAD_KEYS,
|
||||
SYM_PTHREAD_KEYS_MAX,
|
||||
SYM_PTHREAD_SIZEOF_DESCR,
|
||||
SYM_PTHREAD_CREATE_EVENT,
|
||||
SYM_PTHREAD_DEATH_EVENT,
|
||||
SYM_PTHREAD_VERSION,
|
||||
# define DB_STRUCT(type) SYM_SIZEOF_##type,
|
||||
# define DB_STRUCT_FIELD(type, field) SYM_##type##_FIELD_##field,
|
||||
# define DB_SYMBOL(name) SYM_##name,
|
||||
# define DB_VARIABLE(name) SYM_##name, SYM_DESC_##name,
|
||||
# include "structs.def"
|
||||
# undef DB_STRUCT
|
||||
# undef DB_STRUCT_FIELD
|
||||
# undef DB_SYMBOL
|
||||
# undef DB_VARIABLE
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
@ -32,50 +56,68 @@ enum
|
||||
/* Comment out the following for less verbose output. */
|
||||
#ifndef NDEBUG
|
||||
# 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
|
||||
# define LOG(c)
|
||||
#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. */
|
||||
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
|
||||
proc callbacks. */
|
||||
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. */
|
||||
psaddr_t stack_used;
|
||||
psaddr_t stack_user;
|
||||
|
||||
/* Address of the `pthread_keys' array. */
|
||||
struct pthread_key_struct *keys;
|
||||
|
||||
/* Maximum number of thread-local data keys. */
|
||||
int pthread_keys_max;
|
||||
|
||||
/* Size of 2nd level array for thread-local data keys. */
|
||||
int pthread_key_2ndlevel_size;
|
||||
|
||||
/* Sizeof struct _pthread_descr_struct. */
|
||||
int sizeof_descr;
|
||||
|
||||
/* 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;
|
||||
/* The method of locating a thread's th_unique value. */
|
||||
enum
|
||||
{
|
||||
ta_howto_unknown,
|
||||
ta_howto_reg,
|
||||
ta_howto_reg_thread_area,
|
||||
ta_howto_const_thread_area
|
||||
} ta_howto;
|
||||
union
|
||||
{
|
||||
uint32_t const_thread_area; /* Constant argument to ps_get_thread_area. */
|
||||
/* These are as if the descriptor of the field in prregset_t,
|
||||
but DB_DESC_NELEM is overloaded as follows: */
|
||||
db_desc_t reg; /* Signed bias applied to register value. */
|
||||
db_desc_t reg_thread_area; /* Bits to scale down register value. */
|
||||
} ta_howto_data;
|
||||
};
|
||||
|
||||
|
||||
/* 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. */
|
||||
@ -93,6 +135,115 @@ ta_ok (const td_thragent_t *ta)
|
||||
|
||||
|
||||
/* 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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user