]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: tools: add a new function "resolve_dso_name" to find a symbol's DSO
authorWilly Tarreau <w@1wt.eu>
Thu, 21 Nov 2024 14:15:53 +0000 (15:15 +0100)
committerWilly Tarreau <w@1wt.eu>
Thu, 21 Nov 2024 18:58:06 +0000 (19:58 +0100)
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.

include/haproxy/tools.h
src/tools.c

index 72bb5325ef849449ae9e32a00f409422fc1971a6..4f90a05ec4d1cef6fd55e33a97cccf2322466822 100644 (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);
index 968b324858e8b37e17d6598cb9fc6f0430f8dc3e..472baf919218531e807c7dbb040988d1764073a2 100644 (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