MINOR: tools: add a new function "resolve_dso_name" to find a symbol's DSO

In the memprofile summary per DSO, we currently have to pay a high price
by calling dladdr() on each symbol when doing the summary per DSO at the
end, while we're not interested in these details, we just want the DSO
name which can be made cheaper to obtain, and easier to manipulate. So
let's create resolve_dso_name() to only extract minimal information from
an address. At the moment it still uses dladdr() though it avoids all the
extra expensive work, and will further be able to leverage the same
mechanism as "show libs" to instantly spot DSO from address ranges.
This commit is contained in:
Willy Tarreau 2024-11-21 15:15:53 +01:00
parent a205a91bb3
commit 670507a66e
2 changed files with 43 additions and 0 deletions

View File

@ -1113,6 +1113,7 @@ void dump_area_with_syms(struct buffer *output, const void *base, const void *ad
void dump_hex(struct buffer *out, const char *pfx, const void *buf, int len, int unsafe);
int may_access(const void *ptr);
const void *resolve_sym_name(struct buffer *buf, const char *pfx, const void *addr);
const void *resolve_dso_name(struct buffer *buf, const char *pfx, const void *addr);
const char *get_exec_path(void);
void *get_sym_curr_addr(const char *name);
void *get_sym_next_addr(const char *name);

View File

@ -5617,6 +5617,48 @@ const void *resolve_sym_name(struct buffer *buf, const char *pfx, const void *ad
return NULL;
}
/* Tries to append to buffer <buf> the DSO name containing the symbol at address
* <addr>. The name (lib or executable) is limited to what lies between the last
* '/' and the first following '.'. An optional prefix <pfx> is prepended before
* the output if not null. It returns "*unknown*" when the symbol is not found.
*
* The symbol's address is returned, or NULL when unresolved, in order to allow
* the caller to match it against known ones.
*/
const void *resolve_dso_name(struct buffer *buf, const char *pfx, const void *addr)
{
#if (defined(__ELF__) && !defined(__linux__)) || defined(USE_DL)
Dl_info dli;
size_t size;
const char *fname, *p;
/* Now let's try to be smarter */
if (!dladdr_and_size(addr, &dli, &size))
goto unknown;
if (pfx) {
chunk_appendf(buf, "%s", pfx);
pfx = NULL;
}
/* keep the part between '/' and '.' */
fname = dli.dli_fname;
p = strrchr(fname, '/');
if (p++)
fname = p;
p = strchr(fname, '.');
if (!p)
p = fname + strlen(fname);
chunk_appendf(buf, "%.*s", (int)(long)(p - fname), fname);
return addr;
unknown:
#endif /* __ELF__ && !__linux__ || USE_DL */
/* unknown symbol */
chunk_appendf(buf, "%s*unknown*", pfx ? pfx : "");
return NULL;
}
/* On systems where this is supported, let's provide a possibility to enumerate
* the list of object files. The output is appended to a buffer initialized by
* the caller, with one name per line. A trailing zero is always emitted if data