From a4741725a9596b25a9b7308b6a47e85b889d4557 Mon Sep 17 00:00:00 2001
From: Craig Ringer <craig.ringer@2ndquadrant.com>
Date: Mon, 26 Oct 2020 20:43:24 +0800
Subject: [PATCH v1 2/3] Add libpq version information to dynamic symbol table

Add three new data symbols LIBPQ_VERSION_STR, LIBPQ_VERSION_NUM and
LIBPQ_CONFIGURE_ARGS to libpq's symbol table. These make it much easier to
identify a given libpq without debuginfo, even if it cannot be executed (e.g.
due to dependency problems or mismatched platforms).

    $ strip libpq.so
    $ gdb -batch -ex 'p (int)LIBPQ_VERSION_NUM' \
                 -ex 'p (const char *)LIBPQ_VERSION_STR' \
                 -ex 'p (const char *)LIBPQ_CONFIGURE_ARGS' \
                 ./libpq.so.stripped
    $1 = 140000
    $2 = 0x285f0 "PostgreSQL 14devel on x86_64 ...."
    $3 = 0x28660 " '--enable-debug' '--enable-cassert' ...."
---
 src/interfaces/libpq/exports.txt     |  3 +++
 src/interfaces/libpq/libpq-version.c | 32 +++++++++++++++++++++++++---
 2 files changed, 32 insertions(+), 3 deletions(-)

diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt
index 1d8600f0d8..64fb62c802 100644
--- a/src/interfaces/libpq/exports.txt
+++ b/src/interfaces/libpq/exports.txt
@@ -181,3 +181,6 @@ PQgetSSLKeyPassHook_OpenSSL         178
 PQdefaultSSLKeyPassHook_OpenSSL     179
 PQlibInfo                           180
 PQlibInfoPrint                      181
+LIBPQ_VERSION_STR                   182
+LIBPQ_VERSION_NUM                   183
+LIBPQ_CONFIGURE_ARGS                184
diff --git a/src/interfaces/libpq/libpq-version.c b/src/interfaces/libpq/libpq-version.c
index 51a5c608c8..bab0263848 100644
--- a/src/interfaces/libpq/libpq-version.c
+++ b/src/interfaces/libpq/libpq-version.c
@@ -47,21 +47,47 @@
 
 #define libinfo_boolstr(x) (x) == 1 ? gettext_noop("1") : gettext_noop("0")
 
+/*
+ * Store postgres version information in const symbols in the read-only data
+ * section of the libpq binary so they are exposed in the export symbol table,
+ * not just as macros.
+ *
+ * This way the exact version of a given libpq.so / libpq.dll can be determined
+ * even if it was built without macros in debuginfo or if is stripped, and
+ * without necessarily being able to execute the binary (e.g. due to linker
+ * issues).
+ *
+ * We need to store these for PGlibInfoEntries anyway, this just makes them
+ * individually addressable for the use of trace/diagnostic tools and
+ * debuggers.
+ *
+ * The linker will put these in read-only data segments so they won't use extra
+ * dynamic memory at runtime.
+ *
+ * You should prefer to use the normal methods of getting version info in your
+ * applications - PQlibVersion(), PG_VERSION_NUM, the server_version_num GUC,
+ * etc.
+ */
+
+const char * const LIBPQ_VERSION_STR = PG_VERSION_STR;
+const int LIBPQ_VERSION_NUM = PG_VERSION_NUM;
+const char * const LIBPQ_CONFIGURE_ARGS = CONFIGURE_ARGS;
+
 static const PGlibInfoEntry PGlibInfoEntries[] = {
 	{
 		PGRES_LIBINFO_VERSION_NUM,
 		gettext_noop("VERSION_NUM"),
-		CppAsString2(PG_VERSION_NUM), 1, PG_VERSION_NUM
+		CppAsString2(PG_VERSION_NUM), 1, LIBPQ_VERSION_NUM
 	},
 	{
 		PGRES_LIBINFO_VERSION_STR,
 		gettext_noop("VERSION"),
-		PG_VERSION_STR, 0, 0
+		LIBPQ_VERSION_STR, 0, 0
 	},
 	{
 		PGRES_LIBINFO_CONFIGURE_ARGS,
 		gettext_noop("CONFIGURE_ARGS"),
-		CONFIGURE_ARGS, 0, 0
+		LIBPQ_CONFIGURE_ARGS, 0, 0
 	},
 	{
 		PGRES_LIBINFO_USE_SSL,
-- 
2.26.2

