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 <g...@hazardy.de> wrote:

From: Björn Schäpers <bjo...@hazardy.de>

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 <bjo...@hazardy.de>")?

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?= <bjo...@hazardy.de>
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,
+                         &module_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, &fileline, &found_sym,
+           &found_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
@@ -978,6 +1050,7 @@ backtrace_initialize (struct backtrace_state *state,
 #ifdef HAVE_WINDOWS_H
   fileline module_fileline_fn;
   int module_found_sym;
+  HMODULE nt_dll_handle;
 
 #ifdef HAVE_TLHELP32_H
   HANDLE snapshot;
@@ -1065,6 +1138,33 @@ backtrace_initialize (struct backtrace_state *state,
   if (modules)
     free_modules (state, error_callback, data, &modules, 
bytes_allocated_for_modules);
 #endif
+
+  nt_dll_handle = GetModuleHandle (TEXT ("ntdll.dll"));
+  if (nt_dll_handle)
+    {
+      LDR_REGISTER_FUNCTION register_func;
+      const char register_name[] = "LdrRegisterDllNotification";
+      register_func = (LDR_REGISTER_FUNCTION) 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;
+
+             register_func (0, &dll_notification, context, &cookie);
+           }
+       }
+    }
 #endif
 
   if (!state->threaded)
-- 
2.42.1

Reply via email to