[v4,1/3] elf: Introduce separate _r_debug_array variable
Checks
Context |
Check |
Description |
dj/TryBot-apply_patch |
success
|
Patch applied to master at the time it was sent
|
Commit Message
It replaces the ns_debug member of the namespaces. Previously,
the base namespace had an unused ns_debug member.
This change also fixes a concurrency issue: Now _dl_debug_initialize
only updates r_next of the previous namespace's r_debug after the new
r_debug is initialized, so that only the initialized version is
observed. (Client code accessing _r_debug will benefit from load
dependency tracking in CPUs even without explicit barriers.)
---
elf/dl-debug.c | 91 +++++++++++++++++++++-----------------
sysdeps/generic/ldsodefs.h | 2 -
2 files changed, 50 insertions(+), 43 deletions(-)
@@ -30,17 +30,37 @@ extern const int verify_link_map_members[(VERIFY_MEMBER (l_addr)
&& VERIFY_MEMBER (l_prev))
? 1 : -1];
+#ifdef SHARED
+/* r_debug structs for secondary namespaces. The first namespace is
+ handled separately because its r_debug structure must overlap with
+ the public _r_debug symbol, so the first array element corresponds
+ to LM_ID_BASE + 1. See elf/dl-debug-symbols.S. */
+struct r_debug_extended _r_debug_array[DL_NNS - 1];
+
+/* Return the r_debug object for the namespace NS. */
+static inline struct r_debug_extended *
+get_rdebug (Lmid_t ns)
+{
+ if (ns == LM_ID_BASE)
+ return &_r_debug_extended;
+ else
+ return &_r_debug_array[ns - 1];
+}
+#else /* !SHARED */
+static inline struct r_debug_extended *
+get_rdebug (Lmid_t ns)
+{
+ return &_r_debug_extended; /* There is just one namespace. */
+}
+#endif /* !SHARED */
+
/* Update the `r_map' member and return the address of `struct r_debug'
of the namespace NS. */
struct r_debug *
_dl_debug_update (Lmid_t ns)
{
- struct r_debug_extended *r;
- if (ns == LM_ID_BASE)
- r = &_r_debug_extended;
- else
- r = &GL(dl_ns)[ns]._ns_debug;
+ struct r_debug_extended *r = get_rdebug (ns);
if (r->base.r_map == NULL)
atomic_store_release (&r->base.r_map,
(void *) GL(dl_ns)[ns]._ns_loaded);
@@ -54,34 +74,7 @@ _dl_debug_update (Lmid_t ns)
struct r_debug *
_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
{
- struct r_debug_extended *r, **pp = NULL;
-
- if (ns == LM_ID_BASE)
- {
- r = &_r_debug_extended;
- /* Initialize r_version to 1. */
- if (_r_debug_extended.base.r_version == 0)
- _r_debug_extended.base.r_version = 1;
- }
- else if (DL_NNS > 1)
- {
- r = &GL(dl_ns)[ns]._ns_debug;
- if (r->base.r_brk == 0)
- {
- /* Add the new namespace to the linked list. After a namespace
- is initialized, r_brk becomes non-zero. A namespace becomes
- empty (r_map == NULL) when it is unused. But it is never
- removed from the linked list. */
- struct r_debug_extended *p;
- for (pp = &_r_debug_extended.r_next;
- (p = *pp) != NULL;
- pp = &p->r_next)
- ;
-
- r->base.r_version = 2;
- }
- }
-
+ struct r_debug_extended *r = get_rdebug (ns);
if (r->base.r_brk == 0)
{
/* Tell the debugger where to find the map of loaded objects.
@@ -89,20 +82,36 @@ _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
only once. */
r->base.r_ldbase = ldbase ?: _r_debug_extended.base.r_ldbase;
r->base.r_brk = (ElfW(Addr)) &_dl_debug_state;
- r->r_next = NULL;
+
+#ifdef SHARED
+ /* Add the new namespace to the linked list. This assumes that
+ namespaces are allocated in increasing order. After a
+ namespace is initialized, r_brk becomes non-zero. A
+ namespace becomes empty (r_map == NULL) when it is unused.
+ But it is never removed from the linked list. */
+
+ if (ns != LM_ID_BASE)
+ {
+ r->base.r_version = 2;
+ if (ns - 1 == LM_ID_BASE)
+ {
+ atomic_store_release (&_r_debug_extended.r_next, r);
+ /* Now there are multiple namespaces. */
+ atomic_store_release (&_r_debug_extended.base.r_version, 2);
+ }
+ else
+ /* Update r_debug_extended of the previous namespace. */
+ atomic_store_release (&_r_debug_array[ns - 2].r_next, r);
+ }
+ else
+#endif /* SHARED */
+ r->base.r_version = 1;
}
if (r->base.r_map == NULL)
atomic_store_release (&r->base.r_map,
(void *) GL(dl_ns)[ns]._ns_loaded);
- if (pp != NULL)
- {
- atomic_store_release (pp, r);
- /* Bump r_version to 2 for the new namespace. */
- atomic_store_release (&_r_debug_extended.base.r_version, 2);
- }
-
return &r->base;
}
@@ -350,8 +350,6 @@ struct rtld_global
size_t n_elements;
void (*free) (void *);
} _ns_unique_sym_table;
- /* Keep track of changes to each namespace' list. */
- struct r_debug_extended _ns_debug;
} _dl_ns[DL_NNS];
/* One higher than index of last used namespace. */
EXTERN size_t _dl_nns;