Overview
In order to fetch TLS variable values from non-native (target) core dump
file in GDB, a few functions in GLIBC are added, some of them are
modified in order to work with both host and target platforms.
This overview describes both of GDB and GLIBC changes.
GLIBC
The problem was how to modify functions designed to work with host
platform to read TLS data from target platforms. Platform dependent
macros used to calculate start of TLS block are defined in compile time.
The idea was to dump those (target) macro values into the core file and
later retrieve them on the host platform in order to calculate start of
TLS block for target.
td_thr_tlsbase() is modified in order to work with both host and target
platforms.
td_ta_init_consts() is a new function used for initialization of host
TLS macros.
td_ta_init_target_consts() is a new function used for initialization of
target TLS macros.
GDB
GDB will use these functions in order to fetch TLS variables values from
non-native (target) core file.
Regards,
Nikola and Djordje
td_thr_tlsbase tls fetching formula was resolved in build time. It was
dependent of TLS_TCB_AT_TP, TLS_DTV_AT_TP, TLS_PRE_TCB_SIZE and
NO_TLS_OFFSET. Now it is resolved in runtime in order to achieve cross
core file tls fetching functionality. Macros that are used for fetching
are now kept in thread agent and they are initialized in td_ta_new() on
values for host architecture. When libthread_db user wants to use it for
fetching tls variable from non native core file he will need to call new
function td_ta_init_target_consts(). This function will read those
constants. They are written similarly as size of pthread.
nptl_db/ChangeLog:
2017-06-27 Nikola Prica <nikola.prica@rt-rk.com>
Djordje Todorovic <djordje.todorovic@rt-rk.com>
* td_ta_init_target_consts.c: New file.
* Makefile: Include new file.
* Versions: New function
* db-symbols.h: [DB_CONST]
* db_info.c: [DB_CONST]. Defining [TLS_PRE_TCB_SIZE]
as 0 if not defined.
* fetch-value.c: (_td_check_constant) New function
which takes body of most of (_td_check_size_of) body which
is refactored regarding that.
* structs.def: Defining TLS_PRE_TCB_SIZE, TLS_TCB_AT_TP,
TLS_DTV_AT_TP, NO_TLS_OFFSET constants.
* td_ta_new.c: (td_ta_init_target_consts) initializes
thread fetching constants in thread agent.
* td_thr_tlsbase.c: (td_thr_tlsbase) is modified to work
for multiple architectures by changing tls fetching formula
to be evaluated in runtime.
* thread_db.h: New declaration
* thread_dbP.h: [DB_CONST], [DB_GET_CONST]
db_desc_t field, int descriptor_name,
@@ -261,6 +269,8 @@ extern td_err_e _td_store_value_local (td_thragent_t
*ta,
extern td_err_e _td_check_sizeof (td_thragent_t *ta, uint32_t *sizep,
int sizep_name) attribute_hidden;
+extern td_err_e _td_check_constant (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);
@@ -44,6 +44,7 @@ libthread_db-routines = td_init td_log td_ta_new
td_ta_delete \
td_ta_set_event td_ta_event_getmsg \
td_ta_clear_event td_symbol_list \
td_thr_tlsbase td_thr_tls_get_addr \
+ td_ta_init_target_consts \
fetch-value
libthread_db-inhibit-o = $(filter-out .os,$(object-suffixes))
@@ -21,4 +21,7 @@ libthread_db {
GLIBC_2.3.3 {
td_thr_tlsbase;
}
+ GLIBC_2.26 {
+ td_ta_init_target_consts;
+ }
}
@@ -23,6 +23,8 @@
#define DB_STRUCT(type) \
DB_LOOKUP_NAME (SYM_SIZEOF_##type, _thread_db_sizeof_##type)
+#define DB_CONST(name) \
+ DB_LOOKUP_NAME (SYM_CONST_##name, _thread_db_const_##name)
#define DB_STRUCT_FIELD(type, field) \
DB_LOOKUP_NAME (SYM_##type##_FIELD_##field, _thread_db_##type##_##field)
#define DB_SYMBOL(name) \
@@ -36,6 +38,7 @@
# include "structs.def"
# undef DB_STRUCT
+# undef DB_CONST
# undef DB_FUNCTION
# undef DB_SYMBOL
# undef DB_VARIABLE
@@ -68,9 +68,15 @@ DESC (_thread_db_pthread_dtvp,
- (TLS_TCB_SIZE == 0 ? sizeof (tcbhead_t) : 0), union dtv *)
#endif
+/* Definition of this macro is neccessary for enabling cross core
debugging */
+#ifndef TLS_PRE_TCB_SIZE
+#define TLS_PRE_TCB_SIZE 0
+#endif
#define DB_STRUCT(type) \
const uint32_t _thread_db_sizeof_##type = sizeof (type);
+#define DB_CONST(name) \
+ const int32_t _thread_db_const_##name = name;
#define DB_STRUCT_FIELD(type, field) \
DESC (_thread_db_##type##_##field, \
offsetof (type, field), ((type *) 0)->field)
@@ -83,6 +89,7 @@ DESC (_thread_db_pthread_dtvp,
#define DB_FUNCTION(name) /* Nothing. */
#include "structs.def"
#undef DB_STRUCT
+#undef DB_CONST
#undef DB_STRUCT_FIELD
#undef DB_SYMBOL
#undef DB_FUNCTION
@@ -22,21 +22,28 @@
#include <stdint.h>
td_err_e
+_td_check_constant (td_thragent_t *ta, uint32_t *sizep, int sizep_name)
+{
+ 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_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_check_constant(ta,sizep, sizep_name);
return TD_OK;
}
@@ -44,6 +44,11 @@
# endif
#endif /* DB_RTLD_GLOBAL_FIELD */
+DB_CONST (TLS_PRE_TCB_SIZE)
+DB_CONST (TLS_TCB_AT_TP)
+DB_CONST (TLS_DTV_AT_TP)
+DB_CONST (NO_TLS_OFFSET)
+
DB_STRUCT (pthread)
DB_STRUCT_FIELD (pthread, list)
DB_STRUCT_FIELD (pthread, report_events)
nptl_db/td_ta_init_target_consts.c
new file mode 100644
@@ -0,0 +1,58 @@
+/* Initialization function of thread debugger support library.
+ Copyright (C) 1999-2017 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include "thread_dbP.h"
+
+td_err_e
+td_ta_init_target_consts (td_thragent_t *ta)
+{
+ td_err_e err;
+
+ err = _td_check_constant (ta, DB_GET_CONST (&ta, TLS_TCB_AT_TP),
+ SYM_CONST_TLS_TCB_AT_TP);
+ if ( err != TD_OK)
+ return err;
+ err = _td_check_constant (ta, DB_GET_CONST (&ta, TLS_DTV_AT_TP),
+ SYM_CONST_TLS_DTV_AT_TP);
+ if ( err != TD_OK)
+ return err;
+
+ if (!(DB_GET_CONST (ta, TLS_TCB_AT_TP) ^ DB_GET_CONST (ta,
TLS_DTV_AT_TP)))
+ return TD_ERR;
+
+
+ if (DB_GET_CONST (ta, TLS_DTV_AT_TP))
+ {
+ err = _td_check_constant (ta, DB_GET_CONST (&ta, TLS_PRE_TCB_SIZE),
+ SYM_CONST_TLS_PRE_TCB_SIZE);
+ if ( err != TD_OK)
+ return err;
+ }
+ else
+ {
+ DB_GET_CONST (ta, TLS_PRE_TCB_SIZE) = 0;
+ }
+
+ err = _td_check_constant (ta, DB_GET_CONST (&ta, NO_TLS_OFFSET),
+ SYM_CONST_NO_TLS_OFFSET);
+ if ( err != TD_OK)
+ return err;
+
+ return TD_OK;
+}
\ No newline at end of file
@@ -21,6 +21,7 @@
#include <stdlib.h>
#include <string.h>
#include <version.h>
+#include <link.h>
#include "thread_dbP.h"
@@ -29,6 +30,21 @@
be exactly one so we don't spend much though on making it fast. */
LIST_HEAD (__td_agent_list);
+static void
+td_ta_init_consts (td_thragent_t *ta)
+{
+ DB_GET_CONST (ta, TLS_TCB_AT_TP) = TLS_TCB_AT_TP;
+ DB_GET_CONST (ta, TLS_DTV_AT_TP) = TLS_DTV_AT_TP;
+#if TLS_DTV_AT_TP
+ DB_GET_CONST (ta, TLS_PRE_TCB_SIZE) = TLS_PRE_TCB_SIZE;
+#elif TLS_TCB_AT_TP
+ DB_GET_CONST (ta, TLS_PRE_TCB_SIZE) = 0;
+#else
+# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+#endif
+ DB_GET_CONST (ta, NO_TLS_OFFSET) = NO_TLS_OFFSET;
+}
+
td_err_e
td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta)
@@ -60,5 +76,7 @@ td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta)
/* Now add the new agent descriptor to the list. */
list_add (&(*ta)->list, &__td_agent_list);
+ td_ta_init_consts (*ta);
+
return TD_OK;
}
@@ -202,19 +202,17 @@ td_thr_tlsbase (const td_thrhandle_t *th,
if (err != TD_OK)
return err;
ptrdiff_t tlsoff = (uintptr_t)temp;
+ int8_t no_tls_offset = DB_GET_CONST (th->th_ta_p, NO_TLS_OFFSET);
+ int8_t forced_dynamic_tls_offset = no_tls_offset - 1;
- if (tlsoff != FORCED_DYNAMIC_TLS_OFFSET
- && tlsoff != NO_TLS_OFFSET)
+ if (tlsoff != forced_dynamic_tls_offset
+ && tlsoff != no_tls_offset)
{
psaddr_t tp = pd;
+ int8_t variant_sign = ((DB_GET_CONST(th->th_ta_p, TLS_TCB_AT_TP)) ?
(-1) : (1));
+ uint32_t tls_pre_tcb_size = DB_GET_CONST (th->th_ta_p,
TLS_PRE_TCB_SIZE);
-#if TLS_TCB_AT_TP
- dtvptr = tp - tlsoff;
-#elif TLS_DTV_AT_TP
- dtvptr = tp + tlsoff + TLS_PRE_TCB_SIZE;
-#else
-# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
-#endif
+ dtvptr = tp + variant_sign * tlsoff + tls_pre_tcb_size;
*base = dtvptr;
return TD_OK;
@@ -409,6 +409,10 @@ extern td_err_e td_thr_tlsbase (const
td_thrhandle_t *__th,
unsigned long int __modid,
psaddr_t *__base);
+/* Set thread_db constants for fetching tls. This should only be called
when
+ fetching tls from cross target core file. */
+extern td_err_e td_ta_init_target_consts (td_thragent_t *ta);
+
/* 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,
@@ -36,12 +36,14 @@
enum
{
# define DB_STRUCT(type) SYM_SIZEOF_##type,
+# define DB_CONST(name) SYM_CONST_##name,
# 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_CONST
# undef DB_STRUCT_FIELD
# undef DB_SYMBOL
# undef DB_FUNCTION
@@ -88,6 +90,8 @@ struct td_thragent
/* Cached values read from the inferior. */
# define DB_STRUCT(type) \
uint32_t ta_sizeof_##type;
+# define DB_CONST(name) \
+ uint32_t ta_const_##name;
# define DB_STRUCT_FIELD(type, field) \
db_desc_t ta_field_##type##_##field;
# define DB_SYMBOL(name) \
@@ -99,6 +103,7 @@ struct td_thragent
db_desc_t ta_var_##name;
# include "structs.def"
# undef DB_STRUCT
+# undef DB_CONST
# undef DB_STRUCT_FIELD
# undef DB_FUNCTION
# undef DB_SYMBOL
@@ -229,6 +234,9 @@ extern td_err_e _td_fetch_value_local (td_thragent_t
*ta,
: _td_store_value ((ta), (ta)->ta_var_##name, SYM_DESC_##name, \
(psaddr_t) 0 + (idx), (ta)->ta_addr_##name, (value)))
+
+#define DB_GET_CONST(ta, name) ta->ta_const_##name
+
/* Helper functions for those. */
extern td_err_e _td_store_value (td_thragent_t *ta,