* [PATCH v8 0/1] Extend struct r_debug to support multiple namespaces
@ 2021-09-08 18:25 H.J. Lu
2021-09-08 18:25 ` [PATCH v8 1/1] Extend struct r_debug to support multiple namespaces [BZ #15971] H.J. Lu
0 siblings, 1 reply; 4+ messages in thread
From: H.J. Lu @ 2021-09-08 18:25 UTC (permalink / raw)
To: libc-alpha; +Cc: gdb, libc-coord, Florian Weimer, Daniel Walker
Changes in the v8 patch:
1. Check base.r_brk == 0, instead of r_next == NULL, to decide if a
namespace has been initialized. r_next can be NULL after initialization,
but base.r_brk must be non-zero after initialization.
Changes in the v7 patch:
1. Rewrite dl-debug-symbols.S and remove dl-debug-compat-symbols.c.
2. Bump r_version to 2 only when multiple namespaces are used.
3. Verify r_version == 1 without multiple namespaces.
4. Keep the empty (unused) namespace on the namespace linked list.
5. Use atomic_store_release to update r_version and r_next.
6. Add _dl_debug_update without adding the namespace to the namespace
linked list.
Changes in the v6 patch:
1. Add comments for dl-debug-compat-symbols.[o|os] usage.
Changes in the v5 patch:
1. Use struct r_debug as the base for struct r_debug_extended.
2. Keep _dl_debug_initialize return type.
Changes in the v4 patch:
1. Improve the empty namespace removal from the namespace linked list.
2. Check r_version == 0 for the unused namespace.
Changes in the v3 patch:
1. Remove the empty namespace from the namespace linked list.
2. Properly add the new namespace to the linked list.
Changes in the v2 patch:
1. Bump r_version to 2.
2. Don't add DT_DEBUGSZ.
3. Add struct r_debug_extended to extend struct r_debug.
4. Don't update the r_state field in the copy of _r_debug in executable
since it is not consumed by the program.
---
Glibc does not provide an interface for debugger to access libraries
loaded in multiple namespaces via dlmopen.
The current rtld-debugger interface is described in the file:
elf/rtld-debugger-interface.txt
under the "Standard debugger interface" heading. This interface only
provides access to the first link-map (LM_ID_BASE).
1. Bump r_version to 2 when multiple namespaces are used. This triggers
the GDB bug:
https://sourceware.org/bugzilla/show_bug.cgi?id=28236
2. Add struct r_debug_extended to extend struct r_debug into a linked-list,
where each element correlates to an unique namespace.
3. Initialize the r_debug_extended structure. Bump r_version to 2 for
the new namespace and add the new namespace to the namespace linked list.
4. Add _dl_debug_update to return the address of struct r_debug' of a
namespace.
5. Add a hidden symbol, _r_debug_extended, for struct r_debug_extended.
6. Provide the compatibility symbol, _r_debug, with size of struct r_debug,
as an alise of _r_debug_extended, for programs which reference _r_debug.
This fixes BZ #15971.
H.J. Lu (1):
Extend struct r_debug to support multiple namespaces [BZ #15971]
NEWS | 11 ++++-
csu/Makefile | 3 ++
csu/rtld-sizes.sym | 6 +++
elf/Makefile | 7 +++-
elf/dl-close.c | 2 +-
elf/dl-debug-symbols.S | 37 +++++++++++++++++
elf/dl-debug.c | 72 ++++++++++++++++++++++++---------
elf/dl-load.c | 2 +-
elf/dl-open.c | 10 ++---
elf/dl-reloc-static-pie.c | 2 +-
elf/link.h | 36 ++++++++++++-----
elf/rtld-debugger-interface.txt | 14 +++++++
elf/rtld.c | 4 +-
elf/tst-dlmopen4.c | 68 +++++++++++++++++++++++++++++++
elf/tst-dlopen-nodelete-reloc.c | 2 +
include/link.h | 4 ++
sysdeps/generic/ldsodefs.h | 12 ++++--
17 files changed, 247 insertions(+), 45 deletions(-)
create mode 100644 csu/rtld-sizes.sym
create mode 100644 elf/dl-debug-symbols.S
create mode 100644 elf/tst-dlmopen4.c
--
2.31.1
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v8 1/1] Extend struct r_debug to support multiple namespaces [BZ #15971]
2021-09-08 18:25 [PATCH v8 0/1] Extend struct r_debug to support multiple namespaces H.J. Lu
@ 2021-09-08 18:25 ` H.J. Lu
2021-09-10 18:59 ` Florian Weimer
0 siblings, 1 reply; 4+ messages in thread
From: H.J. Lu @ 2021-09-08 18:25 UTC (permalink / raw)
To: libc-alpha; +Cc: gdb, libc-coord, Florian Weimer, Daniel Walker
Glibc does not provide an interface for debugger to access libraries
loaded in multiple namespaces via dlmopen.
The current rtld-debugger interface is described in the file:
elf/rtld-debugger-interface.txt
under the "Standard debugger interface" heading. This interface only
provides access to the first link-map (LM_ID_BASE).
1. Bump r_version to 2 when multiple namespaces are used. This triggers
the GDB bug:
https://sourceware.org/bugzilla/show_bug.cgi?id=28236
2. Add struct r_debug_extended to extend struct r_debug into a linked-list,
where each element correlates to an unique namespace.
3. Initialize the r_debug_extended structure. Bump r_version to 2 for
the new namespace and add the new namespace to the namespace linked list.
4. Add _dl_debug_update to return the address of struct r_debug' of a
namespace.
5. Add a hidden symbol, _r_debug_extended, for struct r_debug_extended.
6. Provide the compatibility symbol, _r_debug, with size of struct r_debug,
as an alise of _r_debug_extended, for programs which reference _r_debug.
This fixes BZ #15971.
---
NEWS | 11 ++++-
csu/Makefile | 3 ++
csu/rtld-sizes.sym | 6 +++
elf/Makefile | 7 +++-
elf/dl-close.c | 2 +-
elf/dl-debug-symbols.S | 37 +++++++++++++++++
elf/dl-debug.c | 72 ++++++++++++++++++++++++---------
elf/dl-load.c | 2 +-
elf/dl-open.c | 10 ++---
elf/dl-reloc-static-pie.c | 2 +-
elf/link.h | 36 ++++++++++++-----
elf/rtld-debugger-interface.txt | 14 +++++++
elf/rtld.c | 4 +-
elf/tst-dlmopen4.c | 68 +++++++++++++++++++++++++++++++
elf/tst-dlopen-nodelete-reloc.c | 2 +
include/link.h | 4 ++
sysdeps/generic/ldsodefs.h | 12 ++++--
17 files changed, 247 insertions(+), 45 deletions(-)
create mode 100644 csu/rtld-sizes.sym
create mode 100644 elf/dl-debug-symbols.S
create mode 100644 elf/tst-dlmopen4.c
diff --git a/NEWS b/NEWS
index 5b014fabbf..fd9d204022 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,9 @@ Version 2.35
Major new features:
+* Bump r_version in the debugger interface to 2 and add a new field,
+ r_next, support multiple namespaces.
+
* Support for the C.UTF-8 locale has been added to glibc. The locale
supports full code-point sorting for all valid Unicode code points. A
limitation in the framework for fnmatch, regexec, and regcomp requires
@@ -21,7 +24,13 @@ Major new features:
Deprecated and removed features, and other changes affecting compatibility:
- [Add deprecations, removals and changes affecting compatibility here]
+* The r_version update in the debugger interface makes the glibc binary
+ incompatible with GDB binaries built without the following commits:
+
+ c0154a4a21a gdb: Don't assume r_ldsomap when r_version > 1 on Linux
+ 4eb629d50d4 gdbserver: Check r_version < 1 for Linux debugger interface
+
+ when audit modules or dlmopen are used.
Changes to build and runtime requirements:
diff --git a/csu/Makefile b/csu/Makefile
index 3054329cea..e2390e4a7d 100644
--- a/csu/Makefile
+++ b/csu/Makefile
@@ -88,6 +88,9 @@ endif
before-compile += $(objpfx)abi-tag.h
generated += abi-tag.h
+# Put it here to generate it earlier.
+gen-as-const-headers += rtld-sizes.sym
+
# These are the special initializer/finalizer files. They are always the
# first and last file in the link. crti.o ... crtn.o define the global
# "functions" _init and _fini to run the .init and .fini sections.
diff --git a/csu/rtld-sizes.sym b/csu/rtld-sizes.sym
new file mode 100644
index 0000000000..13924d5efd
--- /dev/null
+++ b/csu/rtld-sizes.sym
@@ -0,0 +1,6 @@
+#include <link.h>
+
+--
+R_DEBUG_SIZE sizeof (struct r_debug)
+R_DEBUG_EXTENDED_SIZE sizeof (struct r_debug_extended)
+R_DEBUG_EXTENDED_ALIGN __alignof (struct r_debug_extended)
diff --git a/elf/Makefile b/elf/Makefile
index 9f3fadc37e..835b85bd7c 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -35,7 +35,8 @@ dl-routines = $(addprefix dl-,load lookup object reloc deps \
execstack open close trampoline \
exception sort-maps lookup-direct \
call-libc-early-init write \
- thread_gscope_wait tls_init_tp)
+ thread_gscope_wait tls_init_tp \
+ debug-symbols)
ifeq (yes,$(use-ldconfig))
dl-routines += dl-cache
endif
@@ -203,7 +204,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
tst-tls16 tst-tls17 tst-tls18 tst-tls19 tst-tls-dlinfo \
tst-align tst-align2 \
tst-dlmodcount tst-dlopenrpath tst-deep1 \
- tst-dlmopen1 tst-dlmopen3 \
+ tst-dlmopen1 tst-dlmopen3 tst-dlmopen4 \
unload3 unload4 unload5 unload6 unload7 unload8 tst-global1 order2 \
tst-audit1 tst-audit2 tst-audit8 tst-audit9 \
tst-addr1 tst-thrlock \
@@ -1244,6 +1245,8 @@ $(objpfx)tst-dlmopen2.out: $(objpfx)tst-dlmopen1mod.so
$(objpfx)tst-dlmopen3.out: $(objpfx)tst-dlmopen1mod.so
+$(objpfx)tst-dlmopen4.out: $(objpfx)tst-dlmopen1mod.so
+
$(objpfx)tst-audit1.out: $(objpfx)tst-auditmod1.so
tst-audit1-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
diff --git a/elf/dl-close.c b/elf/dl-close.c
index f39001cab9..93ff5c96e9 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -500,7 +500,7 @@ _dl_close_worker (struct link_map *map, bool force)
#endif
/* Notify the debugger we are about to remove some loaded objects. */
- struct r_debug *r = _dl_debug_initialize (0, nsid);
+ struct r_debug *r = _dl_debug_update (nsid);
r->r_state = RT_DELETE;
_dl_debug_state ();
LIBC_PROBE (unmap_start, 2, nsid, r);
diff --git a/elf/dl-debug-symbols.S b/elf/dl-debug-symbols.S
new file mode 100644
index 0000000000..5eb7e8fa3c
--- /dev/null
+++ b/elf/dl-debug-symbols.S
@@ -0,0 +1,37 @@
+/* Define symbols used to communicate dynamic linker state to the
+ debugger at runtime.
+ Copyright (C) 2021 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
+ <https://www.gnu.org/licenses/>. */
+
+#include <rtld-sizes.h>
+
+/* Define 2 symbols, _r_debug_extended and _r_debug, which is an alias
+ of _r_debug_extended, but with the size of struct r_debug and is
+ provided as a compatibility symbol. */
+
+ .globl _r_debug
+ .type _r_debug, %object
+ .size _r_debug, R_DEBUG_SIZE
+ .hidden _r_debug_extended
+ .globl _r_debug_extended
+ .type _r_debug_extended, %object
+ .size _r_debug_extended, R_DEBUG_EXTENDED_SIZE
+ .section .bss
+ .balign R_DEBUG_EXTENDED_ALIGN
+_r_debug:
+_r_debug_extended:
+ .zero R_DEBUG_EXTENDED_SIZE
diff --git a/elf/dl-debug.c b/elf/dl-debug.c
index 2cd5f09753..e64ce9105f 100644
--- a/elf/dl-debug.c
+++ b/elf/dl-debug.c
@@ -30,37 +30,71 @@ extern const int verify_link_map_members[(VERIFY_MEMBER (l_addr)
&& VERIFY_MEMBER (l_prev))
? 1 : -1];
-/* This structure communicates dl state to the debugger. The debugger
- normally finds it via the DT_DEBUG entry in the dynamic section, but in
- a statically-linked program there is no dynamic section for the debugger
- to examine and it looks for this particular symbol name. */
-struct r_debug _r_debug;
+/* 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;
+ if (r->base.r_map == NULL)
+ atomic_store_release (&r->base.r_map,
+ (void *) GL(dl_ns)[ns]._ns_loaded);
+ return &r->base;
+}
-/* Initialize _r_debug if it has not already been done. The argument is
- the run-time load address of the dynamic linker, to be put in
- _r_debug.r_ldbase. Returns the address of _r_debug. */
+/* Initialize _r_debug_extended for the namespace NS. LDBASE is the
+ run-time load address of the dynamic linker, to be put in
+ _r_debug_extended.r_ldbase. Return the address of _r_debug. */
struct r_debug *
_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
{
- struct r_debug *r;
+ struct r_debug_extended *r;
if (ns == LM_ID_BASE)
- r = &_r_debug;
- else
- r = &GL(dl_ns)[ns]._ns_debug;
+ {
+ 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. */
+ r->r_next = _r_debug_extended.r_next;
+ atomic_store_release (&_r_debug_extended.r_next, r);
+ /* Bump r_version to 2 for the new namespace. */
+ r->base.r_version = 2;
+ atomic_store_release (&_r_debug_extended.base.r_version, 2);
+ }
+ }
- if (r->r_map == NULL || ldbase != 0)
+ if (r->base.r_brk == 0)
{
- /* Tell the debugger where to find the map of loaded objects. */
- r->r_version = 1 /* R_DEBUG_VERSION XXX */;
- r->r_ldbase = ldbase ?: _r_debug.r_ldbase;
- r->r_map = (void *) GL(dl_ns)[ns]._ns_loaded;
- r->r_brk = (ElfW(Addr)) &_dl_debug_state;
+ /* Tell the debugger where to find the map of loaded objects.
+ This function is called from dlopen. Initialize the namespace
+ 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;
}
- return r;
+ if (r->base.r_map == NULL)
+ atomic_store_release (&r->base.r_map,
+ (void *) GL(dl_ns)[ns]._ns_loaded);
+
+ return &r->base;
}
diff --git a/elf/dl-load.c b/elf/dl-load.c
index dc911e326a..9b30cd7ff1 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -949,7 +949,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
/* Initialize to keep the compiler happy. */
const char *errstring = NULL;
int errval = 0;
- struct r_debug *r = _dl_debug_initialize (0, nsid);
+ struct r_debug *r = _dl_debug_update (nsid);
bool make_consistent = false;
/* Get file information. To match the kernel behavior, do not fill
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 98f8bf81b3..d519d32961 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -574,7 +574,7 @@ dl_open_worker (void *a)
if ((mode & RTLD_GLOBAL) && new->l_global == 0)
add_to_global_update (new);
- assert (_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT);
+ assert (_dl_debug_update (args->nsid)->r_state == RT_CONSISTENT);
return;
}
@@ -630,7 +630,7 @@ dl_open_worker (void *a)
#endif
/* Notify the debugger all new objects are now ready to go. */
- struct r_debug *r = _dl_debug_initialize (0, args->nsid);
+ struct r_debug *r = _dl_debug_update (args->nsid);
r->r_state = RT_CONSISTENT;
_dl_debug_state ();
LIBC_PROBE (map_complete, 3, args->nsid, r, new);
@@ -830,7 +830,7 @@ no more namespaces available for dlmopen()"));
++GL(dl_nns);
}
- _dl_debug_initialize (0, nsid)->r_state = RT_CONSISTENT;
+ _dl_debug_update (nsid)->r_state = RT_CONSISTENT;
}
/* Never allow loading a DSO in a namespace which is empty. Such
direct placements is only causing problems. Also don't allow
@@ -899,7 +899,7 @@ no more namespaces available for dlmopen()"));
the flag here. */
}
- assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT);
+ assert (_dl_debug_update (args.nsid)->r_state == RT_CONSISTENT);
/* Release the lock. */
__rtld_lock_unlock_recursive (GL(dl_load_lock));
@@ -908,7 +908,7 @@ no more namespaces available for dlmopen()"));
_dl_signal_exception (errcode, &exception, NULL);
}
- assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT);
+ assert (_dl_debug_update (args.nsid)->r_state == RT_CONSISTENT);
/* Release the lock. */
__rtld_lock_unlock_recursive (GL(dl_load_lock));
diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c
index d5bd2f31e9..289651b341 100644
--- a/elf/dl-reloc-static-pie.c
+++ b/elf/dl-reloc-static-pie.c
@@ -51,7 +51,7 @@ _dl_relocate_static_pie (void)
ELF_DYNAMIC_RELOCATE (main_map, 0, 0, 0);
main_map->l_relocated = 1;
- /* Initialize _r_debug. */
+ /* Initialize _r_debug_extended. */
struct r_debug *r = _dl_debug_initialize (0, LM_ID_BASE);
r->r_state = RT_CONSISTENT;
diff --git a/elf/link.h b/elf/link.h
index ff3a85c847..a297318236 100644
--- a/elf/link.h
+++ b/elf/link.h
@@ -34,14 +34,13 @@
#include <bits/elfclass.h> /* Defines __ELF_NATIVE_CLASS. */
#include <bits/link.h>
-/* Rendezvous structure used by the run-time dynamic linker to communicate
- details of shared object loading to the debugger. If the executable's
- dynamic section has a DT_DEBUG element, the run-time linker sets that
- element's value to the address where this structure can be found. */
+/* The legacy rendezvous structure used by the run-time dynamic linker to
+ communicate details of shared object loading to the debugger. */
struct r_debug
{
- int r_version; /* Version number for this protocol. */
+ /* Version number for this protocol. It should be greater than 0. */
+ int r_version;
struct link_map *r_map; /* Head of the chain of loaded objects. */
@@ -63,16 +62,35 @@ struct r_debug
ElfW(Addr) r_ldbase; /* Base address the linker is loaded at. */
};
-/* This is the instance of that structure used by the dynamic linker. */
+/* This is the compatibility symbol of that structure provided by the
+ dynamic linker. */
extern struct r_debug _r_debug;
+/* The extended rendezvous structure used by the run-time dynamic linker
+ to communicate details of shared object loading to the debugger. If
+ the executable's dynamic section has a DT_DEBUG element, the run-time
+ linker sets that element's value to the address where this structure
+ can be found. */
+
+struct r_debug_extended
+ {
+ struct r_debug base;
+
+ /* The following field is added by r_version == 2. */
+
+ /* Link to the next r_debug_extended structure. Each r_debug_extended
+ structure represents a different namespace. The first
+ r_debug_extended structure is for the default namespace. */
+ struct r_debug_extended *r_next;
+ };
+
/* This symbol refers to the "dynamic structure" in the `.dynamic' section
of whatever module refers to `_DYNAMIC'. So, to find its own
- `struct r_debug', a program could do:
+ `struct r_debug_extended', a program could do:
for (dyn = _DYNAMIC; dyn->d_tag != DT_NULL; ++dyn)
if (dyn->d_tag == DT_DEBUG)
- r_debug = (struct r_debug *) dyn->d_un.d_ptr;
- */
+ r_debug_extended = (struct r_debug_extended *) dyn->d_un.d_ptr;
+ */
extern ElfW(Dyn) _DYNAMIC[];
/* Structure describing a loaded shared object. The `l_next' and `l_prev'
diff --git a/elf/rtld-debugger-interface.txt b/elf/rtld-debugger-interface.txt
index 61bc99e4b0..f6aaa28706 100644
--- a/elf/rtld-debugger-interface.txt
+++ b/elf/rtld-debugger-interface.txt
@@ -9,6 +9,9 @@ structure can be found.
The r_debug structure contains (amongst others) the following fields:
+ int r_version:
+ Version number for this protocol. It should be greater than 0.
+
struct link_map *r_map:
A linked list of loaded objects.
@@ -32,6 +35,17 @@ but there is no way for the debugger to discover whether any of the
objects in the link-map have been relocated or not.
+Extension to the r_debug structure
+==================================
+
+The r_debug_extended structure is an extension of the r_debug interface.
+If r_version is 2, one additional field is available:
+
+ struct r_debug_extended *r_next;
+ Link to the next r_debug_extended structure. Each r_debug_extended
+ structure represents a different namespace. The first r_debug_extended
+ structure is for the default namespace.
+
Probe-based debugger interface
==============================
diff --git a/elf/rtld.c b/elf/rtld.c
index 878e6480f4..742c413c48 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -1660,7 +1660,7 @@ dl_main (const ElfW(Phdr) *phdr,
objects. */
call_init_paths (&state);
- /* Initialize _r_debug. */
+ /* Initialize _r_debug_extended. */
struct r_debug *r = _dl_debug_initialize (GL(dl_rtld_map).l_addr,
LM_ID_BASE);
r->r_state = RT_CONSISTENT;
@@ -2491,7 +2491,7 @@ dl_main (const ElfW(Phdr) *phdr,
/* Notify the debugger all new objects are now ready to go. We must re-get
the address since by now the variable might be in another object. */
- r = _dl_debug_initialize (0, LM_ID_BASE);
+ r = _dl_debug_update (LM_ID_BASE);
r->r_state = RT_CONSISTENT;
_dl_debug_state ();
LIBC_PROBE (init_complete, 2, LM_ID_BASE, r);
diff --git a/elf/tst-dlmopen4.c b/elf/tst-dlmopen4.c
new file mode 100644
index 0000000000..7a6c502e8c
--- /dev/null
+++ b/elf/tst-dlmopen4.c
@@ -0,0 +1,68 @@
+/* Test struct r_debug_extended via DT_DEBUG.
+ Copyright (C) 2021 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
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <link.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gnu/lib-names.h>
+#include <support/xdlfcn.h>
+#include <support/check.h>
+#include <support/test-driver.h>
+
+#ifndef ELF_MACHINE_GET_R_DEBUG
+# define ELF_MACHINE_GET_R_DEBUG(d) \
+ (__extension__ ({ \
+ struct r_debug_extended *debug; \
+ if ((d)->d_tag == DT_DEBUG) \
+ debug = (struct r_debug_extended *) (d)->d_un.d_ptr; \
+ else \
+ debug = NULL; \
+ debug; }))
+#endif
+
+static int
+do_test (void)
+{
+ void *h = xdlmopen (LM_ID_NEWLM, "$ORIGIN/tst-dlmopen1mod.so",
+ RTLD_LAZY);
+
+ int status = EXIT_FAILURE;
+ ElfW(Dyn) *d;
+ for (d = _DYNAMIC; d->d_tag != DT_NULL; ++d)
+ {
+ struct r_debug_extended *debug = ELF_MACHINE_GET_R_DEBUG (d);
+ if (debug != NULL)
+ {
+ TEST_VERIFY_EXIT (debug->base.r_version == 2);
+ TEST_VERIFY_EXIT (debug->r_next != NULL);
+ TEST_VERIFY_EXIT (debug->r_next->r_next == NULL);
+ TEST_VERIFY_EXIT (debug->r_next->base.r_map != NULL);
+ TEST_VERIFY_EXIT (debug->r_next->base.r_map->l_name != NULL);
+ const char *name = basename (debug->r_next->base.r_map->l_name);
+ TEST_VERIFY_EXIT (strcmp (name, "tst-dlmopen1mod.so") == 0);
+ status = EXIT_SUCCESS;
+ }
+ }
+
+ xdlclose (h);
+
+ return status;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-dlopen-nodelete-reloc.c b/elf/tst-dlopen-nodelete-reloc.c
index 6b07d88581..22bdf2521d 100644
--- a/elf/tst-dlopen-nodelete-reloc.c
+++ b/elf/tst-dlopen-nodelete-reloc.c
@@ -77,6 +77,7 @@
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
+#include <link.h>
#include <support/check.h>
#include <support/xdlfcn.h>
@@ -161,6 +162,7 @@ do_test (void)
== NULL);
const char *message = dlerror ();
printf ("info: test 6 message: %s\n", message);
+ TEST_VERIFY_EXIT (_r_debug.r_version == 1);
/* This must not close the object, it must still be NODELETE. */
xdlclose (mod14);
xdlopen ("tst-dlopen-nodelete-reloc-mod14.so", RTLD_NOW | RTLD_NOLOAD);
diff --git a/include/link.h b/include/link.h
index 4af16cb596..7b8250db36 100644
--- a/include/link.h
+++ b/include/link.h
@@ -353,6 +353,10 @@ struct auditstate
};
+/* This is the hidden instance of struct r_debug_extended used by the
+ dynamic linker. */
+extern struct r_debug_extended _r_debug_extended attribute_hidden;
+
#if __ELF_NATIVE_CLASS == 32
# define symbind symbind32
#elif __ELF_NATIVE_CLASS == 64
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 9c15259236..0cbcbfb5b0 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -355,7 +355,7 @@ struct rtld_global
void (*free) (void *);
} _ns_unique_sym_table;
/* Keep track of changes to each namespace' list. */
- struct r_debug _ns_debug;
+ struct r_debug_extended _ns_debug;
} _dl_ns[DL_NNS];
/* One higher than index of last used namespace. */
EXTERN size_t _dl_nns;
@@ -1093,12 +1093,16 @@ extern void _dl_sort_maps (struct link_map **maps, unsigned int nmaps,
extern void _dl_debug_state (void);
rtld_hidden_proto (_dl_debug_state)
-/* Initialize `struct r_debug' if it has not already been done. The
- argument is the run-time load address of the dynamic linker, to be put
- in the `r_ldbase' member. Returns the address of the structure. */
+/* Initialize `struct r_debug_extended' for the namespace NS. LDBASE
+ is the run-time load address of the dynamic linker, to be put in the
+ `r_ldbase' member. Return the address of the structure. */
extern struct r_debug *_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
attribute_hidden;
+/* Update the `r_map' member and return the address of `struct r_debug'
+ of the namespace NS. */
+extern struct r_debug *_dl_debug_update (Lmid_t ns) attribute_hidden;
+
/* Initialize the basic data structure for the search paths. SOURCE
is either "LD_LIBRARY_PATH" or "--library-path".
GLIBC_HWCAPS_PREPEND adds additional glibc-hwcaps subdirectories to
--
2.31.1
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v8 1/1] Extend struct r_debug to support multiple namespaces [BZ #15971]
2021-09-08 18:25 ` [PATCH v8 1/1] Extend struct r_debug to support multiple namespaces [BZ #15971] H.J. Lu
@ 2021-09-10 18:59 ` Florian Weimer
2021-09-10 19:26 ` H.J. Lu
0 siblings, 1 reply; 4+ messages in thread
From: Florian Weimer @ 2021-09-10 18:59 UTC (permalink / raw)
To: H.J. Lu; +Cc: libc-alpha, gdb, libc-coord, Daniel Walker
* H. J. Lu:
> diff --git a/elf/link.h b/elf/link.h
> index ff3a85c847..a297318236 100644
> --- a/elf/link.h
> +++ b/elf/link.h
> @@ -34,14 +34,13 @@
> -/* This is the instance of that structure used by the dynamic linker. */
> +/* This is the compatibility symbol of that structure provided by the
> + dynamic linker. */
> extern struct r_debug _r_debug;
I don't think we should say “compatibility symbol” in a public header.
Can we move GNAT off this symbol and deprecate it at least?
> +/* The extended rendezvous structure used by the run-time dynamic linker
> + to communicate details of shared object loading to the debugger. If
> + the executable's dynamic section has a DT_DEBUG element, the run-time
> + linker sets that element's value to the address where this structure
> + can be found. */
> +
> +struct r_debug_extended
> + {
> + struct r_debug base;
> +
> + /* The following field is added by r_version == 2. */
> +
> + /* Link to the next r_debug_extended structure. Each r_debug_extended
> + structure represents a different namespace. The first
> + r_debug_extended structure is for the default namespace. */
> + struct r_debug_extended *r_next;
> + };
> +
> /* This symbol refers to the "dynamic structure" in the `.dynamic' section
> of whatever module refers to `_DYNAMIC'. So, to find its own
> - `struct r_debug', a program could do:
> + `struct r_debug_extended', a program could do:
> for (dyn = _DYNAMIC; dyn->d_tag != DT_NULL; ++dyn)
> if (dyn->d_tag == DT_DEBUG)
> - r_debug = (struct r_debug *) dyn->d_un.d_ptr;
> - */
> + r_debug_extended = (struct r_debug_extended *) dyn->d_un.d_ptr;
> + */
> extern ElfW(Dyn) _DYNAMIC[];
What about shared objects? How can they find r_debug_extended? Should
they just make sure they have DT_DEBUG in their dynamic section?
Calling getauxval (AT_PHDR) has a relocation dependencies, which I
expect some consumers want to avoid.
> +Extension to the r_debug structure
> +==================================
> +
> +The r_debug_extended structure is an extension of the r_debug interface.
> +If r_version is 2, one additional field is available:
> +
> + struct r_debug_extended *r_next;
> + Link to the next r_debug_extended structure. Each r_debug_extended
> + structure represents a different namespace. The first r_debug_extended
> + structure is for the default namespace.
I think this should say how a reader can determine which list elements
are in fact active.
> diff --git a/elf/tst-dlmopen4.c b/elf/tst-dlmopen4.c
> new file mode 100644
> index 0000000000..7a6c502e8c
> --- /dev/null
> +++ b/elf/tst-dlmopen4.c
> +static int
> +do_test (void)
> +{
> + void *h = xdlmopen (LM_ID_NEWLM, "$ORIGIN/tst-dlmopen1mod.so",
> + RTLD_LAZY);
I think this should test that r_version is 1 before the dlmopen call.
> +
> + int status = EXIT_FAILURE;
> + ElfW(Dyn) *d;
> + for (d = _DYNAMIC; d->d_tag != DT_NULL; ++d)
> + {
> + struct r_debug_extended *debug = ELF_MACHINE_GET_R_DEBUG (d);
> + if (debug != NULL)
> + {
> + TEST_VERIFY_EXIT (debug->base.r_version == 2);
You could use TEST_COMPARE.
> + TEST_VERIFY_EXIT (debug->r_next != NULL);
> + TEST_VERIFY_EXIT (debug->r_next->r_next == NULL);
> + TEST_VERIFY_EXIT (debug->r_next->base.r_map != NULL);
> + TEST_VERIFY_EXIT (debug->r_next->base.r_map->l_name != NULL);
> + const char *name = basename (debug->r_next->base.r_map->l_name);
> + TEST_VERIFY_EXIT (strcmp (name, "tst-dlmopen1mod.so") == 0);
You could use TEST_COMPARE_STRING.
Sorry, I have not reviewed the actual mechanics of the patch.
Thanks,
Florian
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v8 1/1] Extend struct r_debug to support multiple namespaces [BZ #15971]
2021-09-10 18:59 ` Florian Weimer
@ 2021-09-10 19:26 ` H.J. Lu
0 siblings, 0 replies; 4+ messages in thread
From: H.J. Lu @ 2021-09-10 19:26 UTC (permalink / raw)
To: Florian Weimer; +Cc: GNU C Library, GDB, libc-coord, Daniel Walker
On Fri, Sep 10, 2021 at 11:59 AM Florian Weimer <fweimer@redhat.com> wrote:
>
> * H. J. Lu:
>
> > diff --git a/elf/link.h b/elf/link.h
> > index ff3a85c847..a297318236 100644
> > --- a/elf/link.h
> > +++ b/elf/link.h
> > @@ -34,14 +34,13 @@
>
> > -/* This is the instance of that structure used by the dynamic linker. */
> > +/* This is the compatibility symbol of that structure provided by the
> > + dynamic linker. */
> > extern struct r_debug _r_debug;
>
> I don't think we should say “compatibility symbol” in a public header.
I will remove "compatibility".
> Can we move GNAT off this symbol and deprecate it at least?
There is no harm in keeping it.
> > +/* The extended rendezvous structure used by the run-time dynamic linker
> > + to communicate details of shared object loading to the debugger. If
> > + the executable's dynamic section has a DT_DEBUG element, the run-time
> > + linker sets that element's value to the address where this structure
> > + can be found. */
> > +
> > +struct r_debug_extended
> > + {
> > + struct r_debug base;
> > +
> > + /* The following field is added by r_version == 2. */
> > +
> > + /* Link to the next r_debug_extended structure. Each r_debug_extended
> > + structure represents a different namespace. The first
> > + r_debug_extended structure is for the default namespace. */
> > + struct r_debug_extended *r_next;
> > + };
> > +
> > /* This symbol refers to the "dynamic structure" in the `.dynamic' section
> > of whatever module refers to `_DYNAMIC'. So, to find its own
> > - `struct r_debug', a program could do:
> > + `struct r_debug_extended', a program could do:
> > for (dyn = _DYNAMIC; dyn->d_tag != DT_NULL; ++dyn)
> > if (dyn->d_tag == DT_DEBUG)
> > - r_debug = (struct r_debug *) dyn->d_un.d_ptr;
> > - */
> > + r_debug_extended = (struct r_debug_extended *) dyn->d_un.d_ptr;
> > + */
> > extern ElfW(Dyn) _DYNAMIC[];
>
> What about shared objects? How can they find r_debug_extended? Should
> they just make sure they have DT_DEBUG in their dynamic section?
Linker generates DT_DEBUG only in the executable. dl_iterate_phdr can be
used to locate DT_DEBUG in the executable.
>
> Calling getauxval (AT_PHDR) has a relocation dependencies, which I
> expect some consumers want to avoid.
>
> > +Extension to the r_debug structure
> > +==================================
> > +
> > +The r_debug_extended structure is an extension of the r_debug interface.
> > +If r_version is 2, one additional field is available:
> > +
> > + struct r_debug_extended *r_next;
> > + Link to the next r_debug_extended structure. Each r_debug_extended
> > + structure represents a different namespace. The first r_debug_extended
> > + structure is for the default namespace.
>
> I think this should say how a reader can determine which list elements
> are in fact active.
I will update it.
>
> > diff --git a/elf/tst-dlmopen4.c b/elf/tst-dlmopen4.c
> > new file mode 100644
> > index 0000000000..7a6c502e8c
> > --- /dev/null
> > +++ b/elf/tst-dlmopen4.c
>
> > +static int
> > +do_test (void)
> > +{
> > + void *h = xdlmopen (LM_ID_NEWLM, "$ORIGIN/tst-dlmopen1mod.so",
> > + RTLD_LAZY);
>
> I think this should test that r_version is 1 before the dlmopen call.
I will add the test.
> > +
> > + int status = EXIT_FAILURE;
> > + ElfW(Dyn) *d;
> > + for (d = _DYNAMIC; d->d_tag != DT_NULL; ++d)
> > + {
> > + struct r_debug_extended *debug = ELF_MACHINE_GET_R_DEBUG (d);
> > + if (debug != NULL)
> > + {
> > + TEST_VERIFY_EXIT (debug->base.r_version == 2);
>
> You could use TEST_COMPARE.
I will fix it.
>
> > + TEST_VERIFY_EXIT (debug->r_next != NULL);
> > + TEST_VERIFY_EXIT (debug->r_next->r_next == NULL);
> > + TEST_VERIFY_EXIT (debug->r_next->base.r_map != NULL);
> > + TEST_VERIFY_EXIT (debug->r_next->base.r_map->l_name != NULL);
> > + const char *name = basename (debug->r_next->base.r_map->l_name);
> > + TEST_VERIFY_EXIT (strcmp (name, "tst-dlmopen1mod.so") == 0);
>
> You could use TEST_COMPARE_STRING.
I will fix it.
> Sorry, I have not reviewed the actual mechanics of the patch.
>
> Thanks,
> Florian
>
Thanks.
--
H.J.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2021-09-10 19:27 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-08 18:25 [PATCH v8 0/1] Extend struct r_debug to support multiple namespaces H.J. Lu
2021-09-08 18:25 ` [PATCH v8 1/1] Extend struct r_debug to support multiple namespaces [BZ #15971] H.J. Lu
2021-09-10 18:59 ` Florian Weimer
2021-09-10 19:26 ` H.J. Lu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).