From 1c59c465f2d359e8c47cf91d1ea458ea3b64ec84 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Mon, 13 May 2024 13:47:41 -0700
Subject: [PATCH v1] WIP: Track shared library in which elog/ereport is called

---
 src/include/fmgr.h             |  1 +
 src/include/utils/elog.h       | 18 +++++++++++++-----
 src/backend/utils/error/elog.c | 33 ++++++++++++++++++++++++---------
 src/backend/utils/fmgr/dfmgr.c | 30 ++++++++++++++++++++++++++++++
 4 files changed, 68 insertions(+), 14 deletions(-)

diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index ccb4070a251..3c7cfd7fee9 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -504,6 +504,7 @@ PG_MAGIC_FUNCTION_NAME(void) \
 	static const Pg_magic_struct Pg_magic_data = PG_MODULE_MAGIC_DATA; \
 	return &Pg_magic_data; \
 } \
+PGDLLEXPORT const char *Pg_extension_filename = NULL; \
 extern int no_such_variable
 
 
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index 054dd2bf62f..5e57f01823d 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -137,6 +137,13 @@ struct Node;
  * prevents gcc from making the unreachability deduction at optlevel -O0.
  *----------
  */
+#ifdef BUILDING_DLL
+#define ELOG_EXTNAME NULL
+#else
+extern PGDLLEXPORT const char *Pg_extension_filename;
+#define ELOG_EXTNAME Pg_extension_filename
+#endif
+
 #ifdef HAVE__BUILTIN_CONSTANT_P
 #define ereport_domain(elevel, domain, ...)	\
 	do { \
@@ -144,7 +151,7 @@ struct Node;
 		if (__builtin_constant_p(elevel) && (elevel) >= ERROR ? \
 			errstart_cold(elevel, domain) : \
 			errstart(elevel, domain)) \
-			__VA_ARGS__, errfinish(__FILE__, __LINE__, __func__); \
+			__VA_ARGS__, errfinish(__FILE__, __LINE__, __func__, ELOG_EXTNAME); \
 		if (__builtin_constant_p(elevel) && (elevel) >= ERROR) \
 			pg_unreachable(); \
 	} while(0)
@@ -154,7 +161,7 @@ struct Node;
 		const int elevel_ = (elevel); \
 		pg_prevent_errno_in_scope(); \
 		if (errstart(elevel_, domain)) \
-			__VA_ARGS__, errfinish(__FILE__, __LINE__, __func__); \
+			__VA_ARGS__, errfinish(__FILE__, __LINE__, __func__, ELOG_EXTNAME); \
 		if (elevel_ >= ERROR) \
 			pg_unreachable(); \
 	} while(0)
@@ -169,7 +176,7 @@ extern bool message_level_is_interesting(int elevel);
 
 extern bool errstart(int elevel, const char *domain);
 extern pg_attribute_cold bool errstart_cold(int elevel, const char *domain);
-extern void errfinish(const char *filename, int lineno, const char *funcname);
+extern void errfinish(const char *filename, int lineno, const char *funcname, const char *extfile);
 
 extern int	errcode(int sqlerrcode);
 
@@ -268,7 +275,7 @@ extern int	getinternalerrposition(void);
 		struct Node *context_ = (context); \
 		pg_prevent_errno_in_scope(); \
 		if (errsave_start(context_, domain)) \
-			__VA_ARGS__, errsave_finish(context_, __FILE__, __LINE__, __func__); \
+			__VA_ARGS__, errsave_finish(context_, __FILE__, __LINE__, __func__, ELOG_EXTNAME); \
 	} while(0)
 
 #define errsave(context, ...)	\
@@ -293,7 +300,7 @@ extern int	getinternalerrposition(void);
 extern bool errsave_start(struct Node *context, const char *domain);
 extern void errsave_finish(struct Node *context,
 						   const char *filename, int lineno,
-						   const char *funcname);
+						   const char *funcname, const char *extname);
 
 
 /* Support for constructing error strings separately from ereport() calls */
@@ -449,6 +456,7 @@ typedef struct ErrorData
 	const char *funcname;		/* __func__ of ereport() call */
 	const char *domain;			/* message domain */
 	const char *context_domain; /* message domain for context message */
+	const char *extname;		/* extension filename or NULL */
 	int			sqlerrcode;		/* encoded ERRSTATE */
 	char	   *message;		/* primary error message (translated) */
 	char	   *detail;			/* detail error message */
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index d91a85cb2d7..1d34e89d7f5 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -180,7 +180,7 @@ static ErrorData *get_error_stack_entry(void);
 static void set_stack_entry_domain(ErrorData *edata, const char *domain);
 static void set_stack_entry_location(ErrorData *edata,
 									 const char *filename, int lineno,
-									 const char *funcname);
+									 const char *funcname, const char *extname);
 static bool matches_backtrace_functions(const char *funcname);
 static pg_noinline void set_backtrace(ErrorData *edata, int num_skip);
 static void set_errdata_field(MemoryContextData *cxt, char **ptr, const char *str);
@@ -474,7 +474,7 @@ errstart(int elevel, const char *domain)
  * return to the caller.  See elog.h for the error level definitions.
  */
 void
-errfinish(const char *filename, int lineno, const char *funcname)
+errfinish(const char *filename, int lineno, const char *funcname, const char *extname)
 {
 	ErrorData  *edata = &errordata[errordata_stack_depth];
 	int			elevel;
@@ -485,7 +485,7 @@ errfinish(const char *filename, int lineno, const char *funcname)
 	CHECK_STACK_DEPTH();
 
 	/* Save the last few bits of error state into the stack entry */
-	set_stack_entry_location(edata, filename, lineno, funcname);
+	set_stack_entry_location(edata, filename, lineno, funcname, extname);
 
 	elevel = edata->elevel;
 
@@ -683,7 +683,7 @@ errsave_start(struct Node *context, const char *domain)
  */
 void
 errsave_finish(struct Node *context, const char *filename, int lineno,
-			   const char *funcname)
+			   const char *funcname, const char *extname)
 {
 	ErrorSaveContext *escontext = (ErrorSaveContext *) context;
 	ErrorData  *edata = &errordata[errordata_stack_depth];
@@ -697,7 +697,7 @@ errsave_finish(struct Node *context, const char *filename, int lineno,
 	 */
 	if (edata->elevel >= ERROR)
 	{
-		errfinish(filename, lineno, funcname);
+		errfinish(filename, lineno, funcname, extname);
 		pg_unreachable();
 	}
 
@@ -708,7 +708,7 @@ errsave_finish(struct Node *context, const char *filename, int lineno,
 	recursion_depth++;
 
 	/* Save the last few bits of error state into the stack entry */
-	set_stack_entry_location(edata, filename, lineno, funcname);
+	set_stack_entry_location(edata, filename, lineno, funcname, extname);
 
 	/* Replace the LOG value that errsave_start inserted */
 	edata->elevel = ERROR;
@@ -798,7 +798,7 @@ set_stack_entry_domain(ErrorData *edata, const char *domain)
 static void
 set_stack_entry_location(ErrorData *edata,
 						 const char *filename, int lineno,
-						 const char *funcname)
+						 const char *funcname, const char *extname)
 {
 	if (filename)
 	{
@@ -817,6 +817,7 @@ set_stack_entry_location(ErrorData *edata,
 	edata->filename = filename;
 	edata->lineno = lineno;
 	edata->funcname = funcname;
+	edata->extname = extname;
 }
 
 /*
@@ -1903,7 +1904,7 @@ ThrowErrorData(ErrorData *edata)
 	recursion_depth--;
 
 	/* Process the error. */
-	errfinish(edata->filename, edata->lineno, edata->funcname);
+	errfinish(edata->filename, edata->lineno, edata->funcname, edata->extname);
 }
 
 /*
@@ -2000,7 +2001,7 @@ pg_re_throw(void)
 		 */
 		error_context_stack = NULL;
 
-		errfinish(edata->filename, edata->lineno, edata->funcname);
+		errfinish(edata->filename, edata->lineno, edata->funcname, edata->extname);
 	}
 
 	/* Doesn't return ... */
@@ -3110,6 +3111,20 @@ log_status_format(StringInfo buf, const char *format, ErrorData *edata)
 				else
 					appendStringInfoString(buf, unpack_sql_state(edata->sqlerrcode));
 				break;
+			case 'E':
+				{
+					const char *extname = edata->extname;
+
+					if (!extname)
+						extname = "postgres";
+
+					if (padding != 0)
+						appendStringInfo(buf, "%*s", padding,
+										 extname);
+					else
+						appendStringInfoString(buf, extname);
+					break;
+				}
 			case 'Q':
 				if (padding != 0)
 					appendStringInfo(buf, "%*lld", padding,
diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c
index eafa0128ef0..873868b6a15 100644
--- a/src/backend/utils/fmgr/dfmgr.c
+++ b/src/backend/utils/fmgr/dfmgr.c
@@ -36,6 +36,7 @@
 #include "storage/fd.h"
 #include "storage/shmem.h"
 #include "utils/hsearch.h"
+#include "utils/memutils.h"
 
 
 /* signature for PostgreSQL-specific library init function */
@@ -268,6 +269,35 @@ internal_load_library(const char *libname)
 				/* issue suitable complaint */
 				incompatible_module_error(libname, &module_magic_data);
 			}
+
+			{
+				const char **extname;
+				char *libname_short;
+
+				extname = dlsym(file_scanner->handle,
+								"Pg_extension_filename");
+				if (!extname)
+					elog(ERROR, "couldn't find Pg_extension_filename");
+
+				/*
+				 * For loaded libraries, the filename, without file ending,
+				 * ought to be unique. Pg_extension_filename is intended for
+				 * logging, a full file path would be onerous.
+				 */
+				libname_short = last_dir_separator(libname) + 1;
+				libname_short = MemoryContextStrdup(TopMemoryContext,
+													last_dir_separator(libname) + 1);
+
+				for (int i = strlen(libname_short); i >= 0; i--)
+				{
+					if (libname_short[i] == '.')
+					{
+						libname_short[i] = '\0';
+						break;
+					}
+				}
+				*extname = MemoryContextStrdup(TopMemoryContext, libname_short);
+			}
 		}
 		else
 		{
-- 
2.44.0.279.g3bd955d269

