[PATCH v3] ld.so: Decorate BSS mappings
Adhemerval Zanella Netto
adhemerval.zanella@linaro.org
Tue Jan 28 14:25:23 GMT 2025
On 28/01/25 07:08, Petr Malat wrote:
> Decorate BSS mappings with [anon: glibc: .bss <file>], for example
> [anon: glibc: .bss /lib/libc.so.6]. The string ".bss" is already used
> by bionic so use the same, but add the filename as well. If the name
> would be longer than what the kernel allows, drop the directory part
> of the path.
>
> Refactor glibc.mem.decorate_maps check to a separate function and use
> it to avoid assembling a name, which would not be used later.
>
> Signed-off-by: Petr Malat <oss@malat.biz>
LGTM, thanks. I will apply once 2.42 opens.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
> ---
> elf/dl-map-segments.h | 30 +++++++++++++++++++
> nptl/allocatestack.c | 4 ---
> sysdeps/generic/setvmaname.h | 12 ++++++++
> sysdeps/unix/sysv/linux/setvmaname.c | 45 ++++++++++++++++++++--------
> sysdeps/unix/sysv/linux/setvmaname.h | 8 +++++
> 5 files changed, 83 insertions(+), 16 deletions(-)
>
> diff --git a/elf/dl-map-segments.h b/elf/dl-map-segments.h
> index 203b6c7b0b..ee68dda550 100644
> --- a/elf/dl-map-segments.h
> +++ b/elf/dl-map-segments.h
> @@ -18,6 +18,7 @@
> <https://www.gnu.org/licenses/>. */
>
> #include <dl-load.h>
> +#include <setvmaname.h>
>
> /* Map a segment and align it properly. */
>
> @@ -182,12 +183,41 @@ _dl_map_segments (struct link_map *l, int fd,
> if (zeroend > zeropage)
> {
> /* Map the remaining zero pages in from the zero fill FD. */
> + char bssname[ANON_VMA_NAME_MAX_LEN] = " glibc: .bss";
> +
> caddr_t mapat;
> mapat = __mmap ((caddr_t) zeropage, zeroend - zeropage,
> c->prot, MAP_ANON|MAP_PRIVATE|MAP_FIXED,
> -1, 0);
> if (__glibc_unlikely (mapat == MAP_FAILED))
> return DL_MAP_SEGMENTS_ERROR_MAP_ZERO_FILL;
> + if (__is_decorate_maps_enabled ())
> + {
> + if (l->l_name != NULL && *l->l_name != '\0')
> + {
> + int i = strlen (bssname), j = 0;
> + int namelen = strlen (l->l_name);
> +
> + bssname[i++] = ' ';
> + if (namelen > sizeof (bssname) - i - 1)
> + for (j = namelen - 1; j > 0; j--)
> + if (l->l_name[j - 1] == '/')
> + break;
> +
> + for (; l->l_name[j] != '\0' && i < sizeof (bssname) - 1;
> + i++, j++)
> + {
> + char ch = l->l_name[j];
> + /* Replace non-printable characters and
> + \, `, $, [ and ]. */
> + if (ch <= 0x1f || ch >= 0x7f || strchr("\\`$[]", ch))
> + ch = '!';
> + bssname[i] = ch;
> + }
> + bssname[i] = 0;
> + }
> + __set_vma_name ((void*)zeropage, zeroend - zeropage, bssname);
> + }
> }
> }
>
> diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
> index 9c1a72bcf0..622c22f050 100644
> --- a/nptl/allocatestack.c
> +++ b/nptl/allocatestack.c
> @@ -549,10 +549,6 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
> return 0;
> }
>
> -/* Maximum supported name from initial kernel support, not exported
> - by user API. */
> -#define ANON_VMA_NAME_MAX_LEN 80
> -
> #define SET_STACK_NAME(__prefix, __stack, __stacksize, __tid) \
> ({ \
> char __stack_name[sizeof (__prefix) + \
> diff --git a/sysdeps/generic/setvmaname.h b/sysdeps/generic/setvmaname.h
> index baca984a54..496fcca33b 100644
> --- a/sysdeps/generic/setvmaname.h
> +++ b/sysdeps/generic/setvmaname.h
> @@ -19,6 +19,18 @@
> #ifndef __SETVMANAME_H
> #define __SETVMANAME_H
>
> +#include <stdbool.h>
> +
> +/* Set this to small value to not waste memory on systems, which do
> + * not support VMA name. */
> +#define ANON_VMA_NAME_MAX_LEN 16
> +
> +static inline bool
> +__is_decorate_maps_enabled (void)
> +{
> + return false;
> +}
> +
> static inline
> void __set_vma_name (void *start, size_t len, const char *name)
> {
> diff --git a/sysdeps/unix/sysv/linux/setvmaname.c b/sysdeps/unix/sysv/linux/setvmaname.c
> index 749c587f12..ea93a5ffbe 100644
> --- a/sysdeps/unix/sysv/linux/setvmaname.c
> +++ b/sysdeps/unix/sysv/linux/setvmaname.c
> @@ -22,6 +22,33 @@
> #include <sysdep.h>
> #include <elf/dl-tunables.h>
>
> +static enum {
> + decorate_unknown = -1,
> + decorate_off,
> + decorate_on
> +} decorate_maps = decorate_unknown;
I think it should be ok to use an enum here, afaik it would be promoted
to int and atomic_load_relaxed should complain if some architecture does
not support it properly.
> +
> +bool
> +__is_decorate_maps_enabled (void)
> +{
> + switch (atomic_load_relaxed (&decorate_maps))
> + {
> + case decorate_unknown:
> + if (TUNABLE_GET (glibc, mem, decorate_maps, int32_t, NULL) != 0)
> + {
> + atomic_store_relaxed (&decorate_maps, decorate_on);
> + return true;
> + }
> + atomic_store_relaxed (&decorate_maps, decorate_off);
> + return false;
> + case decorate_off:
> + return false;
> + case decorate_on:
> + return true;
> + }
> + __builtin_unreachable ();
> +}
> +
> /* If PR_SET_VMA_ANON_NAME is not supported by the kernel, prctl returns
> EINVAL. However, it also returns the same error for invalid argument.
> Since it is an internal-only API, it assumes well formatted input:
> @@ -31,19 +58,13 @@
> void
> __set_vma_name (void *start, size_t len, const char *name)
> {
> - static int prctl_supported = 1;
> - if (atomic_load_relaxed (&prctl_supported) == 0)
> - return;
> -
> - /* Set the prctl as not supported to avoid checking the tunable on every
> - call. */
> - if (TUNABLE_GET (glibc, mem, decorate_maps, int32_t, NULL) != 0)
> + if (__is_decorate_maps_enabled ())
> {
> int r = INTERNAL_SYSCALL_CALL (prctl, PR_SET_VMA, PR_SET_VMA_ANON_NAME,
> - start, len, name);
> - if (r == 0 || r != -EINVAL)
> - return;
> + start, len, name);
> +
> + /* Disable further attempts if not supported by the kernel. */
> + if (r == -EINVAL)
> + atomic_store_relaxed (&decorate_maps, decorate_off);
> }
> - atomic_store_relaxed (&prctl_supported, 0);
> - return;
> }
Ok.
> diff --git a/sysdeps/unix/sysv/linux/setvmaname.h b/sysdeps/unix/sysv/linux/setvmaname.h
> index 715b096799..48643d0dad 100644
> --- a/sysdeps/unix/sysv/linux/setvmaname.h
> +++ b/sysdeps/unix/sysv/linux/setvmaname.h
> @@ -19,9 +19,17 @@
> #ifndef __SETVMANAME_H
> #define __SETVMANAME_H
>
> +/* Maximum supported name from initial kernel support, not exported
> + by user API. */
> +#define ANON_VMA_NAME_MAX_LEN 80
> +
> /* Set the NAME to the anonymous memory map START with size of LEN.
> It assumes well-formatted input. */
> #if IS_IN(libc) || IS_IN(rtld)
> +#include <stdbool.h>
> +
> +bool __is_decorate_maps_enabled (void) attribute_hidden;
> +
> void __set_vma_name (void *start, size_t len, const char *name)
> attribute_hidden;
> #else
Ok.
More information about the Libc-alpha
mailing list