elf: Introduce _dl_debug_change_state

It combines updating r_state with the debugger notification.

The second change to  _dl_open introduces an additional debugger
notification for dlmopen, but debuggers are expected to ignore it.

Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
This commit is contained in:
Florian Weimer 2025-07-04 21:46:16 +02:00
parent 7278d11f3a
commit 8329939a37
6 changed files with 26 additions and 15 deletions

View File

@ -433,8 +433,7 @@ _dl_close_worker (struct link_map *map, bool force)
/* Notify the debugger we are about to remove some loaded objects. /* Notify the debugger we are about to remove some loaded objects.
LA_ACT_DELETE has already been signalled above for !unload_any. */ LA_ACT_DELETE has already been signalled above for !unload_any. */
struct r_debug *r = _dl_debug_update (nsid); struct r_debug *r = _dl_debug_update (nsid);
r->r_state = RT_DELETE; _dl_debug_change_state (r, RT_DELETE);
_dl_debug_state ();
LIBC_PROBE (unmap_start, 2, nsid, r); LIBC_PROBE (unmap_start, 2, nsid, r);
if (unload_global) if (unload_global)
@ -726,8 +725,7 @@ _dl_close_worker (struct link_map *map, bool force)
__rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
/* Notify the debugger those objects are finalized and gone. */ /* Notify the debugger those objects are finalized and gone. */
r->r_state = RT_CONSISTENT; _dl_debug_change_state (r, RT_CONSISTENT);
_dl_debug_state ();
LIBC_PROBE (unmap_complete, 2, nsid, r); LIBC_PROBE (unmap_complete, 2, nsid, r);
#ifdef SHARED #ifdef SHARED

View File

@ -67,6 +67,13 @@ _dl_debug_update (Lmid_t ns)
return &r->base; return &r->base;
} }
void
_dl_debug_change_state (struct r_debug *r, int state)
{
atomic_store_release (&r->r_state, state);
_dl_debug_state ();
}
/* Initialize _r_debug_extended for the namespace NS. LDBASE is the /* Initialize _r_debug_extended for the namespace NS. LDBASE is the
run-time load address of the dynamic linker, to be put in run-time load address of the dynamic linker, to be put in
_r_debug_extended.r_ldbase. Return the address of _r_debug. */ _r_debug_extended.r_ldbase. Return the address of _r_debug. */

View File

@ -921,8 +921,7 @@ _dl_notify_new_object (int mode, Lmid_t nsid, struct link_map *l)
/* Notify the debugger we have added some objects. We need to /* Notify the debugger we have added some objects. We need to
call _dl_debug_initialize in a static program in case dynamic call _dl_debug_initialize in a static program in case dynamic
linking has not been used before. */ linking has not been used before. */
r->r_state = RT_ADD; _dl_debug_change_state (r, RT_ADD);
_dl_debug_state ();
LIBC_PROBE (map_start, 2, nsid, r); LIBC_PROBE (map_start, 2, nsid, r);
} }
else else

View File

@ -772,8 +772,7 @@ dl_open_worker (void *a)
#ifdef SHARED #ifdef SHARED
bool was_not_consistent = r->r_state != RT_CONSISTENT; bool was_not_consistent = r->r_state != RT_CONSISTENT;
#endif #endif
r->r_state = RT_CONSISTENT; _dl_debug_change_state (r, RT_CONSISTENT);
_dl_debug_state ();
LIBC_PROBE (map_complete, 3, nsid, r, args->map); LIBC_PROBE (map_complete, 3, nsid, r, args->map);
#ifdef SHARED #ifdef SHARED
@ -842,7 +841,7 @@ no more namespaces available for dlmopen()"));
} }
GL(dl_ns)[nsid].libc_map = NULL; GL(dl_ns)[nsid].libc_map = NULL;
_dl_debug_update (nsid)->r_state = RT_CONSISTENT; _dl_debug_change_state (_dl_debug_update (nsid), RT_CONSISTENT);
} }
/* Never allow loading a DSO in a namespace which is empty. Such /* Never allow loading a DSO in a namespace which is empty. Such
direct placements is only causing problems. Also don't allow direct placements is only causing problems. Also don't allow

View File

@ -1778,8 +1778,7 @@ dl_main (const ElfW(Phdr) *phdr,
elf_setup_debug_entry (main_map, r); elf_setup_debug_entry (main_map, r);
/* We start adding objects. */ /* We start adding objects. */
r->r_state = RT_ADD; _dl_debug_change_state (r, RT_ADD);
_dl_debug_state ();
LIBC_PROBE (init_start, 2, LM_ID_BASE, r); LIBC_PROBE (init_start, 2, LM_ID_BASE, r);
/* Auditing checkpoint: we are ready to signal that the initial map /* Auditing checkpoint: we are ready to signal that the initial map
@ -2334,8 +2333,7 @@ dl_main (const ElfW(Phdr) *phdr,
/* Notify the debugger all new objects are now ready to go. We must re-get /* 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. */ the address since by now the variable might be in another object. */
r = _dl_debug_update (LM_ID_BASE); r = _dl_debug_update (LM_ID_BASE);
r->r_state = RT_CONSISTENT; _dl_debug_change_state (r, RT_CONSISTENT);
_dl_debug_state ();
LIBC_PROBE (init_complete, 2, LM_ID_BASE, r); LIBC_PROBE (init_complete, 2, LM_ID_BASE, r);
/* Auditing checkpoint: we have added all objects. */ /* Auditing checkpoint: we have added all objects. */

View File

@ -1087,8 +1087,14 @@ extern void _dl_debug_state (void);
rtld_hidden_proto (_dl_debug_state) rtld_hidden_proto (_dl_debug_state)
/* Initialize `struct r_debug_extended' for the namespace NS. LDBASE /* 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 is the run-time load address of the dynamic linker, to be put in
`r_ldbase' member. Return the address of the structure. */ the `r_ldbase' member.
Return the address of the r_debug structure for the namespace.
This is not merely a convenience or optimization, but it is
necessary for the LIBC_PROBE Systemtap/debugger probes to work
reliably: direct variable access can create probes that tools
cannot consume. */
extern struct r_debug *_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns) extern struct r_debug *_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
attribute_hidden; attribute_hidden;
@ -1096,6 +1102,10 @@ extern struct r_debug *_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
of the namespace NS. */ of the namespace NS. */
extern struct r_debug *_dl_debug_update (Lmid_t ns) attribute_hidden; extern struct r_debug *_dl_debug_update (Lmid_t ns) attribute_hidden;
/* Update R->r_state to STATE and notify the debugger by calling
_dl_debug_state. */
void _dl_debug_change_state (struct r_debug *r, int state) attribute_hidden;
/* Initialize the basic data structure for the search paths. SOURCE /* Initialize the basic data structure for the search paths. SOURCE
is either "LD_LIBRARY_PATH" or "--library-path". is either "LD_LIBRARY_PATH" or "--library-path".
GLIBC_HWCAPS_PREPEND adds additional glibc-hwcaps subdirectories to GLIBC_HWCAPS_PREPEND adds additional glibc-hwcaps subdirectories to