From 7fc7a51a4677d8ea6f19dcd411e3c8d3e34602e9 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Mon, 30 Nov 2020 21:24:41 +0100 Subject: [PATCH] Move PluginArchitecture to common Along with the accompanying function to parse a PE32 file. We're going to have to define some common tags for different plugin types. --- meson.build | 1 + src/common/plugins.cpp | 53 +++++++++++++++++++++++++++++++++++++++ src/common/plugins.h | 44 ++++++++++++++++++++++++++++++++ src/plugin/host-process.h | 1 + src/plugin/utils.cpp | 48 ----------------------------------- src/plugin/utils.h | 22 +--------------- 6 files changed, 100 insertions(+), 69 deletions(-) create mode 100644 src/common/plugins.cpp create mode 100644 src/common/plugins.h diff --git a/meson.build b/meson.build index f1811ada..3fcb0a4a 100644 --- a/meson.build +++ b/meson.build @@ -85,6 +85,7 @@ shared_library( 'src/common/serialization/vst2.cpp', 'src/common/configuration.cpp', 'src/common/logging.cpp', + 'src/common/plugins.cpp', 'src/common/utils.cpp', 'src/plugin/bridges/vst2.cpp', 'src/plugin/host-process.cpp', diff --git a/src/common/plugins.cpp b/src/common/plugins.cpp new file mode 100644 index 00000000..449cd21c --- /dev/null +++ b/src/common/plugins.cpp @@ -0,0 +1,53 @@ +#include "plugins.h" + +#include +#include + +namespace fs = boost::filesystem; + +PluginArchitecture find_vst_architecture(fs::path plugin_path) { + std::ifstream file(plugin_path, std::ifstream::binary | std::ifstream::in); + + // The linker will place the offset where the PE signature is placed at the + // end of the MS-DOS stub, at offset 0x3c + uint32_t pe_signature_offset; + file.seekg(0x3c); + file.read(reinterpret_cast(&pe_signature_offset), + sizeof(pe_signature_offset)); + + // The PE32 signature will be followed by a magic number that indicates the + // target architecture of the binary + uint32_t pe_signature; + uint16_t machine_type; + file.seekg(pe_signature_offset); + file.read(reinterpret_cast(&pe_signature), sizeof(pe_signature)); + file.read(reinterpret_cast(&machine_type), sizeof(machine_type)); + + constexpr char expected_pe_signature[4] = {'P', 'E', '\0', '\0'}; + if (pe_signature != + *reinterpret_cast(expected_pe_signature)) { + throw std::runtime_error("'" + plugin_path.string() + + "' is not a valid .dll file"); + } + + // These constants are specified in + // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#machine-types + switch (machine_type) { + case 0x014c: // IMAGE_FILE_MACHINE_I386 + return PluginArchitecture::vst_32; + break; + case 0x8664: // IMAGE_FILE_MACHINE_AMD64 + case 0x0000: // IMAGE_FILE_MACHINE_UNKNOWN + return PluginArchitecture::vst_64; + break; + } + + // When compiled without optimizations, GCC 9.3 will warn that the function + // does not return if we put this in a `default:` case instead. + std::ostringstream error_msg; + error_msg << "'" << plugin_path + << "' is neither a x86 nor a x86_64 PE32 file. Actual " + "architecture: 0x" + << std::hex << machine_type; + throw std::runtime_error(error_msg.str()); +} diff --git a/src/common/plugins.h b/src/common/plugins.h new file mode 100644 index 00000000..478b9e75 --- /dev/null +++ b/src/common/plugins.h @@ -0,0 +1,44 @@ +// yabridge: a Wine VST bridge +// Copyright (C) 2020 Robbert van der Helm +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#ifdef __WINE__ +#include "../wine-host/boost-fix.h" +#endif +#include + +// Utilities and tags for plugin types and architectures + +/** + * A tag to differentiate between 32 and 64-bit plugins, used to determine which + * host application to use. + */ +enum class PluginArchitecture { vst_32, vst_64 }; + +/** + * Determine the architecture of a VST plugin (or rather, a .dll file) based on + * it's header values. + * + * See https://docs.microsoft.com/en-us/windows/win32/debug/pe-format for more + * information on the PE32 format. + * + * @param plugin_path The path to the .dll file we're going to check. + * + * @return The detected architecture. + * @throw std::runtime_error If the file is not a .dll file. + */ +PluginArchitecture find_vst_architecture(boost::filesystem::path); diff --git a/src/plugin/host-process.h b/src/plugin/host-process.h index 8ce79dad..299dab72 100644 --- a/src/plugin/host-process.h +++ b/src/plugin/host-process.h @@ -27,6 +27,7 @@ #include "../common/communication/common.h" #include "../common/logging.h" +#include "../common/plugins.h" #include "utils.h" /** diff --git a/src/plugin/utils.cpp b/src/plugin/utils.cpp index c0b7eba6..ab14641e 100644 --- a/src/plugin/utils.cpp +++ b/src/plugin/utils.cpp @@ -21,7 +21,6 @@ #include #include #include -#include #include // Generated inside of the build directory @@ -55,53 +54,6 @@ std::optional find_wineprefix() { return dosdevices_dir->parent_path(); } -PluginArchitecture find_vst_architecture(fs::path plugin_path) { - std::ifstream file(plugin_path, std::ifstream::binary | std::ifstream::in); - - // The linker will place the offset where the PE signature is placed at the - // end of the MS-DOS stub, at offset 0x3c - uint32_t pe_signature_offset; - file.seekg(0x3c); - file.read(reinterpret_cast(&pe_signature_offset), - sizeof(pe_signature_offset)); - - // The PE32 signature will be followed by a magic number that indicates the - // target architecture of the binary - uint32_t pe_signature; - uint16_t machine_type; - file.seekg(pe_signature_offset); - file.read(reinterpret_cast(&pe_signature), sizeof(pe_signature)); - file.read(reinterpret_cast(&machine_type), sizeof(machine_type)); - - constexpr char expected_pe_signature[4] = {'P', 'E', '\0', '\0'}; - if (pe_signature != - *reinterpret_cast(expected_pe_signature)) { - throw std::runtime_error("'" + plugin_path.string() + - "' is not a valid .dll file"); - } - - // These constants are specified in - // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#machine-types - switch (machine_type) { - case 0x014c: // IMAGE_FILE_MACHINE_I386 - return PluginArchitecture::vst_32; - break; - case 0x8664: // IMAGE_FILE_MACHINE_AMD64 - case 0x0000: // IMAGE_FILE_MACHINE_UNKNOWN - return PluginArchitecture::vst_64; - break; - } - - // When compiled without optimizations, GCC 9.3 will warn that the function - // does not return if we put this in a `default:` case instead. - std::ostringstream error_msg; - error_msg << "'" << plugin_path - << "' is neither a x86 nor a x86_64 PE32 file. Actual " - "architecture: 0x" - << std::hex << machine_type; - throw std::runtime_error(error_msg.str()); -} - fs::path find_vst_host(PluginArchitecture plugin_arch, bool use_plugin_groups) { auto host_name = use_plugin_groups ? yabridge_group_host_name : yabridge_individual_host_name; diff --git a/src/plugin/utils.h b/src/plugin/utils.h index 93bf5c77..67d32bf2 100644 --- a/src/plugin/utils.h +++ b/src/plugin/utils.h @@ -16,11 +16,11 @@ #pragma once -#include #include #include #include "../common/configuration.h" +#include "../common/plugins.h" /** * Boost 1.72 was released with a known breaking bug caused by a missing @@ -39,12 +39,6 @@ class patched_async_pipe : public boost::process::async_pipe { typedef typename handle_type::executor_type executor_type; }; -/** - * A tag to differentiate between 32 and 64-bit plugins, used to determine which - * host application to use. - */ -enum class PluginArchitecture { vst_32, vst_64 }; - /** * Create a logger prefix based on the endpoint base directory used for the * sockets for easy identification. This will result in a prefix of the form @@ -58,20 +52,6 @@ enum class PluginArchitecture { vst_32, vst_64 }; std::string create_logger_prefix( const boost::filesystem::path& endpoint_base_dir); -/** - * Determine the architecture of a VST plugin (or rather, a .dll file) based on - * it's header values. - * - * See https://docs.microsoft.com/en-us/windows/win32/debug/pe-format for more - * information on the PE32 format. - * - * @param plugin_path The path to the .dll file we're going to check. - * - * @return The detected architecture. - * @throw std::runtime_error If the file is not a .dll file. - */ -PluginArchitecture find_vst_architecture(boost::filesystem::path); - /** * Finds the Wine VST host (either `yabridge-host.exe` or `yabridge-host.exe` * depending on the plugin). For this we will search in two places: