]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: debug: add the ability to enter components in the post_mortem struct
authorWilly Tarreau <w@1wt.eu>
Thu, 23 Nov 2023 10:25:34 +0000 (11:25 +0100)
committerWilly Tarreau <w@1wt.eu>
Thu, 23 Nov 2023 14:39:21 +0000 (15:39 +0100)
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.

include/haproxy/debug.h
src/debug.c

index 17880e4e3e24bc70f12b44e9efff0a5112850d74..b7a2e2072fe48c2fa3f7fb21c6c870fa4395e03a 100644 (file)
@@ -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 */
index f964e7e201214f36f0ec06fb238d34d2082d9243..7c449c123c45cb99000e9fbd90ee2431977efc59 100644 (file)
 #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