pg.ddx.io pgsql-hackers@postgresql.org mailing list archive
help / color / mirror / Atom feedFrom: Bryan Green <dbryan.green@gmail.com>
To: Euler Taveira <euler@eulerto.com>
To: Jakub Wartak <jakub.wartak@enterprisedb.com>
Cc: Álvaro Herrera <alvherre@kurilemu.de>
Cc: Michael Paquier <michael@paquier.xyz>
Cc: pgsql-hackers <pgsql-hackers@postgresql.org>
Subject: Re: [PATCH] Add Windows support for backtrace_functions (MSVC only)
Date: Fri, 31 Oct 2025 22:40:58 -0600
Message-ID: <31f43d88-9949-48c5-9497-b9a9b7cdee2b@gmail.com> (raw)
In-Reply-To: <c04e5ca9-d1e1-48a6-acf3-0fd42f103ac0@gmail.com>
References: <202510300932.isdvgkzqzshk@alvherre.pgsql>
<5b4c6ce0-ed17-4abb-9127-859cc95cbdf3@gmail.com>
<CAKZiRmzuqPmgd_A+M+RiuT-4UtDt_TASqQJoqCdvCUrVY3w7cg@mail.gmail.com>
<30aea073-109c-43cc-979c-081b922d055d@gmail.com>
<2241662b-da7d-428f-beba-a416ef48e9e9@app.fastmail.com>
<c04e5ca9-d1e1-48a6-acf3-0fd42f103ac0@gmail.com>
On 10/31/2025 2:07 PM, Bryan Green wrote:
> On 10/31/2025 1:46 PM, Euler Taveira wrote:
>> On Thu, Oct 30, 2025, at 11:51 AM, Bryan Green wrote:
>>> I had reservations about the value the tests were adding, and
>>> considering I am getting more concern around having the tests than not
>>> having them for this initial release I have decided to remove them. v4
>>> patch is attached. It is the same as the initial 0001-* patch.
>>>
>>
>> I spent some time on this patch. Here are some comments and suggestions.
>>
>
> Thanks for the review.
>
>> +#ifdef _MSC_VER
>> +#include <windows.h>
>> +#include <dbghelp.h>
>> +static bool win32_backtrace_symbols_initialized = false;
>> +static HANDLE win32_backtrace_process = NULL;
>> +#endif
>>
>> We usually a different style. Headers go to the top on the same
>> section as
>> system headers and below postgres.h. It is generally kept sorted. The
>> same
>
> Will fix. I will rework the style (error and otherwise) to follow the
> project tradition.
>
>> applies to variables. Add them near the other static variables. BTW
>> does it need
>> the win32_ prefix for a Window-only variable?
>>
>> + wchar_t buffer[sizeof(SYMBOL_INFOW) + MAX_SYM_NAME *
>> sizeof(wchar_t)];
>> + PSYMBOL_INFOW symbol;
>>
>> According to [1], SYMBOL_INFO is an alias that automatically selects
>> ANSI vs
>> UNICODE. Shouldn't we use it instead of SYMBOL_INFOW?
>>
>
> Good point. I was being overly explicit about wanting wide chars, but
> you're right that the generic versions are the way to go.
>
>> + elog(WARNING, "SymInitialize failed with error %lu",
>> error);
>>
>> Is there a reason to continue if SymInitialize failed? It should
>> return after
>
> None at all. Will return immediately.
>
>> printing the message. Per the error message style guide [2], my
>> suggestion is
>> "could not initialize the symbol handler: error code %lu". You can
>> also use
>> GetLastError() directly in the elog call.
>>
>> + symbol = (PSYMBOL_INFOW) buffer;
>> + symbol ->MaxNameLen = MAX_SYM_NAME;
>> + symbol ->SizeOfStruct = sizeof(SYMBOL_INFOW);
>>
>> We generally don't add spaces between variable and a member.
>>
>> + DWORD i;
>>
>> I'm curious why did you declare this variable as DWORD? Shouldn't int be
>> sufficient? The CaptureStackBackTrace function returns an unsigned short
>> (UShort). You can also declare it in the for loop.
>>
>
> Out of habit. I will change it to int.
>
>> + DWORD64 address = (DWORD64) (stack[i]);
>>
>> The parenthesis around stack is superfluous. The code usually doesn't
>> contain
>> additional parenthesis (unless it improves readability).
>>
>
> I will remove the parenthesis.
>
>> + if (frames == 0)
>> + {
>> + appendStringInfoString(&errtrace, "\nNo stack frames
>> captured");
>> + edata->backtrace = errtrace.data;
>> + return;
>> + }
>>
>> It seems CaptureStackBackTrace function may return zero frames under
>> certain
>> conditions. It is a good point having this additional message. I
>> noticed that
>> the current code path (HAVE_BACKTRACE_SYMBOLS) doesn't have this
>> block. IIUC,
>> in certain circumstances (ARM vs unwind-tables flag), the backtrace()
>> also
>> returns zero frames. Should we add this block for the backtrace() code
>> path?
>>
>
> Probably, though that seems like separate cleanup. Want me to include it
> here or handle separately (in another patch)?
>
>> + sym_result = SymFromAddrW(win32_backtrace_process,
>> + address,
>> + &displacement,
>> + symbol);
>>
>> You should use SymFromAddr, no? [3] I saw that you used the Unicode
>> functions
>> instead of the generic functions [4].
>>
>> + /* 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 symbol name to UTF-8 */
>> + utf8_len = WideCharToMultiByte(CP_UTF8, 0,
>> symbol->Name, -1,
>> + NULL, 0, NULL, NULL);
>>
>> You are calling WideCharToMultiByte twice. The reason is to allocate
>> the exact
>> memory size. However, you can adopt another logic to avoid the first
>> call.
>>
>> maxlen = symbol->NameLen * pg_database_encoding_max_length();
>> symbol_name = palloc(maxlen + 1);
>>
>> (I suggest symbol_name instead of ut8_buffer.)
>>
>> You are considering only the UTF-8 case. Shouldn't it use wcstombs or
>> wcstombs_l? Maybe (re)use wchar2char -- see pg_locale_libc.c.
>>
>
> Hmm, you're probably right. I was thinking these Windows API strings
> needed special handling, but wchar2char should handle the conversion to
> database encoding correctly. Let me test that approach.
>
>> + 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);
>> + }
>>
>> Maybe I missed something but is there a reason for not adding the
>> address in the
>> first condition?
>>
>
> No particular reason. I was trying to keep it concise when we have file/
> line info, but for consistency it probably should be there.
>
> Will send v5 with these fixes.
>
>>
>> [1] https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/ns-
>> dbghelp-symbol_infow
>> [2] https://www.postgresql.org/docs/current/error-style-guide.html
>> [3] https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/nf-
>> dbghelp-symfromaddrw
>> [4] https://learn.microsoft.com/en-us/windows/win32/intl/conventions-
>> for-function-prototypes
>>
>>
>
> Thanks again for the review,
> Bryan
Hi all,
v5 patch attached, incorporating all of Euler's feedback with a caveat
around unicode.
The most interesting aspect turned out to be the encoding conversion for
symbol names and file paths. Initially I tried using the generic
SYMBOL_INFO and SymFromAddr functions as Euler suggested, but ran into a
subtle issue: on PostgreSQL's Windows builds, these become SYMBOL_INFOA
and SymFromAddrA (the ANSI versions), which return strings in whatever
Windows ANSI codepage happens to be active (CP1252, etc). This doesn't
necessarily match the database encoding.
When I tried converting these with wchar2char(), it failed because the
input wasn't actually wide characters - leading to backtraces showing
only raw addresses even though symbols were present.
The solution was to use the explicit Unicode versions (SYMBOL_INFOW and
SymFromAddrW), which reliably return UTF-16 strings that wchar2char()
can properly convert to the database encoding. This handles both UTF-8
and non-UTF-8 databases correctly, and wchar2char() gracefully returns
-1 on conversion failure rather than throwing errors during error
handling. Of course this also necessitated using IMAGEHLP_LINEW64 and
SymGetLineFromAddrW64.
Tested with both UTF-8 and WIN1252 databases - backtraces now show
proper symbol names in both cases.
This patch also adds a check for zero frames returned by backtrace() on
Unix/Linux platforms, which can occur in certain circumstances such as
ARM builds without unwind tables.
Bryan
From ba3bf14d523e4c656be1cf3d8bdb80afaa3355ed Mon Sep 17 00:00:00 2001
From: Bryan Green <dbryan.green@gmail.com>
Date: Fri, 31 Oct 2025 20:27:38 -0600
Subject: [PATCH v5] Add backtrace support for Windows using DbgHelp API
Previously, backtrace generation on Windows would return an "unsupported"
message. This patch implements Windows backtrace support using
CaptureStackBackTrace() for capturing the call stack and the DbgHelp API
(SymFromAddrW, SymGetLineFromAddr64) for symbol resolution.
The implementation provides symbol names, offsets, addresses, and when PDB
files are available, source file names and line numbers. Symbol names and
file paths are converted from UTF-16 to the database encoding using
wchar2char(), which properly handles both UTF-8 and non-UTF-8 databases on
Windows. When symbol information is unavailable or encoding conversion
fails, it falls back to displaying raw addresses.
The implementation uses the explicit Unicode versions of the DbgHelp
functions (SYMBOL_INFOW, SymFromAddrW) rather than the generic versions.
This is necessary because the generic SYMBOL_INFO becomes SYMBOL_INFOA on
PostgreSQL's Windows builds (which don't define UNICODE), providing strings
in the Windows ANSI codepage rather than a predictable encoding that can be
converted to the database encoding.
Symbol handler initialization (SymInitialize) is performed once per process
and cached. If initialization fails, a warning is logged and no backtrace
is generated.
This patch also adds a check for zero frames returned by backtrace() on
Unix/Linux platforms, which can occur in certain circumstances such as ARM
builds without unwind tables.
Author: Bryan Green <dbryan.green@gmail.com>
Reviewed-by: Euler Taveira <euler@eulerto.com>
Reviewed-by: Jakub Wartak <jakub.wartak@enterprisedb.com>
---
src/backend/meson.build | 5 ++
src/backend/utils/error/elog.c | 151 ++++++++++++++++++++++++++++++++-
2 files changed, 155 insertions(+), 1 deletion(-)
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..17a3ba256a 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -66,11 +66,15 @@
#include <execinfo.h>
#endif
+#ifdef _MSC_VER
+#include <dbghelp.h>
+#include <windows.h>
+#endif
+
#include "access/xact.h"
#include "common/ip.h"
#include "libpq/libpq.h"
#include "libpq/pqformat.h"
-#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "nodes/miscnodes.h"
#include "pgstat.h"
@@ -140,6 +144,11 @@ static void write_syslog(int level, const char *line);
static void write_eventlog(int level, const char *line, int len);
#endif
+#ifdef _MSC_VER
+static bool backtrace_symbols_initialized = false;
+static HANDLE backtrace_process = NULL;
+#endif
+
/* We provide a small stack of ErrorData records for re-entrant cases */
#define ERRORDATA_STACK_SIZE 5
@@ -1121,6 +1130,13 @@ errbacktrace(void)
* specifies how many inner frames to skip. Use this to avoid showing the
* internal backtrace support functions in the backtrace. This requires that
* this and related functions are not inlined.
+ *
+ * Platform-specific implementations:
+ * - Unix/Linux: Uses backtrace() and backtrace_symbols()
+ * - Windows: Uses CaptureStackBackTrace() with DbgHelp for symbol resolution
+ * (requires PDB files; falls back to exported functions/raw addresses if
+ * unavailable)
+ * - Other: Returns unsupported message
*/
static void
set_backtrace(ErrorData *edata, int num_skip)
@@ -1136,6 +1152,14 @@ set_backtrace(ErrorData *edata, int num_skip)
char **strfrms;
nframes = backtrace(buf, lengthof(buf));
+
+ if (nframes == 0)
+ {
+ appendStringInfoString(&errtrace, "\nNo stack frames captured");
+ edata->backtrace = errtrace.data;
+ return;
+ }
+
strfrms = backtrace_symbols(buf, nframes);
if (strfrms != NULL)
{
@@ -1147,6 +1171,131 @@ set_backtrace(ErrorData *edata, int num_skip)
appendStringInfoString(&errtrace,
"insufficient memory for backtrace generation");
}
+#elif defined(_MSC_VER)
+ {
+ void *buf[100];
+ int nframes;
+ char buffer[sizeof(SYMBOL_INFOW) + MAX_SYM_NAME * sizeof(wchar_t)];
+ PSYMBOL_INFOW symbol;
+
+ if (!backtrace_symbols_initialized)
+ {
+ backtrace_process = GetCurrentProcess();
+
+ SymSetOptions(SYMOPT_UNDNAME |
+ SYMOPT_DEFERRED_LOADS |
+ SYMOPT_LOAD_LINES |
+ SYMOPT_FAIL_CRITICAL_ERRORS);
+
+ if (!SymInitialize(backtrace_process, NULL, TRUE))
+ {
+ elog(WARNING, "could not initialize the symbol handler: error code %lu",
+ GetLastError());
+ edata->backtrace = errtrace.data;
+ return;
+ }
+ backtrace_symbols_initialized = true;
+ }
+
+ nframes = CaptureStackBackTrace(num_skip, lengthof(buf), buf, NULL);
+
+ if (nframes == 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 (int i = 0; i < nframes; i++)
+ {
+ DWORD64 address = (DWORD64)buf[i];
+ DWORD64 displacement = 0;
+ BOOL sym_result;
+
+ sym_result = SymFromAddrW(backtrace_process,
+ address,
+ &displacement,
+ symbol);
+
+ if (sym_result)
+ {
+ IMAGEHLP_LINEW64 line;
+ DWORD line_displacement = 0;
+ char symbol_name[MAX_SYM_NAME];
+ size_t result;
+
+ line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
+
+ /*
+ * Convert symbol name from UTF-16 to database encoding using
+ * wchar2char(), which handles both UTF-8 and non-UTF-8 databases
+ * correctly on Windows.
+ */
+ result = wchar2char(symbol_name, (const wchar_t *) symbol->Name,
+ sizeof(symbol_name), NULL);
+
+ if (result == (size_t) -1)
+ {
+ /* Conversion failed, use address only */
+ appendStringInfo(&errtrace,
+ "\n[0x%llx]",
+ (unsigned long long) address);
+ continue;
+ }
+
+ if (SymGetLineFromAddrW64(backtrace_process,
+ address,
+ &line_displacement,
+ &line))
+ {
+ char filename[MAX_PATH];
+
+ /* Convert filename from UTF-16 to database encoding */
+ result = wchar2char(filename, (const wchar_t *) line.FileName,
+ sizeof(filename), NULL);
+
+ if (result != (size_t) -1)
+ {
+ appendStringInfo(&errtrace,
+ "\n%s+0x%llx [0x%llx] [%s:%lu]",
+ symbol_name,
+ (unsigned long long) displacement,
+ (unsigned long long) address,
+ filename,
+ (unsigned long) line.LineNumber);
+ }
+ else
+ {
+ /* Filename conversion failed, omit it */
+ appendStringInfo(&errtrace,
+ "\n%s+0x%llx [0x%llx]",
+ symbol_name,
+ (unsigned long long) displacement,
+ (unsigned long long) address);
+ }
+ }
+ else
+ {
+ /* No line info available */
+ appendStringInfo(&errtrace,
+ "\n%s+0x%llx [0x%llx]",
+ symbol_name,
+ (unsigned long long) displacement,
+ (unsigned long long) address);
+ }
+ }
+ else
+ {
+ elog(WARNING, "symbol lookup failed: error code %lu",
+ GetLastError());
+ edata->backtrace = errtrace.data;
+ }
+ }
+ }
#else
appendStringInfoString(&errtrace,
"backtrace generation is not supported by this installation");
--
2.46.0.windows.1
Attachments:
[text/plain] v5-0001-Add-Windows-support-for-backtrace_functions.patch (7.8K, ../31f43d88-9949-48c5-9497-b9a9b7cdee2b@gmail.com/2-v5-0001-Add-Windows-support-for-backtrace_functions.patch)
download | inline diff:
From ba3bf14d523e4c656be1cf3d8bdb80afaa3355ed Mon Sep 17 00:00:00 2001
From: Bryan Green <dbryan.green@gmail.com>
Date: Fri, 31 Oct 2025 20:27:38 -0600
Subject: [PATCH v5] Add backtrace support for Windows using DbgHelp API
Previously, backtrace generation on Windows would return an "unsupported"
message. This patch implements Windows backtrace support using
CaptureStackBackTrace() for capturing the call stack and the DbgHelp API
(SymFromAddrW, SymGetLineFromAddr64) for symbol resolution.
The implementation provides symbol names, offsets, addresses, and when PDB
files are available, source file names and line numbers. Symbol names and
file paths are converted from UTF-16 to the database encoding using
wchar2char(), which properly handles both UTF-8 and non-UTF-8 databases on
Windows. When symbol information is unavailable or encoding conversion
fails, it falls back to displaying raw addresses.
The implementation uses the explicit Unicode versions of the DbgHelp
functions (SYMBOL_INFOW, SymFromAddrW) rather than the generic versions.
This is necessary because the generic SYMBOL_INFO becomes SYMBOL_INFOA on
PostgreSQL's Windows builds (which don't define UNICODE), providing strings
in the Windows ANSI codepage rather than a predictable encoding that can be
converted to the database encoding.
Symbol handler initialization (SymInitialize) is performed once per process
and cached. If initialization fails, a warning is logged and no backtrace
is generated.
This patch also adds a check for zero frames returned by backtrace() on
Unix/Linux platforms, which can occur in certain circumstances such as ARM
builds without unwind tables.
Author: Bryan Green <dbryan.green@gmail.com>
Reviewed-by: Euler Taveira <euler@eulerto.com>
Reviewed-by: Jakub Wartak <jakub.wartak@enterprisedb.com>
---
src/backend/meson.build | 5 ++
src/backend/utils/error/elog.c | 151 ++++++++++++++++++++++++++++++++-
2 files changed, 155 insertions(+), 1 deletion(-)
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..17a3ba256a 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -66,11 +66,15 @@
#include <execinfo.h>
#endif
+#ifdef _MSC_VER
+#include <dbghelp.h>
+#include <windows.h>
+#endif
+
#include "access/xact.h"
#include "common/ip.h"
#include "libpq/libpq.h"
#include "libpq/pqformat.h"
-#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "nodes/miscnodes.h"
#include "pgstat.h"
@@ -140,6 +144,11 @@ static void write_syslog(int level, const char *line);
static void write_eventlog(int level, const char *line, int len);
#endif
+#ifdef _MSC_VER
+static bool backtrace_symbols_initialized = false;
+static HANDLE backtrace_process = NULL;
+#endif
+
/* We provide a small stack of ErrorData records for re-entrant cases */
#define ERRORDATA_STACK_SIZE 5
@@ -1121,6 +1130,13 @@ errbacktrace(void)
* specifies how many inner frames to skip. Use this to avoid showing the
* internal backtrace support functions in the backtrace. This requires that
* this and related functions are not inlined.
+ *
+ * Platform-specific implementations:
+ * - Unix/Linux: Uses backtrace() and backtrace_symbols()
+ * - Windows: Uses CaptureStackBackTrace() with DbgHelp for symbol resolution
+ * (requires PDB files; falls back to exported functions/raw addresses if
+ * unavailable)
+ * - Other: Returns unsupported message
*/
static void
set_backtrace(ErrorData *edata, int num_skip)
@@ -1136,6 +1152,14 @@ set_backtrace(ErrorData *edata, int num_skip)
char **strfrms;
nframes = backtrace(buf, lengthof(buf));
+
+ if (nframes == 0)
+ {
+ appendStringInfoString(&errtrace, "\nNo stack frames captured");
+ edata->backtrace = errtrace.data;
+ return;
+ }
+
strfrms = backtrace_symbols(buf, nframes);
if (strfrms != NULL)
{
@@ -1147,6 +1171,131 @@ set_backtrace(ErrorData *edata, int num_skip)
appendStringInfoString(&errtrace,
"insufficient memory for backtrace generation");
}
+#elif defined(_MSC_VER)
+ {
+ void *buf[100];
+ int nframes;
+ char buffer[sizeof(SYMBOL_INFOW) + MAX_SYM_NAME * sizeof(wchar_t)];
+ PSYMBOL_INFOW symbol;
+
+ if (!backtrace_symbols_initialized)
+ {
+ backtrace_process = GetCurrentProcess();
+
+ SymSetOptions(SYMOPT_UNDNAME |
+ SYMOPT_DEFERRED_LOADS |
+ SYMOPT_LOAD_LINES |
+ SYMOPT_FAIL_CRITICAL_ERRORS);
+
+ if (!SymInitialize(backtrace_process, NULL, TRUE))
+ {
+ elog(WARNING, "could not initialize the symbol handler: error code %lu",
+ GetLastError());
+ edata->backtrace = errtrace.data;
+ return;
+ }
+ backtrace_symbols_initialized = true;
+ }
+
+ nframes = CaptureStackBackTrace(num_skip, lengthof(buf), buf, NULL);
+
+ if (nframes == 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 (int i = 0; i < nframes; i++)
+ {
+ DWORD64 address = (DWORD64)buf[i];
+ DWORD64 displacement = 0;
+ BOOL sym_result;
+
+ sym_result = SymFromAddrW(backtrace_process,
+ address,
+ &displacement,
+ symbol);
+
+ if (sym_result)
+ {
+ IMAGEHLP_LINEW64 line;
+ DWORD line_displacement = 0;
+ char symbol_name[MAX_SYM_NAME];
+ size_t result;
+
+ line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
+
+ /*
+ * Convert symbol name from UTF-16 to database encoding using
+ * wchar2char(), which handles both UTF-8 and non-UTF-8 databases
+ * correctly on Windows.
+ */
+ result = wchar2char(symbol_name, (const wchar_t *) symbol->Name,
+ sizeof(symbol_name), NULL);
+
+ if (result == (size_t) -1)
+ {
+ /* Conversion failed, use address only */
+ appendStringInfo(&errtrace,
+ "\n[0x%llx]",
+ (unsigned long long) address);
+ continue;
+ }
+
+ if (SymGetLineFromAddrW64(backtrace_process,
+ address,
+ &line_displacement,
+ &line))
+ {
+ char filename[MAX_PATH];
+
+ /* Convert filename from UTF-16 to database encoding */
+ result = wchar2char(filename, (const wchar_t *) line.FileName,
+ sizeof(filename), NULL);
+
+ if (result != (size_t) -1)
+ {
+ appendStringInfo(&errtrace,
+ "\n%s+0x%llx [0x%llx] [%s:%lu]",
+ symbol_name,
+ (unsigned long long) displacement,
+ (unsigned long long) address,
+ filename,
+ (unsigned long) line.LineNumber);
+ }
+ else
+ {
+ /* Filename conversion failed, omit it */
+ appendStringInfo(&errtrace,
+ "\n%s+0x%llx [0x%llx]",
+ symbol_name,
+ (unsigned long long) displacement,
+ (unsigned long long) address);
+ }
+ }
+ else
+ {
+ /* No line info available */
+ appendStringInfo(&errtrace,
+ "\n%s+0x%llx [0x%llx]",
+ symbol_name,
+ (unsigned long long) displacement,
+ (unsigned long long) address);
+ }
+ }
+ else
+ {
+ elog(WARNING, "symbol lookup failed: error code %lu",
+ GetLastError());
+ edata->backtrace = errtrace.data;
+ }
+ }
+ }
#else
appendStringInfoString(&errtrace,
"backtrace generation is not supported by this installation");
--
2.46.0.windows.1
view thread (36+ messages) latest in thread
Message-ID: <31f43d88-9949-48c5-9497-b9a9b7cdee2b@gmail.com>
Permalink: ../31f43d88-9949-48c5-9497-b9a9b7cdee2b@gmail.com/
Also on: postgresql.org/message-id/31f43d88-9949-48c5-9497-b9a9b7cdee2b@gmail.com
reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: pgsql-hackers@postgresql.org
Cc: dbryan.green@gmail.com, euler@eulerto.com, jakub.wartak@enterprisedb.com, alvherre@kurilemu.de, michael@paquier.xyz
Subject: Re: [PATCH] Add Windows support for backtrace_functions (MSVC only)
In-Reply-To: <31f43d88-9949-48c5-9497-b9a9b7cdee2b@gmail.com>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox