[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