diff options
author | "Steven J. Hill" <sjhill@realitydiluted.com> | 2005-05-07 02:04:55 +0000 |
---|---|---|
committer | "Steven J. Hill" <sjhill@realitydiluted.com> | 2005-05-07 02:04:55 +0000 |
commit | 0b3366f6a93ac0f7e2028745ea557c0acd8722c6 (patch) | |
tree | 2a87cb353c106eb55a44437d3b4d5e0d60af1d36 /libpthread/nptl_db | |
parent | 2274f6b2ddc7d7ea919a8fa1f9c54ef1920cb180 (diff) |
Import in NPTL code from glibc. For further information please
consult the 'README.NPTL' file.
Diffstat (limited to 'libpthread/nptl_db')
48 files changed, 3744 insertions, 0 deletions
diff --git a/libpthread/nptl_db/Makefile b/libpthread/nptl_db/Makefile new file mode 100644 index 000000000..5c73ff28f --- /dev/null +++ b/libpthread/nptl_db/Makefile @@ -0,0 +1,60 @@ +# Copyright (C) 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 +# 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. + +# Makefile for NPTL debug library subdirectory of GNU C Library. + +subdir := nptl_db + +nptl_db-version = 1.0 + +extra-libs = libthread_db +extra-libs-others := $(extra-libs) + +headers = thread_db.h + +libthread_db-routines = td_init td_log td_ta_new td_ta_delete \ + td_ta_get_nthreads td_ta_get_ph \ + td_ta_map_id2thr td_ta_map_lwp2thr \ + td_ta_thr_iter td_ta_tsd_iter \ + td_thr_get_info td_thr_getfpregs td_thr_getgregs \ + td_thr_getxregs td_thr_getxregsize td_thr_setfpregs \ + td_thr_setgregs td_thr_setprio td_thr_setsigpending \ + td_thr_setxregs td_thr_sigsetmask td_thr_tsd \ + td_thr_validate td_thr_dbsuspend td_thr_dbresume \ + td_ta_setconcurrency td_ta_enable_stats \ + td_ta_reset_stats td_ta_get_stats td_ta_event_addr \ + td_thr_event_enable td_thr_set_event \ + 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 \ + 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 db_info.c structs.def +include ../Rules + +# Depend on libc.so so a DT_NEEDED is generated in the shared objects. +# This ensures they will load libc.so for needed symbols if loaded by +# a statically-linked program that hasn't already loaded it. +$(objpfx)libthread_db.so: $(common-objpfx)libc.so \ + $(common-objpfx)libc_nonshared.a diff --git a/libpthread/nptl_db/Versions b/libpthread/nptl_db/Versions new file mode 100644 index 000000000..063493c67 --- /dev/null +++ b/libpthread/nptl_db/Versions @@ -0,0 +1,24 @@ +libthread_db { + GLIBC_2.1.3 { + # t* + td_init; td_log; td_ta_clear_event; td_ta_delete; td_ta_enable_stats; + td_ta_event_addr; td_ta_event_getmsg; td_ta_get_nthreads; td_ta_get_ph; + td_ta_get_stats; td_ta_map_id2thr; td_ta_map_lwp2thr; td_ta_new; + td_ta_reset_stats; td_ta_set_event; td_ta_setconcurrency; + td_ta_thr_iter; td_ta_tsd_iter; td_thr_clear_event; td_thr_dbresume; + td_thr_dbsuspend; td_thr_event_enable; td_thr_event_getmsg; + td_thr_get_info; td_thr_getfpregs; td_thr_getgregs; td_thr_getxregs; + td_thr_getxregsize; td_thr_set_event; td_thr_setfpregs; td_thr_setgregs; + td_thr_setprio; td_thr_setsigpending; td_thr_setxregs; td_thr_sigsetmask; + td_thr_tsd; td_thr_validate; + } + GLIBC_2.2.3 { + td_symbol_list; + } + GLIBC_2.3 { + td_thr_tls_get_addr; + } + GLIBC_2.3.3 { + td_thr_tlsbase; + } +} diff --git a/libpthread/nptl_db/db_info.c b/libpthread/nptl_db/db_info.c new file mode 100644 index 000000000..5000b99ba --- /dev/null +++ b/libpthread/nptl_db/db_info.c @@ -0,0 +1,103 @@ +/* This file is included by pthread_create.c to define in libpthread + all the magic symbols required by libthread_db. + + Copyright (C) 2003, 2004 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. If TLS_TCB_SIZE == 0 (on PowerPC), there is no TCB + containing the DTV at the TP, but actually the TCB lies behind the TP, + i.e. at the very end of the area covered by TLS_PRE_TCB_SIZE. */ +DESC (_thread_db_pthread_dtvp, + TLS_PRE_TCB_SIZE + offsetof (tcbhead_t, dtv) + - (TLS_TCB_SIZE == 0 ? sizeof (tcbhead_t) : 0), 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. */ +#define DB_FUNCTION(name) /* Nothing. */ +#include "structs.def" +#undef DB_STRUCT +#undef DB_STRUCT_FIELD +#undef DB_SYMBOL +#undef DB_FUNCTION +#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, size, regofs, bias) \ + DB_DEFINE_DESC (_thread_db_register##bits, size, (uint32_t)(bias), (regofs)); + +DB_THREAD_SELF +#endif diff --git a/libpthread/nptl_db/fetch-value.c b/libpthread/nptl_db/fetch-value.c new file mode 100644 index 000000000..0d9bb0eb8 --- /dev/null +++ b/libpthread/nptl_db/fetch-value.c @@ -0,0 +1,284 @@ +/* Helper routines for libthread_db. + Copyright (C) 2003, 2004 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 += (int32_t) DB_DESC_OFFSET (desc); + *address += (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; +} diff --git a/libpthread/nptl_db/proc_service.h b/libpthread/nptl_db/proc_service.h new file mode 100644 index 000000000..d49e87ab3 --- /dev/null +++ b/libpthread/nptl_db/proc_service.h @@ -0,0 +1,87 @@ +/* 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 + 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. */ + +/* 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 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; + + +/* This type is opaque in this interface. + It's defined by the user of libthread_db. */ +struct ps_prochandle; + + +/* 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); + + +/* 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); diff --git a/libpthread/nptl_db/structs.def b/libpthread/nptl_db/structs.def new file mode 100644 index 000000000..b17a628e0 --- /dev/null +++ b/libpthread/nptl_db/structs.def @@ -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_FUNCTION (__nptl_create_event) +DB_FUNCTION (__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 diff --git a/libpthread/nptl_db/td_init.c b/libpthread/nptl_db/td_init.c new file mode 100644 index 000000000..946ff7244 --- /dev/null +++ b/libpthread/nptl_db/td_init.c @@ -0,0 +1,32 @@ +/* Initialization function of thread debugger support library. + 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" + +int __td_debug; + + +td_err_e +td_init (void) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_init"); + return TD_OK; +} diff --git a/libpthread/nptl_db/td_log.c b/libpthread/nptl_db/td_log.c new file mode 100644 index 000000000..52212a0e9 --- /dev/null +++ b/libpthread/nptl_db/td_log.c @@ -0,0 +1,32 @@ +/* Noop, left for historical reasons. + 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" + + +td_err_e +td_log (void) +{ + /* This interface is deprecated in the Sun interface. We provide it + for compatibility but don't do anything ourself. We might in + future do some logging if this seems reasonable. */ + LOG ("td_log"); + return TD_OK; +} diff --git a/libpthread/nptl_db/td_symbol_list.c b/libpthread/nptl_db/td_symbol_list.c new file mode 100644 index 000000000..5d6c94e5b --- /dev/null +++ b/libpthread/nptl_db/td_symbol_list.c @@ -0,0 +1,85 @@ +/* Return list of symbols the library can request. + Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2001. + + 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 <assert.h> +#include <gnu/lib-names.h> +#include "thread_dbP.h" + + +#ifdef HAVE_ASM_GLOBAL_DOT_NAME +# define DOT "." /* PPC64 requires . prefix on code symbols. */ +#else +# define DOT /* No prefix. */ +#endif + +static const char *symbol_list_arr[] = +{ +# 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_FUNCTION(name) \ + [SYM_##name] = DOT #name, +# define DB_VARIABLE(name) \ + [SYM_##name] = #name, \ + [SYM_DESC_##name] = "_thread_db_" #name, +# include "structs.def" +# undef DB_STRUCT +# undef DB_FUNCTION +# 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 +}; + + +const char ** +td_symbol_list (void) +{ + return symbol_list_arr; +} + + +ps_err_e +td_lookup (struct ps_prochandle *ps, int idx, psaddr_t *sym_addr) +{ + ps_err_e result; + assert (idx >= 0 && idx < SYM_NUM_MESSAGES); + result = ps_pglobal_lookup (ps, LIBPTHREAD_SO, symbol_list_arr[idx], + sym_addr); + +#ifdef HAVE_ASM_GLOBAL_DOT_NAME + /* For PowerPC, 64-bit uses dot symbols but 32-bit does not. + We could be a 64-bit libthread_db debugging a 32-bit libpthread. */ + if (result == PS_NOSYM && symbol_list_arr[idx][0] == '.') + result = ps_pglobal_lookup (ps, LIBPTHREAD_SO, &symbol_list_arr[idx][1], + sym_addr); +#endif + + return result; +} diff --git a/libpthread/nptl_db/td_ta_clear_event.c b/libpthread/nptl_db/td_ta_clear_event.c new file mode 100644 index 000000000..7a2850c4e --- /dev/null +++ b/libpthread/nptl_db/td_ta_clear_event.c @@ -0,0 +1,79 @@ +/* Globally disable events. + Copyright (C) 1999, 2001, 2002, 2003, 2004 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" + + +td_err_e +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 = 0; + void *copy = NULL; + + LOG ("td_ta_clear_event"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + /* 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); + } + + return err; +} diff --git a/libpthread/nptl_db/td_ta_delete.c b/libpthread/nptl_db/td_ta_delete.c new file mode 100644 index 000000000..57b90e57f --- /dev/null +++ b/libpthread/nptl_db/td_ta_delete.c @@ -0,0 +1,42 @@ +/* Detach to target process. + 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 <stdlib.h> + +#include "thread_dbP.h" + + +td_err_e +td_ta_delete (td_thragent_t *ta) +{ + LOG ("td_ta_delete"); + + /* Safety check. Note that the test will also fail for TA == NULL. */ + if (!ta_ok (ta)) + return TD_BADTA; + + /* Remove the handle from the list. */ + list_del (&ta->list); + + /* The handle was allocated in `td_ta_new'. */ + free (ta); + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_ta_enable_stats.c b/libpthread/nptl_db/td_ta_enable_stats.c new file mode 100644 index 000000000..ec7014ad2 --- /dev/null +++ b/libpthread/nptl_db/td_ta_enable_stats.c @@ -0,0 +1,35 @@ +/* Enable collection of statistics for process. + 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" + + +td_err_e +td_ta_enable_stats (const td_thragent_t *ta, int enable) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_ta_enable_stats"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_ta_event_addr.c b/libpthread/nptl_db/td_ta_event_addr.c new file mode 100644 index 000000000..37196e643 --- /dev/null +++ b/libpthread/nptl_db/td_ta_event_addr.c @@ -0,0 +1,61 @@ +/* Get event address. + 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" + + +td_err_e +td_ta_event_addr (const td_thragent_t *ta_arg, + td_event_e event, td_notify_t *addr) +{ + td_thragent_t *const ta = (td_thragent_t *) ta_arg; + td_err_e err; + psaddr_t taddr; + + LOG ("td_ta_event_addr"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + switch (event) + { + case TD_CREATE: + err = DB_GET_SYMBOL (taddr, ta, __nptl_create_event); + break; + + case TD_DEATH: + err = DB_GET_SYMBOL (taddr, ta, __nptl_death_event); + break; + + default: + /* Event cannot be handled. */ + return TD_NOEVENT; + } + + if (err == TD_OK) + { + /* Success, we got the address. */ + addr->type = NOTIFY_BPT; + addr->u.bptaddr = taddr; + } + + return err; +} diff --git a/libpthread/nptl_db/td_ta_event_getmsg.c b/libpthread/nptl_db/td_ta_event_getmsg.c new file mode 100644 index 000000000..6e68ff4ff --- /dev/null +++ b/libpthread/nptl_db/td_ta_event_getmsg.c @@ -0,0 +1,105 @@ +/* Retrieve event. + 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 <stddef.h> +#include <string.h> + +#include "thread_dbP.h" + + +td_err_e +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_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. */ + err = DB_GET_VALUE (thp, ta, __nptl_last_event, 0); + if (err != TD_OK) + return err; + + if (thp == 0) + /* Nothing waiting. */ + return TD_NOMSG; + + /* 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 ((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 = thp; + + /* Fill the user's data structure. */ + msg->msg.data = (uintptr_t) eventdata; + msg->event = (uintptr_t) eventnum; + msg->th_p = &th; + + /* And clear the event message in the target. */ + 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. */ + err = DB_GET_FIELD (next, ta, thp, pthread, nextevent, 0); + if (err != TD_OK) + return err; + + /* Store the pointer in the list head variable. */ + err = DB_PUT_VALUE (ta, __nptl_last_event, 0, next); + if (err != TD_OK) + return err; + + if (next != 0) + /* Clear the next pointer in the current descriptor. */ + err = DB_PUT_FIELD (ta, thp, pthread, nextevent, 0, 0); + + return err; +} diff --git a/libpthread/nptl_db/td_ta_get_nthreads.c b/libpthread/nptl_db/td_ta_get_nthreads.c new file mode 100644 index 000000000..ffe78bd57 --- /dev/null +++ b/libpthread/nptl_db/td_ta_get_nthreads.c @@ -0,0 +1,42 @@ +/* Get the number of threads in the process. + 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" + +td_err_e +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 in the inferior that tells us. */ + err = DB_GET_VALUE (n, ta, __nptl_nthreads, 0); + if (err == TD_OK) + *np = (uintptr_t) n; + + return err; +} diff --git a/libpthread/nptl_db/td_ta_get_ph.c b/libpthread/nptl_db/td_ta_get_ph.c new file mode 100644 index 000000000..04e01fb73 --- /dev/null +++ b/libpthread/nptl_db/td_ta_get_ph.c @@ -0,0 +1,36 @@ +/* Get external process handle. + 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" + + +td_err_e +td_ta_get_ph (const td_thragent_t *ta, struct ps_prochandle **ph) +{ + LOG ("td_ta_get_ph"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + *ph = ta->ph; + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_ta_get_stats.c b/libpthread/nptl_db/td_ta_get_stats.c new file mode 100644 index 000000000..d5d879c3e --- /dev/null +++ b/libpthread/nptl_db/td_ta_get_stats.c @@ -0,0 +1,35 @@ +/* Retrieve statistics for process. + 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" + + +td_err_e +td_ta_get_stats (const td_thragent_t *ta, td_ta_stats_t *statsp) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_ta_get_stats"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_ta_map_id2thr.c b/libpthread/nptl_db/td_ta_map_id2thr.c new file mode 100644 index 000000000..189a67171 --- /dev/null +++ b/libpthread/nptl_db/td_ta_map_id2thr.c @@ -0,0 +1,38 @@ +/* Map thread ID to thread handle. + 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" + + +td_err_e +td_ta_map_id2thr (const td_thragent_t *ta, pthread_t pt, td_thrhandle_t *th) +{ + LOG ("td_ta_map_id2thr"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + /* Create the `td_thrhandle_t' object. */ + th->th_ta_p = (td_thragent_t *) ta; + th->th_unique = (psaddr_t) pt; + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_ta_map_lwp2thr.c b/libpthread/nptl_db/td_ta_map_lwp2thr.c new file mode 100644 index 000000000..1e93210b9 --- /dev/null +++ b/libpthread/nptl_db/td_ta_map_lwp2thr.c @@ -0,0 +1,178 @@ +/* Which thread is running on an LWP? + Copyright (C) 2003, 2004 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: + 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; +} diff --git a/libpthread/nptl_db/td_ta_new.c b/libpthread/nptl_db/td_ta_new.c new file mode 100644 index 000000000..f84049af3 --- /dev/null +++ b/libpthread/nptl_db/td_ta_new.c @@ -0,0 +1,65 @@ +/* Attach to target process. + 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 <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <version.h> + +#include "thread_dbP.h" + + +/* Datatype for the list of known thread agents. Normally there will + be exactly one so we don't spend much though on making it fast. */ +LIST_HEAD (__td_agent_list); + + +td_err_e +td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta) +{ + psaddr_t versaddr; + char versbuf[sizeof (VERSION)]; + + LOG ("td_ta_new"); + + /* Check whether the versions match. */ + 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 (memcmp (versbuf, VERSION, sizeof VERSION) != 0) + /* Not the right version. */ + return TD_VERSION; + + /* Fill in the appropriate information. */ + *ta = (td_thragent_t *) calloc (1, sizeof (td_thragent_t)); + if (*ta == NULL) + return TD_MALLOC; + + /* Store the proc handle which we will pass to the callback functions + back into the debugger. */ + (*ta)->ph = ps; + + /* Now add the new agent descriptor to the list. */ + list_add (&(*ta)->list, &__td_agent_list); + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_ta_reset_stats.c b/libpthread/nptl_db/td_ta_reset_stats.c new file mode 100644 index 000000000..ea59d2cda --- /dev/null +++ b/libpthread/nptl_db/td_ta_reset_stats.c @@ -0,0 +1,35 @@ +/* Reset statistics. + 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" + + +td_err_e +td_ta_reset_stats (const td_thragent_t *ta) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_ta_reset_stats"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_ta_set_event.c b/libpthread/nptl_db/td_ta_set_event.c new file mode 100644 index 000000000..29fc14bfb --- /dev/null +++ b/libpthread/nptl_db/td_ta_set_event.c @@ -0,0 +1,79 @@ +/* Globally enable events. + Copyright (C) 1999,2001,2002,2003,2004 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" + + +td_err_e +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 = 0; + void *copy = NULL; + + LOG ("td_ta_set_event"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + /* 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); + } + + return err; +} diff --git a/libpthread/nptl_db/td_ta_setconcurrency.c b/libpthread/nptl_db/td_ta_setconcurrency.c new file mode 100644 index 000000000..8552ffbe0 --- /dev/null +++ b/libpthread/nptl_db/td_ta_setconcurrency.c @@ -0,0 +1,35 @@ +/* Set suggested concurrency level for process. + 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" + + +td_err_e +td_ta_setconcurrency (const td_thragent_t *ta, int level) +{ + /* This is something LinuxThreads does not need to support. */ + LOG ("td_ta_setconcurrency"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + return TD_NOCAPAB; +} diff --git a/libpthread/nptl_db/td_ta_thr_iter.c b/libpthread/nptl_db/td_ta_thr_iter.c new file mode 100644 index 000000000..66e437665 --- /dev/null +++ b/libpthread/nptl_db/td_ta_thr_iter.c @@ -0,0 +1,148 @@ +/* Iterate over a process's threads. + Copyright (C) 1999,2000,2001,2002,2003,2004 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" + + +static td_err_e +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, int fake_empty) +{ + 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; + + err = DB_GET_FIELD (next, ta, head, list_t, next, 0); + if (err != TD_OK) + return err; + + if (next == 0 && fake_empty) + { + /* __pthread_initialize_minimal has not run. + There is just the main thread to return. */ + td_thrhandle_t th; + 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; + } + + /* 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) + { + err = _td_check_sizeof (ta, &ta->ta_sizeof_pthread, SYM_SIZEOF_pthread); + if (err != TD_OK) + return err; + } + copy = __alloca (ta->ta_sizeof_pthread); + + while (next != head) + { + psaddr_t addr, schedpolicy, schedprio; + + addr = next - (ofs - (psaddr_t) 0); + if (next == 0 || addr == 0) /* Sanity check. */ + return TD_DBERR; + + /* 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 = ((uintptr_t) schedpolicy == SCHED_OTHER + ? 0 : (uintptr_t) schedprio); + if (descr_pri >= ti_pri) + { + /* 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. */ + err = DB_GET_FIELD_LOCAL (next, ta, copy + (ofs - (psaddr_t) 0), list_t, + next, 0); + if (err != TD_OK) + break; + } + + return err; +} + + +td_err_e +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 = 0; + + LOG ("td_ta_thr_iter"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + /* The thread library keeps two lists for the running threads. One + list contains the thread which are using user-provided stacks + (this includes the main thread) and the other includes the + 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. */ + + 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 (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 err; +} diff --git a/libpthread/nptl_db/td_ta_tsd_iter.c b/libpthread/nptl_db/td_ta_tsd_iter.c new file mode 100644 index 000000000..9cfb1e8de --- /dev/null +++ b/libpthread/nptl_db/td_ta_tsd_iter.c @@ -0,0 +1,81 @@ +/* Iterate over a process's thread-specific data. + 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. + + 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 <alloca.h> + +td_err_e +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; + + /* 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; + + /* 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. */ + 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; +} diff --git a/libpthread/nptl_db/td_thr_clear_event.c b/libpthread/nptl_db/td_thr_clear_event.c new file mode 100644 index 000000000..fc999df9c --- /dev/null +++ b/libpthread/nptl_db/td_thr_clear_event.c @@ -0,0 +1,77 @@ +/* Disable specific event for thread. + 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 <stddef.h> + +#include "thread_dbP.h" + + +td_err_e +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"); + + /* 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); + } + + return err; +} diff --git a/libpthread/nptl_db/td_thr_dbresume.c b/libpthread/nptl_db/td_thr_dbresume.c new file mode 100644 index 000000000..3fd794377 --- /dev/null +++ b/libpthread/nptl_db/td_thr_dbresume.c @@ -0,0 +1,30 @@ +/* Resume execution of given thread. + 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" + + +td_err_e +td_thr_dbresume (const td_thrhandle_t *th) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_thr_dbresume"); + return TD_NOCAPAB; +} diff --git a/libpthread/nptl_db/td_thr_dbsuspend.c b/libpthread/nptl_db/td_thr_dbsuspend.c new file mode 100644 index 000000000..6ef82ad34 --- /dev/null +++ b/libpthread/nptl_db/td_thr_dbsuspend.c @@ -0,0 +1,30 @@ +/* Suspend execution of given thread. + 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" + + +td_err_e +td_thr_dbsuspend (const td_thrhandle_t *th) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_thr_dbsuspend"); + return TD_NOCAPAB; +} diff --git a/libpthread/nptl_db/td_thr_event_enable.c b/libpthread/nptl_db/td_thr_event_enable.c new file mode 100644 index 000000000..a02be5da4 --- /dev/null +++ b/libpthread/nptl_db/td_thr_event_enable.c @@ -0,0 +1,34 @@ +/* Enable event process-wide. + 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" + + +td_err_e +td_thr_event_enable (th, onoff) + const td_thrhandle_t *th; + int onoff; +{ + LOG ("td_thr_event_enable"); + + /* Write the new value into the thread data structure. */ + return DB_PUT_FIELD (th->th_ta_p, th->th_unique, pthread, report_events, 0, + (psaddr_t) 0 + (onoff != 0)); +} diff --git a/libpthread/nptl_db/td_thr_event_getmsg.c b/libpthread/nptl_db/td_thr_event_getmsg.c new file mode 100644 index 000000000..70ea6953e --- /dev/null +++ b/libpthread/nptl_db/td_thr_event_getmsg.c @@ -0,0 +1,119 @@ +/* Retrieve event. + 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 <assert.h> + + +td_err_e +td_thr_event_getmsg (const td_thrhandle_t *th, td_event_msg_t *msg) +{ + td_err_e err; + psaddr_t eventbuf, eventnum, eventdata; + psaddr_t thp, prevp; + void *copy; + + LOG ("td_thr_event_getmsg"); + + /* 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. */ + 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. */ + 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; + + /* And clear the event message in the target. */ + 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. */ + 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; + + while (thp != 0) + { + 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; + + if (thp == th->th_unique) + { + /* PREVP points at this thread, splice it out. */ + 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; + + 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. */ + return DB_PUT_FIELD (th->th_ta_p, thp, pthread, nextevent, 0, 0); + } + + 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; + } + + /* Ack! This should not happen. */ + return TD_DBERR; +} diff --git a/libpthread/nptl_db/td_thr_get_info.c b/libpthread/nptl_db/td_thr_get_info.c new file mode 100644 index 000000000..bb1388804 --- /dev/null +++ b/libpthread/nptl_db/td_thr_get_info.c @@ -0,0 +1,110 @@ +/* Get thread information. + 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. + + 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 <stddef.h> +#include <string.h> +#include "thread_dbP.h" + + +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"); + + /* 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 = (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 ((((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 ((((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_ta_p = th->th_ta_p; + infop->ti_lid = tid == 0 ? ps_getpid (th->th_ta_p->ph) : (uintptr_t) tid; + infop->ti_traceme = report_events != 0; + + 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; +} diff --git a/libpthread/nptl_db/td_thr_getfpregs.c b/libpthread/nptl_db/td_thr_getfpregs.c new file mode 100644 index 000000000..7760512eb --- /dev/null +++ b/libpthread/nptl_db/td_thr_getfpregs.c @@ -0,0 +1,53 @@ +/* Get a thread's floating-point register set. + 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" + + +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. */ + 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 (((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK) + memset (regset, '\0', sizeof (*regset)); + /* Otherwise get the register content through the callback. */ + else + { + err = DB_GET_FIELD (tid, th->th_ta_p, th->th_unique, pthread, tid, 0); + if (err != TD_OK) + return err; + + if (ps_lgetfpregs (th->th_ta_p->ph, (uintptr_t) tid, regset) != PS_OK) + return TD_ERR; + } + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_thr_getgregs.c b/libpthread/nptl_db/td_thr_getgregs.c new file mode 100644 index 000000000..4c2373ef6 --- /dev/null +++ b/libpthread/nptl_db/td_thr_getgregs.c @@ -0,0 +1,53 @@ +/* Get a thread's general register set. + 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. + + 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" + + +td_err_e +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. */ + 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 (((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK) + memset (regset, '\0', sizeof (*regset)); + /* Otherwise get the register content through the callback. */ + else + { + err = DB_GET_FIELD (tid, th->th_ta_p, th->th_unique, pthread, tid, 0); + if (err != TD_OK) + return err; + + if (ps_lgetregs (th->th_ta_p->ph, (uintptr_t) tid, regset) != PS_OK) + return TD_ERR; + } + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_thr_getxregs.c b/libpthread/nptl_db/td_thr_getxregs.c new file mode 100644 index 000000000..3c77ab6be --- /dev/null +++ b/libpthread/nptl_db/td_thr_getxregs.c @@ -0,0 +1,30 @@ +/* Get a thread's extra state register set. + 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" + + +td_err_e +td_thr_getxregs (const td_thrhandle_t *th, void *xregs) +{ + /* XXX This might be platform specific. */ + LOG ("td_thr_getxregs"); + return TD_NOXREGS; +} diff --git a/libpthread/nptl_db/td_thr_getxregsize.c b/libpthread/nptl_db/td_thr_getxregsize.c new file mode 100644 index 000000000..1704e4b0a --- /dev/null +++ b/libpthread/nptl_db/td_thr_getxregsize.c @@ -0,0 +1,30 @@ +/* Get the size of the extra state register set for this architecture. + 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" + + +td_err_e +td_thr_getxregsize (const td_thrhandle_t *th, int *sizep) +{ + /* XXX This might be platform specific. */ + LOG ("td_thr_getxregsize"); + return TD_NOXREGS; +} diff --git a/libpthread/nptl_db/td_thr_set_event.c b/libpthread/nptl_db/td_thr_set_event.c new file mode 100644 index 000000000..2bb0b9d1f --- /dev/null +++ b/libpthread/nptl_db/td_thr_set_event.c @@ -0,0 +1,77 @@ +/* Enable specific event for thread. + 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 <stddef.h> + +#include "thread_dbP.h" + + +td_err_e +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"); + + /* 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); + } + + return err; +} diff --git a/libpthread/nptl_db/td_thr_setfpregs.c b/libpthread/nptl_db/td_thr_setfpregs.c new file mode 100644 index 000000000..01bdb5323 --- /dev/null +++ b/libpthread/nptl_db/td_thr_setfpregs.c @@ -0,0 +1,50 @@ +/* Set a thread's floating-point register set. + 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" + + +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. */ + 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 ((((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK) == 0) + { + err = DB_GET_FIELD (tid, th->th_ta_p, th->th_unique, pthread, tid, 0); + if (err != TD_OK) + return err; + + if (ps_lsetfpregs (th->th_ta_p->ph, (uintptr_t) tid, fpregs) != PS_OK) + return TD_ERR; + } + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_thr_setgregs.c b/libpthread/nptl_db/td_thr_setgregs.c new file mode 100644 index 000000000..2a9ce7e01 --- /dev/null +++ b/libpthread/nptl_db/td_thr_setgregs.c @@ -0,0 +1,50 @@ +/* Set a thread's general register set. + 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" + + +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. */ + 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 ((((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK) == 0) + { + err = DB_GET_FIELD (tid, th->th_ta_p, th->th_unique, pthread, tid, 0); + if (err != TD_OK) + return err; + + if (ps_lsetregs (th->th_ta_p->ph, tid - (psaddr_t) 0, gregs) != PS_OK) + return TD_ERR; + } + + return TD_OK; +} diff --git a/libpthread/nptl_db/td_thr_setprio.c b/libpthread/nptl_db/td_thr_setprio.c new file mode 100644 index 000000000..6032b0ed4 --- /dev/null +++ b/libpthread/nptl_db/td_thr_setprio.c @@ -0,0 +1,30 @@ +/* Set a thread's priority. + 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" + + +td_err_e +td_thr_setprio (const td_thrhandle_t *th, int prio) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_thr_setprio"); + return TD_OK; +} diff --git a/libpthread/nptl_db/td_thr_setsigpending.c b/libpthread/nptl_db/td_thr_setsigpending.c new file mode 100644 index 000000000..e2c9d7ad2 --- /dev/null +++ b/libpthread/nptl_db/td_thr_setsigpending.c @@ -0,0 +1,31 @@ +/* Raise a signal for a thread. + 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" + + +td_err_e +td_thr_setsigpending (const td_thrhandle_t *th, unsigned char n, + const sigset_t *ss) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_thr_setsigpending"); + return TD_OK; +} diff --git a/libpthread/nptl_db/td_thr_setxregs.c b/libpthread/nptl_db/td_thr_setxregs.c new file mode 100644 index 000000000..f48877c78 --- /dev/null +++ b/libpthread/nptl_db/td_thr_setxregs.c @@ -0,0 +1,30 @@ +/* Set a thread's extra state register set. + 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" + + +td_err_e +td_thr_setxregs (const td_thrhandle_t *ta, const void *addr) +{ + /* XXX This might have to be platform specific. */ + LOG ("td_thr_setxregs"); + return TD_NOXREGS; +} diff --git a/libpthread/nptl_db/td_thr_sigsetmask.c b/libpthread/nptl_db/td_thr_sigsetmask.c new file mode 100644 index 000000000..3a68aecd3 --- /dev/null +++ b/libpthread/nptl_db/td_thr_sigsetmask.c @@ -0,0 +1,30 @@ +/* Set a thread's signal mask. + 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" + + +td_err_e +td_thr_sigsetmask (const td_thrhandle_t *th, const sigset_t *ss) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_thr_sigsetmask"); + return TD_OK; +} diff --git a/libpthread/nptl_db/td_thr_tls_get_addr.c b/libpthread/nptl_db/td_thr_tls_get_addr.c new file mode 100644 index 000000000..e7d232272 --- /dev/null +++ b/libpthread/nptl_db/td_thr_tls_get_addr.c @@ -0,0 +1,43 @@ +/* Get address of thread local variable. + Copyright (C) 2002,2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 2002. + + 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 <link.h> +#include "thread_dbP.h" + +td_err_e +td_thr_tls_get_addr (const td_thrhandle_t *th, + psaddr_t map_address, size_t offset, psaddr_t *address) +{ + td_err_e err; + psaddr_t modid; + + /* 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; +} diff --git a/libpthread/nptl_db/td_thr_tlsbase.c b/libpthread/nptl_db/td_thr_tlsbase.c new file mode 100644 index 000000000..c57009a73 --- /dev/null +++ b/libpthread/nptl_db/td_thr_tlsbase.c @@ -0,0 +1,50 @@ +/* Locate TLS data for a thread. + 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" + +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; + + /* Get the DTV pointer from the thread descriptor. */ + 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. */ + 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 ((uintptr_t) dtvptr & 1) + return TD_TLSDEFER; + + *base = dtvptr; + return TD_OK; +} diff --git a/libpthread/nptl_db/td_thr_tsd.c b/libpthread/nptl_db/td_thr_tsd.c new file mode 100644 index 000000000..08f617b7d --- /dev/null +++ b/libpthread/nptl_db/td_thr_tsd.c @@ -0,0 +1,96 @@ +/* Get a thread-specific data pointer for a thread. + 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" + + +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"); + + /* Get the key entry. */ + 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 (((uintptr_t) tk_seq & 1) == 0) + return TD_BADKEY; + + /* 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; + + /* 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 == 0) + return TD_NOTSD; + + /* 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. */ + 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; + + /* 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 err; +} diff --git a/libpthread/nptl_db/td_thr_validate.c b/libpthread/nptl_db/td_thr_validate.c new file mode 100644 index 000000000..3d560a621 --- /dev/null +++ b/libpthread/nptl_db/td_thr_validate.c @@ -0,0 +1,91 @@ +/* Validate a thread handle. + Copyright (C) 1999, 2001, 2002, 2003, 2004 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 <stdbool.h> + +static td_err_e +check_thread_list (const td_thrhandle_t *th, psaddr_t head, bool *uninit) +{ + td_err_e err; + psaddr_t next, ofs; + + err = DB_GET_FIELD (next, th->th_ta_p, head, list_t, next, 0); + if (err == TD_OK) + { + if (next == 0) + { + *uninit = true; + return TD_NOTHR; + } + err = DB_GET_FIELD_ADDRESS (ofs, th->th_ta_p, 0, pthread, list, 0); + } + + while (err == TD_OK) + { + if (next == head) + return TD_NOTHR; + + 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. */ + bool uninit = false; + err = DB_GET_SYMBOL (list, th->th_ta_p, __stack_user); + if (err == TD_OK) + err = check_thread_list (th, list, &uninit); + + /* If our thread is not on this list search the list with stack + using implementation allocated stacks. */ + 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, &uninit); + + if (err == TD_NOTHR && uninit) + { + /* __pthread_initialize_minimal has not run yet. + But the main thread still has a valid ID. */ + td_thrhandle_t main_th; + err = td_ta_map_lwp2thr (th->th_ta_p, + ps_getpid (th->th_ta_p->ph), &main_th); + if (err == TD_OK && th->th_unique != main_th.th_unique) + err = TD_NOTHR; + } + } + + return err; +} diff --git a/libpthread/nptl_db/thread_db.h b/libpthread/nptl_db/thread_db.h new file mode 100644 index 000000000..433b54fd5 --- /dev/null +++ b/libpthread/nptl_db/thread_db.h @@ -0,0 +1,459 @@ +/* thread_db.h -- interface to libthread_db.so library for debugging -lpthread + Copyright (C) 1999,2001,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 + 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_DB_H +#define _THREAD_DB_H 1 + +/* This is the debugger interface for the NPTL library. It is + modelled closely after the interface with same names in Solaris + with the goal to share the same code in the debugger. */ +#include <pthread.h> +#include <stdint.h> +#include <sys/types.h> +#include <sys/procfs.h> + + +/* Error codes of the library. */ +typedef enum +{ + TD_OK, /* No error. */ + TD_ERR, /* No further specified error. */ + TD_NOTHR, /* No matching thread found. */ + TD_NOSV, /* No matching synchronization handle found. */ + TD_NOLWP, /* No matching light-weighted process found. */ + TD_BADPH, /* Invalid process handle. */ + TD_BADTH, /* Invalid thread handle. */ + TD_BADSH, /* Invalid synchronization handle. */ + TD_BADTA, /* Invalid thread agent. */ + TD_BADKEY, /* Invalid key. */ + TD_NOMSG, /* No event available. */ + TD_NOFPREGS, /* No floating-point register content available. */ + TD_NOLIBTHREAD, /* Application not linked with thread library. */ + TD_NOEVENT, /* Requested event is not supported. */ + TD_NOCAPAB, /* Capability not available. */ + TD_DBERR, /* Internal debug library error. */ + TD_NOAPLIC, /* Operation is not applicable. */ + TD_NOTSD, /* No thread-specific data available. */ + TD_MALLOC, /* Out of memory. */ + TD_PARTIALREG, /* Not entire register set was read or written. */ + TD_NOXREGS, /* X register set not available for given thread. */ + 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 no TLS segment in the given module. */ +} td_err_e; + + +/* Possible thread states. TD_THR_ANY_STATE is a pseudo-state used to + select threads regardless of state in td_ta_thr_iter(). */ +typedef enum +{ + TD_THR_ANY_STATE, + TD_THR_UNKNOWN, + TD_THR_STOPPED, + TD_THR_RUN, + TD_THR_ACTIVE, + TD_THR_ZOMBIE, + TD_THR_SLEEP, + TD_THR_STOPPED_ASLEEP +} td_thr_state_e; + +/* Thread type: user or system. TD_THR_ANY_TYPE is a pseudo-type used + to select threads regardless of type in td_ta_thr_iter(). */ +typedef enum +{ + TD_THR_ANY_TYPE, + TD_THR_USER, + TD_THR_SYSTEM +} td_thr_type_e; + + +/* Types of the debugging library. */ + +/* Handle for a process. This type is opaque. */ +typedef struct td_thragent td_thragent_t; + +/* The actual thread handle type. This is also opaque. */ +typedef struct td_thrhandle +{ + td_thragent_t *th_ta_p; + psaddr_t th_unique; +} td_thrhandle_t; + + +/* Forward declaration of a type defined by and for the dynamic linker. */ +struct link_map; + + +/* Flags for `td_ta_thr_iter'. */ +#define TD_THR_ANY_USER_FLAGS 0xffffffff +#define TD_THR_LOWEST_PRIORITY -20 +#define TD_SIGNO_MASK NULL + + +#define TD_EVENTSIZE 2 +#define BT_UISHIFT 5 /* log base 2 of BT_NBIPUI, to extract word index */ +#define BT_NBIPUI (1 << BT_UISHIFT) /* n bits per uint */ +#define BT_UIMASK (BT_NBIPUI - 1) /* to extract bit index */ + +/* Bitmask of enabled events. */ +typedef struct td_thr_events +{ + uint32_t event_bits[TD_EVENTSIZE]; +} td_thr_events_t; + +/* Event set manipulation macros. */ +#define __td_eventmask(n) \ + (UINT32_C (1) << (((n) - 1) & BT_UIMASK)) +#define __td_eventword(n) \ + ((UINT32_C ((n) - 1)) >> BT_UISHIFT) + +#define td_event_emptyset(setp) \ + do { \ + int __i; \ + for (__i = TD_EVENTSIZE; __i > 0; --__i) \ + (setp)->event_bits[__i - 1] = 0; \ + } while (0) + +#define td_event_fillset(setp) \ + do { \ + int __i; \ + for (__i = TD_EVENTSIZE; __i > 0; --__i) \ + (setp)->event_bits[__i - 1] = UINT32_C (0xffffffff); \ + } while (0) + +#define td_event_addset(setp, n) \ + (((setp)->event_bits[__td_eventword (n)]) |= __td_eventmask (n)) +#define td_event_delset(setp, n) \ + (((setp)->event_bits[__td_eventword (n)]) &= ~__td_eventmask (n)) +#define td_eventismember(setp, n) \ + (__td_eventmask (n) & ((setp)->event_bits[__td_eventword (n)])) +#if TD_EVENTSIZE == 2 +# define td_eventisempty(setp) \ + (!((setp)->event_bits[0]) && !((setp)->event_bits[1])) +#else +# error "td_eventisempty must be changed to match TD_EVENTSIZE" +#endif + +/* Events reportable by the thread implementation. */ +typedef enum +{ + TD_ALL_EVENTS, /* Pseudo-event number. */ + TD_EVENT_NONE = TD_ALL_EVENTS, /* Depends on context. */ + TD_READY, /* Is executable now. */ + TD_SLEEP, /* Blocked in a synchronization obj. */ + TD_SWITCHTO, /* Now assigned to a process. */ + TD_SWITCHFROM, /* Not anymore assigned to a process. */ + TD_LOCK_TRY, /* Trying to get an unavailable lock. */ + TD_CATCHSIG, /* Signal posted to the thread. */ + TD_IDLE, /* Process getting idle. */ + TD_CREATE, /* New thread created. */ + TD_DEATH, /* Thread terminated. */ + TD_PREEMPT, /* Preempted. */ + TD_PRI_INHERIT, /* Inherited elevated priority. */ + TD_REAP, /* Reaped. */ + TD_CONCURRENCY, /* Number of processes changing. */ + TD_TIMEOUT, /* Conditional variable wait timed out. */ + TD_MIN_EVENT_NUM = TD_READY, + TD_MAX_EVENT_NUM = TD_TIMEOUT, + TD_EVENTS_ENABLE = 31 /* Event reporting enabled. */ +} td_event_e; + +/* Values representing the different ways events are reported. */ +typedef enum +{ + NOTIFY_BPT, /* User must insert breakpoint at u.bptaddr. */ + NOTIFY_AUTOBPT, /* Breakpoint at u.bptaddr is automatically + inserted. */ + NOTIFY_SYSCALL /* System call u.syscallno will be invoked. */ +} td_notify_e; + +/* Description how event type is reported. */ +typedef struct td_notify +{ + td_notify_e type; /* Way the event is reported. */ + union + { + psaddr_t bptaddr; /* Address of breakpoint. */ + int syscallno; /* Number of system call used. */ + } u; +} td_notify_t; + +/* Structure used to report event. */ +typedef struct td_event_msg +{ + td_event_e event; /* Event type being reported. */ + const td_thrhandle_t *th_p; /* Thread reporting the event. */ + union + { +# if 0 + td_synchandle_t *sh; /* Handle of synchronization object. */ +#endif + uintptr_t data; /* Event specific data. */ + } msg; +} td_event_msg_t; + +/* Structure containing event data available in each thread structure. */ +typedef struct +{ + td_thr_events_t eventmask; /* Mask of enabled events. */ + td_event_e eventnum; /* Number of last event. */ + void *eventdata; /* Data associated with event. */ +} td_eventbuf_t; + + +/* Gathered statistics about the process. */ +typedef struct td_ta_stats +{ + int nthreads; /* Total number of threads in use. */ + int r_concurrency; /* Concurrency level requested by user. */ + int nrunnable_num; /* Average runnable threads, numerator. */ + int nrunnable_den; /* Average runnable threads, denominator. */ + int a_concurrency_num; /* Achieved concurrency level, numerator. */ + int a_concurrency_den; /* Achieved concurrency level, denominator. */ + int nlwps_num; /* Average number of processes in use, + numerator. */ + int nlwps_den; /* Average number of processes in use, + denominator. */ + int nidle_num; /* Average number of idling processes, + numerator. */ + int nidle_den; /* Average number of idling processes, + denominator. */ +} td_ta_stats_t; + + +/* Since Sun's library is based on Solaris threads we have to define a few + types to map them to POSIX threads. */ +typedef pthread_t thread_t; +typedef pthread_key_t thread_key_t; + + +/* Callback for iteration over threads. */ +typedef int td_thr_iter_f (const td_thrhandle_t *, void *); + +/* Callback for iteration over thread local data. */ +typedef int td_key_iter_f (thread_key_t, void (*) (void *), void *); + + + +/* Forward declaration. This has to be defined by the user. */ +struct ps_prochandle; + + +/* Information about the thread. */ +typedef struct td_thrinfo +{ + td_thragent_t *ti_ta_p; /* Process handle. */ + unsigned int ti_user_flags; /* Unused. */ + thread_t ti_tid; /* Thread ID returned by + pthread_create(). */ + char *ti_tls; /* Pointer to thread-local data. */ + psaddr_t ti_startfunc; /* Start function passed to + pthread_create(). */ + psaddr_t ti_stkbase; /* Base of thread's stack. */ + long int ti_stksize; /* Size of thread's stack. */ + psaddr_t ti_ro_area; /* Unused. */ + int ti_ro_size; /* Unused. */ + td_thr_state_e ti_state; /* Thread state. */ + unsigned char ti_db_suspended; /* Nonzero if suspended by debugger. */ + td_thr_type_e ti_type; /* Type of the thread (system vs + user thread). */ + intptr_t ti_pc; /* Unused. */ + intptr_t ti_sp; /* Unused. */ + short int ti_flags; /* Unused. */ + int ti_pri; /* Thread priority. */ + lwpid_t ti_lid; /* Kernel PID for this thread. */ + sigset_t ti_sigmask; /* Signal mask. */ + unsigned char ti_traceme; /* Nonzero if event reporting + enabled. */ + unsigned char ti_preemptflag; /* Unused. */ + unsigned char ti_pirecflag; /* Unused. */ + sigset_t ti_pending; /* Set of pending signals. */ + td_thr_events_t ti_events; /* Set of enabled events. */ +} td_thrinfo_t; + + + +/* Prototypes for exported library functions. */ + +/* Initialize the thread debug support library. */ +extern td_err_e td_init (void); + +/* Historical relict. Should not be used anymore. */ +extern td_err_e td_log (void); + +/* Return list of symbols the library can request. */ +extern const char **td_symbol_list (void); + +/* Generate new thread debug library handle for process PS. */ +extern td_err_e td_ta_new (struct ps_prochandle *__ps, td_thragent_t **__ta); + +/* Free resources allocated for TA. */ +extern td_err_e td_ta_delete (td_thragent_t *__ta); + +/* Get number of currently running threads in process associated with TA. */ +extern td_err_e td_ta_get_nthreads (const td_thragent_t *__ta, int *__np); + +/* Return process handle passed in `td_ta_new' for process associated with + TA. */ +extern td_err_e td_ta_get_ph (const td_thragent_t *__ta, + struct ps_prochandle **__ph); + +/* Map thread library handle PT to thread debug library handle for process + associated with TA and store result in *TH. */ +extern td_err_e td_ta_map_id2thr (const td_thragent_t *__ta, pthread_t __pt, + td_thrhandle_t *__th); + +/* Map process ID LWPID to thread debug library handle for process + associated with TA and store result in *TH. */ +extern td_err_e td_ta_map_lwp2thr (const td_thragent_t *__ta, lwpid_t __lwpid, + td_thrhandle_t *__th); + + +/* Call for each thread in a process associated with TA the callback function + CALLBACK. */ +extern td_err_e td_ta_thr_iter (const td_thragent_t *__ta, + 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); + +/* Call for each defined thread local data entry the callback function KI. */ +extern td_err_e td_ta_tsd_iter (const td_thragent_t *__ta, td_key_iter_f *__ki, + void *__p); + + +/* Get event address for EVENT. */ +extern td_err_e td_ta_event_addr (const td_thragent_t *__ta, + td_event_e __event, td_notify_t *__ptr); + +/* Enable EVENT in global mask. */ +extern td_err_e td_ta_set_event (const td_thragent_t *__ta, + td_thr_events_t *__event); + +/* Disable EVENT in global mask. */ +extern td_err_e td_ta_clear_event (const td_thragent_t *__ta, + td_thr_events_t *__event); + +/* Return information about last event. */ +extern td_err_e td_ta_event_getmsg (const td_thragent_t *__ta, + td_event_msg_t *__msg); + + +/* Set suggested concurrency level for process associated with TA. */ +extern td_err_e td_ta_setconcurrency (const td_thragent_t *__ta, int __level); + + +/* Enable collecting statistics for process associated with TA. */ +extern td_err_e td_ta_enable_stats (const td_thragent_t *__ta, int __enable); + +/* Reset statistics. */ +extern td_err_e td_ta_reset_stats (const td_thragent_t *__ta); + +/* Retrieve statistics from process associated with TA. */ +extern td_err_e td_ta_get_stats (const td_thragent_t *__ta, + td_ta_stats_t *__statsp); + + +/* Validate that TH is a thread handle. */ +extern td_err_e td_thr_validate (const td_thrhandle_t *__th); + +/* Return information about thread TH. */ +extern td_err_e td_thr_get_info (const td_thrhandle_t *__th, + td_thrinfo_t *__infop); + +/* Retrieve floating-point register contents of process running thread TH. */ +extern td_err_e td_thr_getfpregs (const td_thrhandle_t *__th, + prfpregset_t *__regset); + +/* Retrieve general register contents of process running thread TH. */ +extern td_err_e td_thr_getgregs (const td_thrhandle_t *__th, + prgregset_t __gregs); + +/* Retrieve extended register contents of process running thread TH. */ +extern td_err_e td_thr_getxregs (const td_thrhandle_t *__th, void *__xregs); + +/* Get size of extended register set of process running thread TH. */ +extern td_err_e td_thr_getxregsize (const td_thrhandle_t *__th, int *__sizep); + +/* Set floating-point register contents of process running thread TH. */ +extern td_err_e td_thr_setfpregs (const td_thrhandle_t *__th, + const prfpregset_t *__fpregs); + +/* Set general register contents of process running thread TH. */ +extern td_err_e td_thr_setgregs (const td_thrhandle_t *__th, + prgregset_t __gregs); + +/* Set extended register contents of process running thread TH. */ +extern td_err_e td_thr_setxregs (const td_thrhandle_t *__th, + const void *__addr); + + +/* Get address of the given module's TLS storage area for the given thread. */ +extern td_err_e td_thr_tlsbase (const td_thrhandle_t *__th, + unsigned long int __modid, + psaddr_t *__base); + +/* Get address of thread local variable. */ +extern td_err_e td_thr_tls_get_addr (const td_thrhandle_t *__th, + psaddr_t __map_address, size_t __offset, + psaddr_t *__address); + + +/* Enable reporting for EVENT for thread TH. */ +extern td_err_e td_thr_event_enable (const td_thrhandle_t *__th, int __event); + +/* Enable EVENT for thread TH. */ +extern td_err_e td_thr_set_event (const td_thrhandle_t *__th, + td_thr_events_t *__event); + +/* Disable EVENT for thread TH. */ +extern td_err_e td_thr_clear_event (const td_thrhandle_t *__th, + td_thr_events_t *__event); + +/* Get event message for thread TH. */ +extern td_err_e td_thr_event_getmsg (const td_thrhandle_t *__th, + td_event_msg_t *__msg); + + +/* Set priority of thread TH. */ +extern td_err_e td_thr_setprio (const td_thrhandle_t *__th, int __prio); + + +/* Set pending signals for thread TH. */ +extern td_err_e td_thr_setsigpending (const td_thrhandle_t *__th, + unsigned char __n, const sigset_t *__ss); + +/* Set signal mask for thread TH. */ +extern td_err_e td_thr_sigsetmask (const td_thrhandle_t *__th, + const sigset_t *__ss); + + +/* Return thread local data associated with key TK in thread TH. */ +extern td_err_e td_thr_tsd (const td_thrhandle_t *__th, + const thread_key_t __tk, void **__data); + + +/* Suspend execution of thread TH. */ +extern td_err_e td_thr_dbsuspend (const td_thrhandle_t *__th); + +/* Resume execution of thread TH. */ +extern td_err_e td_thr_dbresume (const td_thrhandle_t *__th); + +#endif /* thread_db.h */ diff --git a/libpthread/nptl_db/thread_dbP.h b/libpthread/nptl_db/thread_dbP.h new file mode 100644 index 000000000..c53d1ed94 --- /dev/null +++ b/libpthread/nptl_db/thread_dbP.h @@ -0,0 +1,254 @@ +/* Private header for thread debug library + Copyright (C) 2003, 2004 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" /* This is for *_BITMASK only. */ + +/* Indeces for the symbol names. */ +enum + { +# 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_FUNCTION(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_FUNCTION +# 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 + }; + + +/* Comment out the following for less verbose output. */ +#ifndef NDEBUG +# define LOG(c) if (__td_debug) write (2, c "\n", strlen (c "\n")) +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) ((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; + + /* 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_FUNCTION(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_FUNCTION +# undef DB_SYMBOL +# undef DB_VARIABLE + + /* 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 attribute_hidden; + + +/* Function used to test for correct thread agent pointer. */ +static inline bool +ta_ok (const td_thragent_t *ta) +{ + list_t *runp; + + list_for_each (runp, &__td_agent_list) + if (list_entry (runp, td_thragent_t, list) == ta) + return true; + + return false; +} + + +/* Internal wrapper around ps_pglobal_lookup. */ +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 */ |