info: Load DbgHelp.dll using g_module_open()
authorSeungha Yang <seungha@centricular.com>
Tue, 15 Sep 2020 12:07:27 +0000 (21:07 +0900)
committerGStreamer Merge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Wed, 30 Sep 2020 18:51:40 +0000 (18:51 +0000)
... and update meson file so that enable it only using required headers.

"dependency(...)" is unlikely successful for Windows SDK libraries
since it doesn't ship pkg-config file. So it needs to be changed
to "find_library()" to link corresponding .lib file. That would
result to most MSVC build system will link dbghelp.dll. However,
one drawback of the change is that gstreamer-1.0.dll will mandate
dbghelp.dll although it should be optional. So g_module_open() way
can be the most safe way in this case.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/626>

gst/gstinfo.c
meson.build

index 37987d3..f38c18d 100644 (file)
@@ -156,9 +156,10 @@ static char *gst_info_printf_pointer_extension_func (const char *format,
 #endif /* HAVE_BACKTRACE */
 
 #ifdef HAVE_DBGHELP
-#include <Windows.h>
+#include <windows.h>
 #include <dbghelp.h>
 #include <tlhelp32.h>
+#include <gmodule.h>
 #endif /* HAVE_DBGHELP */
 
 #ifdef G_OS_WIN32
@@ -2958,19 +2959,91 @@ generate_backtrace_trace (void)
 #endif /* HAVE_BACKTRACE */
 
 #ifdef HAVE_DBGHELP
-static void
+/* *INDENT-OFF* */
+static struct
+{
+  DWORD (WINAPI * pSymSetOptions) (DWORD SymOptions);
+  BOOL  (WINAPI * pSymInitialize) (HANDLE hProcess,
+                                   PCSTR UserSearchPath,
+                                   BOOL fInvadeProcess);
+  BOOL  (WINAPI * pStackWalk64)   (DWORD MachineType,
+                                   HANDLE hProcess,
+                                   HANDLE hThread,
+                                   LPSTACKFRAME64 StackFrame,
+                                   PVOID ContextRecord,
+                                   PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
+                                   PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
+                                   PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
+                                   PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
+  PVOID (WINAPI * pSymFunctionTableAccess64) (HANDLE hProcess,
+                                              DWORD64 AddrBase);
+  DWORD64 (WINAPI * pSymGetModuleBase64) (HANDLE hProcess,
+                                          DWORD64 qwAddr);
+  BOOL (WINAPI * pSymFromAddr) (HANDLE hProcess,
+                                DWORD64 Address,
+                                PDWORD64 Displacement,
+                                PSYMBOL_INFO Symbol);
+  BOOL (WINAPI * pSymGetModuleInfo64) (HANDLE hProcess,
+                                       DWORD64 qwAddr,
+                                       PIMAGEHLP_MODULE64 ModuleInfo);
+  BOOL (WINAPI * pSymGetLineFromAddr64) (HANDLE hProcess,
+                                         DWORD64 qwAddr,
+                                         PDWORD pdwDisplacement,
+                                         PIMAGEHLP_LINE64 Line64);
+} dbg_help_vtable = { NULL,};
+/* *INDENT-ON* */
+
+static GModule *dbg_help_module = NULL;
+
+static gboolean
+dbghelp_load_symbol (const gchar * symbol_name, gpointer * symbol)
+{
+  if (dbg_help_module &&
+      !g_module_symbol (dbg_help_module, symbol_name, symbol)) {
+    GST_WARNING ("Cannot load %s symbol", symbol_name);
+    g_module_close (dbg_help_module);
+    dbg_help_module = NULL;
+  }
+
+  return ! !dbg_help_module;
+}
+
+static gboolean
 dbghelp_initialize_symbols (HANDLE process)
 {
   static gsize initialization_value = 0;
 
   if (g_once_init_enter (&initialization_value)) {
     GST_INFO ("Initializing Windows symbol handler");
-    SymSetOptions (SYMOPT_LOAD_LINES);
-    SymInitialize (process, NULL, TRUE);
-    GST_INFO ("Initialized Windows symbol handler");
+
+    dbg_help_module = g_module_open ("dbghelp.dll", G_MODULE_BIND_LAZY);
+    dbghelp_load_symbol ("SymSetOptions",
+        (gpointer *) & dbg_help_vtable.pSymSetOptions);
+    dbghelp_load_symbol ("SymInitialize",
+        (gpointer *) & dbg_help_vtable.pSymInitialize);
+    dbghelp_load_symbol ("StackWalk64",
+        (gpointer *) & dbg_help_vtable.pStackWalk64);
+    dbghelp_load_symbol ("SymFunctionTableAccess64",
+        (gpointer *) & dbg_help_vtable.pSymFunctionTableAccess64);
+    dbghelp_load_symbol ("SymGetModuleBase64",
+        (gpointer *) & dbg_help_vtable.pSymGetModuleBase64);
+    dbghelp_load_symbol ("SymFromAddr",
+        (gpointer *) & dbg_help_vtable.pSymFromAddr);
+    dbghelp_load_symbol ("SymGetModuleInfo64",
+        (gpointer *) & dbg_help_vtable.pSymGetModuleInfo64);
+    dbghelp_load_symbol ("SymGetLineFromAddr64",
+        (gpointer *) & dbg_help_vtable.pSymGetLineFromAddr64);
+
+    if (dbg_help_module) {
+      dbg_help_vtable.pSymSetOptions (SYMOPT_LOAD_LINES);
+      dbg_help_vtable.pSymInitialize (process, NULL, TRUE);
+      GST_INFO ("Initialized Windows symbol handler");
+    }
 
     g_once_init_leave (&initialization_value, 1);
   }
+
+  return ! !dbg_help_module;
 }
 
 static gchar *
@@ -2983,9 +3056,12 @@ generate_dbghelp_trace (void)
   CONTEXT context;
   STACKFRAME64 frame = { 0 };
   PVOID save_context;
-  GString *trace = g_string_new (NULL);
+  GString *trace = NULL;
 
-  dbghelp_initialize_symbols (process);
+  if (!dbghelp_initialize_symbols (process))
+    return NULL;
+
+  trace = g_string_new (NULL);
 
   memset (&context, 0, sizeof (CONTEXT));
   context.ContextFlags = CONTEXT_FULL;
@@ -3024,19 +3100,23 @@ generate_dbghelp_trace (void)
 
     line.SizeOfStruct = sizeof (line);
 
-    if (!StackWalk64 (machine, process, thread, &frame, save_context, 0,
-            SymFunctionTableAccess64, SymGetModuleBase64, 0))
+    if (!dbg_help_vtable.pStackWalk64 (machine, process, thread, &frame,
+            save_context, 0, dbg_help_vtable.pSymFunctionTableAccess64,
+            dbg_help_vtable.pSymGetModuleBase64, 0)) {
       break;
+    }
 
-    if (SymFromAddr (process, frame.AddrPC.Offset, 0, symbol))
+    if (dbg_help_vtable.pSymFromAddr (process, frame.AddrPC.Offset, 0, symbol))
       g_string_append_printf (trace, "%s ", symbol->Name);
     else
       g_string_append (trace, "?? ");
 
-    if (SymGetLineFromAddr64 (process, frame.AddrPC.Offset, &displacement,
-            &line))
-      g_string_append_printf (trace, "(%s:%u)", line.FileName, line.LineNumber);
-    else if (SymGetModuleInfo64 (process, frame.AddrPC.Offset, &module_info))
+    if (dbg_help_vtable.pSymGetLineFromAddr64 (process, frame.AddrPC.Offset,
+            &displacement, &line))
+      g_string_append_printf (trace, "(%s:%lu)", line.FileName,
+          line.LineNumber);
+    else if (dbg_help_vtable.pSymGetModuleInfo64 (process, frame.AddrPC.Offset,
+            &module_info))
       g_string_append_printf (trace, "(%s)", module_info.ImageName);
     else
       g_string_append_printf (trace, "(%s)", "??");
@@ -3044,7 +3124,6 @@ generate_dbghelp_trace (void)
     g_string_append (trace, "\n");
   }
 
-done:
   return g_string_free (trace, FALSE);
 }
 #endif /* HAVE_DBGHELP */
index 6493b78..492373f 100644 (file)
@@ -370,12 +370,13 @@ endif
 backtrace_deps = []
 unwind_dep = dependency('libunwind', required : get_option('libunwind'))
 dw_dep = dependency('libdw', required: get_option('libdw'))
-dbghelp_dep = dependency('DbgHelp', required : get_option('dbghelp'))
-backtrace_deps = [unwind_dep, dw_dep, dbghelp_dep]
+dbghelp_option = get_option('dbghelp')
+have_dbghelp = cc.has_header('dbghelp.h', required: dbghelp_option) and cc.has_header('tlhelp32.h', required: dbghelp_option)
+backtrace_deps = [unwind_dep, dw_dep]
 backtrace_source_info = false
 backtrace_minimal = false
 # MSVC debug stack trace support
-if host_system == 'windows' and dbghelp_dep.found()
+if host_system == 'windows' and have_dbghelp
   cdata.set('HAVE_DBGHELP', 1)
   backtrace_source_info = true
 # DWARF stack trace support with libunwind and elf-utils