MINOR: debug: add support for -dL to dump library names at boot
This is a second help to dump loaded library names late at boot, once
external code has already been initialized. The purpose is to provide
a format that makes it easy to pass to "tar" to produce an archive
containing the executable and the list of dependencies. For example
if haproxy is started as "haproxy -f foo.cfg", a config check only
will suffice to quit before starting, "-q" will be used to disable
undesired output messages, and -dL will be use to dump libraries.
This will result in such a command to trivially produce a tarball
of loaded libraries:
./haproxy -q -c -dL -f foo.cfg | tar -T - -hzcf archive.tgz
(cherry picked from commit 654726db5ab1160ad5dc8d356e2965e69c163dcf)
Signed-off-by: Willy Tarreau <w@1wt.eu>
(cherry picked from commit 6bba474149ec2432274efb8c96b69e748f9c90d4)
Signed-off-by: Willy Tarreau <w@1wt.eu>
diff --git a/doc/management.txt b/doc/management.txt
index ae4aee8..dc65ba9 100644
--- a/doc/management.txt
+++ b/doc/management.txt
@@ -209,6 +209,19 @@
getaddrinfo() exist on various systems and cause anomalies that are
difficult to troubleshoot.
+ -dL : dumps the list of dynamic shared libraries that are loaded at the end
+ of the config processing. This will generally also include deep dependencies
+ such as anything loaded from Lua code for example, as well as the executable
+ itself. The list is printed in a format that ought to be easy enough to
+ sanitize to directly produce a tarball of all dependencies. Since it doesn't
+ stop the program's startup, it is recommended to only use it in combination
+ with "-c" and "-q" where only the list of loaded objects will be displayed
+ (or nothing in case of error). In addition, keep in mind that when providing
+ such a package to help with a core file analysis, most libraries are in fact
+ symbolic links that need to be dereferenced when creating the archive:
+
+ ./haproxy -W -q -c -dL -f foo.cfg | tar -T - -hzcf archive.tgz
+
-dM[<byte>] : forces memory poisoning, which means that each and every
memory region allocated with malloc() or pool_alloc() will be filled with
<byte> before being passed to the caller. When <byte> is not specified, it
diff --git a/include/haproxy/global-t.h b/include/haproxy/global-t.h
index e52bf1e..d4b91a3 100644
--- a/include/haproxy/global-t.h
+++ b/include/haproxy/global-t.h
@@ -39,6 +39,7 @@
#define MODE_ZERO_WARNING 0x200 /* warnings cause a failure */
#define MODE_DIAG 0x400 /* extra warnings */
#define MODE_STOPPING 0x1000 /* the process is in the deinit phase, the event loop is not running anymore. */
+#define MODE_DUMP_LIBS 0x2000 /* dump loaded libraries at the end of init phase */
/* list of last checks to perform, depending on config options */
#define LSTCHK_CAP_BIND 0x00000001 /* check that we can bind to any port */
diff --git a/src/haproxy.c b/src/haproxy.c
index 416f28b..d1c38eb 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -600,6 +600,9 @@
#if defined(SO_REUSEPORT)
" -dR disables SO_REUSEPORT usage\n"
#endif
+#if defined(HA_HAVE_DUMP_LIBS)
+ " -dL dumps loaded object files after config checks\n"
+#endif
" -dr ignores server address resolution failures\n"
" -dV disables SSL verify on servers side\n"
" -dW fails if any warning is emitted\n"
@@ -1621,6 +1624,10 @@
mem_poison_byte = flag[2] ? strtol(flag + 2, NULL, 0) : 'P';
else if (*flag == 'd' && flag[1] == 'r')
global.tune.options |= GTUNE_RESOLVE_DONTFAIL;
+#if defined(HA_HAVE_DUMP_LIBS)
+ else if (*flag == 'd' && flag[1] == 'L')
+ arg_mode |= MODE_DUMP_LIBS;
+#endif
else if (*flag == 'd')
arg_mode |= MODE_DEBUG;
else if (*flag == 'c')
@@ -1756,7 +1763,7 @@
global.mode |= (arg_mode & (MODE_DAEMON | MODE_MWORKER | MODE_FOREGROUND | MODE_VERBOSE
| MODE_QUIET | MODE_CHECK | MODE_DEBUG | MODE_ZERO_WARNING
- | MODE_DIAG));
+ | MODE_DIAG | MODE_DUMP_LIBS));
if (getenv("HAPROXY_MWORKER_WAIT_ONLY")) {
unsetenv("HAPROXY_MWORKER_WAIT_ONLY");
@@ -2009,6 +2016,15 @@
exit(1);
}
+#if defined(HA_HAVE_DUMP_LIBS)
+ if (global.mode & MODE_DUMP_LIBS) {
+ qfprintf(stdout, "List of loaded object files:\n");
+ chunk_reset(&trash);
+ if (dump_libs(&trash, 0))
+ printf("%s", trash.area);
+ }
+#endif
+
if (global.mode & MODE_CHECK) {
struct peers *pr;
struct proxy *px;