diff --git a/include/haproxy/tools.h b/include/haproxy/tools.h index 72bb5325e..4f90a05ec 100644 --- a/include/haproxy/tools.h +++ b/include/haproxy/tools.h @@ -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); diff --git a/src/tools.c b/src/tools.c index 968b32485..472baf919 100644 --- a/src/tools.c +++ b/src/tools.c @@ -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 the DSO name containing the symbol at address + * . The name (lib or executable) is limited to what lies between the last + * '/' and the first following '.'. An optional prefix 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