Merge pull request #2763 from Sonicadvance1/fix_x11_variadic_thunks

Thunks/X11: Fixes variadic packing and callbacks.
This commit is contained in:
Ryan Houdek authored and GitHub committed 2023-07-21 01:49:26 -07:00
commit 82295b2943
4 files changed
+2331 -344

No files matched your search

+25
View File
@@ -0,0 +1,25 @@
#pragma once
#include <array>
#include <string>
extern "C" {
#include <X11/Xlib.h>
}
namespace X11 {
constexpr static std::array<std::string_view, 13> CallbackKeys = {{
XNGeometryCallback,
XNDestroyCallback,
XNPreeditStartCallback,
XNPreeditDoneCallback,
XNPreeditDrawCallback,
XNPreeditCaretCallback,
XNPreeditStateNotifyCallback,
XNStatusStartCallback,
XNStatusDoneCallback,
XNStatusDrawCallback,
XNR6PreeditCallback,
XNStringConversionCallback,
}};
}
+191 -90
View File
@@ -20,134 +20,214 @@ extern "C" {
#undef max
}
#include <algorithm>
#include <array>
#include <cassert>
#include <cstdint>
#include <stdio.h>
#include <cstring>
#include <map>
#include <list>
#include <string>
#include <unistd.h>
#include "common/Guest.h"
#include <stdarg.h>
#include "thunkgen_guest_libX11.inl"
#include "X11Common.h"
// Custom implementations //
#include <vector>
namespace {
// The various X11 variadic functions take a flattened sequence of key:value pairs as arguments.
// The key element is a pointer to a string.
// The value element is a pointer to the data of that key type.
//
// Some keys describe function callbacks for various events that the server interface can call.
// FEX needs to walk these keys and ensure any callback function has a trampoline so the native
// X11 library can call it.
template<typename CallbackType>
static std::list<CallbackType> ConvertCallbackArguments(std::vector<void*> &IncomingArguments) {
assert(IncomingArguments.size() % 2 == 0 && "Incoming arguments needs to be in pairs");
std::list<CallbackType> Callbacks;
// Walk the arguments and convert any callbacks.
const size_t ArgumentPairs = IncomingArguments.size() / 2;
for (size_t i = 0; i < ArgumentPairs; ++i) {
const char *Key = static_cast<const char*>(IncomingArguments[i * 2]);
void** Data = &IncomingArguments[i * 2 + 1];
if (!*Data) {
continue;
}
// Check if the key is a callback and needs to be modified.
auto KeyIt = std::find(X11::CallbackKeys.begin(), X11::CallbackKeys.end(), Key);
if (KeyIt == X11::CallbackKeys.end()) {
continue;
}
// Key matches a callback, we need to wrap this.
CallbackType *IncomingCallback = reinterpret_cast<CallbackType*>(*Data);
CallbackType *ConvertedCallback = &Callbacks.emplace_back(CallbackType {
// Client data stays the same.
.client_data = IncomingCallback->client_data,
// Callback needs a trampoline.
.callback = AllocateHostTrampolineForGuestFunction(IncomingCallback->callback),
});
// Add this converted back in.
*Data = ConvertedCallback;
}
return Callbacks;
}
}
extern "C" {
char* XGetICValues(XIC ic, ...) {
fprintf(stderr, "XGetICValues\n");
va_list ap;
std::vector<unsigned long> args;
va_start(ap, ic);
for (;;) {
auto arg = va_arg(ap, unsigned long);
if (arg == 0)
break;
args.push_back(arg);
fprintf(stderr, "%016lX\n", arg);
}
fprintf(stderr, "XGetICValues\n");
va_list ap;
std::vector<void*> args;
va_start(ap, ic);
for (;;) {
auto arg = va_arg(ap, void*);
if (arg == 0)
break;
args.push_back(arg);
fprintf(stderr, "%p\n", arg);
}
va_end(ap);
auto rv = fexfn_pack_XGetICValues_internal(ic, args.size(), &args[0]);
fprintf(stderr, "RV: %p\n", rv);
return rv;
va_end(ap);
auto rv = fexfn_pack_XGetICValues_internal(ic, args.size(), &args[0]);
fprintf(stderr, "RV: %p\n", rv);
return rv;
}
char* XSetICValues(XIC ic, ...) {
fprintf(stderr, "XSetICValues\n");
va_list ap;
std::vector<unsigned long> args;
va_start(ap, ic);
for (;;) {
auto arg = va_arg(ap, unsigned long);
if (arg == 0)
break;
args.push_back(arg);
fprintf(stderr, "%016lX\n", arg);
}
fprintf(stderr, "XSetICValues\n");
va_list ap;
std::vector<void*> IncomingArguments;
va_start(ap, ic);
for (;;) {
auto Key = va_arg(ap, void*);
if (Key == 0)
break;
va_end(ap);
auto rv = fexfn_pack_XSetICValues_internal(ic, args.size(), &args[0]);
fprintf(stderr, "RV: %p\n", rv);
return rv;
auto Value = va_arg(ap, void*);
IncomingArguments.emplace_back(Key);
IncomingArguments.emplace_back(Value);
}
va_end(ap);
// Callback memory needs to live beyond internal function call.
std::list<XICCallback> Callbacks = ConvertCallbackArguments<XICCallback>(IncomingArguments);
auto rv = fexfn_pack_XSetICValues_internal(ic, IncomingArguments.size(), &IncomingArguments[0]);
fprintf(stderr, "RV: %p\n", rv);
return rv;
}
char* XGetIMValues(XIM ic, ...) {
fprintf(stderr, "XGetIMValues\n");
va_list ap;
std::vector<void*> args;
va_start(ap, ic);
for (;;) {
auto arg = va_arg(ap, void*);
if (arg == 0)
break;
args.push_back(arg);
fprintf(stderr, "%p\n", arg);
}
fprintf(stderr, "XGetIMValues\n");
va_list ap;
std::vector<void*> args;
va_start(ap, ic);
for (;;) {
auto arg = va_arg(ap, void*);
if (arg == 0)
break;
args.push_back(arg);
fprintf(stderr, "%p\n", arg);
}
va_end(ap);
auto rv = fexfn_pack_XGetIMValues_internal(ic, args.size(), &args[0]);
fprintf(stderr, "RV: %p\n", rv);
return rv;
va_end(ap);
auto rv = fexfn_pack_XGetIMValues_internal(ic, args.size(), &args[0]);
fprintf(stderr, "RV: %p\n", rv);
return rv;
}
char* XSetIMValues(XIM ic, ...) {
fprintf(stderr, "XSetIMValues\n");
va_list ap;
std::vector<void*> args;
va_start(ap, ic);
for (;;) {
auto arg = va_arg(ap, void*);
if (arg == 0)
break;
args.push_back(arg);
fprintf(stderr, "%p\n", arg);
}
fprintf(stderr, "XSetIMValues\n");
va_list ap;
std::vector<void*> IncomingArguments;
va_start(ap, ic);
for (;;) {
auto Key = va_arg(ap, void*);
if (Key == 0)
break;
va_end(ap);
auto rv = fexfn_pack_XSetIMValues_internal(ic, args.size(), &args[0]);
fprintf(stderr, "RV: %p\n", rv);
return rv;
auto Value = va_arg(ap, void*);
IncomingArguments.emplace_back(Key);
IncomingArguments.emplace_back(Value);
fprintf(stderr, "%s\n", (char*)Key);
}
va_end(ap);
// Callback memory needs to live beyond internal function call.
std::list<XIMCallback> Callbacks = ConvertCallbackArguments<XIMCallback>(IncomingArguments);
// Send a count (not including nullptr);
auto rv = fexfn_pack_XSetIMValues_internal(ic, IncomingArguments.size(), &IncomingArguments[0]);
fprintf(stderr, "RV: %p\n", rv);
return rv;
}
_XIC* XCreateIC(XIM im, ...) {
fprintf(stderr, "XCreateIC\n");
va_list ap;
std::vector<unsigned long> args;
va_start(ap, im);
for (;;) {
auto arg = va_arg(ap, unsigned long);
if (arg == 0)
break;
args.push_back(arg);
fprintf(stderr, "%016lX\n", arg);
}
fprintf(stderr, "XCreateIC\n");
va_list ap;
std::vector<void*> IncomingArguments;
va_end(ap);
auto rv = fexfn_pack_XCreateIC_internal(im, args.size(), &args[0]);
fprintf(stderr, "RV: %p\n", rv);
return rv;
va_start(ap, im);
for (;;) {
auto Key = va_arg(ap, void*);
if (Key == 0)
break;
auto Value = va_arg(ap, void*);
IncomingArguments.emplace_back(Key);
IncomingArguments.emplace_back(Value);
}
va_end(ap);
// Callback memory needs to live beyond internal function call.
std::list<XICCallback> Callbacks = ConvertCallbackArguments<XICCallback>(IncomingArguments);
auto rv = fexfn_pack_XCreateIC_internal(im, IncomingArguments.size(), &IncomingArguments[0]);
return rv;
}
XVaNestedList XVaCreateNestedList(int unused_arg, ...) {
fprintf(stderr, "XVaCreateNestedList\n");
va_list ap;
std::vector<void*> args;
va_start(ap, unused_arg);
for (;;) {
auto arg = va_arg(ap, void*);
if (arg == 0)
break;
args.push_back(arg);
fprintf(stderr, "%p\n", arg);
}
fprintf(stderr, "XVaCreateNestedList\n");
va_list ap;
std::vector<void*> IncomingArguments;
va_end(ap);
auto rv = fexfn_pack_XVaCreateNestedList_internal(unused_arg, args.size(), &args[0]);
fprintf(stderr, "RV: %p\n", rv);
return rv;
va_start(ap, unused_arg);
for (;;) {
auto Key = va_arg(ap, void*);
if (Key == 0)
break;
auto Value = va_arg(ap, void*);
IncomingArguments.emplace_back(Key);
IncomingArguments.emplace_back(Value);
}
va_end(ap);
// Callback memory needs to live beyond internal function call.
std::list<XICCallback> Callbacks = ConvertCallbackArguments<XICCallback>(IncomingArguments);
auto rv = fexfn_pack_XVaCreateNestedList_internal(unused_arg, IncomingArguments.size(), &IncomingArguments[0]);
fprintf(stderr, "RV: %p\n", rv);
return rv;
}
static void LockMutexFunction(LockInfoPtr) {
@@ -265,6 +345,27 @@ extern "C" {
return ret;
}
Bool XRegisterIMInstantiateCallback(Display* dpy,
struct _XrmHashBucketRec* rdb,
char* res_name,
char* res_class,
XIDProc callback,
XPointer client_data
) {
return fexfn_pack_XRegisterIMInstantiateCallback(dpy, rdb, res_name, res_class, AllocateHostTrampolineForGuestFunction(callback), client_data);
}
Bool XUnregisterIMInstantiateCallback(
Display* dpy,
struct _XrmHashBucketRec* rdb,
char* res_name,
char* res_class,
XIDProc callback,
XPointer client_data
) {
return fexfn_pack_XUnregisterIMInstantiateCallback(dpy, rdb, res_name, res_class, AllocateHostTrampolineForGuestFunction(callback), client_data);
}
void (*_XLockMutex_fn)(LockInfoPtr) = LockMutexFunction;
void (*_XUnlockMutex_fn)(LockInfoPtr) = UnlockMutexFunction;
LockInfoPtr _Xglobal_lock = (LockInfoPtr)0x4142434445464748ULL;
File diff suppressed because it is too large. Load diff
+12 -8
View File
@@ -45,6 +45,10 @@ template<> struct fex_gen_type<std::remove_pointer_t<XIOErrorExitHandler>> {}; /
template<> struct fex_gen_type<Bool(Display*, xReply*, char*, int, XPointer)> {}; // XDisplay::async_handlers->handler
template<> struct fex_gen_type<Bool(XIM, XPointer, XPointer)> {}; // XIMProc
template<> struct fex_gen_type<Bool(XIC, XPointer, XPointer)> {}; // XICProc
template<> struct fex_gen_type<void(Display*, XPointer, XPointer)> {}; // XIDProc
template<> struct fex_gen_type<int(XImage*)> {}; // XImage::f.destroy_image
template<> struct fex_gen_type<unsigned long(XImage*, int, int)> {}; // XImage::f.get_pixel
template<> struct fex_gen_type<int(XImage*, int, int, unsigned long)> {}; // XImage::f.put_pixel
@@ -653,15 +657,15 @@ template<> struct fex_gen_config<Xutf8DrawImageString> {};
template<> struct fex_gen_config<XOpenIM> {};
template<> struct fex_gen_config<XCloseIM> {};
template<> struct fex_gen_config<XGetIMValues> {
using uniform_va_type = void*;
using uniform_va_type = void*;
};
template<> struct fex_gen_config<XSetIMValues> {
using uniform_va_type = void*;
using uniform_va_type = void*;
};
template<> struct fex_gen_config<XDisplayOfIM> {};
template<> struct fex_gen_config<XLocaleOfIM> {};
template<> struct fex_gen_config<XCreateIC> {
using uniform_va_type = unsigned long;
using uniform_va_type = void*;
};
template<> struct fex_gen_config<XDestroyIC> {};
template<> struct fex_gen_config<XSetICFocus> {};
@@ -670,11 +674,11 @@ template<> struct fex_gen_config<XwcResetIC> {};
template<> struct fex_gen_config<XmbResetIC> {};
template<> struct fex_gen_config<Xutf8ResetIC> {};
template<> struct fex_gen_config<XSetICValues> {
using uniform_va_type = unsigned long;
using uniform_va_type = void*;
};
template<> struct fex_gen_config<XGetICValues> {
using uniform_va_type = unsigned long;
using uniform_va_type = void*;
};
template<> struct fex_gen_config<XIMOfIC> {};
@@ -683,11 +687,11 @@ template<> struct fex_gen_config<XmbLookupString> {};
template<> struct fex_gen_config<XwcLookupString> {};
template<> struct fex_gen_config<Xutf8LookupString> {};
template<> struct fex_gen_config<XVaCreateNestedList> {
using uniform_va_type = void*;
using uniform_va_type = void*;
};
template<> struct fex_gen_config<XRegisterIMInstantiateCallback> {};
template<> struct fex_gen_config<XUnregisterIMInstantiateCallback> {};
template<> struct fex_gen_config<XRegisterIMInstantiateCallback> : fexgen::custom_guest_entrypoint {};
template<> struct fex_gen_config<XUnregisterIMInstantiateCallback> : fexgen::custom_guest_entrypoint {};
template<> struct fex_gen_config<XInternalConnectionNumbers> {};
template<> struct fex_gen_config<XProcessInternalConnection> {};
template<> struct fex_gen_config<XAddConnectionWatch> {};