DEBUG: tools: add vma_set_name() helper
Following David Carlier's work in 98d22f21 ("MEDIUM: shctx: Naming shared memory context"), let's provide an helper function to set a name hint on a virtual memory area (ie: anonymous map created using mmap(), or memory area returned by malloc()). Naming will only occur if available, and naming errors will be ignored. The function takes mandatory <type> and <name> parameterss to build the map name as follow: "type:name". When looking at /proc/<pid>/maps, vma named using this helper function will show up this way (provided that the kernel has prtcl support for PR_SET_VMA_ANON_NAME): example, using mmap + MAP_SHARED|MAP_ANONYMOUS: 7364c4fff000-736508000000 rw-s 00000000 00:01 3540 [anon_shmem:type:name] Another example, using mmap + MAP_PRIVATE|MAP_ANONYMOUS or using glibc/malloc() above MMAP_THRESHOLD: 7364c4fff000-736508000000 rw-s 00000000 00:01 3540 [anon:type:name]
This commit is contained in:
parent
4bb6ea5d00
commit
51a8f134ef
@ -1199,4 +1199,7 @@ int openssl_compare_current_version(const char *version);
|
||||
/* compare the current OpenSSL name to a string */
|
||||
int openssl_compare_current_name(const char *name);
|
||||
|
||||
/* vma helpers */
|
||||
void vma_set_name(void *addr, size_t size, const char *type, const char *name);
|
||||
|
||||
#endif /* _HAPROXY_TOOLS_H */
|
||||
|
82
src/tools.c
82
src/tools.c
@ -41,6 +41,7 @@ extern void *__elf_aux_vector;
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
@ -52,6 +53,10 @@ extern void *__elf_aux_vector;
|
||||
#include <sys/auxv.h>
|
||||
#endif
|
||||
|
||||
#if defined(USE_PRCTL)
|
||||
#include <sys/prctl.h>
|
||||
#endif
|
||||
|
||||
#include <import/eb32sctree.h>
|
||||
#include <import/eb32tree.h>
|
||||
#include <import/ebmbtree.h>
|
||||
@ -6459,6 +6464,83 @@ int openssl_compare_current_name(const char *name)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* prctl/PR_SET_VMA wrapper to easily give a name to virtual memory areas,
|
||||
* knowing their address and size.
|
||||
*
|
||||
* It is only intended for use with memory allocated using mmap (private or
|
||||
* shared anonymous maps) or malloc (provided that <size> is at least one page
|
||||
* large), which is memory that may be released using munmap(). For memory
|
||||
* allocated using malloc(), no naming will be attempted if the vma is less
|
||||
* than one page large, because naming is only relevant for large memory
|
||||
* blocks. For instance, glibc/malloc() will directly use mmap() once
|
||||
* MMAP_THRESHOLD is reached (defaults to 128K), and will try to use the
|
||||
* heap as much as possible below that.
|
||||
*
|
||||
* <type> and <name> are mandatory
|
||||
*
|
||||
* The function does nothing if naming API is not available, and naming errors
|
||||
* are ignored.
|
||||
*/
|
||||
void vma_set_name(void *addr, size_t size, const char *type, const char *name)
|
||||
{
|
||||
long pagesize = sysconf(_SC_PAGESIZE);
|
||||
void *aligned_addr;
|
||||
__maybe_unused size_t aligned_size;
|
||||
|
||||
BUG_ON(!type || !name);
|
||||
|
||||
/* prctl/PR_SET/VMA expects the start of an aligned memory address, but
|
||||
* user may have provided address returned by malloc() which may not be
|
||||
* aligned nor point to the beginning of the map
|
||||
*/
|
||||
aligned_addr = (void *)((uintptr_t)addr & -4096);
|
||||
aligned_size = (((addr + size) - aligned_addr) + 4095) & -4096;
|
||||
|
||||
if (aligned_addr != addr) {
|
||||
/* provided pointer likely comes from malloc(), at least it
|
||||
* doesn't come from mmap() which only returns aligned addresses
|
||||
*/
|
||||
if (size < pagesize)
|
||||
return;
|
||||
}
|
||||
#if defined(USE_PRCTL) && defined(PR_SET_VMA)
|
||||
{
|
||||
/*
|
||||
* From Linux 5.17 (and if the `CONFIG_ANON_VMA_NAME` kernel config is set)`,
|
||||
* anonymous regions can be named.
|
||||
* We intentionally ignore errors as it should not jeopardize the memory context
|
||||
* mapping whatsoever (e.g. older kernels).
|
||||
*
|
||||
* The naming can take up to 79 characters, accepting valid ASCII values
|
||||
* except [, ], \, $ and '.
|
||||
* As a result, when looking for /proc/<pid>/maps, we can see the anonymous range
|
||||
* as follow :
|
||||
* `7364c4fff000-736508000000 rw-s 00000000 00:01 3540 [anon_shmem:scope.name]`
|
||||
* (MAP_SHARED)
|
||||
* `7364c4fff000-736508000000 rw-s 00000000 00:01 3540 [anon:scope.name]`
|
||||
* (MAP_PRIVATE)
|
||||
*/
|
||||
char fullname[80];
|
||||
int rn;
|
||||
|
||||
rn = snprintf(fullname, sizeof(fullname), "%s:%s", type, name);
|
||||
|
||||
if (rn >= 0) {
|
||||
/* Give a name to the map by setting PR_SET_VMA_ANON_NAME attribute
|
||||
* using prctl/PR_SET_VMA combination.
|
||||
*
|
||||
* note from 'man prctl':
|
||||
* assigning an attribute to a virtual memory area might prevent it
|
||||
* from being merged with adjacent virtual memory areas due to the
|
||||
* difference in that attribute's value.
|
||||
*/
|
||||
(void)prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME,
|
||||
aligned_addr, aligned_size, fullname);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(RTLD_DEFAULT) || defined(RTLD_NEXT)
|
||||
/* redefine dlopen() so that we can detect unexpected replacement of some
|
||||
* critical symbols, typically init/alloc/free functions coming from alternate
|
||||
|
Loading…
x
Reference in New Issue
Block a user