contrib/plugins/win32_linker.c | 23 +++-------------------- include/sysemu/os-win32.h | 25 +++++++++++++++++++++++++ os-win32.c | 33 +++++++++++++++++++++++++++++++++ plugins/loader.c | 3 +++ 4 files changed, 64 insertions(+), 20 deletions(-)
Previously, a plugin author needed an implementation of the
__pfnDliFailureHook2 or __pfnDliNotifyHook2 hook in the plugin. Now all
they need is a null exported pointer with the right name
(win32_common.c). If QEMU finds this, it will set it to the hook
function, which has now moved into qemu (os-win32.c).
---
contrib/plugins/win32_linker.c | 23 +++--------------------
include/sysemu/os-win32.h | 25 +++++++++++++++++++++++++
os-win32.c | 33 +++++++++++++++++++++++++++++++++
plugins/loader.c | 3 +++
4 files changed, 64 insertions(+), 20 deletions(-)
diff --git a/contrib/plugins/win32_linker.c b/contrib/plugins/win32_linker.c
index 7534b2b8bf..619fdd38c8 100644
--- a/contrib/plugins/win32_linker.c
+++ b/contrib/plugins/win32_linker.c
@@ -4,8 +4,8 @@
* This hook, __pfnDliFailureHook2, is documented in the microsoft documentation here:
* https://learn.microsoft.com/en-us/cpp/build/reference/error-handling-and-notification
* It gets called when a delay-loaded DLL encounters various errors.
- * We handle the specific case of a DLL looking for a "qemu.exe",
- * and give it the running executable (regardless of what it is named).
+ * QEMU will set it to a function which handles the specific case of a DLL looking for
+ * a "qemu.exe", and give it the running executable (regardless of what it is named).
*
* This work is licensed under the terms of the GNU LGPL, version 2 or later.
* See the COPYING.LIB file in the top-level directory.
@@ -14,21 +14,4 @@
#include <windows.h>
#include <delayimp.h>
-FARPROC WINAPI dll_failure_hook(unsigned dliNotify, PDelayLoadInfo pdli);
-
-
-PfnDliHook __pfnDliFailureHook2 = dll_failure_hook;
-
-FARPROC WINAPI dll_failure_hook(unsigned dliNotify, PDelayLoadInfo pdli) {
- if (dliNotify == dliFailLoadLib) {
- /* If the failing request was for qemu.exe, ... */
- if (strcmp(pdli->szDll, "qemu.exe") == 0) {
- /* Then pass back a pointer to the top level module. */
- HMODULE top = GetModuleHandle(NULL);
- return (FARPROC) top;
- }
- }
- /* Otherwise we can't do anything special. */
- return 0;
-}
-
+__declspec(dllexport) PfnDliHook __pfnDliNotifyHook2 = NULL;
diff --git a/include/sysemu/os-win32.h b/include/sysemu/os-win32.h
index 1047d260cb..0f698554b2 100644
--- a/include/sysemu/os-win32.h
+++ b/include/sysemu/os-win32.h
@@ -30,6 +30,8 @@
#include <windows.h>
#include <ws2tcpip.h>
#include "qemu/typedefs.h"
+#include <delayimp.h>
+#include <gmodule.h>
#ifdef HAVE_AFUNIX_H
#include <afunix.h>
@@ -265,6 +267,29 @@ win32_close_exception_handler(struct _EXCEPTION_RECORD*, void*,
void *qemu_win32_map_alloc(size_t size, HANDLE *h, Error **errp);
void qemu_win32_map_free(void *ptr, HANDLE h, Error **errp);
+
+/* dll_delaylink_hook:
+ * @dliNotify: Type of event that caused this callback.
+ * @pdli: Extra data about the DLL being loaded
+ *
+ * For more info on the arguments and when this gets invoked see
+ * https://learn.microsoft.com/en-us/cpp/build/reference/understanding-the-helper-function
+ *
+ * This is to be used on windows as the target of a __pfnDliNotifyHook2 or __pfnDliFailureHook2
+ * hook. If the DLL being loaded is 'qemu.exe', it instead passes back a pointer to the main
+ * executable This gets set into plugins to assist with the plugins delay-linking back to the main
+ * executable, if they define an appropriate symbol. */
+FARPROC WINAPI dll_delaylink_hook(unsigned dliNotify, PDelayLoadInfo pdli);
+
+/* set_dll_delaylink_hook:
+ * @mod: pointer to the DLL being loaded
+ *
+ * takes a pointer to a loaded plugin DLL, and tries to find a __pfnDliNotifyHook2 or
+ * __pfnDliFailureHook2 hook. If it finds either one, and its value is null, it sets it to the
+ * address fo dll_delaylink_hook.
+ */
+void set_dll_delaylink_hook(GModule *mod);
+
#ifdef __cplusplus
}
#endif
diff --git a/os-win32.c b/os-win32.c
index 725ad652e8..4a113d1d10 100644
--- a/os-win32.c
+++ b/os-win32.c
@@ -60,3 +60,36 @@ void os_set_line_buffering(void)
setbuf(stdout, NULL);
setbuf(stderr, NULL);
}
+
+FARPROC WINAPI dll_delaylink_hook(unsigned dliNotify, PDelayLoadInfo pdli) {
+ /* If we just tried, or are about to try to load a DLL ... */
+ if (dliNotify == dliFailLoadLib || dliNotify == dliNotePreLoadLibrary) {
+ /* ... if the failing request was for qemu.exe, ... */
+ if (strcmp(pdli->szDll, "qemu.exe") == 0) {
+ /* ... then pass back a pointer to the top level module. */
+ HMODULE top = GetModuleHandle(NULL);
+ return (FARPROC) top;
+ }
+ }
+ /* Otherwise we can't do anything special. */
+ return 0;
+}
+void set_dll_delaylink_hook(GModule *mod) {
+ /* find the __pfnDliFailureHook2 symbol in the DLL.
+ * if found, set it to our handler.
+ */
+ gpointer sym;
+ PfnDliHook *hook;
+ if (g_module_symbol(mod, "__pfnDliFailureHook2", &sym)) {
+ hook = (PfnDliHook*) sym;
+ if (hook != NULL && *hook == NULL) {
+ *hook = &dll_delaylink_hook;
+ }
+ }
+ if (g_module_symbol(mod, "__pfnDliNotifyHook2", &sym)) {
+ hook = (PfnDliHook*) sym;
+ if (hook != NULL && *hook == NULL) {
+ *hook = &dll_delaylink_hook;
+ }
+ }
+}
diff --git a/plugins/loader.c b/plugins/loader.c
index 734c11cae0..7ead9b26e4 100644
--- a/plugins/loader.c
+++ b/plugins/loader.c
@@ -241,6 +241,9 @@ static int plugin_load(struct qemu_plugin_desc *desc, const qemu_info_t *info, E
}
QTAILQ_INSERT_TAIL(&plugin.ctxs, ctx, entry);
ctx->installing = true;
+ #ifdef CONFIG_WIN32
+ set_dll_delaylink_hook(ctx->handle);
+ #endif
rc = install(ctx->id, info, desc->argc, desc->argv);
ctx->installing = false;
if (rc) {
--
2.42.0.windows.1
© 2016 - 2024 Red Hat, Inc.