0001-Add-Windows-support-for-backtrace_functions.patch
text/plain
Filename: 0001-Add-Windows-support-for-backtrace_functions.patch
Type: text/plain
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch 0001
Subject: Add Windows support for backtrace_functions
| File | + | − |
|---|---|---|
| src/backend/meson.build | 5 | 0 |
| src/backend/utils/error/elog.c | 174 | 0 |
From 81ee688f490fa37b5eb30d1d88123e3d0a8423f2 Mon Sep 17 00:00:00 2001
From: Bryan Green <dbryan.green@gmail.com>
Date: Tue, 21 Oct 2025 19:31:29 -0500
Subject: [PATCH] Add Windows support for backtrace_functions
Implement backtrace generation on Windows using the DbgHelp API, providing
similar functionality to the existing Unix/Linux support. When PDB files
are available, backtraces include function names and source locations.
Without PDB files, raw addresses are shown.
DbgHelp is initialized once per backend and cleaned up via on_proc_exit().
This adds a dependency on dbghelp.lib for MSVC builds.
---
src/backend/meson.build | 5 +
src/backend/utils/error/elog.c | 174 +++++++++++++++++++++++++++++++++
2 files changed, 179 insertions(+)
diff --git a/src/backend/meson.build b/src/backend/meson.build
index b831a54165..eeb69c4079 100644
--- a/src/backend/meson.build
+++ b/src/backend/meson.build
@@ -1,6 +1,11 @@
# Copyright (c) 2022-2025, PostgreSQL Global Development Group
backend_build_deps = [backend_code]
+
+if host_system == 'windows' and cc.get_id() == 'msvc'
+ backend_build_deps += cc.find_library('dbghelp')
+endif
+
backend_sources = []
backend_link_with = [pgport_srv, common_srv]
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 29643c5143..fc421ce444 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -140,6 +140,13 @@ static void write_syslog(int level, const char *line);
static void write_eventlog(int level, const char *line, int len);
#endif
+#ifdef _MSC_VER
+#include <windows.h>
+#include <dbghelp.h>
+static bool win32_backtrace_symbols_initialized = false;
+static HANDLE win32_backtrace_process = NULL;
+#endif
+
/* We provide a small stack of ErrorData records for re-entrant cases */
#define ERRORDATA_STACK_SIZE 5
@@ -1116,6 +1123,18 @@ errbacktrace(void)
return 0;
}
+#ifdef _MSC_VER
+/*
+ * Cleanup function for DbgHelp resources.
+ * Called via on_proc_exit() to release resources allocated by SymInitialize().
+ */
+static void
+win32_backtrace_cleanup(int code, Datum arg)
+{
+ SymCleanup(win32_backtrace_process);
+}
+#endif
+
/*
* Compute backtrace data and add it to the supplied ErrorData. num_skip
* specifies how many inner frames to skip. Use this to avoid showing the
@@ -1147,6 +1166,161 @@ set_backtrace(ErrorData *edata, int num_skip)
appendStringInfoString(&errtrace,
"insufficient memory for backtrace generation");
}
+#elif defined(_MSC_VER)
+ {
+ void *stack[100];
+ DWORD frames;
+ DWORD i;
+ wchar_t buffer[sizeof(SYMBOL_INFOW) + MAX_SYM_NAME * sizeof(wchar_t)];
+ PSYMBOL_INFOW symbol;
+ char *utf8_buffer;
+ int utf8_len;
+
+ if (!win32_backtrace_symbols_initialized)
+ {
+ win32_backtrace_process = GetCurrentProcess();
+
+ SymSetOptions(SYMOPT_UNDNAME |
+ SYMOPT_DEFERRED_LOADS |
+ SYMOPT_LOAD_LINES |
+ SYMOPT_FAIL_CRITICAL_ERRORS);
+
+ if (SymInitialize(win32_backtrace_process, NULL, TRUE))
+ {
+ win32_backtrace_symbols_initialized = true;
+ on_proc_exit(win32_backtrace_cleanup, 0);
+ }
+ else
+ {
+ DWORD error = GetLastError();
+
+ elog(WARNING, "SymInitialize failed with error %lu", error);
+ }
+ }
+
+ frames = CaptureStackBackTrace(num_skip, lengthof(stack), stack, NULL);
+
+ if (frames == 0)
+ {
+ appendStringInfoString(&errtrace, "\nNo stack frames captured");
+ edata->backtrace = errtrace.data;
+ return;
+ }
+
+ symbol = (PSYMBOL_INFOW) buffer;
+ symbol ->MaxNameLen = MAX_SYM_NAME;
+ symbol ->SizeOfStruct = sizeof(SYMBOL_INFOW);
+
+ for (i = 0; i < frames; i++)
+ {
+ DWORD64 address = (DWORD64) (stack[i]);
+ DWORD64 displacement = 0;
+ BOOL sym_result;
+
+ sym_result = SymFromAddrW(win32_backtrace_process,
+ address,
+ &displacement,
+ symbol);
+
+ if (sym_result)
+ {
+ IMAGEHLP_LINEW64 line;
+ DWORD line_displacement = 0;
+
+ line.SizeOfStruct = sizeof(IMAGEHLP_LINEW64);
+
+ if (SymGetLineFromAddrW64(win32_backtrace_process,
+ address,
+ &line_displacement,
+ &line))
+ {
+ /* Convert symbol name to UTF-8 */
+ utf8_len = WideCharToMultiByte(CP_UTF8, 0, symbol->Name, -1,
+ NULL, 0, NULL, NULL);
+ if (utf8_len > 0)
+ {
+ char *filename_utf8;
+ int filename_len;
+
+ utf8_buffer = palloc(utf8_len);
+ WideCharToMultiByte(CP_UTF8, 0, symbol->Name, -1,
+ utf8_buffer, utf8_len, NULL, NULL);
+
+ /* Convert file name to UTF-8 */
+ filename_len = WideCharToMultiByte(CP_UTF8, 0,
+ line.FileName, -1,
+ NULL, 0, NULL, NULL);
+ if (filename_len > 0)
+ {
+ filename_utf8 = palloc(filename_len);
+ WideCharToMultiByte(CP_UTF8, 0, line.FileName, -1,
+ filename_utf8, filename_len,
+ NULL, NULL);
+
+ appendStringInfo(&errtrace,
+ "\n%s+0x%llx [%s:%lu]",
+ utf8_buffer,
+ (unsigned long long) displacement,
+ filename_utf8,
+ (unsigned long) line.LineNumber);
+
+ pfree(filename_utf8);
+ }
+ else
+ {
+ appendStringInfo(&errtrace,
+ "\n%s+0x%llx [0x%llx]",
+ utf8_buffer,
+ (unsigned long long) displacement,
+ (unsigned long long) address);
+ }
+
+ pfree(utf8_buffer);
+ }
+ else
+ {
+ /* Conversion failed, use address only */
+ appendStringInfo(&errtrace,
+ "\n[0x%llx]",
+ (unsigned long long) address);
+ }
+ }
+ else
+ {
+ /* No line info, convert symbol name only */
+ utf8_len = WideCharToMultiByte(CP_UTF8, 0, symbol->Name, -1,
+ NULL, 0, NULL, NULL);
+ if (utf8_len > 0)
+ {
+ utf8_buffer = palloc(utf8_len);
+ WideCharToMultiByte(CP_UTF8, 0, symbol->Name, -1,
+ utf8_buffer, utf8_len, NULL, NULL);
+
+ appendStringInfo(&errtrace,
+ "\n%s+0x%llx [0x%llx]",
+ utf8_buffer,
+ (unsigned long long) displacement,
+ (unsigned long long) address);
+
+ pfree(utf8_buffer);
+ }
+ else
+ {
+ /* Conversion failed, use address only */
+ appendStringInfo(&errtrace,
+ "\n[0x%llx]",
+ (unsigned long long) address);
+ }
+ }
+ }
+ else
+ {
+ appendStringInfo(&errtrace,
+ "\n[0x%llx]",
+ (unsigned long long) address);
+ }
+ }
+ }
#else
appendStringInfoString(&errtrace,
"backtrace generation is not supported by this installation");
--
2.46.0.windows.1