mirror of
https://github.com/mon/ifs_layeredfs.git
synced 2026-08-26 18:44:22 -05:00
Use my fancy new rust tool for checking DLL compatibility
Some checks failed
Build / build (push) Has been cancelled
Some checks failed
Build / build (push) Has been cancelled
This commit is contained in:
@@ -12,6 +12,14 @@ RUN set -eux; \
|
||||
# container run
|
||||
RUN wine wineboot --init
|
||||
|
||||
RUN set -eux; \
|
||||
curl -fsSL "https://api.github.com/repos/mon/windows-dll-compat-checker/releases/latest" \
|
||||
| jq -r '.assets[] | select(.name | contains("linux-x86_64")) | .browser_download_url' \
|
||||
| xargs curl -fsSL -o /tmp/dll_compat_checker.zip; \
|
||||
unzip /tmp/dll_compat_checker.zip -d /usr/local/bin/; \
|
||||
chmod +x /usr/local/bin/windows_dll_compat_checker; \
|
||||
rm /tmp/dll_compat_checker.zip;
|
||||
|
||||
ENV CROSS_32=/opt/llvm-mingw/toolchain-files/meson/i686-mingw32-clang.ini
|
||||
ENV CROSS_64=/opt/llvm-mingw/toolchain-files/meson/x86_64-mingw32-clang.ini
|
||||
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
import argparse
|
||||
import functools
|
||||
import os
|
||||
from collections.abc import Callable
|
||||
from glob import glob
|
||||
from typing import TypeAlias
|
||||
|
||||
import pefile
|
||||
from requests.utils import CaseInsensitiveDict
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("dll_path", nargs="+")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
Imports: TypeAlias = dict[str, list[tuple[bytes | None, int | None]]]
|
||||
Exports: TypeAlias = list[tuple[bytes | None, int | None]]
|
||||
|
||||
|
||||
class MissingDLL(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class MissingFunction(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def load_imports(paths: list[str]) -> CaseInsensitiveDict[Imports]:
|
||||
dlls = CaseInsensitiveDict()
|
||||
for path in paths:
|
||||
print(f"Loading imports from {path}")
|
||||
pe = pefile.PE(path)
|
||||
imports: Imports = {}
|
||||
total = 0
|
||||
for entry in pe.DIRECTORY_ENTRY_IMPORT:
|
||||
these = []
|
||||
for imp in entry.imports:
|
||||
these.append((imp.name, imp.ordinal))
|
||||
|
||||
imports[entry.dll.decode()] = these
|
||||
total += len(these)
|
||||
|
||||
print(f" ...{total} imports from {len(imports)} DLLs")
|
||||
|
||||
dlls[os.path.basename(path)] = imports
|
||||
|
||||
return dlls
|
||||
|
||||
|
||||
def load_exports(path: str) -> Callable[[], Exports]:
|
||||
@functools.cache
|
||||
def load():
|
||||
print(f"Loading exports from {path}...")
|
||||
pe = pefile.PE(path)
|
||||
exports: Exports = []
|
||||
for exp in pe.DIRECTORY_ENTRY_EXPORT.symbols:
|
||||
exports.append((exp.name, exp.ordinal))
|
||||
|
||||
print(f" ...{len(exports)} exports")
|
||||
|
||||
return exports
|
||||
|
||||
return load
|
||||
|
||||
|
||||
available_functions: CaseInsensitiveDict[Callable[[], Exports]] = CaseInsensitiveDict()
|
||||
for dll in glob("./xp_dlls/*.dll"):
|
||||
available_functions[os.path.basename(dll)] = load_exports(dll)
|
||||
|
||||
loaded_dlls = load_imports(args.dll_path)
|
||||
|
||||
# https://www.geoffchappell.com/studies/windows/win32/kernel32/api/index.htm
|
||||
# my test .dll is 32-bit and these are only in 64
|
||||
ignore_functions = [
|
||||
b"RtlLookupFunctionEntry",
|
||||
b"RtlUnwindEx",
|
||||
b"RtlVirtualUnwind",
|
||||
b"RtlRestoreContext",
|
||||
b"__C_specific_handler",
|
||||
]
|
||||
|
||||
exceptions = []
|
||||
for path, needed_functions in loaded_dlls.items():
|
||||
for dll_name, imports in needed_functions.items():
|
||||
if (dll := available_functions.get(dll_name)) is None:
|
||||
if dll_name not in loaded_dlls:
|
||||
exceptions.append(
|
||||
MissingDLL(
|
||||
f"{path}: Need {dll_name} but it's not in the XP DLLs folder"
|
||||
)
|
||||
)
|
||||
continue
|
||||
|
||||
dll = dll()
|
||||
|
||||
for name, ordinal in imports:
|
||||
if name is not None:
|
||||
if name in ignore_functions:
|
||||
continue
|
||||
|
||||
if next((fn for fn in dll if fn[0] == name), None) is None:
|
||||
exceptions.append(
|
||||
MissingFunction(
|
||||
f'{path}: Function "{name}" not present in XP {dll_name}'
|
||||
)
|
||||
)
|
||||
continue
|
||||
elif ordinal is not None:
|
||||
if next((fn for fn in dll if fn[1] == ordinal), None) is None:
|
||||
exceptions.append(
|
||||
MissingFunction(
|
||||
f"{path}: Function with ordinal {ordinal} not present in XP {dll_name}"
|
||||
)
|
||||
)
|
||||
continue
|
||||
else:
|
||||
raise RuntimeError(f"{path}: Import with no name or ordinal???")
|
||||
|
||||
if exceptions:
|
||||
raise ExceptionGroup("Failures", exceptions)
|
||||
|
||||
print("All functions present!")
|
||||
43
meson.build
43
meson.build
@@ -111,7 +111,12 @@ if host_machine.cpu_family() == 'x86'
|
||||
)
|
||||
endif
|
||||
|
||||
python = import('python').find_installation()
|
||||
windows_dll_compat_checker = find_program('windows_dll_compat_checker', required: false)
|
||||
if host_machine.cpu_family() == 'x86_64'
|
||||
xp_check_ini = 'PREMADE/winxp_x86_64.ini'
|
||||
else
|
||||
xp_check_ini = 'PREMADE/winxp_x86_64_32bit_dlls.ini'
|
||||
endif
|
||||
|
||||
foreach cfg : special_cfgs
|
||||
folder_name = cfg[0]
|
||||
@@ -139,14 +144,16 @@ foreach cfg : special_cfgs
|
||||
install_dir: install_dir,
|
||||
install: true,
|
||||
)
|
||||
test(lib_name + '_is_xp',
|
||||
python,
|
||||
args: [
|
||||
files('ensure_xp_compatible.py'),
|
||||
ifs_dll,
|
||||
],
|
||||
workdir: meson.current_source_dir(),
|
||||
)
|
||||
if windows_dll_compat_checker.found()
|
||||
test(lib_name + '_is_xp',
|
||||
windows_dll_compat_checker,
|
||||
args: [
|
||||
ifs_dll,
|
||||
'-s', xp_check_ini,
|
||||
],
|
||||
workdir: meson.current_source_dir(),
|
||||
)
|
||||
endif
|
||||
endforeach
|
||||
|
||||
injector_cfgs = [
|
||||
@@ -183,14 +190,16 @@ foreach cfg : injector_cfgs
|
||||
install: true,
|
||||
)
|
||||
|
||||
test(dll_name + '_is_xp',
|
||||
python,
|
||||
args: [
|
||||
files('ensure_xp_compatible.py'),
|
||||
inject_dll,
|
||||
],
|
||||
workdir: meson.current_source_dir(),
|
||||
)
|
||||
if windows_dll_compat_checker.found()
|
||||
test(dll_name + '_is_xp',
|
||||
windows_dll_compat_checker,
|
||||
args: [
|
||||
inject_dll,
|
||||
'-s', xp_check_ini,
|
||||
],
|
||||
workdir: meson.current_source_dir(),
|
||||
)
|
||||
endif
|
||||
endforeach
|
||||
|
||||
if host_machine.cpu_family() == 'x86_64'
|
||||
|
||||
3
test.sh
3
test.sh
@@ -1,3 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eu
|
||||
|
||||
meson test -C build32 --print-errorlogs "$@"
|
||||
meson test -C build64 --print-errorlogs "$@"
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
Taken from my Jubeat cab's XP image
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user