From: Willy Tarreau Date: Thu, 23 Nov 2023 10:25:34 +0000 (+0100) Subject: MINOR: debug: add the ability to enter components in the post_mortem struct X-Git-Tag: v2.9-dev11~18 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6455fd502407e60de0f6988a9d00303b43c46ca7;p=thirdparty%2Fhaproxy.git MINOR: debug: add the ability to enter components in the post_mortem struct Here the idea is to collect components' versions and build options. The main component is haproxy, but the API is made so that any sub-system can easily add a component there (for example the detailed version of a device detection lib, or some info about a lib loaded from Lua). The elements are stored as a pointer to an array of structs and its count so that it's sufficient to issue this in gdb to list them all at once: print *post_mortem.components@post_mortem.nb_components For now we collect name, version, toolchain, toolchain options, build options and path. Maybe more could be useful in the future. --- diff --git a/include/haproxy/debug.h b/include/haproxy/debug.h index 17880e4e3e..b7a2e2072f 100644 --- a/include/haproxy/debug.h +++ b/include/haproxy/debug.h @@ -32,4 +32,8 @@ void ha_dump_backtrace(struct buffer *buf, const char *prefix, int dump); void ha_backtrace_to_stderr(void); void ha_panic(void); +void post_mortem_add_component(const char *name, const char *version, + const char *toolchain, const char *toolchain_opts, + const char *build_settings, const char *path); + #endif /* _HAPROXY_DEBUG_H */ diff --git a/src/debug.c b/src/debug.c index f964e7e201..7c449c123c 100644 --- a/src/debug.c +++ b/src/debug.c @@ -68,6 +68,21 @@ #define THREAD_DUMP_FSYNC 0x00008000U #define THREAD_DUMP_PMASK 0x7FFF0000U +/* Description of a component with name, version, path, build options etc. E.g. + * one of them is haproxy. Others might be some clearly identified shared libs. + * They're intentionally self-contained and to be placed into an array to make + * it easier to find them in a core. The important fields (name and version) + * are locally allocated, other ones are dynamic. + */ +struct post_mortem_component { + char name[32]; // symbolic short name + char version[32]; // exact version + char *toolchain; // compiler and version (e.g. gcc-11.4.0) + char *toolchain_opts; // optims, arch-specific options (e.g. CFLAGS) + char *build_settings; // build options (e.g. USE_*, TARGET, etc) + char *path; // path if known. +}; + /* This is a collection of information that are centralized to help with core * dump analysis. It must be used with a public variable and gather elements * as much as possible without dereferences so that even when identified in a @@ -111,6 +126,13 @@ struct post_mortem { /* information about dynamic shared libraries involved */ char *libs; // dump of one addr / path per line, or NULL #endif + + /* info about identified distinct components (executable, shared libs, etc). + * These can be all listed at once in gdb using: + * p *post_mortem.components@post_mortem.nb_components + */ + uint nb_components; // # of components below + struct post_mortem_component *components; // NULL or array } post_mortem ALIGNED(256) = { }; /* Points to a copy of the buffer where the dump functions should write, when @@ -2165,13 +2187,49 @@ REGISTER_POST_CHECK(feed_post_mortem); static void deinit_post_mortem(void) { + int comp; + #if defined(HA_HAVE_DUMP_LIBS) ha_free(&post_mortem.libs); #endif + for (comp = 0; comp < post_mortem.nb_components; comp++) { + free(post_mortem.components[comp].toolchain); + free(post_mortem.components[comp].toolchain_opts); + free(post_mortem.components[comp].build_settings); + free(post_mortem.components[comp].path); + } + ha_free(&post_mortem.components); } REGISTER_POST_DEINIT(deinit_post_mortem); +/* Appends a component to the list of post_portem info. May silently fail + * on allocation errors but we don't care since the goal is to provide info + * we have in case it helps. + */ +void post_mortem_add_component(const char *name, const char *version, + const char *toolchain, const char *toolchain_opts, + const char *build_settings, const char *path) +{ + struct post_mortem_component *comp; + int nbcomp = post_mortem.nb_components; + + comp = realloc(post_mortem.components, (nbcomp + 1) * sizeof(*comp)); + if (!comp) + return; + + memset(&comp[nbcomp], 0, sizeof(*comp)); + strlcpy2(comp[nbcomp].name, name, sizeof(comp[nbcomp].name)); + strlcpy2(comp[nbcomp].version, version, sizeof(comp[nbcomp].version)); + comp[nbcomp].toolchain = strdup(toolchain); + comp[nbcomp].toolchain_opts = strdup(toolchain_opts); + comp[nbcomp].build_settings = strdup(build_settings); + comp[nbcomp].path = strdup(path); + + post_mortem.nb_components++; + post_mortem.components = comp; +} + #ifdef USE_THREAD /* init code is called one at a time so let's collect all per-thread info on * the last starting thread. These info are not critical anyway and there's no