[PATCH] libstdc++: detect DLLs on windows with
From: Björn Schäpers libstdc++-v3/Changelog * acinclude.m4 (GLIBCXX_ENABLE_BACKTACE): Add check for tlhelp32.h, matching libbacktrace. * configure: Regenerate. * config.h.in: Regenerate. Signed-off-by: Björn Schäpers --- libstdc++-v3/acinclude.m4 | 4 libstdc++-v3/config.h.in | 3 +++ libstdc++-v3/configure| 15 +++ 3 files changed, 22 insertions(+) diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4 index 51a08bcc8b1..506ce98ae43 100644 --- a/libstdc++-v3/acinclude.m4 +++ b/libstdc++-v3/acinclude.m4 @@ -5481,6 +5481,10 @@ AC_DEFUN([GLIBCXX_ENABLE_BACKTRACE], [ BACKTRACE_CPPFLAGS="$BACKTRACE_CPPFLAGS -DHAVE_DL_ITERATE_PHDR=1" fi AC_CHECK_HEADERS(windows.h) + AC_CHECK_HEADERS(tlhelp32.h, [], [], + [#ifdef HAVE_WINDOWS_H + # include + #endif]) # Check for the fcntl function. if test -n "${with_target_subdir}"; then diff --git a/libstdc++-v3/config.h.in b/libstdc++-v3/config.h.in index 906e0143099..486ba450749 100644 --- a/libstdc++-v3/config.h.in +++ b/libstdc++-v3/config.h.in @@ -490,6 +490,9 @@ /* Define to 1 if you have the `timespec_get' function. */ #undef HAVE_TIMESPEC_GET +/* Define to 1 if you have the header file. */ +#undef HAVE_TLHELP32_H + /* Define to 1 if the target supports thread-local storage. */ #undef HAVE_TLS diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure index 21abaeb0778..a2d59520146 100755 --- a/libstdc++-v3/configure +++ b/libstdc++-v3/configure @@ -53865,6 +53865,21 @@ _ACEOF fi +done + + for ac_header in tlhelp32.h +do : + ac_fn_c_check_header_compile "$LINENO" "tlhelp32.h" "ac_cv_header_tlhelp32_h" "#ifdef HAVE_WINDOWS_H + # include + #endif +" +if test "x$ac_cv_header_tlhelp32_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_TLHELP32_H 1 +_ACEOF + +fi + done -- 2.44.0
Re: [PATCH 5/4] libbacktrace: improve getting debug information for loaded dlls
Am 28.04.2024 um 20:16 schrieb Ian Lance Taylor: On Thu, Apr 25, 2024 at 1:15 PM Björn Schäpers wrote: Attached is the combined version of the two patches, only implementing the variant with the tlhelp32 API. Tested on x86 and x86_64 windows. Kind regards, Björn. A friendly ping. Thanks. Committed as follows. Which of your other patches are still relevant? Thanks. Ian Hi, only this one. Kind regards, Björn.From 55d0f312c0a9c4e2305d72fa2329b37937a02e44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Sch=C3=A4pers?= Date: Sat, 6 Jan 2024 22:53:54 +0100 Subject: [PATCH 2/2] libbacktrace: Add loaded dlls after initialize libbacktrace/Changelog: * pecoff.c [HAVE_WINDOWS_H]: (dll_notification_data): Added (dll_notification_context): Added (dll_notification): Added (backtrace_initialize): Use LdrRegisterDllNotification to load debug information of later loaded dlls. --- libbacktrace/pecoff.c | 106 ++ 1 file changed, 106 insertions(+) diff --git a/libbacktrace/pecoff.c b/libbacktrace/pecoff.c index faa0be0b700..455a5c2191d 100644 --- a/libbacktrace/pecoff.c +++ b/libbacktrace/pecoff.c @@ -61,6 +61,34 @@ POSSIBILITY OF SUCH DAMAGE. */ #undef Module32Next #endif #endif + +#if defined(_ARM_) +#define NTAPI +#else +#define NTAPI __stdcall +#endif + +/* This is a simplified (but binary compatible) version of what Microsoft + defines in their documentation. */ +struct dll_notifcation_data +{ + ULONG reserved; + /* The name as UNICODE_STRING struct. */ + PVOID full_dll_name; + PVOID base_dll_name; + PVOID dll_base; + ULONG size_of_image; +}; + +#define LDR_DLL_NOTIFICATION_REASON_LOADED 1 + +typedef LONG NTSTATUS; +typedef VOID CALLBACK (*LDR_DLL_NOTIFICATION)(ULONG, + struct dll_notifcation_data*, + PVOID); +typedef NTSTATUS NTAPI (*LDR_REGISTER_FUNCTION)(ULONG, + LDR_DLL_NOTIFICATION, PVOID, + PVOID*); #endif /* Coff file header. */ @@ -911,6 +939,53 @@ coff_add (struct backtrace_state *state, int descriptor, return 0; } +#ifdef HAVE_WINDOWS_H +struct dll_notification_context +{ + struct backtrace_state *state; + backtrace_error_callback error_callback; + void *data; +}; + +static VOID CALLBACK +dll_notification (ULONG reason, + struct dll_notifcation_data *notification_data, + PVOID context) +{ + char module_name[MAX_PATH]; + int descriptor; + struct dll_notification_context* dll_context = +(struct dll_notification_context*) context; + struct backtrace_state *state = dll_context->state; + void *data = dll_context->data; + backtrace_error_callback error_callback = dll_context->data; + fileline fileline; + int found_sym; + int found_dwarf; + HMODULE module_handle; + + if (reason != LDR_DLL_NOTIFICATION_REASON_LOADED) +return; + + if (!GetModuleHandleExW (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS + | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + (wchar_t*) notification_data->dll_base, + _handle)) +return; + + if (!GetModuleFileNameA ((HMODULE) module_handle, module_name, MAX_PATH - 1)) +return; + + descriptor = backtrace_open (module_name, error_callback, data, NULL); + + if (descriptor < 0) +return; + + coff_add (state, descriptor, error_callback, data, , _sym, + _dwarf, (uintptr_t) module_handle); +} +#endif + /* Initialize the backtrace data we need from an ELF executable. At the ELF level, all we need to do is find the debug info sections. */ @@ -935,6 +1010,8 @@ backtrace_initialize (struct backtrace_state *state, #endif #ifdef HAVE_WINDOWS_H + HMODULE nt_dll_handle; + module_handle = (uintptr_t) GetModuleHandle (NULL); #endif @@ -981,6 +1058,35 @@ backtrace_initialize (struct backtrace_state *state, } #endif +#ifdef HAVE_WINDOWS_H + nt_dll_handle = GetModuleHandleW (L"ntdll.dll"); + if (nt_dll_handle) +{ + LDR_REGISTER_FUNCTION register_func; + const char register_name[] = "LdrRegisterDllNotification"; + register_func = (void*) GetProcAddress (nt_dll_handle, + register_name); + + if (register_func) + { + PVOID cookie; + struct dll_notification_context *context + = backtrace_alloc (state, + sizeof(struct dll_notification_context), + error_callback, data); + + if (context) + { + context->state = state; + context->data = data; + context->error_callback = error_callback; + +
Re: [PATCH 5/4] libbacktrace: improve getting debug information for loaded dlls
Am 28.04.2024 um 20:16 schrieb Ian Lance Taylor: On Thu, Apr 25, 2024 at 1:15 PM Björn Schäpers wrote: Attached is the combined version of the two patches, only implementing the variant with the tlhelp32 API. Tested on x86 and x86_64 windows. Kind regards, Björn. A friendly ping. Thanks. Committed as follows. Which of your other patches are still relevant? Thanks. Ian Hi, only this one. Kind regards, Björn.From 55d0f312c0a9c4e2305d72fa2329b37937a02e44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Sch=C3=A4pers?= Date: Sat, 6 Jan 2024 22:53:54 +0100 Subject: [PATCH 2/2] libbacktrace: Add loaded dlls after initialize libbacktrace/Changelog: * pecoff.c [HAVE_WINDOWS_H]: (dll_notification_data): Added (dll_notification_context): Added (dll_notification): Added (backtrace_initialize): Use LdrRegisterDllNotification to load debug information of later loaded dlls. --- libbacktrace/pecoff.c | 106 ++ 1 file changed, 106 insertions(+) diff --git a/libbacktrace/pecoff.c b/libbacktrace/pecoff.c index faa0be0b700..455a5c2191d 100644 --- a/libbacktrace/pecoff.c +++ b/libbacktrace/pecoff.c @@ -61,6 +61,34 @@ POSSIBILITY OF SUCH DAMAGE. */ #undef Module32Next #endif #endif + +#if defined(_ARM_) +#define NTAPI +#else +#define NTAPI __stdcall +#endif + +/* This is a simplified (but binary compatible) version of what Microsoft + defines in their documentation. */ +struct dll_notifcation_data +{ + ULONG reserved; + /* The name as UNICODE_STRING struct. */ + PVOID full_dll_name; + PVOID base_dll_name; + PVOID dll_base; + ULONG size_of_image; +}; + +#define LDR_DLL_NOTIFICATION_REASON_LOADED 1 + +typedef LONG NTSTATUS; +typedef VOID CALLBACK (*LDR_DLL_NOTIFICATION)(ULONG, + struct dll_notifcation_data*, + PVOID); +typedef NTSTATUS NTAPI (*LDR_REGISTER_FUNCTION)(ULONG, + LDR_DLL_NOTIFICATION, PVOID, + PVOID*); #endif /* Coff file header. */ @@ -911,6 +939,53 @@ coff_add (struct backtrace_state *state, int descriptor, return 0; } +#ifdef HAVE_WINDOWS_H +struct dll_notification_context +{ + struct backtrace_state *state; + backtrace_error_callback error_callback; + void *data; +}; + +static VOID CALLBACK +dll_notification (ULONG reason, + struct dll_notifcation_data *notification_data, + PVOID context) +{ + char module_name[MAX_PATH]; + int descriptor; + struct dll_notification_context* dll_context = +(struct dll_notification_context*) context; + struct backtrace_state *state = dll_context->state; + void *data = dll_context->data; + backtrace_error_callback error_callback = dll_context->data; + fileline fileline; + int found_sym; + int found_dwarf; + HMODULE module_handle; + + if (reason != LDR_DLL_NOTIFICATION_REASON_LOADED) +return; + + if (!GetModuleHandleExW (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS + | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + (wchar_t*) notification_data->dll_base, + _handle)) +return; + + if (!GetModuleFileNameA ((HMODULE) module_handle, module_name, MAX_PATH - 1)) +return; + + descriptor = backtrace_open (module_name, error_callback, data, NULL); + + if (descriptor < 0) +return; + + coff_add (state, descriptor, error_callback, data, , _sym, + _dwarf, (uintptr_t) module_handle); +} +#endif + /* Initialize the backtrace data we need from an ELF executable. At the ELF level, all we need to do is find the debug info sections. */ @@ -935,6 +1010,8 @@ backtrace_initialize (struct backtrace_state *state, #endif #ifdef HAVE_WINDOWS_H + HMODULE nt_dll_handle; + module_handle = (uintptr_t) GetModuleHandle (NULL); #endif @@ -981,6 +1058,35 @@ backtrace_initialize (struct backtrace_state *state, } #endif +#ifdef HAVE_WINDOWS_H + nt_dll_handle = GetModuleHandleW (L"ntdll.dll"); + if (nt_dll_handle) +{ + LDR_REGISTER_FUNCTION register_func; + const char register_name[] = "LdrRegisterDllNotification"; + register_func = (void*) GetProcAddress (nt_dll_handle, + register_name); + + if (register_func) + { + PVOID cookie; + struct dll_notification_context *context + = backtrace_alloc (state, + sizeof(struct dll_notification_context), + error_callback, data); + + if (context) + { + context->state = state; + context->data = data; + context->error_callback = error_callback; + +
Re: [PATCH] Fix overwriting files with fs::copy_file on windows
Am 24.03.2024 um 22:34 schrieb Björn Schäpers: From: Björn Schäpers This fixes i.e. https://github.com/msys2/MSYS2-packages/issues/1937 I don't know if I picked the right way to do it. When acceptable I think the declaration should be moved into ops-common.h, since then we could use stat_type and also use that in the commonly used function. Manually tested on i686-w64-mingw32. -- >8 -- libstdc++: Fix overwriting files on windows The inodes have no meaning on windows, thus all files have an inode of 0. Use a differenz approach to identify equivalent files. As a result std::filesystem::copy_file did not honor copy_options::overwrite_existing. Factored the method out of std::filesystem::equivalent. libstdc++-v3/Changelog: * include/bits/fs_ops.h: Add declaration of __detail::equivalent_win32. * src/c++17/fs_ops.cc (__detail::equivalent_win32): Implement it (fs::equivalent): Use __detail::equivalent_win32, factored the old test out. * src/filesystem/ops-common.h (_GLIBCXX_FILESYSTEM_IS_WINDOWS): Use the function. Signed-off-by: Björn Schäpers --- libstdc++-v3/include/bits/fs_ops.h | 8 +++ libstdc++-v3/src/c++17/fs_ops.cc | 79 +--- libstdc++-v3/src/filesystem/ops-common.h | 10 ++- 3 files changed, 60 insertions(+), 37 deletions(-) diff --git a/libstdc++-v3/include/bits/fs_ops.h b/libstdc++-v3/include/bits/fs_ops.h index 90650c47b46..d10b78a4bdd 100644 --- a/libstdc++-v3/include/bits/fs_ops.h +++ b/libstdc++-v3/include/bits/fs_ops.h @@ -40,6 +40,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION namespace filesystem { +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS +namespace __detail +{ + bool + equivalent_win32(const wchar_t* p1, const wchar_t* p2, error_code& ec); +} // namespace __detail +#endif //_GLIBCXX_FILESYSTEM_IS_WINDOWS + /** @addtogroup filesystem * @{ */ diff --git a/libstdc++-v3/src/c++17/fs_ops.cc b/libstdc++-v3/src/c++17/fs_ops.cc index 61df19753ef..3cc87d45237 100644 --- a/libstdc++-v3/src/c++17/fs_ops.cc +++ b/libstdc++-v3/src/c++17/fs_ops.cc @@ -67,6 +67,49 @@ namespace fs = std::filesystem; namespace posix = std::filesystem::__gnu_posix; +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS +bool +fs::__detail::equivalent_win32(const wchar_t* p1, const wchar_t* p2, + error_code& ec) +{ + struct auto_handle { +explicit auto_handle(const path& p_) +: handle(CreateFileW(p_.c_str(), 0, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)) +{ } + +~auto_handle() +{ if (*this) CloseHandle(handle); } + +explicit operator bool() const +{ return handle != INVALID_HANDLE_VALUE; } + +bool get_info() +{ return GetFileInformationByHandle(handle, ); } + +HANDLE handle; +BY_HANDLE_FILE_INFORMATION info; + }; + auto_handle h1(p1); + auto_handle h2(p2); + if (!h1 || !h2) +{ + if (!h1 && !h2) + ec = __last_system_error(); + return false; +} + if (!h1.get_info() || !h2.get_info()) +{ + ec = __last_system_error(); + return false; +} + return h1.info.dwVolumeSerialNumber == h2.info.dwVolumeSerialNumber +&& h1.info.nFileIndexHigh == h2.info.nFileIndexHigh +&& h1.info.nFileIndexLow == h2.info.nFileIndexLow; +} +#endif //_GLIBCXX_FILESYSTEM_IS_WINDOWS + fs::path fs::absolute(const path& p) { @@ -858,41 +901,7 @@ fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept if (st1.st_mode != st2.st_mode || st1.st_dev != st2.st_dev) return false; - struct auto_handle { - explicit auto_handle(const path& p_) - : handle(CreateFileW(p_.c_str(), 0, - FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, - 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)) - { } - - ~auto_handle() - { if (*this) CloseHandle(handle); } - - explicit operator bool() const - { return handle != INVALID_HANDLE_VALUE; } - - bool get_info() - { return GetFileInformationByHandle(handle, ); } - - HANDLE handle; - BY_HANDLE_FILE_INFORMATION info; - }; - auto_handle h1(p1); - auto_handle h2(p2); - if (!h1 || !h2) - { - if (!h1 && !h2) - ec = __last_system_error(); - return false; - } - if (!h1.get_info() || !h2.get_info()) - { - ec = __last_system_error(); - return false; - } - return h1.info.dwVolumeSerialNumber == h2.info.dwVolumeSerialNumber - && h1.info.nFileIndexHigh == h2.info.nFileIndexHigh - && h1.info.nFileIndexLow == h2.info.nFileIndexLow; + return __detail::equivalent_win32(p1.c_str(), p2.c_str(), ec); #else return st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino; #endif diff --git a
Re: [PATCH 5/4] libbacktrace: improve getting debug information for loaded dlls
Am 15.03.2024 um 21:40 schrieb Björn Schäpers: Am 25.01.2024 um 23:04 schrieb Ian Lance Taylor: On Thu, Jan 25, 2024 at 11:53 AM Björn Schäpers wrote: Am 23.01.2024 um 23:37 schrieb Ian Lance Taylor: On Thu, Jan 4, 2024 at 2:33 PM Björn Schäpers wrote: Am 03.01.2024 um 00:12 schrieb Björn Schäpers: Am 30.11.2023 um 20:53 schrieb Ian Lance Taylor: On Fri, Jan 20, 2023 at 2:55 AM Björn Schäpers wrote: From: Björn Schäpers Fixes https://github.com/ianlancetaylor/libbacktrace/issues/53, except that libraries loaded after the backtrace_initialize are not handled. But as far as I can see that's the same for elf. Thanks, but I don't want a patch that loops using goto statements. Please rewrite to avoid that. It may be simpler to call a function. Also starting with a module count of 1000 seems like a lot. Do typical Windows programs load that many modules? Ian Rewritten using a function. If that is commited, could you attribute that commit to me (--author="Björn Schäpers ")? Thanks and kind regards, Björn. I noticed that under 64 bit libraries loaded with LoadLibrary were missing. EnumProcessModules stated the correct number of modules, but did not fill the the HMODULEs, but set them to 0. While trying to investigate I noticed if I do the very same thing from main (in C++) I even got fewer module HMODULEs. So I went a different way. This detects all libraries correctly, in 32 and 64 bit. The question is, if it should be a patch on top of the previous, or should they be merged, or even only this solution and drop the EnumProcessModules variant? Is there any reason to use both patches? Seems simpler to just use this one if it works. Thanks. Ian This one needs the tlhelp32 header and its functions, which are (accoridng to the microsoft documentation) are only available since Windows XP rsp. Windows Server 2003. If that's no problem, and in my opinion it shouldn't be, then I can basically drop patch 4 and rebase this one. I don't see that as a problem. It seems like the patch will fall back cleanly on ancient Windows and simply fail to pick up other loaded DLLs. I think that is fine. I'll look for an updated patch. Thanks. Ian Attached is the combined version of the two patches, only implementing the variant with the tlhelp32 API. Tested on x86 and x86_64 windows. Kind regards, Björn. A friendly ping.
Re: [PATCH 5/4] libbacktrace: improve getting debug information for loaded dlls
Am 15.03.2024 um 21:40 schrieb Björn Schäpers: Am 25.01.2024 um 23:04 schrieb Ian Lance Taylor: On Thu, Jan 25, 2024 at 11:53 AM Björn Schäpers wrote: Am 23.01.2024 um 23:37 schrieb Ian Lance Taylor: On Thu, Jan 4, 2024 at 2:33 PM Björn Schäpers wrote: Am 03.01.2024 um 00:12 schrieb Björn Schäpers: Am 30.11.2023 um 20:53 schrieb Ian Lance Taylor: On Fri, Jan 20, 2023 at 2:55 AM Björn Schäpers wrote: From: Björn Schäpers Fixes https://github.com/ianlancetaylor/libbacktrace/issues/53, except that libraries loaded after the backtrace_initialize are not handled. But as far as I can see that's the same for elf. Thanks, but I don't want a patch that loops using goto statements. Please rewrite to avoid that. It may be simpler to call a function. Also starting with a module count of 1000 seems like a lot. Do typical Windows programs load that many modules? Ian Rewritten using a function. If that is commited, could you attribute that commit to me (--author="Björn Schäpers ")? Thanks and kind regards, Björn. I noticed that under 64 bit libraries loaded with LoadLibrary were missing. EnumProcessModules stated the correct number of modules, but did not fill the the HMODULEs, but set them to 0. While trying to investigate I noticed if I do the very same thing from main (in C++) I even got fewer module HMODULEs. So I went a different way. This detects all libraries correctly, in 32 and 64 bit. The question is, if it should be a patch on top of the previous, or should they be merged, or even only this solution and drop the EnumProcessModules variant? Is there any reason to use both patches? Seems simpler to just use this one if it works. Thanks. Ian This one needs the tlhelp32 header and its functions, which are (accoridng to the microsoft documentation) are only available since Windows XP rsp. Windows Server 2003. If that's no problem, and in my opinion it shouldn't be, then I can basically drop patch 4 and rebase this one. I don't see that as a problem. It seems like the patch will fall back cleanly on ancient Windows and simply fail to pick up other loaded DLLs. I think that is fine. I'll look for an updated patch. Thanks. Ian Attached is the combined version of the two patches, only implementing the variant with the tlhelp32 API. Tested on x86 and x86_64 windows. Kind regards, Björn. A friendly ping.
[PATCH] Fix overwriting files with fs::copy_file on windows
From: Björn Schäpers This fixes i.e. https://github.com/msys2/MSYS2-packages/issues/1937 I don't know if I picked the right way to do it. When acceptable I think the declaration should be moved into ops-common.h, since then we could use stat_type and also use that in the commonly used function. Manually tested on i686-w64-mingw32. -- >8 -- libstdc++: Fix overwriting files on windows The inodes have no meaning on windows, thus all files have an inode of 0. Use a differenz approach to identify equivalent files. As a result std::filesystem::copy_file did not honor copy_options::overwrite_existing. Factored the method out of std::filesystem::equivalent. libstdc++-v3/Changelog: * include/bits/fs_ops.h: Add declaration of __detail::equivalent_win32. * src/c++17/fs_ops.cc (__detail::equivalent_win32): Implement it (fs::equivalent): Use __detail::equivalent_win32, factored the old test out. * src/filesystem/ops-common.h (_GLIBCXX_FILESYSTEM_IS_WINDOWS): Use the function. Signed-off-by: Björn Schäpers --- libstdc++-v3/include/bits/fs_ops.h | 8 +++ libstdc++-v3/src/c++17/fs_ops.cc | 79 +--- libstdc++-v3/src/filesystem/ops-common.h | 10 ++- 3 files changed, 60 insertions(+), 37 deletions(-) diff --git a/libstdc++-v3/include/bits/fs_ops.h b/libstdc++-v3/include/bits/fs_ops.h index 90650c47b46..d10b78a4bdd 100644 --- a/libstdc++-v3/include/bits/fs_ops.h +++ b/libstdc++-v3/include/bits/fs_ops.h @@ -40,6 +40,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION namespace filesystem { +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS +namespace __detail +{ + bool + equivalent_win32(const wchar_t* p1, const wchar_t* p2, error_code& ec); +} // namespace __detail +#endif //_GLIBCXX_FILESYSTEM_IS_WINDOWS + /** @addtogroup filesystem * @{ */ diff --git a/libstdc++-v3/src/c++17/fs_ops.cc b/libstdc++-v3/src/c++17/fs_ops.cc index 61df19753ef..3cc87d45237 100644 --- a/libstdc++-v3/src/c++17/fs_ops.cc +++ b/libstdc++-v3/src/c++17/fs_ops.cc @@ -67,6 +67,49 @@ namespace fs = std::filesystem; namespace posix = std::filesystem::__gnu_posix; +#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS +bool +fs::__detail::equivalent_win32(const wchar_t* p1, const wchar_t* p2, + error_code& ec) +{ + struct auto_handle { +explicit auto_handle(const path& p_) +: handle(CreateFileW(p_.c_str(), 0, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)) +{ } + +~auto_handle() +{ if (*this) CloseHandle(handle); } + +explicit operator bool() const +{ return handle != INVALID_HANDLE_VALUE; } + +bool get_info() +{ return GetFileInformationByHandle(handle, ); } + +HANDLE handle; +BY_HANDLE_FILE_INFORMATION info; + }; + auto_handle h1(p1); + auto_handle h2(p2); + if (!h1 || !h2) +{ + if (!h1 && !h2) + ec = __last_system_error(); + return false; +} + if (!h1.get_info() || !h2.get_info()) +{ + ec = __last_system_error(); + return false; +} + return h1.info.dwVolumeSerialNumber == h2.info.dwVolumeSerialNumber +&& h1.info.nFileIndexHigh == h2.info.nFileIndexHigh +&& h1.info.nFileIndexLow == h2.info.nFileIndexLow; +} +#endif //_GLIBCXX_FILESYSTEM_IS_WINDOWS + fs::path fs::absolute(const path& p) { @@ -858,41 +901,7 @@ fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept if (st1.st_mode != st2.st_mode || st1.st_dev != st2.st_dev) return false; - struct auto_handle { - explicit auto_handle(const path& p_) - : handle(CreateFileW(p_.c_str(), 0, - FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, - 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)) - { } - - ~auto_handle() - { if (*this) CloseHandle(handle); } - - explicit operator bool() const - { return handle != INVALID_HANDLE_VALUE; } - - bool get_info() - { return GetFileInformationByHandle(handle, ); } - - HANDLE handle; - BY_HANDLE_FILE_INFORMATION info; - }; - auto_handle h1(p1); - auto_handle h2(p2); - if (!h1 || !h2) - { - if (!h1 && !h2) - ec = __last_system_error(); - return false; - } - if (!h1.get_info() || !h2.get_info()) - { - ec = __last_system_error(); - return false; - } - return h1.info.dwVolumeSerialNumber == h2.info.dwVolumeSerialNumber - && h1.info.nFileIndexHigh == h2.info.nFileIndexHigh - && h1.info.nFileIndexLow == h2.info.nFileIndexLow; + return __detail::equivalent_win32(p1.c_str(), p2.c_str(), ec); #else return st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino; #endif diff --git a/libstdc++-v3/src/filesystem/ops-common.h b/libstdc++-v3/src/filesyst
Re: [PATCH 6/4] libbacktrace: Add loaded dlls after initialize
Am 10.01.2024 um 13:34 schrieb Eli Zaretskii: Date: Tue, 9 Jan 2024 21:02:44 +0100 Cc: i...@google.com, gcc-patc...@gcc.gnu.org, gcc@gcc.gnu.org From: Björn Schäpers Am 07.01.2024 um 18:03 schrieb Eli Zaretskii: In that case, you an call either GetModuleHandeExA or GetModuleHandeExW, the difference is minor. Here an updated version without relying on TEXT or TCHAR, directly calling GetModuleHandleExW. Thanks, this LGTM (but I couldn't test it, I just looked at the sour ce code). Here an updated version. It is rebased on the combined approach of getting the loaded DLLs and two minor changes to suppress warnings. From 55d0f312c0a9c4e2305d72fa2329b37937a02e44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Sch=C3=A4pers?= Date: Sat, 6 Jan 2024 22:53:54 +0100 Subject: [PATCH 2/2] libbacktrace: Add loaded dlls after initialize libbacktrace/Changelog: * pecoff.c [HAVE_WINDOWS_H]: (dll_notification_data): Added (dll_notification_context): Added (dll_notification): Added (backtrace_initialize): Use LdrRegisterDllNotification to load debug information of later loaded dlls. --- libbacktrace/pecoff.c | 106 ++ 1 file changed, 106 insertions(+) diff --git a/libbacktrace/pecoff.c b/libbacktrace/pecoff.c index faa0be0b700..455a5c2191d 100644 --- a/libbacktrace/pecoff.c +++ b/libbacktrace/pecoff.c @@ -61,6 +61,34 @@ POSSIBILITY OF SUCH DAMAGE. */ #undef Module32Next #endif #endif + +#if defined(_ARM_) +#define NTAPI +#else +#define NTAPI __stdcall +#endif + +/* This is a simplified (but binary compatible) version of what Microsoft + defines in their documentation. */ +struct dll_notifcation_data +{ + ULONG reserved; + /* The name as UNICODE_STRING struct. */ + PVOID full_dll_name; + PVOID base_dll_name; + PVOID dll_base; + ULONG size_of_image; +}; + +#define LDR_DLL_NOTIFICATION_REASON_LOADED 1 + +typedef LONG NTSTATUS; +typedef VOID CALLBACK (*LDR_DLL_NOTIFICATION)(ULONG, + struct dll_notifcation_data*, + PVOID); +typedef NTSTATUS NTAPI (*LDR_REGISTER_FUNCTION)(ULONG, + LDR_DLL_NOTIFICATION, PVOID, + PVOID*); #endif /* Coff file header. */ @@ -911,6 +939,53 @@ coff_add (struct backtrace_state *state, int descriptor, return 0; } +#ifdef HAVE_WINDOWS_H +struct dll_notification_context +{ + struct backtrace_state *state; + backtrace_error_callback error_callback; + void *data; +}; + +static VOID CALLBACK +dll_notification (ULONG reason, + struct dll_notifcation_data *notification_data, + PVOID context) +{ + char module_name[MAX_PATH]; + int descriptor; + struct dll_notification_context* dll_context = +(struct dll_notification_context*) context; + struct backtrace_state *state = dll_context->state; + void *data = dll_context->data; + backtrace_error_callback error_callback = dll_context->data; + fileline fileline; + int found_sym; + int found_dwarf; + HMODULE module_handle; + + if (reason != LDR_DLL_NOTIFICATION_REASON_LOADED) +return; + + if (!GetModuleHandleExW (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS + | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + (wchar_t*) notification_data->dll_base, + _handle)) +return; + + if (!GetModuleFileNameA ((HMODULE) module_handle, module_name, MAX_PATH - 1)) +return; + + descriptor = backtrace_open (module_name, error_callback, data, NULL); + + if (descriptor < 0) +return; + + coff_add (state, descriptor, error_callback, data, , _sym, + _dwarf, (uintptr_t) module_handle); +} +#endif + /* Initialize the backtrace data we need from an ELF executable. At the ELF level, all we need to do is find the debug info sections. */ @@ -935,6 +1010,8 @@ backtrace_initialize (struct backtrace_state *state, #endif #ifdef HAVE_WINDOWS_H + HMODULE nt_dll_handle; + module_handle = (uintptr_t) GetModuleHandle (NULL); #endif @@ -981,6 +1058,35 @@ backtrace_initialize (struct backtrace_state *state, } #endif +#ifdef HAVE_WINDOWS_H + nt_dll_handle = GetModuleHandleW (L"ntdll.dll"); + if (nt_dll_handle) +{ + LDR_REGISTER_FUNCTION register_func; + const char register_name[] = "LdrRegisterDllNotification"; + register_func = (void*) GetProcAddress (nt_dll_handle, + register_name); + + if (register_func) + { + PVOID cookie; + struct dll_notification_context *context + = backtrace_alloc (state, + sizeof(struct dll_notification_context), + error_callb
Re: [PATCH 6/4] libbacktrace: Add loaded dlls after initialize
Am 10.01.2024 um 13:34 schrieb Eli Zaretskii: Date: Tue, 9 Jan 2024 21:02:44 +0100 Cc: i...@google.com, gcc-patches@gcc.gnu.org, g...@gcc.gnu.org From: Björn Schäpers Am 07.01.2024 um 18:03 schrieb Eli Zaretskii: In that case, you an call either GetModuleHandeExA or GetModuleHandeExW, the difference is minor. Here an updated version without relying on TEXT or TCHAR, directly calling GetModuleHandleExW. Thanks, this LGTM (but I couldn't test it, I just looked at the sour ce code). Here an updated version. It is rebased on the combined approach of getting the loaded DLLs and two minor changes to suppress warnings. From 55d0f312c0a9c4e2305d72fa2329b37937a02e44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Sch=C3=A4pers?= Date: Sat, 6 Jan 2024 22:53:54 +0100 Subject: [PATCH 2/2] libbacktrace: Add loaded dlls after initialize libbacktrace/Changelog: * pecoff.c [HAVE_WINDOWS_H]: (dll_notification_data): Added (dll_notification_context): Added (dll_notification): Added (backtrace_initialize): Use LdrRegisterDllNotification to load debug information of later loaded dlls. --- libbacktrace/pecoff.c | 106 ++ 1 file changed, 106 insertions(+) diff --git a/libbacktrace/pecoff.c b/libbacktrace/pecoff.c index faa0be0b700..455a5c2191d 100644 --- a/libbacktrace/pecoff.c +++ b/libbacktrace/pecoff.c @@ -61,6 +61,34 @@ POSSIBILITY OF SUCH DAMAGE. */ #undef Module32Next #endif #endif + +#if defined(_ARM_) +#define NTAPI +#else +#define NTAPI __stdcall +#endif + +/* This is a simplified (but binary compatible) version of what Microsoft + defines in their documentation. */ +struct dll_notifcation_data +{ + ULONG reserved; + /* The name as UNICODE_STRING struct. */ + PVOID full_dll_name; + PVOID base_dll_name; + PVOID dll_base; + ULONG size_of_image; +}; + +#define LDR_DLL_NOTIFICATION_REASON_LOADED 1 + +typedef LONG NTSTATUS; +typedef VOID CALLBACK (*LDR_DLL_NOTIFICATION)(ULONG, + struct dll_notifcation_data*, + PVOID); +typedef NTSTATUS NTAPI (*LDR_REGISTER_FUNCTION)(ULONG, + LDR_DLL_NOTIFICATION, PVOID, + PVOID*); #endif /* Coff file header. */ @@ -911,6 +939,53 @@ coff_add (struct backtrace_state *state, int descriptor, return 0; } +#ifdef HAVE_WINDOWS_H +struct dll_notification_context +{ + struct backtrace_state *state; + backtrace_error_callback error_callback; + void *data; +}; + +static VOID CALLBACK +dll_notification (ULONG reason, + struct dll_notifcation_data *notification_data, + PVOID context) +{ + char module_name[MAX_PATH]; + int descriptor; + struct dll_notification_context* dll_context = +(struct dll_notification_context*) context; + struct backtrace_state *state = dll_context->state; + void *data = dll_context->data; + backtrace_error_callback error_callback = dll_context->data; + fileline fileline; + int found_sym; + int found_dwarf; + HMODULE module_handle; + + if (reason != LDR_DLL_NOTIFICATION_REASON_LOADED) +return; + + if (!GetModuleHandleExW (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS + | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + (wchar_t*) notification_data->dll_base, + _handle)) +return; + + if (!GetModuleFileNameA ((HMODULE) module_handle, module_name, MAX_PATH - 1)) +return; + + descriptor = backtrace_open (module_name, error_callback, data, NULL); + + if (descriptor < 0) +return; + + coff_add (state, descriptor, error_callback, data, , _sym, + _dwarf, (uintptr_t) module_handle); +} +#endif + /* Initialize the backtrace data we need from an ELF executable. At the ELF level, all we need to do is find the debug info sections. */ @@ -935,6 +1010,8 @@ backtrace_initialize (struct backtrace_state *state, #endif #ifdef HAVE_WINDOWS_H + HMODULE nt_dll_handle; + module_handle = (uintptr_t) GetModuleHandle (NULL); #endif @@ -981,6 +1058,35 @@ backtrace_initialize (struct backtrace_state *state, } #endif +#ifdef HAVE_WINDOWS_H + nt_dll_handle = GetModuleHandleW (L"ntdll.dll"); + if (nt_dll_handle) +{ + LDR_REGISTER_FUNCTION register_func; + const char register_name[] = "LdrRegisterDllNotification"; + register_func = (void*) GetProcAddress (nt_dll_handle, + register_name); + + if (register_func) + { + PVOID cookie; + struct dll_notification_context *context + = backtrace_alloc (state, + sizeof(struct dll_notification_context), + error_callb
Re: [PATCH 5/4] libbacktrace: improve getting debug information for loaded dlls
Am 25.01.2024 um 23:04 schrieb Ian Lance Taylor: On Thu, Jan 25, 2024 at 11:53 AM Björn Schäpers wrote: Am 23.01.2024 um 23:37 schrieb Ian Lance Taylor: On Thu, Jan 4, 2024 at 2:33 PM Björn Schäpers wrote: Am 03.01.2024 um 00:12 schrieb Björn Schäpers: Am 30.11.2023 um 20:53 schrieb Ian Lance Taylor: On Fri, Jan 20, 2023 at 2:55 AM Björn Schäpers wrote: From: Björn Schäpers Fixes https://github.com/ianlancetaylor/libbacktrace/issues/53, except that libraries loaded after the backtrace_initialize are not handled. But as far as I can see that's the same for elf. Thanks, but I don't want a patch that loops using goto statements. Please rewrite to avoid that. It may be simpler to call a function. Also starting with a module count of 1000 seems like a lot. Do typical Windows programs load that many modules? Ian Rewritten using a function. If that is commited, could you attribute that commit to me (--author="Björn Schäpers ")? Thanks and kind regards, Björn. I noticed that under 64 bit libraries loaded with LoadLibrary were missing. EnumProcessModules stated the correct number of modules, but did not fill the the HMODULEs, but set them to 0. While trying to investigate I noticed if I do the very same thing from main (in C++) I even got fewer module HMODULEs. So I went a different way. This detects all libraries correctly, in 32 and 64 bit. The question is, if it should be a patch on top of the previous, or should they be merged, or even only this solution and drop the EnumProcessModules variant? Is there any reason to use both patches? Seems simpler to just use this one if it works. Thanks. Ian This one needs the tlhelp32 header and its functions, which are (accoridng to the microsoft documentation) are only available since Windows XP rsp. Windows Server 2003. If that's no problem, and in my opinion it shouldn't be, then I can basically drop patch 4 and rebase this one. I don't see that as a problem. It seems like the patch will fall back cleanly on ancient Windows and simply fail to pick up other loaded DLLs. I think that is fine. I'll look for an updated patch. Thanks. Ian Attached is the combined version of the two patches, only implementing the variant with the tlhelp32 API. Tested on x86 and x86_64 windows. Kind regards, Björn.From 33a6380feff66e32ef0f0d7cbad6fb55319f4e2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Sch=C3=A4pers?= Date: Sun, 30 Apr 2023 23:54:32 +0200 Subject: [PATCH 1/2] libbacktrace: get debug information for loaded dlls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes https://github.com/ianlancetaylor/libbacktrace/issues/53, except that libraries loaded after the backtrace_initialize are not handled. But as far as I can see that's the same for elf. Tested on x86_64-linux and i686-w64-mingw32. -- >8 -- libbacktrace/Changelog: * configure.ac: Checked for tlhelp32.h * configure: Regenerate. * config.h.in: Regenerate. * pecoff.c: Include if available. (backtrace_initialize): Use tlhelp32 api for a snapshot to detect loaded modules. (coff_add): New argument for the module handle of the file, to get the base address. Signed-off-by: Björn Schäpers --- libbacktrace/config.h.in | 3 + libbacktrace/configure| 185 -- libbacktrace/configure.ac | 4 + libbacktrace/pecoff.c | 74 +-- 4 files changed, 171 insertions(+), 95 deletions(-) diff --git a/libbacktrace/config.h.in b/libbacktrace/config.h.in index ee2616335c7..9b8ab88ab63 100644 --- a/libbacktrace/config.h.in +++ b/libbacktrace/config.h.in @@ -101,6 +101,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H +/* Define to 1 if you have the header file. */ +#undef HAVE_TLHELP32_H + /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H diff --git a/libbacktrace/configure b/libbacktrace/configure index 7ade966b54d..ca52ee3bafb 100755 --- a/libbacktrace/configure +++ b/libbacktrace/configure @@ -1866,7 +1866,7 @@ else #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, -which can conflict with char $2 (); below. +which can conflict with char $2 (void); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ @@ -1884,7 +1884,7 @@ else #ifdef __cplusplus extern "C" #endif -char $2 (); +char $2 (void); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ @@ -1893,7 +1893,7 @@ choke me #endif int -main () +main (void) { return $2 (); ; @@ -1932,7 +1932,7 @@ else /* end confdefs.h. */ $4 int -main () +main (void) { if (sizeof
Re: [PATCH 5/4] libbacktrace: improve getting debug information for loaded dlls
Am 25.01.2024 um 23:04 schrieb Ian Lance Taylor: On Thu, Jan 25, 2024 at 11:53 AM Björn Schäpers wrote: Am 23.01.2024 um 23:37 schrieb Ian Lance Taylor: On Thu, Jan 4, 2024 at 2:33 PM Björn Schäpers wrote: Am 03.01.2024 um 00:12 schrieb Björn Schäpers: Am 30.11.2023 um 20:53 schrieb Ian Lance Taylor: On Fri, Jan 20, 2023 at 2:55 AM Björn Schäpers wrote: From: Björn Schäpers Fixes https://github.com/ianlancetaylor/libbacktrace/issues/53, except that libraries loaded after the backtrace_initialize are not handled. But as far as I can see that's the same for elf. Thanks, but I don't want a patch that loops using goto statements. Please rewrite to avoid that. It may be simpler to call a function. Also starting with a module count of 1000 seems like a lot. Do typical Windows programs load that many modules? Ian Rewritten using a function. If that is commited, could you attribute that commit to me (--author="Björn Schäpers ")? Thanks and kind regards, Björn. I noticed that under 64 bit libraries loaded with LoadLibrary were missing. EnumProcessModules stated the correct number of modules, but did not fill the the HMODULEs, but set them to 0. While trying to investigate I noticed if I do the very same thing from main (in C++) I even got fewer module HMODULEs. So I went a different way. This detects all libraries correctly, in 32 and 64 bit. The question is, if it should be a patch on top of the previous, or should they be merged, or even only this solution and drop the EnumProcessModules variant? Is there any reason to use both patches? Seems simpler to just use this one if it works. Thanks. Ian This one needs the tlhelp32 header and its functions, which are (accoridng to the microsoft documentation) are only available since Windows XP rsp. Windows Server 2003. If that's no problem, and in my opinion it shouldn't be, then I can basically drop patch 4 and rebase this one. I don't see that as a problem. It seems like the patch will fall back cleanly on ancient Windows and simply fail to pick up other loaded DLLs. I think that is fine. I'll look for an updated patch. Thanks. Ian Attached is the combined version of the two patches, only implementing the variant with the tlhelp32 API. Tested on x86 and x86_64 windows. Kind regards, Björn.From 33a6380feff66e32ef0f0d7cbad6fb55319f4e2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Sch=C3=A4pers?= Date: Sun, 30 Apr 2023 23:54:32 +0200 Subject: [PATCH 1/2] libbacktrace: get debug information for loaded dlls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes https://github.com/ianlancetaylor/libbacktrace/issues/53, except that libraries loaded after the backtrace_initialize are not handled. But as far as I can see that's the same for elf. Tested on x86_64-linux and i686-w64-mingw32. -- >8 -- libbacktrace/Changelog: * configure.ac: Checked for tlhelp32.h * configure: Regenerate. * config.h.in: Regenerate. * pecoff.c: Include if available. (backtrace_initialize): Use tlhelp32 api for a snapshot to detect loaded modules. (coff_add): New argument for the module handle of the file, to get the base address. Signed-off-by: Björn Schäpers --- libbacktrace/config.h.in | 3 + libbacktrace/configure| 185 -- libbacktrace/configure.ac | 4 + libbacktrace/pecoff.c | 74 +-- 4 files changed, 171 insertions(+), 95 deletions(-) diff --git a/libbacktrace/config.h.in b/libbacktrace/config.h.in index ee2616335c7..9b8ab88ab63 100644 --- a/libbacktrace/config.h.in +++ b/libbacktrace/config.h.in @@ -101,6 +101,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H +/* Define to 1 if you have the header file. */ +#undef HAVE_TLHELP32_H + /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H diff --git a/libbacktrace/configure b/libbacktrace/configure index 7ade966b54d..ca52ee3bafb 100755 --- a/libbacktrace/configure +++ b/libbacktrace/configure @@ -1866,7 +1866,7 @@ else #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, -which can conflict with char $2 (); below. +which can conflict with char $2 (void); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ @@ -1884,7 +1884,7 @@ else #ifdef __cplusplus extern "C" #endif -char $2 (); +char $2 (void); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ @@ -1893,7 +1893,7 @@ choke me #endif int -main () +main (void) { return $2 (); ; @@ -1932,7 +1932,7 @@ else /* end confdefs.h. */ $4 int -main () +main (void) { if (sizeof
Re: [PATCH 5/4] libbacktrace: improve getting debug information for loaded dlls
Am 23.01.2024 um 23:37 schrieb Ian Lance Taylor: On Thu, Jan 4, 2024 at 2:33 PM Björn Schäpers wrote: Am 03.01.2024 um 00:12 schrieb Björn Schäpers: Am 30.11.2023 um 20:53 schrieb Ian Lance Taylor: On Fri, Jan 20, 2023 at 2:55 AM Björn Schäpers wrote: From: Björn Schäpers Fixes https://github.com/ianlancetaylor/libbacktrace/issues/53, except that libraries loaded after the backtrace_initialize are not handled. But as far as I can see that's the same for elf. Thanks, but I don't want a patch that loops using goto statements. Please rewrite to avoid that. It may be simpler to call a function. Also starting with a module count of 1000 seems like a lot. Do typical Windows programs load that many modules? Ian Rewritten using a function. If that is commited, could you attribute that commit to me (--author="Björn Schäpers ")? Thanks and kind regards, Björn. I noticed that under 64 bit libraries loaded with LoadLibrary were missing. EnumProcessModules stated the correct number of modules, but did not fill the the HMODULEs, but set them to 0. While trying to investigate I noticed if I do the very same thing from main (in C++) I even got fewer module HMODULEs. So I went a different way. This detects all libraries correctly, in 32 and 64 bit. The question is, if it should be a patch on top of the previous, or should they be merged, or even only this solution and drop the EnumProcessModules variant? Is there any reason to use both patches? Seems simpler to just use this one if it works. Thanks. Ian This one needs the tlhelp32 header and its functions, which are (accoridng to the microsoft documentation) are only available since Windows XP rsp. Windows Server 2003. If that's no problem, and in my opinion it shouldn't be, then I can basically drop patch 4 and rebase this one. Kind regards, Björn.
Re: [PATCH 5/4] libbacktrace: improve getting debug information for loaded dlls
Am 23.01.2024 um 23:37 schrieb Ian Lance Taylor: On Thu, Jan 4, 2024 at 2:33 PM Björn Schäpers wrote: Am 03.01.2024 um 00:12 schrieb Björn Schäpers: Am 30.11.2023 um 20:53 schrieb Ian Lance Taylor: On Fri, Jan 20, 2023 at 2:55 AM Björn Schäpers wrote: From: Björn Schäpers Fixes https://github.com/ianlancetaylor/libbacktrace/issues/53, except that libraries loaded after the backtrace_initialize are not handled. But as far as I can see that's the same for elf. Thanks, but I don't want a patch that loops using goto statements. Please rewrite to avoid that. It may be simpler to call a function. Also starting with a module count of 1000 seems like a lot. Do typical Windows programs load that many modules? Ian Rewritten using a function. If that is commited, could you attribute that commit to me (--author="Björn Schäpers ")? Thanks and kind regards, Björn. I noticed that under 64 bit libraries loaded with LoadLibrary were missing. EnumProcessModules stated the correct number of modules, but did not fill the the HMODULEs, but set them to 0. While trying to investigate I noticed if I do the very same thing from main (in C++) I even got fewer module HMODULEs. So I went a different way. This detects all libraries correctly, in 32 and 64 bit. The question is, if it should be a patch on top of the previous, or should they be merged, or even only this solution and drop the EnumProcessModules variant? Is there any reason to use both patches? Seems simpler to just use this one if it works. Thanks. Ian This one needs the tlhelp32 header and its functions, which are (accoridng to the microsoft documentation) are only available since Windows XP rsp. Windows Server 2003. If that's no problem, and in my opinion it shouldn't be, then I can basically drop patch 4 and rebase this one. Kind regards, Björn.
Re: [PATCH 4/4] libbacktrace: get debug information for loaded dlls
Am 03.01.2024 um 00:12 schrieb Björn Schäpers: Am 30.11.2023 um 20:53 schrieb Ian Lance Taylor: On Fri, Jan 20, 2023 at 2:55 AM Björn Schäpers wrote: From: Björn Schäpers Fixes https://github.com/ianlancetaylor/libbacktrace/issues/53, except that libraries loaded after the backtrace_initialize are not handled. But as far as I can see that's the same for elf. Thanks, but I don't want a patch that loops using goto statements. Please rewrite to avoid that. It may be simpler to call a function. Also starting with a module count of 1000 seems like a lot. Do typical Windows programs load that many modules? Ian Rewritten using a function. If that is commited, could you attribute that commit to me (--author="Björn Schäpers ")? Thanks and kind regards, Björn. A friendly ping.
Re: [PATCH 4/4] libbacktrace: get debug information for loaded dlls
Am 03.01.2024 um 00:12 schrieb Björn Schäpers: Am 30.11.2023 um 20:53 schrieb Ian Lance Taylor: On Fri, Jan 20, 2023 at 2:55 AM Björn Schäpers wrote: From: Björn Schäpers Fixes https://github.com/ianlancetaylor/libbacktrace/issues/53, except that libraries loaded after the backtrace_initialize are not handled. But as far as I can see that's the same for elf. Thanks, but I don't want a patch that loops using goto statements. Please rewrite to avoid that. It may be simpler to call a function. Also starting with a module count of 1000 seems like a lot. Do typical Windows programs load that many modules? Ian Rewritten using a function. If that is commited, could you attribute that commit to me (--author="Björn Schäpers ")? Thanks and kind regards, Björn. A friendly ping.
Re: [PATCH 6/4] libbacktrace: Add loaded dlls after initialize
Am 07.01.2024 um 18:03 schrieb Eli Zaretskii: Date: Sun, 7 Jan 2024 17:07:06 +0100 Cc: i...@google.com, gcc-patc...@gcc.gnu.org, gcc@gcc.gnu.org From: Björn Schäpers That was about GetModuleHandle, not about GetModuleHandleEx. For the latter, all Windows versions that support it also support "wide" APIs. So my suggestion is to use GetModuleHandleExW here. However, you will need to make sure that notification_data->dll_base is declared as 'wchar_t *', not 'char *'. If dll_base is declared as 'char *', then only GetModuleHandleExA will work, and you will lose the ability to support file names with non-ASCII characters outside of the current system codepage. The dll_base is a PVOID. With the GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS flag GetModuleHandleEx does not look for a name, but uses an adress in the module to get the HMODULE, so you cast it to char* or wchar_t* depending on which function you call. Actually one could just cast the dll_base to HMODULE, at least in win32 on x86 the HMODULE of a dll is always its base adress. But to make it safer and future proof I went the way through GetModuleHandeEx. In that case, you an call either GetModuleHandeExA or GetModuleHandeExW, the difference is minor. Here an updated version without relying on TEXT or TCHAR, directly calling GetModuleHandleExW. Kind regards, Björn.From a8e1e64ccb56158ec8a7e5de0d5228f3f6f7e5c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Sch=C3=A4pers?= Date: Sat, 6 Jan 2024 22:53:54 +0100 Subject: [PATCH 3/3] libbacktrace: Add loaded dlls after initialize libbacktrace/Changelog: * pecoff.c [HAVE_WINDOWS_H]: (dll_notification_data): Added (dll_notification_context): Added (dll_notification): Added (backtrace_initialize): Use LdrRegisterDllNotification to load debug information of later loaded dlls. --- libbacktrace/pecoff.c | 104 +- 1 file changed, 103 insertions(+), 1 deletion(-) diff --git a/libbacktrace/pecoff.c b/libbacktrace/pecoff.c index 647baa39640..d973a26f05a 100644 --- a/libbacktrace/pecoff.c +++ b/libbacktrace/pecoff.c @@ -62,6 +62,34 @@ POSSIBILITY OF SUCH DAMAGE. */ #undef Module32Next #endif #endif + +#if defined(_ARM_) +#define NTAPI +#else +#define NTAPI __stdcall +#endif + +/* This is a simplified (but binary compatible) version of what Microsoft + defines in their documentation. */ +struct dll_notifcation_data +{ + ULONG reserved; + /* The name as UNICODE_STRING struct. */ + PVOID full_dll_name; + PVOID base_dll_name; + PVOID dll_base; + ULONG size_of_image; +}; + +#define LDR_DLL_NOTIFICATION_REASON_LOADED 1 + +typedef LONG NTSTATUS; +typedef VOID CALLBACK (*LDR_DLL_NOTIFICATION)(ULONG, + struct dll_notifcation_data*, + PVOID); +typedef NTSTATUS NTAPI (*LDR_REGISTER_FUNCTION)(ULONG, + LDR_DLL_NOTIFICATION, PVOID, + PVOID*); #endif /* Coff file header. */ @@ -912,7 +940,8 @@ coff_add (struct backtrace_state *state, int descriptor, return 0; } -#if defined(HAVE_WINDOWS_H) && !defined(HAVE_TLHELP32_H) +#ifdef HAVE_WINDOWS_H +#ifndef HAVE_TLHELP32_H static void free_modules (struct backtrace_state *state, backtrace_error_callback error_callback, void *data, @@ -958,6 +987,51 @@ get_all_modules (struct backtrace_state *state, } } #endif +struct dll_notification_context +{ + struct backtrace_state *state; + backtrace_error_callback error_callback; + void *data; +}; + +VOID CALLBACK +dll_notification (ULONG reason, +struct dll_notifcation_data *notification_data, +PVOID context) +{ + char module_name[MAX_PATH]; + int descriptor; + struct dll_notification_context* dll_context = +(struct dll_notification_context*) context; + struct backtrace_state *state = dll_context->state; + void *data = dll_context->data; + backtrace_error_callback error_callback = dll_context->data; + fileline fileline; + int found_sym; + int found_dwarf; + HMODULE module_handle; + + if (reason != LDR_DLL_NOTIFICATION_REASON_LOADED) +return; + + if (!GetModuleHandleExW (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS + | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + (wchar_t*) notification_data->dll_base, + _handle)) +return; + + if (!GetModuleFileNameA ((HMODULE) module_handle, module_name, MAX_PATH - 1)) +return; + + descriptor = backtrace_open (module_name, error_callback, data, NULL); + + if (descriptor < 0) +return; + + coff_add (state, descriptor, error_callback, data, , _sym, + _dwarf, (uintptr_t) module_handle); +} +#endif /* Initialize the backtrace data we need from an ELF executable. At
Re: [PATCH 6/4] libbacktrace: Add loaded dlls after initialize
Am 07.01.2024 um 18:03 schrieb Eli Zaretskii: Date: Sun, 7 Jan 2024 17:07:06 +0100 Cc: i...@google.com, gcc-patches@gcc.gnu.org, g...@gcc.gnu.org From: Björn Schäpers That was about GetModuleHandle, not about GetModuleHandleEx. For the latter, all Windows versions that support it also support "wide" APIs. So my suggestion is to use GetModuleHandleExW here. However, you will need to make sure that notification_data->dll_base is declared as 'wchar_t *', not 'char *'. If dll_base is declared as 'char *', then only GetModuleHandleExA will work, and you will lose the ability to support file names with non-ASCII characters outside of the current system codepage. The dll_base is a PVOID. With the GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS flag GetModuleHandleEx does not look for a name, but uses an adress in the module to get the HMODULE, so you cast it to char* or wchar_t* depending on which function you call. Actually one could just cast the dll_base to HMODULE, at least in win32 on x86 the HMODULE of a dll is always its base adress. But to make it safer and future proof I went the way through GetModuleHandeEx. In that case, you an call either GetModuleHandeExA or GetModuleHandeExW, the difference is minor. Here an updated version without relying on TEXT or TCHAR, directly calling GetModuleHandleExW. Kind regards, Björn.From a8e1e64ccb56158ec8a7e5de0d5228f3f6f7e5c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Sch=C3=A4pers?= Date: Sat, 6 Jan 2024 22:53:54 +0100 Subject: [PATCH 3/3] libbacktrace: Add loaded dlls after initialize libbacktrace/Changelog: * pecoff.c [HAVE_WINDOWS_H]: (dll_notification_data): Added (dll_notification_context): Added (dll_notification): Added (backtrace_initialize): Use LdrRegisterDllNotification to load debug information of later loaded dlls. --- libbacktrace/pecoff.c | 104 +- 1 file changed, 103 insertions(+), 1 deletion(-) diff --git a/libbacktrace/pecoff.c b/libbacktrace/pecoff.c index 647baa39640..d973a26f05a 100644 --- a/libbacktrace/pecoff.c +++ b/libbacktrace/pecoff.c @@ -62,6 +62,34 @@ POSSIBILITY OF SUCH DAMAGE. */ #undef Module32Next #endif #endif + +#if defined(_ARM_) +#define NTAPI +#else +#define NTAPI __stdcall +#endif + +/* This is a simplified (but binary compatible) version of what Microsoft + defines in their documentation. */ +struct dll_notifcation_data +{ + ULONG reserved; + /* The name as UNICODE_STRING struct. */ + PVOID full_dll_name; + PVOID base_dll_name; + PVOID dll_base; + ULONG size_of_image; +}; + +#define LDR_DLL_NOTIFICATION_REASON_LOADED 1 + +typedef LONG NTSTATUS; +typedef VOID CALLBACK (*LDR_DLL_NOTIFICATION)(ULONG, + struct dll_notifcation_data*, + PVOID); +typedef NTSTATUS NTAPI (*LDR_REGISTER_FUNCTION)(ULONG, + LDR_DLL_NOTIFICATION, PVOID, + PVOID*); #endif /* Coff file header. */ @@ -912,7 +940,8 @@ coff_add (struct backtrace_state *state, int descriptor, return 0; } -#if defined(HAVE_WINDOWS_H) && !defined(HAVE_TLHELP32_H) +#ifdef HAVE_WINDOWS_H +#ifndef HAVE_TLHELP32_H static void free_modules (struct backtrace_state *state, backtrace_error_callback error_callback, void *data, @@ -958,6 +987,51 @@ get_all_modules (struct backtrace_state *state, } } #endif +struct dll_notification_context +{ + struct backtrace_state *state; + backtrace_error_callback error_callback; + void *data; +}; + +VOID CALLBACK +dll_notification (ULONG reason, +struct dll_notifcation_data *notification_data, +PVOID context) +{ + char module_name[MAX_PATH]; + int descriptor; + struct dll_notification_context* dll_context = +(struct dll_notification_context*) context; + struct backtrace_state *state = dll_context->state; + void *data = dll_context->data; + backtrace_error_callback error_callback = dll_context->data; + fileline fileline; + int found_sym; + int found_dwarf; + HMODULE module_handle; + + if (reason != LDR_DLL_NOTIFICATION_REASON_LOADED) +return; + + if (!GetModuleHandleExW (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS + | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + (wchar_t*) notification_data->dll_base, + _handle)) +return; + + if (!GetModuleFileNameA ((HMODULE) module_handle, module_name, MAX_PATH - 1)) +return; + + descriptor = backtrace_open (module_name, error_callback, data, NULL); + + if (descriptor < 0) +return; + + coff_add (state, descriptor, error_callback, data, , _sym, + _dwarf, (uintptr_t) module_handle); +} +#endif /* Initialize the backtrace data we need from an ELF executable. At
Re: [PATCH 6/4] libbacktrace: Add loaded dlls after initialize
Am 07.01.2024 um 15:46 schrieb Eli Zaretskii: [I re-added the other addressees, as I don' think you meant to make this discussion private between the two of us.] Yeah, that was a mistake. Date: Sun, 7 Jan 2024 12:58:29 +0100 From: Björn Schäpers Am 07.01.2024 um 07:50 schrieb Eli Zaretskii: Date: Sat, 6 Jan 2024 23:15:24 +0100 From: Björn Schäpers Cc: gcc-patc...@gcc.gnu.org, gcc@gcc.gnu.org This patch adds libraries which are loaded after backtrace_initialize, like plugins or similar. I don't know what style is preferred for the Win32 typedefs, should the code use PVOID or void*? It doesn't matter, at least not if the source file includes the Windows header files (where PVOID is defined). + if (reason != /*LDR_DLL_NOTIFICATION_REASON_LOADED*/1) IMO, it would be better to supply a #define if undefined: #ifndef LDR_DLL_NOTIFICATION_REASON_LOADED # define LDR_DLL_NOTIFICATION_REASON_LOADED 1 #endif I surely can define it. But the ifndef is not needed, since there are no headers containing the function signatures, structures or the defines: https://learn.microsoft.com/en-us/windows/win32/devnotes/ldrregisterdllnotification OK, I wasn't sure about that. + if (!GetModuleHandleEx (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS + | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + (TCHAR*) notification_data->dll_base, Is TCHAR correct here? does libbacktrace indeed use TCHAR and relies on compile-time definition of UNICODE? (I'm not familiar with the internals of libbacktrace, so apologies if this is a silly question.) Thanks. As far as I can see it's the first time for TCHAR, I would've gone for GetModuleHandleExW, but https://gcc.gnu.org/pipermail/gcc/2023-January/240534.html That was about GetModuleHandle, not about GetModuleHandleEx. For the latter, all Windows versions that support it also support "wide" APIs. So my suggestion is to use GetModuleHandleExW here. However, you will need to make sure that notification_data->dll_base is declared as 'wchar_t *', not 'char *'. If dll_base is declared as 'char *', then only GetModuleHandleExA will work, and you will lose the ability to support file names with non-ASCII characters outside of the current system codepage. The dll_base is a PVOID. With the GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS flag GetModuleHandleEx does not look for a name, but uses an adress in the module to get the HMODULE, so you cast it to char* or wchar_t* depending on which function you call. Actually one could just cast the dll_base to HMODULE, at least in win32 on x86 the HMODULE of a dll is always its base adress. But to make it safer and future proof I went the way through GetModuleHandeEx. But I didn't want to force GetModuleHandleExA, so I went for TCHAR and GetModuleHandleEx so it automatically chooses which to use. Same for GetModuleHandle of ntdll.dll. The considerations for GetModuleHandle and for GetModuleHandleEx are different: the former is also available on old versions of Windows that doesn't support "wide" APIs.
Re: [PATCH 6/4] libbacktrace: Add loaded dlls after initialize
Am 07.01.2024 um 15:46 schrieb Eli Zaretskii: [I re-added the other addressees, as I don' think you meant to make this discussion private between the two of us.] Yeah, that was a mistake. Date: Sun, 7 Jan 2024 12:58:29 +0100 From: Björn Schäpers Am 07.01.2024 um 07:50 schrieb Eli Zaretskii: Date: Sat, 6 Jan 2024 23:15:24 +0100 From: Björn Schäpers Cc: gcc-patches@gcc.gnu.org, g...@gcc.gnu.org This patch adds libraries which are loaded after backtrace_initialize, like plugins or similar. I don't know what style is preferred for the Win32 typedefs, should the code use PVOID or void*? It doesn't matter, at least not if the source file includes the Windows header files (where PVOID is defined). + if (reason != /*LDR_DLL_NOTIFICATION_REASON_LOADED*/1) IMO, it would be better to supply a #define if undefined: #ifndef LDR_DLL_NOTIFICATION_REASON_LOADED # define LDR_DLL_NOTIFICATION_REASON_LOADED 1 #endif I surely can define it. But the ifndef is not needed, since there are no headers containing the function signatures, structures or the defines: https://learn.microsoft.com/en-us/windows/win32/devnotes/ldrregisterdllnotification OK, I wasn't sure about that. + if (!GetModuleHandleEx (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS + | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + (TCHAR*) notification_data->dll_base, Is TCHAR correct here? does libbacktrace indeed use TCHAR and relies on compile-time definition of UNICODE? (I'm not familiar with the internals of libbacktrace, so apologies if this is a silly question.) Thanks. As far as I can see it's the first time for TCHAR, I would've gone for GetModuleHandleExW, but https://gcc.gnu.org/pipermail/gcc/2023-January/240534.html That was about GetModuleHandle, not about GetModuleHandleEx. For the latter, all Windows versions that support it also support "wide" APIs. So my suggestion is to use GetModuleHandleExW here. However, you will need to make sure that notification_data->dll_base is declared as 'wchar_t *', not 'char *'. If dll_base is declared as 'char *', then only GetModuleHandleExA will work, and you will lose the ability to support file names with non-ASCII characters outside of the current system codepage. The dll_base is a PVOID. With the GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS flag GetModuleHandleEx does not look for a name, but uses an adress in the module to get the HMODULE, so you cast it to char* or wchar_t* depending on which function you call. Actually one could just cast the dll_base to HMODULE, at least in win32 on x86 the HMODULE of a dll is always its base adress. But to make it safer and future proof I went the way through GetModuleHandeEx. But I didn't want to force GetModuleHandleExA, so I went for TCHAR and GetModuleHandleEx so it automatically chooses which to use. Same for GetModuleHandle of ntdll.dll. The considerations for GetModuleHandle and for GetModuleHandleEx are different: the former is also available on old versions of Windows that doesn't support "wide" APIs.
Re: [PATCH 6/4] libbacktrace: Add loaded dlls after initialize
Am 04.01.2024 um 23:33 schrieb Björn Schäpers: Am 03.01.2024 um 00:12 schrieb Björn Schäpers: Am 30.11.2023 um 20:53 schrieb Ian Lance Taylor: On Fri, Jan 20, 2023 at 2:55 AM Björn Schäpers wrote: From: Björn Schäpers Fixes https://github.com/ianlancetaylor/libbacktrace/issues/53, except that libraries loaded after the backtrace_initialize are not handled. But as far as I can see that's the same for elf. Thanks, but I don't want a patch that loops using goto statements. Please rewrite to avoid that. It may be simpler to call a function. Also starting with a module count of 1000 seems like a lot. Do typical Windows programs load that many modules? Ian Rewritten using a function. If that is commited, could you attribute that commit to me (--author="Björn Schäpers ")? Thanks and kind regards, Björn. I noticed that under 64 bit libraries loaded with LoadLibrary were missing. EnumProcessModules stated the correct number of modules, but did not fill the the HMODULEs, but set them to 0. While trying to investigate I noticed if I do the very same thing from main (in C++) I even got fewer module HMODULEs. So I went a different way. This detects all libraries correctly, in 32 and 64 bit. The question is, if it should be a patch on top of the previous, or should they be merged, or even only this solution and drop the EnumProcessModules variant? Kind regards, Björn. This patch adds libraries which are loaded after backtrace_initialize, like plugins or similar. I don't know what style is preferred for the Win32 typedefs, should the code use PVOID or void*? And I'm not sure I wrapped every long line correctly. Kind regards, Björn.From 02e76e727b95dc21dc07d1fe8424b68e37e91a83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Sch=C3=A4pers?= Date: Sat, 6 Jan 2024 22:53:54 +0100 Subject: [PATCH 3/3] libbacktrace: Add loaded dlls after initialize libbacktrace/Changelog: * pecoff.c [HAVE_WINDOWS_H]: (dll_notification_data): Added (dll_notification_context): Added (dll_notification): Added (backtrace_initialize): Use LdrRegisterDllNotification to load debug information of later loaded dlls. --- libbacktrace/pecoff.c | 102 +- 1 file changed, 101 insertions(+), 1 deletion(-) diff --git a/libbacktrace/pecoff.c b/libbacktrace/pecoff.c index 647baa39640..bfe12cc2a0a 100644 --- a/libbacktrace/pecoff.c +++ b/libbacktrace/pecoff.c @@ -62,6 +62,32 @@ POSSIBILITY OF SUCH DAMAGE. */ #undef Module32Next #endif #endif + +#if defined(_ARM_) +#define NTAPI +#else +#define NTAPI __stdcall +#endif + +/* This is a simplified (but binary compatible) version of what Microsoft + defines in their documentation. */ +struct dll_notifcation_data +{ + ULONG reserved; + /* The name as UNICODE_STRING struct. */ + PVOID full_dll_name; + PVOID base_dll_name; + PVOID dll_base; + ULONG size_of_image; +}; + +typedef LONG NTSTATUS; +typedef VOID CALLBACK (*LDR_DLL_NOTIFICATION)(ULONG, + struct dll_notifcation_data*, + PVOID); +typedef NTSTATUS NTAPI (*LDR_REGISTER_FUNCTION)(ULONG, + LDR_DLL_NOTIFICATION, PVOID, + PVOID*); #endif /* Coff file header. */ @@ -912,7 +938,8 @@ coff_add (struct backtrace_state *state, int descriptor, return 0; } -#if defined(HAVE_WINDOWS_H) && !defined(HAVE_TLHELP32_H) +#ifdef HAVE_WINDOWS_H +#ifndef HAVE_TLHELP32_H static void free_modules (struct backtrace_state *state, backtrace_error_callback error_callback, void *data, @@ -958,6 +985,51 @@ get_all_modules (struct backtrace_state *state, } } #endif +struct dll_notification_context +{ + struct backtrace_state *state; + backtrace_error_callback error_callback; + void *data; +}; + +VOID CALLBACK +dll_notification (ULONG reason, +struct dll_notifcation_data *notification_data, +PVOID context) +{ + char module_name[MAX_PATH]; + int descriptor; + struct dll_notification_context* dll_context = +(struct dll_notification_context*) context; + struct backtrace_state *state = dll_context->state; + void *data = dll_context->data; + backtrace_error_callback error_callback = dll_context->data; + fileline fileline; + int found_sym; + int found_dwarf; + HMODULE module_handle; + + if (reason != /*LDR_DLL_NOTIFICATION_REASON_LOADED*/1) +return; + + if (!GetModuleHandleEx (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS + | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + (TCHAR*) notification_data->dll_base, + _handle)) +return; + + if (!GetModuleFileNameA ((HMODULE) module_handle, module_name, MAX_PATH - 1)) +return; + + descriptor
Re: [PATCH 6/4] libbacktrace: Add loaded dlls after initialize
Am 04.01.2024 um 23:33 schrieb Björn Schäpers: Am 03.01.2024 um 00:12 schrieb Björn Schäpers: Am 30.11.2023 um 20:53 schrieb Ian Lance Taylor: On Fri, Jan 20, 2023 at 2:55 AM Björn Schäpers wrote: From: Björn Schäpers Fixes https://github.com/ianlancetaylor/libbacktrace/issues/53, except that libraries loaded after the backtrace_initialize are not handled. But as far as I can see that's the same for elf. Thanks, but I don't want a patch that loops using goto statements. Please rewrite to avoid that. It may be simpler to call a function. Also starting with a module count of 1000 seems like a lot. Do typical Windows programs load that many modules? Ian Rewritten using a function. If that is commited, could you attribute that commit to me (--author="Björn Schäpers ")? Thanks and kind regards, Björn. I noticed that under 64 bit libraries loaded with LoadLibrary were missing. EnumProcessModules stated the correct number of modules, but did not fill the the HMODULEs, but set them to 0. While trying to investigate I noticed if I do the very same thing from main (in C++) I even got fewer module HMODULEs. So I went a different way. This detects all libraries correctly, in 32 and 64 bit. The question is, if it should be a patch on top of the previous, or should they be merged, or even only this solution and drop the EnumProcessModules variant? Kind regards, Björn. This patch adds libraries which are loaded after backtrace_initialize, like plugins or similar. I don't know what style is preferred for the Win32 typedefs, should the code use PVOID or void*? And I'm not sure I wrapped every long line correctly. Kind regards, Björn.From 02e76e727b95dc21dc07d1fe8424b68e37e91a83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Sch=C3=A4pers?= Date: Sat, 6 Jan 2024 22:53:54 +0100 Subject: [PATCH 3/3] libbacktrace: Add loaded dlls after initialize libbacktrace/Changelog: * pecoff.c [HAVE_WINDOWS_H]: (dll_notification_data): Added (dll_notification_context): Added (dll_notification): Added (backtrace_initialize): Use LdrRegisterDllNotification to load debug information of later loaded dlls. --- libbacktrace/pecoff.c | 102 +- 1 file changed, 101 insertions(+), 1 deletion(-) diff --git a/libbacktrace/pecoff.c b/libbacktrace/pecoff.c index 647baa39640..bfe12cc2a0a 100644 --- a/libbacktrace/pecoff.c +++ b/libbacktrace/pecoff.c @@ -62,6 +62,32 @@ POSSIBILITY OF SUCH DAMAGE. */ #undef Module32Next #endif #endif + +#if defined(_ARM_) +#define NTAPI +#else +#define NTAPI __stdcall +#endif + +/* This is a simplified (but binary compatible) version of what Microsoft + defines in their documentation. */ +struct dll_notifcation_data +{ + ULONG reserved; + /* The name as UNICODE_STRING struct. */ + PVOID full_dll_name; + PVOID base_dll_name; + PVOID dll_base; + ULONG size_of_image; +}; + +typedef LONG NTSTATUS; +typedef VOID CALLBACK (*LDR_DLL_NOTIFICATION)(ULONG, + struct dll_notifcation_data*, + PVOID); +typedef NTSTATUS NTAPI (*LDR_REGISTER_FUNCTION)(ULONG, + LDR_DLL_NOTIFICATION, PVOID, + PVOID*); #endif /* Coff file header. */ @@ -912,7 +938,8 @@ coff_add (struct backtrace_state *state, int descriptor, return 0; } -#if defined(HAVE_WINDOWS_H) && !defined(HAVE_TLHELP32_H) +#ifdef HAVE_WINDOWS_H +#ifndef HAVE_TLHELP32_H static void free_modules (struct backtrace_state *state, backtrace_error_callback error_callback, void *data, @@ -958,6 +985,51 @@ get_all_modules (struct backtrace_state *state, } } #endif +struct dll_notification_context +{ + struct backtrace_state *state; + backtrace_error_callback error_callback; + void *data; +}; + +VOID CALLBACK +dll_notification (ULONG reason, +struct dll_notifcation_data *notification_data, +PVOID context) +{ + char module_name[MAX_PATH]; + int descriptor; + struct dll_notification_context* dll_context = +(struct dll_notification_context*) context; + struct backtrace_state *state = dll_context->state; + void *data = dll_context->data; + backtrace_error_callback error_callback = dll_context->data; + fileline fileline; + int found_sym; + int found_dwarf; + HMODULE module_handle; + + if (reason != /*LDR_DLL_NOTIFICATION_REASON_LOADED*/1) +return; + + if (!GetModuleHandleEx (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS + | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + (TCHAR*) notification_data->dll_base, + _handle)) +return; + + if (!GetModuleFileNameA ((HMODULE) module_handle, module_name, MAX_PATH - 1)) +return; + + descriptor
[PATCH 5/4] libbacktrace: improve getting debug information for loaded dlls
Am 03.01.2024 um 00:12 schrieb Björn Schäpers: Am 30.11.2023 um 20:53 schrieb Ian Lance Taylor: On Fri, Jan 20, 2023 at 2:55 AM Björn Schäpers wrote: From: Björn Schäpers Fixes https://github.com/ianlancetaylor/libbacktrace/issues/53, except that libraries loaded after the backtrace_initialize are not handled. But as far as I can see that's the same for elf. Thanks, but I don't want a patch that loops using goto statements. Please rewrite to avoid that. It may be simpler to call a function. Also starting with a module count of 1000 seems like a lot. Do typical Windows programs load that many modules? Ian Rewritten using a function. If that is commited, could you attribute that commit to me (--author="Björn Schäpers ")? Thanks and kind regards, Björn. I noticed that under 64 bit libraries loaded with LoadLibrary were missing. EnumProcessModules stated the correct number of modules, but did not fill the the HMODULEs, but set them to 0. While trying to investigate I noticed if I do the very same thing from main (in C++) I even got fewer module HMODULEs. So I went a different way. This detects all libraries correctly, in 32 and 64 bit. The question is, if it should be a patch on top of the previous, or should they be merged, or even only this solution and drop the EnumProcessModules variant? Kind regards, Björn. From 784e01f1baf92c23c819aeb9e77010412023700f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Sch=C3=A4pers?= Date: Thu, 4 Jan 2024 22:02:03 +0100 Subject: [PATCH 2/2] libbacktrace: improve getting debug information for loaded dlls EnumProcessModules does not always result in all modules loaded, especially those that are loaded with LoadLibrary. libbacktrace/Changelog: * configure.ac: Checked for tlhelp32.h * configure: Regenerate. * config.h.in: Regenerate. * pecoff.c: Include if available. (backtrace_initialize): Use tlhelp32 api for a snapshot to detect loaded modules. --- libbacktrace/config.h.in | 3 + libbacktrace/configure| 185 -- libbacktrace/configure.ac | 4 + libbacktrace/pecoff.c | 62 - 4 files changed, 164 insertions(+), 90 deletions(-) diff --git a/libbacktrace/config.h.in b/libbacktrace/config.h.in index ee2616335c7..9b8ab88ab63 100644 --- a/libbacktrace/config.h.in +++ b/libbacktrace/config.h.in @@ -101,6 +101,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H +/* Define to 1 if you have the header file. */ +#undef HAVE_TLHELP32_H + /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H diff --git a/libbacktrace/configure b/libbacktrace/configure index 7ade966b54d..ca52ee3bafb 100755 --- a/libbacktrace/configure +++ b/libbacktrace/configure @@ -1866,7 +1866,7 @@ else #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, -which can conflict with char $2 (); below. +which can conflict with char $2 (void); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ @@ -1884,7 +1884,7 @@ else #ifdef __cplusplus extern "C" #endif -char $2 (); +char $2 (void); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ @@ -1893,7 +1893,7 @@ choke me #endif int -main () +main (void) { return $2 (); ; @@ -1932,7 +1932,7 @@ else /* end confdefs.h. */ $4 int -main () +main (void) { if (sizeof ($2)) return 0; @@ -1945,7 +1945,7 @@ if ac_fn_c_try_compile "$LINENO"; then : /* end confdefs.h. */ $4 int -main () +main (void) { if (sizeof (($2))) return 0; @@ -1983,7 +1983,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) >= 0)]; test_array [0] = 0; @@ -2000,7 +2000,7 @@ if ac_fn_c_try_compile "$LINENO"; then : /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; @@ -2027,7 +2027,7 @@ else /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) < 0)]; test_array [0] = 0; @@ -2044,7 +2044,7 @@ if ac_fn_c_try_compile "$LINENO"; then : /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) >= $ac_mid)]; test_array [0] = 0; @@ -2079,7 +2079,7 @@ while test "x$ac_lo" != "x$ac_hi"; do /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; @@ -2104,12 +2104,12 @@ esac cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 -static long int
[PATCH 5/4] libbacktrace: improve getting debug information for loaded dlls
Am 03.01.2024 um 00:12 schrieb Björn Schäpers: Am 30.11.2023 um 20:53 schrieb Ian Lance Taylor: On Fri, Jan 20, 2023 at 2:55 AM Björn Schäpers wrote: From: Björn Schäpers Fixes https://github.com/ianlancetaylor/libbacktrace/issues/53, except that libraries loaded after the backtrace_initialize are not handled. But as far as I can see that's the same for elf. Thanks, but I don't want a patch that loops using goto statements. Please rewrite to avoid that. It may be simpler to call a function. Also starting with a module count of 1000 seems like a lot. Do typical Windows programs load that many modules? Ian Rewritten using a function. If that is commited, could you attribute that commit to me (--author="Björn Schäpers ")? Thanks and kind regards, Björn. I noticed that under 64 bit libraries loaded with LoadLibrary were missing. EnumProcessModules stated the correct number of modules, but did not fill the the HMODULEs, but set them to 0. While trying to investigate I noticed if I do the very same thing from main (in C++) I even got fewer module HMODULEs. So I went a different way. This detects all libraries correctly, in 32 and 64 bit. The question is, if it should be a patch on top of the previous, or should they be merged, or even only this solution and drop the EnumProcessModules variant? Kind regards, Björn. From 784e01f1baf92c23c819aeb9e77010412023700f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Sch=C3=A4pers?= Date: Thu, 4 Jan 2024 22:02:03 +0100 Subject: [PATCH 2/2] libbacktrace: improve getting debug information for loaded dlls EnumProcessModules does not always result in all modules loaded, especially those that are loaded with LoadLibrary. libbacktrace/Changelog: * configure.ac: Checked for tlhelp32.h * configure: Regenerate. * config.h.in: Regenerate. * pecoff.c: Include if available. (backtrace_initialize): Use tlhelp32 api for a snapshot to detect loaded modules. --- libbacktrace/config.h.in | 3 + libbacktrace/configure| 185 -- libbacktrace/configure.ac | 4 + libbacktrace/pecoff.c | 62 - 4 files changed, 164 insertions(+), 90 deletions(-) diff --git a/libbacktrace/config.h.in b/libbacktrace/config.h.in index ee2616335c7..9b8ab88ab63 100644 --- a/libbacktrace/config.h.in +++ b/libbacktrace/config.h.in @@ -101,6 +101,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H +/* Define to 1 if you have the header file. */ +#undef HAVE_TLHELP32_H + /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H diff --git a/libbacktrace/configure b/libbacktrace/configure index 7ade966b54d..ca52ee3bafb 100755 --- a/libbacktrace/configure +++ b/libbacktrace/configure @@ -1866,7 +1866,7 @@ else #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, -which can conflict with char $2 (); below. +which can conflict with char $2 (void); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ @@ -1884,7 +1884,7 @@ else #ifdef __cplusplus extern "C" #endif -char $2 (); +char $2 (void); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ @@ -1893,7 +1893,7 @@ choke me #endif int -main () +main (void) { return $2 (); ; @@ -1932,7 +1932,7 @@ else /* end confdefs.h. */ $4 int -main () +main (void) { if (sizeof ($2)) return 0; @@ -1945,7 +1945,7 @@ if ac_fn_c_try_compile "$LINENO"; then : /* end confdefs.h. */ $4 int -main () +main (void) { if (sizeof (($2))) return 0; @@ -1983,7 +1983,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) >= 0)]; test_array [0] = 0; @@ -2000,7 +2000,7 @@ if ac_fn_c_try_compile "$LINENO"; then : /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; @@ -2027,7 +2027,7 @@ else /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) < 0)]; test_array [0] = 0; @@ -2044,7 +2044,7 @@ if ac_fn_c_try_compile "$LINENO"; then : /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) >= $ac_mid)]; test_array [0] = 0; @@ -2079,7 +2079,7 @@ while test "x$ac_lo" != "x$ac_hi"; do /* end confdefs.h. */ $4 int -main () +main (void) { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; @@ -2104,12 +2104,12 @@ esac cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 -static long int
Re: [PATCH 4/4] libbacktrace: get debug information for loaded dlls
Am 30.11.2023 um 20:53 schrieb Ian Lance Taylor: On Fri, Jan 20, 2023 at 2:55 AM Björn Schäpers wrote: From: Björn Schäpers Fixes https://github.com/ianlancetaylor/libbacktrace/issues/53, except that libraries loaded after the backtrace_initialize are not handled. But as far as I can see that's the same for elf. Thanks, but I don't want a patch that loops using goto statements. Please rewrite to avoid that. It may be simpler to call a function. Also starting with a module count of 1000 seems like a lot. Do typical Windows programs load that many modules? Ian Rewritten using a function. If that is commited, could you attribute that commit to me (--author="Björn Schäpers ")? Thanks and kind regards, Björn. From bd552716ee7937cad9d54d4966532d6ea6dbc1bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Sch=C3=A4pers?= Date: Sun, 30 Apr 2023 23:54:32 +0200 Subject: [PATCH] libbacktrace: get debug information for loaded dlls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes https://github.com/ianlancetaylor/libbacktrace/issues/53, except that libraries loaded after the backtrace_initialize are not handled. But as far as I can see that's the same for elf. Tested on x86_64-linux and i686-w64-mingw32. -- >8 -- * pecoff.c (coff_add): New argument for the module handle of the file, to get the base address. * pecoff.c (backtrace_initialize): Iterate over loaded libraries and call coff_add. Signed-off-by: Björn Schäpers --- libbacktrace/pecoff.c | 104 ++ 1 file changed, 96 insertions(+), 8 deletions(-) diff --git a/libbacktrace/pecoff.c b/libbacktrace/pecoff.c index f976a963bf3..3eb9c4a4853 100644 --- a/libbacktrace/pecoff.c +++ b/libbacktrace/pecoff.c @@ -49,6 +49,7 @@ POSSIBILITY OF SUCH DAMAGE. */ #endif #include +#include #endif /* Coff file header. */ @@ -592,7 +593,8 @@ coff_syminfo (struct backtrace_state *state, uintptr_t addr, static int coff_add (struct backtrace_state *state, int descriptor, backtrace_error_callback error_callback, void *data, - fileline *fileline_fn, int *found_sym, int *found_dwarf) + fileline *fileline_fn, int *found_sym, int *found_dwarf, + uintptr_t module_handle ATTRIBUTE_UNUSED) { struct backtrace_view fhdr_view; off_t fhdr_off; @@ -870,12 +872,7 @@ coff_add (struct backtrace_state *state, int descriptor, } #ifdef HAVE_WINDOWS_H - { -uintptr_t module_handle; - -module_handle = (uintptr_t) GetModuleHandle (NULL); -base_address = module_handle - image_base; - } + base_address = module_handle - image_base; #endif if (!backtrace_dwarf_add (state, base_address, _sections, @@ -903,6 +900,53 @@ coff_add (struct backtrace_state *state, int descriptor, return 0; } +#ifdef HAVE_WINDOWS_H +static void +free_modules (struct backtrace_state *state, + backtrace_error_callback error_callback, void *data, + HMODULE **modules, DWORD bytes_allocated) +{ + backtrace_free (state, *modules, bytes_allocated, error_callback, data); + *modules = NULL; +} + +static void +get_all_modules (struct backtrace_state *state, +backtrace_error_callback error_callback, void *data, +HMODULE **modules, DWORD *module_count, DWORD *bytes_allocated) +{ + DWORD bytes_needed = 0; + + for (;;) +{ + *bytes_allocated = *module_count * sizeof(HMODULE); + *modules = backtrace_alloc (state, *bytes_allocated, error_callback, data); + + if (*modules == NULL) + return; + + if (!EnumProcessModules (GetCurrentProcess (), *modules, *module_count, + _needed)) + { + error_callback(data, "Could not enumerate process modules", +(int) GetLastError ()); + free_modules (state, error_callback, data, modules, *bytes_allocated); + return; + } + + *module_count = bytes_needed / sizeof(HMODULE); + if (bytes_needed <= *bytes_allocated) + { + return; + } + + free_modules (state, error_callback, data, modules, *bytes_allocated); + // Add an extra of 2, of some module is loaded in another thread. + *module_count += 2; +} +} +#endif + /* Initialize the backtrace data we need from an ELF executable. At the ELF level, all we need to do is find the debug info sections. */ @@ -917,12 +961,56 @@ backtrace_initialize (struct backtrace_state *state, int found_sym; int found_dwarf; fileline coff_fileline_fn; + uintptr_t module_handle = 0; + +#ifdef HAVE_WINDOWS_H + DWORD i; + DWORD module_count = 100; + DWORD bytes_allocated_for_modules = 0; + HMODULE *modules = NULL; + char module_name[MAX_PATH]; + int module_found_sym; + fileline module_fileline_fn; + + module_handle = (uintptr_t) GetModuleHandle (NULL); +#endif ret = coff_add (state,
Re: [PATCH 4/4] libbacktrace: get debug information for loaded dlls
Am 30.11.2023 um 20:53 schrieb Ian Lance Taylor: On Fri, Jan 20, 2023 at 2:55 AM Björn Schäpers wrote: From: Björn Schäpers Fixes https://github.com/ianlancetaylor/libbacktrace/issues/53, except that libraries loaded after the backtrace_initialize are not handled. But as far as I can see that's the same for elf. Thanks, but I don't want a patch that loops using goto statements. Please rewrite to avoid that. It may be simpler to call a function. Also starting with a module count of 1000 seems like a lot. Do typical Windows programs load that many modules? Ian Rewritten using a function. If that is commited, could you attribute that commit to me (--author="Björn Schäpers ")? Thanks and kind regards, Björn. From bd552716ee7937cad9d54d4966532d6ea6dbc1bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Sch=C3=A4pers?= Date: Sun, 30 Apr 2023 23:54:32 +0200 Subject: [PATCH] libbacktrace: get debug information for loaded dlls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes https://github.com/ianlancetaylor/libbacktrace/issues/53, except that libraries loaded after the backtrace_initialize are not handled. But as far as I can see that's the same for elf. Tested on x86_64-linux and i686-w64-mingw32. -- >8 -- * pecoff.c (coff_add): New argument for the module handle of the file, to get the base address. * pecoff.c (backtrace_initialize): Iterate over loaded libraries and call coff_add. Signed-off-by: Björn Schäpers --- libbacktrace/pecoff.c | 104 ++ 1 file changed, 96 insertions(+), 8 deletions(-) diff --git a/libbacktrace/pecoff.c b/libbacktrace/pecoff.c index f976a963bf3..3eb9c4a4853 100644 --- a/libbacktrace/pecoff.c +++ b/libbacktrace/pecoff.c @@ -49,6 +49,7 @@ POSSIBILITY OF SUCH DAMAGE. */ #endif #include +#include #endif /* Coff file header. */ @@ -592,7 +593,8 @@ coff_syminfo (struct backtrace_state *state, uintptr_t addr, static int coff_add (struct backtrace_state *state, int descriptor, backtrace_error_callback error_callback, void *data, - fileline *fileline_fn, int *found_sym, int *found_dwarf) + fileline *fileline_fn, int *found_sym, int *found_dwarf, + uintptr_t module_handle ATTRIBUTE_UNUSED) { struct backtrace_view fhdr_view; off_t fhdr_off; @@ -870,12 +872,7 @@ coff_add (struct backtrace_state *state, int descriptor, } #ifdef HAVE_WINDOWS_H - { -uintptr_t module_handle; - -module_handle = (uintptr_t) GetModuleHandle (NULL); -base_address = module_handle - image_base; - } + base_address = module_handle - image_base; #endif if (!backtrace_dwarf_add (state, base_address, _sections, @@ -903,6 +900,53 @@ coff_add (struct backtrace_state *state, int descriptor, return 0; } +#ifdef HAVE_WINDOWS_H +static void +free_modules (struct backtrace_state *state, + backtrace_error_callback error_callback, void *data, + HMODULE **modules, DWORD bytes_allocated) +{ + backtrace_free (state, *modules, bytes_allocated, error_callback, data); + *modules = NULL; +} + +static void +get_all_modules (struct backtrace_state *state, +backtrace_error_callback error_callback, void *data, +HMODULE **modules, DWORD *module_count, DWORD *bytes_allocated) +{ + DWORD bytes_needed = 0; + + for (;;) +{ + *bytes_allocated = *module_count * sizeof(HMODULE); + *modules = backtrace_alloc (state, *bytes_allocated, error_callback, data); + + if (*modules == NULL) + return; + + if (!EnumProcessModules (GetCurrentProcess (), *modules, *module_count, + _needed)) + { + error_callback(data, "Could not enumerate process modules", +(int) GetLastError ()); + free_modules (state, error_callback, data, modules, *bytes_allocated); + return; + } + + *module_count = bytes_needed / sizeof(HMODULE); + if (bytes_needed <= *bytes_allocated) + { + return; + } + + free_modules (state, error_callback, data, modules, *bytes_allocated); + // Add an extra of 2, of some module is loaded in another thread. + *module_count += 2; +} +} +#endif + /* Initialize the backtrace data we need from an ELF executable. At the ELF level, all we need to do is find the debug info sections. */ @@ -917,12 +961,56 @@ backtrace_initialize (struct backtrace_state *state, int found_sym; int found_dwarf; fileline coff_fileline_fn; + uintptr_t module_handle = 0; + +#ifdef HAVE_WINDOWS_H + DWORD i; + DWORD module_count = 100; + DWORD bytes_allocated_for_modules = 0; + HMODULE *modules = NULL; + char module_name[MAX_PATH]; + int module_found_sym; + fileline module_fileline_fn; + + module_handle = (uintptr_t) GetModuleHandle (NULL); +#endif ret = coff_add (state,
Re: [PATCH 3/4] libbacktrace: work with aslr on windows
I'll guess it is not needed here, but otherwise defines the macros max and min, they then conflict e.g. with C++'s std::max/std::min. So I consider it best practice to always define it, before including . Am 20.11.2023 um 21:07 schrieb Eli Zaretskii: Date: Mon, 20 Nov 2023 20:57:38 +0100 Cc: gcc-patc...@gcc.gnu.org, gcc@gcc.gnu.org From: Björn Schäpers +#ifndef NOMINMAX +#define NOMINMAX +#endif Why is this part needed? Otherwise, LGTM, thanks. (But I'm don't have the approval rights, so please wait for Ian to chime in.)
Re: [PATCH 3/4] libbacktrace: work with aslr on windows
I'll guess it is not needed here, but otherwise defines the macros max and min, they then conflict e.g. with C++'s std::max/std::min. So I consider it best practice to always define it, before including . Am 20.11.2023 um 21:07 schrieb Eli Zaretskii: Date: Mon, 20 Nov 2023 20:57:38 +0100 Cc: gcc-patches@gcc.gnu.org, g...@gcc.gnu.org From: Björn Schäpers +#ifndef NOMINMAX +#define NOMINMAX +#endif Why is this part needed? Otherwise, LGTM, thanks. (But I'm don't have the approval rights, so please wait for Ian to chime in.)
Re: [PATCH 3/4] libbacktrace: work with aslr on windows
An updated version, using neither A or W, but just the macro. Am 21.01.2023 um 12:42 schrieb Eli Zaretskii: Date: Sat, 21 Jan 2023 11:47:42 +0100 Cc: g...@hazardy.de, gcc-patc...@gcc.gnu.org, gcc@gcc.gnu.org From: Gabriel Ravier On 1/21/23 05:05, Eli Zaretskii wrote: Date: Fri, 20 Jan 2023 21:39:56 +0100 Cc: g...@hazardy.de, gcc-patc...@gcc.gnu.org, gcc@gcc.gnu.org From: Gabriel Ravier - using wide APIs with Windows is generally considered to be a best practice, even when not strictly needed (and in this case I can't see any problem with doing so, unless maybe we want to code to work with Windows 95 or something like that...) There's no reason to forcibly break GDB on platforms where wide APIs are not available. Are there even any platforms that have GetModuleHandleA but not GetModuleHandleW ? MSDN states that Windows XP and Windows Server 2003 are the first versions to support both of the APIs, so if this is supposed to work on Windows 98, for instance, whether we're using GetModuleHandleA or GetModuleHandleW won't matter. I'm not sure I follow the logic. A program that calls GetModuleHandleW will refuse to start on Windows that doesn't have that API. So any version before XP is automatically excluded the moment you use code which calls that API directly (i.e. not through a function pointer or somesuch). A program that calls GetModuleHandleA will also refuse to start on Windows if it doesn't have that API. The set of Windows versions that do not have GetModuleHandleA is, according to MSDN, the same as the set of Windows versions that do not have GetModuleHandleW. MSDN lies (because it wants to pretend that older versions don't exist). Try this much more useful site: http://winapi.freetechsecrets.com/win32/WIN32GetModuleHandle.htm From 52cbe06b1c165172191f66ff7e55a49adecf661d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Sch=C3=A4pers?= Date: Sun, 30 Apr 2023 23:52:37 +0200 Subject: [PATCH 2/3] libbacktrace: work with aslr on windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Any underflow which might happen, will be countered by an overflow in dwarf.c. Tested on x86_64-linux and i686-w64-mingw32. -- >8 -- Fixes https://github.com/ianlancetaylor/libbacktrace/issues/89 and https://github.com/ianlancetaylor/libbacktrace/issues/82. * pecoff.c (coff_add): Set the base_address of the module, to find the debug information on moved applications. Signed-off-by: Björn Schäpers --- libbacktrace/pecoff.c | 21 - 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/libbacktrace/pecoff.c b/libbacktrace/pecoff.c index 56af4828e27..9cc13b47947 100644 --- a/libbacktrace/pecoff.c +++ b/libbacktrace/pecoff.c @@ -39,6 +39,18 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "backtrace.h" #include "internal.h" +#ifdef HAVE_WINDOWS_H +#ifndef WIN32_MEAN_AND_LEAN +#define WIN32_MEAN_AND_LEAN +#endif + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#include +#endif + /* Coff file header. */ typedef struct { @@ -610,6 +622,8 @@ coff_add (struct backtrace_state *state, int descriptor, int debug_view_valid; int is_64; uintptr_t image_base; + uintptr_t base_address = 0; + uintptr_t module_handle; struct dwarf_sections dwarf_sections; *found_sym = 0; @@ -856,7 +870,12 @@ coff_add (struct backtrace_state *state, int descriptor, + (sections[i].offset - min_offset)); } - if (!backtrace_dwarf_add (state, /* base_address */ 0, _sections, +#ifdef HAVE_WINDOWS_H +module_handle = (uintptr_t) GetModuleHandle (NULL); +base_address = module_handle - image_base; +#endif + + if (!backtrace_dwarf_add (state, base_address, _sections, 0, /* FIXME: is_bigendian */ NULL, /* altlink */ error_callback, data, fileline_fn, -- 2.42.1
Re: [PATCH 3/4] libbacktrace: work with aslr on windows
An updated version, using neither A or W, but just the macro. Am 21.01.2023 um 12:42 schrieb Eli Zaretskii: Date: Sat, 21 Jan 2023 11:47:42 +0100 Cc: g...@hazardy.de, gcc-patches@gcc.gnu.org, g...@gcc.gnu.org From: Gabriel Ravier On 1/21/23 05:05, Eli Zaretskii wrote: Date: Fri, 20 Jan 2023 21:39:56 +0100 Cc: g...@hazardy.de, gcc-patches@gcc.gnu.org, g...@gcc.gnu.org From: Gabriel Ravier - using wide APIs with Windows is generally considered to be a best practice, even when not strictly needed (and in this case I can't see any problem with doing so, unless maybe we want to code to work with Windows 95 or something like that...) There's no reason to forcibly break GDB on platforms where wide APIs are not available. Are there even any platforms that have GetModuleHandleA but not GetModuleHandleW ? MSDN states that Windows XP and Windows Server 2003 are the first versions to support both of the APIs, so if this is supposed to work on Windows 98, for instance, whether we're using GetModuleHandleA or GetModuleHandleW won't matter. I'm not sure I follow the logic. A program that calls GetModuleHandleW will refuse to start on Windows that doesn't have that API. So any version before XP is automatically excluded the moment you use code which calls that API directly (i.e. not through a function pointer or somesuch). A program that calls GetModuleHandleA will also refuse to start on Windows if it doesn't have that API. The set of Windows versions that do not have GetModuleHandleA is, according to MSDN, the same as the set of Windows versions that do not have GetModuleHandleW. MSDN lies (because it wants to pretend that older versions don't exist). Try this much more useful site: http://winapi.freetechsecrets.com/win32/WIN32GetModuleHandle.htm From 52cbe06b1c165172191f66ff7e55a49adecf661d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Sch=C3=A4pers?= Date: Sun, 30 Apr 2023 23:52:37 +0200 Subject: [PATCH 2/3] libbacktrace: work with aslr on windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Any underflow which might happen, will be countered by an overflow in dwarf.c. Tested on x86_64-linux and i686-w64-mingw32. -- >8 -- Fixes https://github.com/ianlancetaylor/libbacktrace/issues/89 and https://github.com/ianlancetaylor/libbacktrace/issues/82. * pecoff.c (coff_add): Set the base_address of the module, to find the debug information on moved applications. Signed-off-by: Björn Schäpers --- libbacktrace/pecoff.c | 21 - 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/libbacktrace/pecoff.c b/libbacktrace/pecoff.c index 56af4828e27..9cc13b47947 100644 --- a/libbacktrace/pecoff.c +++ b/libbacktrace/pecoff.c @@ -39,6 +39,18 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "backtrace.h" #include "internal.h" +#ifdef HAVE_WINDOWS_H +#ifndef WIN32_MEAN_AND_LEAN +#define WIN32_MEAN_AND_LEAN +#endif + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#include +#endif + /* Coff file header. */ typedef struct { @@ -610,6 +622,8 @@ coff_add (struct backtrace_state *state, int descriptor, int debug_view_valid; int is_64; uintptr_t image_base; + uintptr_t base_address = 0; + uintptr_t module_handle; struct dwarf_sections dwarf_sections; *found_sym = 0; @@ -856,7 +870,12 @@ coff_add (struct backtrace_state *state, int descriptor, + (sections[i].offset - min_offset)); } - if (!backtrace_dwarf_add (state, /* base_address */ 0, _sections, +#ifdef HAVE_WINDOWS_H +module_handle = (uintptr_t) GetModuleHandle (NULL); +base_address = module_handle - image_base; +#endif + + if (!backtrace_dwarf_add (state, base_address, _sections, 0, /* FIXME: is_bigendian */ NULL, /* altlink */ error_callback, data, fileline_fn, -- 2.42.1
Re: [PATCH 2/4] libbacktrace: detect executable path on windows
Hi, this is what I'm using with GCC 12 and 13 on my windows machines, rebased onto the current HEAD. Kind regards, Björn. Am 06.02.2023 um 01:22 schrieb Ian Lance Taylor: On Sun, Feb 5, 2023 at 1:21 AM Björn Schäpers wrote: Am 24.01.2023 um 19:32 schrieb Ian Lance Taylor: On Tue, Jan 24, 2023 at 10:12 AM Eli Zaretskii via Gcc-patches wrote: From: Ian Lance Taylor Date: Tue, 24 Jan 2023 09:58:10 -0800 Cc: g...@hazardy.de, gcc-patc...@gcc.gnu.org, gcc@gcc.gnu.org I'd rather that the patch look like the appended. Can someone with a Windows system test to see what that builds and passes the tests? ENOPATCH Gah. Ian That seems to be my original patch, right? That one I have tested (and am actually using) on x86 and x64 windows. It's very similar but I changed the windows_get_executable_path function. Ian From e0ee58b71f726606205aa1f0168a724859162c21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Sch=C3=A4pers?= Date: Sun, 30 Apr 2023 23:48:18 +0200 Subject: [PATCH 1/3] libbacktrace: detect executable path on windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tested on x86_64-linux with GCC 12, i686-w64-mingw32 and x86_64-w64-mingw32 with GCC 12 & 13. This patch is rebased onto the current HEAD. -- >8 -- * configure.ac: Add a check for windows.h. * configure, config.h.in: Regenerate. * fileline.c: Add windows_get_executable_path. * fileline.c (fileline_initialize): Add a pass using windows_get_executable_path. Signed-off-by: Björn Schäpers --- libbacktrace/config.h.in | 3 +++ libbacktrace/configure| 13 +++ libbacktrace/configure.ac | 2 ++ libbacktrace/fileline.c | 49 ++- 4 files changed, 66 insertions(+), 1 deletion(-) diff --git a/libbacktrace/config.h.in b/libbacktrace/config.h.in index a4f5bf6..ee2616335c7 100644 --- a/libbacktrace/config.h.in +++ b/libbacktrace/config.h.in @@ -104,6 +104,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H +/* Define to 1 if you have the header file. */ +#undef HAVE_WINDOWS_H + /* Define if -lz is available. */ #undef HAVE_ZLIB diff --git a/libbacktrace/configure b/libbacktrace/configure index 0ccc060901d..7ade966b54d 100755 --- a/libbacktrace/configure +++ b/libbacktrace/configure @@ -13509,6 +13509,19 @@ $as_echo "#define HAVE_LOADQUERY 1" >>confdefs.h fi +for ac_header in windows.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "windows.h" "ac_cv_header_windows_h" "$ac_includes_default" +if test "x$ac_cv_header_windows_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_WINDOWS_H 1 +_ACEOF + +fi + +done + + # Check for the fcntl function. if test -n "${with_target_subdir}"; then case "${host}" in diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac index 71cd50f8cdf..00acb42eb6d 100644 --- a/libbacktrace/configure.ac +++ b/libbacktrace/configure.ac @@ -379,6 +379,8 @@ if test "$have_loadquery" = "yes"; then AC_DEFINE(HAVE_LOADQUERY, 1, [Define if AIX loadquery is available.]) fi +AC_CHECK_HEADERS(windows.h) + # Check for the fcntl function. if test -n "${with_target_subdir}"; then case "${host}" in diff --git a/libbacktrace/fileline.c b/libbacktrace/fileline.c index 0e560b44e7a..28d752e2625 100644 --- a/libbacktrace/fileline.c +++ b/libbacktrace/fileline.c @@ -47,6 +47,18 @@ POSSIBILITY OF SUCH DAMAGE. */ #include #endif +#ifdef HAVE_WINDOWS_H +#ifndef WIN32_MEAN_AND_LEAN +#define WIN32_MEAN_AND_LEAN +#endif + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#include +#endif + #include "backtrace.h" #include "internal.h" @@ -165,6 +177,34 @@ macho_get_executable_path (struct backtrace_state *state, #endif /* !HAVE_DECL__PGMPTR */ +#ifdef HAVE_WINDOWS_H + +static char * +windows_get_executable_path (char *buf, backtrace_error_callback error_callback, +void *data) +{ + size_t got; + int error; + + got = GetModuleFileNameA (NULL, buf, MAX_PATH - 1); + error = GetLastError (); + if (got == 0 + || (got == MAX_PATH - 1 && error == ERROR_INSUFFICIENT_BUFFER)) +{ + error_callback (data, + "could not get the filename of the current executable", + error); + return NULL; +} + return buf; +} + +#else /* !defined (HAVE_WINDOWS_H) */ + +#define windows_get_executable_path(buf, error_callback, data) NULL + +#endif /* !defined (HAVE_WINDOWS_H) */ + /* Initialize the fileline information from the executable. Returns 1 on success, 0 on failure. */ @@ -178,7 +218,11 @@ fileline_initialize (struct backtrace_state *state, int called_error_callback; int descriptor; const char *filename; +#ifdef HAVE_WINDOWS_H
Re: [PATCH 2/4] libbacktrace: detect executable path on windows
Hi, this is what I'm using with GCC 12 and 13 on my windows machines, rebased onto the current HEAD. Kind regards, Björn. Am 06.02.2023 um 01:22 schrieb Ian Lance Taylor: On Sun, Feb 5, 2023 at 1:21 AM Björn Schäpers wrote: Am 24.01.2023 um 19:32 schrieb Ian Lance Taylor: On Tue, Jan 24, 2023 at 10:12 AM Eli Zaretskii via Gcc-patches wrote: From: Ian Lance Taylor Date: Tue, 24 Jan 2023 09:58:10 -0800 Cc: g...@hazardy.de, gcc-patches@gcc.gnu.org, g...@gcc.gnu.org I'd rather that the patch look like the appended. Can someone with a Windows system test to see what that builds and passes the tests? ENOPATCH Gah. Ian That seems to be my original patch, right? That one I have tested (and am actually using) on x86 and x64 windows. It's very similar but I changed the windows_get_executable_path function. Ian From e0ee58b71f726606205aa1f0168a724859162c21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Sch=C3=A4pers?= Date: Sun, 30 Apr 2023 23:48:18 +0200 Subject: [PATCH 1/3] libbacktrace: detect executable path on windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tested on x86_64-linux with GCC 12, i686-w64-mingw32 and x86_64-w64-mingw32 with GCC 12 & 13. This patch is rebased onto the current HEAD. -- >8 -- * configure.ac: Add a check for windows.h. * configure, config.h.in: Regenerate. * fileline.c: Add windows_get_executable_path. * fileline.c (fileline_initialize): Add a pass using windows_get_executable_path. Signed-off-by: Björn Schäpers --- libbacktrace/config.h.in | 3 +++ libbacktrace/configure| 13 +++ libbacktrace/configure.ac | 2 ++ libbacktrace/fileline.c | 49 ++- 4 files changed, 66 insertions(+), 1 deletion(-) diff --git a/libbacktrace/config.h.in b/libbacktrace/config.h.in index a4f5bf6..ee2616335c7 100644 --- a/libbacktrace/config.h.in +++ b/libbacktrace/config.h.in @@ -104,6 +104,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H +/* Define to 1 if you have the header file. */ +#undef HAVE_WINDOWS_H + /* Define if -lz is available. */ #undef HAVE_ZLIB diff --git a/libbacktrace/configure b/libbacktrace/configure index 0ccc060901d..7ade966b54d 100755 --- a/libbacktrace/configure +++ b/libbacktrace/configure @@ -13509,6 +13509,19 @@ $as_echo "#define HAVE_LOADQUERY 1" >>confdefs.h fi +for ac_header in windows.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "windows.h" "ac_cv_header_windows_h" "$ac_includes_default" +if test "x$ac_cv_header_windows_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_WINDOWS_H 1 +_ACEOF + +fi + +done + + # Check for the fcntl function. if test -n "${with_target_subdir}"; then case "${host}" in diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac index 71cd50f8cdf..00acb42eb6d 100644 --- a/libbacktrace/configure.ac +++ b/libbacktrace/configure.ac @@ -379,6 +379,8 @@ if test "$have_loadquery" = "yes"; then AC_DEFINE(HAVE_LOADQUERY, 1, [Define if AIX loadquery is available.]) fi +AC_CHECK_HEADERS(windows.h) + # Check for the fcntl function. if test -n "${with_target_subdir}"; then case "${host}" in diff --git a/libbacktrace/fileline.c b/libbacktrace/fileline.c index 0e560b44e7a..28d752e2625 100644 --- a/libbacktrace/fileline.c +++ b/libbacktrace/fileline.c @@ -47,6 +47,18 @@ POSSIBILITY OF SUCH DAMAGE. */ #include #endif +#ifdef HAVE_WINDOWS_H +#ifndef WIN32_MEAN_AND_LEAN +#define WIN32_MEAN_AND_LEAN +#endif + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#include +#endif + #include "backtrace.h" #include "internal.h" @@ -165,6 +177,34 @@ macho_get_executable_path (struct backtrace_state *state, #endif /* !HAVE_DECL__PGMPTR */ +#ifdef HAVE_WINDOWS_H + +static char * +windows_get_executable_path (char *buf, backtrace_error_callback error_callback, +void *data) +{ + size_t got; + int error; + + got = GetModuleFileNameA (NULL, buf, MAX_PATH - 1); + error = GetLastError (); + if (got == 0 + || (got == MAX_PATH - 1 && error == ERROR_INSUFFICIENT_BUFFER)) +{ + error_callback (data, + "could not get the filename of the current executable", + error); + return NULL; +} + return buf; +} + +#else /* !defined (HAVE_WINDOWS_H) */ + +#define windows_get_executable_path(buf, error_callback, data) NULL + +#endif /* !defined (HAVE_WINDOWS_H) */ + /* Initialize the fileline information from the executable. Returns 1 on success, 0 on failure. */ @@ -178,7 +218,11 @@ fileline_initialize (struct backtrace_state *state, int called_error_callback; int descriptor; const char *filename; +#ifdef HAVE_WINDOWS_H
Re: [PATCH 2/4] libbacktrace: detect executable path on windows
Am 24.01.2023 um 19:32 schrieb Ian Lance Taylor: On Tue, Jan 24, 2023 at 10:12 AM Eli Zaretskii via Gcc-patches wrote: From: Ian Lance Taylor Date: Tue, 24 Jan 2023 09:58:10 -0800 Cc: g...@hazardy.de, gcc-patches@gcc.gnu.org, g...@gcc.gnu.org I'd rather that the patch look like the appended. Can someone with a Windows system test to see what that builds and passes the tests? ENOPATCH Gah. Ian That seems to be my original patch, right? That one I have tested (and am actually using) on x86 and x64 windows.
Re: [PATCH 2/4] libbacktrace: detect executable path on windows
Am 24.01.2023 um 19:32 schrieb Ian Lance Taylor: On Tue, Jan 24, 2023 at 10:12 AM Eli Zaretskii via Gcc-patches wrote: From: Ian Lance Taylor Date: Tue, 24 Jan 2023 09:58:10 -0800 Cc: g...@hazardy.de, gcc-patc...@gcc.gnu.org, gcc@gcc.gnu.org I'd rather that the patch look like the appended. Can someone with a Windows system test to see what that builds and passes the tests? ENOPATCH Gah. Ian That seems to be my original patch, right? That one I have tested (and am actually using) on x86 and x64 windows.
Re: [PATCH 2/4] libbacktrace: detect executable path on windows
Am 24.01.2023 um 17:52 schrieb Eli Zaretskii: From: Ian Lance Taylor Date: Tue, 24 Jan 2023 06:35:21 -0800 Cc: g...@hazardy.de, gcc-patches@gcc.gnu.org, g...@gcc.gnu.org On Windows it seems that MAX_PATH is not a true limit, as an extended length path may be up to 32767 bytes. The limit of 32767 characters (not bytes, AFAIK) is only applicable when using the Unicode (a.k.a. "wide") versions of the Windows Win32 APIs, see https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation Since the above code uses GetModuleFileNameA, which is an "ANSI" single-byte API, it is still subject to the MAX_PATH limitation, and MAX_PATH is defined as 260 on Windows headers. Thanks. Should this code be using GetModuleFileNameW? Or would that mean that the later call to open will fail? We'd need to use _wopen or somesuch, and the file name will have to be a wchar_t array, not a char array, yes. So this is not very practical when file names need to be passed between functions, unless they are converted to UTF-8 (and back again before using them in Windows APIs). And note that even then, the 260-byte limit could be lifted only if the user has a new enough Windows version _and_ has opted in to the long-name feature by turning it on in the Registry. Otherwise, file names used in "wide" APIs can only break the 260-byte limit if they use the special format "\\?\D:\foo\bar", which means file names specified by user outside of the program or file names that come from other programs will need to be reformatted to this special format. 260 bytes does not seem like very much for a path name these days. That's true. But complications with using longer file names are still a PITA on Windows, even though they are a step closer to practically possible. That was basically also my reasoning for choosing the A variant instead of W.
Re: [PATCH 2/4] libbacktrace: detect executable path on windows
Am 24.01.2023 um 17:52 schrieb Eli Zaretskii: From: Ian Lance Taylor Date: Tue, 24 Jan 2023 06:35:21 -0800 Cc: g...@hazardy.de, gcc-patc...@gcc.gnu.org, gcc@gcc.gnu.org On Windows it seems that MAX_PATH is not a true limit, as an extended length path may be up to 32767 bytes. The limit of 32767 characters (not bytes, AFAIK) is only applicable when using the Unicode (a.k.a. "wide") versions of the Windows Win32 APIs, see https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation Since the above code uses GetModuleFileNameA, which is an "ANSI" single-byte API, it is still subject to the MAX_PATH limitation, and MAX_PATH is defined as 260 on Windows headers. Thanks. Should this code be using GetModuleFileNameW? Or would that mean that the later call to open will fail? We'd need to use _wopen or somesuch, and the file name will have to be a wchar_t array, not a char array, yes. So this is not very practical when file names need to be passed between functions, unless they are converted to UTF-8 (and back again before using them in Windows APIs). And note that even then, the 260-byte limit could be lifted only if the user has a new enough Windows version _and_ has opted in to the long-name feature by turning it on in the Registry. Otherwise, file names used in "wide" APIs can only break the 260-byte limit if they use the special format "\\?\D:\foo\bar", which means file names specified by user outside of the program or file names that come from other programs will need to be reformatted to this special format. 260 bytes does not seem like very much for a path name these days. That's true. But complications with using longer file names are still a PITA on Windows, even though they are a step closer to practically possible. That was basically also my reasoning for choosing the A variant instead of W.
Re: [PATCH 1/4] libbacktrace: change all pc related variables to uintptr_t
Am 20.01.2023 um 23:25 schrieb Ian Lance Taylor: On Fri, Jan 20, 2023 at 2:54 AM Björn Schäpers wrote: From: Björn Schäpers It's the right thing to do, since the PC shouldn't go out of the uintptr_t domain, and in backtrace_pcinfo the pc is uintptr_t. This is a preparation for a following patch. Tested on x86_64-linux and i686-w64-mingw32. Thanks. Committed like so, with some additional tweaks. For future reference, when pinging a patch, please reply to the original patch to maintain the thread. Or at least mention the original patch. It was still on my list, I just hadn't gotten to it. Thanks. Ian Thanks for the commit, and sorry for the repost. Because of a fault of my own I had no copy in my mailbox and thus couldn't reply to the first batch. Regards, Björn.
Re: [PATCH 1/4] libbacktrace: change all pc related variables to uintptr_t
Am 20.01.2023 um 23:25 schrieb Ian Lance Taylor: On Fri, Jan 20, 2023 at 2:54 AM Björn Schäpers wrote: From: Björn Schäpers It's the right thing to do, since the PC shouldn't go out of the uintptr_t domain, and in backtrace_pcinfo the pc is uintptr_t. This is a preparation for a following patch. Tested on x86_64-linux and i686-w64-mingw32. Thanks. Committed like so, with some additional tweaks. For future reference, when pinging a patch, please reply to the original patch to maintain the thread. Or at least mention the original patch. It was still on my list, I just hadn't gotten to it. Thanks. Ian Thanks for the commit, and sorry for the repost. Because of a fault of my own I had no copy in my mailbox and thus couldn't reply to the first batch. Regards, Björn.
[PATCH 4/4] libbacktrace: get debug information for loaded dlls
From: Björn Schäpers Fixes https://github.com/ianlancetaylor/libbacktrace/issues/53, except that libraries loaded after the backtrace_initialize are not handled. But as far as I can see that's the same for elf. Tested on x86_64-linux and i686-w64-mingw32. -- >8 -- * pecoff.c (coff_add): New argument for the module handle of the file, to get the base address. * pecoff.c (backtrace_initialize): Iterate over loaded libraries and call coff_add. Signed-off-by: Björn Schäpers --- libbacktrace/pecoff.c | 76 --- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/libbacktrace/pecoff.c b/libbacktrace/pecoff.c index 296f1357b5f..40395109e51 100644 --- a/libbacktrace/pecoff.c +++ b/libbacktrace/pecoff.c @@ -49,6 +49,7 @@ POSSIBILITY OF SUCH DAMAGE. */ #endif #include +#include #endif /* Coff file header. */ @@ -592,7 +593,8 @@ coff_syminfo (struct backtrace_state *state, uintptr_t addr, static int coff_add (struct backtrace_state *state, int descriptor, backtrace_error_callback error_callback, void *data, - fileline *fileline_fn, int *found_sym, int *found_dwarf) + fileline *fileline_fn, int *found_sym, int *found_dwarf, + uintptr_t module_handle ATTRIBUTE_UNUSED) { struct backtrace_view fhdr_view; off_t fhdr_off; @@ -623,7 +625,6 @@ coff_add (struct backtrace_state *state, int descriptor, int is_64; uintptr_t image_base; uintptr_t base_address = 0; - uintptr_t module_handle; struct dwarf_sections dwarf_sections; *found_sym = 0; @@ -871,7 +872,6 @@ coff_add (struct backtrace_state *state, int descriptor, } #ifdef HAVE_WINDOWS_H -module_handle = (uintptr_t) GetModuleHandleW (NULL); base_address = module_handle - image_base; #endif @@ -914,12 +914,80 @@ backtrace_initialize (struct backtrace_state *state, int found_sym; int found_dwarf; fileline coff_fileline_fn; + uintptr_t module_handle = 0; + +#ifdef HAVE_WINDOWS_H + DWORD i; + DWORD module_count; + DWORD bytes_needed_for_modules; + HMODULE *modules; + char module_name[MAX_PATH]; + int module_found_sym; + fileline module_fileline_fn; + + module_handle = (uintptr_t) GetModuleHandleW (NULL); +#endif ret = coff_add (state, descriptor, error_callback, data, - _fileline_fn, _sym, _dwarf); + _fileline_fn, _sym, _dwarf, module_handle); if (!ret) return 0; +#ifdef HAVE_WINDOWS_H + module_count = 1000; + alloc_modules: + modules = backtrace_alloc (state, module_count * sizeof(HMODULE), +error_callback, data); + if (modules == NULL) +goto skip_modules; + if (!EnumProcessModules (GetCurrentProcess (), modules, module_count, + _needed_for_modules)) +{ + error_callback(data, "Could not enumerate process modules", +(int) GetLastError ()); + goto free_modules; +} + if (bytes_needed_for_modules > module_count * sizeof(HMODULE)) +{ + backtrace_free (state, modules, module_count * sizeof(HMODULE), + error_callback, data); + // Add an extra of 2, if some module is loaded in another thread. + module_count = bytes_needed_for_modules / sizeof(HMODULE) + 2; + modules = NULL; + goto alloc_modules; +} + + for (i = 0; i < bytes_needed_for_modules / sizeof(HMODULE); ++i) +{ + if (GetModuleFileNameA (modules[i], module_name, MAX_PATH - 1)) + { + if (strcmp (filename, module_name) == 0) + continue; + + module_handle = (uintptr_t) GetModuleHandleA (module_name); + if (module_handle == 0) + continue; + + descriptor = backtrace_open (module_name, error_callback, data, NULL); + if (descriptor < 0) + continue; + + coff_add (state, descriptor, error_callback, data, + _fileline_fn, _found_sym, _dwarf, + module_handle); + if (module_found_sym) + found_sym = 1; + } +} + + free_modules: + if (modules) +backtrace_free(state, modules, module_count * sizeof(HMODULE), + error_callback, data); + modules = NULL; + skip_modules: +#endif + if (!state->threaded) { if (found_sym) -- 2.38.1
[PATCH 2/4] libbacktrace: detect executable path on windows
From: Björn Schäpers This is actually needed so that libstdc++'s implementation to be able to work on windows. Tested on x86_64-linux and i686-w64-mingw32. -- >8 -- * configure.ac: Add a check for windows.h. * configure, config.h.in: Regenerate. * fileline.c: Add windows_get_executable_path. * fileline.c (fileline_initialiez): Add a pass using windows_get_executable_path. Signed-off-by: Björn Schäpers --- libbacktrace/config.h.in | 3 +++ libbacktrace/configure| 13 libbacktrace/configure.ac | 2 ++ libbacktrace/fileline.c | 43 ++- 4 files changed, 60 insertions(+), 1 deletion(-) diff --git a/libbacktrace/config.h.in b/libbacktrace/config.h.in index a21e2eaf525..355e820741b 100644 --- a/libbacktrace/config.h.in +++ b/libbacktrace/config.h.in @@ -100,6 +100,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H +/* Define to 1 if you have the header file. */ +#undef HAVE_WINDOWS_H + /* Define if -lz is available. */ #undef HAVE_ZLIB diff --git a/libbacktrace/configure b/libbacktrace/configure index a5bd133f4e4..ef677423733 100755 --- a/libbacktrace/configure +++ b/libbacktrace/configure @@ -13403,6 +13403,19 @@ $as_echo "#define HAVE_LOADQUERY 1" >>confdefs.h fi +for ac_header in windows.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "windows.h" "ac_cv_header_windows_h" "$ac_includes_default" +if test "x$ac_cv_header_windows_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_WINDOWS_H 1 +_ACEOF + +fi + +done + + # Check for the fcntl function. if test -n "${with_target_subdir}"; then case "${host}" in diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac index 1daaa2f62d2..b5feb29bcdc 100644 --- a/libbacktrace/configure.ac +++ b/libbacktrace/configure.ac @@ -377,6 +377,8 @@ if test "$have_loadquery" = "yes"; then AC_DEFINE(HAVE_LOADQUERY, 1, [Define if AIX loadquery is available.]) fi +AC_CHECK_HEADERS(windows.h) + # Check for the fcntl function. if test -n "${with_target_subdir}"; then case "${host}" in diff --git a/libbacktrace/fileline.c b/libbacktrace/fileline.c index a40cd498114..73c2c8e8bc9 100644 --- a/libbacktrace/fileline.c +++ b/libbacktrace/fileline.c @@ -47,6 +47,18 @@ POSSIBILITY OF SUCH DAMAGE. */ #include #endif +#ifdef HAVE_WINDOWS_H +#ifndef WIN32_MEAN_AND_LEAN +#define WIN32_MEAN_AND_LEAN +#endif + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#include +#endif + #include "backtrace.h" #include "internal.h" @@ -155,6 +167,28 @@ macho_get_executable_path (struct backtrace_state *state, #endif /* !defined (HAVE_MACH_O_DYLD_H) */ +#ifdef HAVE_WINDOWS_H + +static char * +windows_get_executable_path (char *buf, backtrace_error_callback error_callback, +void *data) +{ + if (GetModuleFileNameA (NULL, buf, MAX_PATH - 1) == 0) +{ + error_callback (data, + "could not get the filename of the current executable", + (int) GetLastError ()); + return NULL; +} + return buf; +} + +#else /* !defined (HAVE_WINDOWS_H) */ + +#define windows_get_executable_path(buf, error_callback, data) NULL + +#endif /* !defined (HAVE_WINDOWS_H) */ + /* Initialize the fileline information from the executable. Returns 1 on success, 0 on failure. */ @@ -168,7 +202,11 @@ fileline_initialize (struct backtrace_state *state, int called_error_callback; int descriptor; const char *filename; +#ifdef HAVE_WINDOWS_H + char buf[MAX_PATH]; +#else char buf[64]; +#endif if (!state->threaded) failed = state->fileline_initialization_failed; @@ -192,7 +230,7 @@ fileline_initialize (struct backtrace_state *state, descriptor = -1; called_error_callback = 0; - for (pass = 0; pass < 8; ++pass) + for (pass = 0; pass < 9; ++pass) { int does_not_exist; @@ -224,6 +262,9 @@ fileline_initialize (struct backtrace_state *state, case 7: filename = macho_get_executable_path (state, error_callback, data); break; + case 8: + filename = windows_get_executable_path (buf, error_callback, data); + break; default: abort (); } -- 2.38.1
[PATCH 2/4] libbacktrace: detect executable path on windows
From: Björn Schäpers This is actually needed so that libstdc++'s implementation to be able to work on windows. Tested on x86_64-linux and i686-w64-mingw32. -- >8 -- * configure.ac: Add a check for windows.h. * configure, config.h.in: Regenerate. * fileline.c: Add windows_get_executable_path. * fileline.c (fileline_initialiez): Add a pass using windows_get_executable_path. Signed-off-by: Björn Schäpers --- libbacktrace/config.h.in | 3 +++ libbacktrace/configure| 13 libbacktrace/configure.ac | 2 ++ libbacktrace/fileline.c | 43 ++- 4 files changed, 60 insertions(+), 1 deletion(-) diff --git a/libbacktrace/config.h.in b/libbacktrace/config.h.in index a21e2eaf525..355e820741b 100644 --- a/libbacktrace/config.h.in +++ b/libbacktrace/config.h.in @@ -100,6 +100,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H +/* Define to 1 if you have the header file. */ +#undef HAVE_WINDOWS_H + /* Define if -lz is available. */ #undef HAVE_ZLIB diff --git a/libbacktrace/configure b/libbacktrace/configure index a5bd133f4e4..ef677423733 100755 --- a/libbacktrace/configure +++ b/libbacktrace/configure @@ -13403,6 +13403,19 @@ $as_echo "#define HAVE_LOADQUERY 1" >>confdefs.h fi +for ac_header in windows.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "windows.h" "ac_cv_header_windows_h" "$ac_includes_default" +if test "x$ac_cv_header_windows_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_WINDOWS_H 1 +_ACEOF + +fi + +done + + # Check for the fcntl function. if test -n "${with_target_subdir}"; then case "${host}" in diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac index 1daaa2f62d2..b5feb29bcdc 100644 --- a/libbacktrace/configure.ac +++ b/libbacktrace/configure.ac @@ -377,6 +377,8 @@ if test "$have_loadquery" = "yes"; then AC_DEFINE(HAVE_LOADQUERY, 1, [Define if AIX loadquery is available.]) fi +AC_CHECK_HEADERS(windows.h) + # Check for the fcntl function. if test -n "${with_target_subdir}"; then case "${host}" in diff --git a/libbacktrace/fileline.c b/libbacktrace/fileline.c index a40cd498114..73c2c8e8bc9 100644 --- a/libbacktrace/fileline.c +++ b/libbacktrace/fileline.c @@ -47,6 +47,18 @@ POSSIBILITY OF SUCH DAMAGE. */ #include #endif +#ifdef HAVE_WINDOWS_H +#ifndef WIN32_MEAN_AND_LEAN +#define WIN32_MEAN_AND_LEAN +#endif + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#include +#endif + #include "backtrace.h" #include "internal.h" @@ -155,6 +167,28 @@ macho_get_executable_path (struct backtrace_state *state, #endif /* !defined (HAVE_MACH_O_DYLD_H) */ +#ifdef HAVE_WINDOWS_H + +static char * +windows_get_executable_path (char *buf, backtrace_error_callback error_callback, +void *data) +{ + if (GetModuleFileNameA (NULL, buf, MAX_PATH - 1) == 0) +{ + error_callback (data, + "could not get the filename of the current executable", + (int) GetLastError ()); + return NULL; +} + return buf; +} + +#else /* !defined (HAVE_WINDOWS_H) */ + +#define windows_get_executable_path(buf, error_callback, data) NULL + +#endif /* !defined (HAVE_WINDOWS_H) */ + /* Initialize the fileline information from the executable. Returns 1 on success, 0 on failure. */ @@ -168,7 +202,11 @@ fileline_initialize (struct backtrace_state *state, int called_error_callback; int descriptor; const char *filename; +#ifdef HAVE_WINDOWS_H + char buf[MAX_PATH]; +#else char buf[64]; +#endif if (!state->threaded) failed = state->fileline_initialization_failed; @@ -192,7 +230,7 @@ fileline_initialize (struct backtrace_state *state, descriptor = -1; called_error_callback = 0; - for (pass = 0; pass < 8; ++pass) + for (pass = 0; pass < 9; ++pass) { int does_not_exist; @@ -224,6 +262,9 @@ fileline_initialize (struct backtrace_state *state, case 7: filename = macho_get_executable_path (state, error_callback, data); break; + case 8: + filename = windows_get_executable_path (buf, error_callback, data); + break; default: abort (); } -- 2.38.1
[PATCH 4/4] libbacktrace: get debug information for loaded dlls
From: Björn Schäpers Fixes https://github.com/ianlancetaylor/libbacktrace/issues/53, except that libraries loaded after the backtrace_initialize are not handled. But as far as I can see that's the same for elf. Tested on x86_64-linux and i686-w64-mingw32. -- >8 -- * pecoff.c (coff_add): New argument for the module handle of the file, to get the base address. * pecoff.c (backtrace_initialize): Iterate over loaded libraries and call coff_add. Signed-off-by: Björn Schäpers --- libbacktrace/pecoff.c | 76 --- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/libbacktrace/pecoff.c b/libbacktrace/pecoff.c index 296f1357b5f..40395109e51 100644 --- a/libbacktrace/pecoff.c +++ b/libbacktrace/pecoff.c @@ -49,6 +49,7 @@ POSSIBILITY OF SUCH DAMAGE. */ #endif #include +#include #endif /* Coff file header. */ @@ -592,7 +593,8 @@ coff_syminfo (struct backtrace_state *state, uintptr_t addr, static int coff_add (struct backtrace_state *state, int descriptor, backtrace_error_callback error_callback, void *data, - fileline *fileline_fn, int *found_sym, int *found_dwarf) + fileline *fileline_fn, int *found_sym, int *found_dwarf, + uintptr_t module_handle ATTRIBUTE_UNUSED) { struct backtrace_view fhdr_view; off_t fhdr_off; @@ -623,7 +625,6 @@ coff_add (struct backtrace_state *state, int descriptor, int is_64; uintptr_t image_base; uintptr_t base_address = 0; - uintptr_t module_handle; struct dwarf_sections dwarf_sections; *found_sym = 0; @@ -871,7 +872,6 @@ coff_add (struct backtrace_state *state, int descriptor, } #ifdef HAVE_WINDOWS_H -module_handle = (uintptr_t) GetModuleHandleW (NULL); base_address = module_handle - image_base; #endif @@ -914,12 +914,80 @@ backtrace_initialize (struct backtrace_state *state, int found_sym; int found_dwarf; fileline coff_fileline_fn; + uintptr_t module_handle = 0; + +#ifdef HAVE_WINDOWS_H + DWORD i; + DWORD module_count; + DWORD bytes_needed_for_modules; + HMODULE *modules; + char module_name[MAX_PATH]; + int module_found_sym; + fileline module_fileline_fn; + + module_handle = (uintptr_t) GetModuleHandleW (NULL); +#endif ret = coff_add (state, descriptor, error_callback, data, - _fileline_fn, _sym, _dwarf); + _fileline_fn, _sym, _dwarf, module_handle); if (!ret) return 0; +#ifdef HAVE_WINDOWS_H + module_count = 1000; + alloc_modules: + modules = backtrace_alloc (state, module_count * sizeof(HMODULE), +error_callback, data); + if (modules == NULL) +goto skip_modules; + if (!EnumProcessModules (GetCurrentProcess (), modules, module_count, + _needed_for_modules)) +{ + error_callback(data, "Could not enumerate process modules", +(int) GetLastError ()); + goto free_modules; +} + if (bytes_needed_for_modules > module_count * sizeof(HMODULE)) +{ + backtrace_free (state, modules, module_count * sizeof(HMODULE), + error_callback, data); + // Add an extra of 2, if some module is loaded in another thread. + module_count = bytes_needed_for_modules / sizeof(HMODULE) + 2; + modules = NULL; + goto alloc_modules; +} + + for (i = 0; i < bytes_needed_for_modules / sizeof(HMODULE); ++i) +{ + if (GetModuleFileNameA (modules[i], module_name, MAX_PATH - 1)) + { + if (strcmp (filename, module_name) == 0) + continue; + + module_handle = (uintptr_t) GetModuleHandleA (module_name); + if (module_handle == 0) + continue; + + descriptor = backtrace_open (module_name, error_callback, data, NULL); + if (descriptor < 0) + continue; + + coff_add (state, descriptor, error_callback, data, + _fileline_fn, _found_sym, _dwarf, + module_handle); + if (module_found_sym) + found_sym = 1; + } +} + + free_modules: + if (modules) +backtrace_free(state, modules, module_count * sizeof(HMODULE), + error_callback, data); + modules = NULL; + skip_modules: +#endif + if (!state->threaded) { if (found_sym) -- 2.38.1
[PATCH 3/4] libbacktrace: work with aslr on windows
From: Björn Schäpers Any underflow which might happen, will be countered by an overflow in dwarf.c. Tested on x86_64-linux and i686-w64-mingw32. -- >8 -- Fixes https://github.com/ianlancetaylor/libbacktrace/issues/89 and https://github.com/ianlancetaylor/libbacktrace/issues/82. * pecoff.c (coff_add): Set the base_address of the module, to find the debug information on moved applications. Signed-off-by: Björn Schäpers --- libbacktrace/pecoff.c | 21 - 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/libbacktrace/pecoff.c b/libbacktrace/pecoff.c index 87b3c0cc647..296f1357b5f 100644 --- a/libbacktrace/pecoff.c +++ b/libbacktrace/pecoff.c @@ -39,6 +39,18 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "backtrace.h" #include "internal.h" +#ifdef HAVE_WINDOWS_H +#ifndef WIN32_MEAN_AND_LEAN +#define WIN32_MEAN_AND_LEAN +#endif + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#include +#endif + /* Coff file header. */ typedef struct { @@ -610,6 +622,8 @@ coff_add (struct backtrace_state *state, int descriptor, int debug_view_valid; int is_64; uintptr_t image_base; + uintptr_t base_address = 0; + uintptr_t module_handle; struct dwarf_sections dwarf_sections; *found_sym = 0; @@ -856,7 +870,12 @@ coff_add (struct backtrace_state *state, int descriptor, + (sections[i].offset - min_offset)); } - if (!backtrace_dwarf_add (state, /* base_address */ 0, _sections, +#ifdef HAVE_WINDOWS_H +module_handle = (uintptr_t) GetModuleHandleW (NULL); +base_address = module_handle - image_base; +#endif + + if (!backtrace_dwarf_add (state, base_address, _sections, 0, /* FIXME: is_bigendian */ NULL, /* altlink */ error_callback, data, fileline_fn, -- 2.38.1
[PATCH 3/4] libbacktrace: work with aslr on windows
From: Björn Schäpers Any underflow which might happen, will be countered by an overflow in dwarf.c. Tested on x86_64-linux and i686-w64-mingw32. -- >8 -- Fixes https://github.com/ianlancetaylor/libbacktrace/issues/89 and https://github.com/ianlancetaylor/libbacktrace/issues/82. * pecoff.c (coff_add): Set the base_address of the module, to find the debug information on moved applications. Signed-off-by: Björn Schäpers --- libbacktrace/pecoff.c | 21 - 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/libbacktrace/pecoff.c b/libbacktrace/pecoff.c index 87b3c0cc647..296f1357b5f 100644 --- a/libbacktrace/pecoff.c +++ b/libbacktrace/pecoff.c @@ -39,6 +39,18 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "backtrace.h" #include "internal.h" +#ifdef HAVE_WINDOWS_H +#ifndef WIN32_MEAN_AND_LEAN +#define WIN32_MEAN_AND_LEAN +#endif + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#include +#endif + /* Coff file header. */ typedef struct { @@ -610,6 +622,8 @@ coff_add (struct backtrace_state *state, int descriptor, int debug_view_valid; int is_64; uintptr_t image_base; + uintptr_t base_address = 0; + uintptr_t module_handle; struct dwarf_sections dwarf_sections; *found_sym = 0; @@ -856,7 +870,12 @@ coff_add (struct backtrace_state *state, int descriptor, + (sections[i].offset - min_offset)); } - if (!backtrace_dwarf_add (state, /* base_address */ 0, _sections, +#ifdef HAVE_WINDOWS_H +module_handle = (uintptr_t) GetModuleHandleW (NULL); +base_address = module_handle - image_base; +#endif + + if (!backtrace_dwarf_add (state, base_address, _sections, 0, /* FIXME: is_bigendian */ NULL, /* altlink */ error_callback, data, fileline_fn, -- 2.38.1
[PATCH 1/4] libbacktrace: change all pc related variables to uintptr_t
From: Björn Schäpers It's the right thing to do, since the PC shouldn't go out of the uintptr_t domain, and in backtrace_pcinfo the pc is uintptr_t. This is a preparation for a following patch. Tested on x86_64-linux and i686-w64-mingw32. -- >8 -- * dwarf.c: changed variables holding pc values from uint64_t to uintptr_t. Signed-off-by: Björn Schäpers --- libbacktrace/dwarf.c | 44 ++-- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/libbacktrace/dwarf.c b/libbacktrace/dwarf.c index 45cc9e77e40..0707ccddd3e 100644 --- a/libbacktrace/dwarf.c +++ b/libbacktrace/dwarf.c @@ -274,8 +274,8 @@ struct function struct function_addrs { /* Range is LOW <= PC < HIGH. */ - uint64_t low; - uint64_t high; + uintptr_t low; + uintptr_t high; /* Function for this address range. */ struct function *function; }; @@ -356,8 +356,8 @@ struct unit struct unit_addrs { /* Range is LOW <= PC < HIGH. */ - uint64_t low; - uint64_t high; + uintptr_t low; + uintptr_t high; /* Compilation unit for this address range. */ struct unit *u; }; @@ -1094,7 +1094,7 @@ resolve_addr_index (const struct dwarf_sections *dwarf_sections, uint64_t addr_base, int addrsize, int is_bigendian, uint64_t addr_index, backtrace_error_callback error_callback, void *data, - uint64_t *address) + uintptr_t *address) { uint64_t offset; struct dwarf_buf addr_buf; @@ -1194,7 +1194,7 @@ function_addrs_search (const void *vkey, const void *ventry) static int add_unit_addr (struct backtrace_state *state, void *rdata, - uint64_t lowpc, uint64_t highpc, + uintptr_t lowpc, uintptr_t highpc, backtrace_error_callback error_callback, void *data, void *pvec) { @@ -1530,10 +1530,10 @@ lookup_abbrev (struct abbrevs *abbrevs, uint64_t code, lowpc/highpc is set or ranges is set. */ struct pcrange { - uint64_t lowpc; /* The low PC value. */ + uintptr_t lowpc; /* The low PC value. */ int have_lowpc; /* Whether a low PC value was found. */ int lowpc_is_addr_index; /* Whether lowpc is in .debug_addr. */ - uint64_t highpc; /* The high PC value. */ + uintptr_t highpc;/* The high PC value. */ int have_highpc; /* Whether a high PC value was found. */ int highpc_is_relative; /* Whether highpc is relative to lowpc. */ int highpc_is_addr_index;/* Whether highpc is in .debug_addr. */ @@ -1613,16 +1613,16 @@ add_low_high_range (struct backtrace_state *state, uintptr_t base_address, int is_bigendian, struct unit *u, const struct pcrange *pcrange, int (*add_range) (struct backtrace_state *state, - void *rdata, uint64_t lowpc, - uint64_t highpc, + void *rdata, uintptr_t lowpc, + uintptr_t highpc, backtrace_error_callback error_callback, void *data, void *vec), void *rdata, backtrace_error_callback error_callback, void *data, void *vec) { - uint64_t lowpc; - uint64_t highpc; + uintptr_t lowpc; + uintptr_t highpc; lowpc = pcrange->lowpc; if (pcrange->lowpc_is_addr_index) @@ -1663,7 +1663,7 @@ add_ranges_from_ranges ( struct unit *u, uint64_t base, const struct pcrange *pcrange, int (*add_range) (struct backtrace_state *state, void *rdata, - uint64_t lowpc, uint64_t highpc, + uintptr_t lowpc, uintptr_t highpc, backtrace_error_callback error_callback, void *data, void *vec), void *rdata, @@ -1727,10 +1727,10 @@ add_ranges_from_rnglists ( struct backtrace_state *state, const struct dwarf_sections *dwarf_sections, uintptr_t base_address, int is_bigendian, -struct unit *u, uint64_t base, +struct unit *u, uintptr_t base, const struct pcrange *pcrange, int (*add_range) (struct backtrace_state *state, void *rdata, - uint64_t lowpc, uint64_t highpc, + uintptr_t lowpc, uintptr_t highpc, backtrace_error_callback error_callback, void *data, void *vec), void *rdata, @@ -1796,8 +1796,8 @@ add_ranges_from_rnglists ( case DW_RLE_startx_endx: { uint64_t index; - uint64_t low; - uint64_t high; + uintptr_t low; + uintptr_t high; index = read_uleb128 (_buf); if (!resolve_addr_index (dwarf_sections, u->addr_base, @@ -1819,8 +1819,8 @@
[PATCH 1/4] libbacktrace: change all pc related variables to uintptr_t
From: Björn Schäpers It's the right thing to do, since the PC shouldn't go out of the uintptr_t domain, and in backtrace_pcinfo the pc is uintptr_t. This is a preparation for a following patch. Tested on x86_64-linux and i686-w64-mingw32. -- >8 -- * dwarf.c: changed variables holding pc values from uint64_t to uintptr_t. Signed-off-by: Björn Schäpers --- libbacktrace/dwarf.c | 44 ++-- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/libbacktrace/dwarf.c b/libbacktrace/dwarf.c index 45cc9e77e40..0707ccddd3e 100644 --- a/libbacktrace/dwarf.c +++ b/libbacktrace/dwarf.c @@ -274,8 +274,8 @@ struct function struct function_addrs { /* Range is LOW <= PC < HIGH. */ - uint64_t low; - uint64_t high; + uintptr_t low; + uintptr_t high; /* Function for this address range. */ struct function *function; }; @@ -356,8 +356,8 @@ struct unit struct unit_addrs { /* Range is LOW <= PC < HIGH. */ - uint64_t low; - uint64_t high; + uintptr_t low; + uintptr_t high; /* Compilation unit for this address range. */ struct unit *u; }; @@ -1094,7 +1094,7 @@ resolve_addr_index (const struct dwarf_sections *dwarf_sections, uint64_t addr_base, int addrsize, int is_bigendian, uint64_t addr_index, backtrace_error_callback error_callback, void *data, - uint64_t *address) + uintptr_t *address) { uint64_t offset; struct dwarf_buf addr_buf; @@ -1194,7 +1194,7 @@ function_addrs_search (const void *vkey, const void *ventry) static int add_unit_addr (struct backtrace_state *state, void *rdata, - uint64_t lowpc, uint64_t highpc, + uintptr_t lowpc, uintptr_t highpc, backtrace_error_callback error_callback, void *data, void *pvec) { @@ -1530,10 +1530,10 @@ lookup_abbrev (struct abbrevs *abbrevs, uint64_t code, lowpc/highpc is set or ranges is set. */ struct pcrange { - uint64_t lowpc; /* The low PC value. */ + uintptr_t lowpc; /* The low PC value. */ int have_lowpc; /* Whether a low PC value was found. */ int lowpc_is_addr_index; /* Whether lowpc is in .debug_addr. */ - uint64_t highpc; /* The high PC value. */ + uintptr_t highpc;/* The high PC value. */ int have_highpc; /* Whether a high PC value was found. */ int highpc_is_relative; /* Whether highpc is relative to lowpc. */ int highpc_is_addr_index;/* Whether highpc is in .debug_addr. */ @@ -1613,16 +1613,16 @@ add_low_high_range (struct backtrace_state *state, uintptr_t base_address, int is_bigendian, struct unit *u, const struct pcrange *pcrange, int (*add_range) (struct backtrace_state *state, - void *rdata, uint64_t lowpc, - uint64_t highpc, + void *rdata, uintptr_t lowpc, + uintptr_t highpc, backtrace_error_callback error_callback, void *data, void *vec), void *rdata, backtrace_error_callback error_callback, void *data, void *vec) { - uint64_t lowpc; - uint64_t highpc; + uintptr_t lowpc; + uintptr_t highpc; lowpc = pcrange->lowpc; if (pcrange->lowpc_is_addr_index) @@ -1663,7 +1663,7 @@ add_ranges_from_ranges ( struct unit *u, uint64_t base, const struct pcrange *pcrange, int (*add_range) (struct backtrace_state *state, void *rdata, - uint64_t lowpc, uint64_t highpc, + uintptr_t lowpc, uintptr_t highpc, backtrace_error_callback error_callback, void *data, void *vec), void *rdata, @@ -1727,10 +1727,10 @@ add_ranges_from_rnglists ( struct backtrace_state *state, const struct dwarf_sections *dwarf_sections, uintptr_t base_address, int is_bigendian, -struct unit *u, uint64_t base, +struct unit *u, uintptr_t base, const struct pcrange *pcrange, int (*add_range) (struct backtrace_state *state, void *rdata, - uint64_t lowpc, uint64_t highpc, + uintptr_t lowpc, uintptr_t highpc, backtrace_error_callback error_callback, void *data, void *vec), void *rdata, @@ -1796,8 +1796,8 @@ add_ranges_from_rnglists ( case DW_RLE_startx_endx: { uint64_t index; - uint64_t low; - uint64_t high; + uintptr_t low; + uintptr_t high; index = read_uleb128 (_buf); if (!resolve_addr_index (dwarf_sections, u->addr_base, @@ -1819,8 +1819,8 @@
[PATCH] libstdc++: Deliver names of C functions in
From: Björn Schäpers One could add (), these are not part of __name. One could also try to check upfront if __cxa_demangle should be called at all. -- >8 -- Tested on i686-w64-mingw32. __cxa_demangle is only to demangle C++ names, for all C functions, extern "C" functions, and including main it returns -2, in that case just adapt the given name. Otherwise it's kept empty, which doesn't look nice in the stacktrace. libstdc++-v3/ChangeLog: * include/std/stacktrace (stacktrace_entry::_S_demangle): Use raw __name if __cxa_demangle could not demangle it. Signed-off-by: Björn Schäpers --- libstdc++-v3/include/std/stacktrace | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libstdc++-v3/include/std/stacktrace b/libstdc++-v3/include/std/stacktrace index 83c6463b0d8..5baf2dcdaca 100644 --- a/libstdc++-v3/include/std/stacktrace +++ b/libstdc++-v3/include/std/stacktrace @@ -219,6 +219,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION &__status); if (__status == 0) __s = __str; + else + __s = __name; __builtin_free(__str); return __s; } -- 2.38.1
[PATCH] libstdc++: Deliver names of C functions in
From: Björn Schäpers One could add (), these are not part of __name. One could also try to check upfront if __cxa_demangle should be called at all. -- >8 -- Tested on i686-w64-mingw32. __cxa_demangle is only to demangle C++ names, for all C functions, extern "C" functions, and including main it returns -2, in that case just adapt the given name. Otherwise it's kept empty, which doesn't look nice in the stacktrace. libstdc++-v3/ChangeLog: * include/std/stacktrace (stacktrace_entry::_S_demangle): Use raw __name if __cxa_demangle could not demangle it. Signed-off-by: Björn Schäpers --- libstdc++-v3/include/std/stacktrace | 9 - 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libstdc++-v3/include/std/stacktrace b/libstdc++-v3/include/std/stacktrace index 83c6463b0d8..6d4051b9f5b 100644 --- a/libstdc++-v3/include/std/stacktrace +++ b/libstdc++-v3/include/std/stacktrace @@ -217,8 +217,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION int __status; char* __str = __cxxabiv1::__cxa_demangle(__name, nullptr, nullptr, &__status); - if (__status == 0) + switch (__status) + { + case 0: __s = __str; + break; + case -2: + __s = __name; + break; + } __builtin_free(__str); return __s; } -- 2.38.1
[PATCH] libstdc++: Deliver names of C functions in
From: Björn Schäpers One could add (), these are not part of __name. One could also try to check upfront if __cxa_demangle should be called at all. -- >8 -- Tested on i686-w64-mingw32. __cxa_demangle is only to demangle C++ names, for all C functions, extern "C" functions, and including main it returns -2, in that case just adapt the given name. Otherwise it's kept empty, which doesn't look nice in the stacktrace. libstdc++-v3/ChangeLog: * include/std/stacktrace (stacktrace_entry::_S_demangle): Use raw __name if __cxa_demangle could not demangle it. Signed-off-by: Björn Schäpers --- libstdc++-v3/include/std/stacktrace | 9 - 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libstdc++-v3/include/std/stacktrace b/libstdc++-v3/include/std/stacktrace index 83c6463b0d8..6d4051b9f5b 100644 --- a/libstdc++-v3/include/std/stacktrace +++ b/libstdc++-v3/include/std/stacktrace @@ -217,8 +217,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION int __status; char* __str = __cxxabiv1::__cxa_demangle(__name, nullptr, nullptr, &__status); - if (__status == 0) + switch (__status) + { + case 0: __s = __str; + break; + case -2: + __s = __name; + break; + } __builtin_free(__str); return __s; } -- 2.38.1
[PATCH] libstdc++: enable on windows
From: Björn Schäpers libstdc++-v3/Changelog * acinclude.m4: Add check for windows.h. * acinclude.m4: Add pecoff as FORMAT_FILE. * config.h.in: Regenerate. * configure: Regenerate. * src/libbacktrace/Makefile.am: Regenerate. * src/libbacktrace/Makefile.in: Add pecoff.c as FORMAT_FILE. Signed-off-by: Björn Schäpers --- libstdc++-v3/acinclude.m4 | 2 ++ libstdc++-v3/src/libbacktrace/Makefile.am | 1 + 2 files changed, 3 insertions(+) diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4 index b957c728ba1..1cfe704e637 100644 --- a/libstdc++-v3/acinclude.m4 +++ b/libstdc++-v3/acinclude.m4 @@ -4981,6 +4981,7 @@ AC_DEFUN([GLIBCXX_ENABLE_BACKTRACE], [ if test "$have_dl_iterate_phdr" = "yes"; then BACKTRACE_CPPFLAGS="$BACKTRACE_CPPFLAGS -DHAVE_DL_ITERATE_PHDR=1" fi + AC_CHECK_HEADERS(windows.h) # Check for the fcntl function. if test -n "${with_target_subdir}"; then @@ -5026,6 +5027,7 @@ glibcxx_cv_sys_filetype=$filetype]) FORMAT_FILE= case "$glibcxx_cv_sys_filetype" in elf*) FORMAT_FILE="elf.lo" ;; +pecoff*) FORMAT_FILE="pecoff.lo" ;; *) AC_MSG_WARN([could not determine output file type]) FORMAT_FILE="unknown.lo" enable_libstdcxx_backtrace=no diff --git a/libstdc++-v3/src/libbacktrace/Makefile.am b/libstdc++-v3/src/libbacktrace/Makefile.am index 52d8f81b97b..b34a429a21d 100644 --- a/libstdc++-v3/src/libbacktrace/Makefile.am +++ b/libstdc++-v3/src/libbacktrace/Makefile.am @@ -71,6 +71,7 @@ libstdc___libbacktrace_la_SOURCES = \ FORMAT_FILES = \ elf.c \ + pecoff.c \ unknown.c VIEW_FILES = \ -- 2.38.1
[PATCH 2/4] libbacktrace: detect executable path on windows
From: Björn Schäpers This is actually needed so that libstdc++'s implementation to be able to work on windows. Tested on x86_64-linux and i686-w64-mingw32. -- >8 -- * configure.ac: Add a check for windows.h. * configure, config.h.in: Regenerate. * fileline.c: Add windows_get_executable_path. * fileline.c (fileline_initialiez): Add a pass using windows_get_executable_path. Signed-off-by: Björn Schäpers --- libbacktrace/configure.ac | 2 ++ libbacktrace/fileline.c | 43 ++- 4 files changed, 60 insertions(+), 1 deletion(-) diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac index 1daaa2f62d2..b5feb29bcdc 100644 --- a/libbacktrace/configure.ac +++ b/libbacktrace/configure.ac @@ -377,6 +377,8 @@ if test "$have_loadquery" = "yes"; then AC_DEFINE(HAVE_LOADQUERY, 1, [Define if AIX loadquery is available.]) fi +AC_CHECK_HEADERS(windows.h) + # Check for the fcntl function. if test -n "${with_target_subdir}"; then case "${host}" in diff --git a/libbacktrace/fileline.c b/libbacktrace/fileline.c index a40cd498114..73c2c8e8bc9 100644 --- a/libbacktrace/fileline.c +++ b/libbacktrace/fileline.c @@ -47,6 +47,18 @@ POSSIBILITY OF SUCH DAMAGE. */ #include #endif +#ifdef HAVE_WINDOWS_H +#ifndef WIN32_MEAN_AND_LEAN +#define WIN32_MEAN_AND_LEAN +#endif + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#include +#endif + #include "backtrace.h" #include "internal.h" @@ -155,6 +167,28 @@ macho_get_executable_path (struct backtrace_state *state, #endif /* !defined (HAVE_MACH_O_DYLD_H) */ +#ifdef HAVE_WINDOWS_H + +static char * +windows_get_executable_path (char *buf, backtrace_error_callback error_callback, +void *data) +{ + if (GetModuleFileNameA (NULL, buf, MAX_PATH - 1) == 0) +{ + error_callback (data, + "could not get the filename of the current executable", + (int) GetLastError ()); + return NULL; +} + return buf; +} + +#else /* !defined (HAVE_WINDOWS_H) */ + +#define windows_get_executable_path(buf, error_callback, data) NULL + +#endif /* !defined (HAVE_WINDOWS_H) */ + /* Initialize the fileline information from the executable. Returns 1 on success, 0 on failure. */ @@ -168,7 +202,11 @@ fileline_initialize (struct backtrace_state *state, int called_error_callback; int descriptor; const char *filename; +#ifdef HAVE_WINDOWS_H + char buf[MAX_PATH]; +#else char buf[64]; +#endif if (!state->threaded) failed = state->fileline_initialization_failed; @@ -192,7 +230,7 @@ fileline_initialize (struct backtrace_state *state, descriptor = -1; called_error_callback = 0; - for (pass = 0; pass < 8; ++pass) + for (pass = 0; pass < 9; ++pass) { int does_not_exist; @@ -224,6 +262,9 @@ fileline_initialize (struct backtrace_state *state, case 7: filename = macho_get_executable_path (state, error_callback, data); break; + case 8: + filename = windows_get_executable_path (buf, error_callback, data); + break; default: abort (); } -- 2.38.1
[PATCH 3/4] libbacktrace: work with aslr on windows
From: Björn Schäpers Any underflow which might happen, will be countered by an overflow in dwarf.c. Tested on x86_64-linux and i686-w64-mingw32. -- >8 -- Fixes https://github.com/ianlancetaylor/libbacktrace/issues/89 and https://github.com/ianlancetaylor/libbacktrace/issues/82. * pecoff.c (coff_add): Set the base_address of the module, to find the debug information on moved applications. Signed-off-by: Björn Schäpers --- libbacktrace/pecoff.c | 21 - 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/libbacktrace/pecoff.c b/libbacktrace/pecoff.c index 87b3c0cc647..296f1357b5f 100644 --- a/libbacktrace/pecoff.c +++ b/libbacktrace/pecoff.c @@ -39,6 +39,18 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "backtrace.h" #include "internal.h" +#ifdef HAVE_WINDOWS_H +#ifndef WIN32_MEAN_AND_LEAN +#define WIN32_MEAN_AND_LEAN +#endif + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#include +#endif + /* Coff file header. */ typedef struct { @@ -610,6 +622,8 @@ coff_add (struct backtrace_state *state, int descriptor, int debug_view_valid; int is_64; uintptr_t image_base; + uintptr_t base_address = 0; + uintptr_t module_handle; struct dwarf_sections dwarf_sections; *found_sym = 0; @@ -856,7 +870,12 @@ coff_add (struct backtrace_state *state, int descriptor, + (sections[i].offset - min_offset)); } - if (!backtrace_dwarf_add (state, /* base_address */ 0, _sections, +#ifdef HAVE_WINDOWS_H +module_handle = (uintptr_t) GetModuleHandleW (NULL); +base_address = module_handle - image_base; +#endif + + if (!backtrace_dwarf_add (state, base_address, _sections, 0, /* FIXME: is_bigendian */ NULL, /* altlink */ error_callback, data, fileline_fn, -- 2.38.1
[PATCH 4/4] libbacktrace: get debug information for loaded dlls
From: Björn Schäpers Fixes https://github.com/ianlancetaylor/libbacktrace/issues/53, except that libraries loaded after the backtrace_initialize are not handled. But as far as I can see that's the same for elf. Tested on x86_64-linux and i686-w64-mingw32. -- >8 -- * pecoff.c (coff_add): New argument for the module handle of the file, to get the base address. * pecoff.c (backtrace_initialize): Iterate over loaded libraries and call coff_add. Signed-off-by: Björn Schäpers --- libbacktrace/pecoff.c | 76 --- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/libbacktrace/pecoff.c b/libbacktrace/pecoff.c index 296f1357b5f..40395109e51 100644 --- a/libbacktrace/pecoff.c +++ b/libbacktrace/pecoff.c @@ -49,6 +49,7 @@ POSSIBILITY OF SUCH DAMAGE. */ #endif #include +#include #endif /* Coff file header. */ @@ -592,7 +593,8 @@ coff_syminfo (struct backtrace_state *state, uintptr_t addr, static int coff_add (struct backtrace_state *state, int descriptor, backtrace_error_callback error_callback, void *data, - fileline *fileline_fn, int *found_sym, int *found_dwarf) + fileline *fileline_fn, int *found_sym, int *found_dwarf, + uintptr_t module_handle ATTRIBUTE_UNUSED) { struct backtrace_view fhdr_view; off_t fhdr_off; @@ -623,7 +625,6 @@ coff_add (struct backtrace_state *state, int descriptor, int is_64; uintptr_t image_base; uintptr_t base_address = 0; - uintptr_t module_handle; struct dwarf_sections dwarf_sections; *found_sym = 0; @@ -871,7 +872,6 @@ coff_add (struct backtrace_state *state, int descriptor, } #ifdef HAVE_WINDOWS_H -module_handle = (uintptr_t) GetModuleHandleW (NULL); base_address = module_handle - image_base; #endif @@ -914,12 +914,80 @@ backtrace_initialize (struct backtrace_state *state, int found_sym; int found_dwarf; fileline coff_fileline_fn; + uintptr_t module_handle = 0; + +#ifdef HAVE_WINDOWS_H + DWORD i; + DWORD module_count; + DWORD bytes_needed_for_modules; + HMODULE *modules; + char module_name[MAX_PATH]; + int module_found_sym; + fileline module_fileline_fn; + + module_handle = (uintptr_t) GetModuleHandleW (NULL); +#endif ret = coff_add (state, descriptor, error_callback, data, - _fileline_fn, _sym, _dwarf); + _fileline_fn, _sym, _dwarf, module_handle); if (!ret) return 0; +#ifdef HAVE_WINDOWS_H + module_count = 1000; + alloc_modules: + modules = backtrace_alloc (state, module_count * sizeof(HMODULE), +error_callback, data); + if (modules == NULL) +goto skip_modules; + if (!EnumProcessModules (GetCurrentProcess (), modules, module_count, + _needed_for_modules)) +{ + error_callback(data, "Could not enumerate process modules", +(int) GetLastError ()); + goto free_modules; +} + if (bytes_needed_for_modules > module_count * sizeof(HMODULE)) +{ + backtrace_free (state, modules, module_count * sizeof(HMODULE), + error_callback, data); + // Add an extra of 2, if some module is loaded in another thread. + module_count = bytes_needed_for_modules / sizeof(HMODULE) + 2; + modules = NULL; + goto alloc_modules; +} + + for (i = 0; i < bytes_needed_for_modules / sizeof(HMODULE); ++i) +{ + if (GetModuleFileNameA (modules[i], module_name, MAX_PATH - 1)) + { + if (strcmp (filename, module_name) == 0) + continue; + + module_handle = (uintptr_t) GetModuleHandleA (module_name); + if (module_handle == 0) + continue; + + descriptor = backtrace_open (module_name, error_callback, data, NULL); + if (descriptor < 0) + continue; + + coff_add (state, descriptor, error_callback, data, + _fileline_fn, _found_sym, _dwarf, + module_handle); + if (module_found_sym) + found_sym = 1; + } +} + + free_modules: + if (modules) +backtrace_free(state, modules, module_count * sizeof(HMODULE), + error_callback, data); + modules = NULL; + skip_modules: +#endif + if (!state->threaded) { if (found_sym) -- 2.38.1
[PATCH 1/4] libbacktrace: change all pc related variables to uintptr_t
From: Björn Schäpers It's the right thing to do, since the PC shouldn't go out of the uintptr_t domain, and in backtrace_pcinfo the pc is uintptr_t. This is a preparation for a following patch. Tested on x86_64-linux and i686-w64-mingw32. -- >8 -- * dwarf.c: changed variables holding pc values from uint64_t to uintptr_t. Signed-off-by: Björn Schäpers --- libbacktrace/dwarf.c | 44 ++-- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/libbacktrace/dwarf.c b/libbacktrace/dwarf.c index 45cc9e77e40..0707ccddd3e 100644 --- a/libbacktrace/dwarf.c +++ b/libbacktrace/dwarf.c @@ -274,8 +274,8 @@ struct function struct function_addrs { /* Range is LOW <= PC < HIGH. */ - uint64_t low; - uint64_t high; + uintptr_t low; + uintptr_t high; /* Function for this address range. */ struct function *function; }; @@ -356,8 +356,8 @@ struct unit struct unit_addrs { /* Range is LOW <= PC < HIGH. */ - uint64_t low; - uint64_t high; + uintptr_t low; + uintptr_t high; /* Compilation unit for this address range. */ struct unit *u; }; @@ -1094,7 +1094,7 @@ resolve_addr_index (const struct dwarf_sections *dwarf_sections, uint64_t addr_base, int addrsize, int is_bigendian, uint64_t addr_index, backtrace_error_callback error_callback, void *data, - uint64_t *address) + uintptr_t *address) { uint64_t offset; struct dwarf_buf addr_buf; @@ -1194,7 +1194,7 @@ function_addrs_search (const void *vkey, const void *ventry) static int add_unit_addr (struct backtrace_state *state, void *rdata, - uint64_t lowpc, uint64_t highpc, + uintptr_t lowpc, uintptr_t highpc, backtrace_error_callback error_callback, void *data, void *pvec) { @@ -1530,10 +1530,10 @@ lookup_abbrev (struct abbrevs *abbrevs, uint64_t code, lowpc/highpc is set or ranges is set. */ struct pcrange { - uint64_t lowpc; /* The low PC value. */ + uintptr_t lowpc; /* The low PC value. */ int have_lowpc; /* Whether a low PC value was found. */ int lowpc_is_addr_index; /* Whether lowpc is in .debug_addr. */ - uint64_t highpc; /* The high PC value. */ + uintptr_t highpc;/* The high PC value. */ int have_highpc; /* Whether a high PC value was found. */ int highpc_is_relative; /* Whether highpc is relative to lowpc. */ int highpc_is_addr_index;/* Whether highpc is in .debug_addr. */ @@ -1613,16 +1613,16 @@ add_low_high_range (struct backtrace_state *state, uintptr_t base_address, int is_bigendian, struct unit *u, const struct pcrange *pcrange, int (*add_range) (struct backtrace_state *state, - void *rdata, uint64_t lowpc, - uint64_t highpc, + void *rdata, uintptr_t lowpc, + uintptr_t highpc, backtrace_error_callback error_callback, void *data, void *vec), void *rdata, backtrace_error_callback error_callback, void *data, void *vec) { - uint64_t lowpc; - uint64_t highpc; + uintptr_t lowpc; + uintptr_t highpc; lowpc = pcrange->lowpc; if (pcrange->lowpc_is_addr_index) @@ -1663,7 +1663,7 @@ add_ranges_from_ranges ( struct unit *u, uint64_t base, const struct pcrange *pcrange, int (*add_range) (struct backtrace_state *state, void *rdata, - uint64_t lowpc, uint64_t highpc, + uintptr_t lowpc, uintptr_t highpc, backtrace_error_callback error_callback, void *data, void *vec), void *rdata, @@ -1727,10 +1727,10 @@ add_ranges_from_rnglists ( struct backtrace_state *state, const struct dwarf_sections *dwarf_sections, uintptr_t base_address, int is_bigendian, -struct unit *u, uint64_t base, +struct unit *u, uintptr_t base, const struct pcrange *pcrange, int (*add_range) (struct backtrace_state *state, void *rdata, - uint64_t lowpc, uint64_t highpc, + uintptr_t lowpc, uintptr_t highpc, backtrace_error_callback error_callback, void *data, void *vec), void *rdata, @@ -1796,8 +1796,8 @@ add_ranges_from_rnglists ( case DW_RLE_startx_endx: { uint64_t index; - uint64_t low; - uint64_t high; + uintptr_t low; + uintptr_t high; index = read_uleb128 (_buf); if (!resolve_addr_index (dwarf_sections, u->addr_base, @@ -1819,8 +1819,8 @@
Re: [PATCH] libstdc++: Add error handler for
One could (for a manual test) always change libbacktrace to call the callback. Or invoke it on a platform where libbacktrace can't figure out the executable path on its own, like currently windows. As for an automated test, I have no idea how to enforce that, without changing the code to be tested. Björn. Am 30.11.2022 um 07:04 schrieb François Dumont: Good catch, then we also need this patch. I still need to test it thought, just to make sure it compiles. Unless you have a nice way to force call to the error callback ? François On 29/11/22 22:41, Björn Schäpers wrote: From: Björn Schäpers Not providing an error handler results in a nullpointer dereference when an error occurs. libstdc++-v3/ChangeLog * include/std/stacktrace: Add __backtrace_error_handler and use it in all calls to libbacktrace. --- libstdc++-v3/include/std/stacktrace | 21 ++--- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/libstdc++-v3/include/std/stacktrace b/libstdc++-v3/include/std/stacktrace index e7cbbee5638..b786441cbad 100644 --- a/libstdc++-v3/include/std/stacktrace +++ b/libstdc++-v3/include/std/stacktrace @@ -85,6 +85,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #define __cpp_lib_stacktrace 202011L + inline void + __backtrace_error_handler(void*, const char*, int) {} + // [stacktrace.entry], class stacktrace_entry class stacktrace_entry { @@ -159,7 +162,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _S_init() { static __glibcxx_backtrace_state* __state - = __glibcxx_backtrace_create_state(nullptr, 1, nullptr, nullptr); + = __glibcxx_backtrace_create_state(nullptr, 1, + __backtrace_error_handler, nullptr); return __state; } @@ -192,7 +196,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return __function != nullptr; }; const auto __state = _S_init(); - if (::__glibcxx_backtrace_pcinfo(__state, _M_pc, +__cb, nullptr, &__data)) + if (::__glibcxx_backtrace_pcinfo(__state, _M_pc, +__cb, + __backtrace_error_handler, &__data)) return true; if (__desc && __desc->empty()) { @@ -201,8 +206,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (__symname) *static_cast<_Data*>(__data)->_M_desc = _S_demangle(__symname); }; - if (::__glibcxx_backtrace_syminfo(__state, _M_pc, +__cb2, nullptr, - &__data)) + if (::__glibcxx_backtrace_syminfo(__state, _M_pc, +__cb2, + __backtrace_error_handler, &__data)) return true; } return false; @@ -252,7 +257,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (auto __cb = __ret._M_prepare()) [[likely]] { auto __state = stacktrace_entry::_S_init(); - if (__glibcxx_backtrace_simple(__state, 1, __cb, nullptr, + if (__glibcxx_backtrace_simple(__state, 1, __cb, + __backtrace_error_handler, std::__addressof(__ret))) __ret._M_clear(); } @@ -270,7 +276,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (auto __cb = __ret._M_prepare()) [[likely]] { auto __state = stacktrace_entry::_S_init(); - if (__glibcxx_backtrace_simple(__state, __skip + 1, __cb, nullptr, + if (__glibcxx_backtrace_simple(__state, __skip + 1, __cb, + __backtrace_error_handler, std::__addressof(__ret))) __ret._M_clear(); } @@ -294,7 +301,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { auto __state = stacktrace_entry::_S_init(); int __err = __glibcxx_backtrace_simple(__state, __skip + 1, __cb, - nullptr, + __backtrace_error_handler, std::__addressof(__ret)); if (__err < 0) __ret._M_clear();
Fwd: [PATCH] libstdc++: Add error handler for
Weitergeleitete Nachricht Betreff: [PATCH] libstdc++: Add error handler for Datum: Tue, 29 Nov 2022 22:41:07 +0100 Von: Björn Schäpers An: gcc-patc...@gc.gnu.org, libstd...@gcc.gnu.org From: Björn Schäpers Not providing an error handler results in a nullpointer dereference when an error occurs. libstdc++-v3/ChangeLog * include/std/stacktrace: Add __backtrace_error_handler and use it in all calls to libbacktrace. --- libstdc++-v3/include/std/stacktrace | 21 ++--- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/libstdc++-v3/include/std/stacktrace b/libstdc++-v3/include/std/stacktrace index e7cbbee5638..b786441cbad 100644 --- a/libstdc++-v3/include/std/stacktrace +++ b/libstdc++-v3/include/std/stacktrace @@ -85,6 +85,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #define __cpp_lib_stacktrace 202011L + inline void + __backtrace_error_handler(void*, const char*, int) {} + // [stacktrace.entry], class stacktrace_entry class stacktrace_entry { @@ -159,7 +162,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _S_init() { static __glibcxx_backtrace_state* __state - = __glibcxx_backtrace_create_state(nullptr, 1, nullptr, nullptr); + = __glibcxx_backtrace_create_state(nullptr, 1, + __backtrace_error_handler, nullptr); return __state; } @@ -192,7 +196,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return __function != nullptr; }; const auto __state = _S_init(); - if (::__glibcxx_backtrace_pcinfo(__state, _M_pc, +__cb, nullptr, &__data)) + if (::__glibcxx_backtrace_pcinfo(__state, _M_pc, +__cb, + __backtrace_error_handler, &__data)) return true; if (__desc && __desc->empty()) { @@ -201,8 +206,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (__symname) *static_cast<_Data*>(__data)->_M_desc = _S_demangle(__symname); }; - if (::__glibcxx_backtrace_syminfo(__state, _M_pc, +__cb2, nullptr, - &__data)) + if (::__glibcxx_backtrace_syminfo(__state, _M_pc, +__cb2, + __backtrace_error_handler, &__data)) return true; } return false; @@ -252,7 +257,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (auto __cb = __ret._M_prepare()) [[likely]] { auto __state = stacktrace_entry::_S_init(); - if (__glibcxx_backtrace_simple(__state, 1, __cb, nullptr, + if (__glibcxx_backtrace_simple(__state, 1, __cb, + __backtrace_error_handler, std::__addressof(__ret))) __ret._M_clear(); } @@ -270,7 +276,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (auto __cb = __ret._M_prepare()) [[likely]] { auto __state = stacktrace_entry::_S_init(); - if (__glibcxx_backtrace_simple(__state, __skip + 1, __cb, nullptr, + if (__glibcxx_backtrace_simple(__state, __skip + 1, __cb, + __backtrace_error_handler, std::__addressof(__ret))) __ret._M_clear(); } @@ -294,7 +301,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { auto __state = stacktrace_entry::_S_init(); int __err = __glibcxx_backtrace_simple(__state, __skip + 1, __cb, - nullptr, + __backtrace_error_handler, std::__addressof(__ret)); if (__err < 0) __ret._M_clear(); -- 2.38.1