@@ -1,3 +1,42 @@
+2017-05-18 Djordje Todorovic <djordje.todorovic@rt-rk.com>
+
+ * Makefile.in(INTERNAL_CCFLAGS): Add CFLAGS for glibc-dep/.
+ (CCOMPILE): Force glibc-dep/ to be compiled with gcc.
+ * gdb/config/glibc.mh(GLIBCFILES): Define object files that
+ will be generated in order to read TLS with GDB Multiarch.
+ [DCROSS_GDB]: Define if it's GDB Multiarch.
+ * gdb/configure.ac(cross_makefile_frag): Add GLIBCFILES in
+ order to generate Makefile for cross platforms to read TLS.
+ * gdb/configure: Regenerate.
+ * gdb/gdb_proc_service.h: Add necessary code in order to
+ compile glibc-dep/ with GCC.
+ * gdb/gdbarch.c: Likewise.
+ * gdb/glibc-dep/README.txt: Brief explanation of glibc-dep/.
+ * gdb/glibc-dep/gdb_td_ta_new.c(init_target_dep_constants): New
+ function.
+ (gdb_td_ta_new): Get current version of GLIBC from coredump file.
+ * gdb/glibc-dep/native-check.c(get_host_mach): New function.
+ (native_check): Check if it is native architecture when using
+ GDB Multiarch.
+ * gdb/glibc-dep/db-symbols.h: Take necessary code from GLIBC
+ in order to annul differences between GLIBC versions for reading
+ TLS.
+ * gdb/glibc-dep/nptl_db/fetch-value.c: Likewise.
+ * gdb/glibc-dep/nptl_db/structs.def: Likewise.
+ * gdb/glibc-dep/nptl_db/td_symbol_list.c: Likewise.
+ * gdb/glibc-dep/nptl_db/td_ta_map_lwp2thr.c: Likewise.
+ * gdb/glibc-dep/nptl_db/td_thr_tls_get_addr.c: Likewise.
+ * gdb/glibc-dep/nptl_db/td_thr_tlsbase.c: Likewise. Modify in
+ order to work with different versions of GLIBC.
+ * gdb/glibc-dep/nptl_db/thread_dbP.h: Likewise.
+ * gdb/glibc-dep/nptl_db/tls.h: Likewise.
+ * gdb/gregset.h: Remove deprecated gregset_t but use
+ elf_gregset_t.
+ * gdb/linux-thread-db.c: (try_thread_db_load_1): Set up TLS
+ functions from glibc-dep/.
+ * gdb/nat/gdb_thread_db.h: (gdb_td_ta_new, gdb_td_thr_tlsbase)
+ (gdb_td_thr_tls_get_addr, native_check): Declare TLS functions.
+
2017-05-17 Yao Qi <yao.qi@linaro.org>
* cli/cli-decode.c (add_alias_cmd): New function.
@@ -117,6 +117,9 @@ depcomp = $(SHELL) $(srcdir)/../depcomp
COMPILE.pre = $(CXX) $(CXX_DIALECT)
COMPILE.post = -c -o $@
COMPILE = $(COMPILE.pre) $(INTERNAL_CFLAGS) $(COMPILE.post)
+INTERNAL_CCFLAGS_TMP = $(filter-out -Wpointer-arith, $(INTERNAL_CFLAGS))
+INTERNAL_CCFLAGS = $(filter-out -Werror, $(INTERNAL_CCFLAGS_TMP))
+CCOMPILE = $(CC) $(INTERNAL_CCFLAGS) $(COMPILE.post)
POSTCOMPILE = @true
# Directory containing source files.
@@ -920,6 +923,10 @@ HAVE_NATIVE_GCORE_HOST = @HAVE_NATIVE_GCORE_HOST@
# End of native-target dependent variables.
+# Cross fragment
+@cross_makefile_frag@
+# End of cross fragment
+
FLAGS_TO_PASS = \
"prefix=$(prefix)" \
"exec_prefix=$(exec_prefix)" \
@@ -1616,7 +1623,7 @@ INFOFILES = gdb.info*
# Makefile.in
DEPFILES = $(TARGET_OBS) $(SER_HARDWIRE) $(NATDEPFILES) \
- $(REMOTE_OBS) $(SIM_OBS)
+ $(REMOTE_OBS) $(SIM_OBS) $(GLIBCFILES)
SOURCES = $(SFILES) $(ALLDEPFILES) $(YYFILES) $(CONFIG_SRCS)
# Don't include YYFILES (*.c) because we already include *.y in SFILES,
@@ -1945,6 +1952,14 @@ all: gdb$(EXEEXT) $(CONFIG_ALL)
$(COMPILE) $<
$(POSTCOMPILE)
+%.o: $(srcdir)/glibc-dep/%.c
+ $(CCOMPILE) $<
+ $(POSTCOMPILE)
+
+%.o: ${srcdir}/glibc-dep/nptl_db/%.c
+ $(CCOMPILE) $<
+ $(POSTCOMPILE)
+
# Specify an explicit rule for gdb/common/agent.c, to avoid a clash with the
# object file generate by gdb/agent.c.
common-agent.o: $(srcdir)/common/agent.c
new file mode 100644
@@ -0,0 +1,6 @@
+# GLIBC fragment comes in here
+GLIBCFILES = td_symbol_list.o \
+ fetch-value.o gdb_td_ta_new.o \
+ td_thr_tlsbase.o td_thr_tls_get_addr.o \
+ td_ta_map_lwp2thr.o native_check.o
+INTERNAL_CFLAGS += -DCROSS_GDB
@@ -806,7 +806,8 @@ PACKAGE_TARNAME
PACKAGE_NAME
PATH_SEPARATOR
SHELL'
-ac_subst_files='nat_makefile_frag'
+ac_subst_files='nat_makefile_frag
+cross_makefile_frag'
ac_user_opts='
enable_option_checking
enable_maintainer_mode
@@ -16738,6 +16739,13 @@ if test "${gdb_native}" = "yes"; then
nativefile=$NAT_FILE
fi
+if test "${gdb_native}" = "no" || test "${enable_targets}" != ""; then
+ cross_makefile_frag=${srcdir}/config/glibc.mh
+else
+ cross_makefile_frag=/dev/null
+fi
+
+
@@ -2206,6 +2206,12 @@ if test "${gdb_native}" = "yes"; then
nativefile=$NAT_FILE
fi
+if test "${gdb_native}" = "no" || test "${enable_targets}" != ""; then
+ cross_makefile_frag=${srcdir}/config/glibc.mh
+else
+ cross_makefile_frag=/dev/null
+fi
+
AC_SUBST(NAT_FILE)
AC_SUBST(NATDEPFILES)
AC_SUBST(NAT_CDEPS)
@@ -2215,6 +2221,7 @@ AC_SUBST(XM_CLIBS)
AC_SUBST(NAT_GENERATED_FILES)
AC_SUBST(HAVE_NATIVE_GCORE_HOST)
AC_SUBST_FILE(nat_makefile_frag)
+AC_SUBST_FILE(cross_makefile_frag)
if test x"${gdb_osabi}" != x ; then
AC_DEFINE_UNQUOTED(GDB_OSABI_DEFAULT, $gdb_osabi,
@@ -62,7 +62,9 @@ EXTERN_C_POP
#include <sys/procfs.h>
#endif
+#ifdef __cplusplus
EXTERN_C_PUSH
+#endif
/* Functions in this interface return one of these status codes. */
typedef enum
@@ -159,7 +161,9 @@ extern ps_err_e ps_lsetxregs (struct ps_prochandle *ph, lwpid_t lwpid,
/* Log a message (sends to gdb_stderr). */
extern void ps_plog (const char *fmt, ...);
+#ifdef __cplusplus
EXTERN_C_POP
+#endif
#endif /* HAVE_PROC_SERVICE_H */
@@ -175,11 +179,20 @@ typedef gdb_fpregset_t gdb_prfpregset_t;
typedef prfpregset_t gdb_prfpregset_t;
#endif
+/* The macro is called because gdb_proc_service.h is included from
+ glibc-dep/nptl_db/thread_dbP.h which is used when compiling
+ glibc-dep files with gcc and the structure below has c++ class
+ ptid as field. When this header is included from
+ glibc-dep/nptl_db/thread_dbP.h there is only need for functions
+ definitions and struct ps_prochandle forward declaration.
+*/
+#ifndef _THREAD_DBP_H
/* GDB specific structure that identifies the target process. */
struct ps_prochandle
{
/* The LWP we use for memory reads. */
ptid_t ptid;
};
+#endif
#endif /* gdb_proc_service.h */
@@ -1497,7 +1497,7 @@ gdbarch_tdep (struct gdbarch *gdbarch)
}
-const struct bfd_arch_info *
+EXTERN_C const struct bfd_arch_info *
gdbarch_bfd_arch_info (struct gdbarch *gdbarch)
{
gdb_assert (gdbarch != NULL);
@@ -5465,7 +5465,7 @@ set_target_gdbarch (struct gdbarch *new_gdbarch)
/* Return the current inferior's arch. */
-struct gdbarch *
+EXTERN_C struct gdbarch *
target_gdbarch (void)
{
return current_inferior ()->gdbarch;
@@ -83,7 +83,7 @@ struct ui_out;
gdbarch. */
/* This is a convenience wrapper for 'current_inferior ()->gdbarch'. */
-extern struct gdbarch *target_gdbarch (void);
+EXTERN_C struct gdbarch *target_gdbarch (void);
/* Callback type for the 'iterate_over_objfiles_in_search_order'
gdbarch method. */
@@ -103,8 +103,8 @@ typedef void (iterate_over_regset_sections_cb)
/* The following are pre-initialized by GDBARCH. */
+EXTERN_C const struct bfd_arch_info * gdbarch_bfd_arch_info (struct gdbarch *gdbarch);
-extern const struct bfd_arch_info * gdbarch_bfd_arch_info (struct gdbarch *gdbarch);
/* set_gdbarch_bfd_arch_info() - not applicable - pre-initialized. */
extern enum bfd_endian gdbarch_byte_order (struct gdbarch *gdbarch);
new file mode 100644
@@ -0,0 +1,42 @@
+Files and functions taken from GLIBC source code (${glibc_src}/nptl_db/) necessary for getting
+TLS variables (from coredump file) when cross GDB using GLIBC version 2.22 and higher are stored into
+${gdb_src}/glibc-dep/nptl_db directory.
+
+gdb_td_ta_new() is stored into ${gdb_src}/glibc-dep/ because functionality of function (td_ta_new())
+from GLIBC source has changed in order to get current version of GLIBC from coredump file.
+
+gdb_td_thr_tlsbase is function taken from nptl_db/td_thr_tlsbase.c,
+which has modified in GLIBC 2.22 and higher, so all dependent files had to be included into GDB source.
+
+------------------------
+
+${gdb_src}/glibc-dep/nptl_db
+
+* thread_dbP.h
+Taken needed definitions and macros.
+
+* db-symbols.h
+Unmodified.
+
+* fetch-value.c
+Taken needed functions.
+
+* structs.def
+Unmodified.
+
+* td_symbol_list.c
+Taken necessary definitions and modified td_lookup function.
+
+* td_ta_map_lwp2thr.c
+Taken only __td_ta_lookup_th_unique function unmodified.
+
+* td_thr_tlsbase.c
+gdb_td_thr_tlsbase(), modified in order to work with all GLIBC versions.
+${gdb_src}/gdb/config/${arch}/tls.h depending on architecture got different
+values of TLS_TCB_AT_TP and TLS_DTV_AT_TP macros taken
+from ${glibc_src}/sysdeps/${arch}/nptl/tls.h.
+
+* td_thr_tls_get_addr.c
+Unmodified.
+
+-------------------------
\ No newline at end of file
new file mode 100644
@@ -0,0 +1,97 @@
+/* Copyright (C) 2000-2017 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <version.h>
+
+#include "nptl_db/thread_dbP.h"
+#include "nat/gdb_thread_db.h"
+#include "nptl_db/tls.h"
+#include "bfd.h"
+
+struct gdbarch;
+extern const struct bfd_arch_info *gdbarch_bfd_arch_info (struct gdbarch *gdbarch);
+extern struct gdbarch *target_gdbarch (void);
+
+static td_err_e
+init_target_dep_constants ()
+{
+ const struct bfd_arch_info *bfdarch = gdbarch_bfd_arch_info (target_gdbarch ());
+ unsigned arch = bfdarch->arch;
+ switch (arch)
+ {
+ case bfd_arch_mips:
+ tls_tcb_at_tp = 0;
+ tls_dtv_at_tp = 1;
+ forced_dynamic_tls_offset = -2;
+ no_tls_offset = -1;
+ tcb_alignment = 16;
+ break;
+ case bfd_arch_arm:
+ tls_tcb_at_tp = 0;
+ tls_dtv_at_tp = 1;
+ forced_dynamic_tls_offset = -2;
+ no_tls_offset = -1;
+ /* Set to zero because not in use for TLS_PRE_TCB_SIZE. */
+ tcb_alignment = 0;
+ break;
+ case bfd_arch_i386:
+ tls_tcb_at_tp = 1;
+ tls_dtv_at_tp = 0;
+ forced_dynamic_tls_offset = -1;
+ no_tls_offset = 0;
+ /* Set to zero because not in use for TLS_PRE_TCB_SIZE. */
+ tcb_alignment = 0;
+ break;
+ case bfd_arch_powerpc:
+ tls_tcb_at_tp = 0;
+ tls_dtv_at_tp = 1;
+ forced_dynamic_tls_offset = -2;
+ no_tls_offset = -1;
+ tcb_alignment = 48;
+ break;
+ case bfd_arch_aarch64:
+ tls_tcb_at_tp = 0;
+ tls_dtv_at_tp = 1;
+ forced_dynamic_tls_offset = -1;
+ no_tls_offset = 0;
+ /* Set to zero because not in use for TLS_PRE_TCB_SIZE. */
+ tcb_alignment = 0;
+ break;
+ default:
+ return TD_ERR;
+ }
+ return TD_OK;
+}
+
+
+td_err_e
+gdb_td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta)
+{
+ psaddr_t versaddr;
+
+ /* 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 (init_target_dep_constants () != TD_OK)
+ return TD_ERR;
+ return TD_OK;
+}
new file mode 100644
@@ -0,0 +1,65 @@
+/* Copyright (C) 2000-2017 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "native_check.h"
+#include <string.h>
+#include <stdio.h>
+#include "../config.h"
+#include "bfd.h"
+#include <sys/utsname.h>
+
+unsigned get_host_mach (char *name_of_arch)
+{
+ unsigned result;
+
+ if (strstr (name_of_arch, "x86_64") != NULL)
+ result = bfd_arch_i386;
+ else if (strstr (name_of_arch, "i386") != NULL)
+ result = bfd_arch_i386;
+ else if (strstr (name_of_arch, "mips") != NULL)
+ result = bfd_arch_mips;
+ else if (strstr (name_of_arch, "arm") != NULL)
+ result = bfd_arch_arm;
+ else if (strstr (name_of_arch, "powerpc") != NULL)
+ result = bfd_arch_powerpc;
+ else if (strstr (name_of_arch, "aarch64") != NULL)
+ result = bfd_arch_aarch64;
+ else
+ result = -1;
+
+ return result;
+}
+
+int native_check (unsigned bfd_arch)
+{
+ struct utsname buf;
+ if (uname (&buf) == 0)
+ {
+ unsigned host_mach = get_host_mach (buf.machine);
+
+ if (host_mach == bfd_arch)
+ {
+ /* zero if it's host */
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+ return -1;
+}
\ No newline at end of file
new file mode 100644
@@ -0,0 +1,19 @@
+/* Copyright (C) 2000-2017 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+unsigned get_host_mach (char *name_of_arch);
+int native_check (unsigned bfd_arch);
\ No newline at end of file
new file mode 100644
@@ -0,0 +1,51 @@
+/* List of symbols in libpthread examined by libthread_db.
+ Copyright (C) 2009-2016 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#define DOT(x) x /* No prefix. */
+
+#define STRINGIFY(name) STRINGIFY_1(name)
+#define STRINGIFY_1(name) #name
+
+#define DB_STRUCT(type) \
+ DB_LOOKUP_NAME (SYM_SIZEOF_##type, _thread_db_sizeof_##type)
+#define DB_STRUCT_FIELD(type, field) \
+ DB_LOOKUP_NAME (SYM_##type##_FIELD_##field, _thread_db_##type##_##field)
+#define DB_SYMBOL(name) \
+ DB_LOOKUP_NAME (SYM_##name, name)
+#define DB_FUNCTION(name) \
+ DB_LOOKUP_NAME (SYM_##name, DOT (name))
+#define DB_VARIABLE(name) \
+ DB_LOOKUP_NAME (SYM_##name, name) \
+ DB_LOOKUP_NAME (SYM_DESC_##name, _thread_db_##name)
+
+# include "structs.def"
+
+# undef DB_STRUCT
+# undef DB_FUNCTION
+# undef DB_SYMBOL
+# undef DB_VARIABLE
+# undef DOT
+
+DB_LOOKUP_NAME_TH_UNIQUE (SYM_TH_UNIQUE_REGISTER64, _thread_db_register64)
+DB_LOOKUP_NAME_TH_UNIQUE (SYM_TH_UNIQUE_REGISTER32, _thread_db_register32)
+DB_LOOKUP_NAME_TH_UNIQUE (SYM_TH_UNIQUE_CONST_THREAD_AREA,
+ _thread_db_const_thread_area)
+DB_LOOKUP_NAME_TH_UNIQUE (SYM_TH_UNIQUE_REGISTER32_THREAD_AREA,
+ _thread_db_register32_thread_area)
+DB_LOOKUP_NAME_TH_UNIQUE (SYM_TH_UNIQUE_REGISTER64_THREAD_AREA,
+ _thread_db_register64_thread_area)
new file mode 100644
@@ -0,0 +1,191 @@
+/* Helper routines for libthread_db.
+ Copyright (C) 2003-2016 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include "thread_dbP.h"
+#include <byteswap.h>
+#include <assert.h>
+#include <stdint.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 && DB_DESC_NELEM (desc) != 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_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;
+}
new file mode 100644
@@ -0,0 +1,112 @@
+/* List of types and symbols in libpthread examined by libthread_db.
+ Copyright (C) 2003-2016 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#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
+
+#ifndef DB_RTLD_VARIABLE
+# define DB_RTLD_VARIABLE(name) DB_VARIABLE (name)
+#endif
+
+#ifndef DB_MAIN_VARIABLE
+# define DB_MAIN_VARIABLE(name) DB_VARIABLE (name)
+#endif
+
+#ifndef DB_RTLD_GLOBAL_FIELD
+#define DB_RTLD_GLOBAL_FIELD(field) \
+ DB_STRUCT_FIELD (rtld_global, _##field) \
+ DB_MAIN_VARIABLE (_##field)
+#endif /* DB_RTLD_GLOBAL_FIELD */
+
+DB_STRUCT (pthread)
+DB_STRUCT_FIELD (pthread, list)
+DB_STRUCT_FIELD (pthread, report_events)
+DB_STRUCT_FIELD (pthread, tid)
+DB_STRUCT_FIELD (pthread, pid)
+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_VARIABLE (__nptl_initial_report_events)
+
+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)
+
+DB_STRUCT_FIELD (link_map, l_tls_modid)
+DB_STRUCT_FIELD (link_map, l_tls_offset)
+
+DB_STRUCT_ARRAY_FIELD (dtv, dtv)
+#define pointer_val pointer.val /* Field of anonymous struct in dtv_t. */
+DB_STRUCT_FIELD (dtv_t, pointer_val)
+DB_STRUCT_FIELD (dtv_t, counter)
+DB_STRUCT_FIELD (pthread, dtvp)
+
+DB_STRUCT (rtld_global)
+DB_RTLD_VARIABLE (_rtld_global)
+DB_RTLD_GLOBAL_FIELD (dl_tls_dtv_slotinfo_list)
+
+DB_STRUCT (dtv_slotinfo_list)
+DB_STRUCT_FIELD (dtv_slotinfo_list, len)
+DB_STRUCT_FIELD (dtv_slotinfo_list, next)
+DB_STRUCT_ARRAY_FIELD (dtv_slotinfo_list, slotinfo)
+
+DB_STRUCT (dtv_slotinfo)
+DB_STRUCT_FIELD (dtv_slotinfo, gen)
+DB_STRUCT_FIELD (dtv_slotinfo, map)
+
+#ifdef STRUCTS_DEF_DEFAULTS
+# undef DB_STRUCT_ARRAY_FIELD
+# undef DB_ARRAY_VARIABLE
+# undef STRUCTS_DEF_DEFAULTS
+#endif
new file mode 100644
@@ -0,0 +1,45 @@
+/* Return list of symbols the library can request.
+ Copyright (C) 2001,2002,2003,2009 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+#include <gnu/lib-names.h>
+#include "thread_dbP.h"
+
+
+static const char *symbol_list_arr[] =
+{
+# define DB_LOOKUP_NAME(idx, name) [idx] = STRINGIFY (name),
+# define DB_LOOKUP_NAME_TH_UNIQUE(idx, name) [idx] = STRINGIFY (name),
+# include "db-symbols.h"
+# undef DB_LOOKUP_NAME
+# undef DB_LOOKUP_NAME_TH_UNIQUE
+
+ [SYM_NUM_MESSAGES] = NULL
+};
+
+ps_err_e
+td_mod_lookup (struct ps_prochandle *ps, const char *mod,
+ int idx, psaddr_t *sym_addr)
+{
+ ps_err_e result;
+ assert (idx >= 0 && idx < SYM_NUM_MESSAGES);
+ result = ps_pglobal_lookup (ps, mod, symbol_list_arr[idx], sym_addr);
+
+ return result;
+}
\ No newline at end of file
new file mode 100644
@@ -0,0 +1,167 @@
+/* Which thread is running on an LWP?
+ Copyright (C) 2003-2016 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include "thread_dbP.h"
+#include <byteswap.h>
+
+
+td_err_e
+__td_ta_lookup_th_unique (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;
+
+ 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)
+ {
+ 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 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, a register holds the 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 = ta;
+
+ return TD_OK;
+}
\ No newline at end of file
new file mode 100644
@@ -0,0 +1,42 @@
+/* Get address of thread local variable.
+ Copyright (C) 2002-2015 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+gdb_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 = gdb_td_thr_tlsbase (th, (uintptr_t) modid, address);
+ if (err == TD_OK)
+ *address += offset;
+ }
+ return err;
+}
new file mode 100644
@@ -0,0 +1,249 @@
+/* Locate TLS data for a thread.
+ Copyright (C) 2003-2016 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include "thread_dbP.h"
+#include "nat/gdb_thread_db.h"
+#include "tls.h"
+
+/* Get the DTV slotinfo list head entry from the dynamic loader state
+ into *LISTHEAD. */
+static td_err_e
+dtv_slotinfo_list (td_thragent_t *ta,
+ psaddr_t *listhead)
+{
+ td_err_e err;
+ psaddr_t head;
+
+ if (ta->ta_addr__rtld_global == 0
+ && td_mod_lookup (ta->ph, LD_SO, SYM__rtld_global,
+ &ta->ta_addr__rtld_global) != PS_OK)
+ ta->ta_addr__rtld_global = (void*)-1;
+
+ if (ta->ta_addr__rtld_global != (void*)-1)
+ {
+ err = DB_GET_FIELD (head, ta, ta->ta_addr__rtld_global,
+ rtld_global, _dl_tls_dtv_slotinfo_list, 0);
+ if (err != TD_OK)
+ return err;
+ }
+ else
+ {
+ if (ta->ta_addr__dl_tls_dtv_slotinfo_list == 0
+ && td_mod_lookup (ta->ph, NULL, SYM__dl_tls_dtv_slotinfo_list,
+ &ta->ta_addr__dl_tls_dtv_slotinfo_list) != PS_OK)
+ return TD_ERR;
+
+ err = _td_fetch_value (ta, ta->ta_var__dl_tls_dtv_slotinfo_list,
+ SYM_DESC__dl_tls_dtv_slotinfo_list,
+ 0, ta->ta_addr__dl_tls_dtv_slotinfo_list, &head);
+ if (err != TD_OK)
+ return err;
+ }
+
+ *listhead = head;
+ return TD_OK;
+}
+
+/* Get the address of the DTV slotinfo entry for MODID into
+ *DTVSLOTINFO. */
+static td_err_e
+dtv_slotinfo (td_thragent_t *ta,
+ unsigned long int modid,
+ psaddr_t *dtvslotinfo)
+{
+ td_err_e err;
+ psaddr_t slot, temp;
+ size_t slbase = 0;
+
+ err = dtv_slotinfo_list (ta, &slot);
+ if (err != TD_OK)
+ return err;
+
+ while (slot)
+ {
+ /* Get the number of entries in this list entry's array. */
+ err = DB_GET_FIELD (temp, ta, slot, dtv_slotinfo_list, len, 0);
+ if (err != TD_OK)
+ return err;
+ size_t len = (uintptr_t)temp;
+
+ /* Did we find the list entry for modid? */
+ if (modid < slbase + len)
+ break;
+
+ /* We didn't, so get the next list entry. */
+ slbase += len;
+ err = DB_GET_FIELD (temp, ta, slot, dtv_slotinfo_list,
+ next, 0);
+ if (err != TD_OK)
+ return err;
+ slot = temp;
+ }
+
+ /* We reached the end of the list and found nothing. */
+ if (!slot)
+ return TD_ERR;
+
+ /* Take the slotinfo for modid from the list entry. */
+ err = DB_GET_FIELD_ADDRESS (temp, ta, slot, dtv_slotinfo_list,
+ slotinfo, modid - slbase);
+ if (err != TD_OK)
+ return err;
+ slot = temp;
+
+ *dtvslotinfo = slot;
+ return TD_OK;
+}
+
+/* Return in *BASE the base address of the TLS block for MODID within
+ TH.
+
+ It should return success and yield the correct pointer in any
+ circumstance where the TLS block for the module and thread
+ requested has already been initialized.
+
+ It should fail with TD_TLSDEFER only when the thread could not
+ possibly have observed any values in that TLS block. That way, the
+ debugger can fall back to showing initial values from the PT_TLS
+ segment (and refusing attempts to mutate) for the TD_TLSDEFER case,
+ and never fail to make the values the program will actually see
+ available to the user of the debugger. */
+td_err_e
+gdb_td_thr_tlsbase (const td_thrhandle_t *th,
+ unsigned long int modid,
+ psaddr_t *base)
+{
+ td_err_e err;
+ psaddr_t dtv, dtvslot, dtvptr, temp;
+ psaddr_t map;
+ size_t modgen;
+
+ if (modid < 1)
+ return TD_NOTLS;
+
+ psaddr_t pd = th->th_unique;
+ if (pd == 0)
+ {
+ /* This is the fake handle for the main thread before libpthread
+ initialization. We are using 0 for its th_unique because we can't
+ trust that its thread register has been initialized. But we need
+ a real pointer to have any TLS access work. In case of dlopen'd
+ libpthread, initialization might not be for quite some time. So
+ try looking up the thread register now. Worst case, it's nonzero
+ uninitialized garbage and we get bogus results for TLS access
+ attempted too early. Tough. */
+
+ td_thrhandle_t main_th;
+ err = __td_ta_lookup_th_unique (th->th_ta_p, ps_getpid (th->th_ta_p->ph),
+ &main_th);
+ if (err == 0)
+ pd = main_th.th_unique;
+ if (pd == 0)
+ return TD_TLSDEFER;
+ }
+
+ if (strcmp (versbuf,"2.22") >= 0)
+ {
+ err = dtv_slotinfo (th->th_ta_p, modid, &temp);
+ if (err != TD_OK)
+ return err;
+
+ psaddr_t slot;
+ err = DB_GET_STRUCT (slot, th->th_ta_p, temp, dtv_slotinfo);
+ if (err != TD_OK)
+ return err;
+
+ /* Take the link_map from the slotinfo. */
+ err = DB_GET_FIELD_LOCAL (map, th->th_ta_p, slot, dtv_slotinfo, map, 0);
+ if (err != TD_OK)
+ return err;
+ if (!map)
+ return TD_ERR;
+
+ /* Ok, the modid is good, now find out what DTV generation it
+ requires. */
+ err = DB_GET_FIELD_LOCAL (temp, th->th_ta_p, slot, dtv_slotinfo, gen, 0);
+ if (err != TD_OK)
+ return err;
+ modgen = (uintptr_t)temp;
+ }
+
+ /* Get the DTV pointer from the thread descriptor. */
+ err = DB_GET_FIELD (dtv, th->th_ta_p, pd, pthread, dtvp, 0);
+ if (err != TD_OK)
+ return err;
+
+ if (strcmp (versbuf,"2.22") >= 0)
+ {
+ psaddr_t dtvgenloc;
+ /* Get the DTV generation count at dtv[0].counter. */
+ err = DB_GET_FIELD_ADDRESS (dtvgenloc, th->th_ta_p, dtv, dtv, dtv, 0);
+ if (err != TD_OK)
+ return err;
+ err = DB_GET_FIELD (temp, th->th_ta_p, dtvgenloc, dtv_t, counter, 0);
+ if (err != TD_OK)
+ return err;
+ size_t dtvgen = (uintptr_t)temp;
+
+ /* Is the DTV current enough? */
+ if (dtvgen < modgen)
+ {
+ try_static_tls:
+ /* If the module uses Static TLS, we're still good. */
+ err = DB_GET_FIELD (temp, th->th_ta_p, map, link_map, l_tls_offset, 0);
+ if (err != TD_OK)
+ return err;
+ ptrdiff_t tlsoff = (uintptr_t)temp;
+
+ if (tlsoff != FORCED_DYNAMIC_TLS_OFFSET
+ && tlsoff != NO_TLS_OFFSET)
+ {
+ psaddr_t tp = pd;
+
+ if (TLS_TCB_AT_TP == 1)
+ dtvptr = tp - tlsoff;
+ else if (TLS_DTV_AT_TP == 1)
+ dtvptr = tp + tlsoff + TLS_PRE_TCB_SIZE;
+ else
+ return TD_ERR;
+
+ *base = dtvptr;
+ return TD_OK;
+ }
+
+ return TD_TLSDEFER;
+ }
+ }
+ /* Find the corresponding entry in the DTV. */
+ err = DB_GET_FIELD_ADDRESS (dtvslot, th->th_ta_p, dtv, dtv, dtv, modid);
+ if (err != TD_OK)
+ return err;
+
+ /* Extract the TLS block address from that DTV slot. */
+ err = DB_GET_FIELD (dtvptr, th->th_ta_p, dtvslot, dtv_t, pointer_val, 0);
+ 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)
+ goto try_static_tls;
+
+ *base = dtvptr;
+ return TD_OK;
+}
new file mode 100644
@@ -0,0 +1,206 @@
+/* Private header for thread debug library
+ Copyright (C) 2003, 2004, 2007, 2011 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _THREAD_DBP_H
+#define _THREAD_DBP_H 1
+
+#ifndef HAVE_SYS_PROCFS_H
+#define HAVE_SYS_PROCFS_H
+#endif
+#ifndef HAVE_LWPID_T
+#define HAVE_LWPID_T
+#endif
+#ifndef HAVE_PSADDR_T
+#define HAVE_PSADDR_T
+#endif
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <alloca.h>
+#include <assert.h>
+#include "../config.h"
+#include "gdb_proc_service.h"
+#include <gnu/lib-names.h>
+#ifdef HAVE_THREAD_DB_H
+#include <thread_db.h>
+#else
+#include "nat/glibc_thread_db.h"
+#endif
+
+# define attribute_hidden __attribute__ ((visibility ("hidden")))
+
+char versbuf[5];
+
+/* 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
+ };
+
+#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];
+
+typedef struct list_head
+{
+ struct list_head *next;
+ struct list_head *prev;
+} list_t;
+
+/* 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;
+};
+
+/* Internal wrappers around ps_pglobal_lookup. */
+extern ps_err_e td_mod_lookup (struct ps_prochandle *ps, const char *modname,
+ int idx, psaddr_t *sym_addr) attribute_hidden;
+#define td_lookup(ps, idx, sym_addr) \
+ td_mod_lookup ((ps), LIBPTHREAD_SO, (idx), (sym_addr))
+
+/* 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))
+
+/* 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;
+
+/* Helper functions for those. */
+#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; \
+ })
+
+extern td_err_e _td_check_sizeof (td_thragent_t *ta, uint32_t *sizep,
+ int sizep_name) attribute_hidden;
+
+extern td_err_e __td_ta_lookup_th_unique (const td_thragent_t *ta,
+ lwpid_t lwpid, td_thrhandle_t *th);
+
+#endif /* thread_dbP.h */
new file mode 100644
@@ -0,0 +1,37 @@
+/* Private header for thread debug library
+ Copyright (C) 2003, 2004, 2007, 2011 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef __TLS_H__
+#define __TLS_H__
+
+unsigned tls_tcb_at_tp;
+unsigned tls_dtv_at_tp;
+int forced_dynamic_tls_offset;
+int no_tls_offset;
+unsigned tcb_alignment;
+
+#define TLS_DTV_AT_TP tls_dtv_at_tp
+#define TLS_TCB_AT_TP tls_tcb_at_tp
+#define TCB_ALIGNMENT tcb_alignment
+
+#define TLS_PRE_TCB_SIZE th->th_ta_p->ta_sizeof_pthread + TCB_ALIGNMENT
+
+#define NO_TLS_OFFSET no_tls_offset
+#define FORCED_DYNAMIC_TLS_OFFSET forced_dynamic_tls_offset
+
+#endif
\ No newline at end of file
@@ -24,11 +24,11 @@
#endif
#ifndef GDB_GREGSET_T
-#define GDB_GREGSET_T gregset_t
+#define GDB_GREGSET_T elf_gregset_t
#endif
#ifndef GDB_FPREGSET_T
-#define GDB_FPREGSET_T fpregset_t
+#define GDB_FPREGSET_T elf_fpregset_t
#endif
typedef GDB_GREGSET_T gdb_gregset_t;
@@ -19,8 +19,10 @@
#include "defs.h"
#include <dlfcn.h>
+EXTERN_C_PUSH
#include "gdb_proc_service.h"
#include "nat/gdb_thread_db.h"
+EXTERN_C_POP
#include "gdb_vecs.h"
#include "bfd.h"
#include "command.h"
@@ -46,6 +48,7 @@
#include <ctype.h>
#include "nat/linux-namespaces.h"
#include <algorithm>
+#include "bfd.h"
/* GNU/Linux libthread_db support.
@@ -536,6 +539,18 @@ try_thread_db_load_1 (struct thread_db_info *info)
info->proc_handle.ptid = inferior_ptid;
/* Now attempt to open a connection to the thread library. */
+#ifdef CROSS_GDB
+ const struct bfd_arch_info *bfdarch = gdbarch_bfd_arch_info (target_gdbarch ());
+ unsigned arch = bfdarch->arch;
+
+ /* If it's host we want to keep old way of counting tls address. */
+ if (native_check (arch) != 0)
+ {
+ /* gdb_td_ta_new has similar behavior as td_ta_new, so if any
+ occurs same error will be catched in td_ta_new */
+ gdb_td_ta_new (&info->proc_handle, &info->thread_agent);
+ }
+#endif
err = info->td_ta_new_p (&info->proc_handle, &info->thread_agent);
if (err != TD_OK)
{
@@ -564,8 +579,22 @@ try_thread_db_load_1 (struct thread_db_info *info)
CHK (TDB_VERBOSE_DLSYM (info, td_thr_get_info));
/* These are not essential. */
+#ifdef CROSS_GDB
+ if (native_check (arch) != 0)
+ {
+ info->td_thr_tls_get_addr_p = gdb_td_thr_tls_get_addr;
+ info->td_thr_tlsbase_p = gdb_td_thr_tlsbase;
+ }
+ else
+ {
+ /* If it's host we want to keep old way of counting tls address. */
+ TDB_DLSYM (info, td_thr_tls_get_addr);
+ TDB_DLSYM (info, td_thr_tlsbase);
+ }
+#else
TDB_DLSYM (info, td_thr_tls_get_addr);
TDB_DLSYM (info, td_thr_tlsbase);
+#endif
/* It's best to avoid td_ta_thr_iter if possible. That walks data
structures in the inferior's address space that may be corrupted,
@@ -28,6 +28,10 @@
#define LIBTHREAD_DB_SO "libthread_db.so.1"
#endif
+#ifndef LD_SO
+#define LD_SO "ld.so.1"
+#endif
+
#ifndef LIBTHREAD_DB_SEARCH_PATH
/* $sdir appears before $pdir for some minimal security protection:
we trust the system libthread_db.so a bit more than some random
@@ -72,4 +76,15 @@ typedef td_err_e (td_thr_tlsbase_ftype) (const td_thrhandle_t *th,
typedef const char ** (td_symbol_list_ftype) (void);
typedef td_err_e (td_ta_delete_ftype) (td_thragent_t *);
+
+extern td_err_e gdb_td_ta_new (struct ps_prochandle *__ps, td_thragent_t **__ta);
+
+extern td_err_e gdb_td_thr_tlsbase (const td_thrhandle_t *th,
+ unsigned long int modid,
+ psaddr_t *base);
+extern td_err_e gdb_td_thr_tls_get_addr (const td_thrhandle_t *th,
+ psaddr_t map_address, size_t offset, psaddr_t *address);
+
+extern int native_check (unsigned bfd_arch);
+
#endif /* GDB_THREAD_DB_H */