From 030a2bfeeb004862ce6b38a4964357e71a709ffa Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 29 May 2026 11:39:05 +0200 Subject: [PATCH] MINOR: debug: add -dA to dump an archive of all dependencies This adds "-dA[file]" on the command line, which dumps an archive of all dependencies detected at runtime into the designated file in tar format. This is equivalent to "set-dumpable libs", but instead of keeping the libs in memory, it dumps them into a file. This may be used after a core dump, in order to provide all necessary libraries to developers to permit them to exploit the core. This may not be available on all operating systems. --- doc/management.txt | 12 +++++++++++ include/haproxy/global.h | 1 + include/haproxy/tools.h | 1 + src/haproxy.c | 25 +++++++++++++++++++++++ src/tools.c | 43 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 82 insertions(+) diff --git a/doc/management.txt b/doc/management.txt index 5dae7064a..dbdf53110 100644 --- a/doc/management.txt +++ b/doc/management.txt @@ -215,6 +215,18 @@ list of options is : in foreground and to show incoming and outgoing events. It must never be used in an init script. + -dA[file] : dump an archive of all dependencies detected at boot time in the + designated file in tar format, immediately after the configuration is done + loading. This is equivalent to "set-dumpable libs", but instead of keeping + the libs in memory, it dumps them into a file. This may be used after a + core dump, in order to provide all necessary libraries to developers to + permit them to exploit the core. This may not be available on all operating + systems. It is highly recommended to use this with the regular + configuration files, and optionally with "-c" when used manually, to make + haproxy immediately exit after the dump, without starting. Example: + + $ haproxy -dA/tmp/libs.tar -c -f /etc/haproxy/haproxy.cfg + -dC[key] : dump the configuration file. It is performed after the lines are tokenized, so comments are stripped and indenting is forced. If a non-zero key is specified, lines are truncated before sensitive/confidential fields, diff --git a/include/haproxy/global.h b/include/haproxy/global.h index 1510bfe0c..854824419 100644 --- a/include/haproxy/global.h +++ b/include/haproxy/global.h @@ -61,6 +61,7 @@ extern struct cfgfile fileless_cfg; /* storage for collected libs */ extern void *lib_storage; extern size_t lib_size; +extern char *lib_output_file; struct proxy; struct server; diff --git a/include/haproxy/tools.h b/include/haproxy/tools.h index ff1ba8bc1..b00c21b3b 100644 --- a/include/haproxy/tools.h +++ b/include/haproxy/tools.h @@ -1155,6 +1155,7 @@ void *get_sym_next_addr(const char *name); int dump_libs(struct buffer *output, int with_addr); void collect_libs(void); void free_collected_libs(void); +int copy_libs_to_file(void); /* Note that this may result in opening libgcc() on first call, so it may need * to have been called once before chrooting. diff --git a/src/haproxy.c b/src/haproxy.c index b38b13d78..62c3262ea 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -274,6 +274,7 @@ unsigned int deprecated_directives_allowed = 0; /* mapped storage for collected libs */ void *lib_storage = NULL; size_t lib_size = 0; +char *lib_output_file = NULL; int check_kw_experimental(struct cfg_keyword *kw, const char *file, int linenum, char **errmsg) @@ -784,6 +785,9 @@ static void usage(char *name) #if defined(HA_HAVE_DUMP_LIBS) " -dL dumps loaded object files after config checks\n" #endif +#if defined(HA_HAVE_DUMP_LIBS) && defined(HA_HAVE_DL_ITERATE_PHDR) + " -dA[file] collects libs into a tar file at \n" +#endif #if defined(USE_CPU_AFFINITY) " -dc dumps the list of selected and evicted CPUs\n" #endif @@ -1627,6 +1631,16 @@ void haproxy_init_args(int argc, char **argv) #if defined(HA_HAVE_DUMP_LIBS) else if (*flag == 'd' && flag[1] == 'L') arg_mode |= MODE_DUMP_LIBS; +# if defined(HA_HAVE_DL_ITERATE_PHDR) + else if (*flag == 'd' && flag[1] == 'A') { + lib_output_file = flag + 2; + if (!*lib_output_file) { + ha_alert("-dA: missing output file name\n"); + exit(1); + } + arg_mode |= MODE_DUMP_LIBS; // stop on libs dump + } +# endif /* HA_HAVE_DL_ITERATE_PHDR */ #endif else if (*flag == 'd' && flag[1] == 'K') { arg_mode |= MODE_DUMP_KWD; @@ -2312,6 +2326,17 @@ static void step_init_2(int argc, char** argv) #if defined(HA_HAVE_DUMP_LIBS) if (global.mode & MODE_DUMP_LIBS && !master) { +# if defined(HA_HAVE_DL_ITERATE_PHDR) + if (lib_output_file) { + /* we'll dump everything to lib_output_file */ + if (copy_libs_to_file() < 0) + deinit_and_exit(1); + /* release memory if no longer needed */ + if ((global.tune.options & (GTUNE_SET_DUMPABLE | GTUNE_COLLECT_LIBS)) != + (GTUNE_SET_DUMPABLE | GTUNE_COLLECT_LIBS)) + free_collected_libs(); + } +# endif qfprintf(stdout, "List of loaded object files:\n"); chunk_reset(&trash); if (dump_libs(&trash, ((arg_mode & (MODE_QUIET|MODE_VERBOSE)) == MODE_VERBOSE))) diff --git a/src/tools.c b/src/tools.c index b9a0da783..6c3dce7c9 100644 --- a/src/tools.c +++ b/src/tools.c @@ -6101,6 +6101,10 @@ void collect_libs(void) void *page; int i; + /* already done */ + if (lib_storage) + return; + /* prepend a directory named after the starting pid */ snprintf(dir_name, sizeof(dir_name), "core-%u", getpid()); ctx.prefix = dir_name; @@ -6162,6 +6166,39 @@ void free_collected_libs(void) lib_size = 0; } +/* Prepare the archive in RAM and copy it to a target file. Returns <0 upon error. */ +int copy_libs_to_file(void) +{ + ssize_t len; + int ret = -1; + int fd = -1; + + fd = open(lib_output_file, O_CREAT | O_WRONLY, S_IRWXU); + if (fd < 0) { + ha_alert("Cannot create output file to dump dependencies: %s.\n", strerror(errno)); + goto fail; + } + + collect_libs(); + if (!lib_storage || !lib_size) { + ha_alert("Failed to collect dependencies.\n"); + goto fail; + } + + len = write(fd, lib_storage, lib_size); + if (len != lib_size) { + ha_alert("Failed to write dependencies to output file: %s.\n", strerror(errno)); + goto fail; + } + + /* OK done */ + ret = 0; + fail: + if (fd >= 0) + close(fd); + return ret; +} + # else // no DL_ITERATE_PHDR # error "No dump_libs() function for this platform" # endif @@ -6183,6 +6220,12 @@ void free_collected_libs(void) { } +/* unsupported platform: do not copy anything */ +int copy_libs_to_file(void) +{ + return -1; +} + #endif // HA_HAVE_DUMP_LIBS /* -- 2.47.3