From 5d454c4733bdf1bf17ada5c6abe282f266cecd21 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 6 Jan 2025 15:51:41 +0100 Subject: [PATCH 1/3] Verify formatting using clang-format --- .github/workflows/build.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1c438095..f29d1c27 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,6 +15,19 @@ on: # cancel-in-progress: true jobs: + verify-formatting: + name: Verify Formatting + runs-on: ubuntu-24.04 + steps: + - name: Checkout Source + uses: actions/checkout@v4 + + - name: Verify Formatting + uses: jidicula/clang-format-action@v4.14.0 + with: + clang-format-version: '19' + check-path: 'src' + dump-registry: name: Dump Registry runs-on: windows-latest From 64c2a79f0f6ed28a4069359a27c082a2dcaf7562 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 6 Jan 2025 16:11:12 +0100 Subject: [PATCH 2/3] Add clang-format file --- .clang-format | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..5d341ef6 --- /dev/null +++ b/.clang-format @@ -0,0 +1,26 @@ +# Format Style Options - Created with Clang Power Tools +--- +BasedOnStyle: Microsoft +AlwaysBreakTemplateDeclarations: Yes +BreakConstructorInitializers: BeforeColon +DerivePointerAlignment: false +FixNamespaceComments: false +KeepEmptyLinesAtTheStartOfBlocks: false +Language: Cpp +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: All +PointerAlignment: Left +SortIncludes: false +AlignEscapedNewlines: Left +PackConstructorInitializers: Never +IndentPPDirectives: None +AlignConsecutiveMacros: + Enabled: true + AcrossEmptyLines: true + AcrossComments: true + AlignCompound: true + PadOperators: true +BraceWrapping: + AfterStruct: true + AfterUnion: true +... From bff8420ffda66df2bf82f63b2fa0ac3a56feceeb Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 6 Jan 2025 17:13:33 +0100 Subject: [PATCH 3/3] Format all the code --- src/analyzer/main.cpp | 385 +- src/analyzer/object_watching.hpp | 52 +- src/analyzer/reflect_extension.hpp | 2366 +++++- src/analyzer/reflect_type_info.hpp | 75 +- src/bad-sample/bad.cpp | 80 +- src/common/network/address.cpp | 615 +- src/common/network/address.hpp | 100 +- src/common/network/socket.cpp | 353 +- src/common/network/socket.hpp | 76 +- src/common/platform/compiler.hpp | 18 +- src/common/platform/file_management.hpp | 561 +- src/common/platform/kernel_mapped.hpp | 1149 +-- src/common/platform/memory.hpp | 162 +- src/common/platform/network.hpp | 4 +- src/common/platform/platform.hpp | 22 +- src/common/platform/primitives.hpp | 28 +- src/common/platform/process.hpp | 1441 ++-- src/common/platform/registry.hpp | 70 +- src/common/platform/status.hpp | 57 +- src/common/platform/synchronisation.hpp | 14 +- src/common/platform/threading.hpp | 103 +- src/common/platform/traits.hpp | 20 +- src/common/platform/unicode.hpp | 100 +- src/common/platform/win_pefile.hpp | 471 +- src/common/utils/buffer_accessor.hpp | 186 +- src/common/utils/concurrency.hpp | 92 +- src/common/utils/container.hpp | 24 +- src/common/utils/file_handle.hpp | 140 +- src/common/utils/finally.hpp | 81 +- src/common/utils/io.cpp | 196 +- src/common/utils/io.hpp | 24 +- src/common/utils/nt_handle.hpp | 120 +- src/common/utils/string.hpp | 67 +- src/common/utils/timer.hpp | 34 +- src/emulator/address_utils.hpp | 20 +- src/emulator/emulator.hpp | 202 +- src/emulator/memory_manager.cpp | 790 +- src/emulator/memory_manager.hpp | 177 +- src/emulator/memory_permission.hpp | 56 +- src/emulator/memory_region.hpp | 8 +- src/emulator/scoped_hook.hpp | 78 +- src/emulator/serialization.hpp | 797 +- src/emulator/serialization_helper.hpp | 60 +- src/emulator/typed_emulator.hpp | 142 +- src/emulator/x64_emulator.hpp | 14 +- src/emulator/x64_register.hpp | 480 +- src/fuzzer/main.cpp | 281 +- src/fuzzing-engine/fuzzer.cpp | 201 +- src/fuzzing-engine/fuzzer.hpp | 44 +- src/fuzzing-engine/input_generator.cpp | 184 +- src/fuzzing-engine/input_generator.hpp | 48 +- src/fuzzing-engine/random_generator.cpp | 48 +- src/fuzzing-engine/random_generator.hpp | 98 +- src/test-sample/test.cpp | 388 +- src/unicorn-emulator/function_wrapper.hpp | 51 +- src/unicorn-emulator/object.hpp | 12 +- src/unicorn-emulator/unicorn.hpp | 42 +- src/unicorn-emulator/unicorn_hook.hpp | 113 +- .../unicorn_memory_regions.hpp | 93 +- src/unicorn-emulator/unicorn_x64_emulator.cpp | 1165 ++- src/unicorn-emulator/unicorn_x64_emulator.hpp | 4 +- src/windows-emulator-test/emulation_test.cpp | 58 +- .../emulation_test_utils.hpp | 51 +- src/windows-emulator-test/main.cpp | 4 +- .../serialization_test.cpp | 100 +- src/windows-emulator-test/time_test.cpp | 57 +- src/windows-emulator/context_frame.cpp | 260 +- src/windows-emulator/context_frame.hpp | 4 +- src/windows-emulator/debugging/gdb_stub.cpp | 201 +- src/windows-emulator/debugging/gdb_stub.hpp | 36 +- .../debugging/win_x64_gdb_stub_handler.hpp | 64 +- .../debugging/x64_gdb_stub_handler.hpp | 324 +- src/windows-emulator/devices/afd_endpoint.cpp | 1047 ++- src/windows-emulator/devices/afd_types.hpp | 176 +- src/windows-emulator/emulator_utils.hpp | 414 +- src/windows-emulator/handles.hpp | 488 +- src/windows-emulator/io_device.cpp | 37 +- src/windows-emulator/io_device.hpp | 276 +- src/windows-emulator/kusd_mmio.cpp | 288 +- src/windows-emulator/kusd_mmio.hpp | 62 +- src/windows-emulator/logger.cpp | 161 +- src/windows-emulator/logger.hpp | 58 +- src/windows-emulator/memory_utils.hpp | 96 +- src/windows-emulator/module/mapped_module.hpp | 58 +- .../module/module_manager.cpp | 162 +- .../module/module_manager.hpp | 84 +- .../module/module_mapping.cpp | 386 +- .../module/module_mapping.hpp | 3 +- src/windows-emulator/process_context.hpp | 918 +-- src/windows-emulator/registry/hive_parser.cpp | 322 +- src/windows-emulator/registry/hive_parser.hpp | 134 +- .../registry/registry_manager.cpp | 198 +- .../registry/registry_manager.hpp | 75 +- src/windows-emulator/std_include.hpp | 52 +- src/windows-emulator/syscall_dispatcher.cpp | 183 +- src/windows-emulator/syscall_dispatcher.hpp | 40 +- src/windows-emulator/syscall_utils.hpp | 289 +- src/windows-emulator/syscalls.cpp | 6958 ++++++++--------- src/windows-emulator/windows_emulator.cpp | 1763 ++--- src/windows-emulator/windows_emulator.hpp | 179 +- 100 files changed, 16439 insertions(+), 14509 deletions(-) diff --git a/src/analyzer/main.cpp b/src/analyzer/main.cpp index 0c3c0476..e585876f 100644 --- a/src/analyzer/main.cpp +++ b/src/analyzer/main.cpp @@ -7,254 +7,247 @@ namespace { - struct analysis_options - { - bool use_gdb{false}; - bool concise_logging{false}; - }; + struct analysis_options + { + bool use_gdb{false}; + bool concise_logging{false}; + }; - void watch_system_objects(windows_emulator& win_emu, const bool cache_logging) - { - (void)win_emu; - (void)cache_logging; + void watch_system_objects(windows_emulator& win_emu, const bool cache_logging) + { + (void)win_emu; + (void)cache_logging; #ifdef OS_WINDOWS - watch_object(win_emu, *win_emu.current_thread().teb, cache_logging); - watch_object(win_emu, win_emu.process().peb, cache_logging); - watch_object(win_emu, emulator_object{win_emu.emu(), kusd_mmio::address()}, cache_logging); + watch_object(win_emu, *win_emu.current_thread().teb, cache_logging); + watch_object(win_emu, win_emu.process().peb, cache_logging); + watch_object(win_emu, emulator_object{win_emu.emu(), kusd_mmio::address()}, cache_logging); - auto* params_hook = watch_object(win_emu, win_emu.process().process_params, cache_logging); + auto* params_hook = watch_object(win_emu, win_emu.process().process_params, cache_logging); - win_emu.emu().hook_memory_write(win_emu.process().peb.value() + offsetof(PEB64, ProcessParameters), 0x8, - [&, cache_logging](const uint64_t address, size_t, const uint64_t value) - { - const auto target_address = win_emu.process().peb.value() + offsetof( - PEB64, ProcessParameters); + win_emu.emu().hook_memory_write( + win_emu.process().peb.value() + offsetof(PEB64, ProcessParameters), 0x8, + [&, cache_logging](const uint64_t address, size_t, const uint64_t value) { + const auto target_address = win_emu.process().peb.value() + offsetof(PEB64, ProcessParameters); - if (address == target_address) - { - const emulator_object obj{ - win_emu.emu(), value - }; + if (address == target_address) + { + const emulator_object obj{win_emu.emu(), value}; - win_emu.emu().delete_hook(params_hook); - params_hook = watch_object(win_emu, obj, cache_logging); - } - }); + win_emu.emu().delete_hook(params_hook); + params_hook = watch_object(win_emu, obj, cache_logging); + } + }); #endif - } + } - void run_emulation(windows_emulator& win_emu, const analysis_options& options) - { - try - { - if (options.use_gdb) - { - const auto* address = "127.0.0.1:28960"; - win_emu.log.print(color::pink, "Waiting for GDB connection on %s...\n", address); + void run_emulation(windows_emulator& win_emu, const analysis_options& options) + { + try + { + if (options.use_gdb) + { + const auto* address = "127.0.0.1:28960"; + win_emu.log.print(color::pink, "Waiting for GDB connection on %s...\n", address); - win_x64_gdb_stub_handler handler{win_emu}; - run_gdb_stub(handler, "i386:x86-64", gdb_registers.size(), address); - } - else - { - win_emu.start(); - } - } - catch (const std::exception& e) - { - win_emu.log.print(color::red, "Emulation failed at: 0x%" PRIx64 " - %s\n", - win_emu.emu().read_instruction_pointer(), e.what()); - throw; - } - catch (...) - { - win_emu.log.print(color::red, "Emulation failed at: 0x%" PRIx64 "\n", - win_emu.emu().read_instruction_pointer()); - throw; - } + win_x64_gdb_stub_handler handler{win_emu}; + run_gdb_stub(handler, "i386:x86-64", gdb_registers.size(), address); + } + else + { + win_emu.start(); + } + } + catch (const std::exception& e) + { + win_emu.log.print(color::red, "Emulation failed at: 0x%" PRIx64 " - %s\n", + win_emu.emu().read_instruction_pointer(), e.what()); + throw; + } + catch (...) + { + win_emu.log.print(color::red, "Emulation failed at: 0x%" PRIx64 "\n", + win_emu.emu().read_instruction_pointer()); + throw; + } - const auto exit_status = win_emu.process().exit_status; - if (exit_status.has_value()) - { - win_emu.log.print(color::red, "Emulation terminated with status: %X\n", *exit_status); - } - else - { - win_emu.log.print(color::red, "Emulation terminated without status!\n"); - } - } + const auto exit_status = win_emu.process().exit_status; + if (exit_status.has_value()) + { + win_emu.log.print(color::red, "Emulation terminated with status: %X\n", *exit_status); + } + else + { + win_emu.log.print(color::red, "Emulation terminated without status!\n"); + } + } - std::vector parse_arguments(const std::span args) - { - std::vector wide_args{}; - wide_args.reserve(args.size() - 1); + std::vector parse_arguments(const std::span args) + { + std::vector wide_args{}; + wide_args.reserve(args.size() - 1); - for (size_t i = 1; i < args.size(); ++i) - { - const auto& arg = args[i]; - wide_args.emplace_back(arg.begin(), arg.end()); - } + for (size_t i = 1; i < args.size(); ++i) + { + const auto& arg = args[i]; + wide_args.emplace_back(arg.begin(), arg.end()); + } - return wide_args; - } + return wide_args; + } - void run(const analysis_options& options, const std::span args) - { - if (args.empty()) - { - return; - } + void run(const analysis_options& options, const std::span args) + { + if (args.empty()) + { + return; + } - emulator_settings settings{ - .application = args[0], - .arguments = parse_arguments(args), - .silent_until_main = options.concise_logging, - }; + emulator_settings settings{ + .application = args[0], + .arguments = parse_arguments(args), + .silent_until_main = options.concise_logging, + }; - windows_emulator win_emu{std::move(settings)}; + windows_emulator win_emu{std::move(settings)}; - (void)&watch_system_objects; - watch_system_objects(win_emu, options.concise_logging); - win_emu.buffer_stdout = true; - //win_emu.verbose_calls = true; + (void)&watch_system_objects; + watch_system_objects(win_emu, options.concise_logging); + win_emu.buffer_stdout = true; + // win_emu.verbose_calls = true; - const auto& exe = *win_emu.process().executable; + const auto& exe = *win_emu.process().executable; - const auto concise_logging = options.concise_logging; + const auto concise_logging = options.concise_logging; - for (const auto& section : exe.sections) - { - if ((section.region.permissions & memory_permission::exec) != memory_permission::exec) - { - continue; - } + for (const auto& section : exe.sections) + { + if ((section.region.permissions & memory_permission::exec) != memory_permission::exec) + { + continue; + } - auto read_handler = [&, section, concise_logging](const uint64_t address, size_t, uint64_t) - { - const auto rip = win_emu.emu().read_instruction_pointer(); - if (win_emu.process().mod_manager.find_by_address(rip) != win_emu.process().executable) - { - return; - } + auto read_handler = [&, section, concise_logging](const uint64_t address, size_t, uint64_t) { + const auto rip = win_emu.emu().read_instruction_pointer(); + if (win_emu.process().mod_manager.find_by_address(rip) != win_emu.process().executable) + { + return; + } - if (concise_logging) - { - static uint64_t count{0}; - ++count; - if (count > 100 && count % 10000 != 0) return; - } + if (concise_logging) + { + static uint64_t count{0}; + ++count; + if (count > 100 && count % 10000 != 0) + return; + } - win_emu.log.print( - color::green, - "Reading from executable section %s at 0x%" PRIx64 " via 0x%" PRIx64 "\n", - section.name.c_str(), address, rip); - }; + win_emu.log.print(color::green, + "Reading from executable section %s at 0x%" PRIx64 " via 0x%" PRIx64 "\n", + section.name.c_str(), address, rip); + }; - const auto write_handler = [&, section, concise_logging](const uint64_t address, size_t, uint64_t) - { - const auto rip = win_emu.emu().read_instruction_pointer(); - if (win_emu.process().mod_manager.find_by_address(rip) != win_emu.process().executable) - { - return; - } + const auto write_handler = [&, section, concise_logging](const uint64_t address, size_t, uint64_t) { + const auto rip = win_emu.emu().read_instruction_pointer(); + if (win_emu.process().mod_manager.find_by_address(rip) != win_emu.process().executable) + { + return; + } - if (concise_logging) - { - static uint64_t count{0}; - ++count; - if (count > 100 && count % 10000 != 0) return; - } + if (concise_logging) + { + static uint64_t count{0}; + ++count; + if (count > 100 && count % 10000 != 0) + return; + } - win_emu.log.print( - color::blue, - "Writing to executable section %s at 0x%" PRIx64 " via 0x%" PRIx64 "\n", - section.name.c_str(), address, rip); - }; + win_emu.log.print(color::blue, "Writing to executable section %s at 0x%" PRIx64 " via 0x%" PRIx64 "\n", + section.name.c_str(), address, rip); + }; - win_emu.emu().hook_memory_read(section.region.start, section.region.length, std::move(read_handler)); - win_emu.emu().hook_memory_write(section.region.start, section.region.length, std::move(write_handler)); - } + win_emu.emu().hook_memory_read(section.region.start, section.region.length, std::move(read_handler)); + win_emu.emu().hook_memory_write(section.region.start, section.region.length, std::move(write_handler)); + } - run_emulation(win_emu, options); - } + run_emulation(win_emu, options); + } - std::vector bundle_arguments(const int argc, char** argv) - { - std::vector args{}; + std::vector bundle_arguments(const int argc, char** argv) + { + std::vector args{}; - for (int i = 1; i < argc; ++i) - { - args.push_back(argv[i]); - } + for (int i = 1; i < argc; ++i) + { + args.push_back(argv[i]); + } - return args; - } + return args; + } - analysis_options parse_options(std::vector& args) - { - analysis_options options{}; + analysis_options parse_options(std::vector& args) + { + analysis_options options{}; - while (!args.empty()) - { - auto arg_it = args.begin(); - const auto& arg = *arg_it; + while (!args.empty()) + { + auto arg_it = args.begin(); + const auto& arg = *arg_it; - if (arg == "-d") - { - options.use_gdb = true; - } - else if (arg == "-c") - { - options.concise_logging = true; - } - else - { - break; - } + if (arg == "-d") + { + options.use_gdb = true; + } + else if (arg == "-c") + { + options.concise_logging = true; + } + else + { + break; + } - args.erase(arg_it); - } + args.erase(arg_it); + } - return options; - } + return options; + } } int main(const int argc, char** argv) { - try - { - auto args = bundle_arguments(argc, argv); - const auto options = parse_options(args); + try + { + auto args = bundle_arguments(argc, argv); + const auto options = parse_options(args); - if (args.empty()) - { - throw std::runtime_error("Application not specified!"); - } + if (args.empty()) + { + throw std::runtime_error("Application not specified!"); + } - do - { - run(options, args); - } - while (options.use_gdb); + do + { + run(options, args); + } while (options.use_gdb); - return 0; - } - catch (std::exception& e) - { - puts(e.what()); + return 0; + } + catch (std::exception& e) + { + puts(e.what()); #if defined(_WIN32) && 0 - MessageBoxA(nullptr, e.what(), "ERROR", MB_ICONERROR); + MessageBoxA(nullptr, e.what(), "ERROR", MB_ICONERROR); #endif - } + } - return 1; + return 1; } #ifdef _WIN32 int WINAPI WinMain(HINSTANCE, HINSTANCE, PSTR, int) { - return main(__argc, __argv); + return main(__argc, __argv); } #endif diff --git a/src/analyzer/object_watching.hpp b/src/analyzer/object_watching.hpp index f382de81..34c2b5fb 100644 --- a/src/analyzer/object_watching.hpp +++ b/src/analyzer/object_watching.hpp @@ -5,36 +5,32 @@ template emulator_hook* watch_object(windows_emulator& emu, emulator_object object, const bool cache_logging = false) { - const reflect_type_info info{}; + const reflect_type_info info{}; - return emu.emu().hook_memory_read(object.value(), object.size(), - [i = std::move(info), object, &emu, cache_logging]( - const uint64_t address, size_t, uint64_t) - { - const auto rip = emu.emu().read_instruction_pointer(); - const auto* mod = emu.process().mod_manager.find_by_address(rip); - const auto is_main_access = mod == emu.process().executable; + return emu.emu().hook_memory_read( + object.value(), object.size(), + [i = std::move(info), object, &emu, cache_logging](const uint64_t address, size_t, uint64_t) { + const auto rip = emu.emu().read_instruction_pointer(); + const auto* mod = emu.process().mod_manager.find_by_address(rip); + const auto is_main_access = mod == emu.process().executable; - if (!emu.verbose_calls && !is_main_access) - { - return; - } + if (!emu.verbose_calls && !is_main_access) + { + return; + } - if (cache_logging) - { - static std::unordered_set logged_addresses{}; - if (is_main_access && !logged_addresses.insert(address).second) - { - return; - } - } + if (cache_logging) + { + static std::unordered_set logged_addresses{}; + if (is_main_access && !logged_addresses.insert(address).second) + { + return; + } + } - const auto offset = address - object.value(); - emu.log.print(is_main_access ? color::green : color::dark_gray, - "Object access: %s - 0x%llX (%s) at 0x%llX (%s)\n", - i.get_type_name().c_str(), - offset, - i.get_member_name(offset).c_str(), rip, - mod ? mod->name.c_str() : ""); - }); + const auto offset = address - object.value(); + emu.log.print(is_main_access ? color::green : color::dark_gray, + "Object access: %s - 0x%llX (%s) at 0x%llX (%s)\n", i.get_type_name().c_str(), offset, + i.get_member_name(offset).c_str(), rip, mod ? mod->name.c_str() : ""); + }); } diff --git a/src/analyzer/reflect_extension.hpp b/src/analyzer/reflect_extension.hpp index 1018c078..014f7aba 100644 --- a/src/analyzer/reflect_extension.hpp +++ b/src/analyzer/reflect_extension.hpp @@ -1,81 +1,2303 @@ #pragma once -namespace { - template struct REFLECT_FWD_LIKE2 { template using type = std::remove_reference_t&&; }; - template<> struct REFLECT_FWD_LIKE2 { template using type = std::remove_reference_t&; }; +namespace +{ + template + struct REFLECT_FWD_LIKE2 + { + template + using type = std::remove_reference_t&&; + }; + template <> + struct REFLECT_FWD_LIKE2 + { + template + using type = std::remove_reference_t&; + }; } // to speed up compilation times #define REFLECT_FWD(...) static_cast(__VA_ARGS__) -#define REFLECT_FWD_LIKE(T, ...) static_cast>::template type>(__VA_ARGS__) +#define REFLECT_FWD_LIKE(T, ...) \ + static_cast>::template type>( \ + __VA_ARGS__) -namespace reflect::inline v1_2_4 { - namespace detail - { - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), REFLECT_FWD_LIKE(T, _101)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), REFLECT_FWD_LIKE(T, _104)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), REFLECT_FWD_LIKE(T, _107)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), REFLECT_FWD_LIKE(T, _110)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), REFLECT_FWD_LIKE(T, _113)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114), REFLECT_FWD_LIKE(T, _115)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114), REFLECT_FWD_LIKE(T, _115), REFLECT_FWD_LIKE(T, _116)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114), REFLECT_FWD_LIKE(T, _115), REFLECT_FWD_LIKE(T, _116), REFLECT_FWD_LIKE(T, _117)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, _118] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114), REFLECT_FWD_LIKE(T, _115), REFLECT_FWD_LIKE(T, _116), REFLECT_FWD_LIKE(T, _117), REFLECT_FWD_LIKE(T, _118)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, _118, _119] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114), REFLECT_FWD_LIKE(T, _115), REFLECT_FWD_LIKE(T, _116), REFLECT_FWD_LIKE(T, _117), REFLECT_FWD_LIKE(T, _118), REFLECT_FWD_LIKE(T, _119)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, _118, _119, _120] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114), REFLECT_FWD_LIKE(T, _115), REFLECT_FWD_LIKE(T, _116), REFLECT_FWD_LIKE(T, _117), REFLECT_FWD_LIKE(T, _118), REFLECT_FWD_LIKE(T, _119), REFLECT_FWD_LIKE(T, _120)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, _118, _119, _120, _121] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114), REFLECT_FWD_LIKE(T, _115), REFLECT_FWD_LIKE(T, _116), REFLECT_FWD_LIKE(T, _117), REFLECT_FWD_LIKE(T, _118), REFLECT_FWD_LIKE(T, _119), REFLECT_FWD_LIKE(T, _120), REFLECT_FWD_LIKE(T, _121)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, _118, _119, _120, _121, _122] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114), REFLECT_FWD_LIKE(T, _115), REFLECT_FWD_LIKE(T, _116), REFLECT_FWD_LIKE(T, _117), REFLECT_FWD_LIKE(T, _118), REFLECT_FWD_LIKE(T, _119), REFLECT_FWD_LIKE(T, _120), REFLECT_FWD_LIKE(T, _121), REFLECT_FWD_LIKE(T, _122)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, _118, _119, _120, _121, _122, _123] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114), REFLECT_FWD_LIKE(T, _115), REFLECT_FWD_LIKE(T, _116), REFLECT_FWD_LIKE(T, _117), REFLECT_FWD_LIKE(T, _118), REFLECT_FWD_LIKE(T, _119), REFLECT_FWD_LIKE(T, _120), REFLECT_FWD_LIKE(T, _121), REFLECT_FWD_LIKE(T, _122), REFLECT_FWD_LIKE(T, _123)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, _118, _119, _120, _121, _122, _123, _124] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114), REFLECT_FWD_LIKE(T, _115), REFLECT_FWD_LIKE(T, _116), REFLECT_FWD_LIKE(T, _117), REFLECT_FWD_LIKE(T, _118), REFLECT_FWD_LIKE(T, _119), REFLECT_FWD_LIKE(T, _120), REFLECT_FWD_LIKE(T, _121), REFLECT_FWD_LIKE(T, _122), REFLECT_FWD_LIKE(T, _123), REFLECT_FWD_LIKE(T, _124)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, _118, _119, _120, _121, _122, _123, _124, _125] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114), REFLECT_FWD_LIKE(T, _115), REFLECT_FWD_LIKE(T, _116), REFLECT_FWD_LIKE(T, _117), REFLECT_FWD_LIKE(T, _118), REFLECT_FWD_LIKE(T, _119), REFLECT_FWD_LIKE(T, _120), REFLECT_FWD_LIKE(T, _121), REFLECT_FWD_LIKE(T, _122), REFLECT_FWD_LIKE(T, _123), REFLECT_FWD_LIKE(T, _124), REFLECT_FWD_LIKE(T, _125)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, _118, _119, _120, _121, _122, _123, _124, _125, _126] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114), REFLECT_FWD_LIKE(T, _115), REFLECT_FWD_LIKE(T, _116), REFLECT_FWD_LIKE(T, _117), REFLECT_FWD_LIKE(T, _118), REFLECT_FWD_LIKE(T, _119), REFLECT_FWD_LIKE(T, _120), REFLECT_FWD_LIKE(T, _121), REFLECT_FWD_LIKE(T, _122), REFLECT_FWD_LIKE(T, _123), REFLECT_FWD_LIKE(T, _124), REFLECT_FWD_LIKE(T, _125), REFLECT_FWD_LIKE(T, _126)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, _118, _119, _120, _121, _122, _123, _124, _125, _126, _127] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114), REFLECT_FWD_LIKE(T, _115), REFLECT_FWD_LIKE(T, _116), REFLECT_FWD_LIKE(T, _117), REFLECT_FWD_LIKE(T, _118), REFLECT_FWD_LIKE(T, _119), REFLECT_FWD_LIKE(T, _120), REFLECT_FWD_LIKE(T, _121), REFLECT_FWD_LIKE(T, _122), REFLECT_FWD_LIKE(T, _123), REFLECT_FWD_LIKE(T, _124), REFLECT_FWD_LIKE(T, _125), REFLECT_FWD_LIKE(T, _126), REFLECT_FWD_LIKE(T, _127)); } - template [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept { auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, _118, _119, _120, _121, _122, _123, _124, _125, _126, _127, _128] = REFLECT_FWD(t); return REFLECT_FWD(fn)(REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114), REFLECT_FWD_LIKE(T, _115), REFLECT_FWD_LIKE(T, _116), REFLECT_FWD_LIKE(T, _117), REFLECT_FWD_LIKE(T, _118), REFLECT_FWD_LIKE(T, _119), REFLECT_FWD_LIKE(T, _120), REFLECT_FWD_LIKE(T, _121), REFLECT_FWD_LIKE(T, _122), REFLECT_FWD_LIKE(T, _123), REFLECT_FWD_LIKE(T, _124), REFLECT_FWD_LIKE(T, _125), REFLECT_FWD_LIKE(T, _126), REFLECT_FWD_LIKE(T, _127), REFLECT_FWD_LIKE(T, _128)); } - } +namespace reflect::inline v1_2_4 +{ + namespace detail + { + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79] = + REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80] = + REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81] = + REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, + _82] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99] = + REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100] = + REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), + REFLECT_FWD_LIKE(T, _100)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101] = + REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), + REFLECT_FWD_LIKE(T, _101)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, + _102] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), + REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, + _102, _103] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), + REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, + _102, _103, _104] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), + REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), + REFLECT_FWD_LIKE(T, _104)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, + _102, _103, _104, _105] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), + REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), + REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, + _102, _103, _104, _105, _106] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), + REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), + REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, + _102, _103, _104, _105, _106, _107] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), + REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), + REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), + REFLECT_FWD_LIKE(T, _107)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, + _102, _103, _104, _105, _106, _107, _108] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), + REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), + REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), + REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, + _102, _103, _104, _105, _106, _107, _108, _109] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), + REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), + REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), + REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, + _102, _103, _104, _105, _106, _107, _108, _109, _110] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), + REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), + REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), + REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), + REFLECT_FWD_LIKE(T, _110)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, + _102, _103, _104, _105, _106, _107, _108, _109, _110, _111] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), + REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), + REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), + REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), + REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, + _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), + REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), + REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), + REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), + REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, + _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), + REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), + REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), + REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), + REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), + REFLECT_FWD_LIKE(T, _113)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, + _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), + REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), + REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), + REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), + REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), + REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, + _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115] = + REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), + REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), + REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), + REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), + REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), + REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114), REFLECT_FWD_LIKE(T, _115)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, + _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116] = + REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), + REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), + REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), + REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), + REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), + REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114), REFLECT_FWD_LIKE(T, _115), + REFLECT_FWD_LIKE(T, _116)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, + _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117] = + REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), + REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), + REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), + REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), + REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), + REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114), REFLECT_FWD_LIKE(T, _115), + REFLECT_FWD_LIKE(T, _116), REFLECT_FWD_LIKE(T, _117)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, + _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, + _118] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), + REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), + REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), + REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), + REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), + REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114), REFLECT_FWD_LIKE(T, _115), + REFLECT_FWD_LIKE(T, _116), REFLECT_FWD_LIKE(T, _117), REFLECT_FWD_LIKE(T, _118)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, + _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, + _118, _119] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), + REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), + REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), + REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), + REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), + REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114), REFLECT_FWD_LIKE(T, _115), + REFLECT_FWD_LIKE(T, _116), REFLECT_FWD_LIKE(T, _117), REFLECT_FWD_LIKE(T, _118), + REFLECT_FWD_LIKE(T, _119)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, + _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, + _118, _119, _120] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), + REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), + REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), + REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), + REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), + REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114), REFLECT_FWD_LIKE(T, _115), + REFLECT_FWD_LIKE(T, _116), REFLECT_FWD_LIKE(T, _117), REFLECT_FWD_LIKE(T, _118), + REFLECT_FWD_LIKE(T, _119), REFLECT_FWD_LIKE(T, _120)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, + _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, + _118, _119, _120, _121] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), + REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), + REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), + REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), + REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), + REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114), REFLECT_FWD_LIKE(T, _115), + REFLECT_FWD_LIKE(T, _116), REFLECT_FWD_LIKE(T, _117), REFLECT_FWD_LIKE(T, _118), + REFLECT_FWD_LIKE(T, _119), REFLECT_FWD_LIKE(T, _120), REFLECT_FWD_LIKE(T, _121)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, + _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, + _118, _119, _120, _121, _122] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), + REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), + REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), + REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), + REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), + REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114), REFLECT_FWD_LIKE(T, _115), + REFLECT_FWD_LIKE(T, _116), REFLECT_FWD_LIKE(T, _117), REFLECT_FWD_LIKE(T, _118), + REFLECT_FWD_LIKE(T, _119), REFLECT_FWD_LIKE(T, _120), REFLECT_FWD_LIKE(T, _121), + REFLECT_FWD_LIKE(T, _122)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, + _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, + _118, _119, _120, _121, _122, _123] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), + REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), + REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), + REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), + REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), + REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114), REFLECT_FWD_LIKE(T, _115), + REFLECT_FWD_LIKE(T, _116), REFLECT_FWD_LIKE(T, _117), REFLECT_FWD_LIKE(T, _118), + REFLECT_FWD_LIKE(T, _119), REFLECT_FWD_LIKE(T, _120), REFLECT_FWD_LIKE(T, _121), + REFLECT_FWD_LIKE(T, _122), REFLECT_FWD_LIKE(T, _123)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, + _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, + _118, _119, _120, _121, _122, _123, _124] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), + REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), + REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), + REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), + REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), + REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114), REFLECT_FWD_LIKE(T, _115), + REFLECT_FWD_LIKE(T, _116), REFLECT_FWD_LIKE(T, _117), REFLECT_FWD_LIKE(T, _118), + REFLECT_FWD_LIKE(T, _119), REFLECT_FWD_LIKE(T, _120), REFLECT_FWD_LIKE(T, _121), + REFLECT_FWD_LIKE(T, _122), REFLECT_FWD_LIKE(T, _123), REFLECT_FWD_LIKE(T, _124)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, + _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, + _118, _119, _120, _121, _122, _123, _124, _125] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), + REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), + REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), + REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), + REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), + REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114), REFLECT_FWD_LIKE(T, _115), + REFLECT_FWD_LIKE(T, _116), REFLECT_FWD_LIKE(T, _117), REFLECT_FWD_LIKE(T, _118), + REFLECT_FWD_LIKE(T, _119), REFLECT_FWD_LIKE(T, _120), REFLECT_FWD_LIKE(T, _121), + REFLECT_FWD_LIKE(T, _122), REFLECT_FWD_LIKE(T, _123), REFLECT_FWD_LIKE(T, _124), + REFLECT_FWD_LIKE(T, _125)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, + _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, + _118, _119, _120, _121, _122, _123, _124, _125, _126] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), + REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), + REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), + REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), + REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), + REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114), REFLECT_FWD_LIKE(T, _115), + REFLECT_FWD_LIKE(T, _116), REFLECT_FWD_LIKE(T, _117), REFLECT_FWD_LIKE(T, _118), + REFLECT_FWD_LIKE(T, _119), REFLECT_FWD_LIKE(T, _120), REFLECT_FWD_LIKE(T, _121), + REFLECT_FWD_LIKE(T, _122), REFLECT_FWD_LIKE(T, _123), REFLECT_FWD_LIKE(T, _124), + REFLECT_FWD_LIKE(T, _125), REFLECT_FWD_LIKE(T, _126)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, + _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, + _118, _119, _120, _121, _122, _123, _124, _125, _126, _127] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), + REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), + REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), + REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), + REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), + REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114), REFLECT_FWD_LIKE(T, _115), + REFLECT_FWD_LIKE(T, _116), REFLECT_FWD_LIKE(T, _117), REFLECT_FWD_LIKE(T, _118), + REFLECT_FWD_LIKE(T, _119), REFLECT_FWD_LIKE(T, _120), REFLECT_FWD_LIKE(T, _121), + REFLECT_FWD_LIKE(T, _122), REFLECT_FWD_LIKE(T, _123), REFLECT_FWD_LIKE(T, _124), + REFLECT_FWD_LIKE(T, _125), REFLECT_FWD_LIKE(T, _126), REFLECT_FWD_LIKE(T, _127)); + } + template + [[nodiscard]] constexpr decltype(auto) visit(Fn&& fn, T&& t, std::integral_constant) noexcept + { + auto&& [_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, + _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, + _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, + _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, + _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, + _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, _117, + _118, _119, _120, _121, _122, _123, _124, _125, _126, _127, _128] = REFLECT_FWD(t); + return REFLECT_FWD(fn)( + REFLECT_FWD_LIKE(T, _1), REFLECT_FWD_LIKE(T, _2), REFLECT_FWD_LIKE(T, _3), REFLECT_FWD_LIKE(T, _4), + REFLECT_FWD_LIKE(T, _5), REFLECT_FWD_LIKE(T, _6), REFLECT_FWD_LIKE(T, _7), REFLECT_FWD_LIKE(T, _8), + REFLECT_FWD_LIKE(T, _9), REFLECT_FWD_LIKE(T, _10), REFLECT_FWD_LIKE(T, _11), REFLECT_FWD_LIKE(T, _12), + REFLECT_FWD_LIKE(T, _13), REFLECT_FWD_LIKE(T, _14), REFLECT_FWD_LIKE(T, _15), REFLECT_FWD_LIKE(T, _16), + REFLECT_FWD_LIKE(T, _17), REFLECT_FWD_LIKE(T, _18), REFLECT_FWD_LIKE(T, _19), REFLECT_FWD_LIKE(T, _20), + REFLECT_FWD_LIKE(T, _21), REFLECT_FWD_LIKE(T, _22), REFLECT_FWD_LIKE(T, _23), REFLECT_FWD_LIKE(T, _24), + REFLECT_FWD_LIKE(T, _25), REFLECT_FWD_LIKE(T, _26), REFLECT_FWD_LIKE(T, _27), REFLECT_FWD_LIKE(T, _28), + REFLECT_FWD_LIKE(T, _29), REFLECT_FWD_LIKE(T, _30), REFLECT_FWD_LIKE(T, _31), REFLECT_FWD_LIKE(T, _32), + REFLECT_FWD_LIKE(T, _33), REFLECT_FWD_LIKE(T, _34), REFLECT_FWD_LIKE(T, _35), REFLECT_FWD_LIKE(T, _36), + REFLECT_FWD_LIKE(T, _37), REFLECT_FWD_LIKE(T, _38), REFLECT_FWD_LIKE(T, _39), REFLECT_FWD_LIKE(T, _40), + REFLECT_FWD_LIKE(T, _41), REFLECT_FWD_LIKE(T, _42), REFLECT_FWD_LIKE(T, _43), REFLECT_FWD_LIKE(T, _44), + REFLECT_FWD_LIKE(T, _45), REFLECT_FWD_LIKE(T, _46), REFLECT_FWD_LIKE(T, _47), REFLECT_FWD_LIKE(T, _48), + REFLECT_FWD_LIKE(T, _49), REFLECT_FWD_LIKE(T, _50), REFLECT_FWD_LIKE(T, _51), REFLECT_FWD_LIKE(T, _52), + REFLECT_FWD_LIKE(T, _53), REFLECT_FWD_LIKE(T, _54), REFLECT_FWD_LIKE(T, _55), REFLECT_FWD_LIKE(T, _56), + REFLECT_FWD_LIKE(T, _57), REFLECT_FWD_LIKE(T, _58), REFLECT_FWD_LIKE(T, _59), REFLECT_FWD_LIKE(T, _60), + REFLECT_FWD_LIKE(T, _61), REFLECT_FWD_LIKE(T, _62), REFLECT_FWD_LIKE(T, _63), REFLECT_FWD_LIKE(T, _64), + REFLECT_FWD_LIKE(T, _65), REFLECT_FWD_LIKE(T, _66), REFLECT_FWD_LIKE(T, _67), REFLECT_FWD_LIKE(T, _68), + REFLECT_FWD_LIKE(T, _69), REFLECT_FWD_LIKE(T, _70), REFLECT_FWD_LIKE(T, _71), REFLECT_FWD_LIKE(T, _72), + REFLECT_FWD_LIKE(T, _73), REFLECT_FWD_LIKE(T, _74), REFLECT_FWD_LIKE(T, _75), REFLECT_FWD_LIKE(T, _76), + REFLECT_FWD_LIKE(T, _77), REFLECT_FWD_LIKE(T, _78), REFLECT_FWD_LIKE(T, _79), REFLECT_FWD_LIKE(T, _80), + REFLECT_FWD_LIKE(T, _81), REFLECT_FWD_LIKE(T, _82), REFLECT_FWD_LIKE(T, _83), REFLECT_FWD_LIKE(T, _84), + REFLECT_FWD_LIKE(T, _85), REFLECT_FWD_LIKE(T, _86), REFLECT_FWD_LIKE(T, _87), REFLECT_FWD_LIKE(T, _88), + REFLECT_FWD_LIKE(T, _89), REFLECT_FWD_LIKE(T, _90), REFLECT_FWD_LIKE(T, _91), REFLECT_FWD_LIKE(T, _92), + REFLECT_FWD_LIKE(T, _93), REFLECT_FWD_LIKE(T, _94), REFLECT_FWD_LIKE(T, _95), REFLECT_FWD_LIKE(T, _96), + REFLECT_FWD_LIKE(T, _97), REFLECT_FWD_LIKE(T, _98), REFLECT_FWD_LIKE(T, _99), REFLECT_FWD_LIKE(T, _100), + REFLECT_FWD_LIKE(T, _101), REFLECT_FWD_LIKE(T, _102), REFLECT_FWD_LIKE(T, _103), + REFLECT_FWD_LIKE(T, _104), REFLECT_FWD_LIKE(T, _105), REFLECT_FWD_LIKE(T, _106), + REFLECT_FWD_LIKE(T, _107), REFLECT_FWD_LIKE(T, _108), REFLECT_FWD_LIKE(T, _109), + REFLECT_FWD_LIKE(T, _110), REFLECT_FWD_LIKE(T, _111), REFLECT_FWD_LIKE(T, _112), + REFLECT_FWD_LIKE(T, _113), REFLECT_FWD_LIKE(T, _114), REFLECT_FWD_LIKE(T, _115), + REFLECT_FWD_LIKE(T, _116), REFLECT_FWD_LIKE(T, _117), REFLECT_FWD_LIKE(T, _118), + REFLECT_FWD_LIKE(T, _119), REFLECT_FWD_LIKE(T, _120), REFLECT_FWD_LIKE(T, _121), + REFLECT_FWD_LIKE(T, _122), REFLECT_FWD_LIKE(T, _123), REFLECT_FWD_LIKE(T, _124), + REFLECT_FWD_LIKE(T, _125), REFLECT_FWD_LIKE(T, _126), REFLECT_FWD_LIKE(T, _127), + REFLECT_FWD_LIKE(T, _128)); + } + } } #undef REFLECT_FWD_LIKE diff --git a/src/analyzer/reflect_type_info.hpp b/src/analyzer/reflect_type_info.hpp index 2d03cb7c..cb58f498 100644 --- a/src/analyzer/reflect_type_info.hpp +++ b/src/analyzer/reflect_type_info.hpp @@ -15,51 +15,50 @@ template class reflect_type_info { -public: - reflect_type_info() - { - this->type_name_ = reflect::type_name(); + public: + reflect_type_info() + { + this->type_name_ = reflect::type_name(); - reflect::for_each([this](auto I) - { - const auto member_name = reflect::member_name(); - const auto member_offset = reflect::offset_of(); + reflect::for_each([this](auto I) { + const auto member_name = reflect::member_name(); + const auto member_offset = reflect::offset_of(); - this->members_[member_offset] = member_name; - }); - } + this->members_[member_offset] = member_name; + }); + } - std::string get_member_name(const size_t offset) const - { - size_t last_offset{}; - std::string_view last_member{}; + std::string get_member_name(const size_t offset) const + { + size_t last_offset{}; + std::string_view last_member{}; - for (const auto& member : this->members_) - { - if (offset == member.first) - { - return member.second; - } + for (const auto& member : this->members_) + { + if (offset == member.first) + { + return member.second; + } - if (offset < member.first) - { - const auto diff = offset - last_offset; - return std::string(last_member) + "+" + std::to_string(diff); - } + if (offset < member.first) + { + const auto diff = offset - last_offset; + return std::string(last_member) + "+" + std::to_string(diff); + } - last_offset = member.first; - last_member = member.second; - } + last_offset = member.first; + last_member = member.second; + } - return ""; - } + return ""; + } - const std::string& get_type_name() const - { - return this->type_name_; - } + const std::string& get_type_name() const + { + return this->type_name_; + } -private: - std::string type_name_{}; - std::map members_{}; + private: + std::string type_name_{}; + std::map members_{}; }; diff --git a/src/bad-sample/bad.cpp b/src/bad-sample/bad.cpp index adabd48b..878721ef 100644 --- a/src/bad-sample/bad.cpp +++ b/src/bad-sample/bad.cpp @@ -5,61 +5,59 @@ #define THE_SIZE 30 -extern "C" NO_INLINE EXPORT_SYMBOL -void vulnerable(const uint8_t* data, const size_t size) +extern "C" NO_INLINE EXPORT_SYMBOL void vulnerable(const uint8_t* data, const size_t size) { - if (size < 10) - { - return; - } + if (size < 10) + { + return; + } - if (data[9] != 'A') - { - return; - } + if (data[9] != 'A') + { + return; + } - if (data[8] != 'B') - { - return; - } + if (data[8] != 'B') + { + return; + } - if (data[7] != 'C') - { - return; - } + if (data[7] != 'C') + { + return; + } - if (data[2] != 'V') - { - return; - } + if (data[2] != 'V') + { + return; + } - if (data[4] != 'H') - { - return; - } + if (data[4] != 'H') + { + return; + } - if (size < 100) - { - return; - } + if (size < 100) + { + return; + } - *(int*)1 = 1; + *(int*)1 = 1; } uint8_t buffer[THE_SIZE] = {}; - int main(int argc, const char* argv[]) { - const void* input = buffer; - auto size = sizeof(buffer); + const void* input = buffer; + auto size = sizeof(buffer); - if (argc > 1) - { - input = argv[1]; - size = strlen(argv[1]); - } + if (argc > 1) + { + input = argv[1]; + size = strlen(argv[1]); + } - vulnerable((uint8_t*)input, size); - return 0; + vulnerable((uint8_t*)input, size); + return 0; } diff --git a/src/common/network/address.cpp b/src/common/network/address.cpp index 1737804e..bb116a90 100644 --- a/src/common/network/address.cpp +++ b/src/common/network/address.cpp @@ -8,376 +8,365 @@ using namespace std::literals; namespace network { - void initialize_wsa() - { + void initialize_wsa() + { #ifdef _WIN32 - static struct wsa_initializer - { - public: - wsa_initializer() - { - WSADATA wsa_data; - if (WSAStartup(MAKEWORD(2, 2), &wsa_data)) - { - throw std::runtime_error("Unable to initialize WSA"); - } - } + static struct wsa_initializer + { + wsa_initializer() + { + WSADATA wsa_data; + if (WSAStartup(MAKEWORD(2, 2), &wsa_data)) + { + throw std::runtime_error("Unable to initialize WSA"); + } + } - ~wsa_initializer() - { - WSACleanup(); - } - } _; + ~wsa_initializer() + { + WSACleanup(); + } + } _; #endif - } + } - address::address() - { - initialize_wsa(); - ZeroMemory(&this->storage_, this->get_max_size()); + address::address() + { + initialize_wsa(); + ZeroMemory(&this->storage_, this->get_max_size()); - this->address_.sa_family = AF_UNSPEC; - } + this->address_.sa_family = AF_UNSPEC; + } - address::address(const std::string& addr, const std::optional& family) - : address() - { - this->parse(addr, family); - } + address::address(const std::string& addr, const std::optional& family) + : address() + { + this->parse(addr, family); + } - address::address(const sockaddr_in6& addr) - : address() - { - this->address6_ = addr; - } + address::address(const sockaddr_in6& addr) + : address() + { + this->address6_ = addr; + } - address::address(const sockaddr_in& addr) - : address() - { - this->address4_ = addr; - } + address::address(const sockaddr_in& addr) + : address() + { + this->address4_ = addr; + } - address::address(const sockaddr* addr, const socklen_t length) - : address() - { - this->set_address(addr, length); - } + address::address(const sockaddr* addr, const socklen_t length) + : address() + { + this->set_address(addr, length); + } - void address::set_ipv4(const uint32_t ip) - { - in_addr addr{}; - addr.s_addr = ip; - this->set_ipv4(addr); - } + void address::set_ipv4(const uint32_t ip) + { + in_addr addr{}; + addr.s_addr = ip; + this->set_ipv4(addr); + } - bool address::operator==(const address& obj) const - { - if (this->address_.sa_family != obj.address_.sa_family) - { - return false; - } + bool address::operator==(const address& obj) const + { + if (this->address_.sa_family != obj.address_.sa_family) + { + return false; + } - if (this->get_port() != obj.get_port()) - { - return false; - } + if (this->get_port() != obj.get_port()) + { + return false; + } - if (this->address_.sa_family == AF_INET) - { - return this->address4_.sin_addr.s_addr == obj.address4_.sin_addr.s_addr; - } - else if (this->address_.sa_family == AF_INET6) - { - return !memcmp(this->address6_.sin6_addr.s6_addr, obj.address6_.sin6_addr.s6_addr, - sizeof(obj.address6_.sin6_addr.s6_addr)); - } + if (this->address_.sa_family == AF_INET) + { + return this->address4_.sin_addr.s_addr == obj.address4_.sin_addr.s_addr; + } + else if (this->address_.sa_family == AF_INET6) + { + return !memcmp(this->address6_.sin6_addr.s6_addr, obj.address6_.sin6_addr.s6_addr, + sizeof(obj.address6_.sin6_addr.s6_addr)); + } - return false; - } + return false; + } - void address::set_ipv4(const in_addr& addr) - { - ZeroMemory(&this->address4_, sizeof(this->address4_)); - this->address4_.sin_family = AF_INET; - this->address4_.sin_addr = addr; - } + void address::set_ipv4(const in_addr& addr) + { + ZeroMemory(&this->address4_, sizeof(this->address4_)); + this->address4_.sin_family = AF_INET; + this->address4_.sin_addr = addr; + } - void address::set_ipv6(const in6_addr& addr) - { - ZeroMemory(&this->address6_, sizeof(this->address6_)); - this->address6_.sin6_family = AF_INET6; - this->address6_.sin6_addr = addr; - } + void address::set_ipv6(const in6_addr& addr) + { + ZeroMemory(&this->address6_, sizeof(this->address6_)); + this->address6_.sin6_family = AF_INET6; + this->address6_.sin6_addr = addr; + } - void address::set_address(const sockaddr* addr, const socklen_t length) - { - if (static_cast(length) >= sizeof(sockaddr_in) && addr->sa_family == AF_INET) - { - this->address4_ = *reinterpret_cast(addr); - } - else if (static_cast(length) == sizeof(sockaddr_in6) && addr->sa_family == AF_INET6) - { - this->address6_ = *reinterpret_cast(addr); - } - else - { - throw std::runtime_error("Invalid network address"); - } - } + void address::set_address(const sockaddr* addr, const socklen_t length) + { + if (static_cast(length) >= sizeof(sockaddr_in) && addr->sa_family == AF_INET) + { + this->address4_ = *reinterpret_cast(addr); + } + else if (static_cast(length) == sizeof(sockaddr_in6) && addr->sa_family == AF_INET6) + { + this->address6_ = *reinterpret_cast(addr); + } + else + { + throw std::runtime_error("Invalid network address"); + } + } - void address::set_port(const unsigned short port) - { - switch (this->address_.sa_family) - { - case AF_INET: - this->address4_.sin_port = htons(port); - break; - case AF_INET6: - this->address6_.sin6_port = htons(port); - break; - default: - throw std::runtime_error("Invalid address family"); - } - } + void address::set_port(const unsigned short port) + { + switch (this->address_.sa_family) + { + case AF_INET: + this->address4_.sin_port = htons(port); + break; + case AF_INET6: + this->address6_.sin6_port = htons(port); + break; + default: + throw std::runtime_error("Invalid address family"); + } + } - unsigned short address::get_port() const - { - switch (this->address_.sa_family) - { - case AF_INET: - return ntohs(this->address4_.sin_port); - case AF_INET6: - return ntohs(this->address6_.sin6_port); - default: - return 0; - } - } + unsigned short address::get_port() const + { + switch (this->address_.sa_family) + { + case AF_INET: + return ntohs(this->address4_.sin_port); + case AF_INET6: + return ntohs(this->address6_.sin6_port); + default: + return 0; + } + } - std::string address::to_string() const - { - char buffer[1000] = {0}; - std::string addr; + std::string address::to_string() const + { + char buffer[1000] = {0}; + std::string addr; - switch (this->address_.sa_family) - { - case AF_INET: - inet_ntop(this->address_.sa_family, &this->address4_.sin_addr, buffer, sizeof(buffer)); - addr = std::string(buffer); - break; - case AF_INET6: - inet_ntop(this->address_.sa_family, &this->address6_.sin6_addr, buffer, sizeof(buffer)); - addr = "[" + std::string(buffer) + "]"; - break; - default: - buffer[0] = '?'; - buffer[1] = 0; - addr = std::string(buffer); - break; - } + switch (this->address_.sa_family) + { + case AF_INET: + inet_ntop(this->address_.sa_family, &this->address4_.sin_addr, buffer, sizeof(buffer)); + addr = std::string(buffer); + break; + case AF_INET6: + inet_ntop(this->address_.sa_family, &this->address6_.sin6_addr, buffer, sizeof(buffer)); + addr = "[" + std::string(buffer) + "]"; + break; + default: + buffer[0] = '?'; + buffer[1] = 0; + addr = std::string(buffer); + break; + } - return addr + ":"s + std::to_string(this->get_port()); - } + return addr + ":"s + std::to_string(this->get_port()); + } - bool address::is_local() const - { - if (this->address_.sa_family != AF_INET) - { - return false; - } + bool address::is_local() const + { + if (this->address_.sa_family != AF_INET) + { + return false; + } - // According to: https://en.wikipedia.org/wiki/Private_network + // According to: https://en.wikipedia.org/wiki/Private_network - uint8_t bytes[4]; - *reinterpret_cast(&bytes) = this->address4_.sin_addr.s_addr; + uint8_t bytes[4]; + *reinterpret_cast(&bytes) = this->address4_.sin_addr.s_addr; - // 10.X.X.X - if (bytes[0] == 10) - { - return true; - } + // 10.X.X.X + if (bytes[0] == 10) + { + return true; + } - // 192.168.X.X - if (bytes[0] == 192 - && bytes[1] == 168) - { - return true; - } + // 192.168.X.X + if (bytes[0] == 192 && bytes[1] == 168) + { + return true; + } - // 172.16.X.X - 172.31.X.X - if (bytes[0] == 172 - && bytes[1] >= 16 - && bytes[1] < 32) - { - return true; - } + // 172.16.X.X - 172.31.X.X + if (bytes[0] == 172 && bytes[1] >= 16 && bytes[1] < 32) + { + return true; + } - // 127.0.0.1 - if (this->address4_.sin_addr.s_addr == 0x0100007F) - { - return true; - } + // 127.0.0.1 + if (this->address4_.sin_addr.s_addr == 0x0100007F) + { + return true; + } - return false; - } + return false; + } - sockaddr& address::get_addr() - { - return this->address_; - } + sockaddr& address::get_addr() + { + return this->address_; + } - const sockaddr& address::get_addr() const - { - return this->address_; - } + const sockaddr& address::get_addr() const + { + return this->address_; + } - sockaddr_in& address::get_in_addr() - { - return this->address4_; - } + sockaddr_in& address::get_in_addr() + { + return this->address4_; + } - sockaddr_in6& address::get_in6_addr() - { - return this->address6_; - } + sockaddr_in6& address::get_in6_addr() + { + return this->address6_; + } - const sockaddr_in& address::get_in_addr() const - { - return this->address4_; - } + const sockaddr_in& address::get_in_addr() const + { + return this->address4_; + } - const sockaddr_in6& address::get_in6_addr() const - { - return this->address6_; - } + const sockaddr_in6& address::get_in6_addr() const + { + return this->address6_; + } - socklen_t address::get_size() const - { - switch (this->address_.sa_family) - { - case AF_INET: - return static_cast(sizeof(this->address4_)); - case AF_INET6: - return static_cast(sizeof(this->address6_)); - default: - return static_cast(sizeof(this->address_)); - } - } + socklen_t address::get_size() const + { + switch (this->address_.sa_family) + { + case AF_INET: + return static_cast(sizeof(this->address4_)); + case AF_INET6: + return static_cast(sizeof(this->address6_)); + default: + return static_cast(sizeof(this->address_)); + } + } - socklen_t address::get_max_size() const - { - constexpr auto s = sizeof(this->address_); - constexpr auto s4 = sizeof(this->address4_); - constexpr auto s6 = sizeof(this->address6_); - constexpr auto sstore = sizeof(this->storage_); - constexpr auto max_size = std::max(sstore, std::max(s, std::max(s4, s6))); - static_assert(max_size == sstore); + socklen_t address::get_max_size() const + { + constexpr auto s = sizeof(this->address_); + constexpr auto s4 = sizeof(this->address4_); + constexpr auto s6 = sizeof(this->address6_); + constexpr auto sstore = sizeof(this->storage_); + constexpr auto max_size = std::max(sstore, std::max(s, std::max(s4, s6))); + static_assert(max_size == sstore); - return static_cast(max_size); - } + return static_cast(max_size); + } - bool address::is_ipv4() const - { - return this->address_.sa_family == AF_INET; - } + bool address::is_ipv4() const + { + return this->address_.sa_family == AF_INET; + } - bool address::is_ipv6() const - { - return this->address_.sa_family == AF_INET6; - } + bool address::is_ipv6() const + { + return this->address_.sa_family == AF_INET6; + } - bool address::is_supported() const - { - return is_ipv4() || is_ipv6(); - } + bool address::is_supported() const + { + return is_ipv4() || is_ipv6(); + } - void address::parse(std::string addr, const std::optional& family) - { - std::optional port_value{}; + void address::parse(std::string addr, const std::optional& family) + { + std::optional port_value{}; - const auto pos = addr.find_last_of(':'); - if (pos != std::string::npos) - { - auto port = addr.substr(pos + 1); - port_value = uint16_t(atoi(port.data())); - addr = addr.substr(0, pos); - } + const auto pos = addr.find_last_of(':'); + if (pos != std::string::npos) + { + auto port = addr.substr(pos + 1); + port_value = uint16_t(atoi(port.data())); + addr = addr.substr(0, pos); + } - this->resolve(addr, family); + this->resolve(addr, family); - if (port_value) - { - this->set_port(*port_value); - } - } + if (port_value) + { + this->set_port(*port_value); + } + } - void address::resolve(const std::string& hostname, const std::optional& family) - { - const auto port = this->get_port(); - auto port_reset_action = utils::finally([this, port]() - { - this->set_port(port); - }); + void address::resolve(const std::string& hostname, const std::optional& family) + { + const auto port = this->get_port(); + auto port_reset_action = utils::finally([this, port]() { this->set_port(port); }); - const auto result = resolve_multiple(hostname); - for (const auto& addr : result) - { - if (addr.is_supported() && (!family || addr.get_addr().sa_family == *family)) - { - this->set_address(&addr.get_addr(), addr.get_size()); - return; - } - } + const auto result = resolve_multiple(hostname); + for (const auto& addr : result) + { + if (addr.is_supported() && (!family || addr.get_addr().sa_family == *family)) + { + this->set_address(&addr.get_addr(), addr.get_size()); + return; + } + } - port_reset_action.cancel(); - throw std::runtime_error{"Unable to resolve hostname: " + hostname}; - } + port_reset_action.cancel(); + throw std::runtime_error{"Unable to resolve hostname: " + hostname}; + } - std::vector
address::resolve_multiple(const std::string& hostname) - { - std::vector
results{}; + std::vector
address::resolve_multiple(const std::string& hostname) + { + std::vector
results{}; - addrinfo* result = nullptr; - if (!getaddrinfo(hostname.data(), nullptr, nullptr, &result)) - { - const auto _2 = utils::finally([&result] - { - freeaddrinfo(result); - }); + addrinfo* result = nullptr; + if (!getaddrinfo(hostname.data(), nullptr, nullptr, &result)) + { + const auto _2 = utils::finally([&result] { freeaddrinfo(result); }); - for (auto* i = result; i; i = i->ai_next) - { - if (i->ai_family == AF_INET || i->ai_family == AF_INET6) - { - address a{}; - a.set_address(i->ai_addr, static_cast(i->ai_addrlen)); - results.emplace_back(std::move(a)); - } - } - } + for (auto* i = result; i; i = i->ai_next) + { + if (i->ai_family == AF_INET || i->ai_family == AF_INET6) + { + address a{}; + a.set_address(i->ai_addr, static_cast(i->ai_addrlen)); + results.emplace_back(std::move(a)); + } + } + } - return results; - } + return results; + } } std::size_t std::hash::operator()(const network::address& a) const noexcept { - const uint32_t family = a.get_addr().sa_family; - const uint32_t port = a.get_port(); + const uint32_t family = a.get_addr().sa_family; + const uint32_t port = a.get_port(); - std::size_t hash = std::hash{}(family); - hash ^= std::hash{}(port); - switch (a.get_addr().sa_family) - { - case AF_INET: - hash ^= std::hash{}(a.get_in_addr().sin_addr.s_addr); - break; - case AF_INET6: - hash ^= std::hash{}(std::string_view{ - reinterpret_cast(a.get_in6_addr().sin6_addr.s6_addr), - sizeof(a.get_in6_addr().sin6_addr.s6_addr) - }); - break; - } + std::size_t hash = std::hash{}(family); + hash ^= std::hash{}(port); + switch (a.get_addr().sa_family) + { + case AF_INET: + hash ^= std::hash{}(a.get_in_addr().sin_addr.s_addr); + break; + case AF_INET6: + hash ^= std::hash{}( + std::string_view{reinterpret_cast(a.get_in6_addr().sin6_addr.s6_addr), + sizeof(a.get_in6_addr().sin6_addr.s6_addr)}); + break; + } - return hash; + return hash; } diff --git a/src/common/network/address.hpp b/src/common/network/address.hpp index 1351f198..f8b6c7df 100644 --- a/src/common/network/address.hpp +++ b/src/common/network/address.hpp @@ -36,71 +36,71 @@ using socklen_t = int; namespace network { - void initialize_wsa(); + void initialize_wsa(); - class address - { - public: - address(); - address(const std::string& addr, const std::optional& family = {}); - address(const sockaddr_in& addr); - address(const sockaddr_in6& addr); - address(const sockaddr* addr, socklen_t length); + class address + { + public: + address(); + address(const std::string& addr, const std::optional& family = {}); + address(const sockaddr_in& addr); + address(const sockaddr_in6& addr); + address(const sockaddr* addr, socklen_t length); - void set_ipv4(uint32_t ip); - void set_ipv4(const in_addr& addr); - void set_ipv6(const in6_addr& addr); - void set_address(const sockaddr* addr, socklen_t length); + void set_ipv4(uint32_t ip); + void set_ipv4(const in_addr& addr); + void set_ipv6(const in6_addr& addr); + void set_address(const sockaddr* addr, socklen_t length); - void set_port(unsigned short port); - [[nodiscard]] unsigned short get_port() const; + void set_port(unsigned short port); + [[nodiscard]] unsigned short get_port() const; - sockaddr& get_addr(); - sockaddr_in& get_in_addr(); - sockaddr_in6& get_in6_addr(); + sockaddr& get_addr(); + sockaddr_in& get_in_addr(); + sockaddr_in6& get_in6_addr(); - const sockaddr& get_addr() const; - const sockaddr_in& get_in_addr() const; - const sockaddr_in6& get_in6_addr() const; + const sockaddr& get_addr() const; + const sockaddr_in& get_in_addr() const; + const sockaddr_in6& get_in6_addr() const; - socklen_t get_size() const; - socklen_t get_max_size() const; + socklen_t get_size() const; + socklen_t get_max_size() const; - bool is_ipv4() const; - bool is_ipv6() const; - bool is_supported() const; + bool is_ipv4() const; + bool is_ipv6() const; + bool is_supported() const; - [[nodiscard]] bool is_local() const; - [[nodiscard]] std::string to_string() const; + [[nodiscard]] bool is_local() const; + [[nodiscard]] std::string to_string() const; - bool operator==(const address& obj) const; + bool operator==(const address& obj) const; - bool operator!=(const address& obj) const - { - return !(*this == obj); - } + bool operator!=(const address& obj) const + { + return !(*this == obj); + } - static std::vector
resolve_multiple(const std::string& hostname); + static std::vector
resolve_multiple(const std::string& hostname); - private: - union - { - sockaddr address_; - sockaddr_in address4_; - sockaddr_in6 address6_; - sockaddr_storage storage_; - }; + private: + union + { + sockaddr address_; + sockaddr_in address4_; + sockaddr_in6 address6_; + sockaddr_storage storage_; + }; - void parse(std::string addr, const std::optional& family = {}); - void resolve(const std::string& hostname, const std::optional& family = {}); - }; + void parse(std::string addr, const std::optional& family = {}); + void resolve(const std::string& hostname, const std::optional& family = {}); + }; } namespace std { - template <> - struct hash - { - std::size_t operator()(const network::address& a) const noexcept; - }; + template <> + struct hash + { + std::size_t operator()(const network::address& a) const noexcept; + }; } diff --git a/src/common/network/socket.cpp b/src/common/network/socket.cpp index 45991ff3..5b81a998 100644 --- a/src/common/network/socket.cpp +++ b/src/common/network/socket.cpp @@ -6,226 +6,225 @@ using namespace std::literals; namespace network { - socket::socket(const int af) - : address_family_(af) - { - initialize_wsa(); - this->socket_ = ::socket(af, SOCK_DGRAM, IPPROTO_UDP); + socket::socket(const int af) + : address_family_(af) + { + initialize_wsa(); + this->socket_ = ::socket(af, SOCK_DGRAM, IPPROTO_UDP); - if (af == AF_INET6) - { - int i = 1; - setsockopt(this->socket_, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast(&i), - static_cast(sizeof(i))); - } - } + if (af == AF_INET6) + { + int i = 1; + setsockopt(this->socket_, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast(&i), + static_cast(sizeof(i))); + } + } - socket::~socket() - { - this->release(); - } + socket::~socket() + { + this->release(); + } - socket::socket(socket&& obj) noexcept - { - this->operator=(std::move(obj)); - } + socket::socket(socket&& obj) noexcept + { + this->operator=(std::move(obj)); + } - socket& socket::operator=(socket&& obj) noexcept - { - if (this != &obj) - { - this->release(); - this->socket_ = obj.socket_; - this->port_ = obj.port_; - this->address_family_ = obj.address_family_; + socket& socket::operator=(socket&& obj) noexcept + { + if (this != &obj) + { + this->release(); + this->socket_ = obj.socket_; + this->port_ = obj.port_; + this->address_family_ = obj.address_family_; - obj.socket_ = INVALID_SOCKET; - obj.address_family_ = AF_UNSPEC; - } + obj.socket_ = INVALID_SOCKET; + obj.address_family_ = AF_UNSPEC; + } - return *this; - } + return *this; + } - void socket::release() - { - if (this->socket_ != INVALID_SOCKET) - { - closesocket(this->socket_); - this->socket_ = INVALID_SOCKET; - } - } + void socket::release() + { + if (this->socket_ != INVALID_SOCKET) + { + closesocket(this->socket_); + this->socket_ = INVALID_SOCKET; + } + } - bool socket::bind_port(const address& target) - { - const auto result = bind(this->socket_, &target.get_addr(), target.get_size()) == 0; - if (result) - { - this->port_ = target.get_port(); - } + bool socket::bind_port(const address& target) + { + const auto result = bind(this->socket_, &target.get_addr(), target.get_size()) == 0; + if (result) + { + this->port_ = target.get_port(); + } - return result; - } + return result; + } - bool socket::send(const address& target, const void* data, const size_t size) const - { - const auto res = sendto(this->socket_, static_cast(data), static_cast(size), 0, - &target.get_addr(), - target.get_size()); - return static_cast(res) == size; - } + bool socket::send(const address& target, const void* data, const size_t size) const + { + const auto res = sendto(this->socket_, static_cast(data), static_cast(size), 0, + &target.get_addr(), target.get_size()); + return static_cast(res) == size; + } - bool socket::send(const address& target, const std::string& data) const - { - return this->send(target, data.data(), data.size()); - } + bool socket::send(const address& target, const std::string& data) const + { + return this->send(target, data.data(), data.size()); + } - bool socket::receive(address& source, std::string& data) const - { - char buffer[0x2000]; - auto len = source.get_max_size(); + bool socket::receive(address& source, std::string& data) const + { + char buffer[0x2000]; + auto len = source.get_max_size(); - const auto result = recvfrom(this->socket_, buffer, static_cast(sizeof(buffer)), 0, &source.get_addr(), - &len); - if (result == SOCKET_ERROR) - { - return false; - } + const auto result = + recvfrom(this->socket_, buffer, static_cast(sizeof(buffer)), 0, &source.get_addr(), &len); + if (result == SOCKET_ERROR) + { + return false; + } - data.assign(buffer, buffer + result); - return true; - } + data.assign(buffer, buffer + result); + return true; + } - bool socket::set_blocking(const bool blocking) - { - return socket::set_blocking(this->socket_, blocking); - } + bool socket::set_blocking(const bool blocking) + { + return socket::set_blocking(this->socket_, blocking); + } - bool socket::set_blocking(SOCKET s, const bool blocking) - { + bool socket::set_blocking(SOCKET s, const bool blocking) + { #ifdef _WIN32 - unsigned long mode = blocking ? 0 : 1; - return ioctlsocket(s, FIONBIO, &mode) == 0; + unsigned long mode = blocking ? 0 : 1; + return ioctlsocket(s, FIONBIO, &mode) == 0; #else - int flags = fcntl(s, F_GETFL, 0); - if (flags == -1) return false; - flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK); - return fcntl(s, F_SETFL, flags) == 0; + int flags = fcntl(s, F_GETFL, 0); + if (flags == -1) + return false; + flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK); + return fcntl(s, F_SETFL, flags) == 0; #endif - } + } - bool socket::sleep(const std::chrono::milliseconds timeout) const - { - /*fd_set fdr; - FD_ZERO(&fdr); - FD_SET(this->socket_, &fdr); + bool socket::sleep(const std::chrono::milliseconds timeout) const + { + /*fd_set fdr; + FD_ZERO(&fdr); + FD_SET(this->socket_, &fdr); - const auto msec = timeout.count(); + const auto msec = timeout.count(); - timeval tv{}; - tv.tv_sec = static_cast(msec / 1000ll); - tv.tv_usec = static_cast((msec % 1000) * 1000); + timeval tv{}; + tv.tv_sec = static_cast(msec / 1000ll); + tv.tv_usec = static_cast((msec % 1000) * 1000); - const auto retval = select(static_cast(this->socket_) + 1, &fdr, nullptr, nullptr, &tv); - if (retval == SOCKET_ERROR) - { - std::this_thread::sleep_for(1ms); - return socket_is_ready; - } + const auto retval = select(static_cast(this->socket_) + 1, &fdr, nullptr, nullptr, &tv); + if (retval == SOCKET_ERROR) + { + std::this_thread::sleep_for(1ms); + return socket_is_ready; + } - if (retval > 0) - { - return socket_is_ready; - } + if (retval > 0) + { + return socket_is_ready; + } - return !socket_is_ready;*/ + return !socket_is_ready;*/ - std::vector sockets{}; - sockets.push_back(this); + std::vector sockets{}; + sockets.push_back(this); - return sleep_sockets(sockets, timeout); - } + return sleep_sockets(sockets, timeout); + } - bool socket::sleep_until(const std::chrono::high_resolution_clock::time_point time_point) const - { - const auto duration = time_point - std::chrono::high_resolution_clock::now(); - return this->sleep(std::chrono::duration_cast(duration)); - } + bool socket::sleep_until(const std::chrono::high_resolution_clock::time_point time_point) const + { + const auto duration = time_point - std::chrono::high_resolution_clock::now(); + return this->sleep(std::chrono::duration_cast(duration)); + } - SOCKET socket::get_socket() const - { - return this->socket_; - } + SOCKET socket::get_socket() const + { + return this->socket_; + } - uint16_t socket::get_port() const - { - return this->port_; - } + uint16_t socket::get_port() const + { + return this->port_; + } - int socket::get_address_family() const - { - return this->address_family_; - } + int socket::get_address_family() const + { + return this->address_family_; + } - bool socket::sleep_sockets(const std::span& sockets, const std::chrono::milliseconds timeout) - { - std::vector pfds{}; - pfds.resize(sockets.size()); + bool socket::sleep_sockets(const std::span& sockets, const std::chrono::milliseconds timeout) + { + std::vector pfds{}; + pfds.resize(sockets.size()); - for (size_t i = 0; i < sockets.size(); ++i) - { - auto& pfd = pfds.at(i); - const auto& socket = sockets[i]; + for (size_t i = 0; i < sockets.size(); ++i) + { + auto& pfd = pfds.at(i); + const auto& socket = sockets[i]; - pfd.fd = socket->get_socket(); - pfd.events = POLLIN; - pfd.revents = 0; - } + pfd.fd = socket->get_socket(); + pfd.events = POLLIN; + pfd.revents = 0; + } - const auto retval = poll(pfds.data(), static_cast(pfds.size()), - static_cast(timeout.count())); + const auto retval = poll(pfds.data(), static_cast(pfds.size()), static_cast(timeout.count())); - if (retval == SOCKET_ERROR) - { - std::this_thread::sleep_for(1ms); - return socket_is_ready; - } + if (retval == SOCKET_ERROR) + { + std::this_thread::sleep_for(1ms); + return socket_is_ready; + } - if (retval > 0) - { - return socket_is_ready; - } + if (retval > 0) + { + return socket_is_ready; + } - return !socket_is_ready; - } + return !socket_is_ready; + } - bool socket::is_socket_ready(const SOCKET s, const bool in_poll) - { - pollfd pfd{}; + bool socket::is_socket_ready(const SOCKET s, const bool in_poll) + { + pollfd pfd{}; - pfd.fd = s; - pfd.events = in_poll ? POLLIN : POLLOUT; - pfd.revents = 0; + pfd.fd = s; + pfd.events = in_poll ? POLLIN : POLLOUT; + pfd.revents = 0; - const auto retval = poll(&pfd, 1, 0); + const auto retval = poll(&pfd, 1, 0); - if (retval == SOCKET_ERROR) - { - std::this_thread::sleep_for(1ms); - return socket_is_ready; - } + if (retval == SOCKET_ERROR) + { + std::this_thread::sleep_for(1ms); + return socket_is_ready; + } - if (retval > 0) - { - return socket_is_ready; - } + if (retval > 0) + { + return socket_is_ready; + } - return !socket_is_ready; - } + return !socket_is_ready; + } - bool socket::sleep_sockets_until(const std::span& sockets, - const std::chrono::high_resolution_clock::time_point time_point) - { - const auto duration = time_point - std::chrono::high_resolution_clock::now(); - return sleep_sockets(sockets, std::chrono::duration_cast(duration)); - } + bool socket::sleep_sockets_until(const std::span& sockets, + const std::chrono::high_resolution_clock::time_point time_point) + { + const auto duration = time_point - std::chrono::high_resolution_clock::now(); + return sleep_sockets(sockets, std::chrono::duration_cast(duration)); + } } diff --git a/src/common/network/socket.hpp b/src/common/network/socket.hpp index ef8f1d35..0900e6ed 100644 --- a/src/common/network/socket.hpp +++ b/src/common/network/socket.hpp @@ -8,63 +8,63 @@ #ifdef _WIN32 using send_size = int; #define GET_SOCKET_ERROR() (WSAGetLastError()) -#define poll WSAPoll -#define SOCK_WOULDBLOCK WSAEWOULDBLOCK +#define poll WSAPoll +#define SOCK_WOULDBLOCK WSAEWOULDBLOCK #else using SOCKET = int; using send_size = size_t; -#define INVALID_SOCKET (SOCKET)(~0) -#define SOCKET_ERROR (-1) +#define INVALID_SOCKET (SOCKET)(~0) +#define SOCKET_ERROR (-1) #define GET_SOCKET_ERROR() (errno) -#define closesocket close -#define SOCK_WOULDBLOCK EWOULDBLOCK +#define closesocket close +#define SOCK_WOULDBLOCK EWOULDBLOCK #endif namespace network { - class socket - { - public: - socket() = default; + class socket + { + public: + socket() = default; - socket(int af); - ~socket(); + socket(int af); + ~socket(); - socket(const socket& obj) = delete; - socket& operator=(const socket& obj) = delete; + socket(const socket& obj) = delete; + socket& operator=(const socket& obj) = delete; - socket(socket&& obj) noexcept; - socket& operator=(socket&& obj) noexcept; + socket(socket&& obj) noexcept; + socket& operator=(socket&& obj) noexcept; - bool bind_port(const address& target); + bool bind_port(const address& target); - [[maybe_unused]] bool send(const address& target, const void* data, size_t size) const; - [[maybe_unused]] bool send(const address& target, const std::string& data) const; - bool receive(address& source, std::string& data) const; + [[maybe_unused]] bool send(const address& target, const void* data, size_t size) const; + [[maybe_unused]] bool send(const address& target, const std::string& data) const; + bool receive(address& source, std::string& data) const; - bool set_blocking(bool blocking); - static bool set_blocking(SOCKET s, bool blocking); + bool set_blocking(bool blocking); + static bool set_blocking(SOCKET s, bool blocking); - static constexpr bool socket_is_ready = true; - bool sleep(std::chrono::milliseconds timeout) const; - bool sleep_until(std::chrono::high_resolution_clock::time_point time_point) const; + static constexpr bool socket_is_ready = true; + bool sleep(std::chrono::milliseconds timeout) const; + bool sleep_until(std::chrono::high_resolution_clock::time_point time_point) const; - SOCKET get_socket() const; - uint16_t get_port() const; + SOCKET get_socket() const; + uint16_t get_port() const; - int get_address_family() const; + int get_address_family() const; - static bool sleep_sockets(const std::span& sockets, std::chrono::milliseconds timeout); - static bool sleep_sockets_until(const std::span& sockets, - std::chrono::high_resolution_clock::time_point time_point); + static bool sleep_sockets(const std::span& sockets, std::chrono::milliseconds timeout); + static bool sleep_sockets_until(const std::span& sockets, + std::chrono::high_resolution_clock::time_point time_point); - static bool is_socket_ready(SOCKET s, bool in_poll); + static bool is_socket_ready(SOCKET s, bool in_poll); - private: - int address_family_{AF_UNSPEC}; - uint16_t port_ = 0; - SOCKET socket_ = INVALID_SOCKET; + private: + int address_family_{AF_UNSPEC}; + uint16_t port_ = 0; + SOCKET socket_ = INVALID_SOCKET; - void release(); - }; + void release(); + }; } diff --git a/src/common/platform/compiler.hpp b/src/common/platform/compiler.hpp index b8fca2ef..eda34323 100644 --- a/src/common/platform/compiler.hpp +++ b/src/common/platform/compiler.hpp @@ -3,7 +3,7 @@ #if defined(_WIN32) || defined(_WIN64) #define OS_WINDOWS #elif defined(__APPLE__) || defined(__MACH__) - #define OS_MAC +#define OS_MAC #elif defined(__linux__) #define OS_LINUX #else @@ -11,9 +11,9 @@ #endif #ifdef OS_WINDOWS -#define EXPORT_SYMBOL __declspec(dllexport) -#define IMPORT_SYMBOL __declspec(dllimport) -#define NO_INLINE __declspec(noinline) +#define EXPORT_SYMBOL __declspec(dllexport) +#define IMPORT_SYMBOL __declspec(dllimport) +#define NO_INLINE __declspec(noinline) #define DECLSPEC_ALIGN(n) __declspec(align(n)) @@ -24,21 +24,21 @@ #define EXPORT_SYMBOL __attribute__((visibility("default"))) #define IMPORT_SYMBOL -#define NO_INLINE __attribute__((noinline)) +#define NO_INLINE __attribute__((noinline)) -#define DECLSPEC_ALIGN(n) alignas(n) -#define fopen_s fopen +#define DECLSPEC_ALIGN(n) alignas(n) +#define fopen_s fopen #define RESTRICTED_POINTER __restrict #ifdef OS_MAC #define _fseeki64 fseeko #define _ftelli64 ftello -#define _stat64 stat +#define _stat64 stat #else #define _fseeki64 fseeko64 #define _ftelli64 ftello64 -#define _stat64 stat64 +#define _stat64 stat64 #endif #endif diff --git a/src/common/platform/file_management.hpp b/src/common/platform/file_management.hpp index 57e6d403..63022c11 100644 --- a/src/common/platform/file_management.hpp +++ b/src/common/platform/file_management.hpp @@ -1,246 +1,250 @@ #pragma once -#define ACCESS_MASK DWORD -#define DEVICE_TYPE DWORD +#define ACCESS_MASK DWORD +#define DEVICE_TYPE DWORD -#define FILE_DEVICE_DISK 0x00000007 -#define FILE_DEVICE_CONSOLE 0x00000050 +#define FILE_DEVICE_DISK 0x00000007 +#define FILE_DEVICE_CONSOLE 0x00000050 -#define FILE_SUPERSEDE 0x00000000 -#define FILE_OPEN 0x00000001 -#define FILE_CREATE 0x00000002 -#define FILE_OPEN_IF 0x00000003 -#define FILE_OVERWRITE 0x00000004 -#define FILE_OVERWRITE_IF 0x00000005 -#define FILE_MAXIMUM_DISPOSITION 0x00000005 +#define FILE_SUPERSEDE 0x00000000 +#define FILE_OPEN 0x00000001 +#define FILE_CREATE 0x00000002 +#define FILE_OPEN_IF 0x00000003 +#define FILE_OVERWRITE 0x00000004 +#define FILE_OVERWRITE_IF 0x00000005 +#define FILE_MAXIMUM_DISPOSITION 0x00000005 #ifndef OS_WINDOWS -#define GENERIC_READ 0x80000000 -#define GENERIC_WRITE 0x40000000 -#define GENERIC_EXECUTE 0x20000000 -#define GENERIC_ALL 0x10000000 +#define GENERIC_READ 0x80000000 +#define GENERIC_WRITE 0x40000000 +#define GENERIC_EXECUTE 0x20000000 +#define GENERIC_ALL 0x10000000 -#undef DELETE -#define DELETE 0x00010000 -#define READ_CONTROL 0x00020000 -#define WRITE_DAC 0x00040000 -#define WRITE_OWNER 0x00080000 -#define SYNCHRONIZE 0x00100000 -#define STANDARD_RIGHTS_REQUIRED 0x000f0000 +#undef DELETE +#define DELETE 0x00010000 +#define READ_CONTROL 0x00020000 +#define WRITE_DAC 0x00040000 +#define WRITE_OWNER 0x00080000 +#define SYNCHRONIZE 0x00100000 +#define STANDARD_RIGHTS_REQUIRED 0x000f0000 -#define FILE_READ_DATA 0x0001 /* file & pipe */ -#define FILE_LIST_DIRECTORY 0x0001 /* directory */ -#define FILE_WRITE_DATA 0x0002 /* file & pipe */ -#define FILE_ADD_FILE 0x0002 /* directory */ -#define FILE_APPEND_DATA 0x0004 /* file */ -#define FILE_ADD_SUBDIRECTORY 0x0004 /* directory */ -#define FILE_CREATE_PIPE_INSTANCE 0x0004 /* named pipe */ -#define FILE_READ_EA 0x0008 /* file & directory */ +#define FILE_READ_DATA 0x0001 /* file & pipe */ +#define FILE_LIST_DIRECTORY 0x0001 /* directory */ +#define FILE_WRITE_DATA 0x0002 /* file & pipe */ +#define FILE_ADD_FILE 0x0002 /* directory */ +#define FILE_APPEND_DATA 0x0004 /* file */ +#define FILE_ADD_SUBDIRECTORY 0x0004 /* directory */ +#define FILE_CREATE_PIPE_INSTANCE 0x0004 /* named pipe */ +#define FILE_READ_EA 0x0008 /* file & directory */ #define FILE_READ_PROPERTIES FILE_READ_EA -#define FILE_WRITE_EA 0x0010 /* file & directory */ +#define FILE_WRITE_EA 0x0010 /* file & directory */ #define FILE_WRITE_PROPERTIES FILE_WRITE_EA -#define FILE_EXECUTE 0x0020 /* file */ -#define FILE_TRAVERSE 0x0020 /* directory */ -#define FILE_DELETE_CHILD 0x0040 /* directory */ -#define FILE_READ_ATTRIBUTES 0x0080 /* all */ -#define FILE_WRITE_ATTRIBUTES 0x0100 /* all */ -#define FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x1ff) +#define FILE_EXECUTE 0x0020 /* file */ +#define FILE_TRAVERSE 0x0020 /* directory */ +#define FILE_DELETE_CHILD 0x0040 /* directory */ +#define FILE_READ_ATTRIBUTES 0x0080 /* all */ +#define FILE_WRITE_ATTRIBUTES 0x0100 /* all */ +#define FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1ff) #endif -#define FILE_DIRECTORY_FILE 0x00000001 -#define FILE_WRITE_THROUGH 0x00000002 -#define FILE_SEQUENTIAL_ONLY 0x00000004 -#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008 +#define FILE_DIRECTORY_FILE 0x00000001 +#define FILE_WRITE_THROUGH 0x00000002 +#define FILE_SEQUENTIAL_ONLY 0x00000004 +#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008 -#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 -#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 -#define FILE_NON_DIRECTORY_FILE 0x00000040 -#define FILE_CREATE_TREE_CONNECTION 0x00000080 +#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 +#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 +#define FILE_NON_DIRECTORY_FILE 0x00000040 +#define FILE_CREATE_TREE_CONNECTION 0x00000080 -#define FILE_ATTRIBUTE_NORMAL 0x00000080 +#define FILE_ATTRIBUTE_NORMAL 0x00000080 -#define PS_ATTRIBUTE_NUMBER_MASK 0x0000ffff -#define PS_ATTRIBUTE_THREAD 0x00010000 // may be used with thread creation -#define PS_ATTRIBUTE_INPUT 0x00020000 // input only -#define PS_ATTRIBUTE_ADDITIVE 0x00040000 // "accumulated" e.g. bitmasks, counters, etc. +#define PS_ATTRIBUTE_NUMBER_MASK 0x0000ffff +#define PS_ATTRIBUTE_THREAD 0x00010000 // may be used with thread creation +#define PS_ATTRIBUTE_INPUT 0x00020000 // input only +#define PS_ATTRIBUTE_ADDITIVE 0x00040000 // "accumulated" e.g. bitmasks, counters, etc. -#define SL_RESTART_SCAN 0x01 -#define SL_RETURN_SINGLE_ENTRY 0x02 -#define SL_NO_CURSOR_UPDATE 0x10 +#define SL_RESTART_SCAN 0x01 +#define SL_RETURN_SINGLE_ENTRY 0x02 +#define SL_NO_CURSOR_UPDATE 0x10 -#define SEC_IMAGE 0x01000000 +#define SEC_IMAGE 0x01000000 typedef enum _FSINFOCLASS { - FileFsVolumeInformation = 1, // q: FILE_FS_VOLUME_INFORMATION - FileFsLabelInformation, // s: FILE_FS_LABEL_INFORMATION (requires FILE_WRITE_DATA to volume) - FileFsSizeInformation, // q: FILE_FS_SIZE_INFORMATION - FileFsDeviceInformation, // q: FILE_FS_DEVICE_INFORMATION - FileFsAttributeInformation, // q: FILE_FS_ATTRIBUTE_INFORMATION - FileFsControlInformation, - // q, s: FILE_FS_CONTROL_INFORMATION (q: requires FILE_READ_DATA; s: requires FILE_WRITE_DATA to volume) - FileFsFullSizeInformation, // q: FILE_FS_FULL_SIZE_INFORMATION - FileFsObjectIdInformation, // q; s: FILE_FS_OBJECTID_INFORMATION (s: requires FILE_WRITE_DATA to volume) - FileFsDriverPathInformation, // q: FILE_FS_DRIVER_PATH_INFORMATION - FileFsVolumeFlagsInformation, - // q; s: FILE_FS_VOLUME_FLAGS_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES to volume) // 10 - FileFsSectorSizeInformation, // q: FILE_FS_SECTOR_SIZE_INFORMATION // since WIN8 - FileFsDataCopyInformation, // q: FILE_FS_DATA_COPY_INFORMATION - FileFsMetadataSizeInformation, // q: FILE_FS_METADATA_SIZE_INFORMATION // since THRESHOLD - FileFsFullSizeInformationEx, // q: FILE_FS_FULL_SIZE_INFORMATION_EX // since REDSTONE5 - FileFsGuidInformation, // q: FILE_FS_GUID_INFORMATION // since 23H2 - FileFsMaximumInformation + FileFsVolumeInformation = 1, // q: FILE_FS_VOLUME_INFORMATION + FileFsLabelInformation, // s: FILE_FS_LABEL_INFORMATION (requires FILE_WRITE_DATA to volume) + FileFsSizeInformation, // q: FILE_FS_SIZE_INFORMATION + FileFsDeviceInformation, // q: FILE_FS_DEVICE_INFORMATION + FileFsAttributeInformation, // q: FILE_FS_ATTRIBUTE_INFORMATION + FileFsControlInformation, + // q, s: FILE_FS_CONTROL_INFORMATION (q: requires FILE_READ_DATA; s: requires FILE_WRITE_DATA to volume) + FileFsFullSizeInformation, // q: FILE_FS_FULL_SIZE_INFORMATION + FileFsObjectIdInformation, // q; s: FILE_FS_OBJECTID_INFORMATION (s: requires FILE_WRITE_DATA to volume) + FileFsDriverPathInformation, // q: FILE_FS_DRIVER_PATH_INFORMATION + FileFsVolumeFlagsInformation, + // q; s: FILE_FS_VOLUME_FLAGS_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES to + // volume) // 10 + FileFsSectorSizeInformation, // q: FILE_FS_SECTOR_SIZE_INFORMATION // since WIN8 + FileFsDataCopyInformation, // q: FILE_FS_DATA_COPY_INFORMATION + FileFsMetadataSizeInformation, // q: FILE_FS_METADATA_SIZE_INFORMATION // since THRESHOLD + FileFsFullSizeInformationEx, // q: FILE_FS_FULL_SIZE_INFORMATION_EX // since REDSTONE5 + FileFsGuidInformation, // q: FILE_FS_GUID_INFORMATION // since 23H2 + FileFsMaximumInformation } FSINFOCLASS, *PFSINFOCLASS; typedef enum _FSINFOCLASS FS_INFORMATION_CLASS; typedef enum _FILE_INFORMATION_CLASS { - FileDirectoryInformation = 1, - // q: FILE_DIRECTORY_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) - FileFullDirectoryInformation, - // q: FILE_FULL_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) - FileBothDirectoryInformation, - // q: FILE_BOTH_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) - FileBasicInformation, - // q; s: FILE_BASIC_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES) - FileStandardInformation, // q: FILE_STANDARD_INFORMATION, FILE_STANDARD_INFORMATION_EX - FileInternalInformation, // q: FILE_INTERNAL_INFORMATION - FileEaInformation, // q: FILE_EA_INFORMATION - FileAccessInformation, // q: FILE_ACCESS_INFORMATION - FileNameInformation, // q: FILE_NAME_INFORMATION - FileRenameInformation, // s: FILE_RENAME_INFORMATION (requires DELETE) // 10 - FileLinkInformation, // s: FILE_LINK_INFORMATION - FileNamesInformation, // q: FILE_NAMES_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) - FileDispositionInformation, // s: FILE_DISPOSITION_INFORMATION (requires DELETE) - FilePositionInformation, // q; s: FILE_POSITION_INFORMATION - FileFullEaInformation, // FILE_FULL_EA_INFORMATION - FileModeInformation, // q; s: FILE_MODE_INFORMATION - FileAlignmentInformation, // q: FILE_ALIGNMENT_INFORMATION - FileAllInformation, // q: FILE_ALL_INFORMATION (requires FILE_READ_ATTRIBUTES) - FileAllocationInformation, // s: FILE_ALLOCATION_INFORMATION (requires FILE_WRITE_DATA) - FileEndOfFileInformation, // s: FILE_END_OF_FILE_INFORMATION (requires FILE_WRITE_DATA) // 20 - FileAlternateNameInformation, // q: FILE_NAME_INFORMATION - FileStreamInformation, // q: FILE_STREAM_INFORMATION - FilePipeInformation, - // q; s: FILE_PIPE_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES) - FilePipeLocalInformation, // q: FILE_PIPE_LOCAL_INFORMATION (requires FILE_READ_ATTRIBUTES) - FilePipeRemoteInformation, - // q; s: FILE_PIPE_REMOTE_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES) - FileMailslotQueryInformation, // q: FILE_MAILSLOT_QUERY_INFORMATION - FileMailslotSetInformation, // s: FILE_MAILSLOT_SET_INFORMATION - FileCompressionInformation, // q: FILE_COMPRESSION_INFORMATION - FileObjectIdInformation, // q: FILE_OBJECTID_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) - FileCompletionInformation, // s: FILE_COMPLETION_INFORMATION // 30 - FileMoveClusterInformation, // s: FILE_MOVE_CLUSTER_INFORMATION (requires FILE_WRITE_DATA) - FileQuotaInformation, // q: FILE_QUOTA_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) - FileReparsePointInformation, - // q: FILE_REPARSE_POINT_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) - FileNetworkOpenInformation, // q: FILE_NETWORK_OPEN_INFORMATION (requires FILE_READ_ATTRIBUTES) - FileAttributeTagInformation, // q: FILE_ATTRIBUTE_TAG_INFORMATION (requires FILE_READ_ATTRIBUTES) - FileTrackingInformation, // s: FILE_TRACKING_INFORMATION (requires FILE_WRITE_DATA) - FileIdBothDirectoryInformation, - // q: FILE_ID_BOTH_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) - FileIdFullDirectoryInformation, - // q: FILE_ID_FULL_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) - FileValidDataLengthInformation, - // s: FILE_VALID_DATA_LENGTH_INFORMATION (requires FILE_WRITE_DATA and/or SeManageVolumePrivilege) - FileShortNameInformation, // s: FILE_NAME_INFORMATION (requires DELETE) // 40 - FileIoCompletionNotificationInformation, - // q; s: FILE_IO_COMPLETION_NOTIFICATION_INFORMATION (q: requires FILE_READ_ATTRIBUTES) // since VISTA - FileIoStatusBlockRangeInformation, // s: FILE_IOSTATUSBLOCK_RANGE_INFORMATION (requires SeLockMemoryPrivilege) - FileIoPriorityHintInformation, - // q; s: FILE_IO_PRIORITY_HINT_INFORMATION, FILE_IO_PRIORITY_HINT_INFORMATION_EX (q: requires FILE_READ_DATA) - FileSfioReserveInformation, // q; s: FILE_SFIO_RESERVE_INFORMATION (q: requires FILE_READ_DATA) - FileSfioVolumeInformation, // q: FILE_SFIO_VOLUME_INFORMATION (requires FILE_READ_ATTRIBUTES) - FileHardLinkInformation, // q: FILE_LINKS_INFORMATION - FileProcessIdsUsingFileInformation, // q: FILE_PROCESS_IDS_USING_FILE_INFORMATION (requires FILE_READ_ATTRIBUTES) - FileNormalizedNameInformation, // q: FILE_NAME_INFORMATION - FileNetworkPhysicalNameInformation, // q: FILE_NETWORK_PHYSICAL_NAME_INFORMATION - FileIdGlobalTxDirectoryInformation, - // q: FILE_ID_GLOBAL_TX_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) // since WIN7 // 50 - FileIsRemoteDeviceInformation, // q: FILE_IS_REMOTE_DEVICE_INFORMATION (requires FILE_READ_ATTRIBUTES) - FileUnusedInformation, - FileNumaNodeInformation, // q: FILE_NUMA_NODE_INFORMATION - FileStandardLinkInformation, // q: FILE_STANDARD_LINK_INFORMATION - FileRemoteProtocolInformation, // q: FILE_REMOTE_PROTOCOL_INFORMATION - FileRenameInformationBypassAccessCheck, // (kernel-mode only); s: FILE_RENAME_INFORMATION // since WIN8 - FileLinkInformationBypassAccessCheck, // (kernel-mode only); s: FILE_LINK_INFORMATION - FileVolumeNameInformation, // q: FILE_VOLUME_NAME_INFORMATION - FileIdInformation, // q: FILE_ID_INFORMATION - FileIdExtdDirectoryInformation, - // q: FILE_ID_EXTD_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) // 60 - FileReplaceCompletionInformation, // s: FILE_COMPLETION_INFORMATION // since WINBLUE - FileHardLinkFullIdInformation, // q: FILE_LINK_ENTRY_FULL_ID_INFORMATION // FILE_LINKS_FULL_ID_INFORMATION - FileIdExtdBothDirectoryInformation, - // q: FILE_ID_EXTD_BOTH_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) // since THRESHOLD - FileDispositionInformationEx, // s: FILE_DISPOSITION_INFO_EX (requires DELETE) // since REDSTONE - FileRenameInformationEx, // s: FILE_RENAME_INFORMATION_EX - FileRenameInformationExBypassAccessCheck, // (kernel-mode only); s: FILE_RENAME_INFORMATION_EX - FileDesiredStorageClassInformation, - // q; s: FILE_DESIRED_STORAGE_CLASS_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES) // since REDSTONE2 - FileStatInformation, // q: FILE_STAT_INFORMATION (requires FILE_READ_ATTRIBUTES) - FileMemoryPartitionInformation, // s: FILE_MEMORY_PARTITION_INFORMATION // since REDSTONE3 - FileStatLxInformation, - // q: FILE_STAT_LX_INFORMATION (requires FILE_READ_ATTRIBUTES and FILE_READ_EA) // since REDSTONE4 // 70 - FileCaseSensitiveInformation, - // q; s: FILE_CASE_SENSITIVE_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES) - FileLinkInformationEx, // s: FILE_LINK_INFORMATION_EX // since REDSTONE5 - FileLinkInformationExBypassAccessCheck, // (kernel-mode only); s: FILE_LINK_INFORMATION_EX - FileStorageReserveIdInformation, - // q; s: FILE_STORAGE_RESERVE_ID_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES) - FileCaseSensitiveInformationForceAccessCheck, // q; s: FILE_CASE_SENSITIVE_INFORMATION - FileKnownFolderInformation, - // q; s: FILE_KNOWN_FOLDER_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES) // since WIN11 - FileStatBasicInformation, // since 23H2 - FileId64ExtdDirectoryInformation, // FILE_ID_64_EXTD_DIR_INFORMATION - FileId64ExtdBothDirectoryInformation, // FILE_ID_64_EXTD_BOTH_DIR_INFORMATION - FileIdAllExtdDirectoryInformation, // FILE_ID_ALL_EXTD_DIR_INFORMATION - FileIdAllExtdBothDirectoryInformation, // FILE_ID_ALL_EXTD_BOTH_DIR_INFORMATION - FileStreamReservationInformation, // FILE_STREAM_RESERVATION_INFORMATION // since 24H2 - FileMupProviderInfo, // MUP_PROVIDER_INFORMATION - FileMaximumInformation + FileDirectoryInformation = 1, + // q: FILE_DIRECTORY_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) + FileFullDirectoryInformation, + // q: FILE_FULL_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) + FileBothDirectoryInformation, + // q: FILE_BOTH_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) + FileBasicInformation, + // q; s: FILE_BASIC_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES) + FileStandardInformation, // q: FILE_STANDARD_INFORMATION, FILE_STANDARD_INFORMATION_EX + FileInternalInformation, // q: FILE_INTERNAL_INFORMATION + FileEaInformation, // q: FILE_EA_INFORMATION + FileAccessInformation, // q: FILE_ACCESS_INFORMATION + FileNameInformation, // q: FILE_NAME_INFORMATION + FileRenameInformation, // s: FILE_RENAME_INFORMATION (requires DELETE) // 10 + FileLinkInformation, // s: FILE_LINK_INFORMATION + FileNamesInformation, // q: FILE_NAMES_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) + FileDispositionInformation, // s: FILE_DISPOSITION_INFORMATION (requires DELETE) + FilePositionInformation, // q; s: FILE_POSITION_INFORMATION + FileFullEaInformation, // FILE_FULL_EA_INFORMATION + FileModeInformation, // q; s: FILE_MODE_INFORMATION + FileAlignmentInformation, // q: FILE_ALIGNMENT_INFORMATION + FileAllInformation, // q: FILE_ALL_INFORMATION (requires FILE_READ_ATTRIBUTES) + FileAllocationInformation, // s: FILE_ALLOCATION_INFORMATION (requires FILE_WRITE_DATA) + FileEndOfFileInformation, // s: FILE_END_OF_FILE_INFORMATION (requires FILE_WRITE_DATA) // 20 + FileAlternateNameInformation, // q: FILE_NAME_INFORMATION + FileStreamInformation, // q: FILE_STREAM_INFORMATION + FilePipeInformation, + // q; s: FILE_PIPE_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES) + FilePipeLocalInformation, // q: FILE_PIPE_LOCAL_INFORMATION (requires FILE_READ_ATTRIBUTES) + FilePipeRemoteInformation, + // q; s: FILE_PIPE_REMOTE_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES) + FileMailslotQueryInformation, // q: FILE_MAILSLOT_QUERY_INFORMATION + FileMailslotSetInformation, // s: FILE_MAILSLOT_SET_INFORMATION + FileCompressionInformation, // q: FILE_COMPRESSION_INFORMATION + FileObjectIdInformation, // q: FILE_OBJECTID_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) + FileCompletionInformation, // s: FILE_COMPLETION_INFORMATION // 30 + FileMoveClusterInformation, // s: FILE_MOVE_CLUSTER_INFORMATION (requires FILE_WRITE_DATA) + FileQuotaInformation, // q: FILE_QUOTA_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) + FileReparsePointInformation, + // q: FILE_REPARSE_POINT_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) + FileNetworkOpenInformation, // q: FILE_NETWORK_OPEN_INFORMATION (requires FILE_READ_ATTRIBUTES) + FileAttributeTagInformation, // q: FILE_ATTRIBUTE_TAG_INFORMATION (requires FILE_READ_ATTRIBUTES) + FileTrackingInformation, // s: FILE_TRACKING_INFORMATION (requires FILE_WRITE_DATA) + FileIdBothDirectoryInformation, + // q: FILE_ID_BOTH_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) + FileIdFullDirectoryInformation, + // q: FILE_ID_FULL_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) + FileValidDataLengthInformation, + // s: FILE_VALID_DATA_LENGTH_INFORMATION (requires FILE_WRITE_DATA and/or SeManageVolumePrivilege) + FileShortNameInformation, // s: FILE_NAME_INFORMATION (requires DELETE) // 40 + FileIoCompletionNotificationInformation, + // q; s: FILE_IO_COMPLETION_NOTIFICATION_INFORMATION (q: requires FILE_READ_ATTRIBUTES) // since VISTA + FileIoStatusBlockRangeInformation, // s: FILE_IOSTATUSBLOCK_RANGE_INFORMATION (requires SeLockMemoryPrivilege) + FileIoPriorityHintInformation, + // q; s: FILE_IO_PRIORITY_HINT_INFORMATION, FILE_IO_PRIORITY_HINT_INFORMATION_EX (q: requires FILE_READ_DATA) + FileSfioReserveInformation, // q; s: FILE_SFIO_RESERVE_INFORMATION (q: requires FILE_READ_DATA) + FileSfioVolumeInformation, // q: FILE_SFIO_VOLUME_INFORMATION (requires FILE_READ_ATTRIBUTES) + FileHardLinkInformation, // q: FILE_LINKS_INFORMATION + FileProcessIdsUsingFileInformation, // q: FILE_PROCESS_IDS_USING_FILE_INFORMATION (requires FILE_READ_ATTRIBUTES) + FileNormalizedNameInformation, // q: FILE_NAME_INFORMATION + FileNetworkPhysicalNameInformation, // q: FILE_NETWORK_PHYSICAL_NAME_INFORMATION + FileIdGlobalTxDirectoryInformation, + // q: FILE_ID_GLOBAL_TX_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) // since WIN7 // + // 50 + FileIsRemoteDeviceInformation, // q: FILE_IS_REMOTE_DEVICE_INFORMATION (requires FILE_READ_ATTRIBUTES) + FileUnusedInformation, + FileNumaNodeInformation, // q: FILE_NUMA_NODE_INFORMATION + FileStandardLinkInformation, // q: FILE_STANDARD_LINK_INFORMATION + FileRemoteProtocolInformation, // q: FILE_REMOTE_PROTOCOL_INFORMATION + FileRenameInformationBypassAccessCheck, // (kernel-mode only); s: FILE_RENAME_INFORMATION // since WIN8 + FileLinkInformationBypassAccessCheck, // (kernel-mode only); s: FILE_LINK_INFORMATION + FileVolumeNameInformation, // q: FILE_VOLUME_NAME_INFORMATION + FileIdInformation, // q: FILE_ID_INFORMATION + FileIdExtdDirectoryInformation, + // q: FILE_ID_EXTD_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) // 60 + FileReplaceCompletionInformation, // s: FILE_COMPLETION_INFORMATION // since WINBLUE + FileHardLinkFullIdInformation, // q: FILE_LINK_ENTRY_FULL_ID_INFORMATION // FILE_LINKS_FULL_ID_INFORMATION + FileIdExtdBothDirectoryInformation, + // q: FILE_ID_EXTD_BOTH_DIR_INFORMATION (requires FILE_LIST_DIRECTORY) (NtQueryDirectoryFile[Ex]) // since THRESHOLD + FileDispositionInformationEx, // s: FILE_DISPOSITION_INFO_EX (requires DELETE) // since REDSTONE + FileRenameInformationEx, // s: FILE_RENAME_INFORMATION_EX + FileRenameInformationExBypassAccessCheck, // (kernel-mode only); s: FILE_RENAME_INFORMATION_EX + FileDesiredStorageClassInformation, + // q; s: FILE_DESIRED_STORAGE_CLASS_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires + // FILE_WRITE_ATTRIBUTES) // since REDSTONE2 + FileStatInformation, // q: FILE_STAT_INFORMATION (requires FILE_READ_ATTRIBUTES) + FileMemoryPartitionInformation, // s: FILE_MEMORY_PARTITION_INFORMATION // since REDSTONE3 + FileStatLxInformation, + // q: FILE_STAT_LX_INFORMATION (requires FILE_READ_ATTRIBUTES and FILE_READ_EA) // since REDSTONE4 // 70 + FileCaseSensitiveInformation, + // q; s: FILE_CASE_SENSITIVE_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES) + FileLinkInformationEx, // s: FILE_LINK_INFORMATION_EX // since REDSTONE5 + FileLinkInformationExBypassAccessCheck, // (kernel-mode only); s: FILE_LINK_INFORMATION_EX + FileStorageReserveIdInformation, + // q; s: FILE_STORAGE_RESERVE_ID_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES) + FileCaseSensitiveInformationForceAccessCheck, // q; s: FILE_CASE_SENSITIVE_INFORMATION + FileKnownFolderInformation, + // q; s: FILE_KNOWN_FOLDER_INFORMATION (q: requires FILE_READ_ATTRIBUTES; s: requires FILE_WRITE_ATTRIBUTES) // + // since WIN11 + FileStatBasicInformation, // since 23H2 + FileId64ExtdDirectoryInformation, // FILE_ID_64_EXTD_DIR_INFORMATION + FileId64ExtdBothDirectoryInformation, // FILE_ID_64_EXTD_BOTH_DIR_INFORMATION + FileIdAllExtdDirectoryInformation, // FILE_ID_ALL_EXTD_DIR_INFORMATION + FileIdAllExtdBothDirectoryInformation, // FILE_ID_ALL_EXTD_BOTH_DIR_INFORMATION + FileStreamReservationInformation, // FILE_STREAM_RESERVATION_INFORMATION // since 24H2 + FileMupProviderInfo, // MUP_PROVIDER_INFORMATION + FileMaximumInformation } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; typedef enum _OBJECT_INFORMATION_CLASS { - ObjectBasicInformation, // q: OBJECT_BASIC_INFORMATION - ObjectNameInformation, // q: OBJECT_NAME_INFORMATION - ObjectTypeInformation, // q: OBJECT_TYPE_INFORMATION - ObjectTypesInformation, // q: OBJECT_TYPES_INFORMATION - ObjectHandleFlagInformation, // qs: OBJECT_HANDLE_FLAG_INFORMATION - ObjectSessionInformation, // s: void // change object session // (requires SeTcbPrivilege) - ObjectSessionObjectInformation, // s: void // change object session // (requires SeTcbPrivilege) - MaxObjectInfoClass + ObjectBasicInformation, // q: OBJECT_BASIC_INFORMATION + ObjectNameInformation, // q: OBJECT_NAME_INFORMATION + ObjectTypeInformation, // q: OBJECT_TYPE_INFORMATION + ObjectTypesInformation, // q: OBJECT_TYPES_INFORMATION + ObjectHandleFlagInformation, // qs: OBJECT_HANDLE_FLAG_INFORMATION + ObjectSessionInformation, // s: void // change object session // (requires SeTcbPrivilege) + ObjectSessionObjectInformation, // s: void // change object session // (requires SeTcbPrivilege) + MaxObjectInfoClass } OBJECT_INFORMATION_CLASS; typedef enum _HARDERROR_RESPONSE_OPTION { - OptionAbortRetryIgnore, - OptionOk, - OptionOkCancel, - OptionRetryCancel, - OptionYesNo, - OptionYesNoCancel, - OptionShutdownSystem, - OptionOkNoWait, - OptionCancelTryContinue + OptionAbortRetryIgnore, + OptionOk, + OptionOkCancel, + OptionRetryCancel, + OptionYesNo, + OptionYesNoCancel, + OptionShutdownSystem, + OptionOkNoWait, + OptionCancelTryContinue } HARDERROR_RESPONSE_OPTION; typedef enum _HARDERROR_RESPONSE { - ResponseReturnToCaller, - ResponseNotHandled, - ResponseAbort, - ResponseCancel, - ResponseIgnore, - ResponseNo, - ResponseOk, - ResponseRetry, - ResponseYes, - ResponseTryAgain, - ResponseContinue + ResponseReturnToCaller, + ResponseNotHandled, + ResponseAbort, + ResponseCancel, + ResponseIgnore, + ResponseNo, + ResponseOk, + ResponseRetry, + ResponseYes, + ResponseTryAgain, + ResponseContinue } HARDERROR_RESPONSE; typedef USHORT RTL_ATOM; @@ -248,113 +252,112 @@ typedef USHORT RTL_ATOM; template struct IO_STATUS_BLOCK { - union - { - NTSTATUS Status; - typename Traits::PVOID Pointer; - }; + union + { + NTSTATUS Status; + typename Traits::PVOID Pointer; + }; - typename Traits::ULONG_PTR Information; + typename Traits::ULONG_PTR Information; }; template struct OBJECT_ATTRIBUTES { - ULONG Length; - typename Traits::HANDLE RootDirectory; - EMULATOR_CAST(typename Traits::PVOID, UNICODE_STRING*) ObjectName; - ULONG Attributes; - typename Traits::PVOID SecurityDescriptor; // PSECURITY_DESCRIPTOR; - typename Traits::PVOID SecurityQualityOfService; // PSECURITY_QUALITY_OF_SERVICE + ULONG Length; + typename Traits::HANDLE RootDirectory; + EMULATOR_CAST(typename Traits::PVOID, UNICODE_STRING*) ObjectName; + ULONG Attributes; + typename Traits::PVOID SecurityDescriptor; // PSECURITY_DESCRIPTOR; + typename Traits::PVOID SecurityQualityOfService; // PSECURITY_QUALITY_OF_SERVICE }; typedef struct _FILE_FS_DEVICE_INFORMATION { - DEVICE_TYPE DeviceType; - ULONG Characteristics; + DEVICE_TYPE DeviceType; + ULONG Characteristics; } FILE_FS_DEVICE_INFORMATION, *PFILE_FS_DEVICE_INFORMATION; typedef struct _FILE_POSITION_INFORMATION { - LARGE_INTEGER CurrentByteOffset; + LARGE_INTEGER CurrentByteOffset; } FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION; typedef struct _FILE_STANDARD_INFORMATION { - LARGE_INTEGER AllocationSize; - LARGE_INTEGER EndOfFile; - ULONG NumberOfLinks; - BOOLEAN DeletePending; - BOOLEAN Directory; + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG NumberOfLinks; + BOOLEAN DeletePending; + BOOLEAN Directory; } FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION; typedef struct _FILE_NAME_INFORMATION { - ULONG FileNameLength; - char16_t FileName[1]; + ULONG FileNameLength; + char16_t FileName[1]; } FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION; typedef struct _FILE_BASIC_INFORMATION { - LARGE_INTEGER CreationTime; // Specifies the time that the file was created. - LARGE_INTEGER LastAccessTime; // Specifies the time that the file was last accessed. - LARGE_INTEGER LastWriteTime; // Specifies the time that the file was last written to. - LARGE_INTEGER ChangeTime; // Specifies the last time the file was changed. - ULONG FileAttributes; // Specifies one or more FILE_ATTRIBUTE_XXX flags. + LARGE_INTEGER CreationTime; // Specifies the time that the file was created. + LARGE_INTEGER LastAccessTime; // Specifies the time that the file was last accessed. + LARGE_INTEGER LastWriteTime; // Specifies the time that the file was last written to. + LARGE_INTEGER ChangeTime; // Specifies the last time the file was changed. + ULONG FileAttributes; // Specifies one or more FILE_ATTRIBUTE_XXX flags. } FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION; typedef struct _FILE_DIRECTORY_INFORMATION { - ULONG NextEntryOffset; - ULONG FileIndex; - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - LARGE_INTEGER EndOfFile; - LARGE_INTEGER AllocationSize; - ULONG FileAttributes; - ULONG FileNameLength; - char16_t FileName[1]; + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + char16_t FileName[1]; } FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION; typedef struct _FILE_FULL_DIR_INFORMATION { - ULONG NextEntryOffset; - ULONG FileIndex; - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - LARGE_INTEGER EndOfFile; - LARGE_INTEGER AllocationSize; - ULONG FileAttributes; - ULONG FileNameLength; - ULONG EaSize; - char16_t FileName[1]; + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + char16_t FileName[1]; } FILE_FULL_DIR_INFORMATION, *PFILE_FULL_DIR_INFORMATION; typedef struct _FILE_BOTH_DIR_INFORMATION { - ULONG NextEntryOffset; - ULONG FileIndex; - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - LARGE_INTEGER EndOfFile; - LARGE_INTEGER AllocationSize; - ULONG FileAttributes; - ULONG FileNameLength; - ULONG EaSize; - char ShortNameLength; - char16_t ShortName[12]; - char16_t FileName[1]; + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + char ShortNameLength; + char16_t ShortName[12]; + char16_t FileName[1]; } FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION; #ifndef OS_WINDOWS -typedef BOOLEAN SECURITY_CONTEXT_TRACKING_MODE, - * PSECURITY_CONTEXT_TRACKING_MODE; +typedef BOOLEAN SECURITY_CONTEXT_TRACKING_MODE, *PSECURITY_CONTEXT_TRACKING_MODE; typedef struct _SECURITY_QUALITY_OF_SERVICE { DWORD Length; @@ -367,17 +370,17 @@ typedef struct _SECURITY_QUALITY_OF_SERVICE typedef struct _PORT_VIEW64 { - ULONG Length; - EMULATOR_CAST(std::uint64_t, HANDLE) SectionHandle; - ULONG SectionOffset; - EMULATOR_CAST(std::int64_t, SIZE_T) ViewSize; - EmulatorTraits::PVOID ViewBase; - EmulatorTraits::PVOID ViewRemoteBase; + ULONG Length; + EMULATOR_CAST(std::uint64_t, HANDLE) SectionHandle; + ULONG SectionOffset; + EMULATOR_CAST(std::int64_t, SIZE_T) ViewSize; + EmulatorTraits::PVOID ViewBase; + EmulatorTraits::PVOID ViewRemoteBase; } PORT_VIEW64, *PPORT_VIEW64; typedef struct _REMOTE_PORT_VIEW64 { - ULONG Length; - EMULATOR_CAST(std::int64_t, SIZE_T) ViewSize; - EmulatorTraits::PVOID ViewBase; + ULONG Length; + EMULATOR_CAST(std::int64_t, SIZE_T) ViewSize; + EmulatorTraits::PVOID ViewBase; } REMOTE_PORT_VIEW64, *PREMOTE_PORT_VIEW64; diff --git a/src/common/platform/kernel_mapped.hpp b/src/common/platform/kernel_mapped.hpp index eba0cb63..cc2303c8 100644 --- a/src/common/platform/kernel_mapped.hpp +++ b/src/common/platform/kernel_mapped.hpp @@ -2,370 +2,370 @@ #include -#define PROCESSOR_FEATURE_MAX 64 -#define GDI_HANDLE_BUFFER_SIZE64 60 +#define PROCESSOR_FEATURE_MAX 64 +#define GDI_HANDLE_BUFFER_SIZE64 60 #define RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_RELEASE_ON_DEACTIVATION 0x00000001 -#define RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_NO_DEACTIVATE 0x00000002 -#define RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_ON_FREE_LIST 0x00000004 -#define RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_HEAP_ALLOCATED 0x00000008 -#define RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_NOT_REALLY_ACTIVATED 0x00000010 -#define ACTIVATION_CONTEXT_STACK_FLAG_QUERIES_DISABLED 0x00000001 -#define GDI_BATCH_BUFFER_SIZE 310 -#define WIN32_CLIENT_INFO_LENGTH 62 -#define STATIC_UNICODE_BUFFER_LENGTH 261 -#define TLS_MINIMUM_AVAILABLE 64 +#define RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_NO_DEACTIVATE 0x00000002 +#define RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_ON_FREE_LIST 0x00000004 +#define RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_HEAP_ALLOCATED 0x00000008 +#define RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_NOT_REALLY_ACTIVATED 0x00000010 +#define ACTIVATION_CONTEXT_STACK_FLAG_QUERIES_DISABLED 0x00000001 +#define GDI_BATCH_BUFFER_SIZE 310 +#define WIN32_CLIENT_INFO_LENGTH 62 +#define STATIC_UNICODE_BUFFER_LENGTH 261 +#define TLS_MINIMUM_AVAILABLE 64 typedef struct _EMU_NT_TIB64 { - struct _EXCEPTION_REGISTRATION_RECORD* ExceptionList; - std::uint64_t* StackBase; - std::uint64_t* StackLimit; - std::uint64_t* SubSystemTib; - std::uint64_t* FibreData; - std::uint64_t* ArbitraryUserPointer; - struct _EMU_NT_TIB64* Self; + struct _EXCEPTION_REGISTRATION_RECORD* ExceptionList; + std::uint64_t* StackBase; + std::uint64_t* StackLimit; + std::uint64_t* SubSystemTib; + std::uint64_t* FibreData; + std::uint64_t* ArbitraryUserPointer; + struct _EMU_NT_TIB64* Self; } EMU_NT_TIB64; typedef EMU_NT_TIB64* PEMU_NT_TIB64; union PEB_BITFIELD_UNION { - BOOLEAN BitField; + BOOLEAN BitField; - struct - { - BOOLEAN ImageUsesLargePages : 1; - BOOLEAN IsProtectedProcess : 1; - BOOLEAN IsImageDynamicallyRelocated : 1; - BOOLEAN SkipPatchingUser32Forwarders : 1; - BOOLEAN IsPackagedProcess : 1; - BOOLEAN IsAppContainer : 1; - BOOLEAN IsProtectedProcessLight : 1; - BOOLEAN IsLongPathAwareProcess : 1; - }; + struct + { + BOOLEAN ImageUsesLargePages : 1; + BOOLEAN IsProtectedProcess : 1; + BOOLEAN IsImageDynamicallyRelocated : 1; + BOOLEAN SkipPatchingUser32Forwarders : 1; + BOOLEAN IsPackagedProcess : 1; + BOOLEAN IsAppContainer : 1; + BOOLEAN IsProtectedProcessLight : 1; + BOOLEAN IsLongPathAwareProcess : 1; + }; }; #ifndef OS_WINDOWS typedef struct _LIST_ENTRY64 { - struct _LIST_ENTRY *Flink; - struct _LIST_ENTRY *Blink; + struct _LIST_ENTRY* Flink; + struct _LIST_ENTRY* Blink; } LIST_ENTRY64, *PLIST_ENTRY64, *RESTRICTED_POINTER PRLIST_ENTRY64; #endif typedef struct _PEB_LDR_DATA64 { - ULONG Length; - BOOLEAN Initialized; - EmulatorTraits::HANDLE SsHandle; - LIST_ENTRY64 InLoadOrderModuleList; - LIST_ENTRY64 InMemoryOrderModuleList; - LIST_ENTRY64 InInitializationOrderModuleList; - std::uint64_t* EntryInProgress; - BOOLEAN ShutdownInProgress; - EmulatorTraits::HANDLE ShutdownThreadId; + ULONG Length; + BOOLEAN Initialized; + EmulatorTraits::HANDLE SsHandle; + LIST_ENTRY64 InLoadOrderModuleList; + LIST_ENTRY64 InMemoryOrderModuleList; + LIST_ENTRY64 InInitializationOrderModuleList; + std::uint64_t* EntryInProgress; + BOOLEAN ShutdownInProgress; + EmulatorTraits::HANDLE ShutdownThreadId; } PEB_LDR_DATA64, *PPEB_LDR_DATA64; typedef struct _STRING64 { - USHORT Length; - USHORT MaximumLength; - char16_t* Buffer; + USHORT Length; + USHORT MaximumLength; + char16_t* Buffer; } STRING64, *PSTRING64, ANSI_STRING64, *PANSI_STRING64, OEM_STRING64, *POEM_STRING64; typedef struct _RTL_DRIVE_LETTER_CURDIR64 { - USHORT Flags; - USHORT Length; - ULONG TimeStamp; - STRING64 DosPath; + USHORT Flags; + USHORT Length; + ULONG TimeStamp; + STRING64 DosPath; } RTL_DRIVE_LETTER_CURDIR64, *PRTL_DRIVE_LETTER_CURDIR64; -#define RTL_MAX_DRIVE_LETTERS 32 +#define RTL_MAX_DRIVE_LETTERS 32 #define RTL_DRIVE_LETTER_VALID (USHORT)0x0001 template struct ARRAY_CONTAINER { - T arr[Size]; + T arr[Size]; }; typedef struct _CURDIR64 { - UNICODE_STRING> DosPath; - EmulatorTraits::HANDLE Handle; + UNICODE_STRING> DosPath; + EmulatorTraits::HANDLE Handle; } CURDIR64, *PCURDIR64; typedef struct _RTL_USER_PROCESS_PARAMETERS64 { - ULONG MaximumLength; - ULONG Length; + ULONG MaximumLength; + ULONG Length; - ULONG Flags; - ULONG DebugFlags; + ULONG Flags; + ULONG DebugFlags; - EmulatorTraits::HANDLE ConsoleHandle; - ULONG ConsoleFlags; - EmulatorTraits::HANDLE StandardInput; - EmulatorTraits::HANDLE StandardOutput; - EmulatorTraits::HANDLE StandardError; + EmulatorTraits::HANDLE ConsoleHandle; + ULONG ConsoleFlags; + EmulatorTraits::HANDLE StandardInput; + EmulatorTraits::HANDLE StandardOutput; + EmulatorTraits::HANDLE StandardError; - CURDIR64 CurrentDirectory; - UNICODE_STRING> DllPath; - UNICODE_STRING> ImagePathName; - UNICODE_STRING> CommandLine; - std::uint64_t* Environment; + CURDIR64 CurrentDirectory; + UNICODE_STRING> DllPath; + UNICODE_STRING> ImagePathName; + UNICODE_STRING> CommandLine; + std::uint64_t* Environment; - ULONG StartingX; - ULONG StartingY; - ULONG CountX; - ULONG CountY; - ULONG CountCharsX; - ULONG CountCharsY; - ULONG FillAttribute; + ULONG StartingX; + ULONG StartingY; + ULONG CountX; + ULONG CountY; + ULONG CountCharsX; + ULONG CountCharsY; + ULONG FillAttribute; - ULONG WindowFlags; - ULONG ShowWindowFlags; - UNICODE_STRING> WindowTitle; - UNICODE_STRING> DesktopInfo; - UNICODE_STRING> ShellInfo; - UNICODE_STRING> RuntimeData; - ARRAY_CONTAINER CurrentDirectories; + ULONG WindowFlags; + ULONG ShowWindowFlags; + UNICODE_STRING> WindowTitle; + UNICODE_STRING> DesktopInfo; + UNICODE_STRING> ShellInfo; + UNICODE_STRING> RuntimeData; + ARRAY_CONTAINER CurrentDirectories; - std::uint64_t* EnvironmentSize; - std::uint64_t* EnvironmentVersion; + std::uint64_t* EnvironmentSize; + std::uint64_t* EnvironmentVersion; - std::uint64_t* PackageDependencyData; - ULONG ProcessGroupId; - ULONG LoaderThreads; + std::uint64_t* PackageDependencyData; + ULONG ProcessGroupId; + ULONG LoaderThreads; - UNICODE_STRING> RedirectionDllName; // REDSTONE4 - UNICODE_STRING> HeapPartitionName; // 19H1 - std::uint64_t* DefaultThreadpoolCpuSetMasks; - ULONG DefaultThreadpoolCpuSetMaskCount; - ULONG DefaultThreadpoolThreadMaximum; - ULONG HeapMemoryTypeMask; // WIN11 + UNICODE_STRING> RedirectionDllName; // REDSTONE4 + UNICODE_STRING> HeapPartitionName; // 19H1 + std::uint64_t* DefaultThreadpoolCpuSetMasks; + ULONG DefaultThreadpoolCpuSetMaskCount; + ULONG DefaultThreadpoolThreadMaximum; + ULONG HeapMemoryTypeMask; // WIN11 } RTL_USER_PROCESS_PARAMETERS64, *PRTL_USER_PROCESS_PARAMETERS64; union PEB_CROSS_PROCESS_FLAGS_UNION { - ULONG CrossProcessFlags; + ULONG CrossProcessFlags; - struct - { - ULONG ProcessInJob : 1; - ULONG ProcessInitializing : 1; - ULONG ProcessUsingVEH : 1; - ULONG ProcessUsingVCH : 1; - ULONG ProcessUsingFTH : 1; - ULONG ProcessPreviouslyThrottled : 1; - ULONG ProcessCurrentlyThrottled : 1; - ULONG ProcessImagesHotPatched : 1; // REDSTONE5 - ULONG ReservedBits0 : 24; - }; + struct + { + ULONG ProcessInJob : 1; + ULONG ProcessInitializing : 1; + ULONG ProcessUsingVEH : 1; + ULONG ProcessUsingVCH : 1; + ULONG ProcessUsingFTH : 1; + ULONG ProcessPreviouslyThrottled : 1; + ULONG ProcessCurrentlyThrottled : 1; + ULONG ProcessImagesHotPatched : 1; // REDSTONE5 + ULONG ReservedBits0 : 24; + }; }; union PEB_KERNEL_CALLBACK_TABLE_UNION64 { - void* KernelCallbackTable; - void* UserSharedInfoPtr; + void* KernelCallbackTable; + void* UserSharedInfoPtr; }; typedef struct _API_SET_NAMESPACE { - ULONG Version; - ULONG Size; - ULONG Flags; - ULONG Count; - ULONG EntryOffset; - ULONG HashOffset; - ULONG HashFactor; + ULONG Version; + ULONG Size; + ULONG Flags; + ULONG Count; + ULONG EntryOffset; + ULONG HashOffset; + ULONG HashFactor; } API_SET_NAMESPACE, *PAPI_SET_NAMESPACE; union PEB_CONTEXT_DATA_UNION64 { - void* pContextData; // WIN7 - void* pUnused; // WIN10 - void* EcCodeBitMap; // WIN11 + void* pContextData; // WIN7 + void* pUnused; // WIN10 + void* EcCodeBitMap; // WIN11 }; union PEB_TRACING_FLAGS_UNION { - ULONG TracingFlags; + ULONG TracingFlags; - struct - { - ULONG HeapTracingEnabled : 1; - ULONG CritSecTracingEnabled : 1; - ULONG LibLoaderTracingEnabled : 1; - ULONG SpareTracingBits : 29; - }; + struct + { + ULONG HeapTracingEnabled : 1; + ULONG CritSecTracingEnabled : 1; + ULONG LibLoaderTracingEnabled : 1; + ULONG SpareTracingBits : 29; + }; }; union PEB_LEAP_SECONDS_FLAG_UNION { - ULONG LeapSecondFlags; + ULONG LeapSecondFlags; - struct - { - ULONG SixtySecondEnabled : 1; - ULONG Reserved : 31; - }; + struct + { + ULONG SixtySecondEnabled : 1; + ULONG Reserved : 31; + }; }; typedef struct _PEB64 { - BOOLEAN InheritedAddressSpace; - BOOLEAN ReadImageFileExecOptions; - BOOLEAN BeingDebugged; - PEB_BITFIELD_UNION BitField; + BOOLEAN InheritedAddressSpace; + BOOLEAN ReadImageFileExecOptions; + BOOLEAN BeingDebugged; + PEB_BITFIELD_UNION BitField; - EmulatorTraits::HANDLE Mutant; + EmulatorTraits::HANDLE Mutant; - std::uint64_t* ImageBaseAddress; - PPEB_LDR_DATA64 Ldr; - PRTL_USER_PROCESS_PARAMETERS64 ProcessParameters; - std::uint64_t* SubSystemData; - std::uint64_t* ProcessHeap; - EMULATOR_CAST(void*, PRTL_CRITICAL_SECTION) FastPebLock; - EMULATOR_CAST(void*, PSLIST_HEADER) AtlThunkSListPtr; - std::uint64_t* IFEOKey; - PEB_CROSS_PROCESS_FLAGS_UNION CrossProcessFlags; - PEB_KERNEL_CALLBACK_TABLE_UNION64 KernelCallbackTable; + std::uint64_t* ImageBaseAddress; + PPEB_LDR_DATA64 Ldr; + PRTL_USER_PROCESS_PARAMETERS64 ProcessParameters; + std::uint64_t* SubSystemData; + std::uint64_t* ProcessHeap; + EMULATOR_CAST(void*, PRTL_CRITICAL_SECTION) FastPebLock; + EMULATOR_CAST(void*, PSLIST_HEADER) AtlThunkSListPtr; + std::uint64_t* IFEOKey; + PEB_CROSS_PROCESS_FLAGS_UNION CrossProcessFlags; + PEB_KERNEL_CALLBACK_TABLE_UNION64 KernelCallbackTable; - ULONG SystemReserved; - ULONG AtlThunkSListPtr32; - PAPI_SET_NAMESPACE ApiSetMap; - ULONG TlsExpansionCounter; - EMULATOR_CAST(void*, PRTL_BITMAP) TlsBitmap; + ULONG SystemReserved; + ULONG AtlThunkSListPtr32; + PAPI_SET_NAMESPACE ApiSetMap; + ULONG TlsExpansionCounter; + EMULATOR_CAST(void*, PRTL_BITMAP) TlsBitmap; - ARRAY_CONTAINER TlsBitmapBits; // TLS_MINIMUM_AVAILABLE - void* ReadOnlySharedMemoryBase; - EMULATOR_CAST(void*, PSILO_USER_SHARED_DATA) SharedData; // HotpatchInformation - std::uint64_t** ReadOnlyStaticServerData; + ARRAY_CONTAINER TlsBitmapBits; // TLS_MINIMUM_AVAILABLE + void* ReadOnlySharedMemoryBase; + EMULATOR_CAST(void*, PSILO_USER_SHARED_DATA) SharedData; // HotpatchInformation + std::uint64_t** ReadOnlyStaticServerData; - std::uint64_t* AnsiCodePageData; // PCPTABLEINFO - std::uint64_t* OemCodePageData; // PCPTABLEINFO - std::uint64_t* UnicodeCaseTableData; // PNLSTABLEINFO + std::uint64_t* AnsiCodePageData; // PCPTABLEINFO + std::uint64_t* OemCodePageData; // PCPTABLEINFO + std::uint64_t* UnicodeCaseTableData; // PNLSTABLEINFO - ULONG NumberOfProcessors; - ULONG NtGlobalFlag; + ULONG NumberOfProcessors; + ULONG NtGlobalFlag; - ULARGE_INTEGER CriticalSectionTimeout; - EMULATOR_CAST(std::int64_t, SIZE_T) HeapSegmentReserve; - EMULATOR_CAST(std::int64_t, SIZE_T) HeapSegmentCommit; - EMULATOR_CAST(std::int64_t, SIZE_T) HeapDeCommitTotalFreeThreshold; - EMULATOR_CAST(std::int64_t, SIZE_T) HeapDeCommitFreeBlockThreshold; + ULARGE_INTEGER CriticalSectionTimeout; + EMULATOR_CAST(std::int64_t, SIZE_T) HeapSegmentReserve; + EMULATOR_CAST(std::int64_t, SIZE_T) HeapSegmentCommit; + EMULATOR_CAST(std::int64_t, SIZE_T) HeapDeCommitTotalFreeThreshold; + EMULATOR_CAST(std::int64_t, SIZE_T) HeapDeCommitFreeBlockThreshold; - ULONG NumberOfHeaps; - ULONG MaximumNumberOfHeaps; - std::uint64_t** ProcessHeaps; // PHEAP + ULONG NumberOfHeaps; + ULONG MaximumNumberOfHeaps; + std::uint64_t** ProcessHeaps; // PHEAP - std::uint64_t* GdiSharedHandleTable; // PGDI_SHARED_MEMORY - std::uint64_t* ProcessStarterHelper; - ULONG GdiDCAttributeList; + std::uint64_t* GdiSharedHandleTable; // PGDI_SHARED_MEMORY + std::uint64_t* ProcessStarterHelper; + ULONG GdiDCAttributeList; - EMULATOR_CAST(void*, PRTL_CRITICAL_SECTION) LoaderLock; + EMULATOR_CAST(void*, PRTL_CRITICAL_SECTION) LoaderLock; - ULONG OSMajorVersion; - ULONG OSMinorVersion; - USHORT OSBuildNumber; - USHORT OSCSDVersion; - ULONG OSPlatformId; - ULONG ImageSubsystem; - ULONG ImageSubsystemMajorVersion; - ULONG ImageSubsystemMinorVersion; - EMULATOR_CAST(std::uint64_t, KAFFINITY) ActiveProcessAffinityMask; - ARRAY_CONTAINER GdiHandleBuffer; - std::uint64_t* PostProcessInitRoutine; + ULONG OSMajorVersion; + ULONG OSMinorVersion; + USHORT OSBuildNumber; + USHORT OSCSDVersion; + ULONG OSPlatformId; + ULONG ImageSubsystem; + ULONG ImageSubsystemMajorVersion; + ULONG ImageSubsystemMinorVersion; + EMULATOR_CAST(std::uint64_t, KAFFINITY) ActiveProcessAffinityMask; + ARRAY_CONTAINER GdiHandleBuffer; + std::uint64_t* PostProcessInitRoutine; - EMULATOR_CAST(void*, PRTL_BITMAP) TlsExpansionBitmap; - ARRAY_CONTAINER TlsExpansionBitmapBits; // TLS_EXPANSION_SLOTS + EMULATOR_CAST(void*, PRTL_BITMAP) TlsExpansionBitmap; + ARRAY_CONTAINER TlsExpansionBitmapBits; // TLS_EXPANSION_SLOTS - ULONG SessionId; + ULONG SessionId; - ULARGE_INTEGER AppCompatFlags; // KACF_* - ULARGE_INTEGER AppCompatFlagsUser; - std::uint64_t* pShimData; - std::uint64_t* AppCompatInfo; // APPCOMPAT_EXE_DATA + ULARGE_INTEGER AppCompatFlags; // KACF_* + ULARGE_INTEGER AppCompatFlagsUser; + std::uint64_t* pShimData; + std::uint64_t* AppCompatInfo; // APPCOMPAT_EXE_DATA - UNICODE_STRING> CSDVersion; + UNICODE_STRING> CSDVersion; - EMULATOR_CAST(void*, PACTIVATION_CONTEXT_DATA) ActivationContextData; - EMULATOR_CAST(void*, PASSEMBLY_STORAGE_MAP) ProcessAssemblyStorageMap; - EMULATOR_CAST(void*, PACTIVATION_CONTEXT_DATA) SystemDefaultActivationContextData; - EMULATOR_CAST(void*, PASSEMBLY_STORAGE_MAP) SystemAssemblyStorageMap; + EMULATOR_CAST(void*, PACTIVATION_CONTEXT_DATA) ActivationContextData; + EMULATOR_CAST(void*, PASSEMBLY_STORAGE_MAP) ProcessAssemblyStorageMap; + EMULATOR_CAST(void*, PACTIVATION_CONTEXT_DATA) SystemDefaultActivationContextData; + EMULATOR_CAST(void*, PASSEMBLY_STORAGE_MAP) SystemAssemblyStorageMap; - EMULATOR_CAST(std::int64_t, SIZE_T) MinimumStackCommit; + EMULATOR_CAST(std::int64_t, SIZE_T) MinimumStackCommit; - ARRAY_CONTAINER SparePointers; // 19H1 (previously FlsCallback to FlsHighIndex) - std::uint64_t* PatchLoaderData; - std::uint64_t* ChpeV2ProcessInfo; // _CHPEV2_PROCESS_INFO + ARRAY_CONTAINER SparePointers; // 19H1 (previously FlsCallback to FlsHighIndex) + std::uint64_t* PatchLoaderData; + std::uint64_t* ChpeV2ProcessInfo; // _CHPEV2_PROCESS_INFO - ULONG AppModelFeatureState; - ARRAY_CONTAINER SpareUlongs; + ULONG AppModelFeatureState; + ARRAY_CONTAINER SpareUlongs; - USHORT ActiveCodePage; - USHORT OemCodePage; - USHORT UseCaseMapping; - USHORT UnusedNlsField; + USHORT ActiveCodePage; + USHORT OemCodePage; + USHORT UseCaseMapping; + USHORT UnusedNlsField; - std::uint64_t* WerRegistrationData; - std::uint64_t* WerShipAssertPtr; + std::uint64_t* WerRegistrationData; + std::uint64_t* WerShipAssertPtr; - PEB_CONTEXT_DATA_UNION64 ContextData; + PEB_CONTEXT_DATA_UNION64 ContextData; - std::uint64_t* pImageHeaderHash; - PEB_TRACING_FLAGS_UNION TracingFlags; + std::uint64_t* pImageHeaderHash; + PEB_TRACING_FLAGS_UNION TracingFlags; - ULONGLONG CsrServerReadOnlySharedMemoryBase; - EMULATOR_CAST(void*, PRTL_CRITICAL_SECTION) TppWorkerpListLock; - LIST_ENTRY64 TppWorkerpList; - ARRAY_CONTAINER WaitOnAddressHashTable; - EMULATOR_CAST(void*, PTELEMETRY_COVERAGE_HEADER) TelemetryCoverageHeader; // REDSTONE3 - ULONG CloudFileFlags; - ULONG CloudFileDiagFlags; // REDSTONE4 - CHAR PlaceholderCompatibilityMode; - ARRAY_CONTAINER PlaceholderCompatibilityModeReserved; - EMULATOR_CAST(void*, PLEAP_SECOND_DATA) LeapSecondData; // REDSTONE5 - PEB_LEAP_SECONDS_FLAG_UNION LeapSecondFlags; + ULONGLONG CsrServerReadOnlySharedMemoryBase; + EMULATOR_CAST(void*, PRTL_CRITICAL_SECTION) TppWorkerpListLock; + LIST_ENTRY64 TppWorkerpList; + ARRAY_CONTAINER WaitOnAddressHashTable; + EMULATOR_CAST(void*, PTELEMETRY_COVERAGE_HEADER) TelemetryCoverageHeader; // REDSTONE3 + ULONG CloudFileFlags; + ULONG CloudFileDiagFlags; // REDSTONE4 + CHAR PlaceholderCompatibilityMode; + ARRAY_CONTAINER PlaceholderCompatibilityModeReserved; + EMULATOR_CAST(void*, PLEAP_SECOND_DATA) LeapSecondData; // REDSTONE5 + PEB_LEAP_SECONDS_FLAG_UNION LeapSecondFlags; - ULONG NtGlobalFlag2; - ULONGLONG ExtendedFeatureDisableMask; // since WIN11 + ULONG NtGlobalFlag2; + ULONGLONG ExtendedFeatureDisableMask; // since WIN11 } PEB64, *PPEB64; typedef struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME64 { - struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME* Previous; - EMULATOR_CAST(void*, ACTIVATION_CONTEXT) ActivationContext; - ULONG Flags; // RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_* + struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME* Previous; + EMULATOR_CAST(void*, ACTIVATION_CONTEXT) ActivationContext; + ULONG Flags; // RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_* } RTL_ACTIVATION_CONTEXT_STACK_FRAME64, *PRTL_ACTIVATION_CONTEXT_STACK_FRAME64; typedef struct _ACTIVATION_CONTEXT_STACK64 { - PRTL_ACTIVATION_CONTEXT_STACK_FRAME64 ActiveFrame; - LIST_ENTRY64 FrameListCache; - ULONG Flags; // ACTIVATION_CONTEXT_STACK_FLAG_* - ULONG NextCookieSequenceNumber; - ULONG StackId; + PRTL_ACTIVATION_CONTEXT_STACK_FRAME64 ActiveFrame; + LIST_ENTRY64 FrameListCache; + ULONG Flags; // ACTIVATION_CONTEXT_STACK_FLAG_* + ULONG NextCookieSequenceNumber; + ULONG StackId; } ACTIVATION_CONTEXT_STACK64, *PACTIVATION_CONTEXT_STACK64; typedef struct _GDI_TEB_BATCH64 { - ULONG Offset; - std::uint64_t* HDC; - ULONG Buffer[GDI_BATCH_BUFFER_SIZE]; + ULONG Offset; + std::uint64_t* HDC; + ULONG Buffer[GDI_BATCH_BUFFER_SIZE]; } GDI_TEB_BATCH64, *PGDI_TEB_BATCH64; #ifndef OS_WINDOWS typedef struct _GUID { - unsigned long Data1; + unsigned long Data1; unsigned short Data2; unsigned short Data3; - unsigned char Data4[8]; + unsigned char Data4[8]; } GUID; typedef struct _PROCESSOR_NUMBER @@ -379,48 +379,47 @@ typedef struct _PROCESSOR_NUMBER union TEB_CURRENT_IDEAL_PROCESSOR_UNION { - PROCESSOR_NUMBER CurrentIdealProcessor; - ULONG IdealProcessorValue; + PROCESSOR_NUMBER CurrentIdealProcessor; + ULONG IdealProcessorValue; - struct - { - UCHAR ReservedPad0; - UCHAR ReservedPad1; - UCHAR ReservedPad2; - UCHAR IdealProcessor; - }; + struct + { + UCHAR ReservedPad0; + UCHAR ReservedPad1; + UCHAR ReservedPad2; + UCHAR IdealProcessor; + }; }; - union TEB_CROSS_TEB_FLAGS_UNION { - USHORT CrossTebFlags; - USHORT SpareCrossTebBits : 16; + USHORT CrossTebFlags; + USHORT SpareCrossTebBits : 16; }; union TEB_SAME_TEB_FLAGS_UNION { - USHORT SameTebFlags; + USHORT SameTebFlags; - struct - { - USHORT SafeThunkCall : 1; - USHORT InDebugPrint : 1; - USHORT HasFiberData : 1; - USHORT SkipThreadAttach : 1; - USHORT WerInShipAssertCode : 1; - USHORT RanProcessInit : 1; - USHORT ClonedThread : 1; - USHORT SuppressDebugMsg : 1; - USHORT DisableUserStackWalk : 1; - USHORT RtlExceptionAttached : 1; - USHORT InitialThread : 1; - USHORT SessionAware : 1; - USHORT LoadOwner : 1; - USHORT LoaderWorker : 1; - USHORT SkipLoaderInit : 1; - USHORT SkipFileAPIBrokering : 1; - }; + struct + { + USHORT SafeThunkCall : 1; + USHORT InDebugPrint : 1; + USHORT HasFiberData : 1; + USHORT SkipThreadAttach : 1; + USHORT WerInShipAssertCode : 1; + USHORT RanProcessInit : 1; + USHORT ClonedThread : 1; + USHORT SuppressDebugMsg : 1; + USHORT DisableUserStackWalk : 1; + USHORT RtlExceptionAttached : 1; + USHORT InitialThread : 1; + USHORT SessionAware : 1; + USHORT LoadOwner : 1; + USHORT LoaderWorker : 1; + USHORT SkipLoaderInit : 1; + USHORT SkipFileAPIBrokering : 1; + }; }; #ifndef OS_WINDOWS @@ -429,247 +428,251 @@ using LCID = DWORD; typedef struct _TEB64 { - EMU_NT_TIB64 NtTib; + EMU_NT_TIB64 NtTib; - std::uint64_t* EnvironmentPointer; - CLIENT_ID64 ClientId; - std::uint64_t* ActiveRpcHandle; - std::uint64_t* ThreadLocalStoragePointer; - PPEB64 ProcessEnvironmentBlock; + std::uint64_t* EnvironmentPointer; + CLIENT_ID64 ClientId; + std::uint64_t* ActiveRpcHandle; + std::uint64_t* ThreadLocalStoragePointer; + PPEB64 ProcessEnvironmentBlock; - ULONG LastErrorValue; - ULONG CountOfOwnedCriticalSections; - std::uint64_t* CsrClientThread; - std::uint64_t* Win32ThreadInfo; - ARRAY_CONTAINER User32Reserved; - ARRAY_CONTAINER UserReserved; - std::uint64_t* WOW32Reserved; - LCID CurrentLocale; - ULONG FpSoftwareStatusRegister; - ARRAY_CONTAINER ReservedForDebuggerInstrumentation; - ARRAY_CONTAINER SystemReserved1; - std::uint64_t* HeapFlsData; - ARRAY_CONTAINER RngState; - CHAR PlaceholderCompatibilityMode; - BOOLEAN PlaceholderHydrationAlwaysExplicit; - ARRAY_CONTAINER PlaceholderReserved; + ULONG LastErrorValue; + ULONG CountOfOwnedCriticalSections; + std::uint64_t* CsrClientThread; + std::uint64_t* Win32ThreadInfo; + ARRAY_CONTAINER User32Reserved; + ARRAY_CONTAINER UserReserved; + std::uint64_t* WOW32Reserved; + LCID CurrentLocale; + ULONG FpSoftwareStatusRegister; + ARRAY_CONTAINER ReservedForDebuggerInstrumentation; + ARRAY_CONTAINER SystemReserved1; + std::uint64_t* HeapFlsData; + ARRAY_CONTAINER RngState; + CHAR PlaceholderCompatibilityMode; + BOOLEAN PlaceholderHydrationAlwaysExplicit; + ARRAY_CONTAINER PlaceholderReserved; - ULONG ProxiedProcessId; - ACTIVATION_CONTEXT_STACK64 ActivationStack; + ULONG ProxiedProcessId; + ACTIVATION_CONTEXT_STACK64 ActivationStack; - ARRAY_CONTAINER WorkingOnBehalfTicket; + ARRAY_CONTAINER WorkingOnBehalfTicket; - NTSTATUS ExceptionCode; + NTSTATUS ExceptionCode; - PACTIVATION_CONTEXT_STACK64 ActivationContextStackPointer; - std::uint64_t* InstrumentationCallbackSp; - std::uint64_t* InstrumentationCallbackPreviousPc; - std::uint64_t* InstrumentationCallbackPreviousSp; - ULONG TxFsContext; - BOOLEAN InstrumentationCallbackDisabled; - BOOLEAN UnalignedLoadStoreExceptions; - GDI_TEB_BATCH64 GdiTebBatch; - CLIENT_ID64 RealClientId; - EmulatorTraits::HANDLE GdiCachedProcessHandle; - ULONG GdiClientPID; - ULONG GdiClientTID; - std::uint64_t* GdiThreadLocalInfo; - ARRAY_CONTAINER Win32ClientInfo; + PACTIVATION_CONTEXT_STACK64 ActivationContextStackPointer; + std::uint64_t* InstrumentationCallbackSp; + std::uint64_t* InstrumentationCallbackPreviousPc; + std::uint64_t* InstrumentationCallbackPreviousSp; + ULONG TxFsContext; + BOOLEAN InstrumentationCallbackDisabled; + BOOLEAN UnalignedLoadStoreExceptions; + GDI_TEB_BATCH64 GdiTebBatch; + CLIENT_ID64 RealClientId; + EmulatorTraits::HANDLE GdiCachedProcessHandle; + ULONG GdiClientPID; + ULONG GdiClientTID; + std::uint64_t* GdiThreadLocalInfo; + ARRAY_CONTAINER Win32ClientInfo; - ARRAY_CONTAINER glDispatchTable; - ARRAY_CONTAINER glReserved1; - std::uint64_t* glReserved2; - std::uint64_t* glSectionInfo; - std::uint64_t* glSection; - std::uint64_t* glTable; - std::uint64_t* glCurrentRC; - std::uint64_t* glContext; + ARRAY_CONTAINER glDispatchTable; + ARRAY_CONTAINER glReserved1; + std::uint64_t* glReserved2; + std::uint64_t* glSectionInfo; + std::uint64_t* glSection; + std::uint64_t* glTable; + std::uint64_t* glCurrentRC; + std::uint64_t* glContext; - NTSTATUS LastStatusValue; + NTSTATUS LastStatusValue; - UNICODE_STRING> StaticUnicodeString; - ARRAY_CONTAINER StaticUnicodeBuffer; + UNICODE_STRING> StaticUnicodeString; + ARRAY_CONTAINER StaticUnicodeBuffer; - std::uint64_t* DeallocationStack; + std::uint64_t* DeallocationStack; - ARRAY_CONTAINER TlsSlots; - LIST_ENTRY64 TlsLinks; + ARRAY_CONTAINER TlsSlots; + LIST_ENTRY64 TlsLinks; - std::uint64_t* Vdm; - std::uint64_t* ReservedForNtRpc; - ARRAY_CONTAINER DbgSsReserved; + std::uint64_t* Vdm; + std::uint64_t* ReservedForNtRpc; + ARRAY_CONTAINER DbgSsReserved; - ULONG HardErrorMode; - ARRAY_CONTAINER Instrumentation; - GUID ActivityId; + ULONG HardErrorMode; + ARRAY_CONTAINER Instrumentation; + GUID ActivityId; - std::uint64_t* SubProcessTag; - std::uint64_t* PerflibData; - std::uint64_t* EtwTraceData; - std::uint64_t* WinSockData; - ULONG GdiBatchCount; + std::uint64_t* SubProcessTag; + std::uint64_t* PerflibData; + std::uint64_t* EtwTraceData; + std::uint64_t* WinSockData; + ULONG GdiBatchCount; - TEB_CURRENT_IDEAL_PROCESSOR_UNION CurrentIdealProcessor; + TEB_CURRENT_IDEAL_PROCESSOR_UNION CurrentIdealProcessor; - ULONG GuaranteedStackBytes; - std::uint64_t* ReservedForPerf; - std::uint64_t* ReservedForOle; // tagSOleTlsData - ULONG WaitingOnLoaderLock; - std::uint64_t* SavedPriorityState; - std::uint64_t* ReservedForCodeCoverage; - std::uint64_t* ThreadPoolData; - std::uint64_t** TlsExpansionSlots; - std::uint64_t* ChpeV2CpuAreaInfo; // CHPEV2_CPUAREA_INFO // previously DeallocationBStore - std::uint64_t* Unused; // previously BStoreLimit - ULONG MuiGeneration; - ULONG IsImpersonating; - std::uint64_t* NlsCache; - std::uint64_t* pShimData; - ULONG HeapData; - EmulatorTraits::HANDLE CurrentTransactionHandle; - EMULATOR_CAST(void*, PTEB_ACTIVE_FRAME) ActiveFrame; - std::uint64_t* FlsData; + ULONG GuaranteedStackBytes; + std::uint64_t* ReservedForPerf; + std::uint64_t* ReservedForOle; // tagSOleTlsData + ULONG WaitingOnLoaderLock; + std::uint64_t* SavedPriorityState; + std::uint64_t* ReservedForCodeCoverage; + std::uint64_t* ThreadPoolData; + std::uint64_t** TlsExpansionSlots; + std::uint64_t* ChpeV2CpuAreaInfo; // CHPEV2_CPUAREA_INFO // previously DeallocationBStore + std::uint64_t* Unused; // previously BStoreLimit + ULONG MuiGeneration; + ULONG IsImpersonating; + std::uint64_t* NlsCache; + std::uint64_t* pShimData; + ULONG HeapData; + EmulatorTraits::HANDLE CurrentTransactionHandle; + EMULATOR_CAST(void*, PTEB_ACTIVE_FRAME) ActiveFrame; + std::uint64_t* FlsData; - std::uint64_t* PreferredLanguages; - std::uint64_t* UserPrefLanguages; - std::uint64_t* MergedPrefLanguages; - ULONG MuiImpersonation; + std::uint64_t* PreferredLanguages; + std::uint64_t* UserPrefLanguages; + std::uint64_t* MergedPrefLanguages; + ULONG MuiImpersonation; - TEB_CROSS_TEB_FLAGS_UNION CrossTebFlags; - TEB_SAME_TEB_FLAGS_UNION SameTebFlags; + TEB_CROSS_TEB_FLAGS_UNION CrossTebFlags; + TEB_SAME_TEB_FLAGS_UNION SameTebFlags; - std::uint64_t* TxnScopeEnterCallback; - std::uint64_t* TxnScopeExitCallback; - std::uint64_t* TxnScopeContext; - ULONG LockCount; - LONG WowTebOffset; - std::uint64_t* ResourceRetValue; - std::uint64_t* ReservedForWdf; - ULONGLONG ReservedForCrt; - GUID EffectiveContainerId; - ULONGLONG LastSleepCounter; // Win11 - ULONG SpinCallCount; - ULONGLONG ExtendedFeatureDisableMask; - std::uint64_t* SchedulerSharedDataSlot; // 24H2 - std::uint64_t* HeapWalkContext; - EMU_GROUP_AFFINITY64 PrimaryGroupAffinity; - ARRAY_CONTAINER Rcu; + std::uint64_t* TxnScopeEnterCallback; + std::uint64_t* TxnScopeExitCallback; + std::uint64_t* TxnScopeContext; + ULONG LockCount; + LONG WowTebOffset; + std::uint64_t* ResourceRetValue; + std::uint64_t* ReservedForWdf; + ULONGLONG ReservedForCrt; + GUID EffectiveContainerId; + ULONGLONG LastSleepCounter; // Win11 + ULONG SpinCallCount; + ULONGLONG ExtendedFeatureDisableMask; + std::uint64_t* SchedulerSharedDataSlot; // 24H2 + std::uint64_t* HeapWalkContext; + EMU_GROUP_AFFINITY64 PrimaryGroupAffinity; + ARRAY_CONTAINER Rcu; } TEB64, *PTEB64; #ifdef OS_WINDOWS -inline TEB64* NtCurrentTeb64(VOID) +inline TEB64* NtCurrentTeb64() { - return (TEB64*)__readgsqword(FIELD_OFFSET(EMU_NT_TIB64, Self)); + return reinterpret_cast(__readgsqword(FIELD_OFFSET(EMU_NT_TIB64, Self))); } #endif #pragma pack(push, 4) typedef struct _KSYSTEM_TIME { - ULONG LowPart; - LONG High1Time; - LONG High2Time; + ULONG LowPart; + LONG High1Time; + LONG High2Time; } KSYSTEM_TIME, *PKSYSTEM_TIME; #pragma pack(pop) typedef enum _NT_PRODUCT_TYPE { - NtProductWinNt = 1, - NtProductLanManNt, - NtProductServer + NtProductWinNt = 1, + NtProductLanManNt, + NtProductServer } NT_PRODUCT_TYPE, *PNT_PRODUCT_TYPE; typedef enum _ALTERNATIVE_ARCHITECTURE_TYPE { - StandardDesign, - NEC98x86, - EndAlternatives + StandardDesign, + NEC98x86, + EndAlternatives } ALTERNATIVE_ARCHITECTURE_TYPE; union KUSD_SHARED_DATA_FLAGS_UNION { - ULONG SharedDataFlags; + ULONG SharedDataFlags; - struct - { - // - // The following bit fields are for the debugger only. Do not use. - // Use the bit definitions instead. - // + struct + { + // + // The following bit fields are for the debugger only. Do not use. + // Use the bit definitions instead. + // - ULONG DbgErrorPortPresent : 1; - ULONG DbgElevationEnabled : 1; - ULONG DbgVirtEnabled : 1; - ULONG DbgInstallerDetectEnabled : 1; - ULONG DbgLkgEnabled : 1; - ULONG DbgDynProcessorEnabled : 1; - ULONG DbgConsoleBrokerEnabled : 1; - ULONG DbgSecureBootEnabled : 1; - ULONG DbgMultiSessionSku : 1; - ULONG DbgMultiUsersInSessionSku : 1; - ULONG DbgStateSeparationEnabled : 1; - ULONG DbgSplitTokenEnabled : 1; - ULONG DbgShadowAdminEnabled : 1; - ULONG SpareBits : 19; - }; + ULONG DbgErrorPortPresent : 1; + ULONG DbgElevationEnabled : 1; + ULONG DbgVirtEnabled : 1; + ULONG DbgInstallerDetectEnabled : 1; + ULONG DbgLkgEnabled : 1; + ULONG DbgDynProcessorEnabled : 1; + ULONG DbgConsoleBrokerEnabled : 1; + ULONG DbgSecureBootEnabled : 1; + ULONG DbgMultiSessionSku : 1; + ULONG DbgMultiUsersInSessionSku : 1; + ULONG DbgStateSeparationEnabled : 1; + ULONG DbgSplitTokenEnabled : 1; + ULONG DbgShadowAdminEnabled : 1; + ULONG SpareBits : 19; + }; }; union KUSD_TICK_COUNT_UNION { - volatile KSYSTEM_TIME TickCount; - volatile std::uint64_t TickCountQuad; + volatile KSYSTEM_TIME TickCount; + volatile std::uint64_t TickCountQuad; - struct - { - ULONG ReservedTickCountOverlay[3]; - ULONG TickCountPad[1]; - }; + struct + { + ULONG ReservedTickCountOverlay[3]; + ULONG TickCountPad[1]; + }; }; union KUSD_VIRTUALIZATION_FLAGS_UNION { - UCHAR VirtualizationFlags; + UCHAR VirtualizationFlags; }; union KUSD_MITIGATION_POLICIES_UNION { - UCHAR MitigationPolicies; + UCHAR MitigationPolicies; - struct - { - UCHAR NXSupportPolicy : 2; - UCHAR SEHValidationPolicy : 2; - UCHAR CurDirDevicesSkippedForDlls : 2; - UCHAR Reserved : 2; - }; + struct + { + UCHAR NXSupportPolicy : 2; + UCHAR SEHValidationPolicy : 2; + UCHAR CurDirDevicesSkippedForDlls : 2; + UCHAR Reserved : 2; + }; }; union KUSD_QPC_DATA_UNION { - USHORT QpcData; + USHORT QpcData; - struct - { - volatile UCHAR QpcBypassEnabled; - UCHAR QpcReserved; - }; + struct + { + volatile UCHAR QpcBypassEnabled; + UCHAR QpcReserved; + }; }; #ifndef OS_WINDOWS #define MAXIMUM_XSTATE_FEATURES 64 -typedef struct _XSTATE_FEATURE { +typedef struct _XSTATE_FEATURE +{ ULONG Offset; ULONG Size; } XSTATE_FEATURE; -typedef struct _XSTATE_CONFIGURATION { +typedef struct _XSTATE_CONFIGURATION +{ std::uint64_t EnabledFeatures; std::uint64_t EnabledVolatileFeatures; ULONG Size; - union { + union + { ULONG ControlFlags; - struct { + struct + { ULONG OptimizedSave : 1; ULONG CompactionEnabled : 1; ULONG Reserved1 : 30; @@ -686,201 +689,201 @@ typedef struct _XSTATE_CONFIGURATION { typedef struct _KUSER_SHARED_DATA64 { - ULONG TickCountLowDeprecated; - ULONG TickCountMultiplier; - volatile KSYSTEM_TIME InterruptTime; - volatile KSYSTEM_TIME SystemTime; - volatile KSYSTEM_TIME TimeZoneBias; - USHORT ImageNumberLow; - USHORT ImageNumberHigh; - ARRAY_CONTAINER NtSystemRoot; - ULONG MaxStackTraceDepth; - ULONG CryptoExponent; - ULONG TimeZoneId; - ULONG LargePageMinimum; - ULONG AitSamplingValue; - ULONG AppCompatFlag; - ULONGLONG RNGSeedVersion; - ULONG GlobalValidationRunlevel; - volatile LONG TimeZoneBiasStamp; - ULONG NtBuildNumber; - NT_PRODUCT_TYPE NtProductType; - BOOLEAN ProductTypeIsValid; - BOOLEAN Reserved0; - USHORT NativeProcessorArchitecture; - ULONG NtMajorVersion; - ULONG NtMinorVersion; - ARRAY_CONTAINER ProcessorFeatures; - ULONG Reserved1; - ULONG Reserved3; - volatile ULONG TimeSlip; - ALTERNATIVE_ARCHITECTURE_TYPE AlternativeArchitecture; - ULONG BootId; - LARGE_INTEGER SystemExpirationDate; - ULONG SuiteMask; - BOOLEAN KdDebuggerEnabled; - KUSD_MITIGATION_POLICIES_UNION MitigationPolicies; - USHORT CyclesPerYield; - volatile ULONG ActiveConsoleId; - volatile ULONG DismountCount; - ULONG ComPlusPackage; - ULONG LastSystemRITEventTickCount; - ULONG NumberOfPhysicalPages; - BOOLEAN SafeBootMode; - KUSD_VIRTUALIZATION_FLAGS_UNION VirtualizationFlags; - ARRAY_CONTAINER Reserved12; - KUSD_SHARED_DATA_FLAGS_UNION SharedDataFlags; - ULONG DataFlagsPad; - ULONGLONG TestRetInstruction; - LONGLONG QpcFrequency; - ULONG SystemCall; - ULONG Reserved2; - ULONGLONG FullNumberOfPhysicalPages; - ULONGLONG SystemCallPad; - KUSD_TICK_COUNT_UNION TickCount; - ULONG Cookie; - ULONG CookiePad; - LONGLONG ConsoleSessionForegroundProcessId; - ULONGLONG TimeUpdateLock; - ULONGLONG BaselineSystemTimeQpc; - ULONGLONG BaselineInterruptTimeQpc; - ULONGLONG QpcSystemTimeIncrement; - ULONGLONG QpcInterruptTimeIncrement; - UCHAR QpcSystemTimeIncrementShift; - UCHAR QpcInterruptTimeIncrementShift; - USHORT UnparkedProcessorCount; - ARRAY_CONTAINER EnclaveFeatureMask; - ULONG TelemetryCoverageRound; - ARRAY_CONTAINER UserModeGlobalLogger; - ULONG ImageFileExecutionOptions; - ULONG LangGenerationCount; - ULONGLONG Reserved4; - volatile ULONGLONG InterruptTimeBias; - volatile ULONGLONG QpcBias; - ULONG ActiveProcessorCount; - volatile UCHAR ActiveGroupCount; - UCHAR Reserved9; - KUSD_QPC_DATA_UNION QpcData; - LARGE_INTEGER TimeZoneBiasEffectiveStart; - LARGE_INTEGER TimeZoneBiasEffectiveEnd; - XSTATE_CONFIGURATION XState; - KSYSTEM_TIME FeatureConfigurationChangeStamp; - ULONG Spare; - std::uint64_t UserPointerAuthMask; - ARRAY_CONTAINER Reserved10; + ULONG TickCountLowDeprecated; + ULONG TickCountMultiplier; + volatile KSYSTEM_TIME InterruptTime; + volatile KSYSTEM_TIME SystemTime; + volatile KSYSTEM_TIME TimeZoneBias; + USHORT ImageNumberLow; + USHORT ImageNumberHigh; + ARRAY_CONTAINER NtSystemRoot; + ULONG MaxStackTraceDepth; + ULONG CryptoExponent; + ULONG TimeZoneId; + ULONG LargePageMinimum; + ULONG AitSamplingValue; + ULONG AppCompatFlag; + ULONGLONG RNGSeedVersion; + ULONG GlobalValidationRunlevel; + volatile LONG TimeZoneBiasStamp; + ULONG NtBuildNumber; + NT_PRODUCT_TYPE NtProductType; + BOOLEAN ProductTypeIsValid; + BOOLEAN Reserved0; + USHORT NativeProcessorArchitecture; + ULONG NtMajorVersion; + ULONG NtMinorVersion; + ARRAY_CONTAINER ProcessorFeatures; + ULONG Reserved1; + ULONG Reserved3; + volatile ULONG TimeSlip; + ALTERNATIVE_ARCHITECTURE_TYPE AlternativeArchitecture; + ULONG BootId; + LARGE_INTEGER SystemExpirationDate; + ULONG SuiteMask; + BOOLEAN KdDebuggerEnabled; + KUSD_MITIGATION_POLICIES_UNION MitigationPolicies; + USHORT CyclesPerYield; + volatile ULONG ActiveConsoleId; + volatile ULONG DismountCount; + ULONG ComPlusPackage; + ULONG LastSystemRITEventTickCount; + ULONG NumberOfPhysicalPages; + BOOLEAN SafeBootMode; + KUSD_VIRTUALIZATION_FLAGS_UNION VirtualizationFlags; + ARRAY_CONTAINER Reserved12; + KUSD_SHARED_DATA_FLAGS_UNION SharedDataFlags; + ULONG DataFlagsPad; + ULONGLONG TestRetInstruction; + LONGLONG QpcFrequency; + ULONG SystemCall; + ULONG Reserved2; + ULONGLONG FullNumberOfPhysicalPages; + ULONGLONG SystemCallPad; + KUSD_TICK_COUNT_UNION TickCount; + ULONG Cookie; + ULONG CookiePad; + LONGLONG ConsoleSessionForegroundProcessId; + ULONGLONG TimeUpdateLock; + ULONGLONG BaselineSystemTimeQpc; + ULONGLONG BaselineInterruptTimeQpc; + ULONGLONG QpcSystemTimeIncrement; + ULONGLONG QpcInterruptTimeIncrement; + UCHAR QpcSystemTimeIncrementShift; + UCHAR QpcInterruptTimeIncrementShift; + USHORT UnparkedProcessorCount; + ARRAY_CONTAINER EnclaveFeatureMask; + ULONG TelemetryCoverageRound; + ARRAY_CONTAINER UserModeGlobalLogger; + ULONG ImageFileExecutionOptions; + ULONG LangGenerationCount; + ULONGLONG Reserved4; + volatile ULONGLONG InterruptTimeBias; + volatile ULONGLONG QpcBias; + ULONG ActiveProcessorCount; + volatile UCHAR ActiveGroupCount; + UCHAR Reserved9; + KUSD_QPC_DATA_UNION QpcData; + LARGE_INTEGER TimeZoneBiasEffectiveStart; + LARGE_INTEGER TimeZoneBiasEffectiveEnd; + XSTATE_CONFIGURATION XState; + KSYSTEM_TIME FeatureConfigurationChangeStamp; + ULONG Spare; + std::uint64_t UserPointerAuthMask; + ARRAY_CONTAINER Reserved10; } KUSER_SHARED_DATA64, *PKUSER_SHARED_DATA64; typedef struct _API_SET_NAMESPACE_ENTRY { - ULONG Flags; - ULONG NameOffset; - ULONG NameLength; - ULONG HashedLength; - ULONG ValueOffset; - ULONG ValueCount; + ULONG Flags; + ULONG NameOffset; + ULONG NameLength; + ULONG HashedLength; + ULONG ValueOffset; + ULONG ValueCount; } API_SET_NAMESPACE_ENTRY, *PAPI_SET_NAMESPACE_ENTRY; typedef struct _API_SET_HASH_ENTRY { - ULONG Hash; - ULONG Index; + ULONG Hash; + ULONG Index; } API_SET_HASH_ENTRY, *PAPI_SET_HASH_ENTRY; typedef struct _API_SET_VALUE_ENTRY { - ULONG Flags; - ULONG NameOffset; - ULONG NameLength; - ULONG ValueOffset; - ULONG ValueLength; + ULONG Flags; + ULONG NameOffset; + ULONG NameLength; + ULONG ValueOffset; + ULONG ValueLength; } API_SET_VALUE_ENTRY, *PAPI_SET_VALUE_ENTRY; template struct PS_ATTRIBUTE { - typename Traits::ULONG_PTR Attribute; - typename Traits::SIZE_T Size; + typename Traits::ULONG_PTR Attribute; + typename Traits::SIZE_T Size; - union - { - typename Traits::ULONG_PTR Value; - typename Traits::PVOID ValuePtr; - }; + union + { + typename Traits::ULONG_PTR Value; + typename Traits::PVOID ValuePtr; + }; - typename Traits::SIZE_T* ReturnLength; + typename Traits::SIZE_T* ReturnLength; }; template struct PS_ATTRIBUTE_LIST { - typename Traits::SIZE_T TotalLength; - PS_ATTRIBUTE Attributes[1]; + typename Traits::SIZE_T TotalLength; + PS_ATTRIBUTE Attributes[1]; }; typedef struct _SYSTEM_TIMEOFDAY_INFORMATION64 { - LARGE_INTEGER BootTime; - LARGE_INTEGER CurrentTime; - LARGE_INTEGER TimeZoneBias; - ULONG TimeZoneId; - ULONG Reserved; - ULONGLONG BootTimeBias; - ULONGLONG SleepTimeBias; + LARGE_INTEGER BootTime; + LARGE_INTEGER CurrentTime; + LARGE_INTEGER TimeZoneBias; + ULONG TimeZoneId; + ULONG Reserved; + ULONGLONG BootTimeBias; + ULONGLONG SleepTimeBias; } SYSTEM_TIMEOFDAY_INFORMATION64, *PSYSTEM_TIMEOFDAY_INFORMATION64; typedef struct _PROCESS_BASIC_INFORMATION64 { - NTSTATUS ExitStatus; - PPEB64 PebBaseAddress; - EMULATOR_CAST(std::uint64_t, KAFFINITY) AffinityMask; - EMULATOR_CAST(std::uint32_t, KPRIORITY) BasePriority; - EMULATOR_CAST(std::uint64_t, HANDLE) UniqueProcessId; - EMULATOR_CAST(std::uint64_t, HANDLE) InheritedFromUniqueProcessId; + NTSTATUS ExitStatus; + PPEB64 PebBaseAddress; + EMULATOR_CAST(std::uint64_t, KAFFINITY) AffinityMask; + EMULATOR_CAST(std::uint32_t, KPRIORITY) BasePriority; + EMULATOR_CAST(std::uint64_t, HANDLE) UniqueProcessId; + EMULATOR_CAST(std::uint64_t, HANDLE) InheritedFromUniqueProcessId; } PROCESS_BASIC_INFORMATION64, *PPROCESS_BASIC_INFORMATION64; typedef struct _KERNEL_USER_TIMES { - LARGE_INTEGER CreateTime; - LARGE_INTEGER ExitTime; - LARGE_INTEGER KernelTime; - LARGE_INTEGER UserTime; + LARGE_INTEGER CreateTime; + LARGE_INTEGER ExitTime; + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; } KERNEL_USER_TIMES, *PKERNEL_USER_TIMES; struct THREAD_TLS_INFO { - ULONG Flags; + ULONG Flags; - union - { - EmulatorTraits::PVOID* TlsVector; - EmulatorTraits::PVOID TlsModulePointer; - }; + union + { + EmulatorTraits::PVOID* TlsVector; + EmulatorTraits::PVOID TlsModulePointer; + }; - EMULATOR_CAST(std::uint64_t, ULONG_PTR) ThreadId; + EMULATOR_CAST(std::uint64_t, ULONG_PTR) ThreadId; }; static_assert(sizeof(THREAD_TLS_INFO) == 0x18); typedef enum _PROCESS_TLS_INFORMATION_TYPE { - ProcessTlsReplaceIndex, - ProcessTlsReplaceVector, - MaxProcessTlsOperation + ProcessTlsReplaceIndex, + ProcessTlsReplaceVector, + MaxProcessTlsOperation } PROCESS_TLS_INFORMATION_TYPE, *PPROCESS_TLS_INFORMATION_TYPE; struct PROCESS_TLS_INFO { - ULONG Unknown; - PROCESS_TLS_INFORMATION_TYPE TlsRequest; - ULONG ThreadDataCount; + ULONG Unknown; + PROCESS_TLS_INFORMATION_TYPE TlsRequest; + ULONG ThreadDataCount; - union - { - ULONG TlsIndex; - ULONG TlsVectorLength; - }; + union + { + ULONG TlsIndex; + ULONG TlsVectorLength; + }; - THREAD_TLS_INFO ThreadData[1]; + THREAD_TLS_INFO ThreadData[1]; }; static_assert(sizeof(PROCESS_TLS_INFO) - sizeof(THREAD_TLS_INFO) == 0x10); diff --git a/src/common/platform/memory.hpp b/src/common/platform/memory.hpp index 8d8758c0..7d2dcbd0 100644 --- a/src/common/platform/memory.hpp +++ b/src/common/platform/memory.hpp @@ -1,21 +1,21 @@ #pragma once -#define PAGE_EXECUTE 0x10 -#define PAGE_EXECUTE_READ 0x20 -#define PAGE_EXECUTE_READWRITE 0x40 -#define PAGE_EXECUTE_WRITECOPY 0x80 +#define PAGE_EXECUTE 0x10 +#define PAGE_EXECUTE_READ 0x20 +#define PAGE_EXECUTE_READWRITE 0x40 +#define PAGE_EXECUTE_WRITECOPY 0x80 -#define PAGE_NOACCESS 0x01 -#define PAGE_READONLY 0x02 -#define PAGE_READWRITE 0x04 -#define PAGE_WRITECOPY 0x08 +#define PAGE_NOACCESS 0x01 +#define PAGE_READONLY 0x02 +#define PAGE_READWRITE 0x04 +#define PAGE_WRITECOPY 0x08 -#define PAGE_TARGETS_INVALID 0x40000000 -#define PAGE_TARGETS_NO_UPDATE 0x40000000 +#define PAGE_TARGETS_INVALID 0x40000000 +#define PAGE_TARGETS_NO_UPDATE 0x40000000 -#define PAGE_GUARD 0x100 -#define PAGE_NOCACHE 0x200 -#define PAGE_WRITECOMBINE 0x400 +#define PAGE_GUARD 0x100 +#define PAGE_NOCACHE 0x200 +#define PAGE_WRITECOMBINE 0x400 #define MEM_COMMIT 0x00001000 #define MEM_RESERVE 0x00002000 @@ -38,94 +38,92 @@ typedef enum _MEMORY_INFORMATION_CLASS { - MemoryBasicInformation, // q: MEMORY_BASIC_INFORMATION - MemoryWorkingSetInformation, // q: MEMORY_WORKING_SET_INFORMATION - MemoryMappedFilenameInformation, // q: UNICODE_STRING - MemoryRegionInformation, // q: MEMORY_REGION_INFORMATION - MemoryWorkingSetExInformation, // q: MEMORY_WORKING_SET_EX_INFORMATION // since VISTA - MemorySharedCommitInformation, // q: MEMORY_SHARED_COMMIT_INFORMATION // since WIN8 - MemoryImageInformation, // q: MEMORY_IMAGE_INFORMATION - MemoryRegionInformationEx, // MEMORY_REGION_INFORMATION - MemoryPrivilegedBasicInformation, // MEMORY_BASIC_INFORMATION - MemoryEnclaveImageInformation, // MEMORY_ENCLAVE_IMAGE_INFORMATION // since REDSTONE3 - MemoryBasicInformationCapped, // 10 - MemoryPhysicalContiguityInformation, // MEMORY_PHYSICAL_CONTIGUITY_INFORMATION // since 20H1 - MemoryBadInformation, // since WIN11 - MemoryBadInformationAllProcesses, // since 22H1 - MemoryImageExtensionInformation, // since 24H2 - MaxMemoryInfoClass + MemoryBasicInformation, // q: MEMORY_BASIC_INFORMATION + MemoryWorkingSetInformation, // q: MEMORY_WORKING_SET_INFORMATION + MemoryMappedFilenameInformation, // q: UNICODE_STRING + MemoryRegionInformation, // q: MEMORY_REGION_INFORMATION + MemoryWorkingSetExInformation, // q: MEMORY_WORKING_SET_EX_INFORMATION // since VISTA + MemorySharedCommitInformation, // q: MEMORY_SHARED_COMMIT_INFORMATION // since WIN8 + MemoryImageInformation, // q: MEMORY_IMAGE_INFORMATION + MemoryRegionInformationEx, // MEMORY_REGION_INFORMATION + MemoryPrivilegedBasicInformation, // MEMORY_BASIC_INFORMATION + MemoryEnclaveImageInformation, // MEMORY_ENCLAVE_IMAGE_INFORMATION // since REDSTONE3 + MemoryBasicInformationCapped, // 10 + MemoryPhysicalContiguityInformation, // MEMORY_PHYSICAL_CONTIGUITY_INFORMATION // since 20H1 + MemoryBadInformation, // since WIN11 + MemoryBadInformationAllProcesses, // since 22H1 + MemoryImageExtensionInformation, // since 24H2 + MaxMemoryInfoClass } MEMORY_INFORMATION_CLASS; typedef enum _SECTION_INHERIT { - ViewShare = 1, - ViewUnmap = 2 + ViewShare = 1, + ViewUnmap = 2 } SECTION_INHERIT; - typedef struct DECLSPEC_ALIGN(16) _EMU_MEMORY_BASIC_INFORMATION64 { - void* BaseAddress; - void* AllocationBase; - DWORD AllocationProtect; - WORD PartitionId; - std::int64_t RegionSize; - DWORD State; - DWORD Protect; - DWORD Type; + void* BaseAddress; + void* AllocationBase; + DWORD AllocationProtect; + WORD PartitionId; + std::int64_t RegionSize; + DWORD State; + DWORD Protect; + DWORD Type; } EMU_MEMORY_BASIC_INFORMATION64, *PEMU_MEMORY_BASIC_INFORMATION64; - typedef struct _MEMORY_IMAGE_INFORMATION64 { - void* ImageBase; - std::int64_t SizeOfImage; + void* ImageBase; + std::int64_t SizeOfImage; - union - { - ULONG ImageFlags; + union + { + ULONG ImageFlags; - struct - { - ULONG ImagePartialMap : 1; - ULONG ImageNotExecutable : 1; - ULONG ImageSigningLevel : 4; // REDSTONE3 - ULONG ImageExtensionPresent : 1; // since 24H2 - ULONG Reserved : 25; - }; - }; + struct + { + ULONG ImagePartialMap : 1; + ULONG ImageNotExecutable : 1; + ULONG ImageSigningLevel : 4; // REDSTONE3 + ULONG ImageExtensionPresent : 1; // since 24H2 + ULONG Reserved : 25; + }; + }; } MEMORY_IMAGE_INFORMATION64, *PMEMORY_IMAGE_INFORMATION64; typedef struct _MEMORY_REGION_INFORMATION { - void* AllocationBase; - ULONG AllocationProtect; + void* AllocationBase; + ULONG AllocationProtect; - union - { - ULONG RegionType; + union + { + ULONG RegionType; - struct - { - ULONG Private : 1; - ULONG MappedDataFile : 1; - ULONG MappedImage : 1; - ULONG MappedPageFile : 1; - ULONG MappedPhysical : 1; - ULONG DirectMapped : 1; - ULONG SoftwareEnclave : 1; // REDSTONE3 - ULONG PageSize64K : 1; - ULONG PlaceholderReservation : 1; // REDSTONE4 - ULONG MappedAwe : 1; // 21H1 - ULONG MappedWriteWatch : 1; - ULONG PageSizeLarge : 1; - ULONG PageSizeHuge : 1; - ULONG Reserved : 19; - }; - }; + struct + { + ULONG Private : 1; + ULONG MappedDataFile : 1; + ULONG MappedImage : 1; + ULONG MappedPageFile : 1; + ULONG MappedPhysical : 1; + ULONG DirectMapped : 1; + ULONG SoftwareEnclave : 1; // REDSTONE3 + ULONG PageSize64K : 1; + ULONG PlaceholderReservation : 1; // REDSTONE4 + ULONG MappedAwe : 1; // 21H1 + ULONG MappedWriteWatch : 1; + ULONG PageSizeLarge : 1; + ULONG PageSizeHuge : 1; + ULONG Reserved : 19; + }; + }; - std::int64_t RegionSize; - std::int64_t CommitSize; - DWORD64 PartitionId; // 19H1 - DWORD64 NodePreference; // 20H1 + std::int64_t RegionSize; + std::int64_t CommitSize; + DWORD64 PartitionId; // 19H1 + DWORD64 NodePreference; // 20H1 } MEMORY_REGION_INFORMATION64, *PMEMORY_REGION_INFORMATION64; diff --git a/src/common/platform/network.hpp b/src/common/platform/network.hpp index 2e14c0a5..1bd2f8e2 100644 --- a/src/common/platform/network.hpp +++ b/src/common/platform/network.hpp @@ -3,6 +3,6 @@ template struct EMU_WSABUF { - ULONG len; - EMULATOR_CAST(typename Traits::PVOID, CHAR*) buf; + ULONG len; + EMULATOR_CAST(typename Traits::PVOID, CHAR*) buf; }; diff --git a/src/common/platform/platform.hpp b/src/common/platform/platform.hpp index a8730fd9..b6ff1afb 100644 --- a/src/common/platform/platform.hpp +++ b/src/common/platform/platform.hpp @@ -2,8 +2,8 @@ #ifdef _WIN32 #pragma warning(push) -#pragma warning(disable: 4201) // nameless struct/union -#pragma warning(disable: 4702) // unreachable code +#pragma warning(disable : 4201) // nameless struct/union +#pragma warning(disable : 4702) // unreachable code #else #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" @@ -27,18 +27,12 @@ #ifdef OS_WINDOWS #pragma comment(lib, "ntdll") -extern "C" { -NTSYSCALLAPI -NTSTATUS -NTAPI -NtQuerySystemInformationEx( - _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass, - _In_reads_bytes_(InputBufferLength) PVOID InputBuffer, - _In_ ULONG InputBufferLength, - _Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation, - _In_ ULONG SystemInformationLength, - _Out_opt_ PULONG ReturnLength -); +extern "C" +{ + NTSYSCALLAPI NTSTATUS NTAPI NtQuerySystemInformationEx( + _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass, _In_reads_bytes_(InputBufferLength) PVOID InputBuffer, + _In_ ULONG InputBufferLength, _Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation, + _In_ ULONG SystemInformationLength, _Out_opt_ PULONG ReturnLength); } #pragma warning(pop) #else diff --git a/src/common/platform/primitives.hpp b/src/common/platform/primitives.hpp index 3fdb937d..36f6b6a3 100644 --- a/src/common/platform/primitives.hpp +++ b/src/common/platform/primitives.hpp @@ -20,31 +20,30 @@ using LONGLONG = std::int64_t; typedef union _ULARGE_INTEGER { - struct - { - DWORD LowPart; - DWORD HighPart; - }; + struct + { + DWORD LowPart; + DWORD HighPart; + }; - ULONGLONG QuadPart; + ULONGLONG QuadPart; } ULARGE_INTEGER; typedef union _LARGE_INTEGER { - struct - { - DWORD LowPart; - LONG HighPart; - }; + struct + { + DWORD LowPart; + LONG HighPart; + }; - LONGLONG QuadPart; + LONGLONG QuadPart; } LARGE_INTEGER; using BYTE = std::uint8_t; -#define CHAR BYTE +#define CHAR BYTE #endif - using WORD = std::uint16_t; #define UCHAR unsigned char @@ -53,7 +52,6 @@ using WORD = std::uint16_t; using CSHORT = short; using USHORT = WORD; - #define DUMMYSTRUCTNAME #ifndef TRUE diff --git a/src/common/platform/process.hpp b/src/common/platform/process.hpp index f4333648..79e41741 100644 --- a/src/common/platform/process.hpp +++ b/src/common/platform/process.hpp @@ -1,365 +1,376 @@ #pragma once -#define CONTEXT_X86_MAIN 0x00010000 -#define CONTEXT_AMD64_MAIN 0x100000 -#define CONTEXT_CONTROL_32 (CONTEXT_X86_MAIN | 0x1L) -#define CONTEXT_CONTROL_64 (CONTEXT_AMD64_MAIN | 0x1L) -#define CONTEXT_INTEGER_32 (CONTEXT_X86_MAIN | 0x2L) -#define CONTEXT_INTEGER_64 (CONTEXT_AMD64_MAIN | 0x2L) -#define CONTEXT_SEGMENTS_32 (CONTEXT_X86_MAIN | 0x4L) -#define CONTEXT_SEGMENTS_64 (CONTEXT_AMD64_MAIN | 0x4L) -#define CONTEXT_FLOATING_POINT_32 (CONTEXT_X86_MAIN | 0x8L) -#define CONTEXT_FLOATING_POINT_64 (CONTEXT_AMD64_MAIN | 0x8L) -#define CONTEXT_DEBUG_REGISTERS_32 (CONTEXT_X86_MAIN | 0x10L) -#define CONTEXT_DEBUG_REGISTERS_64 (CONTEXT_AMD64_MAIN | 0x10L) -#define CONTEXT_XSTATE_32 (CONTEXT_X86_MAIN | 0x20L) -#define CONTEXT_XSTATE_64 (CONTEXT_AMD64_MAIN | 0x20L) - -#define CONTEXT64_ALL (CONTEXT_CONTROL_64 | CONTEXT_INTEGER_64 | CONTEXT_SEGMENTS_64 | \ - CONTEXT_FLOATING_POINT_64 | CONTEXT_DEBUG_REGISTERS_64) +#define CONTEXT_X86_MAIN 0x00010000 +#define CONTEXT_AMD64_MAIN 0x100000 +#define CONTEXT_CONTROL_32 (CONTEXT_X86_MAIN | 0x1L) +#define CONTEXT_CONTROL_64 (CONTEXT_AMD64_MAIN | 0x1L) +#define CONTEXT_INTEGER_32 (CONTEXT_X86_MAIN | 0x2L) +#define CONTEXT_INTEGER_64 (CONTEXT_AMD64_MAIN | 0x2L) +#define CONTEXT_SEGMENTS_32 (CONTEXT_X86_MAIN | 0x4L) +#define CONTEXT_SEGMENTS_64 (CONTEXT_AMD64_MAIN | 0x4L) +#define CONTEXT_FLOATING_POINT_32 (CONTEXT_X86_MAIN | 0x8L) +#define CONTEXT_FLOATING_POINT_64 (CONTEXT_AMD64_MAIN | 0x8L) +#define CONTEXT_DEBUG_REGISTERS_32 (CONTEXT_X86_MAIN | 0x10L) +#define CONTEXT_DEBUG_REGISTERS_64 (CONTEXT_AMD64_MAIN | 0x10L) +#define CONTEXT_XSTATE_32 (CONTEXT_X86_MAIN | 0x20L) +#define CONTEXT_XSTATE_64 (CONTEXT_AMD64_MAIN | 0x20L) +#define CONTEXT64_ALL \ + (CONTEXT_CONTROL_64 | CONTEXT_INTEGER_64 | CONTEXT_SEGMENTS_64 | CONTEXT_FLOATING_POINT_64 | \ + CONTEXT_DEBUG_REGISTERS_64) typedef enum _SYSTEM_INFORMATION_CLASS { - SystemBasicInformation, // q: SYSTEM_BASIC_INFORMATION - SystemProcessorInformation, // q: SYSTEM_PROCESSOR_INFORMATION - SystemPerformanceInformation, // q: SYSTEM_PERFORMANCE_INFORMATION - SystemTimeOfDayInformation, // q: SYSTEM_TIMEOFDAY_INFORMATION - SystemPathInformation, // not implemented - SystemProcessInformation, // q: SYSTEM_PROCESS_INFORMATION - SystemCallCountInformation, // q: SYSTEM_CALL_COUNT_INFORMATION - SystemDeviceInformation, // q: SYSTEM_DEVICE_INFORMATION - SystemProcessorPerformanceInformation, // q: SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION (EX in: USHORT ProcessorGroup) - SystemFlagsInformation, // q: SYSTEM_FLAGS_INFORMATION - SystemCallTimeInformation, // not implemented // SYSTEM_CALL_TIME_INFORMATION // 10 - SystemModuleInformation, // q: RTL_PROCESS_MODULES - SystemLocksInformation, // q: RTL_PROCESS_LOCKS - SystemStackTraceInformation, // q: RTL_PROCESS_BACKTRACES - SystemPagedPoolInformation, // not implemented - SystemNonPagedPoolInformation, // not implemented - SystemHandleInformation, // q: SYSTEM_HANDLE_INFORMATION - SystemObjectInformation, // q: SYSTEM_OBJECTTYPE_INFORMATION mixed with SYSTEM_OBJECT_INFORMATION - SystemPageFileInformation, // q: SYSTEM_PAGEFILE_INFORMATION - SystemVdmInstemulInformation, // q: SYSTEM_VDM_INSTEMUL_INFO - SystemVdmBopInformation, // not implemented // 20 - SystemFileCacheInformation, - // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypeSystemCache) - SystemPoolTagInformation, // q: SYSTEM_POOLTAG_INFORMATION - SystemInterruptInformation, // q: SYSTEM_INTERRUPT_INFORMATION (EX in: USHORT ProcessorGroup) - SystemDpcBehaviorInformation, - // q: SYSTEM_DPC_BEHAVIOR_INFORMATION; s: SYSTEM_DPC_BEHAVIOR_INFORMATION (requires SeLoadDriverPrivilege) - SystemFullMemoryInformation, // not implemented // SYSTEM_MEMORY_USAGE_INFORMATION - SystemLoadGdiDriverInformation, // s (kernel-mode only) - SystemUnloadGdiDriverInformation, // s (kernel-mode only) - SystemTimeAdjustmentInformation, - // q: SYSTEM_QUERY_TIME_ADJUST_INFORMATION; s: SYSTEM_SET_TIME_ADJUST_INFORMATION (requires SeSystemtimePrivilege) - SystemSummaryMemoryInformation, // not implemented // SYSTEM_MEMORY_USAGE_INFORMATION - SystemMirrorMemoryInformation, - // s (requires license value "Kernel-MemoryMirroringSupported") (requires SeShutdownPrivilege) // 30 - SystemPerformanceTraceInformation, // q; s: (type depends on EVENT_TRACE_INFORMATION_CLASS) - SystemObsolete0, // not implemented - SystemExceptionInformation, // q: SYSTEM_EXCEPTION_INFORMATION - SystemCrashDumpStateInformation, // s: SYSTEM_CRASH_DUMP_STATE_INFORMATION (requires SeDebugPrivilege) - SystemKernelDebuggerInformation, // q: SYSTEM_KERNEL_DEBUGGER_INFORMATION - SystemContextSwitchInformation, // q: SYSTEM_CONTEXT_SWITCH_INFORMATION - SystemRegistryQuotaInformation, // q: SYSTEM_REGISTRY_QUOTA_INFORMATION; s (requires SeIncreaseQuotaPrivilege) - SystemExtendServiceTableInformation, // s (requires SeLoadDriverPrivilege) // loads win32k only - SystemPrioritySeperation, // s (requires SeTcbPrivilege) - SystemVerifierAddDriverInformation, // s (requires SeDebugPrivilege) // 40 - SystemVerifierRemoveDriverInformation, // s (requires SeDebugPrivilege) - SystemProcessorIdleInformation, // q: SYSTEM_PROCESSOR_IDLE_INFORMATION (EX in: USHORT ProcessorGroup) - SystemLegacyDriverInformation, // q: SYSTEM_LEGACY_DRIVER_INFORMATION - SystemCurrentTimeZoneInformation, // q; s: RTL_TIME_ZONE_INFORMATION - SystemLookasideInformation, // q: SYSTEM_LOOKASIDE_INFORMATION - SystemTimeSlipNotification, // s: HANDLE (NtCreateEvent) (requires SeSystemtimePrivilege) - SystemSessionCreate, // not implemented - SystemSessionDetach, // not implemented - SystemSessionInformation, // not implemented (SYSTEM_SESSION_INFORMATION) - SystemRangeStartInformation, // q: SYSTEM_RANGE_START_INFORMATION // 50 - SystemVerifierInformation, // q: SYSTEM_VERIFIER_INFORMATION; s (requires SeDebugPrivilege) - SystemVerifierThunkExtend, // s (kernel-mode only) - SystemSessionProcessInformation, // q: SYSTEM_SESSION_PROCESS_INFORMATION - SystemLoadGdiDriverInSystemSpace, - // s: SYSTEM_GDI_DRIVER_INFORMATION (kernel-mode only) (same as SystemLoadGdiDriverInformation) - SystemNumaProcessorMap, // q: SYSTEM_NUMA_INFORMATION - SystemPrefetcherInformation, // q; s: PREFETCHER_INFORMATION // PfSnQueryPrefetcherInformation - SystemExtendedProcessInformation, // q: SYSTEM_PROCESS_INFORMATION - SystemRecommendedSharedDataAlignment, // q: ULONG // KeGetRecommendedSharedDataAlignment - SystemComPlusPackage, // q; s: ULONG - SystemNumaAvailableMemory, // q: SYSTEM_NUMA_INFORMATION // 60 - SystemProcessorPowerInformation, // q: SYSTEM_PROCESSOR_POWER_INFORMATION (EX in: USHORT ProcessorGroup) - SystemEmulationBasicInformation, // q: SYSTEM_BASIC_INFORMATION - SystemEmulationProcessorInformation, // q: SYSTEM_PROCESSOR_INFORMATION - SystemExtendedHandleInformation, // q: SYSTEM_HANDLE_INFORMATION_EX - SystemLostDelayedWriteInformation, // q: ULONG - SystemBigPoolInformation, // q: SYSTEM_BIGPOOL_INFORMATION - SystemSessionPoolTagInformation, // q: SYSTEM_SESSION_POOLTAG_INFORMATION - SystemSessionMappedViewInformation, // q: SYSTEM_SESSION_MAPPED_VIEW_INFORMATION - SystemHotpatchInformation, // q; s: SYSTEM_HOTPATCH_CODE_INFORMATION - SystemObjectSecurityMode, // q: ULONG // 70 - SystemWatchdogTimerHandler, // s: SYSTEM_WATCHDOG_HANDLER_INFORMATION // (kernel-mode only) - SystemWatchdogTimerInformation, // q: SYSTEM_WATCHDOG_TIMER_INFORMATION // (kernel-mode only) - SystemLogicalProcessorInformation, // q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION (EX in: USHORT ProcessorGroup) - SystemWow64SharedInformationObsolete, // not implemented - SystemRegisterFirmwareTableInformationHandler, // s: SYSTEM_FIRMWARE_TABLE_HANDLER // (kernel-mode only) - SystemFirmwareTableInformation, // SYSTEM_FIRMWARE_TABLE_INFORMATION - SystemModuleInformationEx, // q: RTL_PROCESS_MODULE_INFORMATION_EX - SystemVerifierTriageInformation, // not implemented - SystemSuperfetchInformation, // q; s: SUPERFETCH_INFORMATION // PfQuerySuperfetchInformation - SystemMemoryListInformation, - // q: SYSTEM_MEMORY_LIST_INFORMATION; s: SYSTEM_MEMORY_LIST_COMMAND (requires SeProfileSingleProcessPrivilege) // 80 - SystemFileCacheInformationEx, - // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (same as SystemFileCacheInformation) - SystemThreadPriorityClientIdInformation, - // s: SYSTEM_THREAD_CID_PRIORITY_INFORMATION (requires SeIncreaseBasePriorityPrivilege) - SystemProcessorIdleCycleTimeInformation, - // q: SYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION[] (EX in: USHORT ProcessorGroup) - SystemVerifierCancellationInformation, - // SYSTEM_VERIFIER_CANCELLATION_INFORMATION // name:wow64:whNT32QuerySystemVerifierCancellationInformation - SystemProcessorPowerInformationEx, // not implemented - SystemRefTraceInformation, // q; s: SYSTEM_REF_TRACE_INFORMATION // ObQueryRefTraceInformation - SystemSpecialPoolInformation, - // q; s: SYSTEM_SPECIAL_POOL_INFORMATION (requires SeDebugPrivilege) // MmSpecialPoolTag, then MmSpecialPoolCatchOverruns != 0 - SystemProcessIdInformation, // q: SYSTEM_PROCESS_ID_INFORMATION - SystemErrorPortInformation, // s (requires SeTcbPrivilege) - SystemBootEnvironmentInformation, // q: SYSTEM_BOOT_ENVIRONMENT_INFORMATION // 90 - SystemHypervisorInformation, // q: SYSTEM_HYPERVISOR_QUERY_INFORMATION - SystemVerifierInformationEx, // q; s: SYSTEM_VERIFIER_INFORMATION_EX - SystemTimeZoneInformation, // q; s: RTL_TIME_ZONE_INFORMATION (requires SeTimeZonePrivilege) - SystemImageFileExecutionOptionsInformation, - // s: SYSTEM_IMAGE_FILE_EXECUTION_OPTIONS_INFORMATION (requires SeTcbPrivilege) - SystemCoverageInformation, - // q: COVERAGE_MODULES s: COVERAGE_MODULE_REQUEST // ExpCovQueryInformation (requires SeDebugPrivilege) - SystemPrefetchPatchInformation, // SYSTEM_PREFETCH_PATCH_INFORMATION - SystemVerifierFaultsInformation, // s: SYSTEM_VERIFIER_FAULTS_INFORMATION (requires SeDebugPrivilege) - SystemSystemPartitionInformation, // q: SYSTEM_SYSTEM_PARTITION_INFORMATION - SystemSystemDiskInformation, // q: SYSTEM_SYSTEM_DISK_INFORMATION - SystemProcessorPerformanceDistribution, - // q: SYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION (EX in: USHORT ProcessorGroup) // 100 - SystemNumaProximityNodeInformation, // q; s: SYSTEM_NUMA_PROXIMITY_MAP - SystemDynamicTimeZoneInformation, // q; s: RTL_DYNAMIC_TIME_ZONE_INFORMATION (requires SeTimeZonePrivilege) - SystemCodeIntegrityInformation, // q: SYSTEM_CODEINTEGRITY_INFORMATION // SeCodeIntegrityQueryInformation - SystemProcessorMicrocodeUpdateInformation, // s: SYSTEM_PROCESSOR_MICROCODE_UPDATE_INFORMATION - SystemProcessorBrandString, // q: CHAR[] // HaliQuerySystemInformation -> HalpGetProcessorBrandString, info class 23 - SystemVirtualAddressInformation, - // q: SYSTEM_VA_LIST_INFORMATION[]; s: SYSTEM_VA_LIST_INFORMATION[] (requires SeIncreaseQuotaPrivilege) // MmQuerySystemVaInformation - SystemLogicalProcessorAndGroupInformation, - // q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX (EX in: LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType) // since WIN7 // KeQueryLogicalProcessorRelationship - SystemProcessorCycleTimeInformation, // q: SYSTEM_PROCESSOR_CYCLE_TIME_INFORMATION[] (EX in: USHORT ProcessorGroup) - SystemStoreInformation, - // q; s: SYSTEM_STORE_INFORMATION (requires SeProfileSingleProcessPrivilege) // SmQueryStoreInformation - SystemRegistryAppendString, // s: SYSTEM_REGISTRY_APPEND_STRING_PARAMETERS // 110 - SystemAitSamplingValue, // s: ULONG (requires SeProfileSingleProcessPrivilege) - SystemVhdBootInformation, // q: SYSTEM_VHD_BOOT_INFORMATION - SystemCpuQuotaInformation, // q; s: PS_CPU_QUOTA_QUERY_INFORMATION - SystemNativeBasicInformation, // q: SYSTEM_BASIC_INFORMATION - SystemErrorPortTimeouts, // SYSTEM_ERROR_PORT_TIMEOUTS - SystemLowPriorityIoInformation, // q: SYSTEM_LOW_PRIORITY_IO_INFORMATION - SystemTpmBootEntropyInformation, // q: TPM_BOOT_ENTROPY_NT_RESULT // ExQueryTpmBootEntropyInformation - SystemVerifierCountersInformation, // q: SYSTEM_VERIFIER_COUNTERS_INFORMATION - SystemPagedPoolInformationEx, - // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypePagedPool) - SystemSystemPtesInformationEx, - // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypeSystemPtes) // 120 - SystemNodeDistanceInformation, // q: USHORT[4*NumaNodes] // (EX in: USHORT NodeNumber) - SystemAcpiAuditInformation, - // q: SYSTEM_ACPI_AUDIT_INFORMATION // HaliQuerySystemInformation -> HalpAuditQueryResults, info class 26 - SystemBasicPerformanceInformation, - // q: SYSTEM_BASIC_PERFORMANCE_INFORMATION // name:wow64:whNtQuerySystemInformation_SystemBasicPerformanceInformation - SystemQueryPerformanceCounterInformation, // q: SYSTEM_QUERY_PERFORMANCE_COUNTER_INFORMATION // since WIN7 SP1 - SystemSessionBigPoolInformation, // q: SYSTEM_SESSION_POOLTAG_INFORMATION // since WIN8 - SystemBootGraphicsInformation, // q; s: SYSTEM_BOOT_GRAPHICS_INFORMATION (kernel-mode only) - SystemScrubPhysicalMemoryInformation, // q; s: MEMORY_SCRUB_INFORMATION - SystemBadPageInformation, // SYSTEM_BAD_PAGE_INFORMATION - SystemProcessorProfileControlArea, // q; s: SYSTEM_PROCESSOR_PROFILE_CONTROL_AREA - SystemCombinePhysicalMemoryInformation, - // s: MEMORY_COMBINE_INFORMATION, MEMORY_COMBINE_INFORMATION_EX, MEMORY_COMBINE_INFORMATION_EX2 // 130 - SystemEntropyInterruptTimingInformation, // q; s: SYSTEM_ENTROPY_TIMING_INFORMATION - SystemConsoleInformation, // q; s: SYSTEM_CONSOLE_INFORMATION - SystemPlatformBinaryInformation, // q: SYSTEM_PLATFORM_BINARY_INFORMATION (requires SeTcbPrivilege) - SystemPolicyInformation, // q: SYSTEM_POLICY_INFORMATION (Warbird/Encrypt/Decrypt/Execute) - SystemHypervisorProcessorCountInformation, // q: SYSTEM_HYPERVISOR_PROCESSOR_COUNT_INFORMATION - SystemDeviceDataInformation, // q: SYSTEM_DEVICE_DATA_INFORMATION - SystemDeviceDataEnumerationInformation, // q: SYSTEM_DEVICE_DATA_INFORMATION - SystemMemoryTopologyInformation, // q: SYSTEM_MEMORY_TOPOLOGY_INFORMATION - SystemMemoryChannelInformation, // q: SYSTEM_MEMORY_CHANNEL_INFORMATION - SystemBootLogoInformation, // q: SYSTEM_BOOT_LOGO_INFORMATION // 140 - SystemProcessorPerformanceInformationEx, - // q: SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_EX // (EX in: USHORT ProcessorGroup) // since WINBLUE - SystemCriticalProcessErrorLogInformation, - SystemSecureBootPolicyInformation, // q: SYSTEM_SECUREBOOT_POLICY_INFORMATION - SystemPageFileInformationEx, // q: SYSTEM_PAGEFILE_INFORMATION_EX - SystemSecureBootInformation, // q: SYSTEM_SECUREBOOT_INFORMATION - SystemEntropyInterruptTimingRawInformation, - SystemPortableWorkspaceEfiLauncherInformation, // q: SYSTEM_PORTABLE_WORKSPACE_EFI_LAUNCHER_INFORMATION - SystemFullProcessInformation, - // q: SYSTEM_PROCESS_INFORMATION with SYSTEM_PROCESS_INFORMATION_EXTENSION (requires admin) - SystemKernelDebuggerInformationEx, // q: SYSTEM_KERNEL_DEBUGGER_INFORMATION_EX - SystemBootMetadataInformation, // 150 - SystemSoftRebootInformation, // q: ULONG - SystemElamCertificateInformation, // s: SYSTEM_ELAM_CERTIFICATE_INFORMATION - SystemOfflineDumpConfigInformation, // q: OFFLINE_CRASHDUMP_CONFIGURATION_TABLE_V2 - SystemProcessorFeaturesInformation, // q: SYSTEM_PROCESSOR_FEATURES_INFORMATION - SystemRegistryReconciliationInformation, // s: NULL (requires admin) (flushes registry hives) - SystemEdidInformation, // q: SYSTEM_EDID_INFORMATION - SystemManufacturingInformation, // q: SYSTEM_MANUFACTURING_INFORMATION // since THRESHOLD - SystemEnergyEstimationConfigInformation, // q: SYSTEM_ENERGY_ESTIMATION_CONFIG_INFORMATION - SystemHypervisorDetailInformation, // q: SYSTEM_HYPERVISOR_DETAIL_INFORMATION - SystemProcessorCycleStatsInformation, - // q: SYSTEM_PROCESSOR_CYCLE_STATS_INFORMATION (EX in: USHORT ProcessorGroup) // 160 - SystemVmGenerationCountInformation, - SystemTrustedPlatformModuleInformation, // q: SYSTEM_TPM_INFORMATION - SystemKernelDebuggerFlags, // SYSTEM_KERNEL_DEBUGGER_FLAGS - SystemCodeIntegrityPolicyInformation, // q; s: SYSTEM_CODEINTEGRITYPOLICY_INFORMATION - SystemIsolatedUserModeInformation, // q: SYSTEM_ISOLATED_USER_MODE_INFORMATION - SystemHardwareSecurityTestInterfaceResultsInformation, - SystemSingleModuleInformation, // q: SYSTEM_SINGLE_MODULE_INFORMATION - SystemAllowedCpuSetsInformation, // s: SYSTEM_WORKLOAD_ALLOWED_CPU_SET_INFORMATION - SystemVsmProtectionInformation, // q: SYSTEM_VSM_PROTECTION_INFORMATION (previously SystemDmaProtectionInformation) - SystemInterruptCpuSetsInformation, // q: SYSTEM_INTERRUPT_CPU_SET_INFORMATION // 170 - SystemSecureBootPolicyFullInformation, // q: SYSTEM_SECUREBOOT_POLICY_FULL_INFORMATION - SystemCodeIntegrityPolicyFullInformation, - SystemAffinitizedInterruptProcessorInformation, // (requires SeIncreaseBasePriorityPrivilege) - SystemRootSiloInformation, // q: SYSTEM_ROOT_SILO_INFORMATION - SystemCpuSetInformation, // q: SYSTEM_CPU_SET_INFORMATION // since THRESHOLD2 - SystemCpuSetTagInformation, // q: SYSTEM_CPU_SET_TAG_INFORMATION - SystemWin32WerStartCallout, - SystemSecureKernelProfileInformation, // q: SYSTEM_SECURE_KERNEL_HYPERGUARD_PROFILE_INFORMATION - SystemCodeIntegrityPlatformManifestInformation, - // q: SYSTEM_SECUREBOOT_PLATFORM_MANIFEST_INFORMATION // since REDSTONE - SystemInterruptSteeringInformation, - // q: in: SYSTEM_INTERRUPT_STEERING_INFORMATION_INPUT, out: SYSTEM_INTERRUPT_STEERING_INFORMATION_OUTPUT // NtQuerySystemInformationEx // 180 - SystemSupportedProcessorArchitectures, - // p: in opt: HANDLE, out: SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION[] // NtQuerySystemInformationEx - SystemMemoryUsageInformation, // q: SYSTEM_MEMORY_USAGE_INFORMATION - SystemCodeIntegrityCertificateInformation, // q: SYSTEM_CODEINTEGRITY_CERTIFICATE_INFORMATION - SystemPhysicalMemoryInformation, // q: SYSTEM_PHYSICAL_MEMORY_INFORMATION // since REDSTONE2 - SystemControlFlowTransition, // (Warbird/Encrypt/Decrypt/Execute) - SystemKernelDebuggingAllowed, // s: ULONG - SystemActivityModerationExeState, // SYSTEM_ACTIVITY_MODERATION_EXE_STATE - SystemActivityModerationUserSettings, // SYSTEM_ACTIVITY_MODERATION_USER_SETTINGS - SystemCodeIntegrityPoliciesFullInformation, - SystemCodeIntegrityUnlockInformation, // SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION // 190 - SystemIntegrityQuotaInformation, - SystemFlushInformation, // q: SYSTEM_FLUSH_INFORMATION - SystemProcessorIdleMaskInformation, // q: ULONG_PTR[ActiveGroupCount] // since REDSTONE3 - SystemSecureDumpEncryptionInformation, - SystemWriteConstraintInformation, // SYSTEM_WRITE_CONSTRAINT_INFORMATION - SystemKernelVaShadowInformation, // SYSTEM_KERNEL_VA_SHADOW_INFORMATION - SystemHypervisorSharedPageInformation, // SYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION // since REDSTONE4 - SystemFirmwareBootPerformanceInformation, - SystemCodeIntegrityVerificationInformation, // SYSTEM_CODEINTEGRITYVERIFICATION_INFORMATION - SystemFirmwarePartitionInformation, // SYSTEM_FIRMWARE_PARTITION_INFORMATION // 200 - SystemSpeculationControlInformation, - // SYSTEM_SPECULATION_CONTROL_INFORMATION // (CVE-2017-5715) REDSTONE3 and above. - SystemDmaGuardPolicyInformation, // SYSTEM_DMA_GUARD_POLICY_INFORMATION - SystemEnclaveLaunchControlInformation, // SYSTEM_ENCLAVE_LAUNCH_CONTROL_INFORMATION - SystemWorkloadAllowedCpuSetsInformation, // SYSTEM_WORKLOAD_ALLOWED_CPU_SET_INFORMATION // since REDSTONE5 - SystemCodeIntegrityUnlockModeInformation, // SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION - SystemLeapSecondInformation, // SYSTEM_LEAP_SECOND_INFORMATION - SystemFlags2Information, // q: SYSTEM_FLAGS_INFORMATION - SystemSecurityModelInformation, // SYSTEM_SECURITY_MODEL_INFORMATION // since 19H1 - SystemCodeIntegritySyntheticCacheInformation, - SystemFeatureConfigurationInformation, - // q: in: SYSTEM_FEATURE_CONFIGURATION_QUERY, out: SYSTEM_FEATURE_CONFIGURATION_INFORMATION; s: SYSTEM_FEATURE_CONFIGURATION_UPDATE // NtQuerySystemInformationEx // since 20H1 // 210 - SystemFeatureConfigurationSectionInformation, - // q: in: SYSTEM_FEATURE_CONFIGURATION_SECTIONS_REQUEST, out: SYSTEM_FEATURE_CONFIGURATION_SECTIONS_INFORMATION // NtQuerySystemInformationEx - SystemFeatureUsageSubscriptionInformation, - // q: SYSTEM_FEATURE_USAGE_SUBSCRIPTION_DETAILS; s: SYSTEM_FEATURE_USAGE_SUBSCRIPTION_UPDATE - SystemSecureSpeculationControlInformation, // SECURE_SPECULATION_CONTROL_INFORMATION - SystemSpacesBootInformation, // since 20H2 - SystemFwRamdiskInformation, // SYSTEM_FIRMWARE_RAMDISK_INFORMATION - SystemWheaIpmiHardwareInformation, - SystemDifSetRuleClassInformation, // SYSTEM_DIF_VOLATILE_INFORMATION - SystemDifClearRuleClassInformation, - SystemDifApplyPluginVerificationOnDriver, // SYSTEM_DIF_PLUGIN_DRIVER_INFORMATION - SystemDifRemovePluginVerificationOnDriver, // SYSTEM_DIF_PLUGIN_DRIVER_INFORMATION // 220 - SystemShadowStackInformation, // SYSTEM_SHADOW_STACK_INFORMATION - SystemBuildVersionInformation, - // q: in: ULONG (LayerNumber), out: SYSTEM_BUILD_VERSION_INFORMATION // NtQuerySystemInformationEx // 222 - SystemPoolLimitInformation, // SYSTEM_POOL_LIMIT_INFORMATION (requires SeIncreaseQuotaPrivilege) - SystemCodeIntegrityAddDynamicStore, - SystemCodeIntegrityClearDynamicStores, - SystemDifPoolTrackingInformation, - SystemPoolZeroingInformation, // q: SYSTEM_POOL_ZEROING_INFORMATION - SystemDpcWatchdogInformation, // q; s: SYSTEM_DPC_WATCHDOG_CONFIGURATION_INFORMATION - SystemDpcWatchdogInformation2, // q; s: SYSTEM_DPC_WATCHDOG_CONFIGURATION_INFORMATION_V2 - SystemSupportedProcessorArchitectures2, - // q: in opt: HANDLE, out: SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION[] // NtQuerySystemInformationEx // 230 - SystemSingleProcessorRelationshipInformation, - // q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX // (EX in: PROCESSOR_NUMBER Processor) - SystemXfgCheckFailureInformation, // q: SYSTEM_XFG_FAILURE_INFORMATION - SystemIommuStateInformation, // SYSTEM_IOMMU_STATE_INFORMATION // since 22H1 - SystemHypervisorMinrootInformation, // SYSTEM_HYPERVISOR_MINROOT_INFORMATION - SystemHypervisorBootPagesInformation, // SYSTEM_HYPERVISOR_BOOT_PAGES_INFORMATION - SystemPointerAuthInformation, // SYSTEM_POINTER_AUTH_INFORMATION - SystemSecureKernelDebuggerInformation, - SystemOriginalImageFeatureInformation, - // q: in: SYSTEM_ORIGINAL_IMAGE_FEATURE_INFORMATION_INPUT, out: SYSTEM_ORIGINAL_IMAGE_FEATURE_INFORMATION_OUTPUT // NtQuerySystemInformationEx - SystemMemoryNumaInformation, // SYSTEM_MEMORY_NUMA_INFORMATION_INPUT, SYSTEM_MEMORY_NUMA_INFORMATION_OUTPUT - SystemMemoryNumaPerformanceInformation, - // SYSTEM_MEMORY_NUMA_PERFORMANCE_INFORMATION_INPUTSYSTEM_MEMORY_NUMA_PERFORMANCE_INFORMATION_INPUT, SYSTEM_MEMORY_NUMA_PERFORMANCE_INFORMATION_OUTPUT // since 24H2 // 240 - SystemCodeIntegritySignedPoliciesFullInformation, - SystemSecureSecretsInformation, - SystemTrustedAppsRuntimeInformation, // SYSTEM_TRUSTEDAPPS_RUNTIME_INFORMATION - SystemBadPageInformationEx, // SYSTEM_BAD_PAGE_INFORMATION - SystemResourceDeadlockTimeout, // ULONG - SystemBreakOnContextUnwindFailureInformation, // ULONG (requires SeDebugPrivilege) - SystemOslRamdiskInformation, // SYSTEM_OSL_RAMDISK_INFORMATION - MaxSystemInfoClass + SystemBasicInformation, // q: SYSTEM_BASIC_INFORMATION + SystemProcessorInformation, // q: SYSTEM_PROCESSOR_INFORMATION + SystemPerformanceInformation, // q: SYSTEM_PERFORMANCE_INFORMATION + SystemTimeOfDayInformation, // q: SYSTEM_TIMEOFDAY_INFORMATION + SystemPathInformation, // not implemented + SystemProcessInformation, // q: SYSTEM_PROCESS_INFORMATION + SystemCallCountInformation, // q: SYSTEM_CALL_COUNT_INFORMATION + SystemDeviceInformation, // q: SYSTEM_DEVICE_INFORMATION + SystemProcessorPerformanceInformation, // q: SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION (EX in: USHORT ProcessorGroup) + SystemFlagsInformation, // q: SYSTEM_FLAGS_INFORMATION + SystemCallTimeInformation, // not implemented // SYSTEM_CALL_TIME_INFORMATION // 10 + SystemModuleInformation, // q: RTL_PROCESS_MODULES + SystemLocksInformation, // q: RTL_PROCESS_LOCKS + SystemStackTraceInformation, // q: RTL_PROCESS_BACKTRACES + SystemPagedPoolInformation, // not implemented + SystemNonPagedPoolInformation, // not implemented + SystemHandleInformation, // q: SYSTEM_HANDLE_INFORMATION + SystemObjectInformation, // q: SYSTEM_OBJECTTYPE_INFORMATION mixed with SYSTEM_OBJECT_INFORMATION + SystemPageFileInformation, // q: SYSTEM_PAGEFILE_INFORMATION + SystemVdmInstemulInformation, // q: SYSTEM_VDM_INSTEMUL_INFO + SystemVdmBopInformation, // not implemented // 20 + SystemFileCacheInformation, + // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypeSystemCache) + SystemPoolTagInformation, // q: SYSTEM_POOLTAG_INFORMATION + SystemInterruptInformation, // q: SYSTEM_INTERRUPT_INFORMATION (EX in: USHORT ProcessorGroup) + SystemDpcBehaviorInformation, + // q: SYSTEM_DPC_BEHAVIOR_INFORMATION; s: SYSTEM_DPC_BEHAVIOR_INFORMATION (requires SeLoadDriverPrivilege) + SystemFullMemoryInformation, // not implemented // SYSTEM_MEMORY_USAGE_INFORMATION + SystemLoadGdiDriverInformation, // s (kernel-mode only) + SystemUnloadGdiDriverInformation, // s (kernel-mode only) + SystemTimeAdjustmentInformation, + // q: SYSTEM_QUERY_TIME_ADJUST_INFORMATION; s: SYSTEM_SET_TIME_ADJUST_INFORMATION (requires SeSystemtimePrivilege) + SystemSummaryMemoryInformation, // not implemented // SYSTEM_MEMORY_USAGE_INFORMATION + SystemMirrorMemoryInformation, + // s (requires license value "Kernel-MemoryMirroringSupported") (requires SeShutdownPrivilege) // 30 + SystemPerformanceTraceInformation, // q; s: (type depends on EVENT_TRACE_INFORMATION_CLASS) + SystemObsolete0, // not implemented + SystemExceptionInformation, // q: SYSTEM_EXCEPTION_INFORMATION + SystemCrashDumpStateInformation, // s: SYSTEM_CRASH_DUMP_STATE_INFORMATION (requires SeDebugPrivilege) + SystemKernelDebuggerInformation, // q: SYSTEM_KERNEL_DEBUGGER_INFORMATION + SystemContextSwitchInformation, // q: SYSTEM_CONTEXT_SWITCH_INFORMATION + SystemRegistryQuotaInformation, // q: SYSTEM_REGISTRY_QUOTA_INFORMATION; s (requires SeIncreaseQuotaPrivilege) + SystemExtendServiceTableInformation, // s (requires SeLoadDriverPrivilege) // loads win32k only + SystemPrioritySeperation, // s (requires SeTcbPrivilege) + SystemVerifierAddDriverInformation, // s (requires SeDebugPrivilege) // 40 + SystemVerifierRemoveDriverInformation, // s (requires SeDebugPrivilege) + SystemProcessorIdleInformation, // q: SYSTEM_PROCESSOR_IDLE_INFORMATION (EX in: USHORT ProcessorGroup) + SystemLegacyDriverInformation, // q: SYSTEM_LEGACY_DRIVER_INFORMATION + SystemCurrentTimeZoneInformation, // q; s: RTL_TIME_ZONE_INFORMATION + SystemLookasideInformation, // q: SYSTEM_LOOKASIDE_INFORMATION + SystemTimeSlipNotification, // s: HANDLE (NtCreateEvent) (requires SeSystemtimePrivilege) + SystemSessionCreate, // not implemented + SystemSessionDetach, // not implemented + SystemSessionInformation, // not implemented (SYSTEM_SESSION_INFORMATION) + SystemRangeStartInformation, // q: SYSTEM_RANGE_START_INFORMATION // 50 + SystemVerifierInformation, // q: SYSTEM_VERIFIER_INFORMATION; s (requires SeDebugPrivilege) + SystemVerifierThunkExtend, // s (kernel-mode only) + SystemSessionProcessInformation, // q: SYSTEM_SESSION_PROCESS_INFORMATION + SystemLoadGdiDriverInSystemSpace, + // s: SYSTEM_GDI_DRIVER_INFORMATION (kernel-mode only) (same as SystemLoadGdiDriverInformation) + SystemNumaProcessorMap, // q: SYSTEM_NUMA_INFORMATION + SystemPrefetcherInformation, // q; s: PREFETCHER_INFORMATION // PfSnQueryPrefetcherInformation + SystemExtendedProcessInformation, // q: SYSTEM_PROCESS_INFORMATION + SystemRecommendedSharedDataAlignment, // q: ULONG // KeGetRecommendedSharedDataAlignment + SystemComPlusPackage, // q; s: ULONG + SystemNumaAvailableMemory, // q: SYSTEM_NUMA_INFORMATION // 60 + SystemProcessorPowerInformation, // q: SYSTEM_PROCESSOR_POWER_INFORMATION (EX in: USHORT ProcessorGroup) + SystemEmulationBasicInformation, // q: SYSTEM_BASIC_INFORMATION + SystemEmulationProcessorInformation, // q: SYSTEM_PROCESSOR_INFORMATION + SystemExtendedHandleInformation, // q: SYSTEM_HANDLE_INFORMATION_EX + SystemLostDelayedWriteInformation, // q: ULONG + SystemBigPoolInformation, // q: SYSTEM_BIGPOOL_INFORMATION + SystemSessionPoolTagInformation, // q: SYSTEM_SESSION_POOLTAG_INFORMATION + SystemSessionMappedViewInformation, // q: SYSTEM_SESSION_MAPPED_VIEW_INFORMATION + SystemHotpatchInformation, // q; s: SYSTEM_HOTPATCH_CODE_INFORMATION + SystemObjectSecurityMode, // q: ULONG // 70 + SystemWatchdogTimerHandler, // s: SYSTEM_WATCHDOG_HANDLER_INFORMATION // (kernel-mode only) + SystemWatchdogTimerInformation, // q: SYSTEM_WATCHDOG_TIMER_INFORMATION // (kernel-mode only) + SystemLogicalProcessorInformation, // q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION (EX in: USHORT ProcessorGroup) + SystemWow64SharedInformationObsolete, // not implemented + SystemRegisterFirmwareTableInformationHandler, // s: SYSTEM_FIRMWARE_TABLE_HANDLER // (kernel-mode only) + SystemFirmwareTableInformation, // SYSTEM_FIRMWARE_TABLE_INFORMATION + SystemModuleInformationEx, // q: RTL_PROCESS_MODULE_INFORMATION_EX + SystemVerifierTriageInformation, // not implemented + SystemSuperfetchInformation, // q; s: SUPERFETCH_INFORMATION // PfQuerySuperfetchInformation + SystemMemoryListInformation, + // q: SYSTEM_MEMORY_LIST_INFORMATION; s: SYSTEM_MEMORY_LIST_COMMAND (requires SeProfileSingleProcessPrivilege) // 80 + SystemFileCacheInformationEx, + // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (same as SystemFileCacheInformation) + SystemThreadPriorityClientIdInformation, + // s: SYSTEM_THREAD_CID_PRIORITY_INFORMATION (requires SeIncreaseBasePriorityPrivilege) + SystemProcessorIdleCycleTimeInformation, + // q: SYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION[] (EX in: USHORT ProcessorGroup) + SystemVerifierCancellationInformation, + // SYSTEM_VERIFIER_CANCELLATION_INFORMATION // name:wow64:whNT32QuerySystemVerifierCancellationInformation + SystemProcessorPowerInformationEx, // not implemented + SystemRefTraceInformation, // q; s: SYSTEM_REF_TRACE_INFORMATION // ObQueryRefTraceInformation + SystemSpecialPoolInformation, + // q; s: SYSTEM_SPECIAL_POOL_INFORMATION (requires SeDebugPrivilege) // MmSpecialPoolTag, then + // MmSpecialPoolCatchOverruns != 0 + SystemProcessIdInformation, // q: SYSTEM_PROCESS_ID_INFORMATION + SystemErrorPortInformation, // s (requires SeTcbPrivilege) + SystemBootEnvironmentInformation, // q: SYSTEM_BOOT_ENVIRONMENT_INFORMATION // 90 + SystemHypervisorInformation, // q: SYSTEM_HYPERVISOR_QUERY_INFORMATION + SystemVerifierInformationEx, // q; s: SYSTEM_VERIFIER_INFORMATION_EX + SystemTimeZoneInformation, // q; s: RTL_TIME_ZONE_INFORMATION (requires SeTimeZonePrivilege) + SystemImageFileExecutionOptionsInformation, + // s: SYSTEM_IMAGE_FILE_EXECUTION_OPTIONS_INFORMATION (requires SeTcbPrivilege) + SystemCoverageInformation, + // q: COVERAGE_MODULES s: COVERAGE_MODULE_REQUEST // ExpCovQueryInformation (requires SeDebugPrivilege) + SystemPrefetchPatchInformation, // SYSTEM_PREFETCH_PATCH_INFORMATION + SystemVerifierFaultsInformation, // s: SYSTEM_VERIFIER_FAULTS_INFORMATION (requires SeDebugPrivilege) + SystemSystemPartitionInformation, // q: SYSTEM_SYSTEM_PARTITION_INFORMATION + SystemSystemDiskInformation, // q: SYSTEM_SYSTEM_DISK_INFORMATION + SystemProcessorPerformanceDistribution, + // q: SYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION (EX in: USHORT ProcessorGroup) // 100 + SystemNumaProximityNodeInformation, // q; s: SYSTEM_NUMA_PROXIMITY_MAP + SystemDynamicTimeZoneInformation, // q; s: RTL_DYNAMIC_TIME_ZONE_INFORMATION (requires SeTimeZonePrivilege) + SystemCodeIntegrityInformation, // q: SYSTEM_CODEINTEGRITY_INFORMATION // SeCodeIntegrityQueryInformation + SystemProcessorMicrocodeUpdateInformation, // s: SYSTEM_PROCESSOR_MICROCODE_UPDATE_INFORMATION + SystemProcessorBrandString, // q: CHAR[] // HaliQuerySystemInformation -> HalpGetProcessorBrandString, info class 23 + SystemVirtualAddressInformation, + // q: SYSTEM_VA_LIST_INFORMATION[]; s: SYSTEM_VA_LIST_INFORMATION[] (requires SeIncreaseQuotaPrivilege) // + // MmQuerySystemVaInformation + SystemLogicalProcessorAndGroupInformation, + // q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX (EX in: LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType) // since WIN7 + // // KeQueryLogicalProcessorRelationship + SystemProcessorCycleTimeInformation, // q: SYSTEM_PROCESSOR_CYCLE_TIME_INFORMATION[] (EX in: USHORT ProcessorGroup) + SystemStoreInformation, + // q; s: SYSTEM_STORE_INFORMATION (requires SeProfileSingleProcessPrivilege) // SmQueryStoreInformation + SystemRegistryAppendString, // s: SYSTEM_REGISTRY_APPEND_STRING_PARAMETERS // 110 + SystemAitSamplingValue, // s: ULONG (requires SeProfileSingleProcessPrivilege) + SystemVhdBootInformation, // q: SYSTEM_VHD_BOOT_INFORMATION + SystemCpuQuotaInformation, // q; s: PS_CPU_QUOTA_QUERY_INFORMATION + SystemNativeBasicInformation, // q: SYSTEM_BASIC_INFORMATION + SystemErrorPortTimeouts, // SYSTEM_ERROR_PORT_TIMEOUTS + SystemLowPriorityIoInformation, // q: SYSTEM_LOW_PRIORITY_IO_INFORMATION + SystemTpmBootEntropyInformation, // q: TPM_BOOT_ENTROPY_NT_RESULT // ExQueryTpmBootEntropyInformation + SystemVerifierCountersInformation, // q: SYSTEM_VERIFIER_COUNTERS_INFORMATION + SystemPagedPoolInformationEx, + // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypePagedPool) + SystemSystemPtesInformationEx, + // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypeSystemPtes) // 120 + SystemNodeDistanceInformation, // q: USHORT[4*NumaNodes] // (EX in: USHORT NodeNumber) + SystemAcpiAuditInformation, + // q: SYSTEM_ACPI_AUDIT_INFORMATION // HaliQuerySystemInformation -> HalpAuditQueryResults, info class 26 + SystemBasicPerformanceInformation, + // q: SYSTEM_BASIC_PERFORMANCE_INFORMATION // + // name:wow64:whNtQuerySystemInformation_SystemBasicPerformanceInformation + SystemQueryPerformanceCounterInformation, // q: SYSTEM_QUERY_PERFORMANCE_COUNTER_INFORMATION // since WIN7 SP1 + SystemSessionBigPoolInformation, // q: SYSTEM_SESSION_POOLTAG_INFORMATION // since WIN8 + SystemBootGraphicsInformation, // q; s: SYSTEM_BOOT_GRAPHICS_INFORMATION (kernel-mode only) + SystemScrubPhysicalMemoryInformation, // q; s: MEMORY_SCRUB_INFORMATION + SystemBadPageInformation, // SYSTEM_BAD_PAGE_INFORMATION + SystemProcessorProfileControlArea, // q; s: SYSTEM_PROCESSOR_PROFILE_CONTROL_AREA + SystemCombinePhysicalMemoryInformation, + // s: MEMORY_COMBINE_INFORMATION, MEMORY_COMBINE_INFORMATION_EX, MEMORY_COMBINE_INFORMATION_EX2 // 130 + SystemEntropyInterruptTimingInformation, // q; s: SYSTEM_ENTROPY_TIMING_INFORMATION + SystemConsoleInformation, // q; s: SYSTEM_CONSOLE_INFORMATION + SystemPlatformBinaryInformation, // q: SYSTEM_PLATFORM_BINARY_INFORMATION (requires SeTcbPrivilege) + SystemPolicyInformation, // q: SYSTEM_POLICY_INFORMATION (Warbird/Encrypt/Decrypt/Execute) + SystemHypervisorProcessorCountInformation, // q: SYSTEM_HYPERVISOR_PROCESSOR_COUNT_INFORMATION + SystemDeviceDataInformation, // q: SYSTEM_DEVICE_DATA_INFORMATION + SystemDeviceDataEnumerationInformation, // q: SYSTEM_DEVICE_DATA_INFORMATION + SystemMemoryTopologyInformation, // q: SYSTEM_MEMORY_TOPOLOGY_INFORMATION + SystemMemoryChannelInformation, // q: SYSTEM_MEMORY_CHANNEL_INFORMATION + SystemBootLogoInformation, // q: SYSTEM_BOOT_LOGO_INFORMATION // 140 + SystemProcessorPerformanceInformationEx, + // q: SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_EX // (EX in: USHORT ProcessorGroup) // since WINBLUE + SystemCriticalProcessErrorLogInformation, + SystemSecureBootPolicyInformation, // q: SYSTEM_SECUREBOOT_POLICY_INFORMATION + SystemPageFileInformationEx, // q: SYSTEM_PAGEFILE_INFORMATION_EX + SystemSecureBootInformation, // q: SYSTEM_SECUREBOOT_INFORMATION + SystemEntropyInterruptTimingRawInformation, + SystemPortableWorkspaceEfiLauncherInformation, // q: SYSTEM_PORTABLE_WORKSPACE_EFI_LAUNCHER_INFORMATION + SystemFullProcessInformation, + // q: SYSTEM_PROCESS_INFORMATION with SYSTEM_PROCESS_INFORMATION_EXTENSION (requires admin) + SystemKernelDebuggerInformationEx, // q: SYSTEM_KERNEL_DEBUGGER_INFORMATION_EX + SystemBootMetadataInformation, // 150 + SystemSoftRebootInformation, // q: ULONG + SystemElamCertificateInformation, // s: SYSTEM_ELAM_CERTIFICATE_INFORMATION + SystemOfflineDumpConfigInformation, // q: OFFLINE_CRASHDUMP_CONFIGURATION_TABLE_V2 + SystemProcessorFeaturesInformation, // q: SYSTEM_PROCESSOR_FEATURES_INFORMATION + SystemRegistryReconciliationInformation, // s: NULL (requires admin) (flushes registry hives) + SystemEdidInformation, // q: SYSTEM_EDID_INFORMATION + SystemManufacturingInformation, // q: SYSTEM_MANUFACTURING_INFORMATION // since THRESHOLD + SystemEnergyEstimationConfigInformation, // q: SYSTEM_ENERGY_ESTIMATION_CONFIG_INFORMATION + SystemHypervisorDetailInformation, // q: SYSTEM_HYPERVISOR_DETAIL_INFORMATION + SystemProcessorCycleStatsInformation, + // q: SYSTEM_PROCESSOR_CYCLE_STATS_INFORMATION (EX in: USHORT ProcessorGroup) // 160 + SystemVmGenerationCountInformation, + SystemTrustedPlatformModuleInformation, // q: SYSTEM_TPM_INFORMATION + SystemKernelDebuggerFlags, // SYSTEM_KERNEL_DEBUGGER_FLAGS + SystemCodeIntegrityPolicyInformation, // q; s: SYSTEM_CODEINTEGRITYPOLICY_INFORMATION + SystemIsolatedUserModeInformation, // q: SYSTEM_ISOLATED_USER_MODE_INFORMATION + SystemHardwareSecurityTestInterfaceResultsInformation, + SystemSingleModuleInformation, // q: SYSTEM_SINGLE_MODULE_INFORMATION + SystemAllowedCpuSetsInformation, // s: SYSTEM_WORKLOAD_ALLOWED_CPU_SET_INFORMATION + SystemVsmProtectionInformation, // q: SYSTEM_VSM_PROTECTION_INFORMATION (previously SystemDmaProtectionInformation) + SystemInterruptCpuSetsInformation, // q: SYSTEM_INTERRUPT_CPU_SET_INFORMATION // 170 + SystemSecureBootPolicyFullInformation, // q: SYSTEM_SECUREBOOT_POLICY_FULL_INFORMATION + SystemCodeIntegrityPolicyFullInformation, + SystemAffinitizedInterruptProcessorInformation, // (requires SeIncreaseBasePriorityPrivilege) + SystemRootSiloInformation, // q: SYSTEM_ROOT_SILO_INFORMATION + SystemCpuSetInformation, // q: SYSTEM_CPU_SET_INFORMATION // since THRESHOLD2 + SystemCpuSetTagInformation, // q: SYSTEM_CPU_SET_TAG_INFORMATION + SystemWin32WerStartCallout, + SystemSecureKernelProfileInformation, // q: SYSTEM_SECURE_KERNEL_HYPERGUARD_PROFILE_INFORMATION + SystemCodeIntegrityPlatformManifestInformation, + // q: SYSTEM_SECUREBOOT_PLATFORM_MANIFEST_INFORMATION // since REDSTONE + SystemInterruptSteeringInformation, + // q: in: SYSTEM_INTERRUPT_STEERING_INFORMATION_INPUT, out: SYSTEM_INTERRUPT_STEERING_INFORMATION_OUTPUT // + // NtQuerySystemInformationEx // 180 + SystemSupportedProcessorArchitectures, + // p: in opt: HANDLE, out: SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION[] // NtQuerySystemInformationEx + SystemMemoryUsageInformation, // q: SYSTEM_MEMORY_USAGE_INFORMATION + SystemCodeIntegrityCertificateInformation, // q: SYSTEM_CODEINTEGRITY_CERTIFICATE_INFORMATION + SystemPhysicalMemoryInformation, // q: SYSTEM_PHYSICAL_MEMORY_INFORMATION // since REDSTONE2 + SystemControlFlowTransition, // (Warbird/Encrypt/Decrypt/Execute) + SystemKernelDebuggingAllowed, // s: ULONG + SystemActivityModerationExeState, // SYSTEM_ACTIVITY_MODERATION_EXE_STATE + SystemActivityModerationUserSettings, // SYSTEM_ACTIVITY_MODERATION_USER_SETTINGS + SystemCodeIntegrityPoliciesFullInformation, + SystemCodeIntegrityUnlockInformation, // SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION // 190 + SystemIntegrityQuotaInformation, + SystemFlushInformation, // q: SYSTEM_FLUSH_INFORMATION + SystemProcessorIdleMaskInformation, // q: ULONG_PTR[ActiveGroupCount] // since REDSTONE3 + SystemSecureDumpEncryptionInformation, + SystemWriteConstraintInformation, // SYSTEM_WRITE_CONSTRAINT_INFORMATION + SystemKernelVaShadowInformation, // SYSTEM_KERNEL_VA_SHADOW_INFORMATION + SystemHypervisorSharedPageInformation, // SYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION // since REDSTONE4 + SystemFirmwareBootPerformanceInformation, + SystemCodeIntegrityVerificationInformation, // SYSTEM_CODEINTEGRITYVERIFICATION_INFORMATION + SystemFirmwarePartitionInformation, // SYSTEM_FIRMWARE_PARTITION_INFORMATION // 200 + SystemSpeculationControlInformation, + // SYSTEM_SPECULATION_CONTROL_INFORMATION // (CVE-2017-5715) REDSTONE3 and above. + SystemDmaGuardPolicyInformation, // SYSTEM_DMA_GUARD_POLICY_INFORMATION + SystemEnclaveLaunchControlInformation, // SYSTEM_ENCLAVE_LAUNCH_CONTROL_INFORMATION + SystemWorkloadAllowedCpuSetsInformation, // SYSTEM_WORKLOAD_ALLOWED_CPU_SET_INFORMATION // since REDSTONE5 + SystemCodeIntegrityUnlockModeInformation, // SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION + SystemLeapSecondInformation, // SYSTEM_LEAP_SECOND_INFORMATION + SystemFlags2Information, // q: SYSTEM_FLAGS_INFORMATION + SystemSecurityModelInformation, // SYSTEM_SECURITY_MODEL_INFORMATION // since 19H1 + SystemCodeIntegritySyntheticCacheInformation, + SystemFeatureConfigurationInformation, + // q: in: SYSTEM_FEATURE_CONFIGURATION_QUERY, out: SYSTEM_FEATURE_CONFIGURATION_INFORMATION; s: + // SYSTEM_FEATURE_CONFIGURATION_UPDATE // NtQuerySystemInformationEx // since 20H1 // 210 + SystemFeatureConfigurationSectionInformation, + // q: in: SYSTEM_FEATURE_CONFIGURATION_SECTIONS_REQUEST, out: SYSTEM_FEATURE_CONFIGURATION_SECTIONS_INFORMATION // + // NtQuerySystemInformationEx + SystemFeatureUsageSubscriptionInformation, + // q: SYSTEM_FEATURE_USAGE_SUBSCRIPTION_DETAILS; s: SYSTEM_FEATURE_USAGE_SUBSCRIPTION_UPDATE + SystemSecureSpeculationControlInformation, // SECURE_SPECULATION_CONTROL_INFORMATION + SystemSpacesBootInformation, // since 20H2 + SystemFwRamdiskInformation, // SYSTEM_FIRMWARE_RAMDISK_INFORMATION + SystemWheaIpmiHardwareInformation, + SystemDifSetRuleClassInformation, // SYSTEM_DIF_VOLATILE_INFORMATION + SystemDifClearRuleClassInformation, + SystemDifApplyPluginVerificationOnDriver, // SYSTEM_DIF_PLUGIN_DRIVER_INFORMATION + SystemDifRemovePluginVerificationOnDriver, // SYSTEM_DIF_PLUGIN_DRIVER_INFORMATION // 220 + SystemShadowStackInformation, // SYSTEM_SHADOW_STACK_INFORMATION + SystemBuildVersionInformation, + // q: in: ULONG (LayerNumber), out: SYSTEM_BUILD_VERSION_INFORMATION // NtQuerySystemInformationEx // 222 + SystemPoolLimitInformation, // SYSTEM_POOL_LIMIT_INFORMATION (requires SeIncreaseQuotaPrivilege) + SystemCodeIntegrityAddDynamicStore, + SystemCodeIntegrityClearDynamicStores, + SystemDifPoolTrackingInformation, + SystemPoolZeroingInformation, // q: SYSTEM_POOL_ZEROING_INFORMATION + SystemDpcWatchdogInformation, // q; s: SYSTEM_DPC_WATCHDOG_CONFIGURATION_INFORMATION + SystemDpcWatchdogInformation2, // q; s: SYSTEM_DPC_WATCHDOG_CONFIGURATION_INFORMATION_V2 + SystemSupportedProcessorArchitectures2, + // q: in opt: HANDLE, out: SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION[] // NtQuerySystemInformationEx // + // 230 + SystemSingleProcessorRelationshipInformation, + // q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX // (EX in: PROCESSOR_NUMBER Processor) + SystemXfgCheckFailureInformation, // q: SYSTEM_XFG_FAILURE_INFORMATION + SystemIommuStateInformation, // SYSTEM_IOMMU_STATE_INFORMATION // since 22H1 + SystemHypervisorMinrootInformation, // SYSTEM_HYPERVISOR_MINROOT_INFORMATION + SystemHypervisorBootPagesInformation, // SYSTEM_HYPERVISOR_BOOT_PAGES_INFORMATION + SystemPointerAuthInformation, // SYSTEM_POINTER_AUTH_INFORMATION + SystemSecureKernelDebuggerInformation, + SystemOriginalImageFeatureInformation, + // q: in: SYSTEM_ORIGINAL_IMAGE_FEATURE_INFORMATION_INPUT, out: SYSTEM_ORIGINAL_IMAGE_FEATURE_INFORMATION_OUTPUT // + // NtQuerySystemInformationEx + SystemMemoryNumaInformation, // SYSTEM_MEMORY_NUMA_INFORMATION_INPUT, SYSTEM_MEMORY_NUMA_INFORMATION_OUTPUT + SystemMemoryNumaPerformanceInformation, + // SYSTEM_MEMORY_NUMA_PERFORMANCE_INFORMATION_INPUTSYSTEM_MEMORY_NUMA_PERFORMANCE_INFORMATION_INPUT, + // SYSTEM_MEMORY_NUMA_PERFORMANCE_INFORMATION_OUTPUT // since 24H2 // 240 + SystemCodeIntegritySignedPoliciesFullInformation, + SystemSecureSecretsInformation, + SystemTrustedAppsRuntimeInformation, // SYSTEM_TRUSTEDAPPS_RUNTIME_INFORMATION + SystemBadPageInformationEx, // SYSTEM_BAD_PAGE_INFORMATION + SystemResourceDeadlockTimeout, // ULONG + SystemBreakOnContextUnwindFailureInformation, // ULONG (requires SeDebugPrivilege) + SystemOslRamdiskInformation, // SYSTEM_OSL_RAMDISK_INFORMATION + MaxSystemInfoClass } SYSTEM_INFORMATION_CLASS; #ifndef OS_WINDOWS typedef enum _TOKEN_INFORMATION_CLASS { - TokenUser = 1, // q: TOKEN_USER, SE_TOKEN_USER - TokenGroups, // q: TOKEN_GROUPS - TokenPrivileges, // q: TOKEN_PRIVILEGES - TokenOwner, // q; s: TOKEN_OWNER - TokenPrimaryGroup, // q; s: TOKEN_PRIMARY_GROUP - TokenDefaultDacl, // q; s: TOKEN_DEFAULT_DACL - TokenSource, // q: TOKEN_SOURCE - TokenType, // q: TOKEN_TYPE - TokenImpersonationLevel, // q: SECURITY_IMPERSONATION_LEVEL - TokenStatistics, // q: TOKEN_STATISTICS // 10 - TokenRestrictedSids, // q: TOKEN_GROUPS - TokenSessionId, // q; s: ULONG (requires SeTcbPrivilege) - TokenGroupsAndPrivileges, // q: TOKEN_GROUPS_AND_PRIVILEGES - TokenSessionReference, // s: ULONG (requires SeTcbPrivilege) - TokenSandBoxInert, // q: ULONG - TokenAuditPolicy, // q; s: TOKEN_AUDIT_POLICY (requires SeSecurityPrivilege/SeTcbPrivilege) - TokenOrigin, // q; s: TOKEN_ORIGIN (requires SeTcbPrivilege) - TokenElevationType, // q: TOKEN_ELEVATION_TYPE - TokenLinkedToken, // q; s: TOKEN_LINKED_TOKEN (requires SeCreateTokenPrivilege) - TokenElevation, // q: TOKEN_ELEVATION // 20 - TokenHasRestrictions, // q: ULONG - TokenAccessInformation, // q: TOKEN_ACCESS_INFORMATION - TokenVirtualizationAllowed, // q; s: ULONG (requires SeCreateTokenPrivilege) - TokenVirtualizationEnabled, // q; s: ULONG - TokenIntegrityLevel, // q; s: TOKEN_MANDATORY_LABEL - TokenUIAccess, // q; s: ULONG (requires SeTcbPrivilege) - TokenMandatoryPolicy, // q; s: TOKEN_MANDATORY_POLICY (requires SeTcbPrivilege) - TokenLogonSid, // q: TOKEN_GROUPS - TokenIsAppContainer, // q: ULONG // since WIN8 - TokenCapabilities, // q: TOKEN_GROUPS // 30 - TokenAppContainerSid, // q: TOKEN_APPCONTAINER_INFORMATION - TokenAppContainerNumber, // q: ULONG - TokenUserClaimAttributes, // q: CLAIM_SECURITY_ATTRIBUTES_INFORMATION - TokenDeviceClaimAttributes, // q: CLAIM_SECURITY_ATTRIBUTES_INFORMATION - TokenRestrictedUserClaimAttributes, // q: CLAIM_SECURITY_ATTRIBUTES_INFORMATION + TokenUser = 1, // q: TOKEN_USER, SE_TOKEN_USER + TokenGroups, // q: TOKEN_GROUPS + TokenPrivileges, // q: TOKEN_PRIVILEGES + TokenOwner, // q; s: TOKEN_OWNER + TokenPrimaryGroup, // q; s: TOKEN_PRIMARY_GROUP + TokenDefaultDacl, // q; s: TOKEN_DEFAULT_DACL + TokenSource, // q: TOKEN_SOURCE + TokenType, // q: TOKEN_TYPE + TokenImpersonationLevel, // q: SECURITY_IMPERSONATION_LEVEL + TokenStatistics, // q: TOKEN_STATISTICS // 10 + TokenRestrictedSids, // q: TOKEN_GROUPS + TokenSessionId, // q; s: ULONG (requires SeTcbPrivilege) + TokenGroupsAndPrivileges, // q: TOKEN_GROUPS_AND_PRIVILEGES + TokenSessionReference, // s: ULONG (requires SeTcbPrivilege) + TokenSandBoxInert, // q: ULONG + TokenAuditPolicy, // q; s: TOKEN_AUDIT_POLICY (requires SeSecurityPrivilege/SeTcbPrivilege) + TokenOrigin, // q; s: TOKEN_ORIGIN (requires SeTcbPrivilege) + TokenElevationType, // q: TOKEN_ELEVATION_TYPE + TokenLinkedToken, // q; s: TOKEN_LINKED_TOKEN (requires SeCreateTokenPrivilege) + TokenElevation, // q: TOKEN_ELEVATION // 20 + TokenHasRestrictions, // q: ULONG + TokenAccessInformation, // q: TOKEN_ACCESS_INFORMATION + TokenVirtualizationAllowed, // q; s: ULONG (requires SeCreateTokenPrivilege) + TokenVirtualizationEnabled, // q; s: ULONG + TokenIntegrityLevel, // q; s: TOKEN_MANDATORY_LABEL + TokenUIAccess, // q; s: ULONG (requires SeTcbPrivilege) + TokenMandatoryPolicy, // q; s: TOKEN_MANDATORY_POLICY (requires SeTcbPrivilege) + TokenLogonSid, // q: TOKEN_GROUPS + TokenIsAppContainer, // q: ULONG // since WIN8 + TokenCapabilities, // q: TOKEN_GROUPS // 30 + TokenAppContainerSid, // q: TOKEN_APPCONTAINER_INFORMATION + TokenAppContainerNumber, // q: ULONG + TokenUserClaimAttributes, // q: CLAIM_SECURITY_ATTRIBUTES_INFORMATION + TokenDeviceClaimAttributes, // q: CLAIM_SECURITY_ATTRIBUTES_INFORMATION + TokenRestrictedUserClaimAttributes, // q: CLAIM_SECURITY_ATTRIBUTES_INFORMATION TokenRestrictedDeviceClaimAttributes, // q: CLAIM_SECURITY_ATTRIBUTES_INFORMATION - TokenDeviceGroups, // q: TOKEN_GROUPS - TokenRestrictedDeviceGroups, // q: TOKEN_GROUPS - TokenSecurityAttributes, // q; s: TOKEN_SECURITY_ATTRIBUTES_[AND_OPERATION_]INFORMATION (requires SeTcbPrivilege) - TokenIsRestricted, // q: ULONG // 40 - TokenProcessTrustLevel, // q: TOKEN_PROCESS_TRUST_LEVEL // since WINBLUE - TokenPrivateNameSpace, // q; s: ULONG (requires SeTcbPrivilege) // since THRESHOLD + TokenDeviceGroups, // q: TOKEN_GROUPS + TokenRestrictedDeviceGroups, // q: TOKEN_GROUPS + TokenSecurityAttributes, // q; s: TOKEN_SECURITY_ATTRIBUTES_[AND_OPERATION_]INFORMATION (requires SeTcbPrivilege) + TokenIsRestricted, // q: ULONG // 40 + TokenProcessTrustLevel, // q: TOKEN_PROCESS_TRUST_LEVEL // since WINBLUE + TokenPrivateNameSpace, // q; s: ULONG (requires SeTcbPrivilege) // since THRESHOLD TokenSingletonAttributes, // q: TOKEN_SECURITY_ATTRIBUTES_INFORMATION // since REDSTONE - TokenBnoIsolation, // q: TOKEN_BNO_ISOLATION_INFORMATION // since REDSTONE2 - TokenChildProcessFlags, // s: ULONG (requires SeTcbPrivilege) // since REDSTONE3 + TokenBnoIsolation, // q: TOKEN_BNO_ISOLATION_INFORMATION // since REDSTONE2 + TokenChildProcessFlags, // s: ULONG (requires SeTcbPrivilege) // since REDSTONE3 TokenIsLessPrivilegedAppContainer, // q: ULONG // since REDSTONE5 - TokenIsSandboxed, // q: ULONG // since 19H1 - TokenIsAppSilo, // q: ULONG // since WIN11 22H2 // previously TokenOriginatingProcessTrustLevel // q: TOKEN_PROCESS_TRUST_LEVEL + TokenIsSandboxed, // q: ULONG // since 19H1 + TokenIsAppSilo, // q: ULONG // since WIN11 22H2 // previously TokenOriginatingProcessTrustLevel // q: + // TOKEN_PROCESS_TRUST_LEVEL TokenLoggingInformation, // TOKEN_LOGGING_INFORMATION // since 24H2 MaxTokenInfoClass } TOKEN_INFORMATION_CLASS, *PTOKEN_INFORMATION_CLASS; @@ -368,305 +379,307 @@ typedef enum _TOKEN_INFORMATION_CLASS typedef enum _PROCESSINFOCLASS { - ProcessBasicInformation, // q: PROCESS_BASIC_INFORMATION, PROCESS_EXTENDED_BASIC_INFORMATION - ProcessQuotaLimits, // qs: QUOTA_LIMITS, QUOTA_LIMITS_EX - ProcessIoCounters, // q: IO_COUNTERS - ProcessVmCounters, // q: VM_COUNTERS, VM_COUNTERS_EX, VM_COUNTERS_EX2 - ProcessTimes, // q: KERNEL_USER_TIMES - ProcessBasePriority, // s: KPRIORITY - ProcessRaisePriority, // s: ULONG - ProcessDebugPort, // q: HANDLE - ProcessExceptionPort, // s: PROCESS_EXCEPTION_PORT (requires SeTcbPrivilege) - ProcessAccessToken, // s: PROCESS_ACCESS_TOKEN - ProcessLdtInformation, // qs: PROCESS_LDT_INFORMATION // 10 - ProcessLdtSize, // s: PROCESS_LDT_SIZE - ProcessDefaultHardErrorMode, // qs: ULONG - ProcessIoPortHandlers, // (kernel-mode only) // s: PROCESS_IO_PORT_HANDLER_INFORMATION - ProcessPooledUsageAndLimits, // q: POOLED_USAGE_AND_LIMITS - ProcessWorkingSetWatch, // q: PROCESS_WS_WATCH_INFORMATION[]; s: void - ProcessUserModeIOPL, // qs: ULONG (requires SeTcbPrivilege) - ProcessEnableAlignmentFaultFixup, // s: BOOLEAN - ProcessPriorityClass, // qs: PROCESS_PRIORITY_CLASS - ProcessWx86Information, // qs: ULONG (requires SeTcbPrivilege) (VdmAllowed) - ProcessHandleCount, // q: ULONG, PROCESS_HANDLE_INFORMATION // 20 - ProcessAffinityMask, // (q >WIN7)s: KAFFINITY, qs: GROUP_AFFINITY - ProcessPriorityBoost, // qs: ULONG - ProcessDeviceMap, // qs: PROCESS_DEVICEMAP_INFORMATION, PROCESS_DEVICEMAP_INFORMATION_EX - ProcessSessionInformation, // q: PROCESS_SESSION_INFORMATION - ProcessForegroundInformation, // s: PROCESS_FOREGROUND_BACKGROUND - ProcessWow64Information, // q: ULONG_PTR - ProcessImageFileName, // q: UNICODE_STRING - ProcessLUIDDeviceMapsEnabled, // q: ULONG - ProcessBreakOnTermination, // qs: ULONG - ProcessDebugObjectHandle, // q: HANDLE // 30 - ProcessDebugFlags, // qs: ULONG - ProcessHandleTracing, // q: PROCESS_HANDLE_TRACING_QUERY; s: PROCESS_HANDLE_TRACING_ENABLE[_EX] or void to disable - ProcessIoPriority, // qs: IO_PRIORITY_HINT - ProcessExecuteFlags, // qs: ULONG (MEM_EXECUTE_OPTION_*) - ProcessTlsInformation, // PROCESS_TLS_INFORMATION // ProcessResourceManagement - ProcessCookie, // q: ULONG - ProcessImageInformation, // q: SECTION_IMAGE_INFORMATION - ProcessCycleTime, // q: PROCESS_CYCLE_TIME_INFORMATION // since VISTA - ProcessPagePriority, // qs: PAGE_PRIORITY_INFORMATION - ProcessInstrumentationCallback, // s: PVOID or PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION // 40 - ProcessThreadStackAllocation, // s: PROCESS_STACK_ALLOCATION_INFORMATION, PROCESS_STACK_ALLOCATION_INFORMATION_EX - ProcessWorkingSetWatchEx, // q: PROCESS_WS_WATCH_INFORMATION_EX[]; s: void - ProcessImageFileNameWin32, // q: UNICODE_STRING - ProcessImageFileMapping, // q: HANDLE (input) - ProcessAffinityUpdateMode, // qs: PROCESS_AFFINITY_UPDATE_MODE - ProcessMemoryAllocationMode, // qs: PROCESS_MEMORY_ALLOCATION_MODE - ProcessGroupInformation, // q: USHORT[] - ProcessTokenVirtualizationEnabled, // s: ULONG - ProcessConsoleHostProcess, // qs: ULONG_PTR // ProcessOwnerInformation - ProcessWindowInformation, // q: PROCESS_WINDOW_INFORMATION // 50 - ProcessHandleInformation, // q: PROCESS_HANDLE_SNAPSHOT_INFORMATION // since WIN8 - ProcessMitigationPolicy, // s: PROCESS_MITIGATION_POLICY_INFORMATION - ProcessDynamicFunctionTableInformation, // s: PROCESS_DYNAMIC_FUNCTION_TABLE_INFORMATION - ProcessHandleCheckingMode, // qs: ULONG; s: 0 disables, otherwise enables - ProcessKeepAliveCount, // q: PROCESS_KEEPALIVE_COUNT_INFORMATION - ProcessRevokeFileHandles, // s: PROCESS_REVOKE_FILE_HANDLES_INFORMATION - ProcessWorkingSetControl, // s: PROCESS_WORKING_SET_CONTROL (requires SeDebugPrivilege) - ProcessHandleTable, // q: ULONG[] // since WINBLUE - ProcessCheckStackExtentsMode, // qs: ULONG // KPROCESS->CheckStackExtents (CFG) - ProcessCommandLineInformation, // q: UNICODE_STRING // 60 - ProcessProtectionInformation, // q: PS_PROTECTION - ProcessMemoryExhaustion, // s: PROCESS_MEMORY_EXHAUSTION_INFO // since THRESHOLD - ProcessFaultInformation, // s: PROCESS_FAULT_INFORMATION - ProcessTelemetryIdInformation, // q: PROCESS_TELEMETRY_ID_INFORMATION - ProcessCommitReleaseInformation, // qs: PROCESS_COMMIT_RELEASE_INFORMATION - ProcessDefaultCpuSetsInformation, // qs: SYSTEM_CPU_SET_INFORMATION[5] - ProcessAllowedCpuSetsInformation, // qs: SYSTEM_CPU_SET_INFORMATION[5] - ProcessSubsystemProcess, - ProcessJobMemoryInformation, // q: PROCESS_JOB_MEMORY_INFO - ProcessInPrivate, // q: BOOLEAN; s: void // ETW // since THRESHOLD2 // 70 - ProcessRaiseUMExceptionOnInvalidHandleClose, // qs: ULONG; s: 0 disables, otherwise enables - ProcessIumChallengeResponse, - ProcessChildProcessInformation, // q: PROCESS_CHILD_PROCESS_INFORMATION - ProcessHighGraphicsPriorityInformation, // qs: BOOLEAN (requires SeTcbPrivilege) - ProcessSubsystemInformation, // q: SUBSYSTEM_INFORMATION_TYPE // since REDSTONE2 - ProcessEnergyValues, // q: PROCESS_ENERGY_VALUES, PROCESS_EXTENDED_ENERGY_VALUES - ProcessPowerThrottlingState, // qs: POWER_THROTTLING_PROCESS_STATE - ProcessReserved3Information, // ProcessActivityThrottlePolicy // PROCESS_ACTIVITY_THROTTLE_POLICY - ProcessWin32kSyscallFilterInformation, // q: WIN32K_SYSCALL_FILTER - ProcessDisableSystemAllowedCpuSets, // s: BOOLEAN // 80 - ProcessWakeInformation, // q: PROCESS_WAKE_INFORMATION - ProcessEnergyTrackingState, // qs: PROCESS_ENERGY_TRACKING_STATE - ProcessManageWritesToExecutableMemory, // MANAGE_WRITES_TO_EXECUTABLE_MEMORY // since REDSTONE3 - ProcessCaptureTrustletLiveDump, - ProcessTelemetryCoverage, // q: TELEMETRY_COVERAGE_HEADER; s: TELEMETRY_COVERAGE_POINT - ProcessEnclaveInformation, - ProcessEnableReadWriteVmLogging, // qs: PROCESS_READWRITEVM_LOGGING_INFORMATION - ProcessUptimeInformation, // q: PROCESS_UPTIME_INFORMATION - ProcessImageSection, // q: HANDLE - ProcessDebugAuthInformation, // since REDSTONE4 // 90 - ProcessSystemResourceManagement, // s: PROCESS_SYSTEM_RESOURCE_MANAGEMENT - ProcessSequenceNumber, // q: ULONGLONG - ProcessLoaderDetour, // since REDSTONE5 - ProcessSecurityDomainInformation, // q: PROCESS_SECURITY_DOMAIN_INFORMATION - ProcessCombineSecurityDomainsInformation, // s: PROCESS_COMBINE_SECURITY_DOMAINS_INFORMATION - ProcessEnableLogging, // qs: PROCESS_LOGGING_INFORMATION - ProcessLeapSecondInformation, // qs: PROCESS_LEAP_SECOND_INFORMATION - ProcessFiberShadowStackAllocation, // s: PROCESS_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION // since 19H1 - ProcessFreeFiberShadowStackAllocation, // s: PROCESS_FREE_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION - ProcessAltSystemCallInformation, // s: PROCESS_SYSCALL_PROVIDER_INFORMATION // since 20H1 // 100 - ProcessDynamicEHContinuationTargets, // s: PROCESS_DYNAMIC_EH_CONTINUATION_TARGETS_INFORMATION - ProcessDynamicEnforcedCetCompatibleRanges, // s: PROCESS_DYNAMIC_ENFORCED_ADDRESS_RANGE_INFORMATION // since 20H2 - ProcessCreateStateChange, // since WIN11 - ProcessApplyStateChange, - ProcessEnableOptionalXStateFeatures, // s: ULONG64 // optional XState feature bitmask - ProcessAltPrefetchParam, // qs: OVERRIDE_PREFETCH_PARAMETER // App Launch Prefetch (ALPF) // since 22H1 - ProcessAssignCpuPartitions, - ProcessPriorityClassEx, // s: PROCESS_PRIORITY_CLASS_EX - ProcessMembershipInformation, // q: PROCESS_MEMBERSHIP_INFORMATION - ProcessEffectiveIoPriority, // q: IO_PRIORITY_HINT // 110 - ProcessEffectivePagePriority, // q: ULONG - ProcessSchedulerSharedData, // since 24H2 - ProcessSlistRollbackInformation, - ProcessNetworkIoCounters, // q: PROCESS_NETWORK_COUNTERS - ProcessFindFirstThreadByTebValue, // PROCESS_TEB_VALUE_INFORMATION - MaxProcessInfoClass + ProcessBasicInformation, // q: PROCESS_BASIC_INFORMATION, PROCESS_EXTENDED_BASIC_INFORMATION + ProcessQuotaLimits, // qs: QUOTA_LIMITS, QUOTA_LIMITS_EX + ProcessIoCounters, // q: IO_COUNTERS + ProcessVmCounters, // q: VM_COUNTERS, VM_COUNTERS_EX, VM_COUNTERS_EX2 + ProcessTimes, // q: KERNEL_USER_TIMES + ProcessBasePriority, // s: KPRIORITY + ProcessRaisePriority, // s: ULONG + ProcessDebugPort, // q: HANDLE + ProcessExceptionPort, // s: PROCESS_EXCEPTION_PORT (requires SeTcbPrivilege) + ProcessAccessToken, // s: PROCESS_ACCESS_TOKEN + ProcessLdtInformation, // qs: PROCESS_LDT_INFORMATION // 10 + ProcessLdtSize, // s: PROCESS_LDT_SIZE + ProcessDefaultHardErrorMode, // qs: ULONG + ProcessIoPortHandlers, // (kernel-mode only) // s: PROCESS_IO_PORT_HANDLER_INFORMATION + ProcessPooledUsageAndLimits, // q: POOLED_USAGE_AND_LIMITS + ProcessWorkingSetWatch, // q: PROCESS_WS_WATCH_INFORMATION[]; s: void + ProcessUserModeIOPL, // qs: ULONG (requires SeTcbPrivilege) + ProcessEnableAlignmentFaultFixup, // s: BOOLEAN + ProcessPriorityClass, // qs: PROCESS_PRIORITY_CLASS + ProcessWx86Information, // qs: ULONG (requires SeTcbPrivilege) (VdmAllowed) + ProcessHandleCount, // q: ULONG, PROCESS_HANDLE_INFORMATION // 20 + ProcessAffinityMask, // (q >WIN7)s: KAFFINITY, qs: GROUP_AFFINITY + ProcessPriorityBoost, // qs: ULONG + ProcessDeviceMap, // qs: PROCESS_DEVICEMAP_INFORMATION, PROCESS_DEVICEMAP_INFORMATION_EX + ProcessSessionInformation, // q: PROCESS_SESSION_INFORMATION + ProcessForegroundInformation, // s: PROCESS_FOREGROUND_BACKGROUND + ProcessWow64Information, // q: ULONG_PTR + ProcessImageFileName, // q: UNICODE_STRING + ProcessLUIDDeviceMapsEnabled, // q: ULONG + ProcessBreakOnTermination, // qs: ULONG + ProcessDebugObjectHandle, // q: HANDLE // 30 + ProcessDebugFlags, // qs: ULONG + ProcessHandleTracing, // q: PROCESS_HANDLE_TRACING_QUERY; s: PROCESS_HANDLE_TRACING_ENABLE[_EX] or void to disable + ProcessIoPriority, // qs: IO_PRIORITY_HINT + ProcessExecuteFlags, // qs: ULONG (MEM_EXECUTE_OPTION_*) + ProcessTlsInformation, // PROCESS_TLS_INFORMATION // ProcessResourceManagement + ProcessCookie, // q: ULONG + ProcessImageInformation, // q: SECTION_IMAGE_INFORMATION + ProcessCycleTime, // q: PROCESS_CYCLE_TIME_INFORMATION // since VISTA + ProcessPagePriority, // qs: PAGE_PRIORITY_INFORMATION + ProcessInstrumentationCallback, // s: PVOID or PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION // 40 + ProcessThreadStackAllocation, // s: PROCESS_STACK_ALLOCATION_INFORMATION, PROCESS_STACK_ALLOCATION_INFORMATION_EX + ProcessWorkingSetWatchEx, // q: PROCESS_WS_WATCH_INFORMATION_EX[]; s: void + ProcessImageFileNameWin32, // q: UNICODE_STRING + ProcessImageFileMapping, // q: HANDLE (input) + ProcessAffinityUpdateMode, // qs: PROCESS_AFFINITY_UPDATE_MODE + ProcessMemoryAllocationMode, // qs: PROCESS_MEMORY_ALLOCATION_MODE + ProcessGroupInformation, // q: USHORT[] + ProcessTokenVirtualizationEnabled, // s: ULONG + ProcessConsoleHostProcess, // qs: ULONG_PTR // ProcessOwnerInformation + ProcessWindowInformation, // q: PROCESS_WINDOW_INFORMATION // 50 + ProcessHandleInformation, // q: PROCESS_HANDLE_SNAPSHOT_INFORMATION // since WIN8 + ProcessMitigationPolicy, // s: PROCESS_MITIGATION_POLICY_INFORMATION + ProcessDynamicFunctionTableInformation, // s: PROCESS_DYNAMIC_FUNCTION_TABLE_INFORMATION + ProcessHandleCheckingMode, // qs: ULONG; s: 0 disables, otherwise enables + ProcessKeepAliveCount, // q: PROCESS_KEEPALIVE_COUNT_INFORMATION + ProcessRevokeFileHandles, // s: PROCESS_REVOKE_FILE_HANDLES_INFORMATION + ProcessWorkingSetControl, // s: PROCESS_WORKING_SET_CONTROL (requires SeDebugPrivilege) + ProcessHandleTable, // q: ULONG[] // since WINBLUE + ProcessCheckStackExtentsMode, // qs: ULONG // KPROCESS->CheckStackExtents (CFG) + ProcessCommandLineInformation, // q: UNICODE_STRING // 60 + ProcessProtectionInformation, // q: PS_PROTECTION + ProcessMemoryExhaustion, // s: PROCESS_MEMORY_EXHAUSTION_INFO // since THRESHOLD + ProcessFaultInformation, // s: PROCESS_FAULT_INFORMATION + ProcessTelemetryIdInformation, // q: PROCESS_TELEMETRY_ID_INFORMATION + ProcessCommitReleaseInformation, // qs: PROCESS_COMMIT_RELEASE_INFORMATION + ProcessDefaultCpuSetsInformation, // qs: SYSTEM_CPU_SET_INFORMATION[5] + ProcessAllowedCpuSetsInformation, // qs: SYSTEM_CPU_SET_INFORMATION[5] + ProcessSubsystemProcess, + ProcessJobMemoryInformation, // q: PROCESS_JOB_MEMORY_INFO + ProcessInPrivate, // q: BOOLEAN; s: void // ETW // since THRESHOLD2 // 70 + ProcessRaiseUMExceptionOnInvalidHandleClose, // qs: ULONG; s: 0 disables, otherwise enables + ProcessIumChallengeResponse, + ProcessChildProcessInformation, // q: PROCESS_CHILD_PROCESS_INFORMATION + ProcessHighGraphicsPriorityInformation, // qs: BOOLEAN (requires SeTcbPrivilege) + ProcessSubsystemInformation, // q: SUBSYSTEM_INFORMATION_TYPE // since REDSTONE2 + ProcessEnergyValues, // q: PROCESS_ENERGY_VALUES, PROCESS_EXTENDED_ENERGY_VALUES + ProcessPowerThrottlingState, // qs: POWER_THROTTLING_PROCESS_STATE + ProcessReserved3Information, // ProcessActivityThrottlePolicy // PROCESS_ACTIVITY_THROTTLE_POLICY + ProcessWin32kSyscallFilterInformation, // q: WIN32K_SYSCALL_FILTER + ProcessDisableSystemAllowedCpuSets, // s: BOOLEAN // 80 + ProcessWakeInformation, // q: PROCESS_WAKE_INFORMATION + ProcessEnergyTrackingState, // qs: PROCESS_ENERGY_TRACKING_STATE + ProcessManageWritesToExecutableMemory, // MANAGE_WRITES_TO_EXECUTABLE_MEMORY // since REDSTONE3 + ProcessCaptureTrustletLiveDump, + ProcessTelemetryCoverage, // q: TELEMETRY_COVERAGE_HEADER; s: TELEMETRY_COVERAGE_POINT + ProcessEnclaveInformation, + ProcessEnableReadWriteVmLogging, // qs: PROCESS_READWRITEVM_LOGGING_INFORMATION + ProcessUptimeInformation, // q: PROCESS_UPTIME_INFORMATION + ProcessImageSection, // q: HANDLE + ProcessDebugAuthInformation, // since REDSTONE4 // 90 + ProcessSystemResourceManagement, // s: PROCESS_SYSTEM_RESOURCE_MANAGEMENT + ProcessSequenceNumber, // q: ULONGLONG + ProcessLoaderDetour, // since REDSTONE5 + ProcessSecurityDomainInformation, // q: PROCESS_SECURITY_DOMAIN_INFORMATION + ProcessCombineSecurityDomainsInformation, // s: PROCESS_COMBINE_SECURITY_DOMAINS_INFORMATION + ProcessEnableLogging, // qs: PROCESS_LOGGING_INFORMATION + ProcessLeapSecondInformation, // qs: PROCESS_LEAP_SECOND_INFORMATION + ProcessFiberShadowStackAllocation, // s: PROCESS_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION // since 19H1 + ProcessFreeFiberShadowStackAllocation, // s: PROCESS_FREE_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION + ProcessAltSystemCallInformation, // s: PROCESS_SYSCALL_PROVIDER_INFORMATION // since 20H1 // 100 + ProcessDynamicEHContinuationTargets, // s: PROCESS_DYNAMIC_EH_CONTINUATION_TARGETS_INFORMATION + ProcessDynamicEnforcedCetCompatibleRanges, // s: PROCESS_DYNAMIC_ENFORCED_ADDRESS_RANGE_INFORMATION // since 20H2 + ProcessCreateStateChange, // since WIN11 + ProcessApplyStateChange, + ProcessEnableOptionalXStateFeatures, // s: ULONG64 // optional XState feature bitmask + ProcessAltPrefetchParam, // qs: OVERRIDE_PREFETCH_PARAMETER // App Launch Prefetch (ALPF) // since 22H1 + ProcessAssignCpuPartitions, + ProcessPriorityClassEx, // s: PROCESS_PRIORITY_CLASS_EX + ProcessMembershipInformation, // q: PROCESS_MEMBERSHIP_INFORMATION + ProcessEffectiveIoPriority, // q: IO_PRIORITY_HINT // 110 + ProcessEffectivePagePriority, // q: ULONG + ProcessSchedulerSharedData, // since 24H2 + ProcessSlistRollbackInformation, + ProcessNetworkIoCounters, // q: PROCESS_NETWORK_COUNTERS + ProcessFindFirstThreadByTebValue, // PROCESS_TEB_VALUE_INFORMATION + MaxProcessInfoClass } PROCESSINFOCLASS; typedef enum _PS_ATTRIBUTE_NUM { - PsAttributeParentProcess, // in HANDLE - PsAttributeDebugObject, // in HANDLE - PsAttributeToken, // in HANDLE - PsAttributeClientId, // out PCLIENT_ID - PsAttributeTebAddress, // out PTEB * - PsAttributeImageName, // in PWSTR - PsAttributeImageInfo, // out PSECTION_IMAGE_INFORMATION - PsAttributeMemoryReserve, // in PPS_MEMORY_RESERVE - PsAttributePriorityClass, // in UCHAR - PsAttributeErrorMode, // in ULONG - PsAttributeStdHandleInfo, // 10, in PPS_STD_HANDLE_INFO - PsAttributeHandleList, // in HANDLE[] - PsAttributeGroupAffinity, // in PGROUP_AFFINITY - PsAttributePreferredNode, // in PUSHORT - PsAttributeIdealProcessor, // in PPROCESSOR_NUMBER - PsAttributeUmsThread, // ? in PUMS_CREATE_THREAD_ATTRIBUTES - PsAttributeMitigationOptions, // in PPS_MITIGATION_OPTIONS_MAP (PROCESS_CREATION_MITIGATION_POLICY_*) // since WIN8 - PsAttributeProtectionLevel, // in PS_PROTECTION // since WINBLUE - PsAttributeSecureProcess, // in PPS_TRUSTLET_CREATE_ATTRIBUTES, since THRESHOLD - PsAttributeJobList, // in HANDLE[] - PsAttributeChildProcessPolicy, // 20, in PULONG (PROCESS_CREATION_CHILD_PROCESS_*) // since THRESHOLD2 - PsAttributeAllApplicationPackagesPolicy, - // in PULONG (PROCESS_CREATION_ALL_APPLICATION_PACKAGES_*) // since REDSTONE - PsAttributeWin32kFilter, // in PWIN32K_SYSCALL_FILTER - PsAttributeSafeOpenPromptOriginClaim, // in SE_SAFE_OPEN_PROMPT_RESULTS - PsAttributeBnoIsolation, // in PPS_BNO_ISOLATION_PARAMETERS // since REDSTONE2 - PsAttributeDesktopAppPolicy, // in PULONG (PROCESS_CREATION_DESKTOP_APP_*) - PsAttributeChpe, // in BOOLEAN // since REDSTONE3 - PsAttributeMitigationAuditOptions, - // in PPS_MITIGATION_AUDIT_OPTIONS_MAP (PROCESS_CREATION_MITIGATION_AUDIT_POLICY_*) // since 21H1 - PsAttributeMachineType, // in USHORT // since 21H2 - PsAttributeComponentFilter, - PsAttributeEnableOptionalXStateFeatures, // since WIN11 - PsAttributeSupportedMachines, // since 24H2 - PsAttributeSveVectorLength, // PPS_PROCESS_CREATION_SVE_VECTOR_LENGTH - PsAttributeMax + PsAttributeParentProcess, // in HANDLE + PsAttributeDebugObject, // in HANDLE + PsAttributeToken, // in HANDLE + PsAttributeClientId, // out PCLIENT_ID + PsAttributeTebAddress, // out PTEB * + PsAttributeImageName, // in PWSTR + PsAttributeImageInfo, // out PSECTION_IMAGE_INFORMATION + PsAttributeMemoryReserve, // in PPS_MEMORY_RESERVE + PsAttributePriorityClass, // in UCHAR + PsAttributeErrorMode, // in ULONG + PsAttributeStdHandleInfo, // 10, in PPS_STD_HANDLE_INFO + PsAttributeHandleList, // in HANDLE[] + PsAttributeGroupAffinity, // in PGROUP_AFFINITY + PsAttributePreferredNode, // in PUSHORT + PsAttributeIdealProcessor, // in PPROCESSOR_NUMBER + PsAttributeUmsThread, // ? in PUMS_CREATE_THREAD_ATTRIBUTES + PsAttributeMitigationOptions, // in PPS_MITIGATION_OPTIONS_MAP (PROCESS_CREATION_MITIGATION_POLICY_*) // since WIN8 + PsAttributeProtectionLevel, // in PS_PROTECTION // since WINBLUE + PsAttributeSecureProcess, // in PPS_TRUSTLET_CREATE_ATTRIBUTES, since THRESHOLD + PsAttributeJobList, // in HANDLE[] + PsAttributeChildProcessPolicy, // 20, in PULONG (PROCESS_CREATION_CHILD_PROCESS_*) // since THRESHOLD2 + PsAttributeAllApplicationPackagesPolicy, + // in PULONG (PROCESS_CREATION_ALL_APPLICATION_PACKAGES_*) // since REDSTONE + PsAttributeWin32kFilter, // in PWIN32K_SYSCALL_FILTER + PsAttributeSafeOpenPromptOriginClaim, // in SE_SAFE_OPEN_PROMPT_RESULTS + PsAttributeBnoIsolation, // in PPS_BNO_ISOLATION_PARAMETERS // since REDSTONE2 + PsAttributeDesktopAppPolicy, // in PULONG (PROCESS_CREATION_DESKTOP_APP_*) + PsAttributeChpe, // in BOOLEAN // since REDSTONE3 + PsAttributeMitigationAuditOptions, + // in PPS_MITIGATION_AUDIT_OPTIONS_MAP (PROCESS_CREATION_MITIGATION_AUDIT_POLICY_*) // since 21H1 + PsAttributeMachineType, // in USHORT // since 21H2 + PsAttributeComponentFilter, + PsAttributeEnableOptionalXStateFeatures, // since WIN11 + PsAttributeSupportedMachines, // since 24H2 + PsAttributeSveVectorLength, // PPS_PROCESS_CREATION_SVE_VECTOR_LENGTH + PsAttributeMax } PS_ATTRIBUTE_NUM; struct SYSTEM_PROCESSOR_INFORMATION64 { - USHORT ProcessorArchitecture; - USHORT ProcessorLevel; - USHORT ProcessorRevision; - USHORT MaximumProcessors; - ULONG ProcessorFeatureBits; + USHORT ProcessorArchitecture; + USHORT ProcessorLevel; + USHORT ProcessorRevision; + USHORT MaximumProcessors; + ULONG ProcessorFeatureBits; }; #ifndef OS_WINDOWS -typedef struct _M128A { +typedef struct _M128A +{ ULONGLONG Low; LONGLONG High; } M128A, *PM128A; -typedef struct _XMM_SAVE_AREA32 { - WORD ControlWord; - WORD StatusWord; - BYTE TagWord; - BYTE Reserved1; - WORD ErrorOpcode; - DWORD ErrorOffset; - WORD ErrorSelector; - WORD Reserved2; - DWORD DataOffset; - WORD DataSelector; - WORD Reserved3; - DWORD MxCsr; - DWORD MxCsr_Mask; - M128A FloatRegisters[8]; - M128A XmmRegisters[16]; - BYTE Reserved4[96]; +typedef struct _XMM_SAVE_AREA32 +{ + WORD ControlWord; + WORD StatusWord; + BYTE TagWord; + BYTE Reserved1; + WORD ErrorOpcode; + DWORD ErrorOffset; + WORD ErrorSelector; + WORD Reserved2; + DWORD DataOffset; + WORD DataSelector; + WORD Reserved3; + DWORD MxCsr; + DWORD MxCsr_Mask; + M128A FloatRegisters[8]; + M128A XmmRegisters[16]; + BYTE Reserved4[96]; } XMM_SAVE_AREA32, *PXMM_SAVE_AREA32; #endif typedef struct _NEON128 { - ULONGLONG Low; - LONGLONG High; + ULONGLONG Low; + LONGLONG High; } NEON128; typedef struct DECLSPEC_ALIGN(16) _CONTEXT64 { - DWORD64 P1Home; - DWORD64 P2Home; - DWORD64 P3Home; - DWORD64 P4Home; - DWORD64 P5Home; - DWORD64 P6Home; - DWORD ContextFlags; - DWORD MxCsr; - WORD SegCs; - WORD SegDs; - WORD SegEs; - WORD SegFs; - WORD SegGs; - WORD SegSs; - DWORD EFlags; - DWORD64 Dr0; - DWORD64 Dr1; - DWORD64 Dr2; - DWORD64 Dr3; - DWORD64 Dr6; - DWORD64 Dr7; - DWORD64 Rax; - DWORD64 Rcx; - DWORD64 Rdx; - DWORD64 Rbx; - DWORD64 Rsp; - DWORD64 Rbp; - DWORD64 Rsi; - DWORD64 Rdi; - DWORD64 R8; - DWORD64 R9; - DWORD64 R10; - DWORD64 R11; - DWORD64 R12; - DWORD64 R13; - DWORD64 R14; - DWORD64 R15; - DWORD64 Rip; + DWORD64 P1Home; + DWORD64 P2Home; + DWORD64 P3Home; + DWORD64 P4Home; + DWORD64 P5Home; + DWORD64 P6Home; + DWORD ContextFlags; + DWORD MxCsr; + WORD SegCs; + WORD SegDs; + WORD SegEs; + WORD SegFs; + WORD SegGs; + WORD SegSs; + DWORD EFlags; + DWORD64 Dr0; + DWORD64 Dr1; + DWORD64 Dr2; + DWORD64 Dr3; + DWORD64 Dr6; + DWORD64 Dr7; + DWORD64 Rax; + DWORD64 Rcx; + DWORD64 Rdx; + DWORD64 Rbx; + DWORD64 Rsp; + DWORD64 Rbp; + DWORD64 Rsi; + DWORD64 Rdi; + DWORD64 R8; + DWORD64 R9; + DWORD64 R10; + DWORD64 R11; + DWORD64 R12; + DWORD64 R13; + DWORD64 R14; + DWORD64 R15; + DWORD64 Rip; - union - { - XMM_SAVE_AREA32 FltSave; - NEON128 Q[16]; - ULONGLONG D[32]; + union + { + XMM_SAVE_AREA32 FltSave; + NEON128 Q[16]; + ULONGLONG D[32]; - struct - { - M128A Header[2]; - M128A Legacy[8]; - M128A Xmm0; - M128A Xmm1; - M128A Xmm2; - M128A Xmm3; - M128A Xmm4; - M128A Xmm5; - M128A Xmm6; - M128A Xmm7; - M128A Xmm8; - M128A Xmm9; - M128A Xmm10; - M128A Xmm11; - M128A Xmm12; - M128A Xmm13; - M128A Xmm14; - M128A Xmm15; - }; + struct + { + M128A Header[2]; + M128A Legacy[8]; + M128A Xmm0; + M128A Xmm1; + M128A Xmm2; + M128A Xmm3; + M128A Xmm4; + M128A Xmm5; + M128A Xmm6; + M128A Xmm7; + M128A Xmm8; + M128A Xmm9; + M128A Xmm10; + M128A Xmm11; + M128A Xmm12; + M128A Xmm13; + M128A Xmm14; + M128A Xmm15; + }; - DWORD S[32]; - }; + DWORD S[32]; + }; - M128A VectorRegister[26]; - DWORD64 VectorControl; - DWORD64 DebugControl; - DWORD64 LastBranchToRip; - DWORD64 LastBranchFromRip; - DWORD64 LastExceptionToRip; - DWORD64 LastExceptionFromRip; + M128A VectorRegister[26]; + DWORD64 VectorControl; + DWORD64 DebugControl; + DWORD64 LastBranchToRip; + DWORD64 LastBranchFromRip; + DWORD64 LastExceptionToRip; + DWORD64 LastExceptionFromRip; } CONTEXT64, *PCONTEXT64; template struct EMU_EXCEPTION_RECORD { - DWORD ExceptionCode; - DWORD ExceptionFlags; - EMULATOR_CAST(typename Traits::PVOID, struct EMU_EXCEPTION_RECORD *) ExceptionRecord; - typename Traits::PVOID ExceptionAddress; - DWORD NumberParameters; - typename Traits::ULONG_PTR ExceptionInformation[15]; + DWORD ExceptionCode; + DWORD ExceptionFlags; + EMULATOR_CAST(typename Traits::PVOID, struct EMU_EXCEPTION_RECORD*) ExceptionRecord; + typename Traits::PVOID ExceptionAddress; + DWORD NumberParameters; + typename Traits::ULONG_PTR ExceptionInformation[15]; }; template struct EMU_EXCEPTION_POINTERS { - EMULATOR_CAST(typename Traits::PVOID, EMU_EXCEPTION_RECORD*) ExceptionRecord; - EMULATOR_CAST(typename Traits::PVOID, CONTEXT64* or CONTEXT32*) ContextRecord; + EMULATOR_CAST(typename Traits::PVOID, EMU_EXCEPTION_RECORD*) ExceptionRecord; + EMULATOR_CAST(typename Traits::PVOID, CONTEXT64* or CONTEXT32*) ContextRecord; }; #define MAXIMUM_NODE_COUNT64 0x40 @@ -674,98 +687,102 @@ struct EMU_EXCEPTION_POINTERS struct EMU_GROUP_AFFINITY64 { - EMULATOR_CAST(std::uint64_t, KAFFINITY) Mask; - WORD Group; - WORD Reserved[3]; + EMULATOR_CAST(std::uint64_t, KAFFINITY) Mask; + WORD Group; + WORD Reserved[3]; }; typedef struct _SYSTEM_NUMA_INFORMATION64 { - ULONG HighestNodeNumber; - ULONG Reserved; + ULONG HighestNodeNumber; + ULONG Reserved; - union - { - EMU_GROUP_AFFINITY64 ActiveProcessorsGroupAffinity[MAXIMUM_NODE_COUNT64]; - ULONGLONG AvailableMemory[MAXIMUM_NODE_COUNT64]; - ULONGLONG Pad[MAXIMUM_NODE_COUNT64 * 2]; - }; + union + { + EMU_GROUP_AFFINITY64 ActiveProcessorsGroupAffinity[MAXIMUM_NODE_COUNT64]; + ULONGLONG AvailableMemory[MAXIMUM_NODE_COUNT64]; + ULONGLONG Pad[MAXIMUM_NODE_COUNT64 * 2]; + }; } SYSTEM_NUMA_INFORMATION64, *PSYSTEM_NUMA_INFORMATION64; typedef struct _SYSTEM_ERROR_PORT_TIMEOUTS { - ULONG StartTimeout; - ULONG CommTimeout; + ULONG StartTimeout; + ULONG CommTimeout; } SYSTEM_ERROR_PORT_TIMEOUTS, *PSYSTEM_ERROR_PORT_TIMEOUTS; typedef struct _SYSTEM_BASIC_INFORMATION64 { - ULONG Reserved; - ULONG TimerResolution; - ULONG PageSize; - ULONG NumberOfPhysicalPages; - ULONG LowestPhysicalPageNumber; - ULONG HighestPhysicalPageNumber; - ULONG AllocationGranularity; - EMULATOR_CAST(EmulatorTraits::PVOID, ULONG_PTR) MinimumUserModeAddress; - EMULATOR_CAST(EmulatorTraits::PVOID, ULONG_PTR) MaximumUserModeAddress; - EMULATOR_CAST(EmulatorTraits::PVOID, KAFFINITY) ActiveProcessorsAffinityMask; - char NumberOfProcessors; + ULONG Reserved; + ULONG TimerResolution; + ULONG PageSize; + ULONG NumberOfPhysicalPages; + ULONG LowestPhysicalPageNumber; + ULONG HighestPhysicalPageNumber; + ULONG AllocationGranularity; + EMULATOR_CAST(EmulatorTraits::PVOID, ULONG_PTR) MinimumUserModeAddress; + EMULATOR_CAST(EmulatorTraits::PVOID, ULONG_PTR) MaximumUserModeAddress; + EMULATOR_CAST(EmulatorTraits::PVOID, KAFFINITY) ActiveProcessorsAffinityMask; + char NumberOfProcessors; } SYSTEM_BASIC_INFORMATION64, *PSYSTEM_BASIC_INFORMATION64; typedef struct _SYSTEM_RANGE_START_INFORMATION64 { - EmulatorTraits::SIZE_T SystemRangeStart; + EmulatorTraits::SIZE_T SystemRangeStart; } SYSTEM_RANGE_START_INFORMATION64, *PSYSTEM_RANGE_START_INFORMATION64; struct SID_AND_ATTRIBUTES64 { - EMULATOR_CAST(EmulatorTraits::PVOID, PSID) Sid; - DWORD Attributes; + EMULATOR_CAST(EmulatorTraits::PVOID, PSID) Sid; + DWORD Attributes; }; struct TOKEN_USER64 { - SID_AND_ATTRIBUTES64 User; + SID_AND_ATTRIBUTES64 User; }; struct TOKEN_BNO_ISOLATION_INFORMATION64 { - EmulatorTraits::PVOID IsolationPrefix; - BOOLEAN IsolationEnabled; + EmulatorTraits::PVOID IsolationPrefix; + BOOLEAN IsolationEnabled; }; struct TOKEN_MANDATORY_LABEL64 { - SID_AND_ATTRIBUTES64 Label; + SID_AND_ATTRIBUTES64 Label; }; #ifndef OS_WINDOWS -typedef enum _TOKEN_TYPE { +typedef enum _TOKEN_TYPE +{ TokenPrimary = 1, TokenImpersonation } TOKEN_TYPE; typedef TOKEN_TYPE* PTOKEN_TYPE; -typedef struct _TOKEN_ELEVATION { +typedef struct _TOKEN_ELEVATION +{ DWORD TokenIsElevated; -} TOKEN_ELEVATION, * PTOKEN_ELEVATION; +} TOKEN_ELEVATION, *PTOKEN_ELEVATION; -typedef enum _SECURITY_IMPERSONATION_LEVEL { - SecurityAnonymous, - SecurityIdentification, - SecurityImpersonation, - SecurityDelegation +typedef enum _SECURITY_IMPERSONATION_LEVEL +{ + SecurityAnonymous, + SecurityIdentification, + SecurityImpersonation, + SecurityDelegation } SECURITY_IMPERSONATION_LEVEL, *PSECURITY_IMPERSONATION_LEVEL; - -typedef struct _LUID { +typedef struct _LUID +{ DWORD LowPart; LONG HighPart; } LUID, *PLUID; -typedef struct _TOKEN_STATISTICS { +typedef struct _TOKEN_STATISTICS +{ LUID TokenId; LUID AuthenticationId; LARGE_INTEGER ExpirationTime; @@ -782,109 +799,109 @@ typedef struct _TOKEN_STATISTICS { typedef struct _TOKEN_SECURITY_ATTRIBUTES_INFORMATION { - USHORT Version; - USHORT Reserved; - ULONG AttributeCount; + USHORT Version; + USHORT Reserved; + ULONG AttributeCount; - union - { - EmulatorTraits::PVOID pAttributeV1; - } Attribute; + union + { + EmulatorTraits::PVOID pAttributeV1; + } Attribute; } TOKEN_SECURITY_ATTRIBUTES_INFORMATION, *PTOKEN_SECURITY_ATTRIBUTES_INFORMATION; struct GDI_HANDLE_ENTRY64 { - union - { - EmulatorTraits::PVOID Object; - EmulatorTraits::PVOID NextFree; - }; + union + { + EmulatorTraits::PVOID Object; + EmulatorTraits::PVOID NextFree; + }; - union - { - struct - { - USHORT ProcessId; - USHORT Lock : 1; - USHORT Count : 15; - }; + union + { + struct + { + USHORT ProcessId; + USHORT Lock : 1; + USHORT Count : 15; + }; - ULONG Value; - } Owner; + ULONG Value; + } Owner; - USHORT Unique; - UCHAR Type; - UCHAR Flags; - EmulatorTraits::PVOID UserPointer; + USHORT Unique; + UCHAR Type; + UCHAR Flags; + EmulatorTraits::PVOID UserPointer; }; #define GDI_MAX_HANDLE_COUNT 0xFFFF // 0x4000 struct GDI_SHARED_MEMORY64 { - GDI_HANDLE_ENTRY64 Handles[GDI_MAX_HANDLE_COUNT]; + GDI_HANDLE_ENTRY64 Handles[GDI_MAX_HANDLE_COUNT]; }; struct CLIENT_ID64 { - DWORD64 UniqueProcess; - DWORD64 UniqueThread; + DWORD64 UniqueProcess; + DWORD64 UniqueThread; }; struct PORT_MESSAGE64 { - union - { - struct - { - CSHORT DataLength; - CSHORT TotalLength; - } s1; + union + { + struct + { + CSHORT DataLength; + CSHORT TotalLength; + } s1; - ULONG Length; - } u1; + ULONG Length; + } u1; - union - { - struct - { - CSHORT Type; - CSHORT DataInfoOffset; - } s2; + union + { + struct + { + CSHORT Type; + CSHORT DataInfoOffset; + } s2; - ULONG ZeroInit; - } u2; + ULONG ZeroInit; + } u2; - union - { - CLIENT_ID64 ClientId; - double DoNotUseThisField; - }; + union + { + CLIENT_ID64 ClientId; + double DoNotUseThisField; + }; - ULONG MessageId; + ULONG MessageId; - union - { - EmulatorTraits::SIZE_T ClientViewSize; // only valid for LPC_CONNECTION_REQUEST messages - ULONG CallbackId; // only valid for LPC_REQUEST messages - }; + union + { + EmulatorTraits::SIZE_T ClientViewSize; // only valid for LPC_CONNECTION_REQUEST messages + ULONG CallbackId; // only valid for LPC_REQUEST messages + }; }; struct ALPC_MESSAGE_ATTRIBUTES { - ULONG AllocatedAttributes; - ULONG ValidAttributes; + ULONG AllocatedAttributes; + ULONG ValidAttributes; }; template struct PORT_DATA_ENTRY { - typename Traits::PVOID Base; - ULONG Size; + typename Traits::PVOID Base; + ULONG Size; }; template struct EMU_RTL_SRWLOCK { - typename Traits::PVOID Ptr; + typename Traits::PVOID Ptr; }; diff --git a/src/common/platform/registry.hpp b/src/common/platform/registry.hpp index f77dd5d4..dc09d665 100644 --- a/src/common/platform/registry.hpp +++ b/src/common/platform/registry.hpp @@ -2,63 +2,63 @@ typedef enum _KEY_INFORMATION_CLASS { - KeyBasicInformation, // KEY_BASIC_INFORMATION - KeyNodeInformation, // KEY_NODE_INFORMATION - KeyFullInformation, // KEY_FULL_INFORMATION - KeyNameInformation, // KEY_NAME_INFORMATION - KeyCachedInformation, // KEY_CACHED_INFORMATION - KeyFlagsInformation, // KEY_FLAGS_INFORMATION - KeyVirtualizationInformation, // KEY_VIRTUALIZATION_INFORMATION - KeyHandleTagsInformation, // KEY_HANDLE_TAGS_INFORMATION - KeyTrustInformation, // KEY_TRUST_INFORMATION - KeyLayerInformation, // KEY_LAYER_INFORMATION - MaxKeyInfoClass + KeyBasicInformation, // KEY_BASIC_INFORMATION + KeyNodeInformation, // KEY_NODE_INFORMATION + KeyFullInformation, // KEY_FULL_INFORMATION + KeyNameInformation, // KEY_NAME_INFORMATION + KeyCachedInformation, // KEY_CACHED_INFORMATION + KeyFlagsInformation, // KEY_FLAGS_INFORMATION + KeyVirtualizationInformation, // KEY_VIRTUALIZATION_INFORMATION + KeyHandleTagsInformation, // KEY_HANDLE_TAGS_INFORMATION + KeyTrustInformation, // KEY_TRUST_INFORMATION + KeyLayerInformation, // KEY_LAYER_INFORMATION + MaxKeyInfoClass } KEY_INFORMATION_CLASS; typedef enum _KEY_VALUE_INFORMATION_CLASS { - KeyValueBasicInformation, // KEY_VALUE_BASIC_INFORMATION - KeyValueFullInformation, // KEY_VALUE_FULL_INFORMATION - KeyValuePartialInformation, // KEY_VALUE_PARTIAL_INFORMATION - KeyValueFullInformationAlign64, - KeyValuePartialInformationAlign64, // KEY_VALUE_PARTIAL_INFORMATION_ALIGN64 - KeyValueLayerInformation, // KEY_VALUE_LAYER_INFORMATION - MaxKeyValueInfoClass + KeyValueBasicInformation, // KEY_VALUE_BASIC_INFORMATION + KeyValueFullInformation, // KEY_VALUE_FULL_INFORMATION + KeyValuePartialInformation, // KEY_VALUE_PARTIAL_INFORMATION + KeyValueFullInformationAlign64, + KeyValuePartialInformationAlign64, // KEY_VALUE_PARTIAL_INFORMATION_ALIGN64 + KeyValueLayerInformation, // KEY_VALUE_LAYER_INFORMATION + MaxKeyValueInfoClass } KEY_VALUE_INFORMATION_CLASS; struct KEY_NAME_INFORMATION { - std::uint32_t NameLength; - char16_t Name[1]; + std::uint32_t NameLength; + char16_t Name[1]; }; struct KEY_HANDLE_TAGS_INFORMATION { - ULONG HandleTags; + ULONG HandleTags; }; struct KEY_VALUE_BASIC_INFORMATION { - ULONG TitleIndex; - ULONG Type; - ULONG NameLength; - char16_t Name[1]; + ULONG TitleIndex; + ULONG Type; + ULONG NameLength; + char16_t Name[1]; }; struct KEY_VALUE_PARTIAL_INFORMATION { - ULONG TitleIndex; - ULONG Type; - ULONG DataLength; - UCHAR Data[1]; + ULONG TitleIndex; + ULONG Type; + ULONG DataLength; + UCHAR Data[1]; }; struct KEY_VALUE_FULL_INFORMATION { - ULONG TitleIndex; - ULONG Type; - ULONG DataOffset; - ULONG DataLength; - ULONG NameLength; - char16_t Name[1]; + ULONG TitleIndex; + ULONG Type; + ULONG DataOffset; + ULONG DataLength; + ULONG NameLength; + char16_t Name[1]; }; diff --git a/src/common/platform/status.hpp b/src/common/platform/status.hpp index 82b7e6dc..ade2a62f 100644 --- a/src/common/platform/status.hpp +++ b/src/common/platform/status.hpp @@ -5,42 +5,41 @@ using NTSTATUS = std::uint32_t; #ifndef OS_WINDOWS -#define STATUS_WAIT_0 ((NTSTATUS)0x00000000L) -#define STATUS_TIMEOUT ((NTSTATUS)0x00000102L) +#define STATUS_WAIT_0 ((NTSTATUS)0x00000000L) +#define STATUS_TIMEOUT ((NTSTATUS)0x00000102L) -#define STATUS_ACCESS_VIOLATION ((NTSTATUS)0xC0000005L) -#define STATUS_INVALID_HANDLE ((NTSTATUS)0xC0000008L) -#define STATUS_INVALID_PARAMETER ((NTSTATUS)0xC000000DL) +#define STATUS_ACCESS_VIOLATION ((NTSTATUS)0xC0000005L) +#define STATUS_INVALID_HANDLE ((NTSTATUS)0xC0000008L) +#define STATUS_INVALID_PARAMETER ((NTSTATUS)0xC000000DL) +#define STATUS_ILLEGAL_INSTRUCTION ((NTSTATUS)0xC000001DL) -#define STATUS_PENDING ((DWORD)0x00000103L) +#define STATUS_PENDING ((NTSTATUS)0x00000103L) #endif -#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) -#define STATUS_WAIT_1 ((NTSTATUS)0x00000001L) +#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) +#define STATUS_WAIT_1 ((NTSTATUS)0x00000001L) -#define STATUS_UNSUCCESSFUL ((NTSTATUS)0x00000001L) -#define STATUS_ALERTED ((NTSTATUS)0x00000101L) +#define STATUS_UNSUCCESSFUL ((NTSTATUS)0x00000001L) +#define STATUS_ALERTED ((NTSTATUS)0x00000101L) -#define STATUS_OBJECT_NAME_EXISTS ((NTSTATUS)0x40000000L) +#define STATUS_OBJECT_NAME_EXISTS ((NTSTATUS)0x40000000L) -#define STATUS_NO_MORE_FILES ((NTSTATUS)0x80000006L) +#define STATUS_NO_MORE_FILES ((NTSTATUS)0x80000006L) -#define STATUS_ILLEGAL_INSTRUCTION ((DWORD )0xC000001DL) -#define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L) -#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L) -#define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS)0xC0000034L) -#define STATUS_NO_TOKEN ((NTSTATUS)0xC000007CL) -#define STATUS_FILE_INVALID ((NTSTATUS)0xC0000098L) -#define STATUS_MEMORY_NOT_ALLOCATED ((NTSTATUS)0xC00000A0L) -#define STATUS_FILE_IS_A_DIRECTORY ((NTSTATUS)0xC00000BAL) -#define STATUS_NOT_SUPPORTED ((NTSTATUS)0xC00000BBL) -#define STATUS_INVALID_ADDRESS ((NTSTATUS)0xC0000141L) -#define STATUS_NOT_FOUND ((NTSTATUS)0xC0000225L) -#define STATUS_CONNECTION_REFUSED ((NTSTATUS)0xC0000236L) -#define STATUS_ADDRESS_ALREADY_ASSOCIATED ((NTSTATUS)0xC0000328L) +#define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L) +#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L) +#define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS)0xC0000034L) +#define STATUS_NO_TOKEN ((NTSTATUS)0xC000007CL) +#define STATUS_FILE_INVALID ((NTSTATUS)0xC0000098L) +#define STATUS_MEMORY_NOT_ALLOCATED ((NTSTATUS)0xC00000A0L) +#define STATUS_FILE_IS_A_DIRECTORY ((NTSTATUS)0xC00000BAL) +#define STATUS_NOT_SUPPORTED ((NTSTATUS)0xC00000BBL) +#define STATUS_INVALID_ADDRESS ((NTSTATUS)0xC0000141L) +#define STATUS_NOT_FOUND ((NTSTATUS)0xC0000225L) +#define STATUS_CONNECTION_REFUSED ((NTSTATUS)0xC0000236L) +#define STATUS_ADDRESS_ALREADY_ASSOCIATED ((NTSTATUS)0xC0000328L) -#define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L) +#define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L) - -#define FILE_DEVICE_NETWORK 0x00000012 -#define FSCTL_AFD_BASE FILE_DEVICE_NETWORK +#define FILE_DEVICE_NETWORK 0x00000012 +#define FSCTL_AFD_BASE FILE_DEVICE_NETWORK diff --git a/src/common/platform/synchronisation.hpp b/src/common/platform/synchronisation.hpp index 8fc51aa8..a04037b0 100644 --- a/src/common/platform/synchronisation.hpp +++ b/src/common/platform/synchronisation.hpp @@ -2,15 +2,15 @@ typedef enum _EVENT_TYPE { - NotificationEvent, - SynchronizationEvent + NotificationEvent, + SynchronizationEvent } EVENT_TYPE; typedef enum _WAIT_TYPE { - WaitAll, - WaitAny, - WaitNotification, - WaitDequeue, - WaitDpc, + WaitAll, + WaitAny, + WaitNotification, + WaitDequeue, + WaitDpc, } WAIT_TYPE; diff --git a/src/common/platform/threading.hpp b/src/common/platform/threading.hpp index 244994df..7594e991 100644 --- a/src/common/platform/threading.hpp +++ b/src/common/platform/threading.hpp @@ -2,70 +2,69 @@ typedef enum _THREADINFOCLASS { - ThreadBasicInformation, // q: THREAD_BASIC_INFORMATION - ThreadTimes, // q: KERNEL_USER_TIMES - ThreadPriority, // s: KPRIORITY (requires SeIncreaseBasePriorityPrivilege) - ThreadBasePriority, // s: KPRIORITY - ThreadAffinityMask, // s: KAFFINITY - ThreadImpersonationToken, // s: HANDLE - ThreadDescriptorTableEntry, // q: DESCRIPTOR_TABLE_ENTRY (or WOW64_DESCRIPTOR_TABLE_ENTRY) + ThreadBasicInformation, // q: THREAD_BASIC_INFORMATION + ThreadTimes, // q: KERNEL_USER_TIMES + ThreadPriority, // s: KPRIORITY (requires SeIncreaseBasePriorityPrivilege) + ThreadBasePriority, // s: KPRIORITY + ThreadAffinityMask, // s: KAFFINITY + ThreadImpersonationToken, // s: HANDLE + ThreadDescriptorTableEntry, // q: DESCRIPTOR_TABLE_ENTRY (or WOW64_DESCRIPTOR_TABLE_ENTRY) ThreadEnableAlignmentFaultFixup, // s: BOOLEAN ThreadEventPair, ThreadQuerySetWin32StartAddress, // q: ULONG_PTR - ThreadZeroTlsCell, // s: ULONG // TlsIndex // 10 - ThreadPerformanceCount, // q: LARGE_INTEGER - ThreadAmILastThread, // q: ULONG - ThreadIdealProcessor, // s: ULONG - ThreadPriorityBoost, // qs: ULONG - ThreadSetTlsArrayAddress, // s: ULONG_PTR // Obsolete - ThreadIsIoPending, // q: ULONG - ThreadHideFromDebugger, // q: BOOLEAN; s: void - ThreadBreakOnTermination, // qs: ULONG - ThreadSwitchLegacyState, // s: void // NtCurrentThread // NPX/FPU - ThreadIsTerminated, // q: ULONG // 20 - ThreadLastSystemCall, // q: THREAD_LAST_SYSCALL_INFORMATION - ThreadIoPriority, // qs: IO_PRIORITY_HINT (requires SeIncreaseBasePriorityPrivilege) - ThreadCycleTime, // q: THREAD_CYCLE_TIME_INFORMATION - ThreadPagePriority, // qs: PAGE_PRIORITY_INFORMATION - ThreadActualBasePriority, // s: LONG (requires SeIncreaseBasePriorityPrivilege) - ThreadTebInformation, // q: THREAD_TEB_INFORMATION (requires THREAD_GET_CONTEXT + THREAD_SET_CONTEXT) - ThreadCSwitchMon, // Obsolete + ThreadZeroTlsCell, // s: ULONG // TlsIndex // 10 + ThreadPerformanceCount, // q: LARGE_INTEGER + ThreadAmILastThread, // q: ULONG + ThreadIdealProcessor, // s: ULONG + ThreadPriorityBoost, // qs: ULONG + ThreadSetTlsArrayAddress, // s: ULONG_PTR // Obsolete + ThreadIsIoPending, // q: ULONG + ThreadHideFromDebugger, // q: BOOLEAN; s: void + ThreadBreakOnTermination, // qs: ULONG + ThreadSwitchLegacyState, // s: void // NtCurrentThread // NPX/FPU + ThreadIsTerminated, // q: ULONG // 20 + ThreadLastSystemCall, // q: THREAD_LAST_SYSCALL_INFORMATION + ThreadIoPriority, // qs: IO_PRIORITY_HINT (requires SeIncreaseBasePriorityPrivilege) + ThreadCycleTime, // q: THREAD_CYCLE_TIME_INFORMATION + ThreadPagePriority, // qs: PAGE_PRIORITY_INFORMATION + ThreadActualBasePriority, // s: LONG (requires SeIncreaseBasePriorityPrivilege) + ThreadTebInformation, // q: THREAD_TEB_INFORMATION (requires THREAD_GET_CONTEXT + THREAD_SET_CONTEXT) + ThreadCSwitchMon, // Obsolete ThreadCSwitchPmu, - ThreadWow64Context, // qs: WOW64_CONTEXT, ARM_NT_CONTEXT since 20H1 - ThreadGroupInformation, // qs: GROUP_AFFINITY // 30 - ThreadUmsInformation, // q: THREAD_UMS_INFORMATION // Obsolete - ThreadCounterProfiling, // q: BOOLEAN; s: THREAD_PROFILING_INFORMATION? - ThreadIdealProcessorEx, // qs: PROCESSOR_NUMBER; s: previous PROCESSOR_NUMBER on return + ThreadWow64Context, // qs: WOW64_CONTEXT, ARM_NT_CONTEXT since 20H1 + ThreadGroupInformation, // qs: GROUP_AFFINITY // 30 + ThreadUmsInformation, // q: THREAD_UMS_INFORMATION // Obsolete + ThreadCounterProfiling, // q: BOOLEAN; s: THREAD_PROFILING_INFORMATION? + ThreadIdealProcessorEx, // qs: PROCESSOR_NUMBER; s: previous PROCESSOR_NUMBER on return ThreadCpuAccountingInformation, // q: BOOLEAN; s: HANDLE (NtOpenSession) // NtCurrentThread // since WIN8 - ThreadSuspendCount, // q: ULONG // since WINBLUE - ThreadHeterogeneousCpuPolicy, // q: KHETERO_CPU_POLICY // since THRESHOLD - ThreadContainerId, // q: GUID - ThreadNameInformation, // qs: THREAD_NAME_INFORMATION + ThreadSuspendCount, // q: ULONG // since WINBLUE + ThreadHeterogeneousCpuPolicy, // q: KHETERO_CPU_POLICY // since THRESHOLD + ThreadContainerId, // q: GUID + ThreadNameInformation, // qs: THREAD_NAME_INFORMATION ThreadSelectedCpuSets, - ThreadSystemThreadInformation, // q: SYSTEM_THREAD_INFORMATION // 40 - ThreadActualGroupAffinity, // q: GROUP_AFFINITY // since THRESHOLD2 - ThreadDynamicCodePolicyInfo, // q: ULONG; s: ULONG (NtCurrentThread) - ThreadExplicitCaseSensitivity, // qs: ULONG; s: 0 disables, otherwise enables - ThreadWorkOnBehalfTicket, // RTL_WORK_ON_BEHALF_TICKET_EX - ThreadSubsystemInformation, // q: SUBSYSTEM_INFORMATION_TYPE // since REDSTONE2 - ThreadDbgkWerReportActive, // s: ULONG; s: 0 disables, otherwise enables - ThreadAttachContainer, // s: HANDLE (job object) // NtCurrentThread + ThreadSystemThreadInformation, // q: SYSTEM_THREAD_INFORMATION // 40 + ThreadActualGroupAffinity, // q: GROUP_AFFINITY // since THRESHOLD2 + ThreadDynamicCodePolicyInfo, // q: ULONG; s: ULONG (NtCurrentThread) + ThreadExplicitCaseSensitivity, // qs: ULONG; s: 0 disables, otherwise enables + ThreadWorkOnBehalfTicket, // RTL_WORK_ON_BEHALF_TICKET_EX + ThreadSubsystemInformation, // q: SUBSYSTEM_INFORMATION_TYPE // since REDSTONE2 + ThreadDbgkWerReportActive, // s: ULONG; s: 0 disables, otherwise enables + ThreadAttachContainer, // s: HANDLE (job object) // NtCurrentThread ThreadManageWritesToExecutableMemory, // MANAGE_WRITES_TO_EXECUTABLE_MEMORY // since REDSTONE3 - ThreadPowerThrottlingState, // POWER_THROTTLING_THREAD_STATE // since REDSTONE3 (set), WIN11 22H2 (query) - ThreadWorkloadClass, // THREAD_WORKLOAD_CLASS // since REDSTONE5 // 50 - ThreadCreateStateChange, // since WIN11 + ThreadPowerThrottlingState, // POWER_THROTTLING_THREAD_STATE // since REDSTONE3 (set), WIN11 22H2 (query) + ThreadWorkloadClass, // THREAD_WORKLOAD_CLASS // since REDSTONE5 // 50 + ThreadCreateStateChange, // since WIN11 ThreadApplyStateChange, ThreadStrongerBadHandleChecks, // since 22H1 - ThreadEffectiveIoPriority, // q: IO_PRIORITY_HINT - ThreadEffectivePagePriority, // q: ULONG - ThreadUpdateLockOwnership, // since 24H2 + ThreadEffectiveIoPriority, // q: IO_PRIORITY_HINT + ThreadEffectivePagePriority, // q: ULONG + ThreadUpdateLockOwnership, // since 24H2 ThreadSchedulerSharedDataSlot, // SCHEDULER_SHARED_DATA_SLOT_INFORMATION - ThreadTebInformationAtomic, // THREAD_TEB_INFORMATION - ThreadIndexInformation, // THREAD_INDEX_INFORMATION + ThreadTebInformationAtomic, // THREAD_TEB_INFORMATION + ThreadIndexInformation, // THREAD_INDEX_INFORMATION MaxThreadInfoClass } THREADINFOCLASS; - template struct THREAD_NAME_INFORMATION { @@ -80,4 +79,4 @@ typedef struct _THREAD_BASIC_INFORMATION64 EMULATOR_CAST(std::uint64_t, KAFFINITY) AffinityMask; EMULATOR_CAST(std::uint32_t, KPRIORITY) Priority; EMULATOR_CAST(std::uint32_t, KPRIORITY) BasePriority; -} THREAD_BASIC_INFORMATION64, *PTHREAD_BASIC_INFORMATION64; \ No newline at end of file +} THREAD_BASIC_INFORMATION64, *PTHREAD_BASIC_INFORMATION64; diff --git a/src/common/platform/traits.hpp b/src/common/platform/traits.hpp index 758e641a..106d53b8 100644 --- a/src/common/platform/traits.hpp +++ b/src/common/platform/traits.hpp @@ -19,19 +19,19 @@ struct EmulatorTraits; template <> struct EmulatorTraits { - using PVOID = std::uint32_t; - using ULONG_PTR = std::uint32_t; - using SIZE_T = std::uint32_t; - using UNICODE = char16_t; - using HANDLE = std::uint32_t; + using PVOID = std::uint32_t; + using ULONG_PTR = std::uint32_t; + using SIZE_T = std::uint32_t; + using UNICODE = char16_t; + using HANDLE = std::uint32_t; }; template <> struct EmulatorTraits { - using PVOID = std::uint64_t; - using ULONG_PTR = std::uint64_t; - using SIZE_T = std::uint64_t; - using UNICODE = char16_t; - using HANDLE = std::uint64_t; + using PVOID = std::uint64_t; + using ULONG_PTR = std::uint64_t; + using SIZE_T = std::uint64_t; + using UNICODE = char16_t; + using HANDLE = std::uint64_t; }; diff --git a/src/common/platform/unicode.hpp b/src/common/platform/unicode.hpp index 644d9c43..d506ab6c 100644 --- a/src/common/platform/unicode.hpp +++ b/src/common/platform/unicode.hpp @@ -5,76 +5,76 @@ template struct UNICODE_STRING { - USHORT Length; - USHORT MaximumLength; - EMULATOR_CAST(typename Traits::PVOID, char16_t*) Buffer; + USHORT Length; + USHORT MaximumLength; + EMULATOR_CAST(typename Traits::PVOID, char16_t*) Buffer; }; inline std::string u16_to_u8(const std::u16string_view u16_view) { - std::string utf8_str; - utf8_str.reserve(u16_view.size() * 2); - for (const char16_t ch : u16_view) - { - if (ch <= 0x7F) - { - utf8_str.push_back(static_cast(ch)); - } - else if (ch <= 0x7FF) - { - utf8_str.push_back(static_cast(0xC0 | (ch >> 6))); - utf8_str.push_back(static_cast(0x80 | (ch & 0x3F))); - } - else - { - utf8_str.push_back(static_cast(0xE0 | (ch >> 12))); - utf8_str.push_back(static_cast(0x80 | ((ch >> 6) & 0x3F))); - utf8_str.push_back(static_cast(0x80 | (ch & 0x3F))); - } - } - return utf8_str; + std::string utf8_str; + utf8_str.reserve(u16_view.size() * 2); + for (const char16_t ch : u16_view) + { + if (ch <= 0x7F) + { + utf8_str.push_back(static_cast(ch)); + } + else if (ch <= 0x7FF) + { + utf8_str.push_back(static_cast(0xC0 | (ch >> 6))); + utf8_str.push_back(static_cast(0x80 | (ch & 0x3F))); + } + else + { + utf8_str.push_back(static_cast(0xE0 | (ch >> 12))); + utf8_str.push_back(static_cast(0x80 | ((ch >> 6) & 0x3F))); + utf8_str.push_back(static_cast(0x80 | (ch & 0x3F))); + } + } + return utf8_str; } inline std::string w_to_u8(const std::wstring_view w_view) { - std::string utf8_str; - utf8_str.reserve(w_view.size() * 2); - for (const wchar_t w_ch : w_view) - { - const auto ch = static_cast(w_ch); - if (ch <= 0x7F) - { - utf8_str.push_back(static_cast(ch)); - } - else if (ch <= 0x7FF) - { - utf8_str.push_back(static_cast(0xC0 | (ch >> 6))); - utf8_str.push_back(static_cast(0x80 | (ch & 0x3F))); - } - else - { - utf8_str.push_back(static_cast(0xE0 | (ch >> 12))); - utf8_str.push_back(static_cast(0x80 | ((ch >> 6) & 0x3F))); - utf8_str.push_back(static_cast(0x80 | (ch & 0x3F))); - } - } - return utf8_str; + std::string utf8_str; + utf8_str.reserve(w_view.size() * 2); + for (const wchar_t w_ch : w_view) + { + const auto ch = static_cast(w_ch); + if (ch <= 0x7F) + { + utf8_str.push_back(static_cast(ch)); + } + else if (ch <= 0x7FF) + { + utf8_str.push_back(static_cast(0xC0 | (ch >> 6))); + utf8_str.push_back(static_cast(0x80 | (ch & 0x3F))); + } + else + { + utf8_str.push_back(static_cast(0xE0 | (ch >> 12))); + utf8_str.push_back(static_cast(0x80 | ((ch >> 6) & 0x3F))); + utf8_str.push_back(static_cast(0x80 | (ch & 0x3F))); + } + } + return utf8_str; } #ifndef OS_WINDOWS inline int open_unicode(FILE** handle, const std::u16string& fileName, const std::u16string& mode) { - *handle = fopen(u16_to_u8(fileName).c_str(), u16_to_u8(mode).c_str()); - return errno; + *handle = fopen(u16_to_u8(fileName).c_str(), u16_to_u8(mode).c_str()); + return errno; } #else inline std::wstring u16_to_w(const std::u16string& u16str) { - return std::wstring(reinterpret_cast(u16str.data()), u16str.size()); + return std::wstring(reinterpret_cast(u16str.data()), u16str.size()); } inline auto open_unicode(FILE** handle, const std::u16string& fileName, const std::u16string& mode) { - return _wfopen_s(handle, u16_to_w(fileName).c_str(), u16_to_w(mode).c_str()); + return _wfopen_s(handle, u16_to_w(fileName).c_str(), u16_to_w(mode).c_str()); } #endif diff --git a/src/common/platform/win_pefile.hpp b/src/common/platform/win_pefile.hpp index 41ca0e61..20c1327a 100644 --- a/src/common/platform/win_pefile.hpp +++ b/src/common/platform/win_pefile.hpp @@ -2,96 +2,95 @@ #include -#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory -#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory -#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory -#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory -#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory -#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table -#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory +#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory +#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory +#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory +#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory +#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table +#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory // IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // (X86 usage) -#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data -#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP -#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory -#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory -#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers -#define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table -#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors -#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor +#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data +#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP +#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory +#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory +#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers +#define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table +#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors +#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor -#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 // Section contains extended relocations. -#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 // Section can be discarded. -#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 // Section is not cachable. -#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 // Section is not pageable. -#define IMAGE_SCN_MEM_SHARED 0x10000000 // Section is shareable. -#define IMAGE_SCN_MEM_EXECUTE 0x20000000 // Section is executable. -#define IMAGE_SCN_MEM_READ 0x40000000 // Section is readable. -#define IMAGE_SCN_MEM_WRITE 0x80000000 // Section is writeable. +#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 // Section contains extended relocations. +#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 // Section can be discarded. +#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 // Section is not cachable. +#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 // Section is not pageable. +#define IMAGE_SCN_MEM_SHARED 0x10000000 // Section is shareable. +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 // Section is executable. +#define IMAGE_SCN_MEM_READ 0x40000000 // Section is readable. +#define IMAGE_SCN_MEM_WRITE 0x80000000 // Section is writeable. -#define IMAGE_SCN_CNT_CODE 0x00000020 // Section contains code. -#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 // Section contains initialized data. -#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 // Section contains uninitialized data. +#define IMAGE_SCN_CNT_CODE 0x00000020 // Section contains code. +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 // Section contains initialized data. +#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 // Section contains uninitialized data. -#define IMAGE_REL_BASED_ABSOLUTE 0 -#define IMAGE_REL_BASED_HIGH 1 -#define IMAGE_REL_BASED_LOW 2 -#define IMAGE_REL_BASED_HIGHLOW 3 -#define IMAGE_REL_BASED_HIGHADJ 4 -#define IMAGE_REL_BASED_MIPS_JMPADDR 5 -#define IMAGE_REL_BASED_ARM_MOV32A 5 -#define IMAGE_REL_BASED_ARM_MOV32 5 -#define IMAGE_REL_BASED_SECTION 6 -#define IMAGE_REL_BASED_REL 7 -#define IMAGE_REL_BASED_ARM_MOV32T 7 -#define IMAGE_REL_BASED_THUMB_MOV32 7 -#define IMAGE_REL_BASED_MIPS_JMPADDR16 9 -#define IMAGE_REL_BASED_IA64_IMM64 9 -#define IMAGE_REL_BASED_DIR64 10 -#define IMAGE_REL_BASED_HIGH3ADJ 11 +#define IMAGE_REL_BASED_ABSOLUTE 0 +#define IMAGE_REL_BASED_HIGH 1 +#define IMAGE_REL_BASED_LOW 2 +#define IMAGE_REL_BASED_HIGHLOW 3 +#define IMAGE_REL_BASED_HIGHADJ 4 +#define IMAGE_REL_BASED_MIPS_JMPADDR 5 +#define IMAGE_REL_BASED_ARM_MOV32A 5 +#define IMAGE_REL_BASED_ARM_MOV32 5 +#define IMAGE_REL_BASED_SECTION 6 +#define IMAGE_REL_BASED_REL 7 +#define IMAGE_REL_BASED_ARM_MOV32T 7 +#define IMAGE_REL_BASED_THUMB_MOV32 7 +#define IMAGE_REL_BASED_MIPS_JMPADDR16 9 +#define IMAGE_REL_BASED_IA64_IMM64 9 +#define IMAGE_REL_BASED_DIR64 10 +#define IMAGE_REL_BASED_HIGH3ADJ 11 -#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040 -#define IMAGE_FILE_DLL 0x2000 +#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040 +#define IMAGE_FILE_DLL 0x2000 -#define IMAGE_FILE_MACHINE_I386 0x014c -#define IMAGE_FILE_MACHINE_AMD64 0x8664 +#define IMAGE_FILE_MACHINE_I386 0x014c +#define IMAGE_FILE_MACHINE_AMD64 0x8664 -#define PROCESSOR_ARCHITECTURE_AMD64 9 +#define PROCESSOR_ARCHITECTURE_AMD64 9 enum class PEMachineType : std::uint16_t { - UNKNOWN = 0, - I386 = 0x014c, // Intel 386. - R3000 = 0x0162, // MIPS little-endian, 0x160 big-endian - R4000 = 0x0166, // MIPS little-endian - R10000 = 0x0168, // MIPS little-endian - WCEMIPSV2 = 0x0169, // MIPS little-endian WCE v2 - ALPHA = 0x0184, // Alpha_AXP - SH3 = 0x01a2, // SH3 little-endian - SH3DSP = 0x01a3, - SH3E = 0x01a4, // SH3E little-endian - SH4 = 0x01a6, // SH4 little-endian - SH5 = 0x01a8, // SH5 - ARM = 0x01c0, // ARM Little-Endian - THUMB = 0x01c2, // ARM Thumb/Thumb-2 Little-Endian - ARMNT = 0x01c4, // ARM Thumb-2 Little-Endian - AM33 = 0x01d3, - POWERPC = 0x01F0, // IBM PowerPC Little-Endian - POWERPCFP = 0x01f1, - IA64 = 0x0200, // Intel 64 - MIPS16 = 0x0266, // MIPS - ALPHA64 = 0x0284, // ALPHA64 - MIPSFPU = 0x0366, // MIPS - MIPSFPU16 = 0x0466, // MIPS - AXP64 = ALPHA64, - TRICORE = 0x0520, // Infineon - CEF = 0x0CEF, - EBC = 0x0EBC, // EFI Byte Code - AMD64 = 0x8664, // AMD64 (K8) - M32R = 0x9041, // M32R little-endian - CEE = 0xC0EE, + UNKNOWN = 0, + I386 = 0x014c, // Intel 386. + R3000 = 0x0162, // MIPS little-endian, 0x160 big-endian + R4000 = 0x0166, // MIPS little-endian + R10000 = 0x0168, // MIPS little-endian + WCEMIPSV2 = 0x0169, // MIPS little-endian WCE v2 + ALPHA = 0x0184, // Alpha_AXP + SH3 = 0x01a2, // SH3 little-endian + SH3DSP = 0x01a3, + SH3E = 0x01a4, // SH3E little-endian + SH4 = 0x01a6, // SH4 little-endian + SH5 = 0x01a8, // SH5 + ARM = 0x01c0, // ARM Little-Endian + THUMB = 0x01c2, // ARM Thumb/Thumb-2 Little-Endian + ARMNT = 0x01c4, // ARM Thumb-2 Little-Endian + AM33 = 0x01d3, + POWERPC = 0x01F0, // IBM PowerPC Little-Endian + POWERPCFP = 0x01f1, + IA64 = 0x0200, // Intel 64 + MIPS16 = 0x0266, // MIPS + ALPHA64 = 0x0284, // ALPHA64 + MIPSFPU = 0x0366, // MIPS + MIPSFPU16 = 0x0466, // MIPS + AXP64 = ALPHA64, + TRICORE = 0x0520, // Infineon + CEF = 0x0CEF, + EBC = 0x0EBC, // EFI Byte Code + AMD64 = 0x8664, // AMD64 (K8) + M32R = 0x9041, // M32R little-endian + CEE = 0xC0EE, }; - #pragma pack(push, 4) template @@ -102,65 +101,64 @@ struct PEOptionalHeaderBasePart2_t template <> struct PEOptionalHeaderBasePart2_t { - std::uint32_t BaseOfData; - std::uint32_t ImageBase; + std::uint32_t BaseOfData; + std::uint32_t ImageBase; }; template <> struct PEOptionalHeaderBasePart2_t { - std::uint64_t ImageBase; + std::uint64_t ImageBase; }; template struct PEOptionalHeaderBasePart1_t { - enum - { - k_NumberOfDataDirectors = 16 - }; + enum + { + k_NumberOfDataDirectors = 16 + }; - uint16_t Magic; - uint8_t MajorLinkerVersion; - uint8_t MinorLinkerVersion; - uint32_t SizeOfCode; - uint32_t SizeOfInitializedData; - uint32_t SizeOfUninitializedData; - uint32_t AddressOfEntryPoint; - uint32_t BaseOfCode; + uint16_t Magic; + uint8_t MajorLinkerVersion; + uint8_t MinorLinkerVersion; + uint32_t SizeOfCode; + uint32_t SizeOfInitializedData; + uint32_t SizeOfUninitializedData; + uint32_t AddressOfEntryPoint; + uint32_t BaseOfCode; }; - struct PEDirectory_t2 { - std::uint32_t VirtualAddress; - std::uint32_t Size; + std::uint32_t VirtualAddress; + std::uint32_t Size; }; template struct PEOptionalHeaderBasePart3_t : PEOptionalHeaderBasePart1_t, PEOptionalHeaderBasePart2_t { - uint32_t SectionAlignment; - uint32_t FileAlignment; - uint16_t MajorOperatingSystemVersion; - uint16_t MinorOperatingSystemVersion; - uint16_t MajorImageVersion; - uint16_t MinorImageVersion; - uint16_t MajorSubsystemVersion; - uint16_t MinorSubsystemVersion; - uint32_t Win32VersionValue; - uint32_t SizeOfImage; - uint32_t SizeOfHeaders; - uint32_t CheckSum; - uint16_t Subsystem; - uint16_t DllCharacteristics; - T SizeOfStackReserve; - T SizeOfStackCommit; - T SizeOfHeapReserve; - T SizeOfHeapCommit; - uint32_t LoaderFlags; - uint32_t NumberOfRvaAndSizes; - PEDirectory_t2 DataDirectory[PEOptionalHeaderBasePart1_t::k_NumberOfDataDirectors]; + uint32_t SectionAlignment; + uint32_t FileAlignment; + uint16_t MajorOperatingSystemVersion; + uint16_t MinorOperatingSystemVersion; + uint16_t MajorImageVersion; + uint16_t MinorImageVersion; + uint16_t MajorSubsystemVersion; + uint16_t MinorSubsystemVersion; + uint32_t Win32VersionValue; + uint32_t SizeOfImage; + uint32_t SizeOfHeaders; + uint32_t CheckSum; + uint16_t Subsystem; + uint16_t DllCharacteristics; + T SizeOfStackReserve; + T SizeOfStackCommit; + T SizeOfHeapReserve; + T SizeOfHeapCommit; + uint32_t LoaderFlags; + uint32_t NumberOfRvaAndSizes; + PEDirectory_t2 DataDirectory[PEOptionalHeaderBasePart1_t::k_NumberOfDataDirectors]; }; template @@ -171,113 +169,116 @@ struct PEOptionalHeader_t template <> struct PEOptionalHeader_t : PEOptionalHeaderBasePart3_t { - enum - { - k_Magic = 0x10b, // IMAGE_NT_OPTIONAL_HDR32_MAGIC - }; + enum + { + k_Magic = 0x10b, // IMAGE_NT_OPTIONAL_HDR32_MAGIC + }; }; template <> struct PEOptionalHeader_t : PEOptionalHeaderBasePart3_t { - enum - { - k_Magic = 0x20b, // IMAGE_NT_OPTIONAL_HDR64_MAGIC - }; + enum + { + k_Magic = 0x20b, // IMAGE_NT_OPTIONAL_HDR64_MAGIC + }; }; struct PEFileHeader_t { - PEMachineType Machine; - std::uint16_t NumberOfSections; - std::uint32_t TimeDateStamp; - std::uint32_t PointerToSymbolTable; - std::uint32_t NumberOfSymbols; - std::uint16_t SizeOfOptionalHeader; - std::uint16_t Characteristics; + PEMachineType Machine; + std::uint16_t NumberOfSections; + std::uint32_t TimeDateStamp; + std::uint32_t PointerToSymbolTable; + std::uint32_t NumberOfSymbols; + std::uint16_t SizeOfOptionalHeader; + std::uint16_t Characteristics; }; template struct PENTHeaders_t { - enum - { - k_Signature = 0x00004550, // IMAGE_NT_SIGNATURE - }; + enum + { + k_Signature = 0x00004550, // IMAGE_NT_SIGNATURE + }; - uint32_t Signature; - PEFileHeader_t FileHeader; - PEOptionalHeader_t OptionalHeader; + uint32_t Signature; + PEFileHeader_t FileHeader; + PEOptionalHeader_t OptionalHeader; }; struct PEDosHeader_t { - enum - { - k_Magic = 0x5A4D - }; + enum + { + k_Magic = 0x5A4D + }; - std::uint16_t e_magic; // Magic number ( k_Magic ) - std::uint16_t e_cblp; // Bytes on last page of file - std::uint16_t e_cp; // Pages in file - std::uint16_t e_crlc; // Relocations - std::uint16_t e_cparhdr; // Size of header in paragraphs - std::uint16_t e_minalloc; // Minimum extra paragraphs needed - std::uint16_t e_maxalloc; // Maximum extra paragraphs needed - std::uint16_t e_ss; // Initial (relative) SS value - std::uint16_t e_sp; // Initial SP value - std::uint16_t e_csum; // Checksum - std::uint16_t e_ip; // Initial IP value - std::uint16_t e_cs; // Initial (relative) CS value - std::uint16_t e_lfarlc; // File address of relocation table - std::uint16_t e_ovno; // Overlay number - std::uint16_t e_res[4]; // Reserved words - std::uint16_t e_oemid; // OEM identifier (for e_oeminfo) - std::uint16_t e_oeminfo; // OEM information; e_oemid specific - std::uint16_t e_res2[10]; // Reserved words - std::uint32_t e_lfanew; // File address of new exe header + std::uint16_t e_magic; // Magic number ( k_Magic ) + std::uint16_t e_cblp; // Bytes on last page of file + std::uint16_t e_cp; // Pages in file + std::uint16_t e_crlc; // Relocations + std::uint16_t e_cparhdr; // Size of header in paragraphs + std::uint16_t e_minalloc; // Minimum extra paragraphs needed + std::uint16_t e_maxalloc; // Maximum extra paragraphs needed + std::uint16_t e_ss; // Initial (relative) SS value + std::uint16_t e_sp; // Initial SP value + std::uint16_t e_csum; // Checksum + std::uint16_t e_ip; // Initial IP value + std::uint16_t e_cs; // Initial (relative) CS value + std::uint16_t e_lfarlc; // File address of relocation table + std::uint16_t e_ovno; // Overlay number + std::uint16_t e_res[4]; // Reserved words + std::uint16_t e_oemid; // OEM identifier (for e_oeminfo) + std::uint16_t e_oeminfo; // OEM information; e_oemid specific + std::uint16_t e_res2[10]; // Reserved words + std::uint32_t e_lfanew; // File address of new exe header }; #pragma pack(pop) -#define IMAGE_SIZEOF_SHORT_NAME 8 +#define IMAGE_SIZEOF_SHORT_NAME 8 #ifndef OS_WINDOWS typedef struct _IMAGE_SECTION_HEADER { - std::uint8_t Name[IMAGE_SIZEOF_SHORT_NAME]; - union { - std:: uint32_t PhysicalAddress; - std::uint32_t VirtualSize; + std::uint8_t Name[IMAGE_SIZEOF_SHORT_NAME]; + union + { + std::uint32_t PhysicalAddress; + std::uint32_t VirtualSize; } Misc; - std::uint32_t VirtualAddress; - std::uint32_t SizeOfRawData; - std::uint32_t PointerToRawData; - std::uint32_t PointerToRelocations; - std::uint32_t PointerToLinenumbers; - std::uint16_t NumberOfRelocations; - std::uint16_t NumberOfLinenumbers; - std::uint32_t Characteristics; + std::uint32_t VirtualAddress; + std::uint32_t SizeOfRawData; + std::uint32_t PointerToRawData; + std::uint32_t PointerToRelocations; + std::uint32_t PointerToLinenumbers; + std::uint16_t NumberOfRelocations; + std::uint16_t NumberOfLinenumbers; + std::uint32_t Characteristics; } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; -typedef struct _IMAGE_EXPORT_DIRECTORY { - DWORD Characteristics; - DWORD TimeDateStamp; - WORD MajorVersion; - WORD MinorVersion; - DWORD Name; - DWORD Base; - DWORD NumberOfFunctions; - DWORD NumberOfNames; - DWORD AddressOfFunctions; - DWORD AddressOfNames; - DWORD AddressOfNameOrdinals; +typedef struct _IMAGE_EXPORT_DIRECTORY +{ + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD Name; + DWORD Base; + DWORD NumberOfFunctions; + DWORD NumberOfNames; + DWORD AddressOfFunctions; + DWORD AddressOfNames; + DWORD AddressOfNameOrdinals; } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; -typedef struct _IMAGE_BASE_RELOCATION { - DWORD VirtualAddress; - DWORD SizeOfBlock; - WORD TypeOffset[1]; +typedef struct _IMAGE_BASE_RELOCATION +{ + DWORD VirtualAddress; + DWORD SizeOfBlock; + WORD TypeOffset[1]; } IMAGE_BASE_RELOCATION, *PIMAGE_BASE_RELOCATION; #endif @@ -285,56 +286,56 @@ typedef struct _IMAGE_BASE_RELOCATION { template struct SECTION_IMAGE_INFORMATION { - typename Traits::PVOID TransferAddress; - ULONG ZeroBits; - typename Traits::SIZE_T MaximumStackSize; - typename Traits::SIZE_T CommittedStackSize; - ULONG SubSystemType; + typename Traits::PVOID TransferAddress; + ULONG ZeroBits; + typename Traits::SIZE_T MaximumStackSize; + typename Traits::SIZE_T CommittedStackSize; + ULONG SubSystemType; - union - { - struct - { - USHORT SubSystemMinorVersion; - USHORT SubSystemMajorVersion; - }; + union + { + struct + { + USHORT SubSystemMinorVersion; + USHORT SubSystemMajorVersion; + }; - ULONG SubSystemVersion; - }; + ULONG SubSystemVersion; + }; - union - { - struct - { - USHORT MajorOperatingSystemVersion; - USHORT MinorOperatingSystemVersion; - }; + union + { + struct + { + USHORT MajorOperatingSystemVersion; + USHORT MinorOperatingSystemVersion; + }; - ULONG OperatingSystemVersion; - }; + ULONG OperatingSystemVersion; + }; - USHORT ImageCharacteristics; - USHORT DllCharacteristics; - PEMachineType Machine; - BOOLEAN ImageContainsCode; + USHORT ImageCharacteristics; + USHORT DllCharacteristics; + PEMachineType Machine; + BOOLEAN ImageContainsCode; - union - { - UCHAR ImageFlags; + union + { + UCHAR ImageFlags; - struct - { - UCHAR ComPlusNativeReady : 1; - UCHAR ComPlusILOnly : 1; - UCHAR ImageDynamicallyRelocated : 1; - UCHAR ImageMappedFlat : 1; - UCHAR BaseBelow4gb : 1; - UCHAR ComPlusPrefer32bit : 1; - UCHAR Reserved : 2; - }; - }; + struct + { + UCHAR ComPlusNativeReady : 1; + UCHAR ComPlusILOnly : 1; + UCHAR ImageDynamicallyRelocated : 1; + UCHAR ImageMappedFlat : 1; + UCHAR BaseBelow4gb : 1; + UCHAR ComPlusPrefer32bit : 1; + UCHAR Reserved : 2; + }; + }; - ULONG LoaderFlags; - ULONG ImageFileSize; - ULONG CheckSum; + ULONG LoaderFlags; + ULONG ImageFileSize; + ULONG CheckSum; }; diff --git a/src/common/utils/buffer_accessor.hpp b/src/common/utils/buffer_accessor.hpp index c61888c9..67646c29 100644 --- a/src/common/utils/buffer_accessor.hpp +++ b/src/common/utils/buffer_accessor.hpp @@ -5,114 +5,114 @@ namespace utils { - template - requires(std::is_trivially_copyable_v && std::is_same_v>) - class safe_object_accessor - { - public: - safe_object_accessor(const std::span buffer, const size_t offset) - : buffer_(buffer) - , offset_(offset) - { - } + template + requires(std::is_trivially_copyable_v && std::is_same_v>) + class safe_object_accessor + { + public: + safe_object_accessor(const std::span buffer, const size_t offset) + : buffer_(buffer), + offset_(offset) + { + } - /***************************************************************************** - * Object is copied to make sure platform-dependent alignment requirements - * are respected - ****************************************************************************/ + /***************************************************************************** + * Object is copied to make sure platform-dependent alignment requirements + * are respected + ****************************************************************************/ - T get(const size_t element_index = 0) const - { - T value{}; - memcpy(&value, get_valid_pointer(element_index), size); - return value; - } + T get(const size_t element_index = 0) const + { + T value{}; + memcpy(&value, get_valid_pointer(element_index), size); + return value; + } - void set(const T value, const size_t element_index = 0) const - { - memcpy(get_valid_pointer(element_index), &value, size); - } + void set(const T value, const size_t element_index = 0) const + { + memcpy(get_valid_pointer(element_index), &value, size); + } - private: - static constexpr auto size = sizeof(T); + private: + static constexpr auto size = sizeof(T); - std::span buffer_{}; - size_t offset_{}; + std::span buffer_{}; + size_t offset_{}; - S* get_valid_pointer(const size_t element_index) const - { - const auto start_offset = offset_ + (size * element_index); - const auto end_offset = start_offset + size; - if (end_offset > buffer_.size()) - { - throw std::runtime_error("Buffer accessor overflow"); - } + S* get_valid_pointer(const size_t element_index) const + { + const auto start_offset = offset_ + (size * element_index); + const auto end_offset = start_offset + size; + if (end_offset > buffer_.size()) + { + throw std::runtime_error("Buffer accessor overflow"); + } - return buffer_.data() + start_offset; - } - }; + return buffer_.data() + start_offset; + } + }; - template - requires(std::is_same_v>) - class safe_buffer_accessor - { - public: - safe_buffer_accessor(const std::span buffer) - : buffer_(buffer) - { - } + template + requires(std::is_same_v>) + class safe_buffer_accessor + { + public: + safe_buffer_accessor(const std::span buffer) + : buffer_(buffer) + { + } - template - safe_buffer_accessor(const safe_buffer_accessor& obj) - : buffer_(obj.get_buffer()) - { - } + template + safe_buffer_accessor(const safe_buffer_accessor& obj) + : buffer_(obj.get_buffer()) + { + } - template - safe_object_accessor as(const size_t offset) const - { - return {this->buffer_, offset}; - } + template + safe_object_accessor as(const size_t offset) const + { + return {this->buffer_, offset}; + } - T* get_pointer_for_range(const size_t offset, const size_t size) const - { - this->validate(offset, size); - return this->buffer_.data() + offset; - } + T* get_pointer_for_range(const size_t offset, const size_t size) const + { + this->validate(offset, size); + return this->buffer_.data() + offset; + } - void validate(const size_t offset, const size_t size) const - { - const auto end = offset + size; - if (end > buffer_.size()) - { - throw std::runtime_error("Buffer accessor overflow"); - } - } + void validate(const size_t offset, const size_t size) const + { + const auto end = offset + size; + if (end > buffer_.size()) + { + throw std::runtime_error("Buffer accessor overflow"); + } + } - template - std::basic_string as_string(const size_t offset) const - { - safe_object_accessor string_accessor{this->buffer_, offset}; - std::basic_string result{}; + template + std::basic_string as_string(const size_t offset) const + { + safe_object_accessor string_accessor{this->buffer_, offset}; + std::basic_string result{}; - while (true) - { - auto value = string_accessor.get(result.size()); - if (!value) - { - return result; - } + while (true) + { + auto value = string_accessor.get(result.size()); + if (!value) + { + return result; + } - result.push_back(std::move(value)); - } - } + result.push_back(std::move(value)); + } + } - std::span get_buffer() const - { - return this->buffer_; - } + std::span get_buffer() const + { + return this->buffer_; + } - private: - const std::span buffer_{}; - }; + private: + const std::span buffer_{}; + }; } diff --git a/src/common/utils/concurrency.hpp b/src/common/utils/concurrency.hpp index e8be0db0..644ccfcc 100644 --- a/src/common/utils/concurrency.hpp +++ b/src/common/utils/concurrency.hpp @@ -4,54 +4,60 @@ namespace utils::concurrency { - template - class container - { - public: - template - R access(F&& accessor) const - { - std::lock_guard _{mutex_}; - return accessor(object_); - } + template + class container + { + public: + template + R access(F&& accessor) const + { + std::lock_guard _{mutex_}; + return accessor(object_); + } - template - R access(F&& accessor) - { - std::lock_guard _{mutex_}; - return accessor(object_); - } + template + R access(F&& accessor) + { + std::lock_guard _{mutex_}; + return accessor(object_); + } - template - R access_with_lock(F&& accessor) const - { - std::unique_lock lock{mutex_}; - return accessor(object_, lock); - } + template + R access_with_lock(F&& accessor) const + { + std::unique_lock lock{mutex_}; + return accessor(object_, lock); + } - template - R access_with_lock(F&& accessor) - { - std::unique_lock lock{mutex_}; - return accessor(object_, lock); - } + template + R access_with_lock(F&& accessor) + { + std::unique_lock lock{mutex_}; + return accessor(object_, lock); + } - T& get_raw() { return object_; } - const T& get_raw() const { return object_; } + T& get_raw() + { + return object_; + } + const T& get_raw() const + { + return object_; + } - T copy() const - { - std::unique_lock lock{mutex_}; - return object_; - } + T copy() const + { + std::unique_lock lock{mutex_}; + return object_; + } - std::unique_lock acquire_lock() - { - return std::unique_lock{mutex_}; - } + std::unique_lock acquire_lock() + { + return std::unique_lock{mutex_}; + } - private: - mutable MutexType mutex_{}; - T object_{}; - }; + private: + mutable MutexType mutex_{}; + T object_{}; + }; } diff --git a/src/common/utils/container.hpp b/src/common/utils/container.hpp index eeafdf39..2a7cb2f5 100644 --- a/src/common/utils/container.hpp +++ b/src/common/utils/container.hpp @@ -7,19 +7,19 @@ namespace utils { - struct string_hash - { - using is_transparent = void; + struct string_hash + { + using is_transparent = void; - size_t operator()(const std::string_view str) const - { - constexpr std::hash hasher{}; - return hasher(str); - } - }; + size_t operator()(const std::string_view str) const + { + constexpr std::hash hasher{}; + return hasher(str); + } + }; - template - using unordered_string_map = std::unordered_map>; + template + using unordered_string_map = std::unordered_map>; - using unordered_string_set = std::unordered_set>; + using unordered_string_set = std::unordered_set>; } diff --git a/src/common/utils/file_handle.hpp b/src/common/utils/file_handle.hpp index 29603137..240cf8ed 100644 --- a/src/common/utils/file_handle.hpp +++ b/src/common/utils/file_handle.hpp @@ -5,91 +5,91 @@ namespace utils { - class file_handle - { - public: - file_handle() = default; + class file_handle + { + public: + file_handle() = default; - file_handle(FILE* file) - : file_(file) - { - } + file_handle(FILE* file) + : file_(file) + { + } - ~file_handle() - { - this->release(); - } + ~file_handle() + { + this->release(); + } - file_handle(const file_handle&) = delete; - file_handle& operator=(const file_handle&) = delete; + file_handle(const file_handle&) = delete; + file_handle& operator=(const file_handle&) = delete; - file_handle(file_handle&& obj) noexcept - : file_handle() - { - this->operator=(std::move(obj)); - } + file_handle(file_handle&& obj) noexcept + : file_handle() + { + this->operator=(std::move(obj)); + } - file_handle& operator=(file_handle&& obj) noexcept - { - if (this != &obj) - { - this->release(); - this->file_ = obj.file_; - obj.file_ = {}; - } + file_handle& operator=(file_handle&& obj) noexcept + { + if (this != &obj) + { + this->release(); + this->file_ = obj.file_; + obj.file_ = {}; + } - return *this; - } + return *this; + } - file_handle& operator=(FILE* file) noexcept - { - this->release(); - this->file_ = file; + file_handle& operator=(FILE* file) noexcept + { + this->release(); + this->file_ = file; - return *this; - } + return *this; + } - [[nodiscard]] operator bool() const - { - return this->file_; - } + [[nodiscard]] operator bool() const + { + return this->file_; + } - [[nodiscard]] operator FILE*() const - { - return this->file_; - } + [[nodiscard]] operator FILE*() const + { + return this->file_; + } - [[nodiscard]] int64_t size() const - { - const auto current_position = this->tell(); + [[nodiscard]] int64_t size() const + { + const auto current_position = this->tell(); - this->seek_to(0, SEEK_END); - const auto size = this->tell(); - this->seek_to(current_position); + this->seek_to(0, SEEK_END); + const auto size = this->tell(); + this->seek_to(current_position); - return size; - } + return size; + } - bool seek_to(const int64_t position, const int origin = SEEK_SET) const - { - return _fseeki64(this->file_, position, origin) == 0; - } + bool seek_to(const int64_t position, const int origin = SEEK_SET) const + { + return _fseeki64(this->file_, position, origin) == 0; + } - [[nodiscard]] int64_t tell() const - { - return _ftelli64(this->file_); - } + [[nodiscard]] int64_t tell() const + { + return _ftelli64(this->file_); + } - private: - FILE* file_{}; + private: + FILE* file_{}; - void release() - { - if (this->file_) - { - (void)fclose(this->file_); - this->file_ = {}; - } - } - }; + void release() + { + if (this->file_) + { + (void)fclose(this->file_); + this->file_ = {}; + } + } + }; } diff --git a/src/common/utils/finally.hpp b/src/common/utils/finally.hpp index 94489e59..65c74392 100644 --- a/src/common/utils/finally.hpp +++ b/src/common/utils/finally.hpp @@ -4,52 +4,53 @@ namespace utils { - /* - * Copied from here: https://github.com/microsoft/GSL/blob/e0880931ae5885eb988d1a8a57acf8bc2b8dacda/include/gsl/util#L57 - */ + /* + * Copied from here: + * https://github.com/microsoft/GSL/blob/e0880931ae5885eb988d1a8a57acf8bc2b8dacda/include/gsl/util#L57 + */ - template - class final_action - { - public: - static_assert(!std::is_reference::value && !std::is_const::value && - !std::is_volatile::value, - "Final_action should store its callable by value"); + template + class final_action + { + public: + static_assert(!std::is_reference::value && !std::is_const::value && !std::is_volatile::value, + "Final_action should store its callable by value"); - explicit final_action(F f) noexcept : f_(std::move(f)) - { - } + explicit final_action(F f) noexcept + : f_(std::move(f)) + { + } - final_action(final_action&& other) noexcept - : f_(std::move(other.f_)), invoke_(std::exchange(other.invoke_, false)) - { - } + final_action(final_action&& other) noexcept + : f_(std::move(other.f_)), + invoke_(std::exchange(other.invoke_, false)) + { + } - final_action(const final_action&) = delete; - final_action& operator=(const final_action&) = delete; - final_action& operator=(final_action&&) = delete; + final_action(const final_action&) = delete; + final_action& operator=(const final_action&) = delete; + final_action& operator=(final_action&&) = delete; - ~final_action() noexcept - { - if (invoke_) f_(); - } + ~final_action() noexcept + { + if (invoke_) + f_(); + } - // Added by momo5502 - void cancel() - { - invoke_ = false; - } + // Added by momo5502 + void cancel() + { + invoke_ = false; + } - private: - F f_; - bool invoke_{true}; - }; + private: + F f_; + bool invoke_{true}; + }; - template - final_action::type>::type> - finally(F&& f) noexcept - { - return final_action::type>::type>( - std::forward(f)); - } + template + final_action::type>::type> finally(F&& f) noexcept + { + return final_action::type>::type>(std::forward(f)); + } } diff --git a/src/common/utils/io.cpp b/src/common/utils/io.cpp index e7258219..06397a91 100644 --- a/src/common/utils/io.cpp +++ b/src/common/utils/io.cpp @@ -4,121 +4,123 @@ namespace utils::io { - bool remove_file(const std::filesystem::path& file) - { - std::error_code ec{}; - return std::filesystem::remove(file, ec) && !ec; - } + bool remove_file(const std::filesystem::path& file) + { + std::error_code ec{}; + return std::filesystem::remove(file, ec) && !ec; + } - bool move_file(const std::filesystem::path& src, const std::filesystem::path& target) - { - copy_folder(src, target); - return remove_file(src); - } + bool move_file(const std::filesystem::path& src, const std::filesystem::path& target) + { + copy_folder(src, target); + return remove_file(src); + } - bool file_exists(const std::filesystem::path& file) - { - return std::ifstream(file).good(); - } + bool file_exists(const std::filesystem::path& file) + { + return std::ifstream(file).good(); + } - bool write_file(const std::filesystem::path& file, const std::vector& data, const bool append) - { - if (file.has_parent_path()) - { - io::create_directory(file.parent_path()); - } + bool write_file(const std::filesystem::path& file, const std::vector& data, const bool append) + { + if (file.has_parent_path()) + { + io::create_directory(file.parent_path()); + } - std::ofstream stream( - file, std::ios::binary | std::ofstream::out | (append ? std::ofstream::app : std::ofstream::out)); + std::ofstream stream(file, std::ios::binary | std::ofstream::out | + (append ? std::ofstream::app : std::ofstream::out)); - if (stream.is_open()) - { - stream.write(reinterpret_cast(data.data()), static_cast(data.size())); - stream.close(); - return true; - } + if (stream.is_open()) + { + stream.write(reinterpret_cast(data.data()), static_cast(data.size())); + stream.close(); + return true; + } - return false; - } + return false; + } - std::vector read_file(const std::filesystem::path& file) - { - std::vector data; - read_file(file, &data); - return data; - } + std::vector read_file(const std::filesystem::path& file) + { + std::vector data; + read_file(file, &data); + return data; + } - bool read_file(const std::filesystem::path& file, std::vector* data) - { - if (!data) return false; - data->clear(); + bool read_file(const std::filesystem::path& file, std::vector* data) + { + if (!data) + return false; + data->clear(); - std::ifstream stream(file, std::ios::binary); - if (!stream) return false; + std::ifstream stream(file, std::ios::binary); + if (!stream) + return false; - *data = std::vector{(std::istreambuf_iterator(stream)), std::istreambuf_iterator()}; - return true; - } + *data = std::vector{(std::istreambuf_iterator(stream)), std::istreambuf_iterator()}; + return true; + } - std::size_t file_size(const std::filesystem::path& file) - { - std::ifstream stream(file, std::ios::binary); + std::size_t file_size(const std::filesystem::path& file) + { + std::ifstream stream(file, std::ios::binary); - if (stream) - { - stream.seekg(0, std::ios::end); - return static_cast(stream.tellg()); - } + if (stream) + { + stream.seekg(0, std::ios::end); + return static_cast(stream.tellg()); + } - return 0; - } + return 0; + } - bool create_directory(const std::filesystem::path& directory) - { - std::error_code ec{}; - return std::filesystem::create_directories(directory, ec) && !ec; - } + bool create_directory(const std::filesystem::path& directory) + { + std::error_code ec{}; + return std::filesystem::create_directories(directory, ec) && !ec; + } - bool directory_exists(const std::filesystem::path& directory) - { - std::error_code ec{}; - return std::filesystem::is_directory(directory, ec) && !ec; - } + bool directory_exists(const std::filesystem::path& directory) + { + std::error_code ec{}; + return std::filesystem::is_directory(directory, ec) && !ec; + } - bool directory_is_empty(const std::filesystem::path& directory) - { - std::error_code ec{}; - return std::filesystem::is_empty(directory, ec) && !ec; - } + bool directory_is_empty(const std::filesystem::path& directory) + { + std::error_code ec{}; + return std::filesystem::is_empty(directory, ec) && !ec; + } - void copy_folder(const std::filesystem::path& src, const std::filesystem::path& target) - { - std::error_code ec{}; - std::filesystem::copy(src, target, - std::filesystem::copy_options::overwrite_existing | - std::filesystem::copy_options::recursive, ec); - } + void copy_folder(const std::filesystem::path& src, const std::filesystem::path& target) + { + std::error_code ec{}; + std::filesystem::copy( + src, target, std::filesystem::copy_options::overwrite_existing | std::filesystem::copy_options::recursive, + ec); + } - std::vector list_files(const std::filesystem::path& directory, const bool recursive) - { - std::error_code code{}; - std::vector files; + std::vector list_files(const std::filesystem::path& directory, const bool recursive) + { + std::error_code code{}; + std::vector files; - if (recursive) - { - for (auto& file : std::filesystem::recursive_directory_iterator(directory, code)) - { - files.push_back(file.path()); - } - } - else - { - for (auto& file : std::filesystem::directory_iterator(directory, code)) - { - files.push_back(file.path()); - } - } + if (recursive) + { + for (auto& file : std::filesystem::recursive_directory_iterator(directory, code)) + { + files.push_back(file.path()); + } + } + else + { + for (auto& file : std::filesystem::directory_iterator(directory, code)) + { + files.push_back(file.path()); + } + } - return files; - } + return files; + } } diff --git a/src/common/utils/io.hpp b/src/common/utils/io.hpp index d61236bc..38ae1df6 100644 --- a/src/common/utils/io.hpp +++ b/src/common/utils/io.hpp @@ -6,17 +6,17 @@ namespace utils::io { - bool remove_file(const std::filesystem::path& file); - bool move_file(const std::filesystem::path& src, const std::filesystem::path& target); - bool file_exists(const std::filesystem::path& file); - bool write_file(const std::filesystem::path& file, const std::vector& data, bool append = false); - bool read_file(const std::filesystem::path& file, std::vector* data); - std::vector read_file(const std::filesystem::path& file); - size_t file_size(const std::filesystem::path& file); - bool create_directory(const std::filesystem::path& directory); - bool directory_exists(const std::filesystem::path& directory); - bool directory_is_empty(const std::filesystem::path& directory); - void copy_folder(const std::filesystem::path& src, const std::filesystem::path& target); + bool remove_file(const std::filesystem::path& file); + bool move_file(const std::filesystem::path& src, const std::filesystem::path& target); + bool file_exists(const std::filesystem::path& file); + bool write_file(const std::filesystem::path& file, const std::vector& data, bool append = false); + bool read_file(const std::filesystem::path& file, std::vector* data); + std::vector read_file(const std::filesystem::path& file); + size_t file_size(const std::filesystem::path& file); + bool create_directory(const std::filesystem::path& directory); + bool directory_exists(const std::filesystem::path& directory); + bool directory_is_empty(const std::filesystem::path& directory); + void copy_folder(const std::filesystem::path& src, const std::filesystem::path& target); - std::vector list_files(const std::filesystem::path& directory, bool recursive = false); + std::vector list_files(const std::filesystem::path& directory, bool recursive = false); } diff --git a/src/common/utils/nt_handle.hpp b/src/common/utils/nt_handle.hpp index fc97f925..0d00714e 100644 --- a/src/common/utils/nt_handle.hpp +++ b/src/common/utils/nt_handle.hpp @@ -10,80 +10,80 @@ namespace utils::nt { - using HandleFunction = HANDLE(); + using HandleFunction = HANDLE(); - inline HANDLE null_handle() - { - return nullptr; - } + inline HANDLE null_handle() + { + return nullptr; + } - inline HANDLE invalid_handle() - { - return INVALID_HANDLE_VALUE; - } + inline HANDLE invalid_handle() + { + return INVALID_HANDLE_VALUE; + } - template - class handle - { - public: - handle() = default; + template + class handle + { + public: + handle() = default; - handle(const HANDLE h) - : handle_(h) - { - } + handle(const HANDLE h) + : handle_(h) + { + } - ~handle() - { - if (*this) - { - CloseHandle(this->handle_); - this->handle_ = InvalidHandleFunction(); - } - } + ~handle() + { + if (*this) + { + CloseHandle(this->handle_); + this->handle_ = InvalidHandleFunction(); + } + } - handle(const handle&) = delete; - handle& operator=(const handle&) = delete; + handle(const handle&) = delete; + handle& operator=(const handle&) = delete; - handle(handle&& obj) noexcept - : handle() - { - this->operator=(std::move(obj)); - } + handle(handle&& obj) noexcept + : handle() + { + this->operator=(std::move(obj)); + } - handle& operator=(handle&& obj) noexcept - { - if (this != &obj) - { - this->~handle(); - this->handle_ = obj.handle_; - obj.handle_ = InvalidHandleFunction(); - } + handle& operator=(handle&& obj) noexcept + { + if (this != &obj) + { + this->~handle(); + this->handle_ = obj.handle_; + obj.handle_ = InvalidHandleFunction(); + } - return *this; - } + return *this; + } - handle& operator=(HANDLE h) noexcept - { - this->~handle(); - this->handle_ = h; + handle& operator=(HANDLE h) noexcept + { + this->~handle(); + this->handle_ = h; - return *this; - } + return *this; + } - [[nodiscard]] operator bool() const - { - return this->handle_ != InvalidHandleFunction(); - } + [[nodiscard]] operator bool() const + { + return this->handle_ != InvalidHandleFunction(); + } - [[nodiscard]] operator HANDLE() const - { - return this->handle_; - } + [[nodiscard]] operator HANDLE() const + { + return this->handle_; + } - private: - HANDLE handle_{InvalidHandleFunction()}; - }; + private: + HANDLE handle_{InvalidHandleFunction()}; + }; } #endif diff --git a/src/common/utils/string.hpp b/src/common/utils/string.hpp index dac98317..a1c6497e 100644 --- a/src/common/utils/string.hpp +++ b/src/common/utils/string.hpp @@ -6,45 +6,42 @@ namespace utils::string { - inline char char_to_lower(const char val) - { - return static_cast(std::tolower(static_cast(val))); - } + inline char char_to_lower(const char val) + { + return static_cast(std::tolower(static_cast(val))); + } - inline char16_t char_to_lower(const char16_t val) - { - if (val >= u'A' && val <= u'Z') - { - return val + 32; - } + inline char16_t char_to_lower(const char16_t val) + { + if (val >= u'A' && val <= u'Z') + { + return val + 32; + } - return val; - } + return val; + } - inline wchar_t char_to_lower(const wchar_t val) - { - return std::towlower(val); - } + inline wchar_t char_to_lower(const wchar_t val) + { + return std::towlower(val); + } - template - void to_lower_inplace(std::basic_string& str) - { - std::ranges::transform(str, str.begin(), [](const Elem e) - { - return char_to_lower(e); - }); - } + template + void to_lower_inplace(std::basic_string& str) + { + std::ranges::transform(str, str.begin(), [](const Elem e) { return char_to_lower(e); }); + } - template - std::basic_string to_lower(std::basic_string str) - { - to_lower_inplace(str); - return str; - } + template + std::basic_string to_lower(std::basic_string str) + { + to_lower_inplace(str); + return str; + } - template - std::basic_string to_lower_consume(std::basic_string& str) - { - return to_lower(std::move(str)); - } + template + std::basic_string to_lower_consume(std::basic_string& str) + { + return to_lower(std::move(str)); + } } diff --git a/src/common/utils/timer.hpp b/src/common/utils/timer.hpp index 3fd09722..22120bce 100644 --- a/src/common/utils/timer.hpp +++ b/src/common/utils/timer.hpp @@ -4,23 +4,23 @@ namespace utils { - template - class timer - { - public: - void update() - { - this->point_ = Clock::now(); - } + template + class timer + { + public: + void update() + { + this->point_ = Clock::now(); + } - bool has_elapsed(typename Clock::duration duration) const - { - const auto now = Clock::now(); - const auto diff = now - this->point_; - return diff > duration; - } + bool has_elapsed(typename Clock::duration duration) const + { + const auto now = Clock::now(); + const auto diff = now - this->point_; + return diff > duration; + } - private: - typename Clock::time_point point_{Clock::now()}; - }; + private: + typename Clock::time_point point_{Clock::now()}; + }; } diff --git a/src/emulator/address_utils.hpp b/src/emulator/address_utils.hpp index b5b66145..49c154a6 100644 --- a/src/emulator/address_utils.hpp +++ b/src/emulator/address_utils.hpp @@ -4,52 +4,52 @@ template T* offset_pointer(void* data, const size_t offset) { - return reinterpret_cast(static_cast(data) + offset); + return reinterpret_cast(static_cast(data) + offset); } template const T* offset_pointer(const void* data, const size_t offset) { - return reinterpret_cast(static_cast(data) + offset); + return reinterpret_cast(static_cast(data) + offset); } constexpr bool is_within_start_and_end(const uint64_t value, const uint64_t start, const uint64_t end) { - return value >= start && value < end; + return value >= start && value < end; } constexpr bool is_within_start_and_length(const uint64_t value, const uint64_t start, const uint64_t length) { - return is_within_start_and_end(value, start, start + length); + return is_within_start_and_end(value, start, start + length); } constexpr bool regions_intersect(const uint64_t start1, const uint64_t end1, const uint64_t start2, const uint64_t end2) { - return start1 < end2 && start2 < end1; + return start1 < end2 && start2 < end1; } constexpr bool regions_with_length_intersect(const uint64_t start1, const uint64_t length1, const uint64_t start2, const uint64_t length2) { - return regions_intersect(start1, start1 + length1, start2, start2 + length2); + return regions_intersect(start1, start1 + length1, start2, start2 + length2); } constexpr uint64_t align_down(const uint64_t value, const uint64_t alignment) { - return value & ~(alignment - 1); + return value & ~(alignment - 1); } constexpr uint64_t align_up(const uint64_t value, const uint64_t alignment) { - return align_down(value + (alignment - 1), alignment); + return align_down(value + (alignment - 1), alignment); } constexpr uint64_t page_align_down(const uint64_t value, const uint64_t page_size = 0x1000) { - return align_down(value, page_size); + return align_down(value, page_size); } constexpr uint64_t page_align_up(const uint64_t value, const uint64_t page_size = 0x1000) { - return align_up(value, page_size); + return align_up(value, page_size); } diff --git a/src/emulator/emulator.hpp b/src/emulator/emulator.hpp index b20b0925..2e4691ba 100644 --- a/src/emulator/emulator.hpp +++ b/src/emulator/emulator.hpp @@ -11,156 +11,152 @@ using memory_operation = memory_permission; enum class instruction_hook_continuation : bool { - run_instruction = false, - skip_instruction = true, + run_instruction = false, + skip_instruction = true, }; enum class memory_violation_continuation : bool { - stop = false, - resume = true, + stop = false, + resume = true, }; enum class memory_violation_type : uint8_t { - unmapped, - protection, + unmapped, + protection, }; struct basic_block { - uint64_t address; - size_t instruction_count; - size_t size; + uint64_t address; + size_t instruction_count; + size_t size; }; -using edge_generation_hook_callback = std::function; +using edge_generation_hook_callback = + std::function; using basic_block_hook_callback = std::function; using instruction_hook_callback = std::function; using interrupt_hook_callback = std::function; using simple_memory_hook_callback = std::function; -using complex_memory_hook_callback = std::function; +using complex_memory_hook_callback = + std::function; using memory_violation_hook_callback = std::function; + uint64_t address, size_t size, memory_operation operation, memory_violation_type type)>; class emulator : public memory_manager { -public: - emulator() = default; + public: + emulator() = default; - emulator(const emulator&) = delete; - emulator& operator=(const emulator&) = delete; + emulator(const emulator&) = delete; + emulator& operator=(const emulator&) = delete; - emulator(emulator&&) = delete; - emulator& operator=(emulator&&) = delete; + emulator(emulator&&) = delete; + emulator& operator=(emulator&&) = delete; - virtual void start(uint64_t start, uint64_t end = 0, std::chrono::nanoseconds timeout = {}, size_t count = 0) = 0; - virtual void stop() = 0; + virtual void start(uint64_t start, uint64_t end = 0, std::chrono::nanoseconds timeout = {}, size_t count = 0) = 0; + virtual void stop() = 0; - virtual void read_raw_register(int reg, void* value, size_t size) = 0; - virtual void write_raw_register(int reg, const void* value, size_t size) = 0; + virtual void read_raw_register(int reg, void* value, size_t size) = 0; + virtual void write_raw_register(int reg, const void* value, size_t size) = 0; - virtual std::vector save_registers() = 0; - virtual void restore_registers(const std::vector& register_data) = 0; + virtual std::vector save_registers() = 0; + virtual void restore_registers(const std::vector& register_data) = 0; - virtual emulator_hook* hook_memory_violation(uint64_t address, size_t size, - memory_violation_hook_callback callback) = 0; + virtual emulator_hook* hook_memory_violation(uint64_t address, size_t size, + memory_violation_hook_callback callback) = 0; - virtual emulator_hook* hook_memory_access(uint64_t address, size_t size, memory_operation filter, - complex_memory_hook_callback callback) = 0; - virtual emulator_hook* hook_instruction(int instruction_type, instruction_hook_callback callback) = 0; + virtual emulator_hook* hook_memory_access(uint64_t address, size_t size, memory_operation filter, + complex_memory_hook_callback callback) = 0; + virtual emulator_hook* hook_instruction(int instruction_type, instruction_hook_callback callback) = 0; - virtual emulator_hook* hook_interrupt(interrupt_hook_callback callback) = 0; + virtual emulator_hook* hook_interrupt(interrupt_hook_callback callback) = 0; - virtual emulator_hook* hook_edge_generation(edge_generation_hook_callback callback) = 0; - virtual emulator_hook* hook_basic_block(basic_block_hook_callback callback) = 0; + virtual emulator_hook* hook_edge_generation(edge_generation_hook_callback callback) = 0; + virtual emulator_hook* hook_basic_block(basic_block_hook_callback callback) = 0; - virtual void delete_hook(emulator_hook* hook) = 0; + virtual void delete_hook(emulator_hook* hook) = 0; - emulator_hook* hook_memory_violation(memory_violation_hook_callback callback) - { - return this->hook_memory_violation(0, std::numeric_limits::max(), std::move(callback)); - } + emulator_hook* hook_memory_violation(memory_violation_hook_callback callback) + { + return this->hook_memory_violation(0, std::numeric_limits::max(), std::move(callback)); + } - emulator_hook* hook_memory_read(const uint64_t address, const size_t size, simple_memory_hook_callback callback) - { - return this->hook_simple_memory_access(address, size, std::move(callback), memory_operation::read); - } + emulator_hook* hook_memory_read(const uint64_t address, const size_t size, simple_memory_hook_callback callback) + { + return this->hook_simple_memory_access(address, size, std::move(callback), memory_operation::read); + } - emulator_hook* hook_memory_write(const uint64_t address, const size_t size, simple_memory_hook_callback callback) - { - return this->hook_simple_memory_access(address, size, std::move(callback), memory_operation::write); - } + emulator_hook* hook_memory_write(const uint64_t address, const size_t size, simple_memory_hook_callback callback) + { + return this->hook_simple_memory_access(address, size, std::move(callback), memory_operation::write); + } - emulator_hook* hook_memory_execution(const uint64_t address, const size_t size, - simple_memory_hook_callback callback) - { - return this->hook_simple_memory_access(address, size, std::move(callback), memory_operation::exec); - } + emulator_hook* hook_memory_execution(const uint64_t address, const size_t size, + simple_memory_hook_callback callback) + { + return this->hook_simple_memory_access(address, size, std::move(callback), memory_operation::exec); + } - void serialize(utils::buffer_serializer& buffer) const - { - this->perform_serialization(buffer, false); - } + void serialize(utils::buffer_serializer& buffer) const + { + this->perform_serialization(buffer, false); + } - void deserialize(utils::buffer_deserializer& buffer) - { - this->perform_deserialization(buffer, false); - } + void deserialize(utils::buffer_deserializer& buffer) + { + this->perform_deserialization(buffer, false); + } - void save_snapshot() - { - utils::buffer_serializer serializer{}; - this->perform_serialization(serializer, true); - this->last_snapshot_data_ = serializer.move_buffer(); - } + void save_snapshot() + { + utils::buffer_serializer serializer{}; + this->perform_serialization(serializer, true); + this->last_snapshot_data_ = serializer.move_buffer(); + } - void restore_snapshot() - { - if (this->last_snapshot_data_.empty()) - { - return; - } + void restore_snapshot() + { + if (this->last_snapshot_data_.empty()) + { + return; + } - utils::buffer_deserializer deserializer{this->last_snapshot_data_}; - this->perform_deserialization(deserializer, true); - } + utils::buffer_deserializer deserializer{this->last_snapshot_data_}; + this->perform_deserialization(deserializer, true); + } - virtual bool has_violation() const = 0; + virtual bool has_violation() const = 0; -private: - std::vector last_snapshot_data_{}; + private: + std::vector last_snapshot_data_{}; - emulator_hook* hook_simple_memory_access(const uint64_t address, const size_t size, - simple_memory_hook_callback callback, const memory_operation operation) - { - assert((static_cast(operation) & (static_cast(operation) - 1)) == 0); - return this->hook_memory_access(address, size, operation, - [c = std::move(callback)](const uint64_t a, const size_t s, - const uint64_t value, - memory_operation) - { - c(a, s, value); - }); - } + emulator_hook* hook_simple_memory_access(const uint64_t address, const size_t size, + simple_memory_hook_callback callback, const memory_operation operation) + { + assert((static_cast(operation) & (static_cast(operation) - 1)) == 0); + return this->hook_memory_access(address, size, operation, + [c = std::move(callback)](const uint64_t a, const size_t s, + const uint64_t value, + memory_operation) { c(a, s, value); }); + } - void perform_serialization(utils::buffer_serializer& buffer, const bool is_snapshot) const - { - this->serialize_state(buffer, is_snapshot); - this->serialize_memory_state(buffer, is_snapshot); - } + void perform_serialization(utils::buffer_serializer& buffer, const bool is_snapshot) const + { + this->serialize_state(buffer, is_snapshot); + this->serialize_memory_state(buffer, is_snapshot); + } - void perform_deserialization(utils::buffer_deserializer& buffer, const bool is_snapshot) - { - this->deserialize_state(buffer, is_snapshot); - this->deserialize_memory_state(buffer, is_snapshot); - } + void perform_deserialization(utils::buffer_deserializer& buffer, const bool is_snapshot) + { + this->deserialize_state(buffer, is_snapshot); + this->deserialize_memory_state(buffer, is_snapshot); + } - virtual void serialize_state(utils::buffer_serializer& buffer, bool is_snapshot) const = 0; - virtual void deserialize_state(utils::buffer_deserializer& buffer, bool is_snapshot) = 0; + virtual void serialize_state(utils::buffer_serializer& buffer, bool is_snapshot) const = 0; + virtual void deserialize_state(utils::buffer_deserializer& buffer, bool is_snapshot) = 0; }; diff --git a/src/emulator/memory_manager.cpp b/src/emulator/memory_manager.cpp index abd5405f..dcb9bb64 100644 --- a/src/emulator/memory_manager.cpp +++ b/src/emulator/memory_manager.cpp @@ -10,541 +10,547 @@ namespace { - constexpr auto MIN_ALLOCATION_ADDRESS = 0x0000000000010000ULL; - constexpr auto MAX_ALLOCATION_ADDRESS = 0x00007ffffffeffffULL; + constexpr auto MIN_ALLOCATION_ADDRESS = 0x0000000000010000ULL; + constexpr auto MAX_ALLOCATION_ADDRESS = 0x00007ffffffeffffULL; - void split_regions(memory_manager::committed_region_map& regions, const std::vector& split_points) - { - for (auto i = regions.begin(); i != regions.end(); ++i) - { - for (const auto split_point : split_points) - { - if (is_within_start_and_length(split_point, i->first, i->second.length) && i->first != split_point) - { - const auto first_length = split_point - i->first; - const auto second_length = i->second.length - first_length; + void split_regions(memory_manager::committed_region_map& regions, const std::vector& split_points) + { + for (auto i = regions.begin(); i != regions.end(); ++i) + { + for (const auto split_point : split_points) + { + if (is_within_start_and_length(split_point, i->first, i->second.length) && i->first != split_point) + { + const auto first_length = split_point - i->first; + const auto second_length = i->second.length - first_length; - i->second.length = first_length; + i->second.length = first_length; - regions[split_point] = memory_manager::committed_region{second_length, i->second.pemissions}; - } - } - } - } + regions[split_point] = memory_manager::committed_region{second_length, i->second.pemissions}; + } + } + } + } - void merge_regions(memory_manager::committed_region_map& regions) - { - for (auto i = regions.begin(); i != regions.end();) - { - assert(i->second.length > 0); + void merge_regions(memory_manager::committed_region_map& regions) + { + for (auto i = regions.begin(); i != regions.end();) + { + assert(i->second.length > 0); - auto next = i; - std::advance(next, 1); + auto next = i; + std::advance(next, 1); - if (next == regions.end()) - { - break; - } + if (next == regions.end()) + { + break; + } - assert(next->second.length > 0); + assert(next->second.length > 0); - const auto end = i->first + i->second.length; - assert(end <= next->first); + const auto end = i->first + i->second.length; + assert(end <= next->first); - if (end != next->first || i->second.pemissions != next->second.pemissions) - { - ++i; - continue; - } + if (end != next->first || i->second.pemissions != next->second.pemissions) + { + ++i; + continue; + } - i->second.length += next->second.length; - regions.erase(next); - } - } + i->second.length += next->second.length; + regions.erase(next); + } + } } namespace utils { - static void serialize(buffer_serializer& buffer, const memory_manager::committed_region& region) - { - buffer.write(region.length); - buffer.write(region.pemissions); - } + static void serialize(buffer_serializer& buffer, const memory_manager::committed_region& region) + { + buffer.write(region.length); + buffer.write(region.pemissions); + } - static void deserialize(buffer_deserializer& buffer, memory_manager::committed_region& region) - { - region.length = static_cast(buffer.read()); - region.pemissions = buffer.read(); - } + static void deserialize(buffer_deserializer& buffer, memory_manager::committed_region& region) + { + region.length = static_cast(buffer.read()); + region.pemissions = buffer.read(); + } - static void serialize(buffer_serializer& buffer, const memory_manager::reserved_region& region) - { - buffer.write(region.is_mmio); - buffer.write(region.length); - buffer.write_map(region.committed_regions); - } + static void serialize(buffer_serializer& buffer, const memory_manager::reserved_region& region) + { + buffer.write(region.is_mmio); + buffer.write(region.length); + buffer.write_map(region.committed_regions); + } - static void deserialize(buffer_deserializer& buffer, memory_manager::reserved_region& region) - { - buffer.read(region.is_mmio); - region.length = static_cast(buffer.read()); - buffer.read_map(region.committed_regions); - } + static void deserialize(buffer_deserializer& buffer, memory_manager::reserved_region& region) + { + buffer.read(region.is_mmio); + region.length = static_cast(buffer.read()); + buffer.read_map(region.committed_regions); + } } void memory_manager::serialize_memory_state(utils::buffer_serializer& buffer, const bool is_snapshot) const { - buffer.write_map(this->reserved_regions_); + buffer.write_map(this->reserved_regions_); - if (is_snapshot) - { - return; - } + if (is_snapshot) + { + return; + } - std::vector data{}; + std::vector data{}; - for (const auto& reserved_region : this->reserved_regions_) - { - if (reserved_region.second.is_mmio) - { - continue; - } + for (const auto& reserved_region : this->reserved_regions_) + { + if (reserved_region.second.is_mmio) + { + continue; + } - for (const auto& region : reserved_region.second.committed_regions) - { - data.resize(region.second.length); + for (const auto& region : reserved_region.second.committed_regions) + { + data.resize(region.second.length); - this->read_memory(region.first, data.data(), region.second.length); + this->read_memory(region.first, data.data(), region.second.length); - buffer.write(data.data(), region.second.length); - } - } + buffer.write(data.data(), region.second.length); + } + } } void memory_manager::deserialize_memory_state(utils::buffer_deserializer& buffer, const bool is_snapshot) { - if (!is_snapshot) - { - for (const auto& reserved_region : this->reserved_regions_) - { - for (const auto& region : reserved_region.second.committed_regions) - { - this->unmap_memory(region.first, region.second.length); - } - } - } + if (!is_snapshot) + { + for (const auto& reserved_region : this->reserved_regions_) + { + for (const auto& region : reserved_region.second.committed_regions) + { + this->unmap_memory(region.first, region.second.length); + } + } + } - buffer.read_map(this->reserved_regions_); + buffer.read_map(this->reserved_regions_); - if (is_snapshot) - { - return; - } + if (is_snapshot) + { + return; + } - std::vector data{}; + std::vector data{}; - for (auto i = this->reserved_regions_.begin(); i != this->reserved_regions_.end();) - { - auto& reserved_region = i->second; - if (reserved_region.is_mmio) - { - i = this->reserved_regions_.erase(i); - continue; - } + for (auto i = this->reserved_regions_.begin(); i != this->reserved_regions_.end();) + { + auto& reserved_region = i->second; + if (reserved_region.is_mmio) + { + i = this->reserved_regions_.erase(i); + continue; + } - ++i; + ++i; - for (const auto& region : reserved_region.committed_regions) - { - data.resize(region.second.length); + for (const auto& region : reserved_region.committed_regions) + { + data.resize(region.second.length); - buffer.read(data.data(), region.second.length); + buffer.read(data.data(), region.second.length); - this->map_memory(region.first, region.second.length, region.second.pemissions); - this->write_memory(region.first, data.data(), region.second.length); - } - } + this->map_memory(region.first, region.second.length, region.second.pemissions); + this->write_memory(region.first, data.data(), region.second.length); + } + } } bool memory_manager::protect_memory(const uint64_t address, const size_t size, const memory_permission permissions, memory_permission* old_permissions) { - const auto entry = this->find_reserved_region(address); - if (entry == this->reserved_regions_.end()) - { - return false; - } + const auto entry = this->find_reserved_region(address); + if (entry == this->reserved_regions_.end()) + { + return false; + } - const auto end = address + size; - const auto region_end = entry->first + entry->second.length; + const auto end = address + size; + const auto region_end = entry->first + entry->second.length; - if (region_end < end) - { - throw std::runtime_error("Cross region protect not supported yet!"); - } + if (region_end < end) + { + throw std::runtime_error("Cross region protect not supported yet!"); + } - std::optional old_first_permissions{}; + std::optional old_first_permissions{}; - auto& committed_regions = entry->second.committed_regions; - split_regions(committed_regions, {address, end}); + auto& committed_regions = entry->second.committed_regions; + split_regions(committed_regions, {address, end}); - for (auto& sub_region : committed_regions) - { - if (sub_region.first >= end) - { - break; - } + for (auto& sub_region : committed_regions) + { + if (sub_region.first >= end) + { + break; + } - const auto sub_region_end = sub_region.first + sub_region.second.length; - if (sub_region.first >= address && sub_region_end <= end) - { - if (!old_first_permissions.has_value()) - { - old_first_permissions = sub_region.second.pemissions; - } + const auto sub_region_end = sub_region.first + sub_region.second.length; + if (sub_region.first >= address && sub_region_end <= end) + { + if (!old_first_permissions.has_value()) + { + old_first_permissions = sub_region.second.pemissions; + } - this->apply_memory_protection(sub_region.first, sub_region.second.length, permissions); - sub_region.second.pemissions = permissions; - } - } + this->apply_memory_protection(sub_region.first, sub_region.second.length, permissions); + sub_region.second.pemissions = permissions; + } + } - if (old_permissions) - { - *old_permissions = old_first_permissions.value_or(memory_permission::none); - } + if (old_permissions) + { + *old_permissions = old_first_permissions.value_or(memory_permission::none); + } - merge_regions(committed_regions); - return true; + merge_regions(committed_regions); + return true; } bool memory_manager::allocate_mmio(const uint64_t address, const size_t size, mmio_read_callback read_cb, mmio_write_callback write_cb) { - if (this->overlaps_reserved_region(address, size)) - { - return false; - } + if (this->overlaps_reserved_region(address, size)) + { + return false; + } - this->map_mmio(address, size, std::move(read_cb), std::move(write_cb)); + this->map_mmio(address, size, std::move(read_cb), std::move(write_cb)); - const auto entry = this->reserved_regions_.try_emplace(address, - reserved_region{ - .length = size, - .is_mmio = true, - }).first; + const auto entry = this->reserved_regions_ + .try_emplace(address, + reserved_region{ + .length = size, + .is_mmio = true, + }) + .first; - entry->second.committed_regions[address] = committed_region{size, memory_permission::read_write}; + entry->second.committed_regions[address] = committed_region{size, memory_permission::read_write}; - return true; + return true; } bool memory_manager::allocate_memory(const uint64_t address, const size_t size, const memory_permission permissions, const bool reserve_only) { - if (this->overlaps_reserved_region(address, size)) - { - return false; - } + if (this->overlaps_reserved_region(address, size)) + { + return false; + } - const auto entry = this->reserved_regions_.try_emplace(address, reserved_region{.length = size,}).first; + const auto entry = this->reserved_regions_ + .try_emplace(address, + reserved_region{ + .length = size, + }) + .first; - if (!reserve_only) - { - this->map_memory(address, size, permissions); - entry->second.committed_regions[address] = committed_region{size, memory_permission::read_write}; - } + if (!reserve_only) + { + this->map_memory(address, size, permissions); + entry->second.committed_regions[address] = committed_region{size, memory_permission::read_write}; + } - return true; + return true; } bool memory_manager::commit_memory(const uint64_t address, const size_t size, const memory_permission permissions) { - const auto entry = this->find_reserved_region(address); - if (entry == this->reserved_regions_.end()) - { - return false; - } + const auto entry = this->find_reserved_region(address); + if (entry == this->reserved_regions_.end()) + { + return false; + } - const auto end = address + size; - const auto region_end = entry->first + entry->second.length; + const auto end = address + size; + const auto region_end = entry->first + entry->second.length; - if (region_end < end) - { - throw std::runtime_error("Cross region commit not supported yet!"); - } + if (region_end < end) + { + throw std::runtime_error("Cross region commit not supported yet!"); + } - auto& committed_regions = entry->second.committed_regions; - split_regions(committed_regions, {address, end}); + auto& committed_regions = entry->second.committed_regions; + split_regions(committed_regions, {address, end}); - uint64_t last_region_start{}; - const committed_region* last_region{nullptr}; + uint64_t last_region_start{}; + const committed_region* last_region{nullptr}; - for (auto& sub_region : committed_regions) - { - if (sub_region.first >= end) - { - break; - } + for (auto& sub_region : committed_regions) + { + if (sub_region.first >= end) + { + break; + } - const auto sub_region_end = sub_region.first + sub_region.second.length; - if (sub_region.first >= address && sub_region_end <= end) - { - const auto map_start = last_region ? (last_region_start + last_region->length) : address; - const auto map_length = sub_region.first - map_start; + const auto sub_region_end = sub_region.first + sub_region.second.length; + if (sub_region.first >= address && sub_region_end <= end) + { + const auto map_start = last_region ? (last_region_start + last_region->length) : address; + const auto map_length = sub_region.first - map_start; - if (map_length > 0) - { - this->map_memory(map_start, map_length, permissions); - committed_regions[map_start] = committed_region{map_length, permissions}; - } + if (map_length > 0) + { + this->map_memory(map_start, map_length, permissions); + committed_regions[map_start] = committed_region{map_length, permissions}; + } - last_region_start = sub_region.first; - last_region = &sub_region.second; - } - } + last_region_start = sub_region.first; + last_region = &sub_region.second; + } + } - if (!last_region || (last_region_start + last_region->length) < end) - { - const auto map_start = last_region ? (last_region_start + last_region->length) : address; - const auto map_length = end - map_start; + if (!last_region || (last_region_start + last_region->length) < end) + { + const auto map_start = last_region ? (last_region_start + last_region->length) : address; + const auto map_length = end - map_start; - this->map_memory(map_start, map_length, permissions); - committed_regions[map_start] = committed_region{map_length, permissions}; - } + this->map_memory(map_start, map_length, permissions); + committed_regions[map_start] = committed_region{map_length, permissions}; + } - merge_regions(committed_regions); - return true; + merge_regions(committed_regions); + return true; } bool memory_manager::decommit_memory(const uint64_t address, const size_t size) { - const auto entry = this->find_reserved_region(address); - if (entry == this->reserved_regions_.end()) - { - return false; - } + const auto entry = this->find_reserved_region(address); + if (entry == this->reserved_regions_.end()) + { + return false; + } - if (entry->second.is_mmio) - { - throw std::runtime_error("Not allowed to decommit MMIO!"); - } + if (entry->second.is_mmio) + { + throw std::runtime_error("Not allowed to decommit MMIO!"); + } - const auto end = address + size; - const auto region_end = entry->first + entry->second.length; + const auto end = address + size; + const auto region_end = entry->first + entry->second.length; - if (region_end < end) - { - throw std::runtime_error("Cross region decommit not supported yet!"); - } + if (region_end < end) + { + throw std::runtime_error("Cross region decommit not supported yet!"); + } - auto& committed_regions = entry->second.committed_regions; + auto& committed_regions = entry->second.committed_regions; - split_regions(committed_regions, {address, end}); + split_regions(committed_regions, {address, end}); - for (auto i = committed_regions.begin(); i != committed_regions.end();) - { - if (i->first >= end) - { - break; - } + for (auto i = committed_regions.begin(); i != committed_regions.end();) + { + if (i->first >= end) + { + break; + } - const auto sub_region_end = i->first + i->second.length; - if (i->first >= address && sub_region_end <= end) - { - this->unmap_memory(i->first, i->second.length); - i = committed_regions.erase(i); - continue; - } + const auto sub_region_end = i->first + i->second.length; + if (i->first >= address && sub_region_end <= end) + { + this->unmap_memory(i->first, i->second.length); + i = committed_regions.erase(i); + continue; + } - ++i; - } + ++i; + } - return true; + return true; } bool memory_manager::release_memory(const uint64_t address, size_t size) { - const auto entry = this->reserved_regions_.find(address); - if (entry == this->reserved_regions_.end()) - { - return false; - } + const auto entry = this->reserved_regions_.find(address); + if (entry == this->reserved_regions_.end()) + { + return false; + } - if (!size) - { - size = entry->second.length; - } + if (!size) + { + size = entry->second.length; + } - if (size > entry->second.length) - { - throw std::runtime_error("Cross region release not supported yet!"); - } + if (size > entry->second.length) + { + throw std::runtime_error("Cross region release not supported yet!"); + } - const auto end = address + size; - auto& committed_regions = entry->second.committed_regions; + const auto end = address + size; + auto& committed_regions = entry->second.committed_regions; - split_regions(committed_regions, {end}); + split_regions(committed_regions, {end}); - for (auto i = committed_regions.begin(); i != committed_regions.end();) - { - if (i->first >= end) - { - break; - } + for (auto i = committed_regions.begin(); i != committed_regions.end();) + { + if (i->first >= end) + { + break; + } - const auto sub_region_end = i->first + i->second.length; - if (i->first >= address && sub_region_end <= end) - { - this->unmap_memory(i->first, i->second.length); - i = committed_regions.erase(i); - } - else - { - ++i; - } - } + const auto sub_region_end = i->first + i->second.length; + if (i->first >= address && sub_region_end <= end) + { + this->unmap_memory(i->first, i->second.length); + i = committed_regions.erase(i); + } + else + { + ++i; + } + } - entry->second.length -= size; - if (entry->second.length > 0) - { - this->reserved_regions_[address + size] = std::move(entry->second); - } + entry->second.length -= size; + if (entry->second.length > 0) + { + this->reserved_regions_[address + size] = std::move(entry->second); + } - this->reserved_regions_.erase(entry); - return true; + this->reserved_regions_.erase(entry); + return true; } uint64_t memory_manager::find_free_allocation_base(const size_t size, const uint64_t start) const { - uint64_t start_address = - std::max(MIN_ALLOCATION_ADDRESS, start ? start : 0x100000000ULL); + uint64_t start_address = std::max(MIN_ALLOCATION_ADDRESS, start ? start : 0x100000000ULL); - for (const auto& region : this->reserved_regions_) - { - const auto region_end = region.first + region.second.length; - if (region_end < start_address) - { - continue; - } + for (const auto& region : this->reserved_regions_) + { + const auto region_end = region.first + region.second.length; + if (region_end < start_address) + { + continue; + } - if (!regions_with_length_intersect(start_address, size, region.first, region.second.length)) - { - return start_address; - } + if (!regions_with_length_intersect(start_address, size, region.first, region.second.length)) + { + return start_address; + } - start_address = page_align_up(region_end); - } + start_address = page_align_up(region_end); + } - if (start_address + size <= MAX_ALLOCATION_ADDRESS) - { - return start_address; - } + if (start_address + size <= MAX_ALLOCATION_ADDRESS) + { + return start_address; + } - return 0; + return 0; } region_info memory_manager::get_region_info(const uint64_t address) { - region_info result{}; - result.start = MIN_ALLOCATION_ADDRESS; - result.length = MAX_ALLOCATION_ADDRESS - result.start; - result.permissions = memory_permission::none; - result.allocation_base = {}; - result.allocation_length = result.length; - result.is_committed = false; - result.is_reserved = false; + region_info result{}; + result.start = MIN_ALLOCATION_ADDRESS; + result.length = MAX_ALLOCATION_ADDRESS - result.start; + result.permissions = memory_permission::none; + result.allocation_base = {}; + result.allocation_length = result.length; + result.is_committed = false; + result.is_reserved = false; - if (this->reserved_regions_.empty()) - { - return result; - } + if (this->reserved_regions_.empty()) + { + return result; + } - auto upper_bound = this->reserved_regions_.upper_bound(address); - if (upper_bound == this->reserved_regions_.begin()) - { - result.length = upper_bound->first - result.start; - return result; - } + auto upper_bound = this->reserved_regions_.upper_bound(address); + if (upper_bound == this->reserved_regions_.begin()) + { + result.length = upper_bound->first - result.start; + return result; + } - const auto entry = --upper_bound; - const auto lower_end = entry->first + entry->second.length; - if (lower_end <= address) - { - result.start = lower_end; - result.length = MAX_ALLOCATION_ADDRESS - result.start; - return result; - } + const auto entry = --upper_bound; + const auto lower_end = entry->first + entry->second.length; + if (lower_end <= address) + { + result.start = lower_end; + result.length = MAX_ALLOCATION_ADDRESS - result.start; + return result; + } - // We have a reserved region - const auto& reserved_region = entry->second; - const auto& committed_regions = reserved_region.committed_regions; + // We have a reserved region + const auto& reserved_region = entry->second; + const auto& committed_regions = reserved_region.committed_regions; - result.is_reserved = true; - result.allocation_base = entry->first; - result.allocation_length = reserved_region.length; - result.start = result.allocation_base; - result.length = result.allocation_length; + result.is_reserved = true; + result.allocation_base = entry->first; + result.allocation_length = reserved_region.length; + result.start = result.allocation_base; + result.length = result.allocation_length; - if (committed_regions.empty()) - { - return result; - } + if (committed_regions.empty()) + { + return result; + } - auto committed_bound = committed_regions.upper_bound(address); - if (committed_bound == committed_regions.begin()) - { - result.length = committed_bound->first - result.start; - return result; - } + auto committed_bound = committed_regions.upper_bound(address); + if (committed_bound == committed_regions.begin()) + { + result.length = committed_bound->first - result.start; + return result; + } - const auto committed_entry = --committed_bound; - const auto committed_lower_end = committed_entry->first + committed_entry->second.length; - if (committed_lower_end <= address) - { - result.start = committed_lower_end; - result.length = lower_end - result.start; - return result; - } + const auto committed_entry = --committed_bound; + const auto committed_lower_end = committed_entry->first + committed_entry->second.length; + if (committed_lower_end <= address) + { + result.start = committed_lower_end; + result.length = lower_end - result.start; + return result; + } - result.is_committed = true; - result.start = committed_entry->first; - result.length = committed_entry->second.length; - result.permissions = committed_entry->second.pemissions; + result.is_committed = true; + result.start = committed_entry->first; + result.length = committed_entry->second.length; + result.permissions = committed_entry->second.pemissions; - return result; + return result; } memory_manager::reserved_region_map::iterator memory_manager::find_reserved_region(const uint64_t address) { - if (this->reserved_regions_.empty()) - { - return this->reserved_regions_.end(); - } + if (this->reserved_regions_.empty()) + { + return this->reserved_regions_.end(); + } - auto upper_bound = this->reserved_regions_.upper_bound(address); - if (upper_bound == this->reserved_regions_.begin()) - { - return this->reserved_regions_.end(); - } + auto upper_bound = this->reserved_regions_.upper_bound(address); + if (upper_bound == this->reserved_regions_.begin()) + { + return this->reserved_regions_.end(); + } - const auto entry = --upper_bound; - if (entry->first + entry->second.length <= address) - { - return this->reserved_regions_.end(); - } + const auto entry = --upper_bound; + if (entry->first + entry->second.length <= address) + { + return this->reserved_regions_.end(); + } - return entry; + return entry; } bool memory_manager::overlaps_reserved_region(const uint64_t address, const size_t size) const { - for (const auto& region : this->reserved_regions_) - { - if (regions_with_length_intersect(address, size, region.first, region.second.length)) - { - return true; - } - } + for (const auto& region : this->reserved_regions_) + { + if (regions_with_length_intersect(address, size, region.first, region.second.length)) + { + return true; + } + } - return false; + return false; } diff --git a/src/emulator/memory_manager.hpp b/src/emulator/memory_manager.hpp index 0d7bbb98..6c22f666 100644 --- a/src/emulator/memory_manager.hpp +++ b/src/emulator/memory_manager.hpp @@ -7,10 +7,10 @@ struct region_info : basic_memory_region { - uint64_t allocation_base{}; - size_t allocation_length{}; - bool is_reserved{}; - bool is_committed{}; + uint64_t allocation_base{}; + size_t allocation_length{}; + bool is_reserved{}; + bool is_committed{}; }; using mmio_read_callback = std::function; @@ -18,115 +18,114 @@ using mmio_write_callback = std::function; + using committed_region_map = std::map; - struct reserved_region - { - size_t length{}; - committed_region_map committed_regions{}; - bool is_mmio{false}; - }; + struct reserved_region + { + size_t length{}; + committed_region_map committed_regions{}; + bool is_mmio{false}; + }; - virtual ~memory_manager() = default; + virtual ~memory_manager() = default; - template - T read_memory(const uint64_t address) const - { - T value{}; - this->read_memory(address, &value, sizeof(value)); - return value; - } + template + T read_memory(const uint64_t address) const + { + T value{}; + this->read_memory(address, &value, sizeof(value)); + return value; + } - template - T read_memory(const void* address) const - { - return this->read_memory(reinterpret_cast(address)); - } + template + T read_memory(const void* address) const + { + return this->read_memory(reinterpret_cast(address)); + } - std::vector read_memory(const uint64_t address, const size_t size) const - { - std::vector data{}; - data.resize(size); + std::vector read_memory(const uint64_t address, const size_t size) const + { + std::vector data{}; + data.resize(size); - this->read_memory(address, data.data(), data.size()); + this->read_memory(address, data.data(), data.size()); - return data; - } + return data; + } - std::vector read_memory(const void* address, const size_t size) const - { - return this->read_memory(reinterpret_cast(address), size); - } + std::vector read_memory(const void* address, const size_t size) const + { + return this->read_memory(reinterpret_cast(address), size); + } - template - void write_memory(const uint64_t address, const T& value) - { - this->write_memory(address, &value, sizeof(value)); - } + template + void write_memory(const uint64_t address, const T& value) + { + this->write_memory(address, &value, sizeof(value)); + } - template - void write_memory(void* address, const T& value) - { - this->write_memory(reinterpret_cast(address), &value, sizeof(value)); - } + template + void write_memory(void* address, const T& value) + { + this->write_memory(reinterpret_cast(address), &value, sizeof(value)); + } - void write_memory(void* address, const void* data, const size_t size) - { - this->write_memory(reinterpret_cast(address), data, size); - } + void write_memory(void* address, const void* data, const size_t size) + { + this->write_memory(reinterpret_cast(address), data, size); + } - virtual void read_memory(uint64_t address, void* data, size_t size) const = 0; - virtual bool try_read_memory(uint64_t address, void* data, size_t size) const = 0; - virtual void write_memory(uint64_t address, const void* data, size_t size) = 0; + virtual void read_memory(uint64_t address, void* data, size_t size) const = 0; + virtual bool try_read_memory(uint64_t address, void* data, size_t size) const = 0; + virtual void write_memory(uint64_t address, const void* data, size_t size) = 0; - bool protect_memory(uint64_t address, size_t size, memory_permission permissions, - memory_permission* old_permissions = nullptr); + bool protect_memory(uint64_t address, size_t size, memory_permission permissions, + memory_permission* old_permissions = nullptr); - bool allocate_mmio(uint64_t address, size_t size, mmio_read_callback read_cb, mmio_write_callback write_cb); - bool allocate_memory(uint64_t address, size_t size, memory_permission permissions, - bool reserve_only = false); + bool allocate_mmio(uint64_t address, size_t size, mmio_read_callback read_cb, mmio_write_callback write_cb); + bool allocate_memory(uint64_t address, size_t size, memory_permission permissions, bool reserve_only = false); - bool commit_memory(uint64_t address, size_t size, memory_permission permissions); - bool decommit_memory(uint64_t address, size_t size); + bool commit_memory(uint64_t address, size_t size, memory_permission permissions); + bool decommit_memory(uint64_t address, size_t size); - bool release_memory(uint64_t address, size_t size); + bool release_memory(uint64_t address, size_t size); - uint64_t find_free_allocation_base(size_t size, uint64_t start = 0) const; + uint64_t find_free_allocation_base(size_t size, uint64_t start = 0) const; - region_info get_region_info(uint64_t address); + region_info get_region_info(uint64_t address); - uint64_t allocate_memory(const size_t size, const memory_permission permissions, const bool reserve_only = false) - { - const auto allocation_base = this->find_free_allocation_base(size); - if (!allocate_memory(allocation_base, size, permissions, reserve_only)) - { - return 0; - } + uint64_t allocate_memory(const size_t size, const memory_permission permissions, const bool reserve_only = false) + { + const auto allocation_base = this->find_free_allocation_base(size); + if (!allocate_memory(allocation_base, size, permissions, reserve_only)) + { + return 0; + } - return allocation_base; - } + return allocation_base; + } -private: - using reserved_region_map = std::map; - reserved_region_map reserved_regions_{}; + private: + using reserved_region_map = std::map; + reserved_region_map reserved_regions_{}; - reserved_region_map::iterator find_reserved_region(uint64_t address); - bool overlaps_reserved_region(uint64_t address, size_t size) const; + reserved_region_map::iterator find_reserved_region(uint64_t address); + bool overlaps_reserved_region(uint64_t address, size_t size) const; - virtual void map_mmio(uint64_t address, size_t size, mmio_read_callback read_cb, mmio_write_callback write_cb) = 0; - virtual void map_memory(uint64_t address, size_t size, memory_permission permissions) = 0; - virtual void unmap_memory(uint64_t address, size_t size) = 0; + virtual void map_mmio(uint64_t address, size_t size, mmio_read_callback read_cb, mmio_write_callback write_cb) = 0; + virtual void map_memory(uint64_t address, size_t size, memory_permission permissions) = 0; + virtual void unmap_memory(uint64_t address, size_t size) = 0; - virtual void apply_memory_protection(uint64_t address, size_t size, memory_permission permissions) = 0; + virtual void apply_memory_protection(uint64_t address, size_t size, memory_permission permissions) = 0; -protected: - void serialize_memory_state(utils::buffer_serializer& buffer, bool is_snapshot) const; - void deserialize_memory_state(utils::buffer_deserializer& buffer, bool is_snapshot); + protected: + void serialize_memory_state(utils::buffer_serializer& buffer, bool is_snapshot) const; + void deserialize_memory_state(utils::buffer_deserializer& buffer, bool is_snapshot); }; diff --git a/src/emulator/memory_permission.hpp b/src/emulator/memory_permission.hpp index 4eca4171..4c044563 100644 --- a/src/emulator/memory_permission.hpp +++ b/src/emulator/memory_permission.hpp @@ -3,62 +3,52 @@ enum class memory_permission : uint8_t { - none = 0, - read = 1 << 0, - write = 1 << 1, - exec = 1 << 2, - read_write = read | write, - all = read | write | exec + none = 0, + read = 1 << 0, + write = 1 << 1, + exec = 1 << 2, + read_write = read | write, + all = read | write | exec }; /***************************************************************************** * ****************************************************************************/ -inline constexpr memory_permission -operator&(const memory_permission x, const memory_permission y) +inline constexpr memory_permission operator&(const memory_permission x, const memory_permission y) { - return static_cast - (static_cast(x) & static_cast(y)); + return static_cast(static_cast(x) & static_cast(y)); } -inline constexpr memory_permission -operator|(const memory_permission x, const memory_permission y) +inline constexpr memory_permission operator|(const memory_permission x, const memory_permission y) { - return static_cast - (static_cast(x) | static_cast(y)); + return static_cast(static_cast(x) | static_cast(y)); } -inline constexpr memory_permission -operator^(const memory_permission x, const memory_permission y) +inline constexpr memory_permission operator^(const memory_permission x, const memory_permission y) { - return static_cast - (static_cast(x) ^ static_cast(y)); + return static_cast(static_cast(x) ^ static_cast(y)); } -inline constexpr memory_permission -operator~(memory_permission x) +inline constexpr memory_permission operator~(memory_permission x) { - return static_cast(~static_cast(x)); + return static_cast(~static_cast(x)); } -inline memory_permission& -operator&=(memory_permission& x, const memory_permission y) +inline memory_permission& operator&=(memory_permission& x, const memory_permission y) { - x = x & y; - return x; + x = x & y; + return x; } -inline memory_permission& -operator|=(memory_permission& x, const memory_permission y) +inline memory_permission& operator|=(memory_permission& x, const memory_permission y) { - x = x | y; - return x; + x = x | y; + return x; } -inline memory_permission& -operator^=(memory_permission& x, const memory_permission y) +inline memory_permission& operator^=(memory_permission& x, const memory_permission y) { - x = x ^ y; - return x; + x = x ^ y; + return x; } diff --git a/src/emulator/memory_region.hpp b/src/emulator/memory_region.hpp index 880f3666..486bb27f 100644 --- a/src/emulator/memory_region.hpp +++ b/src/emulator/memory_region.hpp @@ -4,12 +4,12 @@ struct basic_memory_region { - uint64_t start{}; - size_t length{}; - memory_permission permissions{}; + uint64_t start{}; + size_t length{}; + memory_permission permissions{}; }; struct memory_region : basic_memory_region { - bool committed{}; + bool committed{}; }; diff --git a/src/emulator/scoped_hook.hpp b/src/emulator/scoped_hook.hpp index 610c57ec..188eeea3 100644 --- a/src/emulator/scoped_hook.hpp +++ b/src/emulator/scoped_hook.hpp @@ -3,52 +3,52 @@ class scoped_hook { -public: - scoped_hook() = default; + public: + scoped_hook() = default; - scoped_hook(emulator& emu, emulator_hook* hook) - : emu_(&emu) - , hook_(hook) - { - } + scoped_hook(emulator& emu, emulator_hook* hook) + : emu_(&emu), + hook_(hook) + { + } - ~scoped_hook() - { - this->remove(); - } + ~scoped_hook() + { + this->remove(); + } - scoped_hook(const scoped_hook&) = delete; - scoped_hook& operator=(const scoped_hook&) = delete; + scoped_hook(const scoped_hook&) = delete; + scoped_hook& operator=(const scoped_hook&) = delete; - scoped_hook(scoped_hook&& obj) noexcept - { - this->operator=(std::move(obj)); - } + scoped_hook(scoped_hook&& obj) noexcept + { + this->operator=(std::move(obj)); + } - scoped_hook& operator=(scoped_hook&& obj) noexcept - { - if (this != &obj) - { - this->remove(); - this->emu_ = obj.emu_; - this->hook_ = obj.hook_; + scoped_hook& operator=(scoped_hook&& obj) noexcept + { + if (this != &obj) + { + this->remove(); + this->emu_ = obj.emu_; + this->hook_ = obj.hook_; - obj.hook_ = {}; - } + obj.hook_ = {}; + } - return *this; - } + return *this; + } - void remove() - { - if (this->hook_) - { - this->emu_->delete_hook(this->hook_); - this->hook_ = {}; - } - } + void remove() + { + if (this->hook_) + { + this->emu_->delete_hook(this->hook_); + this->hook_ = {}; + } + } -private: - emulator* emu_{}; - emulator_hook* hook_{}; + private: + emulator* emu_{}; + emulator_hook* hook_{}; }; diff --git a/src/emulator/serialization.hpp b/src/emulator/serialization.hpp index e86894db..1b6a8333 100644 --- a/src/emulator/serialization.hpp +++ b/src/emulator/serialization.hpp @@ -11,488 +11,483 @@ namespace utils { - class buffer_serializer; - class buffer_deserializer; + class buffer_serializer; + class buffer_deserializer; - template - concept Serializable = requires(T a, const T ac, buffer_serializer& serializer, buffer_deserializer& deserializer) - { - { ac.serialize(serializer) } -> std::same_as; - { a.deserialize(deserializer) } -> std::same_as; - }; + template + concept Serializable = requires(T a, const T ac, buffer_serializer& serializer, buffer_deserializer& deserializer) { + { ac.serialize(serializer) } -> std::same_as; + { a.deserialize(deserializer) } -> std::same_as; + }; - /* Use concept instead, to prevent overhead of virtual function calls - struct serializable - { - virtual ~serializable() = default; - virtual void serialize(buffer_serializer& buffer) const = 0; - virtual void deserialize(buffer_deserializer& buffer) = 0; - }; - */ + /* Use concept instead, to prevent overhead of virtual function calls + struct serializable + { + virtual ~serializable() = default; + virtual void serialize(buffer_serializer& buffer) const = 0; + virtual void deserialize(buffer_deserializer& buffer) = 0; + }; + */ - namespace detail - { - template - struct has_serialize_function : std::false_type - { - }; + namespace detail + { + template + struct has_serialize_function : std::false_type + { + }; - template - struct has_serialize_function(), - std::declval&>()) - )>> - : std::true_type - { - }; + template + struct has_serialize_function(), + std::declval&>()))>> + : std::true_type + { + }; - template - struct has_deserialize_function : std::false_type - { - }; + template + struct has_deserialize_function : std::false_type + { + }; - template - struct has_deserialize_function(), - std::declval&>()))>> - : std::true_type - { - }; + template + struct has_deserialize_function(), + std::declval&>()))>> + : std::true_type + { + }; - template - struct has_deserializer_constructor - : std::bool_constant> - { - }; - } + template + struct has_deserializer_constructor : std::bool_constant> + { + }; + } - class buffer_deserializer - { - public: - template - buffer_deserializer(const std::span buffer, bool no_debugging = false) - : no_debugging_(no_debugging) - , buffer_(reinterpret_cast(buffer.data()), buffer.size() * sizeof(T)) - { - static_assert(std::is_trivially_copyable_v, "Type must be trivially copyable"); - } + class buffer_deserializer + { + public: + template + buffer_deserializer(const std::span buffer, bool no_debugging = false) + : no_debugging_(no_debugging), + buffer_(reinterpret_cast(buffer.data()), buffer.size() * sizeof(T)) + { + static_assert(std::is_trivially_copyable_v, "Type must be trivially copyable"); + } - template - buffer_deserializer(const std::vector& buffer, bool no_debugging = false) - : buffer_deserializer(std::span(buffer), no_debugging) - { - } + template + buffer_deserializer(const std::vector& buffer, bool no_debugging = false) + : buffer_deserializer(std::span(buffer), no_debugging) + { + } - std::span read_data(const size_t length) - { + std::span read_data(const size_t length) + { #ifndef NDEBUG - const uint64_t real_old_size = this->offset_; - (void)real_old_size; + const uint64_t real_old_size = this->offset_; + (void)real_old_size; #endif - if (this->offset_ + length > this->buffer_.size()) - { - throw std::runtime_error("Out of bounds read from byte buffer"); - } + if (this->offset_ + length > this->buffer_.size()) + { + throw std::runtime_error("Out of bounds read from byte buffer"); + } - const std::span result(this->buffer_.data() + this->offset_, length); - this->offset_ += length; + const std::span result(this->buffer_.data() + this->offset_, length); + this->offset_ += length; - (void)this->no_debugging_; + (void)this->no_debugging_; #ifndef NDEBUG - if (!this->no_debugging_) - { - uint64_t old_size{}; - if (this->offset_ + sizeof(old_size) > this->buffer_.size()) - { - throw std::runtime_error("Out of bounds read from byte buffer"); - } + if (!this->no_debugging_) + { + uint64_t old_size{}; + if (this->offset_ + sizeof(old_size) > this->buffer_.size()) + { + throw std::runtime_error("Out of bounds read from byte buffer"); + } - memcpy(&old_size, this->buffer_.data() + this->offset_, sizeof(old_size)); - if (old_size != real_old_size) - { - throw std::runtime_error("Reading from serialized buffer mismatches written data!"); - } + memcpy(&old_size, this->buffer_.data() + this->offset_, sizeof(old_size)); + if (old_size != real_old_size) + { + throw std::runtime_error("Reading from serialized buffer mismatches written data!"); + } - this->offset_ += sizeof(old_size); - } + this->offset_ += sizeof(old_size); + } #endif - return result; - } + return result; + } - void read(void* data, const size_t length) - { - const auto span = this->read_data(length); - memcpy(data, span.data(), length); - } + void read(void* data, const size_t length) + { + const auto span = this->read_data(length); + memcpy(data, span.data(), length); + } - template - void read(T& object) - { - constexpr auto is_trivially_copyable = std::is_trivially_copyable_v; + template + void read(T& object) + { + constexpr auto is_trivially_copyable = std::is_trivially_copyable_v; - if constexpr (Serializable) - { - object.deserialize(*this); - } - else if constexpr (detail::has_deserialize_function::value) - { - deserialize(*this, object); - } - else if constexpr (is_trivially_copyable) - { - union - { - T* type_{}; - void* void_; - } pointers; + if constexpr (Serializable) + { + object.deserialize(*this); + } + else if constexpr (detail::has_deserialize_function::value) + { + deserialize(*this, object); + } + else if constexpr (is_trivially_copyable) + { + union + { + T* type_{}; + void* void_; + } pointers; - pointers.type_ = &object; + pointers.type_ = &object; - this->read(pointers.void_, sizeof(object)); - } - else - { - static_assert(!is_trivially_copyable, "Key must be trivially copyable or implement serializable!"); - std::abort(); - } - } + this->read(pointers.void_, sizeof(object)); + } + else + { + static_assert(!is_trivially_copyable, "Key must be trivially copyable or implement serializable!"); + std::abort(); + } + } - template - T read() - { - auto object = this->construct_object(); - this->read(object); - return object; - } + template + T read() + { + auto object = this->construct_object(); + this->read(object); + return object; + } - template - void read_optional(std::optional& val) - { - if (this->read()) - { - val.emplace(this->read()); - } - else - { - val = std::nullopt; - } - } + template + void read_optional(std::optional& val) + { + if (this->read()) + { + val.emplace(this->read()); + } + else + { + val = std::nullopt; + } + } - template - requires(std::is_invocable_r_v) - void read_optional(std::optional& val, const F& factory) - { - if (this->read()) - { - val.emplace(factory()); - this->read(*val); - } - else - { - val = {}; - } - } + template + requires(std::is_invocable_r_v) + void read_optional(std::optional& val, const F& factory) + { + if (this->read()) + { + val.emplace(factory()); + this->read(*val); + } + else + { + val = {}; + } + } - template - void read_vector(std::vector& result) - { - const auto size = this->read(); - result.clear(); - result.reserve(size); + template + void read_vector(std::vector& result) + { + const auto size = this->read(); + result.clear(); + result.reserve(size); - for (uint64_t i = 0; i < size; ++i) - { - result.emplace_back(this->read()); - } - } + for (uint64_t i = 0; i < size; ++i) + { + result.emplace_back(this->read()); + } + } - template - std::vector read_vector() - { - std::vector result{}; - this->read_vector(result); - return result; - } + template + std::vector read_vector() + { + std::vector result{}; + this->read_vector(result); + return result; + } - template - void read_map(Map& map) - { - using key_type = typename Map::key_type; - using value_type = typename Map::mapped_type; + template + void read_map(Map& map) + { + using key_type = typename Map::key_type; + using value_type = typename Map::mapped_type; - map.clear(); + map.clear(); - const auto size = this->read(); + const auto size = this->read(); - for (uint64_t i = 0; i < size; ++i) - { - auto key = this->read(); - auto value = this->read(); + for (uint64_t i = 0; i < size; ++i) + { + auto key = this->read(); + auto value = this->read(); - map.emplace(std::move(key), std::move(value)); - } - } + map.emplace(std::move(key), std::move(value)); + } + } - template - Map read_map() - { - Map map{}; - this->read_map(map); - return map; - } + template + Map read_map() + { + Map map{}; + this->read_map(map); + return map; + } - template - void read_string(std::basic_string& result) - { - const auto size = this->read(); + template + void read_string(std::basic_string& result) + { + const auto size = this->read(); - result.clear(); - result.reserve(size); + result.clear(); + result.reserve(size); - for (uint64_t i = 0; i < size; ++i) - { - result.push_back(this->read()); - } - } + for (uint64_t i = 0; i < size; ++i) + { + result.push_back(this->read()); + } + } - template - std::basic_string read_string() - { - std::basic_string result{}; - this->read_string(result); - return result; - } + template + std::basic_string read_string() + { + std::basic_string result{}; + this->read_string(result); + return result; + } - size_t get_remaining_size() const - { - return this->buffer_.size() - offset_; - } + size_t get_remaining_size() const + { + return this->buffer_.size() - offset_; + } - std::span get_remaining_data() - { - return this->read_data(this->get_remaining_size()); - } + std::span get_remaining_data() + { + return this->read_data(this->get_remaining_size()); + } - size_t get_offset() const - { - return this->offset_; - } + size_t get_offset() const + { + return this->offset_; + } - template - requires(std::is_invocable_r_v) - void register_factory(F factory) - { - this->factories_[std::type_index(typeid(T))] = [f = std::move(factory)]() -> T* { - return new T(f()); - }; - } + template + requires(std::is_invocable_r_v) + void register_factory(F factory) + { + this->factories_[std::type_index(typeid(T))] = [f = std::move(factory)]() -> T* { return new T(f()); }; + } - private: - bool no_debugging_{false}; - size_t offset_{0}; - std::span buffer_{}; - std::unordered_map> factories_{}; + private: + bool no_debugging_{false}; + size_t offset_{0}; + std::span buffer_{}; + std::unordered_map> factories_{}; - template - T construct_object() - { - if constexpr (detail::has_deserializer_constructor::value) - { - return T(*this); - } - else if constexpr (std::is_default_constructible_v) - { - return {}; - } - else - { - const auto factory = this->factories_.find(std::type_index(typeid(T))); - if (factory == this->factories_.end()) - { - throw std::runtime_error( - "Object construction failed. Missing factory for type: " + std::string(typeid(T).name())); - } + template + T construct_object() + { + if constexpr (detail::has_deserializer_constructor::value) + { + return T(*this); + } + else if constexpr (std::is_default_constructible_v) + { + return {}; + } + else + { + const auto factory = this->factories_.find(std::type_index(typeid(T))); + if (factory == this->factories_.end()) + { + throw std::runtime_error("Object construction failed. Missing factory for type: " + + std::string(typeid(T).name())); + } - auto* object = static_cast(factory->second()); - auto obj = std::move(*object); - delete object; + auto* object = static_cast(factory->second()); + auto obj = std::move(*object); + delete object; - return obj; - } - } - }; + return obj; + } + } + }; - class buffer_serializer - { - public: - buffer_serializer() = default; + class buffer_serializer + { + public: + buffer_serializer() = default; - void write(const void* buffer, const size_t length) - { + void write(const void* buffer, const size_t length) + { #ifndef NDEBUG - const uint64_t old_size = this->buffer_.size(); + const uint64_t old_size = this->buffer_.size(); #endif - const auto* byte_buffer = static_cast(buffer); - this->buffer_.insert(this->buffer_.end(), byte_buffer, byte_buffer + length); + const auto* byte_buffer = static_cast(buffer); + this->buffer_.insert(this->buffer_.end(), byte_buffer, byte_buffer + length); #ifndef NDEBUG - const auto* security_buffer = reinterpret_cast(&old_size); - this->buffer_.insert(this->buffer_.end(), security_buffer, security_buffer + sizeof(old_size)); + const auto* security_buffer = reinterpret_cast(&old_size); + this->buffer_.insert(this->buffer_.end(), security_buffer, security_buffer + sizeof(old_size)); #endif - } + } - void write(const buffer_serializer& object) - { - const auto& buffer = object.get_buffer(); - this->write(buffer.data(), buffer.size()); - } + void write(const buffer_serializer& object) + { + const auto& buffer = object.get_buffer(); + this->write(buffer.data(), buffer.size()); + } - template - void write(const T& object) - { - constexpr auto is_trivially_copyable = std::is_trivially_copyable_v; + template + void write(const T& object) + { + constexpr auto is_trivially_copyable = std::is_trivially_copyable_v; - if constexpr (Serializable) - { - object.serialize(*this); - } - else if constexpr (detail::has_serialize_function::value) - { - serialize(*this, object); - } - else if constexpr (is_trivially_copyable) - { - union - { - const T* type_{}; - const void* void_; - } pointers; + if constexpr (Serializable) + { + object.serialize(*this); + } + else if constexpr (detail::has_serialize_function::value) + { + serialize(*this, object); + } + else if constexpr (is_trivially_copyable) + { + union + { + const T* type_{}; + const void* void_; + } pointers; - pointers.type_ = &object; + pointers.type_ = &object; - this->write(pointers.void_, sizeof(object)); - } - else - { - static_assert(!is_trivially_copyable, "Key must be trivially copyable or implement serializable!"); - std::abort(); - } - } + this->write(pointers.void_, sizeof(object)); + } + else + { + static_assert(!is_trivially_copyable, "Key must be trivially copyable or implement serializable!"); + std::abort(); + } + } - template - void write_optional(const std::optional& val) - { - this->write(val.has_value()); + template + void write_optional(const std::optional& val) + { + this->write(val.has_value()); - if (val.has_value()) - { - this->write(*val); - } - } + if (val.has_value()) + { + this->write(*val); + } + } - template - void write_span(const std::span vec) - { - this->write(static_cast(vec.size())); + template + void write_span(const std::span vec) + { + this->write(static_cast(vec.size())); - for (const auto& v : vec) - { - this->write(v); - } - } + for (const auto& v : vec) + { + this->write(v); + } + } - template - void write_vector(const std::vector vec) - { - this->write_span(std::span(vec)); - } + template + void write_vector(const std::vector vec) + { + this->write_span(std::span(vec)); + } - template - void write_string(const std::basic_string_view str) - { - this->write_span(str); - } + template + void write_string(const std::basic_string_view str) + { + this->write_span(str); + } - template - void write_string(const std::basic_string& str) - { - this->write_string(std::basic_string_view(str)); - } + template + void write_string(const std::basic_string& str) + { + this->write_string(std::basic_string_view(str)); + } - template - void write_map(const Map& map) - { - this->write(map.size()); + template + void write_map(const Map& map) + { + this->write(map.size()); - for (const auto& entry : map) - { - this->write(entry.first); - this->write(entry.second); - } - } + for (const auto& entry : map) + { + this->write(entry.first); + this->write(entry.second); + } + } - const std::vector& get_buffer() const - { - return this->buffer_; - } + const std::vector& get_buffer() const + { + return this->buffer_; + } - std::vector move_buffer() - { - return std::move(this->buffer_); - } + std::vector move_buffer() + { + return std::move(this->buffer_); + } - private: - std::vector buffer_{}; - }; + private: + std::vector buffer_{}; + }; - template <> - inline void buffer_deserializer::read(bool& object) - { - object = this->read() != 0; - } + template <> + inline void buffer_deserializer::read(bool& object) + { + object = this->read() != 0; + } - template <> - inline void buffer_deserializer::read(std::string& object) - { - object = this->read_string(); - } + template <> + inline void buffer_deserializer::read(std::string& object) + { + object = this->read_string(); + } - template <> - inline void buffer_deserializer::read(std::wstring& object) - { - object = this->read_string(); - } + template <> + inline void buffer_deserializer::read(std::wstring& object) + { + object = this->read_string(); + } - template <> - inline void buffer_deserializer::read(std::u16string& object) - { - object = this->read_string(); - } + template <> + inline void buffer_deserializer::read(std::u16string& object) + { + object = this->read_string(); + } - template <> - inline void buffer_serializer::write(const bool& object) - { - this->write(object ? 1 : 0); - } + template <> + inline void buffer_serializer::write(const bool& object) + { + this->write(object ? 1 : 0); + } - template <> - inline void buffer_serializer::write(const std::string& object) - { - this->write_string(object); - } + template <> + inline void buffer_serializer::write(const std::string& object) + { + this->write_string(object); + } - template <> - inline void buffer_serializer::write(const std::wstring& object) - { - this->write_string(object); - } + template <> + inline void buffer_serializer::write(const std::wstring& object) + { + this->write_string(object); + } - template <> - inline void buffer_serializer::write(const std::u16string& object) - { - this->write_string(object); - } + template <> + inline void buffer_serializer::write(const std::u16string& object) + { + this->write_string(object); + } } diff --git a/src/emulator/serialization_helper.hpp b/src/emulator/serialization_helper.hpp index 0d6f58d2..021855ef 100644 --- a/src/emulator/serialization_helper.hpp +++ b/src/emulator/serialization_helper.hpp @@ -7,41 +7,41 @@ namespace utils { - inline void serialize(buffer_serializer& buffer, const std::chrono::steady_clock::time_point& tp) - { - buffer.write(tp.time_since_epoch().count()); - } + inline void serialize(buffer_serializer& buffer, const std::chrono::steady_clock::time_point& tp) + { + buffer.write(tp.time_since_epoch().count()); + } - inline void deserialize(buffer_deserializer& buffer, std::chrono::steady_clock::time_point& tp) - { - using time_point = std::chrono::steady_clock::time_point; - using duration = time_point::duration; + inline void deserialize(buffer_deserializer& buffer, std::chrono::steady_clock::time_point& tp) + { + using time_point = std::chrono::steady_clock::time_point; + using duration = time_point::duration; - const auto count = buffer.read(); - tp = time_point{duration{count}}; - } + const auto count = buffer.read(); + tp = time_point{duration{count}}; + } - inline void serialize(buffer_serializer& buffer, const std::chrono::system_clock::time_point& tp) - { - buffer.write(tp.time_since_epoch().count()); - } + inline void serialize(buffer_serializer& buffer, const std::chrono::system_clock::time_point& tp) + { + buffer.write(tp.time_since_epoch().count()); + } - inline void deserialize(buffer_deserializer& buffer, std::chrono::system_clock::time_point& tp) - { - using time_point = std::chrono::system_clock::time_point; - using duration = time_point::duration; + inline void deserialize(buffer_deserializer& buffer, std::chrono::system_clock::time_point& tp) + { + using time_point = std::chrono::system_clock::time_point; + using duration = time_point::duration; - const auto count = buffer.read(); - tp = time_point{duration{count}}; - } + const auto count = buffer.read(); + tp = time_point{duration{count}}; + } - inline void serialize(buffer_serializer& buffer, const std::filesystem::path& path) - { - buffer.write_string(path.u16string()); - } + inline void serialize(buffer_serializer& buffer, const std::filesystem::path& path) + { + buffer.write_string(path.u16string()); + } - inline void deserialize(buffer_deserializer& buffer, std::filesystem::path& path) - { - path = buffer.read_string(); - } + inline void deserialize(buffer_deserializer& buffer, std::filesystem::path& path) + { + path = buffer.read_string(); + } } diff --git a/src/emulator/typed_emulator.hpp b/src/emulator/typed_emulator.hpp index 078b2e32..d7224940 100644 --- a/src/emulator/typed_emulator.hpp +++ b/src/emulator/typed_emulator.hpp @@ -2,94 +2,94 @@ #include "emulator.hpp" -template +template class typed_emulator : public emulator { -public: - using registers = Register; - using pointer_type = PointerType; - using hookable_instructions = HookableInstructions; + public: + using registers = Register; + using pointer_type = PointerType; + using hookable_instructions = HookableInstructions; - static constexpr size_t pointer_size = sizeof(pointer_type); - static constexpr registers stack_pointer = StackPointer; - static constexpr registers instruction_pointer = InstructionPointer; + static constexpr size_t pointer_size = sizeof(pointer_type); + static constexpr registers stack_pointer = StackPointer; + static constexpr registers instruction_pointer = InstructionPointer; - void start_from_ip(const std::chrono::nanoseconds timeout = {}, const size_t count = 0) - { - this->start(this->read_instruction_pointer(), 0, timeout, count); - } + void start_from_ip(const std::chrono::nanoseconds timeout = {}, const size_t count = 0) + { + this->start(this->read_instruction_pointer(), 0, timeout, count); + } - void write_register(registers reg, const void* value, const size_t size) - { - this->write_raw_register(static_cast(reg), value, size); - } + void write_register(registers reg, const void* value, const size_t size) + { + this->write_raw_register(static_cast(reg), value, size); + } - void read_register(registers reg, void* value, const size_t size) - { - this->read_raw_register(static_cast(reg), value, size); - } + void read_register(registers reg, void* value, const size_t size) + { + this->read_raw_register(static_cast(reg), value, size); + } - template - T reg(const registers regid) - { - T value{}; - this->read_register(regid, &value, sizeof(value)); - return value; - } + template + T reg(const registers regid) + { + T value{}; + this->read_register(regid, &value, sizeof(value)); + return value; + } - template - void reg(const registers regid, const S& maybe_value) - { - T value = static_cast(maybe_value); - this->write_register(regid, &value, sizeof(value)); - } + template + void reg(const registers regid, const S& maybe_value) + { + T value = static_cast(maybe_value); + this->write_register(regid, &value, sizeof(value)); + } - pointer_type read_instruction_pointer() - { - return this->reg(instruction_pointer); - } + pointer_type read_instruction_pointer() + { + return this->reg(instruction_pointer); + } - pointer_type read_stack_pointer() - { - return this->reg(stack_pointer); - } + pointer_type read_stack_pointer() + { + return this->reg(stack_pointer); + } - pointer_type read_stack(const size_t index) - { - pointer_type result{}; - const auto sp = this->read_stack_pointer(); + pointer_type read_stack(const size_t index) + { + pointer_type result{}; + const auto sp = this->read_stack_pointer(); - this->read_memory(sp + (index * pointer_size), &result, sizeof(result)); + this->read_memory(sp + (index * pointer_size), &result, sizeof(result)); - return result; - } + return result; + } - void push_stack(const pointer_type& value) - { - const auto sp = this->read_stack_pointer() - pointer_size; - this->reg(stack_pointer, sp); - this->write_memory(sp, &value, sizeof(value)); - } + void push_stack(const pointer_type& value) + { + const auto sp = this->read_stack_pointer() - pointer_size; + this->reg(stack_pointer, sp); + this->write_memory(sp, &value, sizeof(value)); + } - pointer_type pop_stack() - { - pointer_type result{}; - const auto sp = this->read_stack_pointer(); - this->read_memory(sp, &result, sizeof(result)); - this->reg(stack_pointer, sp + pointer_size); + pointer_type pop_stack() + { + pointer_type result{}; + const auto sp = this->read_stack_pointer(); + this->read_memory(sp, &result, sizeof(result)); + this->reg(stack_pointer, sp + pointer_size); - return result; - } + return result; + } - emulator_hook* hook_instruction(hookable_instructions instruction_type, instruction_hook_callback callback) - { - return this->hook_instruction(static_cast(instruction_type), std::move(callback)); - } + emulator_hook* hook_instruction(hookable_instructions instruction_type, instruction_hook_callback callback) + { + return this->hook_instruction(static_cast(instruction_type), std::move(callback)); + } -private: - emulator_hook* hook_instruction(int instruction_type, instruction_hook_callback callback) override = 0; + private: + emulator_hook* hook_instruction(int instruction_type, instruction_hook_callback callback) override = 0; - void read_raw_register(int reg, void* value, size_t size) override = 0; - void write_raw_register(int reg, const void* value, size_t size) override = 0; + void read_raw_register(int reg, void* value, size_t size) override = 0; + void write_raw_register(int reg, const void* value, size_t size) override = 0; }; diff --git a/src/emulator/x64_emulator.hpp b/src/emulator/x64_emulator.hpp index 6514c1d0..b77882b9 100644 --- a/src/emulator/x64_emulator.hpp +++ b/src/emulator/x64_emulator.hpp @@ -4,12 +4,12 @@ enum class x64_hookable_instructions { - invalid, - syscall, - cpuid, - rdtsc, - rdtscp, + invalid, + syscall, + cpuid, + rdtsc, + rdtscp, }; -using x64_emulator = typed_emulator; +using x64_emulator = + typed_emulator; diff --git a/src/emulator/x64_register.hpp b/src/emulator/x64_register.hpp index 520e1d78..9682a966 100644 --- a/src/emulator/x64_register.hpp +++ b/src/emulator/x64_register.hpp @@ -2,244 +2,244 @@ enum class x64_register { - invalid = 0, - ah, - al, - ax, - bh, - bl, - bp, - bpl, - bx, - ch, - cl, - cs, - cx, - dh, - di, - dil, - dl, - ds, - dx, - eax, - ebp, - ebx, - ecx, - edi, - edx, - eflags, - eip, - es = eip + 2, - esi, - esp, - fpsw, - fs, - gs, - ip, - rax, - rbp, - rbx, - rcx, - rdi, - rdx, - rip, - rsi = rip + 2, - rsp, - si, - sil, - sp, - spl, - ss, - cr0, - cr1, - cr2, - cr3, - cr4, - cr8 = cr4 + 4, - dr0 = cr8 + 8, - dr1, - dr2, - dr3, - dr4, - dr5, - dr6, - dr7, - fp0 = dr7 + 9, - fp1, - fp2, - fp3, - fp4, - fp5, - fp6, - fp7, - k0, - k1, - k2, - k3, - k4, - k5, - k6, - k7, - mm0, - mm1, - mm2, - mm3, - mm4, - mm5, - mm6, - mm7, - r8, - r9, - r10, - r11, - r12, - r13, - r14, - r15, - st0, - st1, - st2, - st3, - st4, - st5, - st6, - st7, - xmm0, - xmm1, - xmm2, - xmm3, - xmm4, - xmm5, - xmm6, - xmm7, - xmm8, - xmm9, - xmm10, - xmm11, - xmm12, - xmm13, - xmm14, - xmm15, - xmm16, - xmm17, - xmm18, - xmm19, - xmm20, - xmm21, - xmm22, - xmm23, - xmm24, - xmm25, - xmm26, - xmm27, - xmm28, - xmm29, - xmm30, - xmm31, - ymm0, - ymm1, - ymm2, - ymm3, - ymm4, - ymm5, - ymm6, - ymm7, - ymm8, - ymm9, - ymm10, - ymm11, - ymm12, - ymm13, - ymm14, - ymm15, - ymm16, - ymm17, - ymm18, - ymm19, - ymm20, - ymm21, - ymm22, - ymm23, - ymm24, - ymm25, - ymm26, - ymm27, - ymm28, - ymm29, - ymm30, - ymm31, - zmm0, - zmm1, - zmm2, - zmm3, - zmm4, - zmm5, - zmm6, - zmm7, - zmm8, - zmm9, - zmm10, - zmm11, - zmm12, - zmm13, - zmm14, - zmm15, - zmm16, - zmm17, - zmm18, - zmm19, - zmm20, - zmm21, - zmm22, - zmm23, - zmm24, - zmm25, - zmm26, - zmm27, - zmm28, - zmm29, - zmm30, - zmm31, - r8b, - r9b, - r10b, - r11b, - r12b, - r13b, - r14b, - r15b, - r8d, - r9d, - r10d, - r11d, - r12d, - r13d, - r14d, - r15d, - r8w, - r9w, - r10w, - r11w, - r12w, - r13w, - r14w, - r15w, - idtr, - gdtr, - ldtr, - tr, - fpcw, - fptag, - msr, - mxcsr, - fs_base, - gs_base, - flags, - rflags, - fip, - fcs, - fdp, - fds, - fop, - end, // Must be last + invalid = 0, + ah, + al, + ax, + bh, + bl, + bp, + bpl, + bx, + ch, + cl, + cs, + cx, + dh, + di, + dil, + dl, + ds, + dx, + eax, + ebp, + ebx, + ecx, + edi, + edx, + eflags, + eip, + es = eip + 2, + esi, + esp, + fpsw, + fs, + gs, + ip, + rax, + rbp, + rbx, + rcx, + rdi, + rdx, + rip, + rsi = rip + 2, + rsp, + si, + sil, + sp, + spl, + ss, + cr0, + cr1, + cr2, + cr3, + cr4, + cr8 = cr4 + 4, + dr0 = cr8 + 8, + dr1, + dr2, + dr3, + dr4, + dr5, + dr6, + dr7, + fp0 = dr7 + 9, + fp1, + fp2, + fp3, + fp4, + fp5, + fp6, + fp7, + k0, + k1, + k2, + k3, + k4, + k5, + k6, + k7, + mm0, + mm1, + mm2, + mm3, + mm4, + mm5, + mm6, + mm7, + r8, + r9, + r10, + r11, + r12, + r13, + r14, + r15, + st0, + st1, + st2, + st3, + st4, + st5, + st6, + st7, + xmm0, + xmm1, + xmm2, + xmm3, + xmm4, + xmm5, + xmm6, + xmm7, + xmm8, + xmm9, + xmm10, + xmm11, + xmm12, + xmm13, + xmm14, + xmm15, + xmm16, + xmm17, + xmm18, + xmm19, + xmm20, + xmm21, + xmm22, + xmm23, + xmm24, + xmm25, + xmm26, + xmm27, + xmm28, + xmm29, + xmm30, + xmm31, + ymm0, + ymm1, + ymm2, + ymm3, + ymm4, + ymm5, + ymm6, + ymm7, + ymm8, + ymm9, + ymm10, + ymm11, + ymm12, + ymm13, + ymm14, + ymm15, + ymm16, + ymm17, + ymm18, + ymm19, + ymm20, + ymm21, + ymm22, + ymm23, + ymm24, + ymm25, + ymm26, + ymm27, + ymm28, + ymm29, + ymm30, + ymm31, + zmm0, + zmm1, + zmm2, + zmm3, + zmm4, + zmm5, + zmm6, + zmm7, + zmm8, + zmm9, + zmm10, + zmm11, + zmm12, + zmm13, + zmm14, + zmm15, + zmm16, + zmm17, + zmm18, + zmm19, + zmm20, + zmm21, + zmm22, + zmm23, + zmm24, + zmm25, + zmm26, + zmm27, + zmm28, + zmm29, + zmm30, + zmm31, + r8b, + r9b, + r10b, + r11b, + r12b, + r13b, + r14b, + r15b, + r8d, + r9d, + r10d, + r11d, + r12d, + r13d, + r14d, + r15d, + r8w, + r9w, + r10w, + r11w, + r12w, + r13w, + r14w, + r15w, + idtr, + gdtr, + ldtr, + tr, + fpcw, + fptag, + msr, + mxcsr, + fs_base, + gs_base, + flags, + rflags, + fip, + fcs, + fdp, + fds, + fop, + end, // Must be last }; diff --git a/src/fuzzer/main.cpp b/src/fuzzer/main.cpp index 7179d79f..9f8e7d8c 100644 --- a/src/fuzzer/main.cpp +++ b/src/fuzzer/main.cpp @@ -9,192 +9,183 @@ bool use_gdb = false; namespace { - void run_emulation(windows_emulator& win_emu) - { - try - { - win_emu.log.disable_output(true); - win_emu.start(); + void run_emulation(windows_emulator& win_emu) + { + try + { + win_emu.log.disable_output(true); + win_emu.start(); - if (win_emu.process().exception_rip.has_value()) - { - throw std::runtime_error("Exception!"); - } - } - catch (...) - { - win_emu.log.disable_output(false); - win_emu.log.print(color::red, "Emulation failed at: 0x%" PRIx64 "\n", - win_emu.emu().read_instruction_pointer()); - throw; - } + if (win_emu.process().exception_rip.has_value()) + { + throw std::runtime_error("Exception!"); + } + } + catch (...) + { + win_emu.log.disable_output(false); + win_emu.log.print(color::red, "Emulation failed at: 0x%" PRIx64 "\n", + win_emu.emu().read_instruction_pointer()); + throw; + } - win_emu.log.disable_output(false); - } + win_emu.log.disable_output(false); + } - void forward_emulator(windows_emulator& win_emu) - { - const auto target = win_emu.process().executable->find_export("vulnerable"); - win_emu.emu().hook_memory_execution(target, 1, [&](uint64_t, size_t, uint64_t) - { - win_emu.emu().stop(); - }); + void forward_emulator(windows_emulator& win_emu) + { + const auto target = win_emu.process().executable->find_export("vulnerable"); + win_emu.emu().hook_memory_execution(target, 1, [&](uint64_t, size_t, uint64_t) { win_emu.emu().stop(); }); - run_emulation(win_emu); - } + run_emulation(win_emu); + } - struct fuzzer_executer : fuzzer::executer - { - windows_emulator emu{}; - std::span emulator_data{}; - std::unordered_set visited_blocks{}; - const std::function* handler{nullptr}; + struct fuzzer_executer : fuzzer::executer + { + windows_emulator emu{}; + std::span emulator_data{}; + std::unordered_set visited_blocks{}; + const std::function* handler{nullptr}; + fuzzer_executer(std::span data) + : emulator_data(data) + { + emu.fuzzing = true; + emu.emu().hook_basic_block([&](const basic_block& block) { + if (this->handler && visited_blocks.emplace(block.address).second) + { + (*this->handler)(block.address); + } + }); - fuzzer_executer(std::span data) - : emulator_data(data) - { - emu.fuzzing = true; - emu.emu().hook_basic_block([&](const basic_block& block) - { - if (this->handler && visited_blocks.emplace(block.address).second) - { - (*this->handler)(block.address); - } - }); + utils::buffer_deserializer deserializer{emulator_data}; + emu.deserialize(deserializer); + emu.save_snapshot(); - utils::buffer_deserializer deserializer{emulator_data}; - emu.deserialize(deserializer); - emu.save_snapshot(); + const auto ret = emu.emu().read_stack(0); - const auto ret = emu.emu().read_stack(0); + emu.emu().hook_memory_execution(ret, 1, [&](uint64_t, size_t, uint64_t) { emu.emu().stop(); }); + } - emu.emu().hook_memory_execution(ret, 1, [&](uint64_t, size_t, uint64_t) - { - emu.emu().stop(); - }); - } + void restore_emulator() + { + /*utils::buffer_deserializer deserializer{ emulator_data }; + emu.deserialize(deserializer);*/ + emu.restore_snapshot(); + } - void restore_emulator() - { - /*utils::buffer_deserializer deserializer{ emulator_data }; - emu.deserialize(deserializer);*/ - emu.restore_snapshot(); - } + fuzzer::execution_result execute(std::span data, + const std::function& coverage_handler) override + { + // printf("Input size: %zd\n", data.size()); + this->handler = &coverage_handler; + this->visited_blocks.clear(); - fuzzer::execution_result execute(std::span data, - const std::function& coverage_handler) override - { - //printf("Input size: %zd\n", data.size()); - this->handler = &coverage_handler; - this->visited_blocks.clear(); + restore_emulator(); - restore_emulator(); + const auto memory = emu.emu().allocate_memory(page_align_up(std::max(data.size(), size_t(1))), + memory_permission::read_write); + emu.emu().write_memory(memory, data.data(), data.size()); - const auto memory = emu.emu().allocate_memory(page_align_up(std::max(data.size(), size_t(1))), - memory_permission::read_write); - emu.emu().write_memory(memory, data.data(), data.size()); + emu.emu().reg(x64_register::rcx, memory); + emu.emu().reg(x64_register::rdx, data.size()); - emu.emu().reg(x64_register::rcx, memory); - emu.emu().reg(x64_register::rdx, data.size()); + try + { + run_emulation(emu); + return fuzzer::execution_result::success; + } + catch (...) + { + return fuzzer::execution_result::error; + } + } + }; - try - { - run_emulation(emu); - return fuzzer::execution_result::success; - } - catch (...) - { - return fuzzer::execution_result::error; - } - } - }; + struct my_fuzzing_handler : fuzzer::fuzzing_handler + { + std::vector emulator_state{}; + std::atomic_bool stop_fuzzing{false}; - struct my_fuzzing_handler : fuzzer::fuzzing_handler - { - std::vector emulator_state{}; - std::atomic_bool stop_fuzzing{false}; + my_fuzzing_handler(std::vector emulator_state) + : emulator_state(std::move(emulator_state)) + { + } - my_fuzzing_handler(std::vector emulator_state) - : emulator_state(std::move(emulator_state)) - { - } + std::unique_ptr make_executer() override + { + return std::make_unique(emulator_state); + } - std::unique_ptr make_executer() override - { - return std::make_unique(emulator_state); - } + bool stop() override + { + return stop_fuzzing; + } + }; - bool stop() override - { - return stop_fuzzing; - } - }; + void run_fuzzer(const windows_emulator& base_emulator) + { + const auto concurrency = std::thread::hardware_concurrency() + 2; - void run_fuzzer(const windows_emulator& base_emulator) - { - const auto concurrency = std::thread::hardware_concurrency() + 2; + utils::buffer_serializer serializer{}; + base_emulator.serialize(serializer); - utils::buffer_serializer serializer{}; - base_emulator.serialize(serializer); + my_fuzzing_handler handler{serializer.move_buffer()}; - my_fuzzing_handler handler{serializer.move_buffer()}; + fuzzer::run(handler, concurrency); + } - fuzzer::run(handler, concurrency); - } + void run(const std::string_view application) + { + emulator_settings settings{ + .application = application, + }; - void run(const std::string_view application) - { - emulator_settings settings{ - .application = application, - }; + windows_emulator win_emu{std::move(settings)}; - windows_emulator win_emu{std::move(settings)}; - - forward_emulator(win_emu); - run_fuzzer(win_emu); - } + forward_emulator(win_emu); + run_fuzzer(win_emu); + } } int main(const int argc, char** argv) { - if (argc <= 1) - { - puts("Application not specified!"); - return 1; - } + if (argc <= 1) + { + puts("Application not specified!"); + return 1; + } - //setvbuf(stdout, nullptr, _IOFBF, 0x10000); - if (argc > 2 && argv[1] == "-d"s) - { - use_gdb = true; - } + // setvbuf(stdout, nullptr, _IOFBF, 0x10000); + if (argc > 2 && argv[1] == "-d"s) + { + use_gdb = true; + } - try - { - do - { - run(argv[use_gdb ? 2 : 1]); - } - while (use_gdb); + try + { + do + { + run(argv[use_gdb ? 2 : 1]); + } while (use_gdb); - return 0; - } - catch (std::exception& e) - { - puts(e.what()); + return 0; + } + catch (std::exception& e) + { + puts(e.what()); #if defined(_WIN32) && 0 - MessageBoxA(nullptr, e.what(), "ERROR", MB_ICONERROR); + MessageBoxA(nullptr, e.what(), "ERROR", MB_ICONERROR); #endif - } + } - return 1; + return 1; } #ifdef _WIN32 int WINAPI WinMain(HINSTANCE, HINSTANCE, PSTR, int) { - return main(__argc, __argv); + return main(__argc, __argv); } #endif diff --git a/src/fuzzing-engine/fuzzer.cpp b/src/fuzzing-engine/fuzzer.cpp index f6338403..d08be3da 100644 --- a/src/fuzzing-engine/fuzzer.cpp +++ b/src/fuzzing-engine/fuzzer.cpp @@ -5,128 +5,121 @@ namespace fuzzer { - namespace - { - class fuzzing_context - { - public: - fuzzing_context(input_generator& generator, fuzzing_handler& handler) - : generator(generator) - , handler(handler) - { - } + namespace + { + class fuzzing_context + { + public: + fuzzing_context(input_generator& generator, fuzzing_handler& handler) + : generator(generator), + handler(handler) + { + } - void stop() - { - this->stop_ = true; - } + void stop() + { + this->stop_ = true; + } - bool should_stop() - { - if (this->stop_) - { - return true; - } + bool should_stop() + { + if (this->stop_) + { + return true; + } - if (!handler.stop()) - { - return false; - } + if (!handler.stop()) + { + return false; + } - this->stop_ = true; - return true; - } + this->stop_ = true; + return true; + } - input_generator& generator; - fuzzing_handler& handler; - std::atomic_uint64_t executions{0}; + input_generator& generator; + fuzzing_handler& handler; + std::atomic_uint64_t executions{0}; - private: - std::atomic_bool stop_{false}; - }; + private: + std::atomic_bool stop_{false}; + }; - void perform_fuzzing_iteration(fuzzing_context& context, executer& executer) - { - ++context.executions; - context.generator.access_input([&](const std::span input) - { - uint64_t score{0}; - const auto result = executer.execute(input, [&](uint64_t) - { - ++score; - }); + void perform_fuzzing_iteration(fuzzing_context& context, executer& executer) + { + ++context.executions; + context.generator.access_input([&](const std::span input) { + uint64_t score{0}; + const auto result = executer.execute(input, [&](uint64_t) { ++score; }); - if (result == execution_result::error) - { - printf("Found error!\n"); - context.stop(); - } + if (result == execution_result::error) + { + printf("Found error!\n"); + context.stop(); + } - return score; - }); - } + return score; + }); + } - void worker(fuzzing_context& context) - { - const auto executer = context.handler.make_executer(); + void worker(fuzzing_context& context) + { + const auto executer = context.handler.make_executer(); - while (!context.should_stop()) - { - perform_fuzzing_iteration(context, *executer); - } - } + while (!context.should_stop()) + { + perform_fuzzing_iteration(context, *executer); + } + } - struct worker_pool - { - fuzzing_context* context_{nullptr}; - std::vector workers_{}; + struct worker_pool + { + fuzzing_context* context_{nullptr}; + std::vector workers_{}; - worker_pool(fuzzing_context& context, const size_t concurrency) - : context_(&context) - { - this->workers_.reserve(concurrency); + worker_pool(fuzzing_context& context, const size_t concurrency) + : context_(&context) + { + this->workers_.reserve(concurrency); - for (size_t i = 0; i < concurrency; ++i) - { - this->workers_.emplace_back([&context] - { - worker(context); - }); - } - } + for (size_t i = 0; i < concurrency; ++i) + { + this->workers_.emplace_back([&context] { worker(context); }); + } + } - ~worker_pool() - { - if (this->workers_.empty()) - { - return; - } + ~worker_pool() + { + if (this->workers_.empty()) + { + return; + } - this->context_->stop(); + this->context_->stop(); - for (auto& w : this->workers_) - { - w.join(); - } - } - }; - } + for (auto& w : this->workers_) + { + w.join(); + } + } + }; + } - void run(fuzzing_handler& handler, const size_t concurrency) - { - input_generator generator{}; - fuzzing_context context{generator, handler}; - worker_pool pool{context, concurrency}; + void run(fuzzing_handler& handler, const size_t concurrency) + { + input_generator generator{}; + fuzzing_context context{generator, handler}; + worker_pool pool{context, concurrency}; - while (!context.should_stop()) - { - std::this_thread::sleep_for(std::chrono::seconds{1}); + while (!context.should_stop()) + { + std::this_thread::sleep_for(std::chrono::seconds{1}); - const auto executions = context.executions.exchange(0); - const auto highest_scorer = context.generator.get_highest_scorer(); - const auto avg_score = context.generator.get_average_score(); - printf("Executions/s: %" PRIu64 " - Score: %" PRIx64 " - Avg: %.3f\n", executions, highest_scorer.score, - avg_score); - } - } + const auto executions = context.executions.exchange(0); + const auto highest_scorer = context.generator.get_highest_scorer(); + const auto avg_score = context.generator.get_average_score(); + printf("Executions/s: %" PRIu64 " - Score: %" PRIx64 " - Avg: %.3f\n", executions, highest_scorer.score, + avg_score); + } + } } diff --git a/src/fuzzing-engine/fuzzer.hpp b/src/fuzzing-engine/fuzzer.hpp index 900a0f83..fdaedcaf 100644 --- a/src/fuzzing-engine/fuzzer.hpp +++ b/src/fuzzing-engine/fuzzer.hpp @@ -7,33 +7,33 @@ namespace fuzzer { - using coverage_functor = void(uint64_t address); + using coverage_functor = void(uint64_t address); - enum class execution_result - { - success, - error, - }; + enum class execution_result + { + success, + error, + }; - struct executer - { - virtual ~executer() = default; + struct executer + { + virtual ~executer() = default; - virtual execution_result execute(std::span data, - const std::function& coverage_handler) = 0; - }; + virtual execution_result execute(std::span data, + const std::function& coverage_handler) = 0; + }; - struct fuzzing_handler - { - virtual ~fuzzing_handler() = default; + struct fuzzing_handler + { + virtual ~fuzzing_handler() = default; - virtual std::unique_ptr make_executer() = 0; + virtual std::unique_ptr make_executer() = 0; - virtual bool stop() - { - return false; - } - }; + virtual bool stop() + { + return false; + } + }; - void run(fuzzing_handler& handler, size_t concurrency = std::thread::hardware_concurrency()); + void run(fuzzing_handler& handler, size_t concurrency = std::thread::hardware_concurrency()); } diff --git a/src/fuzzing-engine/input_generator.cpp b/src/fuzzing-engine/input_generator.cpp index a04e869d..2be1d9ea 100644 --- a/src/fuzzing-engine/input_generator.cpp +++ b/src/fuzzing-engine/input_generator.cpp @@ -4,120 +4,118 @@ namespace fuzzer { - namespace - { - constexpr size_t MAX_TOP_SCORER = 20; + namespace + { + constexpr size_t MAX_TOP_SCORER = 20; - void mutate_input(random_generator& rng, std::vector& input) - { - if (input.empty() || rng.get(3) == 0) - { - const auto new_bytes = rng.get_geometric() + 1; - input.resize(input.size() + new_bytes); - } - else if (rng.get(10) == 0) - { - const auto remove_bytes = rng.get_geometric() % input.size(); - input.resize(input.size() - remove_bytes); - } + void mutate_input(random_generator& rng, std::vector& input) + { + if (input.empty() || rng.get(3) == 0) + { + const auto new_bytes = rng.get_geometric() + 1; + input.resize(input.size() + new_bytes); + } + else if (rng.get(10) == 0) + { + const auto remove_bytes = rng.get_geometric() % input.size(); + input.resize(input.size() - remove_bytes); + } - const auto mutations = (rng.get_geometric() + 1) % input.size(); + const auto mutations = (rng.get_geometric() + 1) % input.size(); + for (size_t i = 0; i < mutations; ++i) + { + const auto index = rng.get(input.size()); + input[index] = rng.get(); + } + } + } - for (size_t i = 0; i < mutations; ++i) - { - const auto index = rng.get(input.size()); - input[index] = rng.get(); - } - } - } + input_generator::input_generator() = default; - input_generator::input_generator() = default; + std::vector input_generator::generate_next_input() + { + std::vector input{}; + std::unique_lock lock{this->mutex_}; - std::vector input_generator::generate_next_input() - { - std::vector input{}; - std::unique_lock lock{this->mutex_}; + if (!this->top_scorer_.empty()) + { + const auto index = this->rng.get() % this->top_scorer_.size(); + input = this->top_scorer_[index].data; + } - if (!this->top_scorer_.empty()) - { - const auto index = this->rng.get() % this->top_scorer_.size(); - input = this->top_scorer_[index].data; - } + mutate_input(this->rng, input); - mutate_input(this->rng, input); + return input; + } - return input; - } + void input_generator::access_input(const std::function& handler) + { + auto next_input = this->generate_next_input(); + const auto score = handler(next_input); - void input_generator::access_input(const std::function& handler) - { - auto next_input = this->generate_next_input(); - const auto score = handler(next_input); + input_entry e{}; + e.data = std::move(next_input); + e.score = score; - input_entry e{}; - e.data = std::move(next_input); - e.score = score; + this->store_input_entry(std::move(e)); + } - this->store_input_entry(std::move(e)); - } + input_entry input_generator::get_highest_scorer() + { + std::unique_lock lock{this->mutex_}; + return this->highest_scorer_; + } - input_entry input_generator::get_highest_scorer() - { - std::unique_lock lock{this->mutex_}; - return this->highest_scorer_; - } + double input_generator::get_average_score() + { + std::unique_lock lock{this->mutex_}; - double input_generator::get_average_score() - { - std::unique_lock lock{this->mutex_}; + double score{0.0}; + for (const auto& e : this->top_scorer_) + { + score += static_cast(e.score); + } - double score{0.0}; - for (const auto& e : this->top_scorer_) - { - score += static_cast(e.score); - } + return score / static_cast(this->top_scorer_.size()); + } - return score / static_cast(this->top_scorer_.size()); - } + void input_generator::store_input_entry(input_entry entry) + { + std::unique_lock lock{this->mutex_}; - void input_generator::store_input_entry(input_entry entry) - { - std::unique_lock lock{this->mutex_}; + if (entry.score < this->lowest_score && this->rng.get(40) != 0) + { + return; + } - if (entry.score < this->lowest_score && this->rng.get(40) != 0) - { - return; - } + if (entry.score > this->highest_scorer_.score) + { + this->highest_scorer_ = entry; + } - if (entry.score > this->highest_scorer_.score) - { - this->highest_scorer_ = entry; - } + if (this->top_scorer_.size() < MAX_TOP_SCORER) + { + this->top_scorer_.emplace_back(std::move(entry)); + return; + } - if (this->top_scorer_.size() < MAX_TOP_SCORER) - { - this->top_scorer_.emplace_back(std::move(entry)); - return; - } + const auto insert_at_random = this->rng.get(10) == 0; + const auto index = + insert_at_random ? (this->rng.get() % this->top_scorer_.size()) : this->lowest_scorer; - const auto insert_at_random = this->rng.get(10) == 0; - const auto index = insert_at_random - ? (this->rng.get() % this->top_scorer_.size()) - : this->lowest_scorer; + this->top_scorer_[index] = std::move(entry); - this->top_scorer_[index] = std::move(entry); + this->lowest_score = this->top_scorer_[0].score; + this->lowest_scorer = 0; - this->lowest_score = this->top_scorer_[0].score; - this->lowest_scorer = 0; - - for (size_t i = 1; i < this->top_scorer_.size(); ++i) - { - if (this->top_scorer_[i].score < this->lowest_score) - { - this->lowest_score = this->top_scorer_[i].score; - this->lowest_scorer = i; - } - } - } + for (size_t i = 1; i < this->top_scorer_.size(); ++i) + { + if (this->top_scorer_[i].score < this->lowest_score) + { + this->lowest_score = this->top_scorer_[i].score; + this->lowest_scorer = i; + } + } + } } diff --git a/src/fuzzing-engine/input_generator.hpp b/src/fuzzing-engine/input_generator.hpp index 8cbea089..da9840e6 100644 --- a/src/fuzzing-engine/input_generator.hpp +++ b/src/fuzzing-engine/input_generator.hpp @@ -8,37 +8,37 @@ namespace fuzzer { - using input_score = uint64_t; - using input_handler = input_score(std::span); + using input_score = uint64_t; + using input_handler = input_score(std::span); - struct input_entry - { - std::vector data{}; - input_score score{}; - }; + struct input_entry + { + std::vector data{}; + input_score score{}; + }; - class input_generator - { - public: - input_generator(); + class input_generator + { + public: + input_generator(); - void access_input(const std::function& handler); + void access_input(const std::function& handler); - input_entry get_highest_scorer(); - double get_average_score(); + input_entry get_highest_scorer(); + double get_average_score(); - private: - std::mutex mutex_{}; - random_generator rng{}; + private: + std::mutex mutex_{}; + random_generator rng{}; - std::vector top_scorer_{}; - input_score lowest_score{0}; - size_t lowest_scorer{0}; + std::vector top_scorer_{}; + input_score lowest_score{0}; + size_t lowest_scorer{0}; - input_entry highest_scorer_{}; + input_entry highest_scorer_{}; - std::vector generate_next_input(); + std::vector generate_next_input(); - void store_input_entry(input_entry entry); - }; + void store_input_entry(input_entry entry); + }; } diff --git a/src/fuzzing-engine/random_generator.cpp b/src/fuzzing-engine/random_generator.cpp index 9985840b..c18b96e7 100644 --- a/src/fuzzing-engine/random_generator.cpp +++ b/src/fuzzing-engine/random_generator.cpp @@ -3,33 +3,33 @@ namespace fuzzer { - random_generator::random_generator() - : rng_(std::random_device()()) - { - } + random_generator::random_generator() + : rng_(std::random_device()()) + { + } - std::mt19937::result_type random_generator::generate_number() - { - return this->distribution_(this->rng_); - } + std::mt19937::result_type random_generator::generate_number() + { + return this->distribution_(this->rng_); + } - void random_generator::fill(void* data, const size_t size) - { - this->fill(std::span(static_cast(data), size)); - } + void random_generator::fill(void* data, const size_t size) + { + this->fill(std::span(static_cast(data), size)); + } - void random_generator::fill(std::span data) - { - size_t i = 0; - while (i < data.size()) - { - const auto number = this->generate_number(); + void random_generator::fill(std::span data) + { + size_t i = 0; + while (i < data.size()) + { + const auto number = this->generate_number(); - const auto remaining_data = data.size() - i; - const auto data_to_fill = std::min(remaining_data, sizeof(number)); + const auto remaining_data = data.size() - i; + const auto data_to_fill = std::min(remaining_data, sizeof(number)); - memcpy(data.data() + i, &number, data_to_fill); - i += data_to_fill; - } - } + memcpy(data.data() + i, &number, data_to_fill); + i += data_to_fill; + } + } } diff --git a/src/fuzzing-engine/random_generator.hpp b/src/fuzzing-engine/random_generator.hpp index 37a61689..ffc81d4e 100644 --- a/src/fuzzing-engine/random_generator.hpp +++ b/src/fuzzing-engine/random_generator.hpp @@ -6,65 +6,65 @@ namespace fuzzer { - class random_generator - { - public: - random_generator(); + class random_generator + { + public: + random_generator(); - void fill(std::span data); - void fill(void* data, size_t size); + void fill(std::span data); + void fill(void* data, size_t size); - template - requires(std::is_trivially_copyable_v) - T get() - { - T value{}; - this->fill(&value, sizeof(value)); - return value; - } + template + requires(std::is_trivially_copyable_v) + T get() + { + T value{}; + this->fill(&value, sizeof(value)); + return value; + } - template - T get(const T& max) - { - return this->get() % max; - } + template + T get(const T& max) + { + return this->get() % max; + } - template - T get(T min, T max) - { - if (max < min) - { - std::swap(max, min); - } + template + T get(T min, T max) + { + if (max < min) + { + std::swap(max, min); + } - const auto diff = max - min; + const auto diff = max - min; - return (this->get() % diff) + min; - } + return (this->get() % diff) + min; + } - template - T get_geometric() - { - T value{0}; + template + T get_geometric() + { + T value{0}; - while (this->get()) - { - ++value; - } + while (this->get()) + { + ++value; + } - return value; - } + return value; + } - private: - std::mt19937 rng_; - std::uniform_int_distribution distribution_{}; + private: + std::mt19937 rng_; + std::uniform_int_distribution distribution_{}; - std::mt19937::result_type generate_number(); - }; + std::mt19937::result_type generate_number(); + }; - template <> - inline bool random_generator::get() - { - return (this->generate_number() & 1) != 0; - } + template <> + inline bool random_generator::get() + { + return (this->generate_number() & 1) != 0; + } } diff --git a/src/test-sample/test.cpp b/src/test-sample/test.cpp index 6842432c..efa056c8 100644 --- a/src/test-sample/test.cpp +++ b/src/test-sample/test.cpp @@ -19,12 +19,12 @@ __declspec(dllexport) bool do_the_task = true; struct tls_struct { - DWORD num = 1337; + DWORD num = 1337; - tls_struct() - { - num = GetCurrentThreadId(); - } + tls_struct() + { + num = GetCurrentThreadId(); + } }; thread_local tls_struct tls_var{}; @@ -32,297 +32,293 @@ thread_local tls_struct tls_var{}; // getenv is broken right now :( std::string read_env(const char* env) { - char buffer[0x1000] = {}; - if (!GetEnvironmentVariableA(env, buffer, sizeof(buffer))) - { - return {}; - } + char buffer[0x1000] = {}; + if (!GetEnvironmentVariableA(env, buffer, sizeof(buffer))) + { + return {}; + } - return buffer; + return buffer; } bool test_threads() { - constexpr auto thread_count = 5ULL; + constexpr auto thread_count = 5ULL; - std::atomic counter{0}; + std::atomic counter{0}; - std::vector threads{}; - threads.reserve(thread_count); + std::vector threads{}; + threads.reserve(thread_count); - for (auto i = 0ULL; i < thread_count; ++i) - { - threads.emplace_back([&counter] - { - ++counter; - std::this_thread::yield(); - ++counter; - // Host scheduling/cpu performance can have impact on emulator scheduling - //std::this_thread::sleep_for(std::chrono::milliseconds(100)); - ++counter; - }); - } + for (auto i = 0ULL; i < thread_count; ++i) + { + threads.emplace_back([&counter] { + ++counter; + std::this_thread::yield(); + ++counter; + // Host scheduling/cpu performance can have impact on emulator scheduling + // std::this_thread::sleep_for(std::chrono::milliseconds(100)); + ++counter; + }); + } - for (auto& t : threads) - { - t.join(); - } + for (auto& t : threads) + { + t.join(); + } - return counter == (thread_count * 3ULL); + return counter == (thread_count * 3ULL); } bool test_tls() { - std::atomic_bool kill{false}; - std::atomic_uint32_t successes{0}; - constexpr uint32_t thread_count = 2; + std::atomic_bool kill{false}; + std::atomic_uint32_t successes{0}; + constexpr uint32_t thread_count = 2; - std::vector ts{}; - kill = false; + std::vector ts{}; + kill = false; - for (size_t i = 0; i < thread_count; ++i) - { - ts.emplace_back([&] - { - while (!kill) - { - std::this_thread::yield(); - } + for (size_t i = 0; i < thread_count; ++i) + { + ts.emplace_back([&] { + while (!kill) + { + std::this_thread::yield(); + } - if (tls_var.num == GetCurrentThreadId()) - { - ++successes; - } - }); - } + if (tls_var.num == GetCurrentThreadId()) + { + ++successes; + } + }); + } - LoadLibraryA("d3dcompiler_47.dll"); - LoadLibraryA("dsound.dll"); - /*LoadLibraryA("d3d9.dll"); - LoadLibraryA("dxgi.dll"); - LoadLibraryA("wlanapi.dll");*/ + LoadLibraryA("d3dcompiler_47.dll"); + LoadLibraryA("dsound.dll"); + /*LoadLibraryA("d3d9.dll"); + LoadLibraryA("dxgi.dll"); + LoadLibraryA("wlanapi.dll");*/ - kill = true; + kill = true; - for (auto& t : ts) - { - if (t.joinable()) - { - t.join(); - } - } + for (auto& t : ts) + { + if (t.joinable()) + { + t.join(); + } + } - return successes == thread_count; + return successes == thread_count; } bool test_env() { - const auto computername = read_env("COMPUTERNAME"); + const auto computername = read_env("COMPUTERNAME"); - SetEnvironmentVariableA("BLUB", "LUL"); + SetEnvironmentVariableA("BLUB", "LUL"); - const auto blub = read_env("BLUB"); + const auto blub = read_env("BLUB"); - return !computername.empty() && blub == "LUL"; + return !computername.empty() && blub == "LUL"; } bool test_io() { - const auto* filename = "a.txt"; + const auto* filename = "a.txt"; - FILE* fp{}; - (void)fopen_s(&fp, filename, "wb"); + FILE* fp{}; + (void)fopen_s(&fp, filename, "wb"); - if (!fp) - { - puts("Bad file"); - return false; - } + if (!fp) + { + puts("Bad file"); + return false; + } - const std::string text = "Blub"; + const std::string text = "Blub"; - (void)fwrite(text.data(), 1, text.size(), fp); - (void)fclose(fp); + (void)fwrite(text.data(), 1, text.size(), fp); + (void)fclose(fp); - std::ifstream t(filename); - t.seekg(0, std::ios::end); - const size_t size = t.tellg(); - std::string buffer(size, ' '); - t.seekg(0); - t.read(buffer.data(), static_cast(size)); + std::ifstream t(filename); + t.seekg(0, std::ios::end); + const size_t size = t.tellg(); + std::string buffer(size, ' '); + t.seekg(0); + t.read(buffer.data(), static_cast(size)); - return text == buffer; + return text == buffer; } bool test_dir_io() { - size_t count = 0; + size_t count = 0; - for (auto i : std::filesystem::directory_iterator(R"(C:\Windows\System32\)")) - { - ++count; - if (count > 30) - { - return true; - } - } + for (auto i : std::filesystem::directory_iterator(R"(C:\Windows\System32\)")) + { + ++count; + if (count > 30) + { + return true; + } + } - return count > 30; + return count > 30; } std::optional read_registry_string(const HKEY root, const char* path, const char* value) { - HKEY key{}; - if (RegOpenKeyExA(root, path, 0, KEY_READ, &key) != - ERROR_SUCCESS) - { - return std::nullopt; - } + HKEY key{}; + if (RegOpenKeyExA(root, path, 0, KEY_READ, &key) != ERROR_SUCCESS) + { + return std::nullopt; + } - char data[MAX_PATH]{}; - DWORD length = sizeof(data); - const auto res = RegQueryValueExA(key, value, nullptr, nullptr, reinterpret_cast(data), &length); + char data[MAX_PATH]{}; + DWORD length = sizeof(data); + const auto res = RegQueryValueExA(key, value, nullptr, nullptr, reinterpret_cast(data), &length); - if (RegCloseKey(key) != ERROR_SUCCESS) - { - return std::nullopt; - } + if (RegCloseKey(key) != ERROR_SUCCESS) + { + return std::nullopt; + } - if (res != ERROR_SUCCESS) - { - return std::nullopt; - } + if (res != ERROR_SUCCESS) + { + return std::nullopt; + } - if (length == 0) - { - return ""; - } + if (length == 0) + { + return ""; + } - return {std::string(data, min(length - 1, sizeof(data)))}; + return {std::string(data, min(length - 1, sizeof(data)))}; } bool test_registry() { - const auto val = read_registry_string(HKEY_LOCAL_MACHINE, R"(SOFTWARE\Microsoft\Windows\CurrentVersion)", - "ProgramFilesDir"); - if (!val) - { - return false; - } + const auto val = + read_registry_string(HKEY_LOCAL_MACHINE, R"(SOFTWARE\Microsoft\Windows\CurrentVersion)", "ProgramFilesDir"); + if (!val) + { + return false; + } - return *val == "C:\\Program Files"; + return *val == "C:\\Program Files"; } void throw_exception() { - if (do_the_task) - { - throw std::runtime_error("OK"); - } + if (do_the_task) + { + throw std::runtime_error("OK"); + } } bool test_exceptions() { - try - { - throw_exception(); - return false; - } - catch (const std::exception& e) - { - return e.what() == std::string("OK"); - } + try + { + throw_exception(); + return false; + } + catch (const std::exception& e) + { + return e.what() == std::string("OK"); + } } void throw_access_violation() { - if (do_the_task) - { - *reinterpret_cast(1) = 1; - } + if (do_the_task) + { + *reinterpret_cast(1) = 1; + } } bool test_access_violation_exception() { - __try - { - throw_access_violation(); - return false; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode() == STATUS_ACCESS_VIOLATION; - } + __try + { + throw_access_violation(); + return false; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode() == STATUS_ACCESS_VIOLATION; + } } bool test_ud2_exception(void* address) { - __try - { - static_cast(address)(); - return false; - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - return GetExceptionCode() == STATUS_ILLEGAL_INSTRUCTION; - } + __try + { + static_cast(address)(); + return false; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode() == STATUS_ILLEGAL_INSTRUCTION; + } } bool test_illegal_instruction_exception() { - const auto address = VirtualAlloc(nullptr, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); - if (!address) - { - return false; - } + const auto address = VirtualAlloc(nullptr, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if (!address) + { + return false; + } - memcpy(address, "\x0F\x0B", 2); // ud2 + memcpy(address, "\x0F\x0B", 2); // ud2 - const auto res = test_ud2_exception(address); + const auto res = test_ud2_exception(address); - VirtualFree(address, 0x1000, MEM_RELEASE); + VirtualFree(address, 0x1000, MEM_RELEASE); - return res; + return res; } bool test_native_exceptions() { - return test_access_violation_exception() - && test_illegal_instruction_exception(); + return test_access_violation_exception() && test_illegal_instruction_exception(); } void print_time() { - const auto epoch_time = std::chrono::system_clock::now().time_since_epoch(); - printf("Time: %lld\n", epoch_time.count()); + const auto epoch_time = std::chrono::system_clock::now().time_since_epoch(); + printf("Time: %lld\n", epoch_time.count()); } -#define RUN_TEST(func, name) \ -{ \ - printf("Running test '" name "': "); \ - const auto res = func(); \ - valid &= res; \ - puts(res ? "Success" : "Fail"); \ -} +#define RUN_TEST(func, name) \ + { \ + printf("Running test '" name "': "); \ + const auto res = func(); \ + valid &= res; \ + puts(res ? "Success" : "Fail"); \ + } int main(int argc, const char* argv[]) { - if (argc == 2 && argv[1] == "-time"sv) - { - print_time(); - return 0; - } + if (argc == 2 && argv[1] == "-time"sv) + { + print_time(); + return 0; + } - bool valid = true; + bool valid = true; - RUN_TEST(test_io, "I/O") - RUN_TEST(test_dir_io, "Dir I/O") - RUN_TEST(test_registry, "Registry") - RUN_TEST(test_threads, "Threads") - RUN_TEST(test_env, "Environment") - RUN_TEST(test_exceptions, "Exceptions") - RUN_TEST(test_native_exceptions, "Native Exceptions") - RUN_TEST(test_tls, "TLS") + RUN_TEST(test_io, "I/O") + RUN_TEST(test_dir_io, "Dir I/O") + RUN_TEST(test_registry, "Registry") + RUN_TEST(test_threads, "Threads") + RUN_TEST(test_env, "Environment") + RUN_TEST(test_exceptions, "Exceptions") + RUN_TEST(test_native_exceptions, "Native Exceptions") + RUN_TEST(test_tls, "TLS") - return valid ? 0 : 1; + return valid ? 0 : 1; } diff --git a/src/unicorn-emulator/function_wrapper.hpp b/src/unicorn-emulator/function_wrapper.hpp index 47bb6876..f908dac5 100644 --- a/src/unicorn-emulator/function_wrapper.hpp +++ b/src/unicorn-emulator/function_wrapper.hpp @@ -8,36 +8,35 @@ template class function_wrapper : public object { -public: - using user_data_pointer = void*; - using c_function_type = ReturnType(Args..., user_data_pointer); - using functor_type = std::function; + public: + using user_data_pointer = void*; + using c_function_type = ReturnType(Args..., user_data_pointer); + using functor_type = std::function; - function_wrapper() = default; + function_wrapper() = default; - function_wrapper(functor_type functor) - : functor_(std::make_unique(std::move(functor))) - { - } + function_wrapper(functor_type functor) + : functor_(std::make_unique(std::move(functor))) + { + } - c_function_type* get_c_function() const - { - return +[](Args... args, user_data_pointer user_data) -> ReturnType - { - return (*static_cast(user_data))(std::forward(args)...); - }; - } + c_function_type* get_c_function() const + { + return +[](Args... args, user_data_pointer user_data) -> ReturnType { + return (*static_cast(user_data))(std::forward(args)...); + }; + } - void* get_function() const - { - return reinterpret_cast(this->get_c_function()); - } + void* get_function() const + { + return reinterpret_cast(this->get_c_function()); + } - user_data_pointer get_user_data() const - { - return this->functor_.get(); - } + user_data_pointer get_user_data() const + { + return this->functor_.get(); + } -private: - std::unique_ptr functor_{}; + private: + std::unique_ptr functor_{}; }; diff --git a/src/unicorn-emulator/object.hpp b/src/unicorn-emulator/object.hpp index 28cf52b0..8639c6b3 100644 --- a/src/unicorn-emulator/object.hpp +++ b/src/unicorn-emulator/object.hpp @@ -2,11 +2,11 @@ struct object { - object() = default; - virtual ~object() = default; + object() = default; + virtual ~object() = default; - object(object&&) = default; - object(const object&) = default; - object& operator=(object&&) = default; - object& operator=(const object&) = default; + object(object&&) = default; + object(const object&) = default; + object& operator=(object&&) = default; + object& operator=(const object&) = default; }; diff --git a/src/unicorn-emulator/unicorn.hpp b/src/unicorn-emulator/unicorn.hpp index e93d3631..a129404c 100644 --- a/src/unicorn-emulator/unicorn.hpp +++ b/src/unicorn-emulator/unicorn.hpp @@ -2,7 +2,7 @@ #ifdef _MSC_VER #pragma warning(push) -#pragma warning(disable: 4505) +#pragma warning(disable : 4505) #endif #ifdef __clang__ @@ -25,27 +25,27 @@ namespace unicorn { - struct unicorn_error : std::runtime_error - { - unicorn_error(const uc_err error_code) - : std::runtime_error(uc_strerror(error_code)) - , code(error_code) - { - } + struct unicorn_error : std::runtime_error + { + unicorn_error(const uc_err error_code) + : std::runtime_error(uc_strerror(error_code)), + code(error_code) + { + } - uc_err code{}; - }; + uc_err code{}; + }; - inline void throw_if_unicorn_error(const uc_err error_code) - { - if (error_code != UC_ERR_OK) - { - throw unicorn_error(error_code); - } - } + inline void throw_if_unicorn_error(const uc_err error_code) + { + if (error_code != UC_ERR_OK) + { + throw unicorn_error(error_code); + } + } - inline void uce(const uc_err error_code) - { - throw_if_unicorn_error(error_code); - } + inline void uce(const uc_err error_code) + { + throw_if_unicorn_error(error_code); + } } diff --git a/src/unicorn-emulator/unicorn_hook.hpp b/src/unicorn-emulator/unicorn_hook.hpp index 6b23b6ee..3c2d6731 100644 --- a/src/unicorn-emulator/unicorn_hook.hpp +++ b/src/unicorn-emulator/unicorn_hook.hpp @@ -4,74 +4,73 @@ namespace unicorn { - class unicorn_hook - { - public: - unicorn_hook() = default; + class unicorn_hook + { + public: + unicorn_hook() = default; - unicorn_hook(uc_engine* uc) - : unicorn_hook(uc, {}) - { - } + unicorn_hook(uc_engine* uc) + : unicorn_hook(uc, {}) + { + } - unicorn_hook(uc_engine* uc, const uc_hook hook) - : uc_(uc) - , hook_(hook) - { - } + unicorn_hook(uc_engine* uc, const uc_hook hook) + : uc_(uc), + hook_(hook) + { + } - ~unicorn_hook() - { - release(); - } + ~unicorn_hook() + { + release(); + } - unicorn_hook(const unicorn_hook&) = delete; - unicorn_hook& operator=(const unicorn_hook&) = delete; + unicorn_hook(const unicorn_hook&) = delete; + unicorn_hook& operator=(const unicorn_hook&) = delete; + unicorn_hook(unicorn_hook&& obj) noexcept + { + this->operator=(std::move(obj)); + } - unicorn_hook(unicorn_hook&& obj) noexcept - { - this->operator=(std::move(obj)); - } + uc_hook* make_reference() + { + if (!this->uc_) + { + throw std::runtime_error("Cannot make reference on default constructed hook"); + } - uc_hook* make_reference() - { - if (!this->uc_) - { - throw std::runtime_error("Cannot make reference on default constructed hook"); - } + this->release(); + return &this->hook_; + } - this->release(); - return &this->hook_; - } + unicorn_hook& operator=(unicorn_hook&& obj) noexcept + { + if (this != &obj) + { + this->release(); - unicorn_hook& operator=(unicorn_hook&& obj) noexcept - { - if (this != &obj) - { - this->release(); + this->uc_ = obj.uc_; + this->hook_ = obj.hook_; - this->uc_ = obj.uc_; - this->hook_ = obj.hook_; + obj.hook_ = {}; + obj.uc_ = {}; + } - obj.hook_ = {}; - obj.uc_ = {}; - } + return *this; + } - return *this; - } + void release() + { + if (this->hook_ && this->uc_) + { + uc_hook_del(this->uc_, this->hook_); + this->hook_ = {}; + } + } - void release() - { - if (this->hook_ && this->uc_) - { - uc_hook_del(this->uc_, this->hook_); - this->hook_ = {}; - } - } - - private: - uc_engine* uc_{}; - uc_hook hook_{}; - }; + private: + uc_engine* uc_{}; + uc_hook hook_{}; + }; } diff --git a/src/unicorn-emulator/unicorn_memory_regions.hpp b/src/unicorn-emulator/unicorn_memory_regions.hpp index 55bc6a6c..b6452691 100644 --- a/src/unicorn-emulator/unicorn_memory_regions.hpp +++ b/src/unicorn-emulator/unicorn_memory_regions.hpp @@ -6,62 +6,61 @@ namespace unicorn { - class unicorn_memory_regions - { - public: - unicorn_memory_regions(uc_engine* uc) - { - uce(uc_mem_regions(uc, &this->regions_, &this->count_)); - } + class unicorn_memory_regions + { + public: + unicorn_memory_regions(uc_engine* uc) + { + uce(uc_mem_regions(uc, &this->regions_, &this->count_)); + } + ~unicorn_memory_regions() + { + this->release(); + } - ~unicorn_memory_regions() - { - this->release(); - } + unicorn_memory_regions(const unicorn_memory_regions&) = delete; + unicorn_memory_regions& operator=(const unicorn_memory_regions&) = delete; - unicorn_memory_regions(const unicorn_memory_regions&) = delete; - unicorn_memory_regions& operator=(const unicorn_memory_regions&) = delete; + unicorn_memory_regions(unicorn_memory_regions&& obj) noexcept + { + this->operator=(std::move(obj)); + } - unicorn_memory_regions(unicorn_memory_regions&& obj) noexcept - { - this->operator=(std::move(obj)); - } + unicorn_memory_regions& operator=(unicorn_memory_regions&& obj) noexcept + { + if (this != &obj) + { + this->release(); - unicorn_memory_regions& operator=(unicorn_memory_regions&& obj) noexcept - { - if (this != &obj) - { - this->release(); + this->count_ = obj.count_; + this->regions_ = obj.regions_; - this->count_ = obj.count_; - this->regions_ = obj.regions_; + obj.count_ = {}; + obj.regions_ = nullptr; + } - obj.count_ = {}; - obj.regions_ = nullptr; - } + return *this; + } - return *this; - } + std::span get_span() const + { + return {this->regions_, this->count_}; + } - std::span get_span() const - { - return {this->regions_, this->count_}; - } + private: + uint32_t count_{}; + uc_mem_region* regions_{}; - private: - uint32_t count_{}; - uc_mem_region* regions_{}; + void release() + { + if (this->regions_) + { + uc_free(regions_); + } - void release() - { - if (this->regions_) - { - uc_free(regions_); - } - - this->count_ = {}; - this->regions_ = nullptr; - } - }; + this->count_ = {}; + this->regions_ = nullptr; + } + }; } diff --git a/src/unicorn-emulator/unicorn_x64_emulator.cpp b/src/unicorn-emulator/unicorn_x64_emulator.cpp index 4bac8420..2fe9f4ef 100644 --- a/src/unicorn-emulator/unicorn_x64_emulator.cpp +++ b/src/unicorn-emulator/unicorn_x64_emulator.cpp @@ -9,654 +9,629 @@ namespace unicorn { - namespace - { - static_assert(static_cast(memory_permission::none) == UC_PROT_NONE); - static_assert(static_cast(memory_permission::read) == UC_PROT_READ); - static_assert(static_cast(memory_permission::exec) == UC_PROT_EXEC); - static_assert(static_cast(memory_permission::all) == UC_PROT_ALL); + namespace + { + static_assert(static_cast(memory_permission::none) == UC_PROT_NONE); + static_assert(static_cast(memory_permission::read) == UC_PROT_READ); + static_assert(static_cast(memory_permission::exec) == UC_PROT_EXEC); + static_assert(static_cast(memory_permission::all) == UC_PROT_ALL); - static_assert(static_cast(x64_register::end) == UC_X86_REG_ENDING); + static_assert(static_cast(x64_register::end) == UC_X86_REG_ENDING); - uc_x86_insn map_hookable_instruction(const x64_hookable_instructions instruction) - { - switch (instruction) - { - case x64_hookable_instructions::syscall: - return UC_X86_INS_SYSCALL; - case x64_hookable_instructions::cpuid: - return UC_X86_INS_CPUID; - case x64_hookable_instructions::rdtsc: - return UC_X86_INS_RDTSC; - case x64_hookable_instructions::rdtscp: - return UC_X86_INS_RDTSCP; - default: - throw std::runtime_error("Bad instruction for mapping"); - } - } + uc_x86_insn map_hookable_instruction(const x64_hookable_instructions instruction) + { + switch (instruction) + { + case x64_hookable_instructions::syscall: + return UC_X86_INS_SYSCALL; + case x64_hookable_instructions::cpuid: + return UC_X86_INS_CPUID; + case x64_hookable_instructions::rdtsc: + return UC_X86_INS_RDTSC; + case x64_hookable_instructions::rdtscp: + return UC_X86_INS_RDTSCP; + default: + throw std::runtime_error("Bad instruction for mapping"); + } + } - memory_violation_type map_memory_violation_type(const uc_mem_type mem_type) - { - switch (mem_type) - { - case UC_MEM_READ_PROT: - case UC_MEM_WRITE_PROT: - case UC_MEM_FETCH_PROT: - return memory_violation_type::protection; - case UC_MEM_READ_UNMAPPED: - case UC_MEM_WRITE_UNMAPPED: - case UC_MEM_FETCH_UNMAPPED: - return memory_violation_type::unmapped; - default: - throw std::runtime_error("Memory type does not constitute a violation"); - } - } + memory_violation_type map_memory_violation_type(const uc_mem_type mem_type) + { + switch (mem_type) + { + case UC_MEM_READ_PROT: + case UC_MEM_WRITE_PROT: + case UC_MEM_FETCH_PROT: + return memory_violation_type::protection; + case UC_MEM_READ_UNMAPPED: + case UC_MEM_WRITE_UNMAPPED: + case UC_MEM_FETCH_UNMAPPED: + return memory_violation_type::unmapped; + default: + throw std::runtime_error("Memory type does not constitute a violation"); + } + } - memory_operation map_memory_operation(const uc_mem_type mem_type) - { - switch (mem_type) - { - case UC_MEM_READ: - case UC_MEM_READ_PROT: - case UC_MEM_READ_UNMAPPED: - return memory_operation::read; - case UC_MEM_WRITE: - case UC_MEM_WRITE_PROT: - case UC_MEM_WRITE_UNMAPPED: - return memory_operation::write; - case UC_MEM_FETCH: - case UC_MEM_FETCH_PROT: - case UC_MEM_FETCH_UNMAPPED: - return memory_operation::exec; - default: - return memory_operation::none; - } - } + memory_operation map_memory_operation(const uc_mem_type mem_type) + { + switch (mem_type) + { + case UC_MEM_READ: + case UC_MEM_READ_PROT: + case UC_MEM_READ_UNMAPPED: + return memory_operation::read; + case UC_MEM_WRITE: + case UC_MEM_WRITE_PROT: + case UC_MEM_WRITE_UNMAPPED: + return memory_operation::write; + case UC_MEM_FETCH: + case UC_MEM_FETCH_PROT: + case UC_MEM_FETCH_UNMAPPED: + return memory_operation::exec; + default: + return memory_operation::none; + } + } - struct hook_object : object - { - emulator_hook* as_opaque_hook() - { - return reinterpret_cast(this); - } - }; + struct hook_object : object + { + emulator_hook* as_opaque_hook() + { + return reinterpret_cast(this); + } + }; - class hook_container : public hook_object - { - public: - template - requires(std::is_base_of_v - && std::is_move_constructible_v) - void add(T data, unicorn_hook hook) - { - hook_entry entry{}; + class hook_container : public hook_object + { + public: + template + requires(std::is_base_of_v && std::is_move_constructible_v) + void add(T data, unicorn_hook hook) + { + hook_entry entry{}; - entry.data = std::make_unique(std::move(data)); - entry.hook = std::move(hook); + entry.data = std::make_unique(std::move(data)); + entry.hook = std::move(hook); - this->hooks_.emplace_back(std::move(entry)); - } + this->hooks_.emplace_back(std::move(entry)); + } - private: - struct hook_entry - { - std::unique_ptr data{}; - unicorn_hook hook{}; - }; + private: + struct hook_entry + { + std::unique_ptr data{}; + unicorn_hook hook{}; + }; - std::vector hooks_; - }; + std::vector hooks_; + }; - struct mmio_callbacks - { - using read_wrapper = function_wrapper; - using write_wrapper = function_wrapper; + struct mmio_callbacks + { + using read_wrapper = function_wrapper; + using write_wrapper = function_wrapper; - read_wrapper read{}; - write_wrapper write{}; - }; + read_wrapper read{}; + write_wrapper write{}; + }; - class uc_context_serializer - { - public: - uc_context_serializer(uc_engine* uc, const bool in_place) - : uc_(uc) - { - if (in_place) - { - // Unicorn stores pointers in the struct. The serialization here is broken - throw std::runtime_error("Memory saving not supported atm"); - } + class uc_context_serializer + { + public: + uc_context_serializer(uc_engine* uc, const bool in_place) + : uc_(uc) + { + if (in_place) + { + // Unicorn stores pointers in the struct. The serialization here is broken + throw std::runtime_error("Memory saving not supported atm"); + } #ifndef OS_WINDOWS #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wconversion" #endif - uc_ctl_context_mode(uc, UC_CTL_CONTEXT_CPU | (in_place ? UC_CTL_CONTEXT_MEMORY : 0)); + uc_ctl_context_mode(uc, UC_CTL_CONTEXT_CPU | (in_place ? UC_CTL_CONTEXT_MEMORY : 0)); #ifndef OS_WINDOWS #pragma GCC diagnostic pop #endif - this->size_ = uc_context_size(uc); - uce(uc_context_alloc(uc, &this->context_)); - } + this->size_ = uc_context_size(uc); + uce(uc_context_alloc(uc, &this->context_)); + } - ~uc_context_serializer() - { - if (this->context_) - { - (void)uc_context_free(this->context_); - } - } + ~uc_context_serializer() + { + if (this->context_) + { + (void)uc_context_free(this->context_); + } + } - void serialize(utils::buffer_serializer& buffer) const - { - uce(uc_context_save(this->uc_, this->context_)); - buffer.write(this->context_, this->size_); - } + void serialize(utils::buffer_serializer& buffer) const + { + uce(uc_context_save(this->uc_, this->context_)); + buffer.write(this->context_, this->size_); + } - void deserialize(utils::buffer_deserializer& buffer) const - { - buffer.read(this->context_, this->size_); - uce(uc_context_restore(this->uc_, this->context_)); - } + void deserialize(utils::buffer_deserializer& buffer) const + { + buffer.read(this->context_, this->size_); + uce(uc_context_restore(this->uc_, this->context_)); + } - uc_context_serializer(uc_context_serializer&&) = delete; - uc_context_serializer(const uc_context_serializer&) = delete; - uc_context_serializer& operator=(uc_context_serializer&&) = delete; - uc_context_serializer& operator=(const uc_context_serializer&) = delete; + uc_context_serializer(uc_context_serializer&&) = delete; + uc_context_serializer(const uc_context_serializer&) = delete; + uc_context_serializer& operator=(uc_context_serializer&&) = delete; + uc_context_serializer& operator=(const uc_context_serializer&) = delete; - private: - uc_engine* uc_{}; - uc_context* context_{}; - size_t size_{}; - }; + private: + uc_engine* uc_{}; + uc_context* context_{}; + size_t size_{}; + }; - void add_read_hook(uc_engine* uc, const uint64_t address, const size_t size, hook_container& container, - const std::shared_ptr& callback) - { - function_wrapper wrapper( - [callback](uc_engine*, const uc_mem_type type, const uint64_t address, const int size, - const int64_t) - { - const auto operation = map_memory_operation(type); - if (operation != memory_permission::none) - { - (*callback)(address, static_cast(size), 0, operation); - } - }); + void add_read_hook(uc_engine* uc, const uint64_t address, const size_t size, hook_container& container, + const std::shared_ptr& callback) + { + function_wrapper wrapper( + [callback](uc_engine*, const uc_mem_type type, const uint64_t address, const int size, const int64_t) { + const auto operation = map_memory_operation(type); + if (operation != memory_permission::none) + { + (*callback)(address, static_cast(size), 0, operation); + } + }); - unicorn_hook hook{uc}; + unicorn_hook hook{uc}; - uce(uc_hook_add(uc, hook.make_reference(), UC_HOOK_MEM_READ, wrapper.get_function(), - wrapper.get_user_data(), address, address + size)); + uce(uc_hook_add(uc, hook.make_reference(), UC_HOOK_MEM_READ, wrapper.get_function(), + wrapper.get_user_data(), address, address + size)); - container.add(std::move(wrapper), std::move(hook)); - } + container.add(std::move(wrapper), std::move(hook)); + } - void add_write_hook(uc_engine* uc, const uint64_t address, const size_t size, hook_container& container, - const std::shared_ptr& callback) - { - function_wrapper wrapper( - [callback](uc_engine*, const uc_mem_type type, const uint64_t address, const int size, - const uint64_t value) - { - const auto operation = map_memory_operation(type); - if (operation != memory_permission::none) - { - (*callback)(address, static_cast(size), value, operation); - } - }); + void add_write_hook(uc_engine* uc, const uint64_t address, const size_t size, hook_container& container, + const std::shared_ptr& callback) + { + function_wrapper wrapper( + [callback](uc_engine*, const uc_mem_type type, const uint64_t address, const int size, + const uint64_t value) { + const auto operation = map_memory_operation(type); + if (operation != memory_permission::none) + { + (*callback)(address, static_cast(size), value, operation); + } + }); - unicorn_hook hook{uc}; + unicorn_hook hook{uc}; - uce(uc_hook_add(uc, hook.make_reference(), UC_HOOK_MEM_WRITE, wrapper.get_function(), - wrapper.get_user_data(), address, address + size)); + uce(uc_hook_add(uc, hook.make_reference(), UC_HOOK_MEM_WRITE, wrapper.get_function(), + wrapper.get_user_data(), address, address + size)); - container.add(std::move(wrapper), std::move(hook)); - } + container.add(std::move(wrapper), std::move(hook)); + } - void add_exec_hook(uc_engine* uc, const uint64_t address, const size_t size, hook_container& container, - const std::shared_ptr& callback) - { - function_wrapper wrapper( - [callback](uc_engine*, const uint64_t address, const uint32_t size) - { - (*callback)(address, size, 0, memory_permission::exec); - }); + void add_exec_hook(uc_engine* uc, const uint64_t address, const size_t size, hook_container& container, + const std::shared_ptr& callback) + { + function_wrapper wrapper( + [callback](uc_engine*, const uint64_t address, const uint32_t size) { + (*callback)(address, size, 0, memory_permission::exec); + }); - unicorn_hook hook{uc}; + unicorn_hook hook{uc}; - uce(uc_hook_add(uc, hook.make_reference(), UC_HOOK_CODE, wrapper.get_function(), - wrapper.get_user_data(), address, address + size)); + uce(uc_hook_add(uc, hook.make_reference(), UC_HOOK_CODE, wrapper.get_function(), wrapper.get_user_data(), + address, address + size)); - container.add(std::move(wrapper), std::move(hook)); - } + container.add(std::move(wrapper), std::move(hook)); + } - basic_block map_block(const uc_tb& translation_block) - { - basic_block block{}; + basic_block map_block(const uc_tb& translation_block) + { + basic_block block{}; - block.address = translation_block.pc; - block.instruction_count = translation_block.icount; - block.size = translation_block.size; + block.address = translation_block.pc; + block.instruction_count = translation_block.icount; + block.size = translation_block.size; - return block; - } + return block; + } - class unicorn_x64_emulator : public x64_emulator - { - public: - unicorn_x64_emulator() - { - uce(uc_open(UC_ARCH_X86, UC_MODE_64, &this->uc_)); + class unicorn_x64_emulator : public x64_emulator + { + public: + unicorn_x64_emulator() + { + uce(uc_open(UC_ARCH_X86, UC_MODE_64, &this->uc_)); #ifndef OS_WINDOWS #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wconversion" #endif - uce(uc_ctl_set_tcg_buffer_size(this->uc_, 2 << 30 /* 2 gb */)); + uce(uc_ctl_set_tcg_buffer_size(this->uc_, 2 << 30 /* 2 gb */)); #ifndef OS_WINDOWS #pragma GCC diagnostic pop #endif - } - - ~unicorn_x64_emulator() override - { - this->hooks_.clear(); - uc_close(this->uc_); - } - - void start(const uint64_t start, const uint64_t end, std::chrono::nanoseconds timeout, - const size_t count) override - { - if (timeout.count() < 0) - { - timeout = {}; - } - - this->has_violation_ = false; - const auto timeoutYs = std::chrono::duration_cast(timeout); - const auto res = uc_emu_start(*this, start, end, static_cast(timeoutYs.count()), - count); - if (res == UC_ERR_OK) - { - return; - } - - const auto is_violation = // - res == UC_ERR_READ_UNMAPPED || // - res == UC_ERR_WRITE_UNMAPPED || // - res == UC_ERR_FETCH_UNMAPPED || // - res == UC_ERR_READ_PROT || // - res == UC_ERR_WRITE_PROT || // - res == UC_ERR_FETCH_PROT; - - if (!is_violation || !this->has_violation_) - { - uce(res); - } - } - - void stop() override - { - uce(uc_emu_stop(*this)); - } - - void write_raw_register(const int reg, const void* value, const size_t size) override - { - size_t result_size = size; - uce(uc_reg_write2(*this, reg, value, &result_size)); - - if (size < result_size) - { - throw std::runtime_error( - "Register size mismatch: " + std::to_string(size) + " != " + std::to_string(result_size)); - } - } - - void read_raw_register(const int reg, void* value, const size_t size) override - { - size_t result_size = size; - memset(value, 0, size); - uce(uc_reg_read2(*this, reg, value, &result_size)); - - if (size < result_size) - { - throw std::runtime_error( - "Register size mismatch: " + std::to_string(size) + " != " + std::to_string(result_size)); - } - } - - void map_mmio(const uint64_t address, const size_t size, mmio_read_callback read_cb, - mmio_write_callback write_cb) override - { - mmio_callbacks cb{ - .read = mmio_callbacks::read_wrapper( - [c = std::move(read_cb)](uc_engine*, const uint64_t addr, const uint32_t s) - { - return c(addr, s); - }), - .write = mmio_callbacks::write_wrapper( - [c = std::move(write_cb)](uc_engine*, const uint64_t addr, const uint32_t s, - const uint64_t value) - { - c(addr, s, value); - }) - }; - - uce(uc_mmio_map(*this, address, size, cb.read.get_c_function(), cb.read.get_user_data(), - cb.write.get_c_function(), cb.write.get_user_data())); - - this->mmio_[address] = std::move(cb); - } - - void map_memory(const uint64_t address, const size_t size, memory_permission permissions) override - { - uce(uc_mem_map(*this, address, size, static_cast(permissions))); - } - - void unmap_memory(const uint64_t address, const size_t size) override - { - uce(uc_mem_unmap(*this, address, size)); - - const auto mmio_entry = this->mmio_.find(address); - if (mmio_entry != this->mmio_.end()) - { - this->mmio_.erase(mmio_entry); - } - } - - bool try_read_memory(const uint64_t address, void* data, const size_t size) const override - { - return uc_mem_read(*this, address, data, size) == UC_ERR_OK; - } - - void read_memory(const uint64_t address, void* data, const size_t size) const override - { - uce(uc_mem_read(*this, address, data, size)); - } - - void write_memory(const uint64_t address, const void* data, const size_t size) override - { - uce(uc_mem_write(*this, address, data, size)); - } - - void apply_memory_protection(const uint64_t address, const size_t size, - memory_permission permissions) override - { - uce(uc_mem_protect(*this, address, size, static_cast(permissions))); - } - - emulator_hook* hook_instruction(int instruction_type, - instruction_hook_callback callback) override - { - function_wrapper wrapper([c = std::move(callback)](uc_engine*) - { - return (c() == instruction_hook_continuation::skip_instruction) - ? 1 - : 0; - }); - - unicorn_hook hook{*this}; - auto container = std::make_unique(); - - const auto inst_type = static_cast(instruction_type); - - if (inst_type == x64_hookable_instructions::invalid) - { - uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_INSN_INVALID, wrapper.get_function(), - wrapper.get_user_data(), 0, std::numeric_limits::max())); - } - else - { - const auto uc_instruction = map_hookable_instruction(inst_type); - uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_INSN, wrapper.get_function(), - wrapper.get_user_data(), 0, std::numeric_limits::max(), - uc_instruction)); - } - - container->add(std::move(wrapper), std::move(hook)); - - auto* result = container->as_opaque_hook(); - - this->hooks_.push_back(std::move(container)); - - return result; - } - - emulator_hook* hook_basic_block(basic_block_hook_callback callback) override - { - function_wrapper wrapper( - [c = std::move(callback)](uc_engine*, const uint64_t address, const size_t size) - { - basic_block block{}; - block.address = address; - block.size = size; - - c(block); - }); - - unicorn_hook hook{*this}; - auto container = std::make_unique(); - - uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_BLOCK, wrapper.get_function(), - wrapper.get_user_data(), 0, std::numeric_limits::max()) - ); - - container->add(std::move(wrapper), std::move(hook)); - - auto* result = container->as_opaque_hook(); - this->hooks_.push_back(std::move(container)); - return result; - } - - emulator_hook* hook_edge_generation(edge_generation_hook_callback callback) override - { - function_wrapper wrapper( - [c = std::move(callback)](uc_engine*, const uc_tb* cur_tb, const uc_tb* prev_tb) - { - const auto current_block = map_block(*cur_tb); - const auto previous_block = map_block(*prev_tb); - - c(current_block, previous_block); - }); - - unicorn_hook hook{*this}; - auto container = std::make_unique(); - - uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_EDGE_GENERATED, wrapper.get_function(), - wrapper.get_user_data(), 0, std::numeric_limits::max()) - ); - - container->add(std::move(wrapper), std::move(hook)); - - auto* result = container->as_opaque_hook(); - this->hooks_.push_back(std::move(container)); - return result; - } - - emulator_hook* hook_interrupt(interrupt_hook_callback callback) override - { - function_wrapper wrapper( - [c = std::move(callback)](uc_engine*, const int interrupt_type) - { - c(interrupt_type); - }); - - unicorn_hook hook{*this}; - auto container = std::make_unique(); - - uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_INTR, wrapper.get_function(), - wrapper.get_user_data(), 0, std::numeric_limits::max()) - ); - - container->add(std::move(wrapper), std::move(hook)); - - auto* result = container->as_opaque_hook(); - this->hooks_.push_back(std::move(container)); - return result; - } - - emulator_hook* hook_memory_violation(uint64_t address, size_t size, - memory_violation_hook_callback callback) override - { - function_wrapper wrapper( - [c = std::move(callback), this](uc_engine*, const uc_mem_type type, - const uint64_t address, const int size, const int64_t) - { - const auto ip = this->read_instruction_pointer(); - - assert(size >= 0); - const auto operation = map_memory_operation(type); - const auto violation = map_memory_violation_type(type); - - const auto resume = c(address, static_cast(size), operation, violation) == - memory_violation_continuation::resume; - - const auto has_ip_changed = ip != this->read_instruction_pointer(); - - if (!resume) - { - return false; - } - - this->has_violation_ = resume && has_ip_changed; - - if (has_ip_changed) - { - return false; - } - - return true; - }); - - unicorn_hook hook{*this}; - auto container = std::make_unique(); - - uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_MEM_INVALID, wrapper.get_function(), - wrapper.get_user_data(), address, size)); - - container->add(std::move(wrapper), std::move(hook)); - - auto* result = container->as_opaque_hook(); - this->hooks_.push_back(std::move(container)); - return result; - } - - emulator_hook* hook_memory_access(const uint64_t address, const size_t size, const memory_operation filter, - complex_memory_hook_callback callback) override - { - if (filter == memory_permission::none) - { - return nullptr; - } - - const auto shared_callback = std::make_shared(std::move(callback)); - - auto container = std::make_unique(); - - if ((filter & memory_operation::read) != memory_operation::none) - { - add_read_hook(*this, address, size, *container, shared_callback); - } - - if ((filter & memory_operation::write) != memory_operation::none) - { - add_write_hook(*this, address, size, *container, shared_callback); - } - - if ((filter & memory_operation::exec) != memory_operation::none) - { - add_exec_hook(*this, address, size, *container, shared_callback); - } - - auto* result = container->as_opaque_hook(); - - this->hooks_.push_back(std::move(container)); - - return result; - } - - void delete_hook(emulator_hook* hook) override - { - const auto entry = std::ranges::find_if(this->hooks_, [&](const std::unique_ptr& hook_ptr) - { - return hook_ptr->as_opaque_hook() == hook; - }); - - if (entry != this->hooks_.end()) - { - this->hooks_.erase(entry); - } - } - - operator uc_engine*() const - { - return this->uc_; - } - - void serialize_state(utils::buffer_serializer& buffer, const bool is_snapshot) const override - { - if (this->has_snapshots_ && !is_snapshot) - { - // TODO: Investigate if this is really necessary - throw std::runtime_error("Unable to serialize after snapshot was taken!"); - } - - this->has_snapshots_ |= is_snapshot; - - const uc_context_serializer serializer(this->uc_, is_snapshot); - serializer.serialize(buffer); - } - - void deserialize_state(utils::buffer_deserializer& buffer, const bool is_snapshot) override - { - if (this->has_snapshots_ && !is_snapshot) - { - // TODO: Investigate if this is really necessary - throw std::runtime_error("Unable to deserialize after snapshot was taken!"); - } - - const uc_context_serializer serializer(this->uc_, is_snapshot); - serializer.deserialize(buffer); - } - - std::vector save_registers() override - { - utils::buffer_serializer buffer{}; - const uc_context_serializer serializer(this->uc_, false); - serializer.serialize(buffer); - return buffer.move_buffer(); - } - - void restore_registers(const std::vector& register_data) override - { - utils::buffer_deserializer buffer{register_data}; - const uc_context_serializer serializer(this->uc_, false); - serializer.deserialize(buffer); - } - - bool has_violation() const override - { - return this->has_violation_; - } - - private: - mutable bool has_snapshots_{false}; - uc_engine* uc_{}; - bool has_violation_{false}; - std::vector> hooks_{}; - std::unordered_map mmio_{}; - }; - } - - std::unique_ptr create_x64_emulator() - { - return std::make_unique(); - } + } + + ~unicorn_x64_emulator() override + { + this->hooks_.clear(); + uc_close(this->uc_); + } + + void start(const uint64_t start, const uint64_t end, std::chrono::nanoseconds timeout, + const size_t count) override + { + if (timeout.count() < 0) + { + timeout = {}; + } + + this->has_violation_ = false; + const auto timeoutYs = std::chrono::duration_cast(timeout); + const auto res = uc_emu_start(*this, start, end, static_cast(timeoutYs.count()), count); + if (res == UC_ERR_OK) + { + return; + } + + const auto is_violation = // + res == UC_ERR_READ_UNMAPPED || // + res == UC_ERR_WRITE_UNMAPPED || // + res == UC_ERR_FETCH_UNMAPPED || // + res == UC_ERR_READ_PROT || // + res == UC_ERR_WRITE_PROT || // + res == UC_ERR_FETCH_PROT; + + if (!is_violation || !this->has_violation_) + { + uce(res); + } + } + + void stop() override + { + uce(uc_emu_stop(*this)); + } + + void write_raw_register(const int reg, const void* value, const size_t size) override + { + size_t result_size = size; + uce(uc_reg_write2(*this, reg, value, &result_size)); + + if (size < result_size) + { + throw std::runtime_error("Register size mismatch: " + std::to_string(size) + + " != " + std::to_string(result_size)); + } + } + + void read_raw_register(const int reg, void* value, const size_t size) override + { + size_t result_size = size; + memset(value, 0, size); + uce(uc_reg_read2(*this, reg, value, &result_size)); + + if (size < result_size) + { + throw std::runtime_error("Register size mismatch: " + std::to_string(size) + + " != " + std::to_string(result_size)); + } + } + + void map_mmio(const uint64_t address, const size_t size, mmio_read_callback read_cb, + mmio_write_callback write_cb) override + { + mmio_callbacks cb{.read = mmio_callbacks::read_wrapper( + [c = std::move(read_cb)](uc_engine*, const uint64_t addr, const uint32_t s) { + return c(addr, s); + }), + .write = mmio_callbacks::write_wrapper( + [c = std::move(write_cb)](uc_engine*, const uint64_t addr, const uint32_t s, + const uint64_t value) { c(addr, s, value); })}; + + uce(uc_mmio_map(*this, address, size, cb.read.get_c_function(), cb.read.get_user_data(), + cb.write.get_c_function(), cb.write.get_user_data())); + + this->mmio_[address] = std::move(cb); + } + + void map_memory(const uint64_t address, const size_t size, memory_permission permissions) override + { + uce(uc_mem_map(*this, address, size, static_cast(permissions))); + } + + void unmap_memory(const uint64_t address, const size_t size) override + { + uce(uc_mem_unmap(*this, address, size)); + + const auto mmio_entry = this->mmio_.find(address); + if (mmio_entry != this->mmio_.end()) + { + this->mmio_.erase(mmio_entry); + } + } + + bool try_read_memory(const uint64_t address, void* data, const size_t size) const override + { + return uc_mem_read(*this, address, data, size) == UC_ERR_OK; + } + + void read_memory(const uint64_t address, void* data, const size_t size) const override + { + uce(uc_mem_read(*this, address, data, size)); + } + + void write_memory(const uint64_t address, const void* data, const size_t size) override + { + uce(uc_mem_write(*this, address, data, size)); + } + + void apply_memory_protection(const uint64_t address, const size_t size, + memory_permission permissions) override + { + uce(uc_mem_protect(*this, address, size, static_cast(permissions))); + } + + emulator_hook* hook_instruction(int instruction_type, instruction_hook_callback callback) override + { + function_wrapper wrapper([c = std::move(callback)](uc_engine*) { + return (c() == instruction_hook_continuation::skip_instruction) ? 1 : 0; + }); + + unicorn_hook hook{*this}; + auto container = std::make_unique(); + + const auto inst_type = static_cast(instruction_type); + + if (inst_type == x64_hookable_instructions::invalid) + { + uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_INSN_INVALID, wrapper.get_function(), + wrapper.get_user_data(), 0, std::numeric_limits::max())); + } + else + { + const auto uc_instruction = map_hookable_instruction(inst_type); + uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_INSN, wrapper.get_function(), + wrapper.get_user_data(), 0, std::numeric_limits::max(), + uc_instruction)); + } + + container->add(std::move(wrapper), std::move(hook)); + + auto* result = container->as_opaque_hook(); + + this->hooks_.push_back(std::move(container)); + + return result; + } + + emulator_hook* hook_basic_block(basic_block_hook_callback callback) override + { + function_wrapper wrapper( + [c = std::move(callback)](uc_engine*, const uint64_t address, const size_t size) { + basic_block block{}; + block.address = address; + block.size = size; + + c(block); + }); + + unicorn_hook hook{*this}; + auto container = std::make_unique(); + + uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_BLOCK, wrapper.get_function(), + wrapper.get_user_data(), 0, std::numeric_limits::max())); + + container->add(std::move(wrapper), std::move(hook)); + + auto* result = container->as_opaque_hook(); + this->hooks_.push_back(std::move(container)); + return result; + } + + emulator_hook* hook_edge_generation(edge_generation_hook_callback callback) override + { + function_wrapper wrapper( + [c = std::move(callback)](uc_engine*, const uc_tb* cur_tb, const uc_tb* prev_tb) { + const auto current_block = map_block(*cur_tb); + const auto previous_block = map_block(*prev_tb); + + c(current_block, previous_block); + }); + + unicorn_hook hook{*this}; + auto container = std::make_unique(); + + uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_EDGE_GENERATED, wrapper.get_function(), + wrapper.get_user_data(), 0, std::numeric_limits::max())); + + container->add(std::move(wrapper), std::move(hook)); + + auto* result = container->as_opaque_hook(); + this->hooks_.push_back(std::move(container)); + return result; + } + + emulator_hook* hook_interrupt(interrupt_hook_callback callback) override + { + function_wrapper wrapper( + [c = std::move(callback)](uc_engine*, const int interrupt_type) { c(interrupt_type); }); + + unicorn_hook hook{*this}; + auto container = std::make_unique(); + + uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_INTR, wrapper.get_function(), + wrapper.get_user_data(), 0, std::numeric_limits::max())); + + container->add(std::move(wrapper), std::move(hook)); + + auto* result = container->as_opaque_hook(); + this->hooks_.push_back(std::move(container)); + return result; + } + + emulator_hook* hook_memory_violation(uint64_t address, size_t size, + memory_violation_hook_callback callback) override + { + function_wrapper wrapper( + [c = std::move(callback), this](uc_engine*, const uc_mem_type type, const uint64_t address, + const int size, const int64_t) { + const auto ip = this->read_instruction_pointer(); + + assert(size >= 0); + const auto operation = map_memory_operation(type); + const auto violation = map_memory_violation_type(type); + + const auto resume = c(address, static_cast(size), operation, violation) == + memory_violation_continuation::resume; + + const auto has_ip_changed = ip != this->read_instruction_pointer(); + + if (!resume) + { + return false; + } + + this->has_violation_ = resume && has_ip_changed; + + if (has_ip_changed) + { + return false; + } + + return true; + }); + + unicorn_hook hook{*this}; + auto container = std::make_unique(); + + uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_MEM_INVALID, wrapper.get_function(), + wrapper.get_user_data(), address, size)); + + container->add(std::move(wrapper), std::move(hook)); + + auto* result = container->as_opaque_hook(); + this->hooks_.push_back(std::move(container)); + return result; + } + + emulator_hook* hook_memory_access(const uint64_t address, const size_t size, const memory_operation filter, + complex_memory_hook_callback callback) override + { + if (filter == memory_permission::none) + { + return nullptr; + } + + const auto shared_callback = std::make_shared(std::move(callback)); + + auto container = std::make_unique(); + + if ((filter & memory_operation::read) != memory_operation::none) + { + add_read_hook(*this, address, size, *container, shared_callback); + } + + if ((filter & memory_operation::write) != memory_operation::none) + { + add_write_hook(*this, address, size, *container, shared_callback); + } + + if ((filter & memory_operation::exec) != memory_operation::none) + { + add_exec_hook(*this, address, size, *container, shared_callback); + } + + auto* result = container->as_opaque_hook(); + + this->hooks_.push_back(std::move(container)); + + return result; + } + + void delete_hook(emulator_hook* hook) override + { + const auto entry = + std::ranges::find_if(this->hooks_, [&](const std::unique_ptr& hook_ptr) { + return hook_ptr->as_opaque_hook() == hook; + }); + + if (entry != this->hooks_.end()) + { + this->hooks_.erase(entry); + } + } + + operator uc_engine*() const + { + return this->uc_; + } + + void serialize_state(utils::buffer_serializer& buffer, const bool is_snapshot) const override + { + if (this->has_snapshots_ && !is_snapshot) + { + // TODO: Investigate if this is really necessary + throw std::runtime_error("Unable to serialize after snapshot was taken!"); + } + + this->has_snapshots_ |= is_snapshot; + + const uc_context_serializer serializer(this->uc_, is_snapshot); + serializer.serialize(buffer); + } + + void deserialize_state(utils::buffer_deserializer& buffer, const bool is_snapshot) override + { + if (this->has_snapshots_ && !is_snapshot) + { + // TODO: Investigate if this is really necessary + throw std::runtime_error("Unable to deserialize after snapshot was taken!"); + } + + const uc_context_serializer serializer(this->uc_, is_snapshot); + serializer.deserialize(buffer); + } + + std::vector save_registers() override + { + utils::buffer_serializer buffer{}; + const uc_context_serializer serializer(this->uc_, false); + serializer.serialize(buffer); + return buffer.move_buffer(); + } + + void restore_registers(const std::vector& register_data) override + { + utils::buffer_deserializer buffer{register_data}; + const uc_context_serializer serializer(this->uc_, false); + serializer.deserialize(buffer); + } + + bool has_violation() const override + { + return this->has_violation_; + } + + private: + mutable bool has_snapshots_{false}; + uc_engine* uc_{}; + bool has_violation_{false}; + std::vector> hooks_{}; + std::unordered_map mmio_{}; + }; + } + + std::unique_ptr create_x64_emulator() + { + return std::make_unique(); + } } diff --git a/src/unicorn-emulator/unicorn_x64_emulator.hpp b/src/unicorn-emulator/unicorn_x64_emulator.hpp index ca57015b..f0535a56 100644 --- a/src/unicorn-emulator/unicorn_x64_emulator.hpp +++ b/src/unicorn-emulator/unicorn_x64_emulator.hpp @@ -12,6 +12,6 @@ namespace unicorn { - UNICORN_EMULATOR_DLL_STORAGE - std::unique_ptr create_x64_emulator(); + UNICORN_EMULATOR_DLL_STORAGE + std::unique_ptr create_x64_emulator(); } diff --git a/src/windows-emulator-test/emulation_test.cpp b/src/windows-emulator-test/emulation_test.cpp index bddf56e3..9c6acd57 100644 --- a/src/windows-emulator-test/emulation_test.cpp +++ b/src/windows-emulator-test/emulation_test.cpp @@ -2,46 +2,46 @@ namespace test { - TEST(EmulationTest, BasicEmulationWorks) - { - auto emu = create_sample_emulator(); - emu.start(); + TEST(EmulationTest, BasicEmulationWorks) + { + auto emu = create_sample_emulator(); + emu.start(); - ASSERT_TERMINATED_SUCCESSFULLY(emu); - } + ASSERT_TERMINATED_SUCCESSFULLY(emu); + } - TEST(EmulationTest, CountedEmulationWorks) - { - constexpr auto count = 200000; + TEST(EmulationTest, CountedEmulationWorks) + { + constexpr auto count = 200000; - auto emu = create_sample_emulator(); - emu.start({}, count); + auto emu = create_sample_emulator(); + emu.start({}, count); - ASSERT_EQ(emu.process().executed_instructions, count); - } + ASSERT_EQ(emu.process().executed_instructions, count); + } - TEST(EmulationTest, CountedEmulationIsAccurate) - { - auto emu = create_sample_emulator(); - emu.start(); + TEST(EmulationTest, CountedEmulationIsAccurate) + { + auto emu = create_sample_emulator(); + emu.start(); - ASSERT_TERMINATED_SUCCESSFULLY(emu); + ASSERT_TERMINATED_SUCCESSFULLY(emu); - const auto executedInstructions = emu.process().executed_instructions; + const auto executedInstructions = emu.process().executed_instructions; - auto new_emu = create_sample_emulator(); + auto new_emu = create_sample_emulator(); - constexpr auto offset = 1; - const auto instructionsToExecute = executedInstructions - offset; + constexpr auto offset = 1; + const auto instructionsToExecute = executedInstructions - offset; - new_emu.start({}, instructionsToExecute); + new_emu.start({}, instructionsToExecute); - ASSERT_EQ(new_emu.process().executed_instructions, instructionsToExecute); - ASSERT_NOT_TERMINATED(new_emu); + ASSERT_EQ(new_emu.process().executed_instructions, instructionsToExecute); + ASSERT_NOT_TERMINATED(new_emu); - new_emu.start({}, offset); + new_emu.start({}, offset); - ASSERT_TERMINATED_SUCCESSFULLY(new_emu); - ASSERT_EQ(new_emu.process().executed_instructions, executedInstructions); - } + ASSERT_TERMINATED_SUCCESSFULLY(new_emu); + ASSERT_EQ(new_emu.process().executed_instructions, executedInstructions); + } } diff --git a/src/windows-emulator-test/emulation_test_utils.hpp b/src/windows-emulator-test/emulation_test_utils.hpp index cc934220..15bf4858 100644 --- a/src/windows-emulator-test/emulation_test_utils.hpp +++ b/src/windows-emulator-test/emulation_test_utils.hpp @@ -3,37 +3,36 @@ #include #include -#define ASSERT_NOT_TERMINATED(win_emu) \ - do { \ - ASSERT_FALSE((win_emu).process().exit_status.has_value()); \ - } while(false) +#define ASSERT_NOT_TERMINATED(win_emu) \ + do \ + { \ + ASSERT_FALSE((win_emu).process().exit_status.has_value()); \ + } while (false) +#define ASSERT_TERMINATED_WITH_STATUS(win_emu, status) \ + do \ + { \ + ASSERT_TRUE((win_emu).process().exit_status.has_value()); \ + ASSERT_EQ(*(win_emu).process().exit_status, status); \ + } while (false) -#define ASSERT_TERMINATED_WITH_STATUS(win_emu, status) \ - do { \ - ASSERT_TRUE((win_emu).process().exit_status.has_value()); \ - ASSERT_EQ(*(win_emu).process().exit_status, status); \ - } while(false) - -#define ASSERT_TERMINATED_SUCCESSFULLY(win_emu) \ - ASSERT_TERMINATED_WITH_STATUS(win_emu, STATUS_SUCCESS) +#define ASSERT_TERMINATED_SUCCESSFULLY(win_emu) ASSERT_TERMINATED_WITH_STATUS(win_emu, STATUS_SUCCESS) namespace test { - inline windows_emulator create_sample_emulator(emulator_settings settings) - { - settings.application = "./test-sample.exe"; - return windows_emulator{std::move(settings)}; - } + inline windows_emulator create_sample_emulator(emulator_settings settings) + { + settings.application = "./test-sample.exe"; + return windows_emulator{std::move(settings)}; + } - inline windows_emulator create_sample_emulator() - { - emulator_settings settings - { - .disable_logging = true, - .use_relative_time = true, - }; + inline windows_emulator create_sample_emulator() + { + emulator_settings settings{ + .disable_logging = true, + .use_relative_time = true, + }; - return create_sample_emulator(std::move(settings)); - } + return create_sample_emulator(std::move(settings)); + } } diff --git a/src/windows-emulator-test/main.cpp b/src/windows-emulator-test/main.cpp index cdf4fb81..978a5982 100644 --- a/src/windows-emulator-test/main.cpp +++ b/src/windows-emulator-test/main.cpp @@ -2,6 +2,6 @@ int main(int argc, char* argv[]) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } diff --git a/src/windows-emulator-test/serialization_test.cpp b/src/windows-emulator-test/serialization_test.cpp index 2dba1a19..835e7857 100644 --- a/src/windows-emulator-test/serialization_test.cpp +++ b/src/windows-emulator-test/serialization_test.cpp @@ -2,77 +2,77 @@ namespace test { - TEST(SerializationTest, SerializedDataIsReproducible) - { - auto emu1 = create_sample_emulator(); - emu1.start(); + TEST(SerializationTest, SerializedDataIsReproducible) + { + auto emu1 = create_sample_emulator(); + emu1.start(); - ASSERT_TERMINATED_SUCCESSFULLY(emu1); + ASSERT_TERMINATED_SUCCESSFULLY(emu1); - utils::buffer_serializer serializer1{}; - emu1.serialize(serializer1); + utils::buffer_serializer serializer1{}; + emu1.serialize(serializer1); - utils::buffer_deserializer deserializer{serializer1.get_buffer()}; + utils::buffer_deserializer deserializer{serializer1.get_buffer()}; - windows_emulator new_emu{}; - new_emu.deserialize(deserializer); + windows_emulator new_emu{}; + new_emu.deserialize(deserializer); - utils::buffer_serializer serializer2{}; - new_emu.serialize(serializer2); + utils::buffer_serializer serializer2{}; + new_emu.serialize(serializer2); - auto buffer1 = serializer1.move_buffer(); - auto buffer2 = serializer2.move_buffer(); + auto buffer1 = serializer1.move_buffer(); + auto buffer2 = serializer2.move_buffer(); - ASSERT_EQ(serializer1.get_buffer(), serializer2.get_buffer()); - } + ASSERT_EQ(serializer1.get_buffer(), serializer2.get_buffer()); + } - TEST(SerializationTest, EmulationIsReproducible) - { - auto emu1 = create_sample_emulator(); - emu1.start(); + TEST(SerializationTest, EmulationIsReproducible) + { + auto emu1 = create_sample_emulator(); + emu1.start(); - ASSERT_TERMINATED_SUCCESSFULLY(emu1); + ASSERT_TERMINATED_SUCCESSFULLY(emu1); - utils::buffer_serializer serializer1{}; - emu1.serialize(serializer1); + utils::buffer_serializer serializer1{}; + emu1.serialize(serializer1); - auto emu2 = create_sample_emulator(); - emu2.start(); + auto emu2 = create_sample_emulator(); + emu2.start(); - ASSERT_TERMINATED_SUCCESSFULLY(emu2); + ASSERT_TERMINATED_SUCCESSFULLY(emu2); - utils::buffer_serializer serializer2{}; - emu2.serialize(serializer2); + utils::buffer_serializer serializer2{}; + emu2.serialize(serializer2); - ASSERT_EQ(serializer1.get_buffer(), serializer2.get_buffer()); - } + ASSERT_EQ(serializer1.get_buffer(), serializer2.get_buffer()); + } - TEST(SerializationTest, DeserializedEmulatorBehavesLikeSource) - { - auto emu = create_sample_emulator(); - emu.start({}, 100); + TEST(SerializationTest, DeserializedEmulatorBehavesLikeSource) + { + auto emu = create_sample_emulator(); + emu.start({}, 100); - utils::buffer_serializer serializer{}; - emu.serialize(serializer); + utils::buffer_serializer serializer{}; + emu.serialize(serializer); - utils::buffer_deserializer deserializer{serializer.get_buffer()}; + utils::buffer_deserializer deserializer{serializer.get_buffer()}; - windows_emulator new_emu{}; - new_emu.log.disable_output(true); - new_emu.deserialize(deserializer); + windows_emulator new_emu{}; + new_emu.log.disable_output(true); + new_emu.deserialize(deserializer); - new_emu.start(); - ASSERT_TERMINATED_SUCCESSFULLY(new_emu); + new_emu.start(); + ASSERT_TERMINATED_SUCCESSFULLY(new_emu); - emu.start(); - ASSERT_TERMINATED_SUCCESSFULLY(emu); + emu.start(); + ASSERT_TERMINATED_SUCCESSFULLY(emu); - utils::buffer_serializer serializer1{}; - utils::buffer_serializer serializer2{}; + utils::buffer_serializer serializer1{}; + utils::buffer_serializer serializer2{}; - emu.serialize(serializer1); - new_emu.serialize(serializer2); + emu.serialize(serializer1); + new_emu.serialize(serializer2); - ASSERT_EQ(serializer1.get_buffer(), serializer2.get_buffer()); - } + ASSERT_EQ(serializer1.get_buffer(), serializer2.get_buffer()); + } } diff --git a/src/windows-emulator-test/time_test.cpp b/src/windows-emulator-test/time_test.cpp index 70f1971d..00158a05 100644 --- a/src/windows-emulator-test/time_test.cpp +++ b/src/windows-emulator-test/time_test.cpp @@ -2,44 +2,41 @@ namespace test { - TEST(TimeTest, SystemTimeIsAccurate) - { - std::string output_buffer{}; + TEST(TimeTest, SystemTimeIsAccurate) + { + std::string output_buffer{}; - const emulator_settings settings{ - .arguments = {u"-time"}, - .stdout_callback = [&output_buffer](const std::string_view data) - { - output_buffer.append(data); - }, - .disable_logging = true, - .use_relative_time = false, - }; + const emulator_settings settings{ + .arguments = {u"-time"}, + .stdout_callback = [&output_buffer](const std::string_view data) { output_buffer.append(data); }, + .disable_logging = true, + .use_relative_time = false, + }; - auto emu = create_sample_emulator(settings); - emu.start(); + auto emu = create_sample_emulator(settings); + emu.start(); - constexpr auto prefix = "Time: "sv; + constexpr auto prefix = "Time: "sv; - ASSERT_TERMINATED_SUCCESSFULLY(emu); - ASSERT_TRUE(output_buffer.starts_with(prefix)); + ASSERT_TERMINATED_SUCCESSFULLY(emu); + ASSERT_TRUE(output_buffer.starts_with(prefix)); - output_buffer = output_buffer.substr(prefix.size()); - while (!output_buffer.empty() && (output_buffer.back() == '\n' || output_buffer.back() == '\r')) - { - output_buffer.pop_back(); - } + output_buffer = output_buffer.substr(prefix.size()); + while (!output_buffer.empty() && (output_buffer.back() == '\n' || output_buffer.back() == '\r')) + { + output_buffer.pop_back(); + } - const auto time = strtoll(output_buffer.c_str(), nullptr, 10); + const auto time = strtoll(output_buffer.c_str(), nullptr, 10); - using time_point = std::chrono::system_clock::time_point; + using time_point = std::chrono::system_clock::time_point; - const time_point::duration time_duration(time); - const time_point tp(time_duration); + const time_point::duration time_duration(time); + const time_point tp(time_duration); - const auto now = std::chrono::system_clock::now(); - const auto diff = now - tp; + const auto now = std::chrono::system_clock::now(); + const auto diff = now - tp; - ASSERT_LE(diff, std::chrono::hours(1)); - } + ASSERT_LE(diff, std::chrono::hours(1)); + } } diff --git a/src/windows-emulator/context_frame.cpp b/src/windows-emulator/context_frame.cpp index 3ca0c9d4..01bd06d0 100644 --- a/src/windows-emulator/context_frame.cpp +++ b/src/windows-emulator/context_frame.cpp @@ -3,149 +3,149 @@ namespace context_frame { - void restore(x64_emulator& emu, const CONTEXT64& context) - { - if (context.ContextFlags & CONTEXT_DEBUG_REGISTERS_64) - { - emu.reg(x64_register::dr0, context.Dr0); - emu.reg(x64_register::dr1, context.Dr1); - emu.reg(x64_register::dr2, context.Dr2); - emu.reg(x64_register::dr3, context.Dr3); - emu.reg(x64_register::dr6, context.Dr6); - emu.reg(x64_register::dr7, context.Dr7); - } + void restore(x64_emulator& emu, const CONTEXT64& context) + { + if (context.ContextFlags & CONTEXT_DEBUG_REGISTERS_64) + { + emu.reg(x64_register::dr0, context.Dr0); + emu.reg(x64_register::dr1, context.Dr1); + emu.reg(x64_register::dr2, context.Dr2); + emu.reg(x64_register::dr3, context.Dr3); + emu.reg(x64_register::dr6, context.Dr6); + emu.reg(x64_register::dr7, context.Dr7); + } - if (context.ContextFlags & CONTEXT_CONTROL_64) - { - emu.reg(x64_register::ss, context.SegSs); - emu.reg(x64_register::cs, context.SegCs); + if (context.ContextFlags & CONTEXT_CONTROL_64) + { + emu.reg(x64_register::ss, context.SegSs); + emu.reg(x64_register::cs, context.SegCs); - emu.reg(x64_register::rip, context.Rip); - emu.reg(x64_register::rsp, context.Rsp); + emu.reg(x64_register::rip, context.Rip); + emu.reg(x64_register::rsp, context.Rsp); - emu.reg(x64_register::eflags, context.EFlags); - } + emu.reg(x64_register::eflags, context.EFlags); + } - if (context.ContextFlags & CONTEXT_INTEGER_64) - { - emu.reg(x64_register::rax, context.Rax); - emu.reg(x64_register::rbx, context.Rbx); - emu.reg(x64_register::rcx, context.Rcx); - emu.reg(x64_register::rdx, context.Rdx); - emu.reg(x64_register::rbp, context.Rbp); - emu.reg(x64_register::rsi, context.Rsi); - emu.reg(x64_register::rdi, context.Rdi); - emu.reg(x64_register::r8, context.R8); - emu.reg(x64_register::r9, context.R9); - emu.reg(x64_register::r10, context.R10); - emu.reg(x64_register::r11, context.R11); - emu.reg(x64_register::r12, context.R12); - emu.reg(x64_register::r13, context.R13); - emu.reg(x64_register::r14, context.R14); - emu.reg(x64_register::r15, context.R15); - } + if (context.ContextFlags & CONTEXT_INTEGER_64) + { + emu.reg(x64_register::rax, context.Rax); + emu.reg(x64_register::rbx, context.Rbx); + emu.reg(x64_register::rcx, context.Rcx); + emu.reg(x64_register::rdx, context.Rdx); + emu.reg(x64_register::rbp, context.Rbp); + emu.reg(x64_register::rsi, context.Rsi); + emu.reg(x64_register::rdi, context.Rdi); + emu.reg(x64_register::r8, context.R8); + emu.reg(x64_register::r9, context.R9); + emu.reg(x64_register::r10, context.R10); + emu.reg(x64_register::r11, context.R11); + emu.reg(x64_register::r12, context.R12); + emu.reg(x64_register::r13, context.R13); + emu.reg(x64_register::r14, context.R14); + emu.reg(x64_register::r15, context.R15); + } - /*if (context.ContextFlags & CONTEXT_SEGMENTS) - { - emu.reg(x64_register::ds, context.SegDs); - emu.reg(x64_register::es, context.SegEs); - emu.reg(x64_register::fs, context.SegFs); - emu.reg(x64_register::gs, context.SegGs); - }*/ + /*if (context.ContextFlags & CONTEXT_SEGMENTS) + { + emu.reg(x64_register::ds, context.SegDs); + emu.reg(x64_register::es, context.SegEs); + emu.reg(x64_register::fs, context.SegFs); + emu.reg(x64_register::gs, context.SegGs); + }*/ - if (context.ContextFlags & CONTEXT_FLOATING_POINT_64) - { - emu.reg(x64_register::fpcw, context.FltSave.ControlWord); - emu.reg(x64_register::fpsw, context.FltSave.StatusWord); - emu.reg(x64_register::fptag, context.FltSave.TagWord); + if (context.ContextFlags & CONTEXT_FLOATING_POINT_64) + { + emu.reg(x64_register::fpcw, context.FltSave.ControlWord); + emu.reg(x64_register::fpsw, context.FltSave.StatusWord); + emu.reg(x64_register::fptag, context.FltSave.TagWord); - for (int i = 0; i < 8; i++) - { - const auto reg = static_cast(static_cast(x64_register::st0) + i); - emu.reg(reg, context.FltSave.FloatRegisters[i]); - } - } + for (int i = 0; i < 8; i++) + { + const auto reg = static_cast(static_cast(x64_register::st0) + i); + emu.reg(reg, context.FltSave.FloatRegisters[i]); + } + } - if (context.ContextFlags & CONTEXT_XSTATE_64) - { - emu.reg(x64_register::mxcsr, context.MxCsr); + if (context.ContextFlags & CONTEXT_XSTATE_64) + { + emu.reg(x64_register::mxcsr, context.MxCsr); - for (int i = 0; i < 16; i++) - { - const auto reg = static_cast(static_cast(x64_register::xmm0) + i); - emu.reg(reg, (&context.Xmm0)[i]); - } - } - } + for (int i = 0; i < 16; i++) + { + const auto reg = static_cast(static_cast(x64_register::xmm0) + i); + emu.reg(reg, (&context.Xmm0)[i]); + } + } + } - void save(x64_emulator& emu, CONTEXT64& context) - { - if (context.ContextFlags & CONTEXT_DEBUG_REGISTERS_64) - { - context.Dr0 = emu.reg(x64_register::dr0); - context.Dr1 = emu.reg(x64_register::dr1); - context.Dr2 = emu.reg(x64_register::dr2); - context.Dr3 = emu.reg(x64_register::dr3); - context.Dr6 = emu.reg(x64_register::dr6); - context.Dr7 = emu.reg(x64_register::dr7); - } + void save(x64_emulator& emu, CONTEXT64& context) + { + if (context.ContextFlags & CONTEXT_DEBUG_REGISTERS_64) + { + context.Dr0 = emu.reg(x64_register::dr0); + context.Dr1 = emu.reg(x64_register::dr1); + context.Dr2 = emu.reg(x64_register::dr2); + context.Dr3 = emu.reg(x64_register::dr3); + context.Dr6 = emu.reg(x64_register::dr6); + context.Dr7 = emu.reg(x64_register::dr7); + } - if (context.ContextFlags & CONTEXT_CONTROL_64) - { - context.SegSs = emu.reg(x64_register::ss); - context.SegCs = emu.reg(x64_register::cs); - context.Rip = emu.reg(x64_register::rip); - context.Rsp = emu.reg(x64_register::rsp); - context.EFlags = emu.reg(x64_register::eflags); - } + if (context.ContextFlags & CONTEXT_CONTROL_64) + { + context.SegSs = emu.reg(x64_register::ss); + context.SegCs = emu.reg(x64_register::cs); + context.Rip = emu.reg(x64_register::rip); + context.Rsp = emu.reg(x64_register::rsp); + context.EFlags = emu.reg(x64_register::eflags); + } - if (context.ContextFlags & CONTEXT_INTEGER_64) - { - context.Rax = emu.reg(x64_register::rax); - context.Rbx = emu.reg(x64_register::rbx); - context.Rcx = emu.reg(x64_register::rcx); - context.Rdx = emu.reg(x64_register::rdx); - context.Rbp = emu.reg(x64_register::rbp); - context.Rsi = emu.reg(x64_register::rsi); - context.Rdi = emu.reg(x64_register::rdi); - context.R8 = emu.reg(x64_register::r8); - context.R9 = emu.reg(x64_register::r9); - context.R10 = emu.reg(x64_register::r10); - context.R11 = emu.reg(x64_register::r11); - context.R12 = emu.reg(x64_register::r12); - context.R13 = emu.reg(x64_register::r13); - context.R14 = emu.reg(x64_register::r14); - context.R15 = emu.reg(x64_register::r15); - } + if (context.ContextFlags & CONTEXT_INTEGER_64) + { + context.Rax = emu.reg(x64_register::rax); + context.Rbx = emu.reg(x64_register::rbx); + context.Rcx = emu.reg(x64_register::rcx); + context.Rdx = emu.reg(x64_register::rdx); + context.Rbp = emu.reg(x64_register::rbp); + context.Rsi = emu.reg(x64_register::rsi); + context.Rdi = emu.reg(x64_register::rdi); + context.R8 = emu.reg(x64_register::r8); + context.R9 = emu.reg(x64_register::r9); + context.R10 = emu.reg(x64_register::r10); + context.R11 = emu.reg(x64_register::r11); + context.R12 = emu.reg(x64_register::r12); + context.R13 = emu.reg(x64_register::r13); + context.R14 = emu.reg(x64_register::r14); + context.R15 = emu.reg(x64_register::r15); + } - if (context.ContextFlags & CONTEXT_SEGMENTS_64) - { - context.SegDs = emu.reg(x64_register::ds); - context.SegEs = emu.reg(x64_register::es); - context.SegFs = emu.reg(x64_register::fs); - context.SegGs = emu.reg(x64_register::gs); - } + if (context.ContextFlags & CONTEXT_SEGMENTS_64) + { + context.SegDs = emu.reg(x64_register::ds); + context.SegEs = emu.reg(x64_register::es); + context.SegFs = emu.reg(x64_register::fs); + context.SegGs = emu.reg(x64_register::gs); + } - if (context.ContextFlags & CONTEXT_FLOATING_POINT_64) - { - context.FltSave.ControlWord = emu.reg(x64_register::fpcw); - context.FltSave.StatusWord = emu.reg(x64_register::fpsw); - context.FltSave.TagWord = static_cast(emu.reg(x64_register::fptag)); - for (int i = 0; i < 8; i++) - { - const auto reg = static_cast(static_cast(x64_register::st0) + i); - context.FltSave.FloatRegisters[i] = emu.reg(reg); - } - } + if (context.ContextFlags & CONTEXT_FLOATING_POINT_64) + { + context.FltSave.ControlWord = emu.reg(x64_register::fpcw); + context.FltSave.StatusWord = emu.reg(x64_register::fpsw); + context.FltSave.TagWord = static_cast(emu.reg(x64_register::fptag)); + for (int i = 0; i < 8; i++) + { + const auto reg = static_cast(static_cast(x64_register::st0) + i); + context.FltSave.FloatRegisters[i] = emu.reg(reg); + } + } - if (context.ContextFlags & CONTEXT_XSTATE_64) - { - context.MxCsr = emu.reg(x64_register::mxcsr); - for (int i = 0; i < 16; i++) - { - const auto reg = static_cast(static_cast(x64_register::xmm0) + i); - (&context.Xmm0)[i] = emu.reg(reg); - } - } - } + if (context.ContextFlags & CONTEXT_XSTATE_64) + { + context.MxCsr = emu.reg(x64_register::mxcsr); + for (int i = 0; i < 16; i++) + { + const auto reg = static_cast(static_cast(x64_register::xmm0) + i); + (&context.Xmm0)[i] = emu.reg(reg); + } + } + } } diff --git a/src/windows-emulator/context_frame.hpp b/src/windows-emulator/context_frame.hpp index 9f922446..8f7e5bcd 100644 --- a/src/windows-emulator/context_frame.hpp +++ b/src/windows-emulator/context_frame.hpp @@ -3,6 +3,6 @@ namespace context_frame { - void save(x64_emulator& emu, CONTEXT64& context); - void restore(x64_emulator& emu, const CONTEXT64& context); + void save(x64_emulator& emu, CONTEXT64& context); + void restore(x64_emulator& emu, const CONTEXT64& context); } diff --git a/src/windows-emulator/debugging/gdb_stub.cpp b/src/windows-emulator/debugging/gdb_stub.cpp index 7d1d2fc1..6d38a08f 100644 --- a/src/windows-emulator/debugging/gdb_stub.cpp +++ b/src/windows-emulator/debugging/gdb_stub.cpp @@ -3,137 +3,134 @@ #include -extern "C" { +extern "C" +{ #include } namespace { - gdb_action_t map_gdb_action(const gdb_action action) - { - switch (action) - { - case gdb_action::none: - return ACT_NONE; - case gdb_action::resume: - return ACT_RESUME; - case gdb_action::shutdown: - return ACT_SHUTDOWN; - } + gdb_action_t map_gdb_action(const gdb_action action) + { + switch (action) + { + case gdb_action::none: + return ACT_NONE; + case gdb_action::resume: + return ACT_RESUME; + case gdb_action::shutdown: + return ACT_SHUTDOWN; + } - throw std::runtime_error("Bad action"); - } + throw std::runtime_error("Bad action"); + } - breakpoint_type map_breakpoint_type(const bp_type_t type) - { - switch (type) - { - case BP_SOFTWARE: - return breakpoint_type::software; - case BP_HARDWARE_EXEC: - return breakpoint_type::hardware_exec; - case BP_HARDWARE_WRITE: - return breakpoint_type::hardware_write; - case BP_HARDWARE_READ: - return breakpoint_type::hardware_read; - case BP_HARDWARE_READ_WRITE: - return breakpoint_type::hardware_read_write; - } + breakpoint_type map_breakpoint_type(const bp_type_t type) + { + switch (type) + { + case BP_SOFTWARE: + return breakpoint_type::software; + case BP_HARDWARE_EXEC: + return breakpoint_type::hardware_exec; + case BP_HARDWARE_WRITE: + return breakpoint_type::hardware_write; + case BP_HARDWARE_READ: + return breakpoint_type::hardware_read; + case BP_HARDWARE_READ_WRITE: + return breakpoint_type::hardware_read_write; + } - throw std::runtime_error("Bad breakpoint type"); - } + throw std::runtime_error("Bad breakpoint type"); + } - gdb_stub_handler& get_handler(void* args) - { - return *static_cast(args); - } + gdb_stub_handler& get_handler(void* args) + { + return *static_cast(args); + } - gdb_action_t cont(void* args) - { - return map_gdb_action(get_handler(args).cont()); - } + gdb_action_t cont(void* args) + { + return map_gdb_action(get_handler(args).cont()); + } - gdb_action_t stepi(void* args) - { - return map_gdb_action(get_handler(args).stepi()); - } + gdb_action_t stepi(void* args) + { + return map_gdb_action(get_handler(args).stepi()); + } - int read_reg(void* args, const int regno, size_t* value) - { - return get_handler(args).read_reg(regno, value) ? 0 : 1; - } + int read_reg(void* args, const int regno, size_t* value) + { + return get_handler(args).read_reg(regno, value) ? 0 : 1; + } - int write_reg(void* args, const int regno, const size_t value) - { - return get_handler(args).write_reg(regno, value) ? 0 : 1; - } + int write_reg(void* args, const int regno, const size_t value) + { + return get_handler(args).write_reg(regno, value) ? 0 : 1; + } - int read_mem(void* args, const size_t addr, const size_t len, void* val) - { - return get_handler(args).read_mem(addr, len, val) ? 0 : 1; - } + int read_mem(void* args, const size_t addr, const size_t len, void* val) + { + return get_handler(args).read_mem(addr, len, val) ? 0 : 1; + } - int write_mem(void* args, const size_t addr, const size_t len, void* val) - { - return get_handler(args).write_mem(addr, len, val) ? 0 : 1; - } + int write_mem(void* args, const size_t addr, const size_t len, void* val) + { + return get_handler(args).write_mem(addr, len, val) ? 0 : 1; + } - bool set_bp(void* args, const size_t addr, const bp_type_t type, const size_t size) - { - return get_handler(args).set_bp(map_breakpoint_type(type), addr, size); - } + bool set_bp(void* args, const size_t addr, const bp_type_t type, const size_t size) + { + return get_handler(args).set_bp(map_breakpoint_type(type), addr, size); + } - bool del_bp(void* args, const size_t addr, const bp_type_t type, const size_t size) - { - return get_handler(args).del_bp(map_breakpoint_type(type), addr, size); - } + bool del_bp(void* args, const size_t addr, const bp_type_t type, const size_t size) + { + return get_handler(args).del_bp(map_breakpoint_type(type), addr, size); + } - void on_interrupt(void* args) - { - get_handler(args).on_interrupt(); - } + void on_interrupt(void* args) + { + get_handler(args).on_interrupt(); + } - target_ops get_target_ops() - { - target_ops ops{}; + target_ops get_target_ops() + { + target_ops ops{}; - ops.cont = cont; - ops.stepi = stepi; - ops.read_reg = read_reg; - ops.write_reg = write_reg; - ops.read_mem = read_mem; - ops.write_mem = write_mem; - ops.set_bp = set_bp; - ops.del_bp = del_bp; - ops.on_interrupt = on_interrupt; + ops.cont = cont; + ops.stepi = stepi; + ops.read_reg = read_reg; + ops.write_reg = write_reg; + ops.read_mem = read_mem; + ops.write_mem = write_mem; + ops.set_bp = set_bp; + ops.del_bp = del_bp; + ops.on_interrupt = on_interrupt; - return ops; - } + return ops; + } } bool run_gdb_stub(gdb_stub_handler& handler, std::string target_description, const size_t register_count, std::string bind_address) { - const arch_info_t info - { - target_description.data(), - static_cast(register_count), - sizeof(uint64_t), - }; + const arch_info_t info{ + target_description.data(), + static_cast(register_count), + sizeof(uint64_t), + }; - auto ops = get_target_ops(); + auto ops = get_target_ops(); - gdbstub_t stub{}; + gdbstub_t stub{}; - if (!gdbstub_init(&stub, &ops, info, bind_address.data())) - { - return false; - } + if (!gdbstub_init(&stub, &ops, info, bind_address.data())) + { + return false; + } - const auto _ = utils::finally([&] - { - gdbstub_close(&stub); - }); + const auto _ = utils::finally([&] { gdbstub_close(&stub); }); - return gdbstub_run(&stub, &handler); + return gdbstub_run(&stub, &handler); } diff --git a/src/windows-emulator/debugging/gdb_stub.hpp b/src/windows-emulator/debugging/gdb_stub.hpp index 82dbae58..de6101f3 100644 --- a/src/windows-emulator/debugging/gdb_stub.hpp +++ b/src/windows-emulator/debugging/gdb_stub.hpp @@ -2,37 +2,37 @@ enum class gdb_action : uint8_t { - none, - resume, - shutdown, + none, + resume, + shutdown, }; enum class breakpoint_type : uint8_t { - software, - hardware_exec, - hardware_write, - hardware_read, - hardware_read_write, + software, + hardware_exec, + hardware_write, + hardware_read, + hardware_read_write, }; struct gdb_stub_handler { - virtual ~gdb_stub_handler() = default; + virtual ~gdb_stub_handler() = default; - virtual gdb_action cont() = 0; - virtual gdb_action stepi() = 0; + virtual gdb_action cont() = 0; + virtual gdb_action stepi() = 0; - virtual bool read_reg(int regno, size_t* value) = 0; - virtual bool write_reg(int regno, size_t value) = 0; + virtual bool read_reg(int regno, size_t* value) = 0; + virtual bool write_reg(int regno, size_t value) = 0; - virtual bool read_mem(size_t addr, size_t len, void* val) = 0; - virtual bool write_mem(size_t addr, size_t len, void* val) = 0; + virtual bool read_mem(size_t addr, size_t len, void* val) = 0; + virtual bool write_mem(size_t addr, size_t len, void* val) = 0; - virtual bool set_bp(breakpoint_type type, size_t addr, size_t size) = 0; - virtual bool del_bp(breakpoint_type type, size_t addr, size_t size) = 0; + virtual bool set_bp(breakpoint_type type, size_t addr, size_t size) = 0; + virtual bool del_bp(breakpoint_type type, size_t addr, size_t size) = 0; - virtual void on_interrupt() = 0; + virtual void on_interrupt() = 0; }; bool run_gdb_stub(gdb_stub_handler& handler, std::string target_description, size_t register_count, diff --git a/src/windows-emulator/debugging/win_x64_gdb_stub_handler.hpp b/src/windows-emulator/debugging/win_x64_gdb_stub_handler.hpp index a9427df2..ce2bc314 100644 --- a/src/windows-emulator/debugging/win_x64_gdb_stub_handler.hpp +++ b/src/windows-emulator/debugging/win_x64_gdb_stub_handler.hpp @@ -5,41 +5,41 @@ class win_x64_gdb_stub_handler : public x64_gdb_stub_handler { -public: - win_x64_gdb_stub_handler(windows_emulator& win_emu) - : x64_gdb_stub_handler(win_emu.emu()) - , win_emu_(&win_emu) - { - } + public: + win_x64_gdb_stub_handler(windows_emulator& win_emu) + : x64_gdb_stub_handler(win_emu.emu()), + win_emu_(&win_emu) + { + } - gdb_action cont() override - { - try - { - this->win_emu_->start(); - } - catch (const std::exception& e) - { - puts(e.what()); - } + gdb_action cont() override + { + try + { + this->win_emu_->start(); + } + catch (const std::exception& e) + { + puts(e.what()); + } - return gdb_action::resume; - } + return gdb_action::resume; + } - gdb_action stepi() override - { - try - { - this->win_emu_->start({}, 1); - } - catch (const std::exception& e) - { - puts(e.what()); - } + gdb_action stepi() override + { + try + { + this->win_emu_->start({}, 1); + } + catch (const std::exception& e) + { + puts(e.what()); + } - return gdb_action::resume; - } + return gdb_action::resume; + } -private: - windows_emulator* win_emu_{}; + private: + windows_emulator* win_emu_{}; }; diff --git a/src/windows-emulator/debugging/x64_gdb_stub_handler.hpp b/src/windows-emulator/debugging/x64_gdb_stub_handler.hpp index 8b29877b..66961d54 100644 --- a/src/windows-emulator/debugging/x64_gdb_stub_handler.hpp +++ b/src/windows-emulator/debugging/x64_gdb_stub_handler.hpp @@ -4,212 +4,194 @@ #include "scoped_hook.hpp" inline std::vector gdb_registers{ - x64_register::rax, - x64_register::rbx, - x64_register::rcx, - x64_register::rdx, - x64_register::rsi, - x64_register::rdi, - x64_register::rbp, - x64_register::rsp, - x64_register::r8, - x64_register::r9, - x64_register::r10, - x64_register::r11, - x64_register::r12, - x64_register::r13, - x64_register::r14, - x64_register::r15, - x64_register::rip, - x64_register::rflags, - /*x64_register::cs, - x64_register::ss, - x64_register::ds, - x64_register::es, - x64_register::fs, - x64_register::gs,*/ + x64_register::rax, x64_register::rbx, x64_register::rcx, x64_register::rdx, x64_register::rsi, x64_register::rdi, + x64_register::rbp, x64_register::rsp, x64_register::r8, x64_register::r9, x64_register::r10, x64_register::r11, + x64_register::r12, x64_register::r13, x64_register::r14, x64_register::r15, x64_register::rip, x64_register::rflags, + /*x64_register::cs, + x64_register::ss, + x64_register::ds, + x64_register::es, + x64_register::fs, + x64_register::gs,*/ }; inline memory_operation map_breakpoint_type(const breakpoint_type type) { - switch (type) - { - case breakpoint_type::software: - case breakpoint_type::hardware_exec: - return memory_operation::exec; - case breakpoint_type::hardware_read: - return memory_permission::read; - case breakpoint_type::hardware_write: - return memory_permission::write; - case breakpoint_type::hardware_read_write: - return memory_permission::read_write; - default: - throw std::runtime_error("Bad bp type"); - } + switch (type) + { + case breakpoint_type::software: + case breakpoint_type::hardware_exec: + return memory_operation::exec; + case breakpoint_type::hardware_read: + return memory_permission::read; + case breakpoint_type::hardware_write: + return memory_permission::write; + case breakpoint_type::hardware_read_write: + return memory_permission::read_write; + default: + throw std::runtime_error("Bad bp type"); + } } struct breakpoint_key { - size_t addr{}; - size_t size{}; - breakpoint_type type{}; + size_t addr{}; + size_t size{}; + breakpoint_type type{}; - bool operator==(const breakpoint_key& other) const - { - return this->addr == other.addr && this->size == other.size && this->type == other.type; - } + bool operator==(const breakpoint_key& other) const + { + return this->addr == other.addr && this->size == other.size && this->type == other.type; + } }; template <> struct std::hash { - std::size_t operator()(const breakpoint_key& k) const noexcept - { - return ((std::hash()(k.addr) - ^ (std::hash()(k.size) << 1)) >> 1) - ^ (std::hash()(static_cast(k.type)) << 1); - } + std::size_t operator()(const breakpoint_key& k) const noexcept + { + return ((std::hash()(k.addr) ^ (std::hash()(k.size) << 1)) >> 1) ^ + (std::hash()(static_cast(k.type)) << 1); + } }; class x64_gdb_stub_handler : public gdb_stub_handler { -public: - x64_gdb_stub_handler(x64_emulator& emu) - : emu_(&emu) - { - } + public: + x64_gdb_stub_handler(x64_emulator& emu) + : emu_(&emu) + { + } - ~x64_gdb_stub_handler() override = default; + ~x64_gdb_stub_handler() override = default; - gdb_action cont() override - { - try - { - this->emu_->start_from_ip(); - } - catch (const std::exception& e) - { - puts(e.what()); - } + gdb_action cont() override + { + try + { + this->emu_->start_from_ip(); + } + catch (const std::exception& e) + { + puts(e.what()); + } - return gdb_action::resume; - } + return gdb_action::resume; + } - gdb_action stepi() override - { - try - { - this->emu_->start_from_ip({}, 1); - } - catch (const std::exception& e) - { - puts(e.what()); - } + gdb_action stepi() override + { + try + { + this->emu_->start_from_ip({}, 1); + } + catch (const std::exception& e) + { + puts(e.what()); + } - return gdb_action::resume; - } + return gdb_action::resume; + } - bool read_reg(const int regno, size_t* value) override - { - *value = 0; + bool read_reg(const int regno, size_t* value) override + { + *value = 0; - try - { - if (static_cast(regno) >= gdb_registers.size()) - { - return true; - } + try + { + if (static_cast(regno) >= gdb_registers.size()) + { + return true; + } - this->emu_->read_register(gdb_registers[regno], value, sizeof(*value)); - return true; - } - catch (...) - { - return true; - } - } + this->emu_->read_register(gdb_registers[regno], value, sizeof(*value)); + return true; + } + catch (...) + { + return true; + } + } - bool write_reg(const int regno, const size_t value) override - { - try - { - if (static_cast(regno) >= gdb_registers.size()) - { - return true; - } + bool write_reg(const int regno, const size_t value) override + { + try + { + if (static_cast(regno) >= gdb_registers.size()) + { + return true; + } - this->emu_->write_register(gdb_registers[regno], &value, sizeof(value)); - return true; - } - catch (...) - { - return false; - } - } + this->emu_->write_register(gdb_registers[regno], &value, sizeof(value)); + return true; + } + catch (...) + { + return false; + } + } - bool read_mem(const size_t addr, const size_t len, void* val) override - { - return this->emu_->try_read_memory(addr, val, len); - } + bool read_mem(const size_t addr, const size_t len, void* val) override + { + return this->emu_->try_read_memory(addr, val, len); + } - bool write_mem(const size_t addr, const size_t len, void* val) override - { - try - { - this->emu_->write_memory(addr, val, len); - return true; - } - catch (...) - { - return false; - } - } + bool write_mem(const size_t addr, const size_t len, void* val) override + { + try + { + this->emu_->write_memory(addr, val, len); + return true; + } + catch (...) + { + return false; + } + } - bool set_bp(const breakpoint_type type, const size_t addr, const size_t size) override - { - try - { - this->hooks_[{addr, size, type}] = scoped_hook(*this->emu_, this->emu_->hook_memory_access( - addr, size, map_breakpoint_type(type), - [this](uint64_t, size_t, uint64_t, memory_operation) - { - this->on_interrupt(); - })); + bool set_bp(const breakpoint_type type, const size_t addr, const size_t size) override + { + try + { + this->hooks_[{addr, size, type}] = scoped_hook( + *this->emu_, this->emu_->hook_memory_access( + addr, size, map_breakpoint_type(type), + [this](uint64_t, size_t, uint64_t, memory_operation) { this->on_interrupt(); })); - return true; - } - catch (...) - { - return false; - } - } + return true; + } + catch (...) + { + return false; + } + } - bool del_bp(const breakpoint_type type, const size_t addr, const size_t size) override - { - try - { - const auto entry = this->hooks_.find({addr, size, type}); - if (entry == this->hooks_.end()) - { - return false; - } + bool del_bp(const breakpoint_type type, const size_t addr, const size_t size) override + { + try + { + const auto entry = this->hooks_.find({addr, size, type}); + if (entry == this->hooks_.end()) + { + return false; + } - this->hooks_.erase(entry); + this->hooks_.erase(entry); - return true; - } - catch (...) - { - return false; - } - } + return true; + } + catch (...) + { + return false; + } + } - void on_interrupt() override - { - this->emu_->stop(); - } + void on_interrupt() override + { + this->emu_->stop(); + } -private: - x64_emulator* emu_{}; - std::unordered_map hooks_{}; + private: + x64_emulator* emu_{}; + std::unordered_map hooks_{}; }; diff --git a/src/windows-emulator/devices/afd_endpoint.cpp b/src/windows-emulator/devices/afd_endpoint.cpp index 8b9766ce..6b431881 100644 --- a/src/windows-emulator/devices/afd_endpoint.cpp +++ b/src/windows-emulator/devices/afd_endpoint.cpp @@ -11,534 +11,529 @@ namespace { - struct afd_creation_data - { - uint64_t unk1; - char afd_open_packet_xx[0x10]; - uint64_t unk2; - int address_family; - int type; - int protocol; - // ... - }; - - afd_creation_data get_creation_data(windows_emulator& win_emu, const io_device_creation_data& data) - { - if (!data.buffer || data.length < sizeof(afd_creation_data)) - { - throw std::runtime_error("Bad AFD creation data"); - } - - return win_emu.emu().read_memory(data.buffer); - } - - std::pair> get_poll_info( - windows_emulator& win_emu, const io_device_context& c) - { - constexpr auto info_size = offsetof(AFD_POLL_INFO64, Handles); - if (!c.input_buffer || c.input_buffer_length < info_size) - { - throw std::runtime_error("Bad AFD poll data"); - } - - AFD_POLL_INFO64 poll_info{}; - win_emu.emu().read_memory(c.input_buffer, &poll_info, info_size); - - std::vector handle_info{}; - - const emulator_object handle_info_obj{win_emu.emu(), c.input_buffer + info_size}; - - if (c.input_buffer_length < (info_size + sizeof(AFD_POLL_HANDLE_INFO64) * poll_info.NumberOfHandles)) - { - throw std::runtime_error("Bad AFD poll handle data"); - } - - for (ULONG i = 0; i < poll_info.NumberOfHandles; ++i) - { - handle_info.emplace_back(handle_info_obj.read(i)); - } - - return {std::move(poll_info), std::move(handle_info)}; - } - - int16_t map_afd_request_events_to_socket(const ULONG poll_events) - { - int16_t socket_events{}; - - if (poll_events & (AFD_POLL_ACCEPT | AFD_POLL_RECEIVE)) - { - socket_events |= POLLRDNORM; - } - - if (poll_events & AFD_POLL_RECEIVE_EXPEDITED) - { - socket_events |= POLLRDNORM; - } - - if (poll_events & AFD_POLL_RECEIVE_EXPEDITED) - { - socket_events |= POLLRDBAND; - } - - if (poll_events & (AFD_POLL_CONNECT_FAIL | AFD_POLL_SEND)) - { - socket_events |= POLLWRNORM; - } - - return socket_events; - } - - ULONG map_socket_response_events_to_afd(const int16_t socket_events) - { - ULONG afd_events = 0; - - if (socket_events & POLLRDNORM) - { - afd_events |= (AFD_POLL_ACCEPT | AFD_POLL_RECEIVE); - } - - if (socket_events & POLLRDBAND) - { - afd_events |= AFD_POLL_RECEIVE_EXPEDITED; - } - - if (socket_events & POLLWRNORM) - { - afd_events |= (AFD_POLL_CONNECT_FAIL | AFD_POLL_SEND); - } - - if ((socket_events & (POLLHUP | POLLERR)) == (POLLHUP | POLLERR)) - { - afd_events |= (AFD_POLL_CONNECT_FAIL | AFD_POLL_ABORT); - } - else if (socket_events & POLLHUP) - { - afd_events |= AFD_POLL_DISCONNECT; - } - - if (socket_events & POLLNVAL) - { - afd_events |= AFD_POLL_LOCAL_CLOSE; - } - - return afd_events; - } - - NTSTATUS perform_poll(windows_emulator& win_emu, const io_device_context& c, - const std::span endpoints, - const std::span handles) - { - std::vector poll_data{}; - poll_data.resize(endpoints.size()); - - for (size_t i = 0; i < endpoints.size() && i < handles.size(); ++i) - { - auto& pfd = poll_data.at(i); - auto& handle = handles[i]; - - pfd.fd = endpoints[i]; - pfd.events = map_afd_request_events_to_socket(handle.PollEvents); - pfd.revents = pfd.events; - } - - const auto count = poll(poll_data.data(), static_cast(poll_data.size()), 0); - if (count <= 0) - { - return STATUS_PENDING; - } - - constexpr auto info_size = offsetof(AFD_POLL_INFO64, Handles); - const emulator_object handle_info_obj{win_emu.emu(), c.input_buffer + info_size}; - - size_t current_index = 0; - - for (size_t i = 0; i < endpoints.size(); ++i) - { - const auto& pfd = poll_data.at(i); - if (pfd.revents == 0) - { - continue; - } - - auto entry = handle_info_obj.read(i); - entry.PollEvents = map_socket_response_events_to_afd(pfd.revents); - entry.Status = STATUS_SUCCESS; - - handle_info_obj.write(entry, current_index++); - break; - } - - assert(current_index == static_cast(count)); - - emulator_object{win_emu.emu(), c.input_buffer}.access([&](AFD_POLL_INFO64& info) - { - info.NumberOfHandles = static_cast(current_index); - }); - - return STATUS_SUCCESS; - } - - struct afd_endpoint : io_device - { - bool executing_delayed_ioctl_{}; - std::optional creation_data{}; - std::optional s_{}; - std::optional require_poll_{}; - std::optional delayed_ioctl_{}; - std::optional timeout_{}; - - afd_endpoint() - { - network::initialize_wsa(); - } - - afd_endpoint(afd_endpoint&&) = delete; - afd_endpoint& operator=(afd_endpoint&&) = delete; - - ~afd_endpoint() override - { - if (this->s_) - { - closesocket(*this->s_); - } - } - - void create(windows_emulator& win_emu, const io_device_creation_data& data) override - { - this->creation_data = get_creation_data(win_emu, data); - this->setup(); - } - - void setup() - { - if (!this->creation_data) - { - return; - } - - const auto& data = *this->creation_data; - - // TODO: values map to windows values; might not be the case for other platforms - const auto sock = socket(data.address_family, data.type, data.protocol); - if (sock == INVALID_SOCKET) - { - throw std::runtime_error("Failed to create socket!"); - } - - network::socket::set_blocking(sock, false); - - this->s_ = sock; - } - - void delay_ioctrl(const io_device_context& c, - const std::optional timeout = {}, - const std::optional require_poll = {}) - { - if (this->executing_delayed_ioctl_) - { - return; - } - - this->timeout_ = timeout; - this->require_poll_ = require_poll; - this->delayed_ioctl_ = c; - } - - void clear_pending_state() - { - this->timeout_ = {}; - this->require_poll_ = {}; - this->delayed_ioctl_ = {}; - } - - void work(windows_emulator& win_emu) override - { - if (!this->delayed_ioctl_ || !this->s_) - { - return; - } - - this->executing_delayed_ioctl_ = true; - const auto _ = utils::finally([&] - { - this->executing_delayed_ioctl_ = false; - }); - - if (this->require_poll_.has_value()) - { - const auto is_ready = network::socket::is_socket_ready(*this->s_, *this->require_poll_); - if (!is_ready) - { - return; - } - } - - const auto status = this->execute_ioctl(win_emu, *this->delayed_ioctl_); - if (status == STATUS_PENDING) - { - if (!this->timeout_ || this->timeout_ > std::chrono::steady_clock::now()) - { - return; - } - - write_io_status(this->delayed_ioctl_->io_status_block, STATUS_TIMEOUT); - } - - auto* e = win_emu.process().events.get(this->delayed_ioctl_->event); - if (e) - { - e->signaled = true; - } - - this->clear_pending_state(); - } - - void deserialize(utils::buffer_deserializer& buffer) override - { - buffer.read(this->creation_data); - this->setup(); - - buffer.read(this->require_poll_); - buffer.read(this->delayed_ioctl_); - buffer.read(this->timeout_); - } - - void serialize(utils::buffer_serializer& buffer) const override - { - buffer.write(this->creation_data); - buffer.write(this->require_poll_); - buffer.write(this->delayed_ioctl_); - buffer.write(this->timeout_); - } - - NTSTATUS io_control(windows_emulator& win_emu, const io_device_context& c) override - { - if (_AFD_BASE(c.io_control_code) != FSCTL_AFD_BASE) - { - win_emu.log.print(color::cyan, "Bad AFD IOCTL: %X\n", c.io_control_code); - return STATUS_NOT_SUPPORTED; - } - - win_emu.log.print(color::cyan, "AFD IOCTL: %X\n", c.io_control_code); - - const auto request = _AFD_REQUEST(c.io_control_code); - - switch (request) - { - case AFD_BIND: - return this->ioctl_bind(win_emu, c); - case AFD_SEND_DATAGRAM: - return this->ioctl_send_datagram(win_emu, c); - case AFD_RECEIVE_DATAGRAM: - return this->ioctl_receive_datagram(win_emu, c); - case AFD_POLL: - return this->ioctl_poll(win_emu, c); - case AFD_SET_CONTEXT: - case AFD_GET_INFORMATION: - return STATUS_SUCCESS; - default: - win_emu.log.print(color::gray, "Unsupported AFD IOCTL: %X\n", c.io_control_code); - return STATUS_NOT_SUPPORTED; - } - } - - NTSTATUS ioctl_bind(windows_emulator& win_emu, const io_device_context& c) const - { - const auto data = win_emu.emu().read_memory(c.input_buffer, c.input_buffer_length); - - constexpr auto address_offset = 4; - - if (data.size() < address_offset) - { - return STATUS_BUFFER_TOO_SMALL; - } - - const auto* address = reinterpret_cast(data.data() + address_offset); - const auto address_size = static_cast(data.size() - address_offset); - - const network::address addr(address, address_size); - - if (bind(*this->s_, &addr.get_addr(), addr.get_size()) == SOCKET_ERROR) - { - return STATUS_ADDRESS_ALREADY_ASSOCIATED; - } - - return STATUS_SUCCESS; - } - - static std::vector resolve_endpoints(windows_emulator& win_emu, - const std::span handles) - { - auto& proc = win_emu.process(); - - std::vector endpoints{}; - endpoints.reserve(handles.size()); - - for (const auto& handle : handles) - { - auto* device = proc.devices.get(handle.Handle); - if (!device) - { - throw std::runtime_error("Bad device!"); - } - - const auto* endpoint = device->get_internal_device(); - if (!endpoint) - { - throw std::runtime_error("Device is not an AFD endpoint!"); - } - - endpoints.push_back(*endpoint->s_); - } - - return endpoints; - } - - NTSTATUS ioctl_poll(windows_emulator& win_emu, const io_device_context& c) - { - const auto [info, handles] = get_poll_info(win_emu, c); - const auto endpoints = resolve_endpoints(win_emu, handles); - - const auto status = perform_poll(win_emu, c, endpoints, handles); - if (status != STATUS_PENDING) - { - return status; - } - - if (!this->executing_delayed_ioctl_) - { - if (!info.Timeout.QuadPart) - { - return status; - } - - std::optional timeout{}; - if (info.Timeout.QuadPart != std::numeric_limits::max()) - { - timeout = convert_delay_interval_to_time_point(info.Timeout); - } - - this->delay_ioctrl(c, timeout); - } - - return STATUS_PENDING; - } - - NTSTATUS ioctl_receive_datagram(windows_emulator& win_emu, const io_device_context& c) - { - auto& emu = win_emu.emu(); - - if (c.input_buffer_length < sizeof(AFD_RECV_DATAGRAM_INFO>)) - { - return STATUS_BUFFER_TOO_SMALL; - } - - const auto receive_info = emu.read_memory>>(c.input_buffer); - const auto buffer = emu.read_memory>>(receive_info.BufferArray); - - std::vector address{}; - - unsigned long address_length = 0x1000; - if (receive_info.AddressLength) - { - address_length = emu.read_memory(receive_info.AddressLength); - } - - address.resize(std::clamp(address_length, 1UL, 0x1000UL)); - - if (!buffer.len || buffer.len > 0x10000 || !buffer.buf) - { - return STATUS_INVALID_PARAMETER; - } - - auto fromlength = static_cast(address.size()); - - std::vector data{}; - data.resize(buffer.len); - - const auto recevied_data = recvfrom(*this->s_, data.data(), static_cast(data.size()), 0, - reinterpret_cast(address.data()), &fromlength); - - if (recevied_data < 0) - { - const auto error = GET_SOCKET_ERROR(); - if (error == SOCK_WOULDBLOCK) - { - this->delay_ioctrl(c, {}, true); - return STATUS_PENDING; - } - - return STATUS_UNSUCCESSFUL; - } - - const auto data_size = std::min(data.size(), static_cast(recevied_data)); - emu.write_memory(buffer.buf, data.data(), data_size); - - if (receive_info.Address && address_length) - { - const auto address_size = std::min(address.size(), static_cast(address_length)); - emu.write_memory(receive_info.Address, address.data(), address_size); - } - - if (c.io_status_block) - { - IO_STATUS_BLOCK> block{}; - block.Information = static_cast(recevied_data); - c.io_status_block.write(block); - } - - return STATUS_SUCCESS; - } - - NTSTATUS ioctl_send_datagram(windows_emulator& win_emu, const io_device_context& c) - { - const auto& emu = win_emu.emu(); - - if (c.input_buffer_length < sizeof(AFD_SEND_DATAGRAM_INFO>)) - { - return STATUS_BUFFER_TOO_SMALL; - } - - const auto send_info = emu.read_memory>>(c.input_buffer); - const auto buffer = emu.read_memory>>(send_info.BufferArray); - - const auto address = emu.read_memory(send_info.TdiConnInfo.RemoteAddress, - static_cast(send_info.TdiConnInfo.RemoteAddressLength)); - - const network::address target(reinterpret_cast(address.data()), - static_cast(address.size())); - - const auto data = emu.read_memory(buffer.buf, buffer.len); - - const auto sent_data = sendto(*this->s_, reinterpret_cast(data.data()), - static_cast(data.size()), 0 /* ? */, &target.get_addr(), - target.get_size()); - - if (sent_data < 0) - { - const auto error = GET_SOCKET_ERROR(); - if (error == SOCK_WOULDBLOCK) - { - this->delay_ioctrl(c, {}, false); - return STATUS_PENDING; - } - - return STATUS_UNSUCCESSFUL; - } - - if (c.io_status_block) - { - IO_STATUS_BLOCK> block{}; - block.Information = static_cast(sent_data); - c.io_status_block.write(block); - } - - return STATUS_SUCCESS; - } - }; + struct afd_creation_data + { + uint64_t unk1; + char afd_open_packet_xx[0x10]; + uint64_t unk2; + int address_family; + int type; + int protocol; + // ... + }; + + afd_creation_data get_creation_data(windows_emulator& win_emu, const io_device_creation_data& data) + { + if (!data.buffer || data.length < sizeof(afd_creation_data)) + { + throw std::runtime_error("Bad AFD creation data"); + } + + return win_emu.emu().read_memory(data.buffer); + } + + std::pair> get_poll_info(windows_emulator& win_emu, + const io_device_context& c) + { + constexpr auto info_size = offsetof(AFD_POLL_INFO64, Handles); + if (!c.input_buffer || c.input_buffer_length < info_size) + { + throw std::runtime_error("Bad AFD poll data"); + } + + AFD_POLL_INFO64 poll_info{}; + win_emu.emu().read_memory(c.input_buffer, &poll_info, info_size); + + std::vector handle_info{}; + + const emulator_object handle_info_obj{win_emu.emu(), c.input_buffer + info_size}; + + if (c.input_buffer_length < (info_size + sizeof(AFD_POLL_HANDLE_INFO64) * poll_info.NumberOfHandles)) + { + throw std::runtime_error("Bad AFD poll handle data"); + } + + for (ULONG i = 0; i < poll_info.NumberOfHandles; ++i) + { + handle_info.emplace_back(handle_info_obj.read(i)); + } + + return {std::move(poll_info), std::move(handle_info)}; + } + + int16_t map_afd_request_events_to_socket(const ULONG poll_events) + { + int16_t socket_events{}; + + if (poll_events & (AFD_POLL_ACCEPT | AFD_POLL_RECEIVE)) + { + socket_events |= POLLRDNORM; + } + + if (poll_events & AFD_POLL_RECEIVE_EXPEDITED) + { + socket_events |= POLLRDNORM; + } + + if (poll_events & AFD_POLL_RECEIVE_EXPEDITED) + { + socket_events |= POLLRDBAND; + } + + if (poll_events & (AFD_POLL_CONNECT_FAIL | AFD_POLL_SEND)) + { + socket_events |= POLLWRNORM; + } + + return socket_events; + } + + ULONG map_socket_response_events_to_afd(const int16_t socket_events) + { + ULONG afd_events = 0; + + if (socket_events & POLLRDNORM) + { + afd_events |= (AFD_POLL_ACCEPT | AFD_POLL_RECEIVE); + } + + if (socket_events & POLLRDBAND) + { + afd_events |= AFD_POLL_RECEIVE_EXPEDITED; + } + + if (socket_events & POLLWRNORM) + { + afd_events |= (AFD_POLL_CONNECT_FAIL | AFD_POLL_SEND); + } + + if ((socket_events & (POLLHUP | POLLERR)) == (POLLHUP | POLLERR)) + { + afd_events |= (AFD_POLL_CONNECT_FAIL | AFD_POLL_ABORT); + } + else if (socket_events & POLLHUP) + { + afd_events |= AFD_POLL_DISCONNECT; + } + + if (socket_events & POLLNVAL) + { + afd_events |= AFD_POLL_LOCAL_CLOSE; + } + + return afd_events; + } + + NTSTATUS perform_poll(windows_emulator& win_emu, const io_device_context& c, + const std::span endpoints, + const std::span handles) + { + std::vector poll_data{}; + poll_data.resize(endpoints.size()); + + for (size_t i = 0; i < endpoints.size() && i < handles.size(); ++i) + { + auto& pfd = poll_data.at(i); + auto& handle = handles[i]; + + pfd.fd = endpoints[i]; + pfd.events = map_afd_request_events_to_socket(handle.PollEvents); + pfd.revents = pfd.events; + } + + const auto count = poll(poll_data.data(), static_cast(poll_data.size()), 0); + if (count <= 0) + { + return STATUS_PENDING; + } + + constexpr auto info_size = offsetof(AFD_POLL_INFO64, Handles); + const emulator_object handle_info_obj{win_emu.emu(), c.input_buffer + info_size}; + + size_t current_index = 0; + + for (size_t i = 0; i < endpoints.size(); ++i) + { + const auto& pfd = poll_data.at(i); + if (pfd.revents == 0) + { + continue; + } + + auto entry = handle_info_obj.read(i); + entry.PollEvents = map_socket_response_events_to_afd(pfd.revents); + entry.Status = STATUS_SUCCESS; + + handle_info_obj.write(entry, current_index++); + break; + } + + assert(current_index == static_cast(count)); + + emulator_object{win_emu.emu(), c.input_buffer}.access( + [&](AFD_POLL_INFO64& info) { info.NumberOfHandles = static_cast(current_index); }); + + return STATUS_SUCCESS; + } + + struct afd_endpoint : io_device + { + bool executing_delayed_ioctl_{}; + std::optional creation_data{}; + std::optional s_{}; + std::optional require_poll_{}; + std::optional delayed_ioctl_{}; + std::optional timeout_{}; + + afd_endpoint() + { + network::initialize_wsa(); + } + + afd_endpoint(afd_endpoint&&) = delete; + afd_endpoint& operator=(afd_endpoint&&) = delete; + + ~afd_endpoint() override + { + if (this->s_) + { + closesocket(*this->s_); + } + } + + void create(windows_emulator& win_emu, const io_device_creation_data& data) override + { + this->creation_data = get_creation_data(win_emu, data); + this->setup(); + } + + void setup() + { + if (!this->creation_data) + { + return; + } + + const auto& data = *this->creation_data; + + // TODO: values map to windows values; might not be the case for other platforms + const auto sock = socket(data.address_family, data.type, data.protocol); + if (sock == INVALID_SOCKET) + { + throw std::runtime_error("Failed to create socket!"); + } + + network::socket::set_blocking(sock, false); + + this->s_ = sock; + } + + void delay_ioctrl(const io_device_context& c, + const std::optional timeout = {}, + const std::optional require_poll = {}) + { + if (this->executing_delayed_ioctl_) + { + return; + } + + this->timeout_ = timeout; + this->require_poll_ = require_poll; + this->delayed_ioctl_ = c; + } + + void clear_pending_state() + { + this->timeout_ = {}; + this->require_poll_ = {}; + this->delayed_ioctl_ = {}; + } + + void work(windows_emulator& win_emu) override + { + if (!this->delayed_ioctl_ || !this->s_) + { + return; + } + + this->executing_delayed_ioctl_ = true; + const auto _ = utils::finally([&] { this->executing_delayed_ioctl_ = false; }); + + if (this->require_poll_.has_value()) + { + const auto is_ready = network::socket::is_socket_ready(*this->s_, *this->require_poll_); + if (!is_ready) + { + return; + } + } + + const auto status = this->execute_ioctl(win_emu, *this->delayed_ioctl_); + if (status == STATUS_PENDING) + { + if (!this->timeout_ || this->timeout_ > std::chrono::steady_clock::now()) + { + return; + } + + write_io_status(this->delayed_ioctl_->io_status_block, STATUS_TIMEOUT); + } + + auto* e = win_emu.process().events.get(this->delayed_ioctl_->event); + if (e) + { + e->signaled = true; + } + + this->clear_pending_state(); + } + + void deserialize(utils::buffer_deserializer& buffer) override + { + buffer.read(this->creation_data); + this->setup(); + + buffer.read(this->require_poll_); + buffer.read(this->delayed_ioctl_); + buffer.read(this->timeout_); + } + + void serialize(utils::buffer_serializer& buffer) const override + { + buffer.write(this->creation_data); + buffer.write(this->require_poll_); + buffer.write(this->delayed_ioctl_); + buffer.write(this->timeout_); + } + + NTSTATUS io_control(windows_emulator& win_emu, const io_device_context& c) override + { + if (_AFD_BASE(c.io_control_code) != FSCTL_AFD_BASE) + { + win_emu.log.print(color::cyan, "Bad AFD IOCTL: %X\n", c.io_control_code); + return STATUS_NOT_SUPPORTED; + } + + win_emu.log.print(color::cyan, "AFD IOCTL: %X\n", c.io_control_code); + + const auto request = _AFD_REQUEST(c.io_control_code); + + switch (request) + { + case AFD_BIND: + return this->ioctl_bind(win_emu, c); + case AFD_SEND_DATAGRAM: + return this->ioctl_send_datagram(win_emu, c); + case AFD_RECEIVE_DATAGRAM: + return this->ioctl_receive_datagram(win_emu, c); + case AFD_POLL: + return this->ioctl_poll(win_emu, c); + case AFD_SET_CONTEXT: + case AFD_GET_INFORMATION: + return STATUS_SUCCESS; + default: + win_emu.log.print(color::gray, "Unsupported AFD IOCTL: %X\n", c.io_control_code); + return STATUS_NOT_SUPPORTED; + } + } + + NTSTATUS ioctl_bind(windows_emulator& win_emu, const io_device_context& c) const + { + const auto data = win_emu.emu().read_memory(c.input_buffer, c.input_buffer_length); + + constexpr auto address_offset = 4; + + if (data.size() < address_offset) + { + return STATUS_BUFFER_TOO_SMALL; + } + + const auto* address = reinterpret_cast(data.data() + address_offset); + const auto address_size = static_cast(data.size() - address_offset); + + const network::address addr(address, address_size); + + if (bind(*this->s_, &addr.get_addr(), addr.get_size()) == SOCKET_ERROR) + { + return STATUS_ADDRESS_ALREADY_ASSOCIATED; + } + + return STATUS_SUCCESS; + } + + static std::vector resolve_endpoints(windows_emulator& win_emu, + const std::span handles) + { + auto& proc = win_emu.process(); + + std::vector endpoints{}; + endpoints.reserve(handles.size()); + + for (const auto& handle : handles) + { + auto* device = proc.devices.get(handle.Handle); + if (!device) + { + throw std::runtime_error("Bad device!"); + } + + const auto* endpoint = device->get_internal_device(); + if (!endpoint) + { + throw std::runtime_error("Device is not an AFD endpoint!"); + } + + endpoints.push_back(*endpoint->s_); + } + + return endpoints; + } + + NTSTATUS ioctl_poll(windows_emulator& win_emu, const io_device_context& c) + { + const auto [info, handles] = get_poll_info(win_emu, c); + const auto endpoints = resolve_endpoints(win_emu, handles); + + const auto status = perform_poll(win_emu, c, endpoints, handles); + if (status != STATUS_PENDING) + { + return status; + } + + if (!this->executing_delayed_ioctl_) + { + if (!info.Timeout.QuadPart) + { + return status; + } + + std::optional timeout{}; + if (info.Timeout.QuadPart != std::numeric_limits::max()) + { + timeout = convert_delay_interval_to_time_point(info.Timeout); + } + + this->delay_ioctrl(c, timeout); + } + + return STATUS_PENDING; + } + + NTSTATUS ioctl_receive_datagram(windows_emulator& win_emu, const io_device_context& c) + { + auto& emu = win_emu.emu(); + + if (c.input_buffer_length < sizeof(AFD_RECV_DATAGRAM_INFO>)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + const auto receive_info = emu.read_memory>>(c.input_buffer); + const auto buffer = emu.read_memory>>(receive_info.BufferArray); + + std::vector address{}; + + unsigned long address_length = 0x1000; + if (receive_info.AddressLength) + { + address_length = emu.read_memory(receive_info.AddressLength); + } + + address.resize(std::clamp(address_length, 1UL, 0x1000UL)); + + if (!buffer.len || buffer.len > 0x10000 || !buffer.buf) + { + return STATUS_INVALID_PARAMETER; + } + + auto fromlength = static_cast(address.size()); + + std::vector data{}; + data.resize(buffer.len); + + const auto recevied_data = recvfrom(*this->s_, data.data(), static_cast(data.size()), 0, + reinterpret_cast(address.data()), &fromlength); + + if (recevied_data < 0) + { + const auto error = GET_SOCKET_ERROR(); + if (error == SOCK_WOULDBLOCK) + { + this->delay_ioctrl(c, {}, true); + return STATUS_PENDING; + } + + return STATUS_UNSUCCESSFUL; + } + + const auto data_size = std::min(data.size(), static_cast(recevied_data)); + emu.write_memory(buffer.buf, data.data(), data_size); + + if (receive_info.Address && address_length) + { + const auto address_size = std::min(address.size(), static_cast(address_length)); + emu.write_memory(receive_info.Address, address.data(), address_size); + } + + if (c.io_status_block) + { + IO_STATUS_BLOCK> block{}; + block.Information = static_cast(recevied_data); + c.io_status_block.write(block); + } + + return STATUS_SUCCESS; + } + + NTSTATUS ioctl_send_datagram(windows_emulator& win_emu, const io_device_context& c) + { + const auto& emu = win_emu.emu(); + + if (c.input_buffer_length < sizeof(AFD_SEND_DATAGRAM_INFO>)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + const auto send_info = emu.read_memory>>(c.input_buffer); + const auto buffer = emu.read_memory>>(send_info.BufferArray); + + const auto address = emu.read_memory(send_info.TdiConnInfo.RemoteAddress, + static_cast(send_info.TdiConnInfo.RemoteAddressLength)); + + const network::address target(reinterpret_cast(address.data()), + static_cast(address.size())); + + const auto data = emu.read_memory(buffer.buf, buffer.len); + + const auto sent_data = + sendto(*this->s_, reinterpret_cast(data.data()), static_cast(data.size()), + 0 /* ? */, &target.get_addr(), target.get_size()); + + if (sent_data < 0) + { + const auto error = GET_SOCKET_ERROR(); + if (error == SOCK_WOULDBLOCK) + { + this->delay_ioctrl(c, {}, false); + return STATUS_PENDING; + } + + return STATUS_UNSUCCESSFUL; + } + + if (c.io_status_block) + { + IO_STATUS_BLOCK> block{}; + block.Information = static_cast(sent_data); + c.io_status_block.write(block); + } + + return STATUS_SUCCESS; + } + }; } std::unique_ptr create_afd_endpoint() { - return std::make_unique(); + return std::make_unique(); } diff --git a/src/windows-emulator/devices/afd_types.hpp b/src/windows-emulator/devices/afd_types.hpp index 55310bce..dd0d106e 100644 --- a/src/windows-emulator/devices/afd_types.hpp +++ b/src/windows-emulator/devices/afd_types.hpp @@ -7,88 +7,88 @@ typedef LONG TDI_STATUS; template struct TDI_CONNECTION_INFORMATION { - LONG UserDataLength; - typename Traits::PVOID UserData; - LONG OptionsLength; - typename Traits::PVOID Options; - LONG RemoteAddressLength; - typename Traits::PVOID RemoteAddress; + LONG UserDataLength; + typename Traits::PVOID UserData; + LONG OptionsLength; + typename Traits::PVOID Options; + LONG RemoteAddressLength; + typename Traits::PVOID RemoteAddress; }; template struct TDI_REQUEST { - union - { - typename Traits::HANDLE AddressHandle; - EMULATOR_CAST(typename Traits::PVOID, CONNECTION_CONTEXT) ConnectionContext; - typename Traits::HANDLE ControlChannel; - } Handle; + union + { + typename Traits::HANDLE AddressHandle; + EMULATOR_CAST(typename Traits::PVOID, CONNECTION_CONTEXT) ConnectionContext; + typename Traits::HANDLE ControlChannel; + } Handle; - typename Traits::PVOID RequestNotifyObject; - typename Traits::PVOID RequestContext; - TDI_STATUS TdiStatus; + typename Traits::PVOID RequestNotifyObject; + typename Traits::PVOID RequestContext; + TDI_STATUS TdiStatus; }; template struct TDI_REQUEST_SEND_DATAGRAM { - TDI_REQUEST Request; - EMULATOR_CAST(typename Traits::PVOID, PTDI_CONNECTION_INFORMATION) SendDatagramInformation; + TDI_REQUEST Request; + EMULATOR_CAST(typename Traits::PVOID, PTDI_CONNECTION_INFORMATION) SendDatagramInformation; }; template struct AFD_SEND_INFO { - EMULATOR_CAST(typename Traits::PVOID, LPWSABUF) BufferArray; - ULONG BufferCount; - ULONG AfdFlags; - ULONG TdiFlags; + EMULATOR_CAST(typename Traits::PVOID, LPWSABUF) BufferArray; + ULONG BufferCount; + ULONG AfdFlags; + ULONG TdiFlags; }; template struct AFD_SEND_DATAGRAM_INFO { - EMULATOR_CAST(typename Traits::PVOID, LPWSABUF) BufferArray; - ULONG BufferCount; - ULONG AfdFlags; - TDI_REQUEST_SEND_DATAGRAM TdiRequest; - TDI_CONNECTION_INFORMATION TdiConnInfo; + EMULATOR_CAST(typename Traits::PVOID, LPWSABUF) BufferArray; + ULONG BufferCount; + ULONG AfdFlags; + TDI_REQUEST_SEND_DATAGRAM TdiRequest; + TDI_CONNECTION_INFORMATION TdiConnInfo; }; template struct AFD_RECV_INFO { - EMULATOR_CAST(typename Traits::PVOID, LPWSABUF) BufferArray; - ULONG BufferCount; - ULONG AfdFlags; - ULONG TdiFlags; + EMULATOR_CAST(typename Traits::PVOID, LPWSABUF) BufferArray; + ULONG BufferCount; + ULONG AfdFlags; + ULONG TdiFlags; }; template struct AFD_RECV_DATAGRAM_INFO { - EMULATOR_CAST(typename Traits::PVOID, LPWSABUF) BufferArray; - ULONG BufferCount; - ULONG AfdFlags; - ULONG TdiFlags; - typename Traits::PVOID Address; - EMULATOR_CAST(typename Traits::PVOID, PULONG) AddressLength; + EMULATOR_CAST(typename Traits::PVOID, LPWSABUF) BufferArray; + ULONG BufferCount; + ULONG AfdFlags; + ULONG TdiFlags; + typename Traits::PVOID Address; + EMULATOR_CAST(typename Traits::PVOID, PULONG) AddressLength; }; struct AFD_POLL_HANDLE_INFO64 { - EmulatorTraits::HANDLE Handle; - ULONG PollEvents; - NTSTATUS Status; + EmulatorTraits::HANDLE Handle; + ULONG PollEvents; + NTSTATUS Status; }; struct AFD_POLL_INFO64 { - LARGE_INTEGER Timeout; - ULONG NumberOfHandles; - BOOLEAN Unique; - AFD_POLL_HANDLE_INFO64 Handles[1]; + LARGE_INTEGER Timeout; + ULONG NumberOfHandles; + BOOLEAN Unique; + AFD_POLL_HANDLE_INFO64 Handles[1]; }; #define AFD_POLL_RECEIVE_BIT 0 @@ -117,59 +117,57 @@ struct AFD_POLL_INFO64 #define AFD_NUM_POLL_EVENTS 11 #define AFD_POLL_ALL ((1 << AFD_NUM_POLL_EVENTS) - 1) -#define _AFD_REQUEST(ioctl) \ - ((((ULONG)(ioctl)) >> 2) & 0x03FF) -#define _AFD_BASE(ioctl) \ - ((((ULONG)(ioctl)) >> 12) & 0xFFFFF) +#define _AFD_REQUEST(ioctl) ((((ULONG)(ioctl)) >> 2) & 0x03FF) +#define _AFD_BASE(ioctl) ((((ULONG)(ioctl)) >> 12) & 0xFFFFF) -#define FSCTL_AFD_BASE FILE_DEVICE_NETWORK +#define FSCTL_AFD_BASE FILE_DEVICE_NETWORK -#define AFD_BIND 0 -#define AFD_CONNECT 1 -#define AFD_START_LISTEN 2 -#define AFD_WAIT_FOR_LISTEN 3 -#define AFD_ACCEPT 4 -#define AFD_RECEIVE 5 -#define AFD_RECEIVE_DATAGRAM 6 -#define AFD_SEND 7 -#define AFD_SEND_DATAGRAM 8 -#define AFD_POLL 9 -#define AFD_PARTIAL_DISCONNECT 10 +#define AFD_BIND 0 +#define AFD_CONNECT 1 +#define AFD_START_LISTEN 2 +#define AFD_WAIT_FOR_LISTEN 3 +#define AFD_ACCEPT 4 +#define AFD_RECEIVE 5 +#define AFD_RECEIVE_DATAGRAM 6 +#define AFD_SEND 7 +#define AFD_SEND_DATAGRAM 8 +#define AFD_POLL 9 +#define AFD_PARTIAL_DISCONNECT 10 -#define AFD_GET_ADDRESS 11 -#define AFD_QUERY_RECEIVE_INFO 12 -#define AFD_QUERY_HANDLES 13 -#define AFD_SET_INFORMATION 14 -#define AFD_GET_CONTEXT_LENGTH 15 -#define AFD_GET_CONTEXT 16 -#define AFD_SET_CONTEXT 17 +#define AFD_GET_ADDRESS 11 +#define AFD_QUERY_RECEIVE_INFO 12 +#define AFD_QUERY_HANDLES 13 +#define AFD_SET_INFORMATION 14 +#define AFD_GET_CONTEXT_LENGTH 15 +#define AFD_GET_CONTEXT 16 +#define AFD_SET_CONTEXT 17 -#define AFD_SET_CONNECT_DATA 18 -#define AFD_SET_CONNECT_OPTIONS 19 -#define AFD_SET_DISCONNECT_DATA 20 -#define AFD_SET_DISCONNECT_OPTIONS 21 +#define AFD_SET_CONNECT_DATA 18 +#define AFD_SET_CONNECT_OPTIONS 19 +#define AFD_SET_DISCONNECT_DATA 20 +#define AFD_SET_DISCONNECT_OPTIONS 21 -#define AFD_GET_CONNECT_DATA 22 -#define AFD_GET_CONNECT_OPTIONS 23 -#define AFD_GET_DISCONNECT_DATA 24 -#define AFD_GET_DISCONNECT_OPTIONS 25 +#define AFD_GET_CONNECT_DATA 22 +#define AFD_GET_CONNECT_OPTIONS 23 +#define AFD_GET_DISCONNECT_DATA 24 +#define AFD_GET_DISCONNECT_OPTIONS 25 -#define AFD_SIZE_CONNECT_DATA 26 -#define AFD_SIZE_CONNECT_OPTIONS 27 -#define AFD_SIZE_DISCONNECT_DATA 28 -#define AFD_SIZE_DISCONNECT_OPTIONS 29 +#define AFD_SIZE_CONNECT_DATA 26 +#define AFD_SIZE_CONNECT_OPTIONS 27 +#define AFD_SIZE_DISCONNECT_DATA 28 +#define AFD_SIZE_DISCONNECT_OPTIONS 29 -#define AFD_GET_INFORMATION 30 -#define AFD_TRANSMIT_FILE 31 -#define AFD_SUPER_ACCEPT 32 +#define AFD_GET_INFORMATION 30 +#define AFD_TRANSMIT_FILE 31 +#define AFD_SUPER_ACCEPT 32 -#define AFD_EVENT_SELECT 33 -#define AFD_ENUM_NETWORK_EVENTS 34 +#define AFD_EVENT_SELECT 33 +#define AFD_ENUM_NETWORK_EVENTS 34 -#define AFD_DEFER_ACCEPT 35 -#define AFD_WAIT_FOR_LISTEN_LIFO 36 -#define AFD_SET_QOS 37 -#define AFD_GET_QOS 38 -#define AFD_NO_OPERATION 39 -#define AFD_VALIDATE_GROUP 40 +#define AFD_DEFER_ACCEPT 35 +#define AFD_WAIT_FOR_LISTEN_LIFO 36 +#define AFD_SET_QOS 37 +#define AFD_GET_QOS 38 +#define AFD_NO_OPERATION 39 +#define AFD_VALIDATE_GROUP 40 #define AFD_GET_UNACCEPTED_CONNECT_DATA 41 diff --git a/src/windows-emulator/emulator_utils.hpp b/src/windows-emulator/emulator_utils.hpp index c151761b..ae3cf9b1 100644 --- a/src/windows-emulator/emulator_utils.hpp +++ b/src/windows-emulator/emulator_utils.hpp @@ -8,31 +8,31 @@ using emulator_pointer = uint64_t; template class object_wrapper { - T* obj_; + T* obj_; -public: - object_wrapper(T& obj) - : obj_(&obj) - { - } + public: + object_wrapper(T& obj) + : obj_(&obj) + { + } - T& get() const - { - return *this->obj_; - } + T& get() const + { + return *this->obj_; + } - operator T&() const - { - return this->get(); - } + operator T&() const + { + return this->get(); + } - void serialize(utils::buffer_serializer&) const - { - } + void serialize(utils::buffer_serializer&) const + { + } - void deserialize(utils::buffer_deserializer&) - { - } + void deserialize(utils::buffer_deserializer&) + { + } }; class windows_emulator; @@ -45,256 +45,250 @@ using windows_emulator_wrapper = object_wrapper; template class emulator_object { -public: - using value_type = T; + public: + using value_type = T; - emulator_object(const x64_emulator_wrapper& wrapper, const uint64_t address = 0) - : emulator_object(wrapper.get(), address) - { - } + emulator_object(const x64_emulator_wrapper& wrapper, const uint64_t address = 0) + : emulator_object(wrapper.get(), address) + { + } - emulator_object(emulator& emu, const uint64_t address = 0) - : emu_(&emu) - , address_(address) - { - } + emulator_object(emulator& emu, const uint64_t address = 0) + : emu_(&emu), + address_(address) + { + } - emulator_object(emulator& emu, const void* address) - : emulator_object(emu, reinterpret_cast(address)) - { - } + emulator_object(emulator& emu, const void* address) + : emulator_object(emu, reinterpret_cast(address)) + { + } - uint64_t value() const - { - return this->address_; - } + uint64_t value() const + { + return this->address_; + } - constexpr uint64_t size() const - { - return sizeof(T); - } + constexpr uint64_t size() const + { + return sizeof(T); + } - uint64_t end() const - { - return this->value() + this->size(); - } + uint64_t end() const + { + return this->value() + this->size(); + } - T* ptr() const - { - return reinterpret_cast(this->address_); - } + T* ptr() const + { + return reinterpret_cast(this->address_); + } - operator bool() const - { - return this->address_ != 0; - } + operator bool() const + { + return this->address_ != 0; + } - T read(const size_t index = 0) const - { - T obj{}; - this->emu_->read_memory(this->address_ + index * this->size(), &obj, sizeof(obj)); - return obj; - } + T read(const size_t index = 0) const + { + T obj{}; + this->emu_->read_memory(this->address_ + index * this->size(), &obj, sizeof(obj)); + return obj; + } - void write(const T& value, const size_t index = 0) const - { - this->emu_->write_memory(this->address_ + index * this->size(), &value, sizeof(value)); - } + void write(const T& value, const size_t index = 0) const + { + this->emu_->write_memory(this->address_ + index * this->size(), &value, sizeof(value)); + } - void write_if_valid(const T& value, const size_t index = 0) const - { - if (this->operator bool()) - { - this->write(value, index); - } - } + void write_if_valid(const T& value, const size_t index = 0) const + { + if (this->operator bool()) + { + this->write(value, index); + } + } - template - void access(const F& accessor, const size_t index = 0) const - { - T obj{}; - this->emu_->read_memory(this->address_ + index * this->size(), &obj, sizeof(obj)); + template + void access(const F& accessor, const size_t index = 0) const + { + T obj{}; + this->emu_->read_memory(this->address_ + index * this->size(), &obj, sizeof(obj)); - accessor(obj); + accessor(obj); - this->write(obj, index); - } + this->write(obj, index); + } - void serialize(utils::buffer_serializer& buffer) const - { - buffer.write(this->address_); - } + void serialize(utils::buffer_serializer& buffer) const + { + buffer.write(this->address_); + } - void deserialize(utils::buffer_deserializer& buffer) - { - buffer.read(this->address_); - } + void deserialize(utils::buffer_deserializer& buffer) + { + buffer.read(this->address_); + } - void set_address(const uint64_t address) - { - this->address_ = address; - } + void set_address(const uint64_t address) + { + this->address_ = address; + } -private: - emulator* emu_{}; - uint64_t address_{}; + private: + emulator* emu_{}; + uint64_t address_{}; }; - // TODO: warning emulator_utils is hardcoded for 64bit unicode_string usage class emulator_allocator { -public: - emulator_allocator(emulator& emu) - : emu_(&emu) - { - } + public: + emulator_allocator(emulator& emu) + : emu_(&emu) + { + } - emulator_allocator(emulator& emu, const uint64_t address, const uint64_t size) - : emu_(&emu) - , address_(address) - , size_(size) - , active_address_(address) - { - } + emulator_allocator(emulator& emu, const uint64_t address, const uint64_t size) + : emu_(&emu), + address_(address), + size_(size), + active_address_(address) + { + } - uint64_t reserve(const uint64_t count, const uint64_t alignment = 1) - { - const auto potential_start = align_up(this->active_address_, alignment); - const auto potential_end = potential_start + count; - const auto total_end = this->address_ + this->size_; + uint64_t reserve(const uint64_t count, const uint64_t alignment = 1) + { + const auto potential_start = align_up(this->active_address_, alignment); + const auto potential_end = potential_start + count; + const auto total_end = this->address_ + this->size_; - if (potential_end > total_end) - { - throw std::runtime_error("Out of memory"); - } + if (potential_end > total_end) + { + throw std::runtime_error("Out of memory"); + } - this->active_address_ = potential_end; + this->active_address_ = potential_end; - return potential_start; - } + return potential_start; + } - template - emulator_object reserve(const size_t count = 1) - { - const auto potential_start = this->reserve(sizeof(T) * count, alignof(T)); - return emulator_object(*this->emu_, potential_start); - } + template + emulator_object reserve(const size_t count = 1) + { + const auto potential_start = this->reserve(sizeof(T) * count, alignof(T)); + return emulator_object(*this->emu_, potential_start); + } + char16_t* copy_string(const std::u16string_view str) + { + UNICODE_STRING> uc_str{}; + this->make_unicode_string(uc_str, str); + return reinterpret_cast(uc_str.Buffer); + } - char16_t* copy_string(const std::u16string_view str) - { - UNICODE_STRING> uc_str{}; - this->make_unicode_string(uc_str, str); - return reinterpret_cast(uc_str.Buffer); - } + void make_unicode_string(UNICODE_STRING>& result, const std::u16string_view str) + { + constexpr auto element_size = sizeof(str[0]); + constexpr auto required_alignment = alignof(decltype(str[0])); + const auto total_length = str.size() * element_size; - void make_unicode_string(UNICODE_STRING>& result, const std::u16string_view str) - { - constexpr auto element_size = sizeof(str[0]); - constexpr auto required_alignment = alignof(decltype(str[0])); - const auto total_length = str.size() * element_size; + const auto string_buffer = this->reserve(total_length + element_size, required_alignment); - const auto string_buffer = this->reserve(total_length + element_size, required_alignment); + this->emu_->write_memory(string_buffer, str.data(), total_length); - this->emu_->write_memory(string_buffer, str.data(), total_length); + constexpr std::array nullbyte{}; + this->emu_->write_memory(string_buffer + total_length, nullbyte.data(), nullbyte.size()); - constexpr std::array nullbyte{}; - this->emu_->write_memory(string_buffer + total_length, nullbyte.data(), nullbyte.size()); + result.Buffer = string_buffer; + result.Length = static_cast(total_length); + result.MaximumLength = static_cast(total_length + element_size); + } - result.Buffer = string_buffer; - result.Length = static_cast(total_length); - result.MaximumLength = static_cast(total_length + element_size); - } + emulator_object>> make_unicode_string(const std::u16string_view str) + { + const auto unicode_string = this->reserve>>(); - emulator_object>> make_unicode_string(const std::u16string_view str) - { - const auto unicode_string = this->reserve>>(); + unicode_string.access( + [&](UNICODE_STRING>& unicode_str) { this->make_unicode_string(unicode_str, str); }); - unicode_string.access([&](UNICODE_STRING>& unicode_str) - { - this->make_unicode_string(unicode_str, str); - }); + return unicode_string; + } - return unicode_string; - } + uint64_t get_base() const + { + return this->address_; + } - uint64_t get_base() const - { - return this->address_; - } + uint64_t get_size() const + { + return this->size_; + } - uint64_t get_size() const - { - return this->size_; - } + uint64_t get_next_address() const + { + return this->active_address_; + } - uint64_t get_next_address() const - { - return this->active_address_; - } + emulator& get_emulator() const + { + return *this->emu_; + } - emulator& get_emulator() const - { - return *this->emu_; - } + void serialize(utils::buffer_serializer& buffer) const + { + buffer.write(this->address_); + buffer.write(this->size_); + buffer.write(this->active_address_); + } - void serialize(utils::buffer_serializer& buffer) const - { - buffer.write(this->address_); - buffer.write(this->size_); - buffer.write(this->active_address_); - } + void deserialize(utils::buffer_deserializer& buffer) + { + buffer.read(this->address_); + buffer.read(this->size_); + buffer.read(this->active_address_); + } - void deserialize(utils::buffer_deserializer& buffer) - { - buffer.read(this->address_); - buffer.read(this->size_); - buffer.read(this->active_address_); - } + void release() + { + if (this->emu_ && this->address_ && this->size_) + { + this->emu_->release_memory(this->address_, this->size_); + this->address_ = 0; + this->size_ = 0; + } + } - void release() - { - if (this->emu_ && this->address_ && this->size_) - { - this->emu_->release_memory(this->address_, this->size_); - this->address_ = 0; - this->size_ = 0; - } - } - -private: - emulator* emu_{}; - uint64_t address_{}; - uint64_t size_{}; - uint64_t active_address_{0}; + private: + emulator* emu_{}; + uint64_t address_{}; + uint64_t size_{}; + uint64_t active_address_{0}; }; - inline std::u16string read_unicode_string(const emulator& emu, const UNICODE_STRING> ucs) { - static_assert(offsetof(UNICODE_STRING>, Length) == 0); - static_assert(offsetof(UNICODE_STRING>, MaximumLength) == 2); - static_assert(offsetof(UNICODE_STRING>, Buffer) == 8); - static_assert(sizeof(UNICODE_STRING>) == 16); + static_assert(offsetof(UNICODE_STRING>, Length) == 0); + static_assert(offsetof(UNICODE_STRING>, MaximumLength) == 2); + static_assert(offsetof(UNICODE_STRING>, Buffer) == 8); + static_assert(sizeof(UNICODE_STRING>) == 16); - std::u16string result{}; - result.resize(ucs.Length / 2); + std::u16string result{}; + result.resize(ucs.Length / 2); - emu.read_memory(ucs.Buffer, result.data(), ucs.Length); + emu.read_memory(ucs.Buffer, result.data(), ucs.Length); - return result; + return result; } - inline std::u16string read_unicode_string(const emulator& emu, const emulator_object>> uc_string) { - const auto ucs = uc_string.read(); - return read_unicode_string(emu, ucs); + const auto ucs = uc_string.read(); + return read_unicode_string(emu, ucs); } inline std::u16string read_unicode_string(emulator& emu, const UNICODE_STRING>* uc_string) { - return read_unicode_string(emu, emulator_object>>{emu, uc_string}); + return read_unicode_string(emu, emulator_object>>{emu, uc_string}); } diff --git a/src/windows-emulator/handles.hpp b/src/windows-emulator/handles.hpp index 35362a4f..cc99ac0d 100644 --- a/src/windows-emulator/handles.hpp +++ b/src/windows-emulator/handles.hpp @@ -2,33 +2,33 @@ struct handle_types { - enum type : uint16_t - { - reserved = 0, - file, - device, - event, - section, - symlink, - directory, - semaphore, - port, - thread, - registry, - mutant, - token, - }; + enum type : uint16_t + { + reserved = 0, + file, + device, + event, + section, + symlink, + directory, + semaphore, + port, + thread, + registry, + mutant, + token, + }; }; #pragma pack(push) #pragma pack(1) struct handle_value { - uint64_t id : 32; - uint64_t type : 16; - uint64_t padding : 14; - uint64_t is_system : 1; - uint64_t is_pseudo : 1; + uint64_t id : 32; + uint64_t type : 16; + uint64_t padding : 14; + uint64_t is_system : 1; + uint64_t is_pseudo : 1; }; #pragma pack(pop) @@ -37,315 +37,315 @@ static_assert(sizeof(handle_value) == 8); // TODO: this is a concrete 64bit handle union handle { - handle_value value; - uint64_t bits; - std::uint64_t h; + handle_value value; + uint64_t bits; + std::uint64_t h; }; namespace utils { - inline void serialize(buffer_serializer& buffer, const handle& h) - { - buffer.write(h.bits); - } + inline void serialize(buffer_serializer& buffer, const handle& h) + { + buffer.write(h.bits); + } - inline void deserialize(buffer_deserializer& buffer, handle& h) - { - buffer.read(h.bits); - } + inline void deserialize(buffer_deserializer& buffer, handle& h) + { + buffer.read(h.bits); + } } inline bool operator==(const handle& h1, const handle& h2) { - return h1.bits == h2.bits; + return h1.bits == h2.bits; } inline bool operator==(const handle& h1, const uint64_t& h2) { - return h1.bits == h2; + return h1.bits == h2; } inline handle_value get_handle_value(const uint64_t h) { - handle hh{}; - hh.bits = h; - return hh.value; + handle hh{}; + hh.bits = h; + return hh.value; } constexpr handle make_handle(const uint32_t id, const handle_types::type type, const bool is_pseudo) { - handle_value value{}; + handle_value value{}; - value.padding = 0; - value.id = id; - value.type = type; - value.is_system = false; - value.is_pseudo = is_pseudo; + value.padding = 0; + value.id = id; + value.type = type; + value.is_system = false; + value.is_pseudo = is_pseudo; - return {value}; + return {value}; } constexpr handle make_handle(const uint64_t value) { - handle h{}; - h.bits = value; - return h; + handle h{}; + h.bits = value; + return h; } constexpr handle make_pseudo_handle(const uint32_t id, const handle_types::type type) { - return make_handle(id, type, true); + return make_handle(id, type, true); } namespace handle_detail { - template - struct has_deleter_function : std::false_type - { - }; + template + struct has_deleter_function : std::false_type + { + }; - template - struct has_deleter_function()))>> - : std::is_same())), bool> - { - }; + template + struct has_deleter_function()))>> + : std::is_same())), bool> + { + }; } struct generic_handle_store { - virtual ~generic_handle_store() = default; - virtual bool erase(const handle h) = 0; + virtual ~generic_handle_store() = default; + virtual bool erase(const handle h) = 0; }; template - requires(utils::Serializable) + requires(utils::Serializable) class handle_store : public generic_handle_store { -public: - using index_type = uint32_t; - using value_map = std::map; + public: + using index_type = uint32_t; + using value_map = std::map; - bool block_mutation(bool blocked) - { - std::swap(this->block_mutation_, blocked); - return blocked; - } + bool block_mutation(bool blocked) + { + std::swap(this->block_mutation_, blocked); + return blocked; + } - handle store(T value) - { - if (this->block_mutation_) - { - throw std::runtime_error("Mutation of handle store is blocked!"); - } + handle store(T value) + { + if (this->block_mutation_) + { + throw std::runtime_error("Mutation of handle store is blocked!"); + } - auto index = this->find_free_index(); - this->store_.emplace(index, std::move(value)); + auto index = this->find_free_index(); + this->store_.emplace(index, std::move(value)); - return make_handle(index); - } + return make_handle(index); + } - handle make_handle(const index_type index) const - { - handle h{}; - h.bits = 0; - h.value.is_pseudo = false; - h.value.type = Type; - h.value.id = index << IndexShift; + handle make_handle(const index_type index) const + { + handle h{}; + h.bits = 0; + h.value.is_pseudo = false; + h.value.type = Type; + h.value.id = index << IndexShift; - return h; - } + return h; + } - T* get_by_index(const uint32_t index) - { - return this->get(this->make_handle(index)); - } + T* get_by_index(const uint32_t index) + { + return this->get(this->make_handle(index)); + } - T* get(const handle_value h) - { - const auto entry = this->get_iterator(h); - if (entry == this->store_.end()) - { - return nullptr; - } + T* get(const handle_value h) + { + const auto entry = this->get_iterator(h); + if (entry == this->store_.end()) + { + return nullptr; + } - return &entry->second; - } + return &entry->second; + } - T* get(const handle h) - { - return this->get(h.value); - } + T* get(const handle h) + { + return this->get(h.value); + } - T* get(const uint64_t h) - { - handle hh{}; - hh.bits = h; + T* get(const uint64_t h) + { + handle hh{}; + hh.bits = h; - return this->get(hh); - } + return this->get(hh); + } - size_t size() const - { - return this->store_.size(); - } + size_t size() const + { + return this->store_.size(); + } - bool erase(const typename value_map::iterator& entry) - { - if (this->block_mutation_) - { - throw std::runtime_error("Mutation of handle store is blocked!"); - } + bool erase(const typename value_map::iterator& entry) + { + if (this->block_mutation_) + { + throw std::runtime_error("Mutation of handle store is blocked!"); + } - if (entry == this->store_.end()) - { - return false; - } + if (entry == this->store_.end()) + { + return false; + } - if constexpr (handle_detail::has_deleter_function()) - { - if (!T::deleter(entry->second)) - { - return false; - } - } + if constexpr (handle_detail::has_deleter_function()) + { + if (!T::deleter(entry->second)) + { + return false; + } + } - this->store_.erase(entry); - return true; - } + this->store_.erase(entry); + return true; + } - bool erase(const handle_value h) - { - const auto entry = this->get_iterator(h); - return this->erase(entry); - } + bool erase(const handle_value h) + { + const auto entry = this->get_iterator(h); + return this->erase(entry); + } - bool erase(const handle h) override - { - return this->erase(h.value); - } + bool erase(const handle h) override + { + return this->erase(h.value); + } - bool erase(const uint64_t h) - { - handle hh{}; - hh.bits = h; + bool erase(const uint64_t h) + { + handle hh{}; + hh.bits = h; - return this->erase(hh); - } + return this->erase(hh); + } - bool erase(const T& value) - { - const auto entry = this->find(value); - return this->erase(entry); - } + bool erase(const T& value) + { + const auto entry = this->find(value); + return this->erase(entry); + } - void serialize(utils::buffer_serializer& buffer) const - { - buffer.write(this->block_mutation_); - buffer.write_map(this->store_); - } + void serialize(utils::buffer_serializer& buffer) const + { + buffer.write(this->block_mutation_); + buffer.write_map(this->store_); + } - void deserialize(utils::buffer_deserializer& buffer) - { - buffer.read(this->block_mutation_); - buffer.read_map(this->store_); - } + void deserialize(utils::buffer_deserializer& buffer) + { + buffer.read(this->block_mutation_); + buffer.read_map(this->store_); + } - typename value_map::iterator find(const T& value) - { - auto i = this->store_.begin(); - for (; i != this->store_.end(); ++i) - { - if (&i->second == &value) - { - break; - } - } + typename value_map::iterator find(const T& value) + { + auto i = this->store_.begin(); + for (; i != this->store_.end(); ++i) + { + if (&i->second == &value) + { + break; + } + } - return i; - } + return i; + } - typename value_map::const_iterator find(const T& value) const - { - auto i = this->store_.begin(); - for (; i != this->store_.end(); ++i) - { - if (&i->second == &value) - { - break; - } - } + typename value_map::const_iterator find(const T& value) const + { + auto i = this->store_.begin(); + for (; i != this->store_.end(); ++i) + { + if (&i->second == &value) + { + break; + } + } - return i; - } + return i; + } - handle find_handle(const T& value) const - { - const auto entry = this->find(value); - if (entry == this->end()) - { - return {}; - } + handle find_handle(const T& value) const + { + const auto entry = this->find(value); + if (entry == this->end()) + { + return {}; + } - return this->make_handle(entry->first); - } + return this->make_handle(entry->first); + } - handle find_handle(const T* value) const - { - if (!value) - { - return {}; - } + handle find_handle(const T* value) const + { + if (!value) + { + return {}; + } - return this->find_handle(*value); - } + return this->find_handle(*value); + } - typename value_map::iterator begin() - { - return this->store_.begin(); - } + typename value_map::iterator begin() + { + return this->store_.begin(); + } - typename value_map::const_iterator begin() const - { - return this->store_.begin(); - } + typename value_map::const_iterator begin() const + { + return this->store_.begin(); + } - typename value_map::iterator end() - { - return this->store_.end(); - } + typename value_map::iterator end() + { + return this->store_.end(); + } - typename value_map::const_iterator end() const - { - return this->store_.end(); - } + typename value_map::const_iterator end() const + { + return this->store_.end(); + } -private: - typename value_map::iterator get_iterator(const handle_value h) - { - if (h.type != Type || h.is_pseudo) - { - return this->store_.end(); - } + private: + typename value_map::iterator get_iterator(const handle_value h) + { + if (h.type != Type || h.is_pseudo) + { + return this->store_.end(); + } - return this->store_.find(static_cast(h.id) >> IndexShift); - } + return this->store_.find(static_cast(h.id) >> IndexShift); + } - uint32_t find_free_index() - { - uint32_t index = 1; - for (; index > 0; ++index) - { - if (!this->store_.contains(index)) - { - break; - } - } + uint32_t find_free_index() + { + uint32_t index = 1; + for (; index > 0; ++index) + { + if (!this->store_.contains(index)) + { + break; + } + } - return index; - } + return index; + } - bool block_mutation_{false}; - value_map store_{}; + bool block_mutation_{false}; + value_map store_{}; }; constexpr auto KNOWN_DLLS_DIRECTORY = make_pseudo_handle(0x1, handle_types::directory); diff --git a/src/windows-emulator/io_device.cpp b/src/windows-emulator/io_device.cpp index 00374b39..db443bd0 100644 --- a/src/windows-emulator/io_device.cpp +++ b/src/windows-emulator/io_device.cpp @@ -3,30 +3,27 @@ namespace { - struct dummy_device : stateless_device - { - NTSTATUS io_control(windows_emulator&, const io_device_context&) override - { - return STATUS_SUCCESS; - } - }; + struct dummy_device : stateless_device + { + NTSTATUS io_control(windows_emulator&, const io_device_context&) override + { + return STATUS_SUCCESS; + } + }; } std::unique_ptr create_device(const std::u16string_view device) { - if (device == u"CNG" - || device == u"KsecDD" - || device == u"PcwDrv" - || device == u"DeviceApi\\CMApi" - || device == u"ConDrv\\Server") - { - return std::make_unique(); - } + if (device == u"CNG" || device == u"KsecDD" || device == u"PcwDrv" || device == u"DeviceApi\\CMApi" || + device == u"ConDrv\\Server") + { + return std::make_unique(); + } - if (device == u"Afd\\Endpoint") - { - return create_afd_endpoint(); - } + if (device == u"Afd\\Endpoint") + { + return create_afd_endpoint(); + } - throw std::runtime_error("Unsupported device: " + u16_to_u8(device)); + throw std::runtime_error("Unsupported device: " + u16_to_u8(device)); } diff --git a/src/windows-emulator/io_device.hpp b/src/windows-emulator/io_device.hpp index 965d1da3..ceb4d571 100644 --- a/src/windows-emulator/io_device.hpp +++ b/src/windows-emulator/io_device.hpp @@ -12,190 +12,188 @@ struct process_context; struct io_device_context { - handle event{}; - emulator_pointer /*PIO_APC_ROUTINE*/ apc_routine{}; - emulator_pointer apc_context{}; - emulator_object>> io_status_block; - ULONG io_control_code{}; - emulator_pointer input_buffer{}; - ULONG input_buffer_length{}; - emulator_pointer output_buffer{}; - ULONG output_buffer_length{}; + handle event{}; + emulator_pointer /*PIO_APC_ROUTINE*/ apc_routine{}; + emulator_pointer apc_context{}; + emulator_object>> io_status_block; + ULONG io_control_code{}; + emulator_pointer input_buffer{}; + ULONG input_buffer_length{}; + emulator_pointer output_buffer{}; + ULONG output_buffer_length{}; - io_device_context(x64_emulator& emu) - : io_status_block(emu) - { - } + io_device_context(x64_emulator& emu) + : io_status_block(emu) + { + } - io_device_context(utils::buffer_deserializer& buffer) - : io_device_context(buffer.read().get()) - { - } + io_device_context(utils::buffer_deserializer& buffer) + : io_device_context(buffer.read().get()) + { + } - void serialize(utils::buffer_serializer& buffer) const - { - buffer.write(event); - buffer.write(apc_routine); - buffer.write(apc_context); - buffer.write(io_status_block); - buffer.write(io_control_code); - buffer.write(input_buffer); - buffer.write(input_buffer_length); - buffer.write(output_buffer); - buffer.write(output_buffer_length); - } + void serialize(utils::buffer_serializer& buffer) const + { + buffer.write(event); + buffer.write(apc_routine); + buffer.write(apc_context); + buffer.write(io_status_block); + buffer.write(io_control_code); + buffer.write(input_buffer); + buffer.write(input_buffer_length); + buffer.write(output_buffer); + buffer.write(output_buffer_length); + } - void deserialize(utils::buffer_deserializer& buffer) - { - buffer.read(event); - buffer.read(apc_routine); - buffer.read(apc_context); - buffer.read(io_status_block); - buffer.read(io_control_code); - buffer.read(input_buffer); - buffer.read(input_buffer_length); - buffer.read(output_buffer); - buffer.read(output_buffer_length); - } + void deserialize(utils::buffer_deserializer& buffer) + { + buffer.read(event); + buffer.read(apc_routine); + buffer.read(apc_context); + buffer.read(io_status_block); + buffer.read(io_control_code); + buffer.read(input_buffer); + buffer.read(input_buffer_length); + buffer.read(output_buffer); + buffer.read(output_buffer_length); + } }; struct io_device_creation_data { - uint64_t buffer; - uint32_t length; + uint64_t buffer; + uint32_t length; }; inline void write_io_status(const emulator_object>> io_status_block, const NTSTATUS status) { - if (io_status_block) - { - io_status_block.access([&](IO_STATUS_BLOCK>& status_block) - { - status_block.Status = status; - }); - } + if (io_status_block) + { + io_status_block.access( + [&](IO_STATUS_BLOCK>& status_block) { status_block.Status = status; }); + } } struct io_device { - io_device() = default; - virtual ~io_device() = default; + io_device() = default; + virtual ~io_device() = default; - io_device(io_device&&) = default; - io_device& operator=(io_device&&) = default; + io_device(io_device&&) = default; + io_device& operator=(io_device&&) = default; - io_device(const io_device&) = delete; - io_device& operator=(const io_device&) = delete; + io_device(const io_device&) = delete; + io_device& operator=(const io_device&) = delete; - virtual NTSTATUS io_control(windows_emulator& win_emu, const io_device_context& context) = 0; + virtual NTSTATUS io_control(windows_emulator& win_emu, const io_device_context& context) = 0; - virtual void create(windows_emulator& win_emu, const io_device_creation_data& data) - { - (void)win_emu; - (void)data; - } + virtual void create(windows_emulator& win_emu, const io_device_creation_data& data) + { + (void)win_emu; + (void)data; + } - virtual void work(windows_emulator& win_emu) - { - (void)win_emu; - } + virtual void work(windows_emulator& win_emu) + { + (void)win_emu; + } - virtual void serialize(utils::buffer_serializer& buffer) const = 0; - virtual void deserialize(utils::buffer_deserializer& buffer) = 0; + virtual void serialize(utils::buffer_serializer& buffer) const = 0; + virtual void deserialize(utils::buffer_deserializer& buffer) = 0; - NTSTATUS execute_ioctl(windows_emulator& win_emu, const io_device_context& c) - { - if (c.io_status_block) - { - c.io_status_block.write({}); - } + NTSTATUS execute_ioctl(windows_emulator& win_emu, const io_device_context& c) + { + if (c.io_status_block) + { + c.io_status_block.write({}); + } - const auto result = this->io_control(win_emu, c); - write_io_status(c.io_status_block, result); - return result; - } + const auto result = this->io_control(win_emu, c); + write_io_status(c.io_status_block, result); + return result; + } }; struct stateless_device : io_device { - void create(windows_emulator&, const io_device_creation_data&) final - { - } + void create(windows_emulator&, const io_device_creation_data&) final + { + } - void serialize(utils::buffer_serializer&) const override - { - } + void serialize(utils::buffer_serializer&) const override + { + } - void deserialize(utils::buffer_deserializer&) override - { - } + void deserialize(utils::buffer_deserializer&) override + { + } }; std::unique_ptr create_device(std::u16string_view device); class io_device_container : public io_device { -public: - io_device_container() = default; + public: + io_device_container() = default; - io_device_container(std::u16string device, windows_emulator& win_emu, const io_device_creation_data& data) - : device_name_(std::move(device)) - { - this->setup(); - this->device_->create(win_emu, data); - } + io_device_container(std::u16string device, windows_emulator& win_emu, const io_device_creation_data& data) + : device_name_(std::move(device)) + { + this->setup(); + this->device_->create(win_emu, data); + } - NTSTATUS io_control(windows_emulator& win_emu, const io_device_context& context) override - { - this->assert_validity(); - return this->device_->io_control(win_emu, context); - } + NTSTATUS io_control(windows_emulator& win_emu, const io_device_context& context) override + { + this->assert_validity(); + return this->device_->io_control(win_emu, context); + } - void work(windows_emulator& win_emu) override - { - this->assert_validity(); - return this->device_->work(win_emu); - } + void work(windows_emulator& win_emu) override + { + this->assert_validity(); + return this->device_->work(win_emu); + } - void serialize(utils::buffer_serializer& buffer) const override - { - this->assert_validity(); + void serialize(utils::buffer_serializer& buffer) const override + { + this->assert_validity(); - buffer.write_string(this->device_name_); - this->device_->serialize(buffer); - } + buffer.write_string(this->device_name_); + this->device_->serialize(buffer); + } - void deserialize(utils::buffer_deserializer& buffer) override - { - buffer.read_string(this->device_name_); - this->setup(); - this->device_->deserialize(buffer); - } + void deserialize(utils::buffer_deserializer& buffer) override + { + buffer.read_string(this->device_name_); + this->setup(); + this->device_->deserialize(buffer); + } - template - requires(std::is_base_of_v || std::is_same_v) - T* get_internal_device() - { - this->assert_validity(); - auto* value = this->device_.get(); - return dynamic_cast(value); - } + template + requires(std::is_base_of_v || std::is_same_v) + T* get_internal_device() + { + this->assert_validity(); + auto* value = this->device_.get(); + return dynamic_cast(value); + } -private: - std::u16string device_name_{}; - std::unique_ptr device_{}; + private: + std::u16string device_name_{}; + std::unique_ptr device_{}; - void setup() - { - this->device_ = create_device(this->device_name_); - } + void setup() + { + this->device_ = create_device(this->device_name_); + } - void assert_validity() const - { - if (!this->device_) - { - throw std::runtime_error("Device not created!"); - } - } + void assert_validity() const + { + if (!this->device_) + { + throw std::runtime_error("Device not created!"); + } + } }; diff --git a/src/windows-emulator/kusd_mmio.cpp b/src/windows-emulator/kusd_mmio.cpp index b88e2d23..d8f6176c 100644 --- a/src/windows-emulator/kusd_mmio.cpp +++ b/src/windows-emulator/kusd_mmio.cpp @@ -10,216 +10,214 @@ constexpr auto KUSD_BUFFER_SIZE = page_align_up(KUSD_SIZE); namespace { - void setup_kusd(KUSER_SHARED_DATA64& kusd, const bool use_relative_time) - { - memset(reinterpret_cast(&kusd), 0, sizeof(kusd)); + void setup_kusd(KUSER_SHARED_DATA64& kusd, const bool use_relative_time) + { + memset(reinterpret_cast(&kusd), 0, sizeof(kusd)); - kusd.TickCountMultiplier = 0x0fa00000; - kusd.InterruptTime.LowPart = 0x17bd9547; - kusd.InterruptTime.High1Time = 0x0000004b; - kusd.InterruptTime.High2Time = 0x0000004b; - kusd.SystemTime.LowPart = 0x7af9da99; - kusd.SystemTime.High1Time = 0x01db27b9; - kusd.SystemTime.High2Time = 0x01db27b9; - kusd.TimeZoneBias.LowPart = 0x3c773000; - kusd.TimeZoneBias.High1Time = -17; - kusd.TimeZoneBias.High2Time = -17; - kusd.TimeZoneId = 0x00000002; - kusd.LargePageMinimum = 0x00200000; - kusd.RNGSeedVersion = 0x0000000000000013; - kusd.TimeZoneBiasStamp = 0x00000004; - kusd.NtBuildNumber = 0x00006c51; - kusd.NtProductType = NtProductWinNt; - kusd.ProductTypeIsValid = 0x01; - kusd.NativeProcessorArchitecture = 0x0009; - kusd.NtMajorVersion = 0x0000000a; - kusd.BootId = 0x0000000b; - kusd.SystemExpirationDate.QuadPart = 0x01dc26860a9ff300; - kusd.SuiteMask = 0x00000110; - kusd.MitigationPolicies.MitigationPolicies = 0x0a; - kusd.MitigationPolicies.NXSupportPolicy = 0x02; - kusd.MitigationPolicies.SEHValidationPolicy = 0x02; - kusd.CyclesPerYield = 0x0064; - kusd.DismountCount = 0x00000006; - kusd.ComPlusPackage = 0x00000001; - kusd.LastSystemRITEventTickCount = 0x01ec1fd3; - kusd.NumberOfPhysicalPages = 0x00bf0958; - kusd.FullNumberOfPhysicalPages = 0x0000000000bf0958; - kusd.TickCount.TickCount.LowPart = 0x001f7f05; - kusd.TickCount.TickCountQuad = 0x00000000001f7f05; - kusd.Cookie = 0x1c3471da; - kusd.ConsoleSessionForegroundProcessId = 0x00000000000028f4; - kusd.TimeUpdateLock = 0x0000000002b28586; - kusd.BaselineSystemTimeQpc = 0x0000004b17cd596c; - kusd.BaselineInterruptTimeQpc = 0x0000004b17cd596c; - kusd.QpcSystemTimeIncrement = 0x8000000000000000; - kusd.QpcInterruptTimeIncrement = 0x8000000000000000; - kusd.QpcSystemTimeIncrementShift = 0x01; - kusd.QpcInterruptTimeIncrementShift = 0x01; - kusd.UnparkedProcessorCount = 0x000c; - kusd.TelemetryCoverageRound = 0x00000001; - kusd.LangGenerationCount = 0x00000003; - kusd.InterruptTimeBias = 0x00000015a5d56406; - kusd.QpcBias = 0x000000159530c4af; - kusd.ActiveProcessorCount = 0x0000000c; - kusd.ActiveGroupCount = 0x01; - kusd.QpcData.QpcData = 0x0083; - kusd.QpcData.QpcBypassEnabled = 0x83; - kusd.TimeZoneBiasEffectiveStart.QuadPart = 0x01db276e654cb2ff; - kusd.TimeZoneBiasEffectiveEnd.QuadPart = 0x01db280b8c3b2800; - kusd.XState.EnabledFeatures = 0x000000000000001f; - kusd.XState.EnabledVolatileFeatures = 0x000000000000000f; - kusd.XState.Size = 0x000003c0; + kusd.TickCountMultiplier = 0x0fa00000; + kusd.InterruptTime.LowPart = 0x17bd9547; + kusd.InterruptTime.High1Time = 0x0000004b; + kusd.InterruptTime.High2Time = 0x0000004b; + kusd.SystemTime.LowPart = 0x7af9da99; + kusd.SystemTime.High1Time = 0x01db27b9; + kusd.SystemTime.High2Time = 0x01db27b9; + kusd.TimeZoneBias.LowPart = 0x3c773000; + kusd.TimeZoneBias.High1Time = -17; + kusd.TimeZoneBias.High2Time = -17; + kusd.TimeZoneId = 0x00000002; + kusd.LargePageMinimum = 0x00200000; + kusd.RNGSeedVersion = 0x0000000000000013; + kusd.TimeZoneBiasStamp = 0x00000004; + kusd.NtBuildNumber = 0x00006c51; + kusd.NtProductType = NtProductWinNt; + kusd.ProductTypeIsValid = 0x01; + kusd.NativeProcessorArchitecture = 0x0009; + kusd.NtMajorVersion = 0x0000000a; + kusd.BootId = 0x0000000b; + kusd.SystemExpirationDate.QuadPart = 0x01dc26860a9ff300; + kusd.SuiteMask = 0x00000110; + kusd.MitigationPolicies.MitigationPolicies = 0x0a; + kusd.MitigationPolicies.NXSupportPolicy = 0x02; + kusd.MitigationPolicies.SEHValidationPolicy = 0x02; + kusd.CyclesPerYield = 0x0064; + kusd.DismountCount = 0x00000006; + kusd.ComPlusPackage = 0x00000001; + kusd.LastSystemRITEventTickCount = 0x01ec1fd3; + kusd.NumberOfPhysicalPages = 0x00bf0958; + kusd.FullNumberOfPhysicalPages = 0x0000000000bf0958; + kusd.TickCount.TickCount.LowPart = 0x001f7f05; + kusd.TickCount.TickCountQuad = 0x00000000001f7f05; + kusd.Cookie = 0x1c3471da; + kusd.ConsoleSessionForegroundProcessId = 0x00000000000028f4; + kusd.TimeUpdateLock = 0x0000000002b28586; + kusd.BaselineSystemTimeQpc = 0x0000004b17cd596c; + kusd.BaselineInterruptTimeQpc = 0x0000004b17cd596c; + kusd.QpcSystemTimeIncrement = 0x8000000000000000; + kusd.QpcInterruptTimeIncrement = 0x8000000000000000; + kusd.QpcSystemTimeIncrementShift = 0x01; + kusd.QpcInterruptTimeIncrementShift = 0x01; + kusd.UnparkedProcessorCount = 0x000c; + kusd.TelemetryCoverageRound = 0x00000001; + kusd.LangGenerationCount = 0x00000003; + kusd.InterruptTimeBias = 0x00000015a5d56406; + kusd.QpcBias = 0x000000159530c4af; + kusd.ActiveProcessorCount = 0x0000000c; + kusd.ActiveGroupCount = 0x01; + kusd.QpcData.QpcData = 0x0083; + kusd.QpcData.QpcBypassEnabled = 0x83; + kusd.TimeZoneBiasEffectiveStart.QuadPart = 0x01db276e654cb2ff; + kusd.TimeZoneBiasEffectiveEnd.QuadPart = 0x01db280b8c3b2800; + kusd.XState.EnabledFeatures = 0x000000000000001f; + kusd.XState.EnabledVolatileFeatures = 0x000000000000000f; + kusd.XState.Size = 0x000003c0; - if (use_relative_time) - { - kusd.QpcFrequency = 1000; - } - else - { - kusd.QpcFrequency = std::chrono::steady_clock::period::den; - } + if (use_relative_time) + { + kusd.QpcFrequency = 1000; + } + else + { + kusd.QpcFrequency = std::chrono::steady_clock::period::den; + } - constexpr std::wstring_view root_dir{L"C:\\WINDOWS"}; - memcpy(&kusd.NtSystemRoot.arr[0], root_dir.data(), root_dir.size() * 2); + constexpr std::wstring_view root_dir{L"C:\\WINDOWS"}; + memcpy(&kusd.NtSystemRoot.arr[0], root_dir.data(), root_dir.size() * 2); - kusd.ImageNumberLow = IMAGE_FILE_MACHINE_I386; - kusd.ImageNumberHigh = IMAGE_FILE_MACHINE_AMD64; - } + kusd.ImageNumberLow = IMAGE_FILE_MACHINE_I386; + kusd.ImageNumberHigh = IMAGE_FILE_MACHINE_AMD64; + } } namespace utils { - inline void serialize(buffer_serializer& buffer, const KUSER_SHARED_DATA64& kusd) - { - static_assert(KUSD_SIZE == sizeof(kusd)); - buffer.write(&kusd, KUSD_SIZE); - } + inline void serialize(buffer_serializer& buffer, const KUSER_SHARED_DATA64& kusd) + { + static_assert(KUSD_SIZE == sizeof(kusd)); + buffer.write(&kusd, KUSD_SIZE); + } - inline void deserialize(buffer_deserializer& buffer, KUSER_SHARED_DATA64& kusd) - { - buffer.read(&kusd, KUSD_SIZE); - } + inline void deserialize(buffer_deserializer& buffer, KUSER_SHARED_DATA64& kusd) + { + buffer.read(&kusd, KUSD_SIZE); + } } kusd_mmio::kusd_mmio(x64_emulator& emu, process_context& process) - : emu_(&emu) - , process_(&process) + : emu_(&emu), + process_(&process) { } kusd_mmio::~kusd_mmio() { - this->deregister_mmio(); + this->deregister_mmio(); } kusd_mmio::kusd_mmio(utils::buffer_deserializer& buffer) - : kusd_mmio(buffer.read(), buffer.read()) + : kusd_mmio(buffer.read(), buffer.read()) { } void kusd_mmio::setup(const bool use_relative_time) { - this->use_relative_time_ = use_relative_time; + this->use_relative_time_ = use_relative_time; - setup_kusd(this->kusd_, use_relative_time); - this->start_time_ = convert_from_ksystem_time(this->kusd_.SystemTime); + setup_kusd(this->kusd_, use_relative_time); + this->start_time_ = convert_from_ksystem_time(this->kusd_.SystemTime); - this->register_mmio(); + this->register_mmio(); } void kusd_mmio::serialize(utils::buffer_serializer& buffer) const { - buffer.write(this->use_relative_time_); - buffer.write(this->kusd_); - buffer.write(this->start_time_); + buffer.write(this->use_relative_time_); + buffer.write(this->kusd_); + buffer.write(this->start_time_); } void kusd_mmio::deserialize(utils::buffer_deserializer& buffer) { - buffer.read(this->use_relative_time_); - buffer.read(this->kusd_); - buffer.read(this->start_time_); + buffer.read(this->use_relative_time_); + buffer.read(this->kusd_); + buffer.read(this->start_time_); - this->deregister_mmio(); - this->register_mmio(); + this->deregister_mmio(); + this->register_mmio(); } uint64_t kusd_mmio::read(const uint64_t addr, const size_t size) { - uint64_t result{}; + uint64_t result{}; - this->update(); + this->update(); - if (addr >= KUSD_SIZE) - { - return result; - } + if (addr >= KUSD_SIZE) + { + return result; + } - const auto end = addr + size; - const auto valid_end = std::min(end, static_cast(KUSD_SIZE)); - const auto real_size = valid_end - addr; + const auto end = addr + size; + const auto valid_end = std::min(end, static_cast(KUSD_SIZE)); + const auto real_size = valid_end - addr; - if (real_size > sizeof(result)) - { - return result; - } + if (real_size > sizeof(result)) + { + return result; + } - const auto* kusd_buffer = reinterpret_cast(&this->kusd_); - memcpy(&result, kusd_buffer + addr, real_size); + const auto* kusd_buffer = reinterpret_cast(&this->kusd_); + memcpy(&result, kusd_buffer + addr, real_size); - return result; + return result; } uint64_t kusd_mmio::address() { - return KUSD_ADDRESS; + return KUSD_ADDRESS; } void kusd_mmio::update() { - auto time = this->start_time_; + auto time = this->start_time_; - if (this->use_relative_time_) - { - const auto passed_time = this->process_->executed_instructions; - const auto clock_frequency = static_cast(this->kusd_.QpcFrequency); + if (this->use_relative_time_) + { + const auto passed_time = this->process_->executed_instructions; + const auto clock_frequency = static_cast(this->kusd_.QpcFrequency); - using duration = std::chrono::system_clock::duration; - time += duration(passed_time * duration::period::den / clock_frequency); - } - else - { - time = std::chrono::system_clock::now(); - } + using duration = std::chrono::system_clock::duration; + time += duration(passed_time * duration::period::den / clock_frequency); + } + else + { + time = std::chrono::system_clock::now(); + } - convert_to_ksystem_time(&this->kusd_.SystemTime, time); + convert_to_ksystem_time(&this->kusd_.SystemTime, time); } void kusd_mmio::register_mmio() { - if (this->registered_) - { - return; - } + if (this->registered_) + { + return; + } - this->registered_ = true; + this->registered_ = true; - this->emu_->allocate_mmio(KUSD_ADDRESS, KUSD_BUFFER_SIZE, - [this](const uint64_t addr, const size_t size) - { - return this->read(addr, size); - }, [](const uint64_t, const size_t, const uint64_t) - { - // Writing not supported! - }); + this->emu_->allocate_mmio( + KUSD_ADDRESS, KUSD_BUFFER_SIZE, + [this](const uint64_t addr, const size_t size) { return this->read(addr, size); }, + [](const uint64_t, const size_t, const uint64_t) { + // Writing not supported! + }); } void kusd_mmio::deregister_mmio() { - if (this->registered_) - { - this->registered_ = false; - this->emu_->release_memory(KUSD_ADDRESS, KUSD_BUFFER_SIZE); - } + if (this->registered_) + { + this->registered_ = false; + this->emu_->release_memory(KUSD_ADDRESS, KUSD_BUFFER_SIZE); + } } diff --git a/src/windows-emulator/kusd_mmio.hpp b/src/windows-emulator/kusd_mmio.hpp index fc7c2adc..1399799f 100644 --- a/src/windows-emulator/kusd_mmio.hpp +++ b/src/windows-emulator/kusd_mmio.hpp @@ -10,48 +10,48 @@ class windows_emulator; class kusd_mmio { -public: - kusd_mmio(x64_emulator& emu, process_context& process); - ~kusd_mmio(); + public: + kusd_mmio(x64_emulator& emu, process_context& process); + ~kusd_mmio(); - kusd_mmio(utils::buffer_deserializer& buffer); + kusd_mmio(utils::buffer_deserializer& buffer); - kusd_mmio(kusd_mmio&&) = delete; - kusd_mmio(const kusd_mmio&) = delete; - kusd_mmio& operator=(kusd_mmio&& obj) = delete; - kusd_mmio& operator=(const kusd_mmio&) = delete; + kusd_mmio(kusd_mmio&&) = delete; + kusd_mmio(const kusd_mmio&) = delete; + kusd_mmio& operator=(kusd_mmio&& obj) = delete; + kusd_mmio& operator=(const kusd_mmio&) = delete; - void serialize(utils::buffer_serializer& buffer) const; - void deserialize(utils::buffer_deserializer& buffer); + void serialize(utils::buffer_serializer& buffer) const; + void deserialize(utils::buffer_deserializer& buffer); - KUSER_SHARED_DATA64& get() - { - return this->kusd_; - } + KUSER_SHARED_DATA64& get() + { + return this->kusd_; + } - const KUSER_SHARED_DATA64& get() const - { - return this->kusd_; - } + const KUSER_SHARED_DATA64& get() const + { + return this->kusd_; + } - static uint64_t address(); + static uint64_t address(); - void setup(bool use_relative_time); + void setup(bool use_relative_time); -private: - x64_emulator* emu_{}; - process_context* process_{}; + private: + x64_emulator* emu_{}; + process_context* process_{}; - bool registered_{}; - bool use_relative_time_{}; + bool registered_{}; + bool use_relative_time_{}; - KUSER_SHARED_DATA64 kusd_{}; - std::chrono::system_clock::time_point start_time_{}; + KUSER_SHARED_DATA64 kusd_{}; + std::chrono::system_clock::time_point start_time_{}; - uint64_t read(uint64_t addr, size_t size); + uint64_t read(uint64_t addr, size_t size); - void update(); + void update(); - void register_mmio(); - void deregister_mmio(); + void register_mmio(); + void deregister_mmio(); }; diff --git a/src/windows-emulator/logger.cpp b/src/windows-emulator/logger.cpp index b38e94de..80c8247f 100644 --- a/src/windows-emulator/logger.cpp +++ b/src/windows-emulator/logger.cpp @@ -7,130 +7,141 @@ namespace { #ifdef _WIN32 #define COLOR(win, posix) win - using color_type = WORD; + using color_type = WORD; #else #define COLOR(win, posix) posix - using color_type = const char*; + using color_type = const char*; #endif - color_type get_reset_color() - { - return COLOR(7, "\033[0m"); - } + color_type get_reset_color() + { + return COLOR(7, "\033[0m"); + } - color_type get_color_type(const color c) - { - using enum color; + color_type get_color_type(const color c) + { + using enum color; - switch (c) - { - case black: return COLOR(0x8, "\033[0;90m"); - case red: return COLOR(0xC, "\033[0;91m"); - case green: return COLOR(0xA, "\033[0;92m"); - case yellow: return COLOR(0xE, "\033[0;93m"); - case blue: return COLOR(0x9, "\033[0;94m"); - case cyan: return COLOR(0xB, "\033[0;96m"); - case pink: return COLOR(0xD, "\033[0;95m"); - case white: return COLOR(0xF, "\033[0;97m"); - case dark_gray: return COLOR(0x8, "\033[0;97m"); - case gray: - default: return get_reset_color(); - } - } + switch (c) + { + case black: + return COLOR(0x8, "\033[0;90m"); + case red: + return COLOR(0xC, "\033[0;91m"); + case green: + return COLOR(0xA, "\033[0;92m"); + case yellow: + return COLOR(0xE, "\033[0;93m"); + case blue: + return COLOR(0x9, "\033[0;94m"); + case cyan: + return COLOR(0xB, "\033[0;96m"); + case pink: + return COLOR(0xD, "\033[0;95m"); + case white: + return COLOR(0xF, "\033[0;97m"); + case dark_gray: + return COLOR(0x8, "\033[0;97m"); + case gray: + default: + return get_reset_color(); + } + } #ifdef _WIN32 - HANDLE get_console_handle() - { - return GetStdHandle(STD_OUTPUT_HANDLE); - } + HANDLE get_console_handle() + { + return GetStdHandle(STD_OUTPUT_HANDLE); + } #endif - void set_color(const color_type color) - { + void set_color(const color_type color) + { #ifdef _WIN32 - SetConsoleTextAttribute(get_console_handle(), color); + SetConsoleTextAttribute(get_console_handle(), color); #else - printf("%s", color); + printf("%s", color); #endif - } + } - void reset_color() - { - (void)fflush(stdout); - set_color(get_reset_color()); - (void)fflush(stdout); - } + void reset_color() + { + (void)fflush(stdout); + set_color(get_reset_color()); + (void)fflush(stdout); + } - std::string_view format(va_list* ap, const char* message) - { - thread_local char buffer[0x1000]; + std::string_view format(va_list* ap, const char* message) + { + thread_local char buffer[0x1000]; #ifdef _WIN32 - const int count = _vsnprintf_s(buffer, sizeof(buffer), sizeof(buffer), message, *ap); + const int count = _vsnprintf_s(buffer, sizeof(buffer), sizeof(buffer), message, *ap); #else - const int count = vsnprintf(buffer, sizeof(buffer), message, *ap); + const int count = vsnprintf(buffer, sizeof(buffer), message, *ap); #endif - if (count < 0) return {}; - return {buffer, static_cast(count)}; - } + if (count < 0) + return {}; + return {buffer, static_cast(count)}; + } -#define format_to_string(msg, str)\ - va_list ap;\ - va_start(ap, msg);\ - const auto str = format(&ap, msg);\ - va_end(ap); +#define format_to_string(msg, str) \ + va_list ap; \ + va_start(ap, msg); \ + const auto str = format(&ap, msg); \ + va_end(ap); - void print_colored(const std::string_view& line, const color_type base_color) - { - const auto _ = utils::finally(&reset_color); - set_color(base_color); - (void)fwrite(line.data(), 1, line.size(), stdout); - } + void print_colored(const std::string_view& line, const color_type base_color) + { + const auto _ = utils::finally(&reset_color); + set_color(base_color); + (void)fwrite(line.data(), 1, line.size(), stdout); + } } void logger::print(const color c, const std::string_view message) const { - if (this->disable_output_) - { - return; - } + if (this->disable_output_) + { + return; + } - print_colored(message, get_color_type(c)); + print_colored(message, get_color_type(c)); } void logger::print(const color c, const char* message, ...) const { - format_to_string(message, data); - this->print(c, data); + format_to_string(message, data); + this->print(c, data); } void logger::info(const char* message, ...) const { - format_to_string(message, data); - this->print(color::cyan, data); + format_to_string(message, data); + this->print(color::cyan, data); } void logger::warn(const char* message, ...) const { - format_to_string(message, data); - this->print(color::yellow, data); + format_to_string(message, data); + this->print(color::yellow, data); } void logger::error(const char* message, ...) const { - format_to_string(message, data); - this->print(color::red, data); + format_to_string(message, data); + this->print(color::red, data); } void logger::success(const char* message, ...) const { - format_to_string(message, data); - this->print(color::green, data); + format_to_string(message, data); + this->print(color::green, data); } void logger::log(const char* message, ...) const { - format_to_string(message, data); - this->print(color::gray, data); + format_to_string(message, data); + this->print(color::gray, data); } diff --git a/src/windows-emulator/logger.hpp b/src/windows-emulator/logger.hpp index 734e1ef6..2e1c3af2 100644 --- a/src/windows-emulator/logger.hpp +++ b/src/windows-emulator/logger.hpp @@ -3,44 +3,44 @@ #ifdef OS_WINDOWS #define FORMAT_ATTRIBUTE(fmt_pos, var_pos) #else -#define FORMAT_ATTRIBUTE(fmt_pos, var_pos) __attribute__((format( printf, fmt_pos, var_pos))) +#define FORMAT_ATTRIBUTE(fmt_pos, var_pos) __attribute__((format(printf, fmt_pos, var_pos))) #endif enum class color { - black, - red, - green, - yellow, - blue, - cyan, - pink, - white, - gray, - dark_gray, + black, + red, + green, + yellow, + blue, + cyan, + pink, + white, + gray, + dark_gray, }; class logger { -public: - void print(color c, std::string_view message) const; - void print(color c, const char* message, ...) const FORMAT_ATTRIBUTE(3, 4); - void info(const char* message, ...) const FORMAT_ATTRIBUTE(2, 3); - void warn(const char* message, ...) const FORMAT_ATTRIBUTE(2, 3); - void error(const char* message, ...) const FORMAT_ATTRIBUTE(2, 3); - void success(const char* message, ...) const FORMAT_ATTRIBUTE(2, 3); - void log(const char* message, ...) const FORMAT_ATTRIBUTE(2, 3); + public: + void print(color c, std::string_view message) const; + void print(color c, const char* message, ...) const FORMAT_ATTRIBUTE(3, 4); + void info(const char* message, ...) const FORMAT_ATTRIBUTE(2, 3); + void warn(const char* message, ...) const FORMAT_ATTRIBUTE(2, 3); + void error(const char* message, ...) const FORMAT_ATTRIBUTE(2, 3); + void success(const char* message, ...) const FORMAT_ATTRIBUTE(2, 3); + void log(const char* message, ...) const FORMAT_ATTRIBUTE(2, 3); - void disable_output(const bool value) - { - this->disable_output_ = value; - } + void disable_output(const bool value) + { + this->disable_output_ = value; + } - bool is_output_disabled() const - { - return this->disable_output_; - } + bool is_output_disabled() const + { + return this->disable_output_; + } -private: - bool disable_output_{false}; + private: + bool disable_output_{false}; }; diff --git a/src/windows-emulator/memory_utils.hpp b/src/windows-emulator/memory_utils.hpp index 30d36851..70b1a1f8 100644 --- a/src/windows-emulator/memory_utils.hpp +++ b/src/windows-emulator/memory_utils.hpp @@ -5,69 +5,69 @@ inline std::string get_permission_string(const memory_permission permission) { - const bool has_exec = (permission & memory_permission::exec) != memory_permission::none; - const bool has_read = (permission & memory_permission::read) != memory_permission::none; - const bool has_write = (permission & memory_permission::write) != memory_permission::none; + const bool has_exec = (permission & memory_permission::exec) != memory_permission::none; + const bool has_read = (permission & memory_permission::read) != memory_permission::none; + const bool has_write = (permission & memory_permission::write) != memory_permission::none; - std::string res = {}; - res.reserve(3); + std::string res = {}; + res.reserve(3); - res.push_back(has_read ? 'r' : '-'); - res.push_back(has_write ? 'w' : '-'); - res.push_back(has_exec ? 'x' : '-'); + res.push_back(has_read ? 'r' : '-'); + res.push_back(has_write ? 'w' : '-'); + res.push_back(has_exec ? 'x' : '-'); - return res; + return res; } inline memory_permission map_nt_to_emulator_protection(uint32_t nt_protection) { - nt_protection &= ~static_cast(PAGE_GUARD); // TODO: Implement that + nt_protection &= ~static_cast(PAGE_GUARD); // TODO: Implement that - switch (nt_protection) - { - case PAGE_NOACCESS: - return memory_permission::none; - case PAGE_READONLY: - return memory_permission::read; - case PAGE_READWRITE: - case PAGE_WRITECOPY: - return memory_permission::read | memory_permission::write; - case PAGE_EXECUTE: - case PAGE_EXECUTE_READ: - return memory_permission::read | memory_permission::exec; - case PAGE_EXECUTE_READWRITE: - return memory_permission::all; - case PAGE_EXECUTE_WRITECOPY: - default: - throw std::runtime_error("Failed to map protection"); - } + switch (nt_protection) + { + case PAGE_NOACCESS: + return memory_permission::none; + case PAGE_READONLY: + return memory_permission::read; + case PAGE_READWRITE: + case PAGE_WRITECOPY: + return memory_permission::read | memory_permission::write; + case PAGE_EXECUTE: + case PAGE_EXECUTE_READ: + return memory_permission::read | memory_permission::exec; + case PAGE_EXECUTE_READWRITE: + return memory_permission::all; + case PAGE_EXECUTE_WRITECOPY: + default: + throw std::runtime_error("Failed to map protection"); + } } inline uint32_t map_emulator_to_nt_protection(const memory_permission permission) { - const bool has_exec = (permission & memory_permission::exec) != memory_permission::none; - const bool has_read = (permission & memory_permission::read) != memory_permission::none; - const bool has_write = (permission & memory_permission::write) != memory_permission::none; + const bool has_exec = (permission & memory_permission::exec) != memory_permission::none; + const bool has_read = (permission & memory_permission::read) != memory_permission::none; + const bool has_write = (permission & memory_permission::write) != memory_permission::none; - if (!has_read) - { - return PAGE_NOACCESS; - } + if (!has_read) + { + return PAGE_NOACCESS; + } - if (has_exec && has_write) - { - return PAGE_EXECUTE_READWRITE; - } + if (has_exec && has_write) + { + return PAGE_EXECUTE_READWRITE; + } - if (has_exec) - { - return PAGE_EXECUTE_READ; - } + if (has_exec) + { + return PAGE_EXECUTE_READ; + } - if (has_write) - { - return PAGE_READWRITE; - } + if (has_write) + { + return PAGE_READWRITE; + } - return PAGE_READONLY; + return PAGE_READONLY; } diff --git a/src/windows-emulator/module/mapped_module.hpp b/src/windows-emulator/module/mapped_module.hpp index cf2b91dd..29ff878f 100644 --- a/src/windows-emulator/module/mapped_module.hpp +++ b/src/windows-emulator/module/mapped_module.hpp @@ -3,10 +3,10 @@ struct exported_symbol { - std::string name{}; - uint64_t ordinal{}; - uint64_t rva{}; - uint64_t address{}; + std::string name{}; + uint64_t ordinal{}; + uint64_t rva{}; + uint64_t address{}; }; using exported_symbols = std::vector; @@ -14,39 +14,39 @@ using address_name_mapping = std::map; struct mapped_section { - std::string name{}; - basic_memory_region region{}; + std::string name{}; + basic_memory_region region{}; }; struct mapped_module { - std::string name{}; - std::filesystem::path path{}; + std::string name{}; + std::filesystem::path path{}; - uint64_t image_base{}; - uint64_t size_of_image{}; - uint64_t entry_point{}; + uint64_t image_base{}; + uint64_t size_of_image{}; + uint64_t entry_point{}; - exported_symbols exports{}; - address_name_mapping address_names{}; + exported_symbols exports{}; + address_name_mapping address_names{}; - std::vector sections{}; + std::vector sections{}; - bool is_within(const uint64_t address) const - { - return address >= this->image_base && address < (this->image_base + this->size_of_image); - } + bool is_within(const uint64_t address) const + { + return address >= this->image_base && address < (this->image_base + this->size_of_image); + } - uint64_t find_export(const std::string_view export_name) const - { - for (auto& symbol : this->exports) - { - if (symbol.name == export_name) - { - return symbol.address; - } - } + uint64_t find_export(const std::string_view export_name) const + { + for (auto& symbol : this->exports) + { + if (symbol.name == export_name) + { + return symbol.address; + } + } - return 0; - } + return 0; + } }; diff --git a/src/windows-emulator/module/module_manager.cpp b/src/windows-emulator/module/module_manager.cpp index 881be43e..71baf230 100644 --- a/src/windows-emulator/module/module_manager.cpp +++ b/src/windows-emulator/module/module_manager.cpp @@ -5,124 +5,124 @@ namespace { - std::filesystem::path canonicalize_module_path(const std::filesystem::path& file) - { - constexpr std::u16string_view nt_prefix = u"\\??\\"; - const auto wide_file = file.u16string(); + std::filesystem::path canonicalize_module_path(const std::filesystem::path& file) + { + constexpr std::u16string_view nt_prefix = u"\\??\\"; + const auto wide_file = file.u16string(); - if (!wide_file.starts_with(nt_prefix)) - { - return canonical(absolute(file)); - } + if (!wide_file.starts_with(nt_prefix)) + { + return canonical(absolute(file)); + } - return canonicalize_module_path(wide_file.substr(nt_prefix.size())); - } + return canonicalize_module_path(wide_file.substr(nt_prefix.size())); + } } namespace utils { - static void serialize(buffer_serializer& buffer, const exported_symbol& sym) - { - buffer.write(sym.name); - buffer.write(sym.ordinal); - buffer.write(sym.rva); - buffer.write(sym.address); - } + static void serialize(buffer_serializer& buffer, const exported_symbol& sym) + { + buffer.write(sym.name); + buffer.write(sym.ordinal); + buffer.write(sym.rva); + buffer.write(sym.address); + } - static void deserialize(buffer_deserializer& buffer, exported_symbol& sym) - { - buffer.read(sym.name); - buffer.read(sym.ordinal); - buffer.read(sym.rva); - buffer.read(sym.address); - } + static void deserialize(buffer_deserializer& buffer, exported_symbol& sym) + { + buffer.read(sym.name); + buffer.read(sym.ordinal); + buffer.read(sym.rva); + buffer.read(sym.address); + } - static void serialize(buffer_serializer& buffer, const mapped_module& mod) - { - buffer.write_string(mod.name); - buffer.write(mod.path.u16string()); + static void serialize(buffer_serializer& buffer, const mapped_module& mod) + { + buffer.write_string(mod.name); + buffer.write(mod.path.u16string()); - buffer.write(mod.image_base); - buffer.write(mod.size_of_image); - buffer.write(mod.entry_point); + buffer.write(mod.image_base); + buffer.write(mod.size_of_image); + buffer.write(mod.entry_point); - buffer.write_vector(mod.exports); - buffer.write_map(mod.address_names); - } + buffer.write_vector(mod.exports); + buffer.write_map(mod.address_names); + } - static void deserialize(buffer_deserializer& buffer, mapped_module& mod) - { - mod.name = buffer.read_string(); - mod.path = buffer.read_string(); + static void deserialize(buffer_deserializer& buffer, mapped_module& mod) + { + mod.name = buffer.read_string(); + mod.path = buffer.read_string(); - buffer.read(mod.image_base); - buffer.read(mod.size_of_image); - buffer.read(mod.entry_point); + buffer.read(mod.image_base); + buffer.read(mod.size_of_image); + buffer.read(mod.entry_point); - buffer.read_vector(mod.exports); - buffer.read_map(mod.address_names); - } + buffer.read_vector(mod.exports); + buffer.read_map(mod.address_names); + } } module_manager::module_manager(emulator& emu) - : emu_(&emu) + : emu_(&emu) { } mapped_module* module_manager::map_module(const std::filesystem::path& file, logger& logger) { - auto canonical_file = canonicalize_module_path(file); + auto canonical_file = canonicalize_module_path(file); - for (auto& mod : this->modules_) - { - if (mod.second.path == canonical_file) - { - return &mod.second; - } - } + for (auto& mod : this->modules_) + { + if (mod.second.path == canonical_file) + { + return &mod.second; + } + } - try - { - auto mod = map_module_from_file(*this->emu_, std::move(canonical_file)); + try + { + auto mod = map_module_from_file(*this->emu_, std::move(canonical_file)); - logger.log("Mapped %s at 0x%" PRIx64 "\n", mod.path.generic_string().c_str(), mod.image_base); + logger.log("Mapped %s at 0x%" PRIx64 "\n", mod.path.generic_string().c_str(), mod.image_base); - const auto image_base = mod.image_base; - const auto entry = this->modules_.try_emplace(image_base, std::move(mod)); - return &entry.first->second; - } - catch (const std::exception& e) - { - logger.error("Failed to map %s: %s\n", file.generic_string().c_str(), e.what()); - return nullptr; - } - catch (...) - { - logger.error("Failed to map %s: Unknown error\n", file.generic_string().c_str()); - return nullptr; - } + const auto image_base = mod.image_base; + const auto entry = this->modules_.try_emplace(image_base, std::move(mod)); + return &entry.first->second; + } + catch (const std::exception& e) + { + logger.error("Failed to map %s: %s\n", file.generic_string().c_str(), e.what()); + return nullptr; + } + catch (...) + { + logger.error("Failed to map %s: Unknown error\n", file.generic_string().c_str()); + return nullptr; + } } void module_manager::serialize(utils::buffer_serializer& buffer) const { - buffer.write_map(this->modules_); + buffer.write_map(this->modules_); } void module_manager::deserialize(utils::buffer_deserializer& buffer) { - buffer.read_map(this->modules_); + buffer.read_map(this->modules_); } bool module_manager::unmap(const uint64_t address) { - const auto mod = this->modules_.find(address); - if (mod == this->modules_.end()) - { - return false; - } + const auto mod = this->modules_.find(address); + if (mod == this->modules_.end()) + { + return false; + } - unmap_module(*this->emu_, mod->second); - this->modules_.erase(mod); + unmap_module(*this->emu_, mod->second); + this->modules_.erase(mod); - return true; + return true; } diff --git a/src/windows-emulator/module/module_manager.hpp b/src/windows-emulator/module/module_manager.hpp index 3f5fb255..5e9a3e21 100644 --- a/src/windows-emulator/module/module_manager.hpp +++ b/src/windows-emulator/module/module_manager.hpp @@ -6,58 +6,58 @@ class logger; class module_manager { -public: - module_manager(emulator& emu); + public: + module_manager(emulator& emu); - mapped_module* map_module(const std::filesystem::path& file, logger& logger); + mapped_module* map_module(const std::filesystem::path& file, logger& logger); - mapped_module* find_by_address(const uint64_t address) - { - const auto entry = this->get_module(address); - if (entry != this->modules_.end()) - { - return &entry->second; - } + mapped_module* find_by_address(const uint64_t address) + { + const auto entry = this->get_module(address); + if (entry != this->modules_.end()) + { + return &entry->second; + } - return nullptr; - } + return nullptr; + } - const char* find_name(const uint64_t address) - { - const auto* mod = this->find_by_address(address); - if (!mod) - { - return ""; - } + const char* find_name(const uint64_t address) + { + const auto* mod = this->find_by_address(address); + if (!mod) + { + return ""; + } - return mod->name.c_str(); - } + return mod->name.c_str(); + } - void serialize(utils::buffer_serializer& buffer) const; - void deserialize(utils::buffer_deserializer& buffer); + void serialize(utils::buffer_serializer& buffer) const; + void deserialize(utils::buffer_deserializer& buffer); - bool unmap(const uint64_t address); + bool unmap(const uint64_t address); -private: - emulator* emu_{}; + private: + emulator* emu_{}; - using module_map = std::map; - module_map modules_{}; + using module_map = std::map; + module_map modules_{}; - module_map::iterator get_module(const uint64_t address) - { - if (this->modules_.empty()) - { - return this->modules_.end(); - } + module_map::iterator get_module(const uint64_t address) + { + if (this->modules_.empty()) + { + return this->modules_.end(); + } - auto upper_bound = this->modules_.upper_bound(address); - if (upper_bound == this->modules_.begin()) - { - return this->modules_.end(); - } + auto upper_bound = this->modules_.upper_bound(address); + if (upper_bound == this->modules_.begin()) + { + return this->modules_.end(); + } - std::advance(upper_bound, -1); - return upper_bound; - } + std::advance(upper_bound, -1); + return upper_bound; + } }; diff --git a/src/windows-emulator/module/module_mapping.cpp b/src/windows-emulator/module/module_mapping.cpp index 8d1577b1..5e6af650 100644 --- a/src/windows-emulator/module/module_mapping.cpp +++ b/src/windows-emulator/module/module_mapping.cpp @@ -7,265 +7,259 @@ namespace { - uint64_t get_first_section_offset(const PENTHeaders_t& nt_headers, const uint64_t nt_headers_offset) - { - const uint8_t* nt_headers_addr = reinterpret_cast(&nt_headers); - size_t optional_header_offset = reinterpret_cast(&(nt_headers.OptionalHeader)) - reinterpret_cast< - uintptr_t>(&nt_headers); - size_t optional_header_size = nt_headers.FileHeader.SizeOfOptionalHeader; - const uint8_t* first_section_addr = nt_headers_addr + optional_header_offset + optional_header_size; + uint64_t get_first_section_offset(const PENTHeaders_t& nt_headers, const uint64_t nt_headers_offset) + { + const uint8_t* nt_headers_addr = reinterpret_cast(&nt_headers); + size_t optional_header_offset = + reinterpret_cast(&(nt_headers.OptionalHeader)) - reinterpret_cast(&nt_headers); + size_t optional_header_size = nt_headers.FileHeader.SizeOfOptionalHeader; + const uint8_t* first_section_addr = nt_headers_addr + optional_header_offset + optional_header_size; - const auto first_section_absolute = reinterpret_cast(first_section_addr); - const auto absolute_base = reinterpret_cast(&nt_headers); - return nt_headers_offset + (first_section_absolute - absolute_base); - } + const auto first_section_absolute = reinterpret_cast(first_section_addr); + const auto absolute_base = reinterpret_cast(&nt_headers); + return nt_headers_offset + (first_section_absolute - absolute_base); + } - std::vector read_mapped_memory(const emulator& emu, const mapped_module& binary) - { - std::vector memory{}; - memory.resize(binary.size_of_image); - emu.read_memory(binary.image_base, memory.data(), memory.size()); + std::vector read_mapped_memory(const emulator& emu, const mapped_module& binary) + { + std::vector memory{}; + memory.resize(binary.size_of_image); + emu.read_memory(binary.image_base, memory.data(), memory.size()); - return memory; - } + return memory; + } - void collect_exports(mapped_module& binary, const utils::safe_buffer_accessor buffer, - const PEOptionalHeader_t& optional_header) - { - auto& export_directory_entry = optional_header.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; - if (export_directory_entry.VirtualAddress == 0 || export_directory_entry.Size == 0) - { - return; - } + void collect_exports(mapped_module& binary, const utils::safe_buffer_accessor buffer, + const PEOptionalHeader_t& optional_header) + { + auto& export_directory_entry = optional_header.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; + if (export_directory_entry.VirtualAddress == 0 || export_directory_entry.Size == 0) + { + return; + } - const auto export_directory = buffer.as(export_directory_entry. - VirtualAddress).get(); + const auto export_directory = buffer.as(export_directory_entry.VirtualAddress).get(); - const auto names_count = export_directory.NumberOfNames; - //const auto function_count = export_directory.NumberOfFunctions; + const auto names_count = export_directory.NumberOfNames; + // const auto function_count = export_directory.NumberOfFunctions; - const auto names = buffer.as(export_directory.AddressOfNames); - const auto ordinals = buffer.as(export_directory.AddressOfNameOrdinals); - const auto functions = buffer.as(export_directory.AddressOfFunctions); + const auto names = buffer.as(export_directory.AddressOfNames); + const auto ordinals = buffer.as(export_directory.AddressOfNameOrdinals); + const auto functions = buffer.as(export_directory.AddressOfFunctions); - binary.exports.reserve(names_count); + binary.exports.reserve(names_count); - for (DWORD i = 0; i < names_count; i++) - { - const auto ordinal = ordinals.get(i); + for (DWORD i = 0; i < names_count; i++) + { + const auto ordinal = ordinals.get(i); - exported_symbol symbol{}; - symbol.ordinal = export_directory.Base + ordinal; - symbol.rva = functions.get(ordinal); - symbol.address = binary.image_base + symbol.rva; - symbol.name = buffer.as_string(names.get(i)); + exported_symbol symbol{}; + symbol.ordinal = export_directory.Base + ordinal; + symbol.rva = functions.get(ordinal); + symbol.address = binary.image_base + symbol.rva; + symbol.name = buffer.as_string(names.get(i)); - binary.exports.push_back(std::move(symbol)); - } + binary.exports.push_back(std::move(symbol)); + } - for (const auto& symbol : binary.exports) - { - binary.address_names.try_emplace(symbol.address, symbol.name); - } - } + for (const auto& symbol : binary.exports) + { + binary.address_names.try_emplace(symbol.address, symbol.name); + } + } - template - requires(std::is_integral_v) - void apply_relocation(const utils::safe_buffer_accessor buffer, const uint64_t offset, - const uint64_t delta) - { - const auto obj = buffer.as(offset); - const auto value = obj.get(); - const auto new_value = value + static_cast(delta); - obj.set(new_value); - } + template + requires(std::is_integral_v) + void apply_relocation(const utils::safe_buffer_accessor buffer, const uint64_t offset, + const uint64_t delta) + { + const auto obj = buffer.as(offset); + const auto value = obj.get(); + const auto new_value = value + static_cast(delta); + obj.set(new_value); + } - void apply_relocations(const mapped_module& binary, const utils::safe_buffer_accessor buffer, - const PEOptionalHeader_t& optional_header) - { - const auto delta = binary.image_base - optional_header.ImageBase; - if (delta == 0) - { - return; - } + void apply_relocations(const mapped_module& binary, const utils::safe_buffer_accessor buffer, + const PEOptionalHeader_t& optional_header) + { + const auto delta = binary.image_base - optional_header.ImageBase; + if (delta == 0) + { + return; + } - const auto directory = &optional_header.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; - if (directory->Size == 0) - { - return; - } + const auto directory = &optional_header.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; + if (directory->Size == 0) + { + return; + } - auto relocation_offset = directory->VirtualAddress; - const auto relocation_end = relocation_offset + directory->Size; + auto relocation_offset = directory->VirtualAddress; + const auto relocation_end = relocation_offset + directory->Size; - while (relocation_offset < relocation_end) - { - const auto relocation = buffer.as(relocation_offset).get(); + while (relocation_offset < relocation_end) + { + const auto relocation = buffer.as(relocation_offset).get(); - if (relocation.VirtualAddress <= 0 || relocation.SizeOfBlock <= sizeof(IMAGE_BASE_RELOCATION)) - { - break; - } + if (relocation.VirtualAddress <= 0 || relocation.SizeOfBlock <= sizeof(IMAGE_BASE_RELOCATION)) + { + break; + } - const auto data_size = relocation.SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION); - const auto entry_count = data_size / sizeof(uint16_t); + const auto data_size = relocation.SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION); + const auto entry_count = data_size / sizeof(uint16_t); - const auto entries = buffer.as(relocation_offset + sizeof(IMAGE_BASE_RELOCATION)); + const auto entries = buffer.as(relocation_offset + sizeof(IMAGE_BASE_RELOCATION)); - relocation_offset += relocation.SizeOfBlock; + relocation_offset += relocation.SizeOfBlock; - for (size_t i = 0; i < entry_count; ++i) - { - const auto entry = entries.get(i); + for (size_t i = 0; i < entry_count; ++i) + { + const auto entry = entries.get(i); - const int type = entry >> 12; - const auto offset = static_cast(entry & 0xfff); - const auto total_offset = relocation.VirtualAddress + offset; + const int type = entry >> 12; + const auto offset = static_cast(entry & 0xfff); + const auto total_offset = relocation.VirtualAddress + offset; - switch (type) - { - case IMAGE_REL_BASED_ABSOLUTE: - break; + switch (type) + { + case IMAGE_REL_BASED_ABSOLUTE: + break; - case IMAGE_REL_BASED_HIGHLOW: - apply_relocation(buffer, total_offset, delta); - break; + case IMAGE_REL_BASED_HIGHLOW: + apply_relocation(buffer, total_offset, delta); + break; - case IMAGE_REL_BASED_DIR64: - apply_relocation(buffer, total_offset, delta); - break; + case IMAGE_REL_BASED_DIR64: + apply_relocation(buffer, total_offset, delta); + break; - default: - throw std::runtime_error("Unknown relocation type: " + std::to_string(type)); - } - } - } - } + default: + throw std::runtime_error("Unknown relocation type: " + std::to_string(type)); + } + } + } + } - void map_sections(emulator& emu, mapped_module& binary, - const utils::safe_buffer_accessor buffer, - const PENTHeaders_t& nt_headers, const uint64_t nt_headers_offset) - { - const auto first_section_offset = get_first_section_offset(nt_headers, nt_headers_offset); - const auto sections = buffer.as(first_section_offset); + void map_sections(emulator& emu, mapped_module& binary, const utils::safe_buffer_accessor buffer, + const PENTHeaders_t& nt_headers, const uint64_t nt_headers_offset) + { + const auto first_section_offset = get_first_section_offset(nt_headers, nt_headers_offset); + const auto sections = buffer.as(first_section_offset); - for (size_t i = 0; i < nt_headers.FileHeader.NumberOfSections; ++i) - { - const auto section = sections.get(i); - const auto target_ptr = binary.image_base + section.VirtualAddress; + for (size_t i = 0; i < nt_headers.FileHeader.NumberOfSections; ++i) + { + const auto section = sections.get(i); + const auto target_ptr = binary.image_base + section.VirtualAddress; - if (section.SizeOfRawData > 0) - { - const auto size_of_data = std::min(section.SizeOfRawData, section.Misc.VirtualSize); - const auto* source_ptr = buffer.get_pointer_for_range(section.PointerToRawData, size_of_data); - emu.write_memory(target_ptr, source_ptr, size_of_data); - } + if (section.SizeOfRawData > 0) + { + const auto size_of_data = std::min(section.SizeOfRawData, section.Misc.VirtualSize); + const auto* source_ptr = buffer.get_pointer_for_range(section.PointerToRawData, size_of_data); + emu.write_memory(target_ptr, source_ptr, size_of_data); + } - auto permissions = memory_permission::none; + auto permissions = memory_permission::none; - if (section.Characteristics & IMAGE_SCN_MEM_EXECUTE) - { - permissions |= memory_permission::exec; - } + if (section.Characteristics & IMAGE_SCN_MEM_EXECUTE) + { + permissions |= memory_permission::exec; + } - if (section.Characteristics & IMAGE_SCN_MEM_READ) - { - permissions |= memory_permission::read; - } + if (section.Characteristics & IMAGE_SCN_MEM_READ) + { + permissions |= memory_permission::read; + } - if (section.Characteristics & IMAGE_SCN_MEM_WRITE) - { - permissions |= memory_permission::write; - } + if (section.Characteristics & IMAGE_SCN_MEM_WRITE) + { + permissions |= memory_permission::write; + } - const auto size_of_section = page_align_up(std::max(section.SizeOfRawData, section.Misc.VirtualSize)); + const auto size_of_section = page_align_up(std::max(section.SizeOfRawData, section.Misc.VirtualSize)); - emu.protect_memory(target_ptr, size_of_section, permissions, nullptr); + emu.protect_memory(target_ptr, size_of_section, permissions, nullptr); - mapped_section section_info{}; - section_info.region.start = target_ptr; - section_info.region.length = size_of_section; - section_info.region.permissions = permissions; + mapped_section section_info{}; + section_info.region.start = target_ptr; + section_info.region.length = size_of_section; + section_info.region.permissions = permissions; - for (size_t j = 0; j < sizeof(section.Name) && section.Name[j]; ++j) - { - section_info.name.push_back(static_cast(section.Name[j])); - } + for (size_t j = 0; j < sizeof(section.Name) && section.Name[j]; ++j) + { + section_info.name.push_back(static_cast(section.Name[j])); + } - binary.sections.push_back(std::move(section_info)); - } - } + binary.sections.push_back(std::move(section_info)); + } + } } -mapped_module map_module_from_data(emulator& emu, const std::span data, - std::filesystem::path file) +mapped_module map_module_from_data(emulator& emu, const std::span data, std::filesystem::path file) { - mapped_module binary{}; - binary.path = std::move(file); - binary.name = binary.path.filename().string(); + mapped_module binary{}; + binary.path = std::move(file); + binary.name = binary.path.filename().string(); - utils::safe_buffer_accessor buffer{data}; + utils::safe_buffer_accessor buffer{data}; - const auto dos_header = buffer.as(0).get(); - const auto nt_headers_offset = dos_header.e_lfanew; + const auto dos_header = buffer.as(0).get(); + const auto nt_headers_offset = dos_header.e_lfanew; - const auto nt_headers = buffer.as>(nt_headers_offset).get(); - auto& optional_header = nt_headers.OptionalHeader; + const auto nt_headers = buffer.as>(nt_headers_offset).get(); + auto& optional_header = nt_headers.OptionalHeader; - if (nt_headers.FileHeader.Machine != PEMachineType::AMD64) - { - throw std::runtime_error("Unsupported architecture!"); - } + if (nt_headers.FileHeader.Machine != PEMachineType::AMD64) + { + throw std::runtime_error("Unsupported architecture!"); + } - binary.image_base = optional_header.ImageBase; - binary.size_of_image = page_align_up(optional_header.SizeOfImage); // TODO: Sanitize + binary.image_base = optional_header.ImageBase; + binary.size_of_image = page_align_up(optional_header.SizeOfImage); // TODO: Sanitize - if (!emu.allocate_memory(binary.image_base, binary.size_of_image, memory_permission::read)) - { - binary.image_base = emu.find_free_allocation_base(binary.size_of_image); - const auto is_dll = nt_headers.FileHeader.Characteristics & IMAGE_FILE_DLL; - const auto has_dynamic_base = - optional_header.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE; - const auto is_relocatable = is_dll || has_dynamic_base; + if (!emu.allocate_memory(binary.image_base, binary.size_of_image, memory_permission::read)) + { + binary.image_base = emu.find_free_allocation_base(binary.size_of_image); + const auto is_dll = nt_headers.FileHeader.Characteristics & IMAGE_FILE_DLL; + const auto has_dynamic_base = optional_header.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE; + const auto is_relocatable = is_dll || has_dynamic_base; - if (!is_relocatable || !emu.allocate_memory(binary.image_base, binary.size_of_image, - memory_permission::read)) - { - throw std::runtime_error("Memory range not allocatable"); - } - } + if (!is_relocatable || !emu.allocate_memory(binary.image_base, binary.size_of_image, memory_permission::read)) + { + throw std::runtime_error("Memory range not allocatable"); + } + } - binary.entry_point = binary.image_base + optional_header.AddressOfEntryPoint; + binary.entry_point = binary.image_base + optional_header.AddressOfEntryPoint; - const auto* header_buffer = buffer.get_pointer_for_range(0, optional_header.SizeOfHeaders); - emu.write_memory(binary.image_base, header_buffer, - optional_header.SizeOfHeaders); + const auto* header_buffer = buffer.get_pointer_for_range(0, optional_header.SizeOfHeaders); + emu.write_memory(binary.image_base, header_buffer, optional_header.SizeOfHeaders); - map_sections(emu, binary, buffer, nt_headers, nt_headers_offset); + map_sections(emu, binary, buffer, nt_headers, nt_headers_offset); - auto mapped_memory = read_mapped_memory(emu, binary); - utils::safe_buffer_accessor mapped_buffer{mapped_memory}; + auto mapped_memory = read_mapped_memory(emu, binary); + utils::safe_buffer_accessor mapped_buffer{mapped_memory}; - apply_relocations(binary, mapped_buffer, optional_header); - collect_exports(binary, mapped_buffer, optional_header); + apply_relocations(binary, mapped_buffer, optional_header); + collect_exports(binary, mapped_buffer, optional_header); - emu.write_memory(binary.image_base, mapped_memory.data(), mapped_memory.size()); + emu.write_memory(binary.image_base, mapped_memory.data(), mapped_memory.size()); - return binary; + return binary; } mapped_module map_module_from_file(emulator& emu, std::filesystem::path file) { - const auto data = utils::io::read_file(file); - if (data.empty()) - { - throw std::runtime_error("Bad file data"); - } + const auto data = utils::io::read_file(file); + if (data.empty()) + { + throw std::runtime_error("Bad file data"); + } - return map_module_from_data(emu, data, std::move(file)); + return map_module_from_data(emu, data, std::move(file)); } bool unmap_module(emulator& emu, const mapped_module& mod) { - return emu.release_memory(mod.image_base, mod.size_of_image); + return emu.release_memory(mod.image_base, mod.size_of_image); } diff --git a/src/windows-emulator/module/module_mapping.hpp b/src/windows-emulator/module/module_mapping.hpp index f0802b4c..de93d6c7 100644 --- a/src/windows-emulator/module/module_mapping.hpp +++ b/src/windows-emulator/module/module_mapping.hpp @@ -3,8 +3,7 @@ #include #include "mapped_module.hpp" -mapped_module map_module_from_data(emulator& emu, std::span data, - std::filesystem::path file); +mapped_module map_module_from_data(emulator& emu, std::span data, std::filesystem::path file); mapped_module map_module_from_file(emulator& emu, std::filesystem::path file); bool unmap_module(emulator& emu, const mapped_module& mod); diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index eb6cbbe2..2bf037a2 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -15,630 +15,630 @@ #include "kusd_mmio.hpp" #define PEB_SEGMENT_SIZE (20 << 20) // 20 MB -#define GS_SEGMENT_SIZE (1 << 20) // 1 MB +#define GS_SEGMENT_SIZE (1 << 20) // 1 MB #define IA32_GS_BASE_MSR 0xC0000101 -#define STACK_SIZE 0x40000ULL +#define STACK_SIZE 0x40000ULL -#define GDT_ADDR 0x30000 -#define GDT_LIMIT 0x1000 -#define GDT_ENTRY_SIZE 0x8 +#define GDT_ADDR 0x30000 +#define GDT_LIMIT 0x1000 +#define GDT_ENTRY_SIZE 0x8 class windows_emulator; struct ref_counted_object { - uint32_t ref_count{1}; + uint32_t ref_count{1}; - void serialize(utils::buffer_serializer& buffer) const - { - buffer.write(this->ref_count); - } + void serialize(utils::buffer_serializer& buffer) const + { + buffer.write(this->ref_count); + } - void deserialize(utils::buffer_deserializer& buffer) - { - buffer.read(this->ref_count); - } + void deserialize(utils::buffer_deserializer& buffer) + { + buffer.read(this->ref_count); + } - static bool deleter(ref_counted_object& e) - { - return --e.ref_count == 0; - } + static bool deleter(ref_counted_object& e) + { + return --e.ref_count == 0; + } }; struct event : ref_counted_object { - bool signaled{}; - EVENT_TYPE type{}; - std::u16string name{}; + bool signaled{}; + EVENT_TYPE type{}; + std::u16string name{}; - bool is_signaled() - { - const auto res = this->signaled; + bool is_signaled() + { + const auto res = this->signaled; - if (this->type == SynchronizationEvent) - { - this->signaled = false; - } + if (this->type == SynchronizationEvent) + { + this->signaled = false; + } - return res; - } + return res; + } - void serialize(utils::buffer_serializer& buffer) const - { - buffer.write(this->signaled); - buffer.write(this->type); - buffer.write(this->name); + void serialize(utils::buffer_serializer& buffer) const + { + buffer.write(this->signaled); + buffer.write(this->type); + buffer.write(this->name); - ref_counted_object::serialize(buffer); - } + ref_counted_object::serialize(buffer); + } - void deserialize(utils::buffer_deserializer& buffer) - { - buffer.read(this->signaled); - buffer.read(this->type); - buffer.read(this->name); + void deserialize(utils::buffer_deserializer& buffer) + { + buffer.read(this->signaled); + buffer.read(this->type); + buffer.read(this->name); - ref_counted_object::deserialize(buffer); - } + ref_counted_object::deserialize(buffer); + } }; struct mutant : ref_counted_object { - uint32_t locked_count{0}; - uint32_t owning_thread_id{}; - std::u16string name{}; + uint32_t locked_count{0}; + uint32_t owning_thread_id{}; + std::u16string name{}; - bool try_lock(const uint32_t thread_id) - { - if (this->locked_count == 0) - { - ++this->locked_count; - this->owning_thread_id = thread_id; - return true; - } + bool try_lock(const uint32_t thread_id) + { + if (this->locked_count == 0) + { + ++this->locked_count; + this->owning_thread_id = thread_id; + return true; + } - if (this->owning_thread_id != thread_id) - { - return false; - } + if (this->owning_thread_id != thread_id) + { + return false; + } - ++this->locked_count; - return true; - } + ++this->locked_count; + return true; + } - uint32_t release() - { - const auto old_count = this->locked_count; + uint32_t release() + { + const auto old_count = this->locked_count; - if (this->locked_count <= 0) - { - return old_count; - } + if (this->locked_count <= 0) + { + return old_count; + } - --this->locked_count; - return old_count; - } + --this->locked_count; + return old_count; + } - void serialize(utils::buffer_serializer& buffer) const - { - buffer.write(this->locked_count); - buffer.write(this->owning_thread_id); - buffer.write(this->name); + void serialize(utils::buffer_serializer& buffer) const + { + buffer.write(this->locked_count); + buffer.write(this->owning_thread_id); + buffer.write(this->name); - ref_counted_object::serialize(buffer); - } + ref_counted_object::serialize(buffer); + } - void deserialize(utils::buffer_deserializer& buffer) - { - buffer.read(this->locked_count); - buffer.read(this->owning_thread_id); - buffer.read(this->name); + void deserialize(utils::buffer_deserializer& buffer) + { + buffer.read(this->locked_count); + buffer.read(this->owning_thread_id); + buffer.read(this->name); - ref_counted_object::deserialize(buffer); - } + ref_counted_object::deserialize(buffer); + } }; struct file_entry { - std::filesystem::path file_path{}; + std::filesystem::path file_path{}; - void serialize(utils::buffer_serializer& buffer) const - { - buffer.write(this->file_path); - } + void serialize(utils::buffer_serializer& buffer) const + { + buffer.write(this->file_path); + } - void deserialize(utils::buffer_deserializer& buffer) - { - buffer.read(this->file_path); - } + void deserialize(utils::buffer_deserializer& buffer) + { + buffer.read(this->file_path); + } }; struct file_enumeration_state { - size_t current_index{0}; - std::vector files{}; + size_t current_index{0}; + std::vector files{}; - void serialize(utils::buffer_serializer& buffer) const - { - buffer.write(this->current_index); - buffer.write_vector(this->files); - } + void serialize(utils::buffer_serializer& buffer) const + { + buffer.write(this->current_index); + buffer.write_vector(this->files); + } - void deserialize(utils::buffer_deserializer& buffer) - { - buffer.read(this->current_index); - buffer.read_vector(this->files); - } + void deserialize(utils::buffer_deserializer& buffer) + { + buffer.read(this->current_index); + buffer.read_vector(this->files); + } }; struct file { - utils::file_handle handle{}; - std::u16string name{}; - std::optional enumeration_state{}; + utils::file_handle handle{}; + std::u16string name{}; + std::optional enumeration_state{}; - bool is_file() const - { - return this->handle; - } + bool is_file() const + { + return this->handle; + } - bool is_directory() const - { - return !this->is_file(); - } + bool is_directory() const + { + return !this->is_file(); + } - void serialize(utils::buffer_serializer& buffer) const - { - // TODO: Serialize handle - buffer.write(this->name); - buffer.write_optional(this->enumeration_state); - } + void serialize(utils::buffer_serializer& buffer) const + { + // TODO: Serialize handle + buffer.write(this->name); + buffer.write_optional(this->enumeration_state); + } - void deserialize(utils::buffer_deserializer& buffer) - { - buffer.read(this->name); - buffer.read_optional(this->enumeration_state); - this->handle = {}; - } + void deserialize(utils::buffer_deserializer& buffer) + { + buffer.read(this->name); + buffer.read_optional(this->enumeration_state); + this->handle = {}; + } }; struct section { - std::u16string name{}; - std::u16string file_name{}; - uint64_t maximum_size{}; - uint32_t section_page_protection{}; - uint32_t allocation_attributes{}; + std::u16string name{}; + std::u16string file_name{}; + uint64_t maximum_size{}; + uint32_t section_page_protection{}; + uint32_t allocation_attributes{}; - bool is_image() const - { - return this->allocation_attributes & SEC_IMAGE; - } + bool is_image() const + { + return this->allocation_attributes & SEC_IMAGE; + } - void serialize(utils::buffer_serializer& buffer) const - { - buffer.write(this->name); - buffer.write(this->file_name); - buffer.write(this->maximum_size); - buffer.write(this->section_page_protection); - buffer.write(this->allocation_attributes); - } + void serialize(utils::buffer_serializer& buffer) const + { + buffer.write(this->name); + buffer.write(this->file_name); + buffer.write(this->maximum_size); + buffer.write(this->section_page_protection); + buffer.write(this->allocation_attributes); + } - void deserialize(utils::buffer_deserializer& buffer) - { - buffer.read(this->name); - buffer.read(this->file_name); - buffer.read(this->maximum_size); - buffer.read(this->section_page_protection); - buffer.read(this->allocation_attributes); - } + void deserialize(utils::buffer_deserializer& buffer) + { + buffer.read(this->name); + buffer.read(this->file_name); + buffer.read(this->maximum_size); + buffer.read(this->section_page_protection); + buffer.read(this->allocation_attributes); + } }; struct semaphore : ref_counted_object { - std::u16string name{}; - volatile uint32_t current_count{}; - uint32_t max_count{}; + std::u16string name{}; + volatile uint32_t current_count{}; + uint32_t max_count{}; - void serialize(utils::buffer_serializer& buffer) const - { - buffer.write(this->name); - buffer.write(this->current_count); - buffer.write(this->max_count); + void serialize(utils::buffer_serializer& buffer) const + { + buffer.write(this->name); + buffer.write(this->current_count); + buffer.write(this->max_count); - ref_counted_object::serialize(buffer); - } + ref_counted_object::serialize(buffer); + } - void deserialize(utils::buffer_deserializer& buffer) - { - buffer.read(this->name); - buffer.read(this->current_count); - buffer.read(this->max_count); + void deserialize(utils::buffer_deserializer& buffer) + { + buffer.read(this->name); + buffer.read(this->current_count); + buffer.read(this->max_count); - ref_counted_object::deserialize(buffer); - } + ref_counted_object::deserialize(buffer); + } }; struct port { - std::u16string name{}; - uint64_t view_base{}; + std::u16string name{}; + uint64_t view_base{}; - void serialize(utils::buffer_serializer& buffer) const - { - buffer.write(this->name); - buffer.write(this->view_base); - } + void serialize(utils::buffer_serializer& buffer) const + { + buffer.write(this->name); + buffer.write(this->view_base); + } - void deserialize(utils::buffer_deserializer& buffer) - { - buffer.read(this->name); - buffer.read(this->view_base); - } + void deserialize(utils::buffer_deserializer& buffer) + { + buffer.read(this->name); + buffer.read(this->view_base); + } }; struct process_context; class moved_marker { -public: - moved_marker() = default; + public: + moved_marker() = default; - moved_marker(const moved_marker& copy) = default; - moved_marker& operator=(const moved_marker&) = default; + moved_marker(const moved_marker& copy) = default; + moved_marker& operator=(const moved_marker&) = default; - moved_marker(moved_marker&& obj) noexcept - : moved_marker() - { - this->operator=(std::move(obj)); - } + moved_marker(moved_marker&& obj) noexcept + : moved_marker() + { + this->operator=(std::move(obj)); + } - moved_marker& operator=(moved_marker&& obj) noexcept - { - if (this != &obj) - { - this->was_moved_ = obj.was_moved_; - obj.was_moved_ = true; - } + moved_marker& operator=(moved_marker&& obj) noexcept + { + if (this != &obj) + { + this->was_moved_ = obj.was_moved_; + obj.was_moved_ = true; + } - return *this; - } + return *this; + } - ~moved_marker() = default; + ~moved_marker() = default; - bool was_moved() const - { - return this->was_moved_; - } + bool was_moved() const + { + return this->was_moved_; + } -private: - bool was_moved_{false}; + private: + bool was_moved_{false}; }; class emulator_thread : ref_counted_object { -public: - emulator_thread(x64_emulator& emu) - : emu_ptr(&emu) - { - } + public: + emulator_thread(x64_emulator& emu) + : emu_ptr(&emu) + { + } - emulator_thread(utils::buffer_deserializer& buffer) - : emulator_thread(buffer.read().get()) - { - } + emulator_thread(utils::buffer_deserializer& buffer) + : emulator_thread(buffer.read().get()) + { + } - emulator_thread(x64_emulator& emu, const process_context& context, uint64_t start_address, uint64_t argument, - uint64_t stack_size, uint32_t id); + emulator_thread(x64_emulator& emu, const process_context& context, uint64_t start_address, uint64_t argument, + uint64_t stack_size, uint32_t id); - emulator_thread(const emulator_thread&) = delete; - emulator_thread& operator=(const emulator_thread&) = delete; + emulator_thread(const emulator_thread&) = delete; + emulator_thread& operator=(const emulator_thread&) = delete; - emulator_thread(emulator_thread&& obj) noexcept = default; - emulator_thread& operator=(emulator_thread&& obj) noexcept = default; + emulator_thread(emulator_thread&& obj) noexcept = default; + emulator_thread& operator=(emulator_thread&& obj) noexcept = default; - ~emulator_thread() - { - this->release(); - } + ~emulator_thread() + { + this->release(); + } - moved_marker marker{}; + moved_marker marker{}; - x64_emulator* emu_ptr{}; + x64_emulator* emu_ptr{}; - uint64_t stack_base{}; - uint64_t stack_size{}; - uint64_t start_address{}; - uint64_t argument{}; - uint64_t executed_instructions{0}; + uint64_t stack_base{}; + uint64_t stack_size{}; + uint64_t start_address{}; + uint64_t argument{}; + uint64_t executed_instructions{0}; - uint32_t id{}; + uint32_t id{}; - std::u16string name{}; + std::u16string name{}; - std::optional exit_status{}; - std::vector await_objects{}; - bool await_any{false}; - bool waiting_for_alert{false}; - bool alerted{false}; - std::optional await_time{}; + std::optional exit_status{}; + std::vector await_objects{}; + bool await_any{false}; + bool waiting_for_alert{false}; + bool alerted{false}; + std::optional await_time{}; - std::optional pending_status{}; + std::optional pending_status{}; - std::optional gs_segment; - std::optional> teb; + std::optional gs_segment; + std::optional> teb; - std::vector last_registers{}; + std::vector last_registers{}; - void mark_as_ready(NTSTATUS status); + void mark_as_ready(NTSTATUS status); - bool is_await_time_over() const - { - return this->await_time.has_value() && this->await_time.value() < std::chrono::steady_clock::now(); - } + bool is_await_time_over() const + { + return this->await_time.has_value() && this->await_time.value() < std::chrono::steady_clock::now(); + } - bool is_thread_ready(windows_emulator& win_emu); + bool is_thread_ready(windows_emulator& win_emu); - void save(x64_emulator& emu) - { - this->last_registers = emu.save_registers(); - } + void save(x64_emulator& emu) + { + this->last_registers = emu.save_registers(); + } - void restore(x64_emulator& emu) const - { - emu.restore_registers(this->last_registers); - } + void restore(x64_emulator& emu) const + { + emu.restore_registers(this->last_registers); + } - void setup_if_necessary(x64_emulator& emu, const process_context& context) - { - if (!this->executed_instructions) - { - this->setup_registers(emu, context); - } + void setup_if_necessary(x64_emulator& emu, const process_context& context) + { + if (!this->executed_instructions) + { + this->setup_registers(emu, context); + } - if (this->pending_status.has_value()) - { - const auto status = *this->pending_status; - this->pending_status = {}; + if (this->pending_status.has_value()) + { + const auto status = *this->pending_status; + this->pending_status = {}; - emu.reg(x64_register::rax, static_cast(status)); - } - } + emu.reg(x64_register::rax, static_cast(status)); + } + } - void serialize(utils::buffer_serializer& buffer) const - { - if (this->marker.was_moved()) - { - throw std::runtime_error("Object was moved!"); - } + void serialize(utils::buffer_serializer& buffer) const + { + if (this->marker.was_moved()) + { + throw std::runtime_error("Object was moved!"); + } - buffer.write(this->stack_base); - buffer.write(this->stack_size); - buffer.write(this->start_address); - buffer.write(this->argument); - buffer.write(this->executed_instructions); - buffer.write(this->id); + buffer.write(this->stack_base); + buffer.write(this->stack_size); + buffer.write(this->start_address); + buffer.write(this->argument); + buffer.write(this->executed_instructions); + buffer.write(this->id); - buffer.write_string(this->name); + buffer.write_string(this->name); - buffer.write_optional(this->exit_status); - buffer.write_vector(this->await_objects); - buffer.write(this->await_any); + buffer.write_optional(this->exit_status); + buffer.write_vector(this->await_objects); + buffer.write(this->await_any); - buffer.write(this->waiting_for_alert); - buffer.write(this->alerted); + buffer.write(this->waiting_for_alert); + buffer.write(this->alerted); - buffer.write_optional(this->await_time); - buffer.write_optional(this->pending_status); - buffer.write_optional(this->gs_segment); - buffer.write_optional(this->teb); + buffer.write_optional(this->await_time); + buffer.write_optional(this->pending_status); + buffer.write_optional(this->gs_segment); + buffer.write_optional(this->teb); - buffer.write_vector(this->last_registers); - } + buffer.write_vector(this->last_registers); + } - void deserialize(utils::buffer_deserializer& buffer) - { - if (this->marker.was_moved()) - { - throw std::runtime_error("Object was moved!"); - } + void deserialize(utils::buffer_deserializer& buffer) + { + if (this->marker.was_moved()) + { + throw std::runtime_error("Object was moved!"); + } - this->release(); + this->release(); - buffer.read(this->stack_base); - buffer.read(this->stack_size); - buffer.read(this->start_address); - buffer.read(this->argument); - buffer.read(this->executed_instructions); - buffer.read(this->id); + buffer.read(this->stack_base); + buffer.read(this->stack_size); + buffer.read(this->start_address); + buffer.read(this->argument); + buffer.read(this->executed_instructions); + buffer.read(this->id); - buffer.read_string(this->name); + buffer.read_string(this->name); - buffer.read_optional(this->exit_status); - buffer.read_vector(this->await_objects); - buffer.read(this->await_any); + buffer.read_optional(this->exit_status); + buffer.read_vector(this->await_objects); + buffer.read(this->await_any); - buffer.read(this->waiting_for_alert); - buffer.read(this->alerted); + buffer.read(this->waiting_for_alert); + buffer.read(this->alerted); - buffer.read_optional(this->await_time); - buffer.read_optional(this->pending_status); - buffer.read_optional(this->gs_segment, [this] { return emulator_allocator(*this->emu_ptr); }); - buffer.read_optional(this->teb, [this] { return emulator_object(*this->emu_ptr); }); + buffer.read_optional(this->await_time); + buffer.read_optional(this->pending_status); + buffer.read_optional(this->gs_segment, [this] { return emulator_allocator(*this->emu_ptr); }); + buffer.read_optional(this->teb, [this] { return emulator_object(*this->emu_ptr); }); - buffer.read_vector(this->last_registers); - } + buffer.read_vector(this->last_registers); + } -private: - void setup_registers(x64_emulator& emu, const process_context& context) const; + private: + void setup_registers(x64_emulator& emu, const process_context& context) const; - void release() - { - if (this->marker.was_moved()) - { - return; - } + void release() + { + if (this->marker.was_moved()) + { + return; + } - if (this->stack_base) - { - if (!this->emu_ptr) - { - throw std::runtime_error("Emulator was never assigned!"); - } + if (this->stack_base) + { + if (!this->emu_ptr) + { + throw std::runtime_error("Emulator was never assigned!"); + } - this->emu_ptr->release_memory(this->stack_base, this->stack_size); - this->stack_base = 0; - } + this->emu_ptr->release_memory(this->stack_base, this->stack_size); + this->stack_base = 0; + } - if (this->gs_segment) - { - this->gs_segment->release(); - this->gs_segment = {}; - } - } + if (this->gs_segment) + { + this->gs_segment->release(); + this->gs_segment = {}; + } + } }; struct process_context { - process_context(x64_emulator& emu) - : base_allocator(emu) - , peb(emu) - , process_params(emu) - , kusd(emu, *this) - , mod_manager(emu) - { - } + process_context(x64_emulator& emu) + : base_allocator(emu), + peb(emu), + process_params(emu), + kusd(emu, *this), + mod_manager(emu) + { + } - registry_manager registry{}; + registry_manager registry{}; - uint64_t executed_instructions{0}; - uint64_t current_ip{0}; - uint64_t previous_ip{0}; + uint64_t executed_instructions{0}; + uint64_t current_ip{0}; + uint64_t previous_ip{0}; - std::optional exception_rip{}; - std::optional exit_status{}; + std::optional exception_rip{}; + std::optional exit_status{}; - emulator_allocator base_allocator; + emulator_allocator base_allocator; - emulator_object peb; - emulator_object process_params; - kusd_mmio kusd; + emulator_object peb; + emulator_object process_params; + kusd_mmio kusd; - module_manager mod_manager; + module_manager mod_manager; - mapped_module* executable{}; - mapped_module* ntdll{}; - mapped_module* win32u{}; + mapped_module* executable{}; + mapped_module* ntdll{}; + mapped_module* win32u{}; - uint64_t ldr_initialize_thunk{}; - uint64_t rtl_user_thread_start{}; - uint64_t ki_user_exception_dispatcher{}; + uint64_t ldr_initialize_thunk{}; + uint64_t rtl_user_thread_start{}; + uint64_t ki_user_exception_dispatcher{}; - handle_store events{}; - handle_store files{}; - handle_store sections{}; - handle_store devices{}; - handle_store semaphores{}; - handle_store ports{}; - handle_store mutants{}; - handle_store registry_keys{}; - std::map atoms{}; + handle_store events{}; + handle_store files{}; + handle_store sections{}; + handle_store devices{}; + handle_store semaphores{}; + handle_store ports{}; + handle_store mutants{}; + handle_store registry_keys{}; + std::map atoms{}; - std::vector default_register_set{}; + std::vector default_register_set{}; - uint32_t current_thread_id{0}; - handle_store threads{}; - emulator_thread* active_thread{nullptr}; + uint32_t current_thread_id{0}; + handle_store threads{}; + emulator_thread* active_thread{nullptr}; - void serialize(utils::buffer_serializer& buffer) const - { - buffer.write(this->registry); - buffer.write(this->executed_instructions); - buffer.write(this->current_ip); - buffer.write(this->previous_ip); - buffer.write_optional(this->exception_rip); - buffer.write_optional(this->exit_status); - buffer.write(this->base_allocator); - buffer.write(this->peb); - buffer.write(this->process_params); - buffer.write(this->kusd); - buffer.write(this->mod_manager); + void serialize(utils::buffer_serializer& buffer) const + { + buffer.write(this->registry); + buffer.write(this->executed_instructions); + buffer.write(this->current_ip); + buffer.write(this->previous_ip); + buffer.write_optional(this->exception_rip); + buffer.write_optional(this->exit_status); + buffer.write(this->base_allocator); + buffer.write(this->peb); + buffer.write(this->process_params); + buffer.write(this->kusd); + buffer.write(this->mod_manager); - buffer.write(this->executable->image_base); - buffer.write(this->ntdll->image_base); - buffer.write(this->win32u->image_base); + buffer.write(this->executable->image_base); + buffer.write(this->ntdll->image_base); + buffer.write(this->win32u->image_base); - buffer.write(this->ldr_initialize_thunk); - buffer.write(this->rtl_user_thread_start); - buffer.write(this->ki_user_exception_dispatcher); + buffer.write(this->ldr_initialize_thunk); + buffer.write(this->rtl_user_thread_start); + buffer.write(this->ki_user_exception_dispatcher); - buffer.write(this->events); - buffer.write(this->files); - buffer.write(this->sections); - buffer.write(this->devices); - buffer.write(this->semaphores); - buffer.write(this->ports); - buffer.write(this->mutants); - buffer.write(this->registry_keys); - buffer.write_map(this->atoms); + buffer.write(this->events); + buffer.write(this->files); + buffer.write(this->sections); + buffer.write(this->devices); + buffer.write(this->semaphores); + buffer.write(this->ports); + buffer.write(this->mutants); + buffer.write(this->registry_keys); + buffer.write_map(this->atoms); - buffer.write_vector(this->default_register_set); - buffer.write(this->current_thread_id); - buffer.write(this->threads); + buffer.write_vector(this->default_register_set); + buffer.write(this->current_thread_id); + buffer.write(this->threads); - buffer.write(this->threads.find_handle(this->active_thread).bits); - } + buffer.write(this->threads.find_handle(this->active_thread).bits); + } - void deserialize(utils::buffer_deserializer& buffer) - { - buffer.read(this->registry); - buffer.read(this->executed_instructions); - buffer.read(this->current_ip); - buffer.read(this->previous_ip); - buffer.read_optional(this->exception_rip); - buffer.read_optional(this->exit_status); - buffer.read(this->base_allocator); - buffer.read(this->peb); - buffer.read(this->process_params); - buffer.read(this->kusd); - buffer.read(this->mod_manager); + void deserialize(utils::buffer_deserializer& buffer) + { + buffer.read(this->registry); + buffer.read(this->executed_instructions); + buffer.read(this->current_ip); + buffer.read(this->previous_ip); + buffer.read_optional(this->exception_rip); + buffer.read_optional(this->exit_status); + buffer.read(this->base_allocator); + buffer.read(this->peb); + buffer.read(this->process_params); + buffer.read(this->kusd); + buffer.read(this->mod_manager); - const auto executable_base = buffer.read(); - const auto ntdll_base = buffer.read(); - const auto win32u_base = buffer.read(); + const auto executable_base = buffer.read(); + const auto ntdll_base = buffer.read(); + const auto win32u_base = buffer.read(); - this->executable = this->mod_manager.find_by_address(executable_base); - this->ntdll = this->mod_manager.find_by_address(ntdll_base); - this->win32u = this->mod_manager.find_by_address(win32u_base); + this->executable = this->mod_manager.find_by_address(executable_base); + this->ntdll = this->mod_manager.find_by_address(ntdll_base); + this->win32u = this->mod_manager.find_by_address(win32u_base); - buffer.read(this->ldr_initialize_thunk); - buffer.read(this->rtl_user_thread_start); - buffer.read(this->ki_user_exception_dispatcher); + buffer.read(this->ldr_initialize_thunk); + buffer.read(this->rtl_user_thread_start); + buffer.read(this->ki_user_exception_dispatcher); - buffer.read(this->events); - buffer.read(this->files); - buffer.read(this->sections); - buffer.read(this->devices); - buffer.read(this->semaphores); - buffer.read(this->ports); - buffer.read(this->mutants); - buffer.read(this->registry_keys); - buffer.read_map(this->atoms); + buffer.read(this->events); + buffer.read(this->files); + buffer.read(this->sections); + buffer.read(this->devices); + buffer.read(this->semaphores); + buffer.read(this->ports); + buffer.read(this->mutants); + buffer.read(this->registry_keys); + buffer.read_map(this->atoms); - buffer.read_vector(this->default_register_set); - buffer.read(this->current_thread_id); + buffer.read_vector(this->default_register_set); + buffer.read(this->current_thread_id); - buffer.read(this->threads); + buffer.read(this->threads); - this->active_thread = this->threads.get(buffer.read()); - } + this->active_thread = this->threads.get(buffer.read()); + } - handle create_thread(x64_emulator& emu, const uint64_t start_address, const uint64_t argument, - const uint64_t stack_size) - { - emulator_thread t{emu, *this, start_address, argument, stack_size, ++this->current_thread_id}; - return this->threads.store(std::move(t)); - } + handle create_thread(x64_emulator& emu, const uint64_t start_address, const uint64_t argument, + const uint64_t stack_size) + { + emulator_thread t{emu, *this, start_address, argument, stack_size, ++this->current_thread_id}; + return this->threads.store(std::move(t)); + } }; diff --git a/src/windows-emulator/registry/hive_parser.cpp b/src/windows-emulator/registry/hive_parser.cpp index d5d6d293..68ecb9a3 100644 --- a/src/windows-emulator/registry/hive_parser.cpp +++ b/src/windows-emulator/registry/hive_parser.cpp @@ -5,216 +5,216 @@ namespace { - constexpr uint64_t MAIN_ROOT_OFFSET = 0x1000; - constexpr uint64_t MAIN_KEY_BLOCK_OFFSET = MAIN_ROOT_OFFSET + 0x20; + constexpr uint64_t MAIN_ROOT_OFFSET = 0x1000; + constexpr uint64_t MAIN_KEY_BLOCK_OFFSET = MAIN_ROOT_OFFSET + 0x20; - struct offset_entry_t - { - int32_t offset; - int32_t hash; - }; + struct offset_entry_t + { + int32_t offset; + int32_t hash; + }; - struct offsets_t - { - int32_t block_size; - char block_type[2]; - int16_t count; - offset_entry_t entries[1]; - }; + struct offsets_t + { + int32_t block_size; + char block_type[2]; + int16_t count; + offset_entry_t entries[1]; + }; - struct key_block_t - { - int32_t block_size; - char block_type[2]; - uint8_t dummya[18]; - int32_t subkey_count; - uint8_t dummyb[4]; - int32_t subkeys; - uint8_t dummyc[4]; - int32_t value_count; - int32_t offsets; - uint8_t dummyd[28]; - int16_t len; - int16_t du; - char name[255]; - }; + struct key_block_t + { + int32_t block_size; + char block_type[2]; + uint8_t dummya[18]; + int32_t subkey_count; + uint8_t dummyb[4]; + int32_t subkeys; + uint8_t dummyc[4]; + int32_t value_count; + int32_t offsets; + uint8_t dummyd[28]; + int16_t len; + int16_t du; + char name[255]; + }; - struct value_block_t - { - int32_t block_size; - char block_type[2]; - int16_t name_len; - int32_t size; - int32_t offset; - int32_t value_type; - int16_t flags; - int16_t dummy; - char name[255]; - }; + struct value_block_t + { + int32_t block_size; + char block_type[2]; + int16_t name_len; + int32_t size; + int32_t offset; + int32_t value_type; + int16_t flags; + int16_t dummy; + char name[255]; + }; - bool read_file_data_safe(std::ifstream& file, const uint64_t offset, void* buffer, const size_t size) - { - if (file.bad()) - { - return false; - } + bool read_file_data_safe(std::ifstream& file, const uint64_t offset, void* buffer, const size_t size) + { + if (file.bad()) + { + return false; + } - file.clear(); + file.clear(); - if (!file.good()) - { - return false; - } + if (!file.good()) + { + return false; + } - file.seekg(static_cast(offset)); + file.seekg(static_cast(offset)); - if (!file.good()) - { - return false; - } + if (!file.good()) + { + return false; + } - file.read(static_cast(buffer), static_cast(size)); + file.read(static_cast(buffer), static_cast(size)); - return file.good(); - } + return file.good(); + } - void read_file_data(std::ifstream& file, const uint64_t offset, void* buffer, const size_t size) - { - if (!read_file_data_safe(file, offset, buffer, size)) - { - throw std::runtime_error("Failed to read file data"); - } - } + void read_file_data(std::ifstream& file, const uint64_t offset, void* buffer, const size_t size) + { + if (!read_file_data_safe(file, offset, buffer, size)) + { + throw std::runtime_error("Failed to read file data"); + } + } - std::vector read_file_data(std::ifstream& file, const uint64_t offset, const size_t size) - { - std::vector result{}; - result.resize(size); + std::vector read_file_data(std::ifstream& file, const uint64_t offset, const size_t size) + { + std::vector result{}; + result.resize(size); - read_file_data(file, offset, result.data(), size); - return result; - } + read_file_data(file, offset, result.data(), size); + return result; + } - std::string read_file_data_string(std::ifstream& file, const uint64_t offset, const size_t size) - { - std::string result{}; - result.resize(size); + std::string read_file_data_string(std::ifstream& file, const uint64_t offset, const size_t size) + { + std::string result{}; + result.resize(size); - read_file_data(file, offset, result.data(), size); - return result; - } + read_file_data(file, offset, result.data(), size); + return result; + } - template - requires(std::is_trivially_copyable_v) - T read_file_object(std::ifstream& file, const uint64_t offset, const size_t array_index = 0) - { - T obj{}; - read_file_data(file, offset + (array_index * sizeof(T)), &obj, sizeof(T)); - return obj; - } + template + requires(std::is_trivially_copyable_v) + T read_file_object(std::ifstream& file, const uint64_t offset, const size_t array_index = 0) + { + T obj{}; + read_file_data(file, offset + (array_index * sizeof(T)), &obj, sizeof(T)); + return obj; + } - hive_key parse_root_block(std::ifstream& file, const std::filesystem::path& file_path) - { - try - { - if (read_file_data_string(file, 0, 4) != "regf") - { - throw std::runtime_error("Invalid signature"); - } + hive_key parse_root_block(std::ifstream& file, const std::filesystem::path& file_path) + { + try + { + if (read_file_data_string(file, 0, 4) != "regf") + { + throw std::runtime_error("Invalid signature"); + } - const auto key_block = read_file_object(file, MAIN_KEY_BLOCK_OFFSET); + const auto key_block = read_file_object(file, MAIN_KEY_BLOCK_OFFSET); - return {key_block.subkeys, key_block.value_count, key_block.offsets}; - } - catch (const std::exception& e) - { - throw std::runtime_error("Bad hive file '" + file_path.string() + "': " + e.what()); - } - } + return {key_block.subkeys, key_block.value_count, key_block.offsets}; + } + catch (const std::exception& e) + { + throw std::runtime_error("Bad hive file '" + file_path.string() + "': " + e.what()); + } + } } const hive_value* hive_key::get_value(std::ifstream& file, const std::string_view name) { - this->parse(file); + this->parse(file); - const auto entry = this->values_.find(name); - if (entry == this->values_.end()) - { - return nullptr; - } + const auto entry = this->values_.find(name); + if (entry == this->values_.end()) + { + return nullptr; + } - auto& value = entry->second; + auto& value = entry->second; - if (!value.parsed) - { - value.data = read_file_data(file, MAIN_ROOT_OFFSET + value.data_offset, value.data_length); - value.parsed = true; - } + if (!value.parsed) + { + value.data = read_file_data(file, MAIN_ROOT_OFFSET + value.data_offset, value.data_length); + value.parsed = true; + } - return &value; + return &value; } void hive_key::parse(std::ifstream& file) { - if (this->parsed_) - { - return; - } + if (this->parsed_) + { + return; + } - this->parsed_ = true; + this->parsed_ = true; - // Values + // Values - for (auto i = 0; i < this->value_count_; i++) - { - const auto offset = read_file_object(file, MAIN_ROOT_OFFSET + this->value_offsets_ + 4, i); - const auto value = read_file_object(file, MAIN_ROOT_OFFSET + offset); + for (auto i = 0; i < this->value_count_; i++) + { + const auto offset = read_file_object(file, MAIN_ROOT_OFFSET + this->value_offsets_ + 4, i); + const auto value = read_file_object(file, MAIN_ROOT_OFFSET + offset); - std::string value_name(value.name, std::min(value.name_len, static_cast(sizeof(value.name)))); + std::string value_name(value.name, std::min(value.name_len, static_cast(sizeof(value.name)))); - raw_hive_value raw_value{}; - raw_value.parsed = false; - raw_value.type = value.value_type; - raw_value.name = value_name; - raw_value.data_length = value.size & 0xffff; - raw_value.data_offset = value.offset + 4; + raw_hive_value raw_value{}; + raw_value.parsed = false; + raw_value.type = value.value_type; + raw_value.name = value_name; + raw_value.data_length = value.size & 0xffff; + raw_value.data_offset = value.offset + 4; - if (value.size & 1 << 31) - { - raw_value.data_offset = offset + static_cast(offsetof(value_block_t, offset)); - } + if (value.size & 1 << 31) + { + raw_value.data_offset = offset + static_cast(offsetof(value_block_t, offset)); + } - utils::string::to_lower_inplace(value_name); - this->values_[std::move(value_name)] = std::move(raw_value); - } + utils::string::to_lower_inplace(value_name); + this->values_[std::move(value_name)] = std::move(raw_value); + } - // Subkeys + // Subkeys - const auto item = read_file_object(file, MAIN_ROOT_OFFSET + this->subkey_block_offset_); + const auto item = read_file_object(file, MAIN_ROOT_OFFSET + this->subkey_block_offset_); - if (item.block_type[1] != 'f' && item.block_type[1] != 'h') - { - return; - } + if (item.block_type[1] != 'f' && item.block_type[1] != 'h') + { + return; + } - const auto entry_offsets = this->subkey_block_offset_ + offsetof(offsets_t, entries); + const auto entry_offsets = this->subkey_block_offset_ + offsetof(offsets_t, entries); - for (short i = 0; i < item.count; ++i) - { - const auto offset_entry = read_file_object(file, MAIN_ROOT_OFFSET + entry_offsets, i); + for (short i = 0; i < item.count; ++i) + { + const auto offset_entry = read_file_object(file, MAIN_ROOT_OFFSET + entry_offsets, i); - const auto subkey_block_offset = MAIN_ROOT_OFFSET + offset_entry.offset; - const auto subkey = read_file_object(file, subkey_block_offset); + const auto subkey_block_offset = MAIN_ROOT_OFFSET + offset_entry.offset; + const auto subkey = read_file_object(file, subkey_block_offset); - std::string subkey_name(subkey.name, std::min(subkey.len, static_cast(sizeof(subkey.name)))); - utils::string::to_lower_inplace(subkey_name); + std::string subkey_name(subkey.name, std::min(subkey.len, static_cast(sizeof(subkey.name)))); + utils::string::to_lower_inplace(subkey_name); - this->sub_keys_.emplace(std::move(subkey_name), hive_key{subkey.subkeys, subkey.value_count, subkey.offsets}); - } + this->sub_keys_.emplace(std::move(subkey_name), hive_key{subkey.subkeys, subkey.value_count, subkey.offsets}); + } } hive_parser::hive_parser(const std::filesystem::path& file_path) - : file_(file_path, std::ios::binary) - , root_key_(parse_root_block(file_, file_path)) + : file_(file_path, std::ios::binary), + root_key_(parse_root_block(file_, file_path)) { } diff --git a/src/windows-emulator/registry/hive_parser.hpp b/src/windows-emulator/registry/hive_parser.hpp index 5746e389..249fb0f8 100644 --- a/src/windows-emulator/registry/hive_parser.hpp +++ b/src/windows-emulator/registry/hive_parser.hpp @@ -8,95 +8,95 @@ struct hive_value { - uint32_t type{}; - std::string name{}; - std::vector data{}; + uint32_t type{}; + std::string name{}; + std::vector data{}; }; class hive_key { -public: - hive_key(const int subkey_block_offset, const int value_count, const int value_offsets) - : subkey_block_offset_(subkey_block_offset) - , value_count_(value_count) - , value_offsets_(value_offsets) - { - } + public: + hive_key(const int subkey_block_offset, const int value_count, const int value_offsets) + : subkey_block_offset_(subkey_block_offset), + value_count_(value_count), + value_offsets_(value_offsets) + { + } - utils::unordered_string_map& get_sub_keys(std::ifstream& file) - { - this->parse(file); - return this->sub_keys_; - } + utils::unordered_string_map& get_sub_keys(std::ifstream& file) + { + this->parse(file); + return this->sub_keys_; + } - hive_key* get_sub_key(std::ifstream& file, const std::string_view name) - { - auto& sub_keys = this->get_sub_keys(file); - const auto entry = sub_keys.find(name); + hive_key* get_sub_key(std::ifstream& file, const std::string_view name) + { + auto& sub_keys = this->get_sub_keys(file); + const auto entry = sub_keys.find(name); - if (entry == sub_keys.end()) - { - return nullptr; - } + if (entry == sub_keys.end()) + { + return nullptr; + } - return &entry->second; - } + return &entry->second; + } - const hive_value* get_value(std::ifstream& file, const std::string_view name); + const hive_value* get_value(std::ifstream& file, const std::string_view name); -private: - struct raw_hive_value : hive_value - { - bool parsed{false}; - int data_offset{}; - size_t data_length{}; - }; + private: + struct raw_hive_value : hive_value + { + bool parsed{false}; + int data_offset{}; + size_t data_length{}; + }; - bool parsed_{false}; - utils::unordered_string_map sub_keys_{}; - utils::unordered_string_map values_{}; + bool parsed_{false}; + utils::unordered_string_map sub_keys_{}; + utils::unordered_string_map values_{}; - const int subkey_block_offset_{}; - const int value_count_{}; - const int value_offsets_{}; + const int subkey_block_offset_{}; + const int value_count_{}; + const int value_offsets_{}; - void parse(std::ifstream& file); + void parse(std::ifstream& file); }; class hive_parser { -public: - explicit hive_parser(const std::filesystem::path& file_path); + public: + explicit hive_parser(const std::filesystem::path& file_path); - [[nodiscard]] hive_key* get_sub_key(const std::filesystem::path& key) - { - hive_key* current_key = &this->root_key_; + [[nodiscard]] hive_key* get_sub_key(const std::filesystem::path& key) + { + hive_key* current_key = &this->root_key_; - for (const auto& key_part : key) - { - if (!current_key) - { - return nullptr; - } + for (const auto& key_part : key) + { + if (!current_key) + { + return nullptr; + } - current_key = current_key->get_sub_key(this->file_, key_part.string()); - } + current_key = current_key->get_sub_key(this->file_, key_part.string()); + } - return current_key; - } + return current_key; + } - [[nodiscard]] const hive_value* get_value(const std::filesystem::path& key, const std::string_view name) - { - auto* sub_key = this->get_sub_key(key); - if (!sub_key) - { - return nullptr; - } + [[nodiscard]] const hive_value* get_value(const std::filesystem::path& key, const std::string_view name) + { + auto* sub_key = this->get_sub_key(key); + if (!sub_key) + { + return nullptr; + } - return sub_key->get_value(this->file_, name); - } + return sub_key->get_value(this->file_, name); + } -private: - std::ifstream file_{}; - hive_key root_key_; + private: + std::ifstream file_{}; + hive_key root_key_; }; diff --git a/src/windows-emulator/registry/registry_manager.cpp b/src/windows-emulator/registry/registry_manager.cpp index 9947035e..ad5c7801 100644 --- a/src/windows-emulator/registry/registry_manager.cpp +++ b/src/windows-emulator/registry/registry_manager.cpp @@ -7,33 +7,33 @@ namespace { - std::filesystem::path canonicalize_path(const std::filesystem::path& key) - { - auto path = key.lexically_normal().wstring(); - return utils::string::to_lower_consume(path); - } + std::filesystem::path canonicalize_path(const std::filesystem::path& key) + { + auto path = key.lexically_normal().wstring(); + return utils::string::to_lower_consume(path); + } - bool is_subpath(const std::filesystem::path& root, const std::filesystem::path& p) - { - auto root_it = root.begin(); - auto p_it = p.begin(); + bool is_subpath(const std::filesystem::path& root, const std::filesystem::path& p) + { + auto root_it = root.begin(); + auto p_it = p.begin(); - for (; root_it != root.end(); ++root_it, ++p_it) - { - if (p_it == p.end() || *root_it != *p_it) - { - return false; - } - } + for (; root_it != root.end(); ++root_it, ++p_it) + { + if (p_it == p.end() || *root_it != *p_it) + { + return false; + } + } - return true; - } + return true; + } - void register_hive(registry_manager::hive_map& hives, - const std::filesystem::path& key, const std::filesystem::path& file) - { - hives[canonicalize_path(key)] = std::make_unique(file); - } + void register_hive(registry_manager::hive_map& hives, const std::filesystem::path& key, + const std::filesystem::path& file) + { + hives[canonicalize_path(key)] = std::make_unique(file); + } } registry_manager::registry_manager() = default; @@ -42,130 +42,130 @@ registry_manager::registry_manager(registry_manager&&) noexcept = default; registry_manager& registry_manager::operator=(registry_manager&&) noexcept = default; registry_manager::registry_manager(const std::filesystem::path& hive_path) - : hive_path_(absolute(hive_path)) + : hive_path_(absolute(hive_path)) { - this->setup(); + this->setup(); } void registry_manager::setup() { - this->path_mapping_.clear(); - this->hives_.clear(); + this->path_mapping_.clear(); + this->hives_.clear(); - const std::filesystem::path root = R"(\registry)"; - const std::filesystem::path machine = root / "machine"; + const std::filesystem::path root = R"(\registry)"; + const std::filesystem::path machine = root / "machine"; - register_hive(this->hives_, machine / "system", this->hive_path_ / "SYSTEM"); - register_hive(this->hives_, machine / "security", this->hive_path_ / "SECURITY"); - register_hive(this->hives_, machine / "sam", this->hive_path_ / "SAM"); - register_hive(this->hives_, machine / "software", this->hive_path_ / "SOFTWARE"); - register_hive(this->hives_, machine / "system", this->hive_path_ / "SYSTEM"); - register_hive(this->hives_, machine / "hardware", this->hive_path_ / "HARDWARE"); + register_hive(this->hives_, machine / "system", this->hive_path_ / "SYSTEM"); + register_hive(this->hives_, machine / "security", this->hive_path_ / "SECURITY"); + register_hive(this->hives_, machine / "sam", this->hive_path_ / "SAM"); + register_hive(this->hives_, machine / "software", this->hive_path_ / "SOFTWARE"); + register_hive(this->hives_, machine / "system", this->hive_path_ / "SYSTEM"); + register_hive(this->hives_, machine / "hardware", this->hive_path_ / "HARDWARE"); - register_hive(this->hives_, root / "user", this->hive_path_ / "NTUSER.dat"); + register_hive(this->hives_, root / "user", this->hive_path_ / "NTUSER.dat"); - this->add_path_mapping(machine / "system" / "CurrentControlSet", machine / "system" / "ControlSet001"); + this->add_path_mapping(machine / "system" / "CurrentControlSet", machine / "system" / "ControlSet001"); } void registry_manager::serialize(utils::buffer_serializer& buffer) const { - buffer.write(this->hive_path_); + buffer.write(this->hive_path_); } void registry_manager::deserialize(utils::buffer_deserializer& buffer) { - buffer.read(this->hive_path_); - this->setup(); + buffer.read(this->hive_path_); + this->setup(); } std::filesystem::path registry_manager::normalize_path(const std::filesystem::path& path) const { - auto canonical_path = canonicalize_path(path); + auto canonical_path = canonicalize_path(path); - for (const auto& mapping : this->path_mapping_) - { - if (is_subpath(mapping.first, canonical_path)) - { - return mapping.second / canonical_path.lexically_relative(mapping.first); - } - } + for (const auto& mapping : this->path_mapping_) + { + if (is_subpath(mapping.first, canonical_path)) + { + return mapping.second / canonical_path.lexically_relative(mapping.first); + } + } - return canonical_path; + return canonical_path; } void registry_manager::add_path_mapping(const std::filesystem::path& key, const std::filesystem::path& value) { - this->path_mapping_[canonicalize_path(key)] = canonicalize_path(value); + this->path_mapping_[canonicalize_path(key)] = canonicalize_path(value); } std::optional registry_manager::get_key(const std::filesystem::path& key) { - const auto normal_key = this->normalize_path(key); + const auto normal_key = this->normalize_path(key); - if (is_subpath(normal_key, "\\registry\\machine")) - { - registry_key reg_key{}; - reg_key.hive = normal_key; - return {std::move(reg_key)}; - } + if (is_subpath(normal_key, "\\registry\\machine")) + { + registry_key reg_key{}; + reg_key.hive = normal_key; + return {std::move(reg_key)}; + } - const auto iterator = this->find_hive(normal_key); - if (iterator == this->hives_.end()) - { - return {}; - } + const auto iterator = this->find_hive(normal_key); + if (iterator == this->hives_.end()) + { + return {}; + } - registry_key reg_key{}; - reg_key.hive = iterator->first; - reg_key.path = normal_key.lexically_relative(reg_key.hive); + registry_key reg_key{}; + reg_key.hive = iterator->first; + reg_key.path = normal_key.lexically_relative(reg_key.hive); - if (reg_key.path.empty()) - { - return {std::move(reg_key)}; - } + if (reg_key.path.empty()) + { + return {std::move(reg_key)}; + } - const auto entry = iterator->second->get_sub_key(reg_key.path); - if (!entry) - { - return std::nullopt; - } + const auto entry = iterator->second->get_sub_key(reg_key.path); + if (!entry) + { + return std::nullopt; + } - return {std::move(reg_key)}; + return {std::move(reg_key)}; } std::optional registry_manager::get_value(const registry_key& key, std::string name) { - utils::string::to_lower_inplace(name); + utils::string::to_lower_inplace(name); - const auto iterator = this->hives_.find(key.hive); - if (iterator == this->hives_.end()) - { - return std::nullopt; - } + const auto iterator = this->hives_.find(key.hive); + if (iterator == this->hives_.end()) + { + return std::nullopt; + } - auto* entry = iterator->second->get_value(key.path, name); - if (!entry) - { - return std::nullopt; - } + auto* entry = iterator->second->get_value(key.path, name); + if (!entry) + { + return std::nullopt; + } - registry_value v{}; - v.type = entry->type; - v.name = entry->name; - v.data = entry->data; + registry_value v{}; + v.type = entry->type; + v.name = entry->name; + v.data = entry->data; - return v; + return v; } registry_manager::hive_map::iterator registry_manager::find_hive(const std::filesystem::path& key) { - for (auto i = this->hives_.begin(); i != this->hives_.end(); ++i) - { - if (is_subpath(i->first, key)) - { - return i; - } - } + for (auto i = this->hives_.begin(); i != this->hives_.end(); ++i) + { + if (is_subpath(i->first, key)) + { + return i; + } + } - return this->hives_.end(); + return this->hives_.end(); } diff --git a/src/windows-emulator/registry/registry_manager.hpp b/src/windows-emulator/registry/registry_manager.hpp index aed43c16..0c14d79c 100644 --- a/src/windows-emulator/registry/registry_manager.hpp +++ b/src/windows-emulator/registry/registry_manager.hpp @@ -6,61 +6,60 @@ struct registry_key { - std::filesystem::path hive{}; - std::filesystem::path path{}; + std::filesystem::path hive{}; + std::filesystem::path path{}; - void serialize(utils::buffer_serializer& buffer) const - { - buffer.write(this->hive); - buffer.write(this->path); - } + void serialize(utils::buffer_serializer& buffer) const + { + buffer.write(this->hive); + buffer.write(this->path); + } - void deserialize(utils::buffer_deserializer& buffer) - { - buffer.read(this->hive); - buffer.read(this->path); - } + void deserialize(utils::buffer_deserializer& buffer) + { + buffer.read(this->hive); + buffer.read(this->path); + } }; struct registry_value { - uint32_t type; - std::string_view name; - std::span data; + uint32_t type; + std::string_view name; + std::span data; }; class registry_manager { -public: - using hive_ptr = std::unique_ptr; - using hive_map = std::unordered_map; + public: + using hive_ptr = std::unique_ptr; + using hive_map = std::unordered_map; - registry_manager(); - registry_manager(const std::filesystem::path& hive_path); - ~registry_manager(); + registry_manager(); + registry_manager(const std::filesystem::path& hive_path); + ~registry_manager(); - registry_manager(registry_manager&&) noexcept; - registry_manager& operator=(registry_manager&&) noexcept; + registry_manager(registry_manager&&) noexcept; + registry_manager& operator=(registry_manager&&) noexcept; - registry_manager(const registry_manager&) = delete; - registry_manager& operator=(const registry_manager&) = delete; + registry_manager(const registry_manager&) = delete; + registry_manager& operator=(const registry_manager&) = delete; + void serialize(utils::buffer_serializer& buffer) const; + void deserialize(utils::buffer_deserializer& buffer); - void serialize(utils::buffer_serializer& buffer) const; - void deserialize(utils::buffer_deserializer& buffer); + std::optional get_key(const std::filesystem::path& key); + std::optional get_value(const registry_key& key, std::string name); - std::optional get_key(const std::filesystem::path& key); - std::optional get_value(const registry_key& key, std::string name); + private: + std::filesystem::path hive_path_{}; + hive_map hives_{}; + std::unordered_map path_mapping_{}; -private: - std::filesystem::path hive_path_{}; - hive_map hives_{}; - std::unordered_map path_mapping_{}; + std::filesystem::path normalize_path(const std::filesystem::path& path) const; + void add_path_mapping(const std::filesystem::path& key, const std::filesystem::path& value); - std::filesystem::path normalize_path(const std::filesystem::path& path) const; - void add_path_mapping(const std::filesystem::path& key, const std::filesystem::path& value); + hive_map::iterator find_hive(const std::filesystem::path& key); - hive_map::iterator find_hive(const std::filesystem::path& key); - - void setup(); + void setup(); }; diff --git a/src/windows-emulator/std_include.hpp b/src/windows-emulator/std_include.hpp index a82acdab..55d332a4 100644 --- a/src/windows-emulator/std_include.hpp +++ b/src/windows-emulator/std_include.hpp @@ -2,32 +2,32 @@ #ifdef _WIN32 #pragma warning(push) -#pragma warning(disable: 4005) -#pragma warning(disable: 4127) -#pragma warning(disable: 4201) -#pragma warning(disable: 4244) -#pragma warning(disable: 4245) -#pragma warning(disable: 4324) -#pragma warning(disable: 4458) -#pragma warning(disable: 4471) -#pragma warning(disable: 4505) -#pragma warning(disable: 4702) -#pragma warning(disable: 4996) -#pragma warning(disable: 5054) -#pragma warning(disable: 6011) -#pragma warning(disable: 6297) -#pragma warning(disable: 6385) -#pragma warning(disable: 6386) -#pragma warning(disable: 6387) -#pragma warning(disable: 26110) -#pragma warning(disable: 26451) -#pragma warning(disable: 26444) -#pragma warning(disable: 26451) -#pragma warning(disable: 26489) -#pragma warning(disable: 26495) -#pragma warning(disable: 26498) -#pragma warning(disable: 26812) -#pragma warning(disable: 28020) +#pragma warning(disable : 4005) +#pragma warning(disable : 4127) +#pragma warning(disable : 4201) +#pragma warning(disable : 4244) +#pragma warning(disable : 4245) +#pragma warning(disable : 4324) +#pragma warning(disable : 4458) +#pragma warning(disable : 4471) +#pragma warning(disable : 4505) +#pragma warning(disable : 4702) +#pragma warning(disable : 4996) +#pragma warning(disable : 5054) +#pragma warning(disable : 6011) +#pragma warning(disable : 6297) +#pragma warning(disable : 6385) +#pragma warning(disable : 6386) +#pragma warning(disable : 6387) +#pragma warning(disable : 26110) +#pragma warning(disable : 26451) +#pragma warning(disable : 26444) +#pragma warning(disable : 26451) +#pragma warning(disable : 26489) +#pragma warning(disable : 26495) +#pragma warning(disable : 26498) +#pragma warning(disable : 26812) +#pragma warning(disable : 28020) #pragma warning(pop) #endif diff --git a/src/windows-emulator/syscall_dispatcher.cpp b/src/windows-emulator/syscall_dispatcher.cpp index 6237ffdc..8bb835d9 100644 --- a/src/windows-emulator/syscall_dispatcher.cpp +++ b/src/windows-emulator/syscall_dispatcher.cpp @@ -3,145 +3,138 @@ static void serialize(utils::buffer_serializer& buffer, const syscall_handler_entry& obj) { - buffer.write(obj.name); + buffer.write(obj.name); } static void deserialize(utils::buffer_deserializer& buffer, syscall_handler_entry& obj) { - buffer.read(obj.name); - obj.handler = nullptr; + buffer.read(obj.name); + obj.handler = nullptr; } void syscall_dispatcher::serialize(utils::buffer_serializer& buffer) const { - buffer.write_map(this->handlers_); + buffer.write_map(this->handlers_); } void syscall_dispatcher::deserialize(utils::buffer_deserializer& buffer) { - buffer.read_map(this->handlers_); - this->add_handlers(); + buffer.read_map(this->handlers_); + this->add_handlers(); } - void syscall_dispatcher::setup(const exported_symbols& ntdll_exports, std::span ntdll_data, const exported_symbols& win32u_exports, std::span win32u_data) { - this->handlers_ = {}; + this->handlers_ = {}; - const auto ntdll_syscalls = find_syscalls(ntdll_exports, ntdll_data); - const auto win32u_syscalls = find_syscalls(win32u_exports, win32u_data); + const auto ntdll_syscalls = find_syscalls(ntdll_exports, ntdll_data); + const auto win32u_syscalls = find_syscalls(win32u_exports, win32u_data); - map_syscalls(this->handlers_, ntdll_syscalls); - map_syscalls(this->handlers_, win32u_syscalls); + map_syscalls(this->handlers_, ntdll_syscalls); + map_syscalls(this->handlers_, win32u_syscalls); - this->add_handlers(); + this->add_handlers(); } void syscall_dispatcher::add_handlers() { - std::map handler_mapping{}; + std::map handler_mapping{}; - syscall_dispatcher::add_handlers(handler_mapping); + syscall_dispatcher::add_handlers(handler_mapping); - for (auto& entry : this->handlers_) - { - const auto handler = handler_mapping.find(entry.second.name); - if (handler == handler_mapping.end()) - { - continue; - } + for (auto& entry : this->handlers_) + { + const auto handler = handler_mapping.find(entry.second.name); + if (handler == handler_mapping.end()) + { + continue; + } - entry.second.handler = handler->second; + entry.second.handler = handler->second; #ifndef NDEBUG - handler_mapping.erase(handler); + handler_mapping.erase(handler); #endif - } + } } void syscall_dispatcher::dispatch(windows_emulator& win_emu) { - auto& emu = win_emu.emu(); - auto& context = win_emu.process(); + auto& emu = win_emu.emu(); + auto& context = win_emu.process(); - const auto address = emu.read_instruction_pointer(); - const auto syscall_id = emu.reg(x64_register::eax); + const auto address = emu.read_instruction_pointer(); + const auto syscall_id = emu.reg(x64_register::eax); + const syscall_context c{win_emu, emu, context, true}; - const syscall_context c{win_emu, emu, context, true}; + try + { + const auto entry = this->handlers_.find(syscall_id); + if (entry == this->handlers_.end()) + { + printf("Unknown syscall: 0x%X\n", syscall_id); + c.emu.reg(x64_register::rax, STATUS_NOT_SUPPORTED); + c.emu.stop(); + return; + } - try - { - const auto entry = this->handlers_.find(syscall_id); - if (entry == this->handlers_.end()) - { - printf("Unknown syscall: 0x%X\n", syscall_id); - c.emu.reg(x64_register::rax, STATUS_NOT_SUPPORTED); - c.emu.stop(); - return; - } + if (!entry->second.handler) + { + printf("Unimplemented syscall: %s - 0x%X\n", entry->second.name.c_str(), syscall_id); + c.emu.reg(x64_register::rax, STATUS_NOT_SUPPORTED); + c.emu.stop(); + return; + } - if (!entry->second.handler) - { - printf("Unimplemented syscall: %s - 0x%X\n", entry->second.name.c_str(), syscall_id); - c.emu.reg(x64_register::rax, STATUS_NOT_SUPPORTED); - c.emu.stop(); - return; - } + const auto* mod = context.mod_manager.find_by_address(address); + if (mod != context.ntdll && mod != context.win32u) + { + win_emu.log.print(color::blue, "Executing inline syscall: %s (0x%X) at 0x%" PRIx64 " (%s)\n", + entry->second.name.c_str(), syscall_id, address, mod ? mod->name.c_str() : ""); + } + else + { + if (mod->is_within(context.previous_ip)) + { + const auto rsp = c.emu.read_stack_pointer(); + const auto return_address = c.emu.read_memory(rsp); + const auto* mod_name = context.mod_manager.find_name(return_address); - const auto* mod = context.mod_manager.find_by_address(address); - if (mod != context.ntdll && mod != context.win32u) - { - win_emu.log.print(color::blue, "Executing inline syscall: %s (0x%X) at 0x%" PRIx64 " (%s)\n", - entry->second.name.c_str(), - syscall_id, - address, mod ? mod->name.c_str() : ""); - } - else - { - if (mod->is_within(context.previous_ip)) - { - const auto rsp = c.emu.read_stack_pointer(); - const auto return_address = c.emu.read_memory(rsp); - const auto* mod_name = context.mod_manager.find_name(return_address); + win_emu.log.print(color::dark_gray, + "Executing syscall: %s (0x%X) at 0x%" PRIx64 " via 0x%" PRIx64 " (%s)\n", + entry->second.name.c_str(), syscall_id, address, return_address, mod_name); + } + else + { + const auto* previous_mod = context.mod_manager.find_by_address(context.previous_ip); + win_emu.log.print(color::blue, + "Crafted out-of-line syscall: %s (0x%X) at 0x%" PRIx64 " (%s) via 0x%" PRIx64 + " (%s)\n", + entry->second.name.c_str(), syscall_id, address, mod ? mod->name.c_str() : "", + context.previous_ip, previous_mod ? previous_mod->name.c_str() : ""); + } + } - win_emu.log.print(color::dark_gray, - "Executing syscall: %s (0x%X) at 0x%" PRIx64 " via 0x%" PRIx64 " (%s)\n", - entry->second.name.c_str(), - syscall_id, address, return_address, mod_name); - } - else - { - const auto* previous_mod = context.mod_manager.find_by_address(context.previous_ip); - win_emu.log.print(color::blue, - "Crafted out-of-line syscall: %s (0x%X) at 0x%" PRIx64 " (%s) via 0x%" PRIx64 - " (%s)\n", - entry->second.name.c_str(), - syscall_id, - address, mod ? mod->name.c_str() : "", context.previous_ip, - previous_mod ? previous_mod->name.c_str() : ""); - } - } - - entry->second.handler(c); - } - catch (std::exception& e) - { - printf("Syscall threw an exception: %X (0x%" PRIx64 ") - %s\n", syscall_id, address, e.what()); - emu.reg(x64_register::rax, STATUS_UNSUCCESSFUL); - emu.stop(); - } - catch (...) - { - printf("Syscall threw an unknown exception: %X (0x%" PRIx64 ")\n", syscall_id, address); - emu.reg(x64_register::rax, STATUS_UNSUCCESSFUL); - emu.stop(); - } + entry->second.handler(c); + } + catch (std::exception& e) + { + printf("Syscall threw an exception: %X (0x%" PRIx64 ") - %s\n", syscall_id, address, e.what()); + emu.reg(x64_register::rax, STATUS_UNSUCCESSFUL); + emu.stop(); + } + catch (...) + { + printf("Syscall threw an unknown exception: %X (0x%" PRIx64 ")\n", syscall_id, address); + emu.reg(x64_register::rax, STATUS_UNSUCCESSFUL); + emu.stop(); + } } syscall_dispatcher::syscall_dispatcher(const exported_symbols& ntdll_exports, std::span ntdll_data, const exported_symbols& win32u_exports, std::span win32u_data) { - this->setup(ntdll_exports, ntdll_data, win32u_exports, win32u_data); + this->setup(ntdll_exports, ntdll_data, win32u_exports, win32u_data); } diff --git a/src/windows-emulator/syscall_dispatcher.hpp b/src/windows-emulator/syscall_dispatcher.hpp index 23a5185e..c5a42f4e 100644 --- a/src/windows-emulator/syscall_dispatcher.hpp +++ b/src/windows-emulator/syscall_dispatcher.hpp @@ -3,39 +3,39 @@ #include "process_context.hpp" struct syscall_context; -using syscall_handler = void(*)(const syscall_context& c); +using syscall_handler = void (*)(const syscall_context& c); struct syscall_handler_entry { - syscall_handler handler{}; - std::string name{}; + syscall_handler handler{}; + std::string name{}; }; class windows_emulator; class syscall_dispatcher { -public: - syscall_dispatcher() = default; - syscall_dispatcher(const exported_symbols& ntdll_exports, std::span ntdll_data, - const exported_symbols& win32u_exports, std::span win32u_data); + public: + syscall_dispatcher() = default; + syscall_dispatcher(const exported_symbols& ntdll_exports, std::span ntdll_data, + const exported_symbols& win32u_exports, std::span win32u_data); - void dispatch(windows_emulator& win_emu); + void dispatch(windows_emulator& win_emu); - void serialize(utils::buffer_serializer& buffer) const; - void deserialize(utils::buffer_deserializer& buffer); + void serialize(utils::buffer_serializer& buffer) const; + void deserialize(utils::buffer_deserializer& buffer); - void setup(const exported_symbols& ntdll_exports, std::span ntdll_data, - const exported_symbols& win32u_exports, std::span win32u_data); + void setup(const exported_symbols& ntdll_exports, std::span ntdll_data, + const exported_symbols& win32u_exports, std::span win32u_data); - std::string get_syscall_name(const uint64_t id) - { - return this->handlers_.at(id).name; - } + std::string get_syscall_name(const uint64_t id) + { + return this->handlers_.at(id).name; + } -private: - std::map handlers_{}; + private: + std::map handlers_{}; - static void add_handlers(std::map& handler_mapping); - void add_handlers(); + static void add_handlers(std::map& handler_mapping); + void add_handlers(); }; diff --git a/src/windows-emulator/syscall_utils.hpp b/src/windows-emulator/syscall_utils.hpp index 41819729..2c406c97 100644 --- a/src/windows-emulator/syscall_utils.hpp +++ b/src/windows-emulator/syscall_utils.hpp @@ -5,202 +5,193 @@ struct syscall_context { - windows_emulator& win_emu; - x64_emulator& emu; - process_context& proc; - mutable bool write_status{true}; - mutable bool retrigger_syscall{false}; + windows_emulator& win_emu; + x64_emulator& emu; + process_context& proc; + mutable bool write_status{true}; + mutable bool retrigger_syscall{false}; }; inline uint64_t get_syscall_argument(x64_emulator& emu, const size_t index) { - switch (index) - { - case 0: - return emu.reg(x64_register::r10); - case 1: - return emu.reg(x64_register::rdx); - case 2: - return emu.reg(x64_register::r8); - case 3: - return emu.reg(x64_register::r9); - default: - return emu.read_stack(index + 1); - } + switch (index) + { + case 0: + return emu.reg(x64_register::r10); + case 1: + return emu.reg(x64_register::rdx); + case 2: + return emu.reg(x64_register::r8); + case 3: + return emu.reg(x64_register::r9); + default: + return emu.read_stack(index + 1); + } } inline bool is_uppercase(const char character) { - return toupper(character) == character; + return toupper(character) == character; } inline bool is_syscall(const std::string_view name) { - return name.starts_with("Nt") && name.size() > 3 && is_uppercase(name[2]); + return name.starts_with("Nt") && name.size() > 3 && is_uppercase(name[2]); } inline std::optional extract_syscall_id(const exported_symbol& symbol, std::span data) { - if (!is_syscall(symbol.name)) - { - return std::nullopt; - } + if (!is_syscall(symbol.name)) + { + return std::nullopt; + } - constexpr auto instruction_size = 5; - constexpr auto instruction_offset = 3; - constexpr auto instruction_operand_offset = 1; - constexpr auto instruction_opcode = static_cast(0xB8); + constexpr auto instruction_size = 5; + constexpr auto instruction_offset = 3; + constexpr auto instruction_operand_offset = 1; + constexpr auto instruction_opcode = static_cast(0xB8); - const auto instruction_rva = symbol.rva + instruction_offset; + const auto instruction_rva = symbol.rva + instruction_offset; - if (data.size() < (instruction_rva + instruction_size) || data[instruction_rva] != instruction_opcode) - { - return std::nullopt; - } + if (data.size() < (instruction_rva + instruction_size) || data[instruction_rva] != instruction_opcode) + { + return std::nullopt; + } - uint32_t syscall_id{0}; - static_assert(sizeof(syscall_id) <= (instruction_size - instruction_operand_offset)); - memcpy(&syscall_id, data.data() + instruction_rva + instruction_operand_offset, sizeof(syscall_id)); + uint32_t syscall_id{0}; + static_assert(sizeof(syscall_id) <= (instruction_size - instruction_operand_offset)); + memcpy(&syscall_id, data.data() + instruction_rva + instruction_operand_offset, sizeof(syscall_id)); - return syscall_id; + return syscall_id; } inline std::map find_syscalls(const exported_symbols& exports, std::span data) { - std::map syscalls{}; + std::map syscalls{}; - for (const auto& symbol : exports) - { - const auto id = extract_syscall_id(symbol, data); - if (id) - { - auto& entry = syscalls[*id]; + for (const auto& symbol : exports) + { + const auto id = extract_syscall_id(symbol, data); + if (id) + { + auto& entry = syscalls[*id]; - if (!entry.empty()) - { - throw std::runtime_error( - "Syscall with id " + std::to_string(*id) + ", which is mapping to " + symbol.name + - ", was already mapped to " + entry); - } + if (!entry.empty()) + { + throw std::runtime_error("Syscall with id " + std::to_string(*id) + ", which is mapping to " + + symbol.name + ", was already mapped to " + entry); + } - entry = symbol.name; - } - } + entry = symbol.name; + } + } - return syscalls; + return syscalls; } -inline void map_syscalls(std::map& handlers, - std::map syscalls) +inline void map_syscalls(std::map& handlers, std::map syscalls) { - for (auto& [id, name] : syscalls) - { - auto& entry = handlers[id]; + for (auto& [id, name] : syscalls) + { + auto& entry = handlers[id]; - if (!entry.name.empty()) - { - throw std::runtime_error( - "Syscall with id " + std::to_string(id) + ", which is mapping to " + name + - ", was previously mapped to " + entry.name); - } + if (!entry.name.empty()) + { + throw std::runtime_error("Syscall with id " + std::to_string(id) + ", which is mapping to " + name + + ", was previously mapped to " + entry.name); + } - entry.name = std::move(name); - entry.handler = nullptr; - } + entry.name = std::move(name); + entry.handler = nullptr; + } } template - requires(std::is_integral_v || std::is_enum_v) + requires(std::is_integral_v || std::is_enum_v) T resolve_argument(x64_emulator& emu, const size_t index) { - const auto arg = get_syscall_argument(emu, index); - return static_cast(arg); + const auto arg = get_syscall_argument(emu, index); + return static_cast(arg); } template - requires(std::is_same_v, handle>) + requires(std::is_same_v, handle>) handle resolve_argument(x64_emulator& emu, const size_t index) { - handle h{}; - h.bits = resolve_argument(emu, index); - return h; + handle h{}; + h.bits = resolve_argument(emu, index); + return h; } template - requires(std::is_same_v>) + requires(std::is_same_v>) T resolve_argument(x64_emulator& emu, const size_t index) { - const auto arg = get_syscall_argument(emu, index); - return T(emu, arg); + const auto arg = get_syscall_argument(emu, index); + return T(emu, arg); } template T resolve_indexed_argument(x64_emulator& emu, size_t& index) { - return resolve_argument(emu, index++); + return resolve_argument(emu, index++); } inline void write_status(const syscall_context& c, const NTSTATUS status, const uint64_t initial_ip) { - if (c.write_status && !c.retrigger_syscall) - { - c.emu.reg(x64_register::rax, static_cast(status)); - } + if (c.write_status && !c.retrigger_syscall) + { + c.emu.reg(x64_register::rax, static_cast(status)); + } - const auto new_ip = c.emu.read_instruction_pointer(); - if (initial_ip != new_ip || c.retrigger_syscall) - { - c.emu.reg(x64_register::rip, new_ip - 2); - } + const auto new_ip = c.emu.read_instruction_pointer(); + if (initial_ip != new_ip || c.retrigger_syscall) + { + c.emu.reg(x64_register::rip, new_ip - 2); + } } inline void forward_syscall(const syscall_context& c, NTSTATUS (*handler)()) { - const auto ip = c.emu.read_instruction_pointer(); + const auto ip = c.emu.read_instruction_pointer(); - const auto ret = handler(); - write_status(c, ret, ip); + const auto ret = handler(); + write_status(c, ret, ip); } template void forward_syscall(const syscall_context& c, NTSTATUS (*handler)(const syscall_context&, Args...)) { - const auto ip = c.emu.read_instruction_pointer(); + const auto ip = c.emu.read_instruction_pointer(); - size_t index = 0; - std::tuple func_args - { - c, - resolve_indexed_argument>>(c.emu, index)... - }; + size_t index = 0; + std::tuple func_args{ + c, resolve_indexed_argument>>(c.emu, index)...}; - (void)index; + (void)index; - const auto ret = std::apply(handler, std::move(func_args)); - write_status(c, ret, ip); + const auto ret = std::apply(handler, std::move(func_args)); + write_status(c, ret, ip); } template syscall_handler make_syscall_handler() { - return +[](const syscall_context& c) - { - forward_syscall(c, Handler); - }; + return +[](const syscall_context& c) { forward_syscall(c, Handler); }; } template void write_attribute(emulator& emu, const PS_ATTRIBUTE& attribute, const T& value) { - if (attribute.ReturnLength) - { - emulator_object{emu, attribute.ReturnLength}.write(sizeof(T)); - } + if (attribute.ReturnLength) + { + emulator_object{emu, attribute.ReturnLength}.write(sizeof(T)); + } - if (attribute.Size >= sizeof(T)) - { - emulator_object{emu, attribute.Value}.write(value); - } + if (attribute.Size >= sizeof(T)) + { + emulator_object{emu, attribute.Value}.write(value); + } } constexpr auto HUNDRED_NANOSECONDS_IN_ONE_SECOND = 10000000LL; @@ -209,67 +200,65 @@ constexpr auto WINDOWS_EPOCH_DIFFERENCE = EPOCH_DIFFERENCE_1601_TO_1970_SECONDS inline std::chrono::steady_clock::time_point convert_delay_interval_to_time_point(const LARGE_INTEGER delay_interval) { - if (delay_interval.QuadPart <= 0) - { - const auto relative_time = -delay_interval.QuadPart; - const auto relative_ticks_in_ms = relative_time / 10; - const auto relative_fraction_ns = (relative_time % 10) * 100; - const auto relative_duration = std::chrono::microseconds(relative_ticks_in_ms) + - std::chrono::nanoseconds(relative_fraction_ns); + if (delay_interval.QuadPart <= 0) + { + const auto relative_time = -delay_interval.QuadPart; + const auto relative_ticks_in_ms = relative_time / 10; + const auto relative_fraction_ns = (relative_time % 10) * 100; + const auto relative_duration = + std::chrono::microseconds(relative_ticks_in_ms) + std::chrono::nanoseconds(relative_fraction_ns); - return std::chrono::steady_clock::now() + relative_duration; - } + return std::chrono::steady_clock::now() + relative_duration; + } - const auto delay_seconds_since_1601 = delay_interval.QuadPart / HUNDRED_NANOSECONDS_IN_ONE_SECOND; - const auto delay_fraction_ns = (delay_interval.QuadPart % HUNDRED_NANOSECONDS_IN_ONE_SECOND) * 100; + const auto delay_seconds_since_1601 = delay_interval.QuadPart / HUNDRED_NANOSECONDS_IN_ONE_SECOND; + const auto delay_fraction_ns = (delay_interval.QuadPart % HUNDRED_NANOSECONDS_IN_ONE_SECOND) * 100; - const auto delay_seconds_since_1970 = delay_seconds_since_1601 - EPOCH_DIFFERENCE_1601_TO_1970_SECONDS; + const auto delay_seconds_since_1970 = delay_seconds_since_1601 - EPOCH_DIFFERENCE_1601_TO_1970_SECONDS; - const auto target_time = - std::chrono::system_clock::from_time_t(delay_seconds_since_1970) + - std::chrono::nanoseconds(delay_fraction_ns); + const auto target_time = + std::chrono::system_clock::from_time_t(delay_seconds_since_1970) + std::chrono::nanoseconds(delay_fraction_ns); - const auto now_system = std::chrono::system_clock::now(); + const auto now_system = std::chrono::system_clock::now(); - const auto duration_until_target = std::chrono::duration_cast< - std::chrono::microseconds>(target_time - now_system); + const auto duration_until_target = std::chrono::duration_cast(target_time - now_system); - return std::chrono::steady_clock::now() + duration_until_target; + return std::chrono::steady_clock::now() + duration_until_target; } inline KSYSTEM_TIME convert_to_ksystem_time(const std::chrono::system_clock::time_point& tp) { - const auto duration = tp.time_since_epoch(); - const auto ns_duration = std::chrono::duration_cast(duration); + const auto duration = tp.time_since_epoch(); + const auto ns_duration = std::chrono::duration_cast(duration); - const auto total_ticks = ns_duration.count() / 100 + WINDOWS_EPOCH_DIFFERENCE; + const auto total_ticks = ns_duration.count() / 100 + WINDOWS_EPOCH_DIFFERENCE; - KSYSTEM_TIME time{}; - time.LowPart = static_cast(total_ticks); - time.High1Time = static_cast(total_ticks >> 32); - time.High2Time = time.High1Time; + KSYSTEM_TIME time{}; + time.LowPart = static_cast(total_ticks); + time.High1Time = static_cast(total_ticks >> 32); + time.High2Time = time.High1Time; - return time; + return time; } inline void convert_to_ksystem_time(volatile KSYSTEM_TIME* dest, const std::chrono::system_clock::time_point& tp) { - const auto time = convert_to_ksystem_time(tp); - memcpy(const_cast(dest), &time, sizeof(*dest)); + const auto time = convert_to_ksystem_time(tp); + memcpy(const_cast(dest), &time, sizeof(*dest)); } inline std::chrono::system_clock::time_point convert_from_ksystem_time(const KSYSTEM_TIME& time) { - auto totalTicks = (static_cast(time.High1Time) << 32) | time.LowPart; - totalTicks -= WINDOWS_EPOCH_DIFFERENCE; + auto totalTicks = (static_cast(time.High1Time) << 32) | time.LowPart; + totalTicks -= WINDOWS_EPOCH_DIFFERENCE; - const auto duration = std::chrono::system_clock::duration(totalTicks * 100); - return std::chrono::system_clock::time_point(duration); + const auto duration = std::chrono::system_clock::duration(totalTicks * 100); + return std::chrono::system_clock::time_point(duration); } inline std::chrono::system_clock::time_point convert_from_ksystem_time(const volatile KSYSTEM_TIME& time) { - return convert_from_ksystem_time(*const_cast(&time)); + return convert_from_ksystem_time(*const_cast(&time)); } #ifndef OS_WINDOWS @@ -278,7 +267,7 @@ using __time64_t = int64_t; inline LARGE_INTEGER convert_unix_to_windows_time(const __time64_t unix_time) { - LARGE_INTEGER windows_time{}; - windows_time.QuadPart = (unix_time + EPOCH_DIFFERENCE_1601_TO_1970_SECONDS) * HUNDRED_NANOSECONDS_IN_ONE_SECOND; - return windows_time; + LARGE_INTEGER windows_time{}; + windows_time.QuadPart = (unix_time + EPOCH_DIFFERENCE_1601_TO_1970_SECONDS) * HUNDRED_NANOSECONDS_IN_ONE_SECOND; + return windows_time; } diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 32c8a9ee..d28f93f7 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -16,3548 +16,3440 @@ namespace { - NTSTATUS handle_NtQueryPerformanceCounter(const syscall_context& c, - const emulator_object performance_counter, - const emulator_object performance_frequency) - { - try - { - if (performance_counter) - { - performance_counter.access([&](LARGE_INTEGER& value) - { - if (c.win_emu.time_is_relative()) - { - value.QuadPart = static_cast(c.proc.executed_instructions); - } - else - { - value.QuadPart = std::chrono::steady_clock::now().time_since_epoch().count(); - } - }); - } - - if (performance_frequency) - { - performance_frequency.access([&](LARGE_INTEGER& value) - { - value.QuadPart = c.proc.kusd.get().QpcFrequency; - }); - } - - return STATUS_SUCCESS; - } - catch (...) - { - return STATUS_ACCESS_VIOLATION; - } - } - - NTSTATUS handle_NtManageHotPatch() - { - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtCreateWorkerFactory() - { - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtOpenKey(const syscall_context& c, const emulator_object key_handle, - const ACCESS_MASK /*desired_access*/, - const emulator_object>> object_attributes) - { - const auto attributes = object_attributes.read(); - auto key = read_unicode_string( - c.emu, reinterpret_cast>*>(attributes.ObjectName)); - - if (attributes.RootDirectory) - { - const auto* parent_handle = c.proc.registry_keys.get(attributes.RootDirectory); - if (!parent_handle) - { - return STATUS_INVALID_HANDLE; - } - - const std::filesystem::path full_path = parent_handle->hive / parent_handle->path / key; - key = full_path.u16string(); - } - - c.win_emu.log.print(color::dark_gray, "--> Registry key: %s\n", u16_to_u8(key).c_str()); - - auto entry = c.proc.registry.get_key(key); - if (!entry.has_value()) - { - return STATUS_OBJECT_NAME_NOT_FOUND; - } - - const auto handle = c.proc.registry_keys.store(std::move(entry.value())); - key_handle.write(handle); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtOpenKeyEx(const syscall_context& c, const emulator_object key_handle, - const ACCESS_MASK desired_access, - const emulator_object>> object_attributes, - ULONG /*open_options*/) - { - return handle_NtOpenKey(c, key_handle, desired_access, object_attributes); - } - - NTSTATUS handle_NtQueryKey(const syscall_context& c, const handle key_handle, - const KEY_INFORMATION_CLASS key_information_class, - const uint64_t key_information, const ULONG length, - const emulator_object result_length) - { - const auto* key = c.proc.registry_keys.get(key_handle); - if (!key) - { - return STATUS_INVALID_HANDLE; - } - - if (key_information_class == KeyNameInformation) - { - auto key_name = (key->hive / key->path).wstring(); - while (key_name.ends_with('/') || key_name.ends_with('\\')) - { - key_name.pop_back(); - } - - std::ranges::transform(key_name, key_name.begin(), std::towupper); - - const auto required_size = sizeof(KEY_NAME_INFORMATION) + (key_name.size() * 2) - 1; - result_length.write(static_cast(required_size)); - - if (required_size > length) - { - return STATUS_BUFFER_TOO_SMALL; - } - - KEY_NAME_INFORMATION info{}; - info.NameLength = static_cast(key_name.size() * 2); - - const emulator_object info_obj{c.emu, key_information}; - info_obj.write(info); - - c.emu.write_memory(key_information + offsetof(KEY_NAME_INFORMATION, Name), - key_name.data(), - info.NameLength); - - return STATUS_SUCCESS; - } - - if (key_information_class == KeyHandleTagsInformation) - { - constexpr auto required_size = sizeof(KEY_HANDLE_TAGS_INFORMATION); - result_length.write(required_size); - - if (required_size > length) - { - return STATUS_BUFFER_TOO_SMALL; - } - - KEY_HANDLE_TAGS_INFORMATION info{}; - info.HandleTags = 0; // ? - - const emulator_object info_obj{c.emu, key_information}; - info_obj.write(info); - - return STATUS_SUCCESS; - } - - c.win_emu.log.print(color::gray, "Unsupported registry class: %X\n", key_information_class); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtQueryValueKey(const syscall_context& c, const handle key_handle, - const emulator_object>> value_name, - const KEY_VALUE_INFORMATION_CLASS key_value_information_class, - const uint64_t key_value_information, - const ULONG length, const emulator_object result_length) - { - const auto* key = c.proc.registry_keys.get(key_handle); - if (!key) - { - return STATUS_INVALID_HANDLE; - } - - const auto query_name = read_unicode_string(c.emu, value_name); - - const auto value = c.proc.registry.get_value(*key, u16_to_u8(query_name)); - if (!value) - { - return STATUS_OBJECT_NAME_NOT_FOUND; - } - - const std::wstring original_name(value->name.begin(), value->name.end()); - - if (key_value_information_class == KeyValueBasicInformation) - { - constexpr auto base_size = offsetof(KEY_VALUE_BASIC_INFORMATION, Name); - const auto required_size = base_size + (original_name.size() * 2) - 1; - result_length.write(static_cast(required_size)); - - KEY_VALUE_BASIC_INFORMATION info{}; - info.TitleIndex = 0; - info.Type = value->type; - info.NameLength = static_cast(original_name.size() * 2); - - if (base_size <= length) - { - c.emu.write_memory(key_value_information, &info, base_size); - } - - if (required_size > length) - { - return STATUS_BUFFER_OVERFLOW; - } - - c.emu.write_memory(key_value_information + base_size, original_name.data(), info.NameLength); - - return STATUS_SUCCESS; - } - - if (key_value_information_class == KeyValuePartialInformation) - { - constexpr auto base_size = offsetof(KEY_VALUE_PARTIAL_INFORMATION, Data); - const auto required_size = base_size + value->data.size(); - result_length.write(static_cast(required_size)); - - KEY_VALUE_PARTIAL_INFORMATION info{}; - info.TitleIndex = 0; - info.Type = value->type; - info.DataLength = static_cast(value->data.size()); - - if (base_size <= length) - { - c.emu.write_memory(key_value_information, &info, base_size); - } - - if (required_size > length) - { - return STATUS_BUFFER_OVERFLOW; - } - - c.emu.write_memory(key_value_information + base_size, value->data.data(), value->data.size()); - - return STATUS_SUCCESS; - } - - if (key_value_information_class == KeyValueFullInformation) - { - constexpr auto base_size = offsetof(KEY_VALUE_FULL_INFORMATION, Name); - const auto name_size = original_name.size() * 2; - const auto value_size = value->data.size(); - const auto required_size = base_size + name_size + value_size + -1; - result_length.write(static_cast(required_size)); - - KEY_VALUE_FULL_INFORMATION info{}; - info.TitleIndex = 0; - info.Type = value->type; - info.DataLength = static_cast(value->data.size()); - info.NameLength = static_cast(original_name.size() * 2); - - if (base_size <= length) - { - c.emu.write_memory(key_value_information, &info, base_size); - } - - if (required_size > length) - { - return STATUS_BUFFER_OVERFLOW; - } - - c.emu.write_memory(key_value_information + base_size, - original_name.data(), - info.NameLength); - - c.emu.write_memory(key_value_information + base_size + info.NameLength, - value->data.data(), - value->data.size()); - - return STATUS_SUCCESS; - } - - c.win_emu.log.print(color::gray, "Unsupported registry value class: %X\n", key_value_information_class); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtCreateKey() - { - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtNotifyChangeKey() - { - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtSetInformationThread(const syscall_context& c, const handle thread_handle, - const THREADINFOCLASS info_class, - const uint64_t thread_information, - const uint32_t thread_information_length) - { - auto* thread = thread_handle == CURRENT_THREAD - ? c.proc.active_thread - : c.proc.threads.get(thread_handle); - - if (!thread) - { - return STATUS_INVALID_HANDLE; - } - - if (info_class == ThreadSchedulerSharedDataSlot) - { - return STATUS_SUCCESS; - } - - if (info_class == ThreadHideFromDebugger) - { - c.win_emu.log.print(color::pink, "--> Hiding thread %X from debugger!\n", thread->id); - return STATUS_SUCCESS; - } - - if (info_class == ThreadNameInformation) - { - if (thread_information_length != sizeof(THREAD_NAME_INFORMATION>)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object>> info{c.emu, thread_information}; - const auto i = info.read(); - thread->name = read_unicode_string(c.emu, i.ThreadName); - - c.win_emu.log.print(color::blue, "Setting thread (%d) name: %s\n", thread->id, - u16_to_u8(thread->name).c_str()); - - return STATUS_SUCCESS; - } - - if (info_class == ThreadImpersonationToken) - { - if (thread_information_length != sizeof(handle)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object info{c.emu, thread_information}; - info.write(DUMMY_IMPERSONATION_TOKEN); - - return STATUS_SUCCESS; - } - - if (info_class == ThreadZeroTlsCell) - { - if (thread_information_length != sizeof(ULONG)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const auto tls_index = c.emu.read_memory(thread_information); - const auto teb = thread->teb->read(); - - auto* tls_vector = teb.ThreadLocalStoragePointer; - c.emu.write_memory(tls_vector + tls_index, nullptr); - - return STATUS_SUCCESS; - } - - printf("Unsupported thread set info class: %X\n", info_class); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtSetEvent(const syscall_context& c, const uint64_t handle, - const emulator_object previous_state) - { - const auto entry = c.proc.events.get(handle); - if (!entry) - { - return STATUS_INVALID_HANDLE; - } - - if (previous_state.value()) - { - previous_state.write(entry->signaled ? 1ULL : 0ULL); - } - - entry->signaled = true; - return STATUS_SUCCESS; - } - - generic_handle_store* get_handle_store(process_context& proc, const handle h) - { - switch (h.value.type) - { - case handle_types::thread: - return &proc.threads; - case handle_types::event: - return &proc.events; - case handle_types::file: - return &proc.files; - case handle_types::device: - return &proc.devices; - case handle_types::semaphore: - return &proc.semaphores; - case handle_types::registry: - return &proc.registry_keys; - case handle_types::mutant: - return &proc.mutants; - case handle_types::port: - return &proc.ports; - case handle_types::section: - return &proc.sections; - default: - return nullptr; - } - } - - NTSTATUS handle_NtClose(const syscall_context& c, const handle h) - { - const auto value = h.value; - if (value.is_pseudo) - { - return STATUS_SUCCESS; - } - - auto* handle_store = get_handle_store(c.proc, h); - if (handle_store && handle_store->erase(h)) - { - return STATUS_SUCCESS; - } - - return STATUS_INVALID_HANDLE; - } - - NTSTATUS handle_NtTraceEvent() - { - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtReleaseMutant(const syscall_context& c, const handle mutant_handle, - const emulator_object previous_count) - { - if (mutant_handle.value.type != handle_types::mutant) - { - c.win_emu.log.error("Bad handle type for NtReleaseMutant\n"); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - auto* mutant = c.proc.mutants.get(mutant_handle); - if (!mutant) - { - return STATUS_INVALID_HANDLE; - } - - const auto old_count = mutant->release(); - - if (previous_count) - { - previous_count.write(static_cast(old_count)); - } - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtCreateMutant(const syscall_context& c, const emulator_object mutant_handle, - const ACCESS_MASK /*desired_access*/, - const emulator_object>> object_attributes, - const BOOLEAN initial_owner) - { - std::u16string name{}; - if (object_attributes) - { - const auto attributes = object_attributes.read(); - if (attributes.ObjectName) - { - name = read_unicode_string( - c.emu, emulator_object>>{c.emu, attributes.ObjectName}); - } - } - - if (!name.empty()) - { - for (const auto& mutant : c.proc.mutants) - { - if (mutant.second.name == name) - { - return STATUS_OBJECT_NAME_EXISTS; - } - } - } - - mutant e{}; - e.name = std::move(name); - - if (initial_owner) - { - e.try_lock(c.win_emu.current_thread().id); - } - - const auto handle = c.proc.mutants.store(std::move(e)); - mutant_handle.write(handle); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtCreateEvent(const syscall_context& c, const emulator_object event_handle, - const ACCESS_MASK /*desired_access*/, - const emulator_object>> object_attributes, - const EVENT_TYPE event_type, const BOOLEAN initial_state) - { - std::u16string name{}; - if (object_attributes) - { - const auto attributes = object_attributes.read(); - if (attributes.ObjectName) - { - name = read_unicode_string( - c.emu, reinterpret_cast>*>(attributes.ObjectName)); - } - } - - if (!name.empty()) - { - for (const auto& event : c.proc.events) - { - if (event.second.name == name) - { - return STATUS_OBJECT_NAME_EXISTS; - } - } - } - - event e{}; - e.type = event_type; - e.signaled = initial_state != FALSE; - e.name = std::move(name); - - const auto handle = c.proc.events.store(std::move(e)); - event_handle.write(handle); - - static_assert(sizeof(EVENT_TYPE) == sizeof(uint32_t)); - static_assert(sizeof(ACCESS_MASK) == sizeof(uint32_t)); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtOpenEvent(const syscall_context& c, const emulator_object event_handle, - const ACCESS_MASK /*desired_access*/, - const emulator_object>> object_attributes) - { - const auto attributes = object_attributes.read(); - const auto name = read_unicode_string( - c.emu, reinterpret_cast>*>(attributes.ObjectName)); - - for (auto& entry : c.proc.events) - { - if (entry.second.name == name) - { - ++entry.second.ref_count; - event_handle.write(c.proc.events.make_handle(entry.first).bits); - return STATUS_SUCCESS; - } - } - - return STATUS_NOT_FOUND; - } - - NTSTATUS handle_NtQueryVolumeInformationFile(const syscall_context& c, const handle file_handle, - const uint64_t /*io_status_block*/, const uint64_t fs_information, - const ULONG /*length*/, - const FS_INFORMATION_CLASS fs_information_class) - { - if (fs_information_class != FileFsDeviceInformation) - { - printf("Unsupported fs info class: %X\n", fs_information_class); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - const emulator_object info_obj{c.emu, fs_information}; - info_obj.access([&](FILE_FS_DEVICE_INFORMATION& info) - { - if (file_handle == STDOUT_HANDLE.bits && !c.win_emu.buffer_stdout) - { - info.DeviceType = FILE_DEVICE_CONSOLE; - info.Characteristics = 0x20000; - } - else - { - info.DeviceType = FILE_DEVICE_DISK; - info.Characteristics = 0x20020; - } - }); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtOpenSection(const syscall_context& c, const emulator_object section_handle, - const ACCESS_MASK /*desired_access*/, - const emulator_object>> object_attributes) - { - const auto attributes = object_attributes.read(); - - auto filename = read_unicode_string( - c.emu, reinterpret_cast>*>(attributes.ObjectName)); - c.win_emu.log.print(color::dark_gray, "--> Opening section: %s\n", u16_to_u8(filename).c_str()); - - if (filename == u"\\Windows\\SharedSection") - { - section_handle.write(SHARED_SECTION); - return STATUS_SUCCESS; - } - - if (attributes.RootDirectory != KNOWN_DLLS_DIRECTORY) - { - puts("Unsupported section"); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - utils::string::to_lower_inplace(filename); - - for (auto& section_entry : c.proc.sections) - { - if (section_entry.second.is_image() && section_entry.second.name == filename) - { - section_handle.write(c.proc.sections.make_handle(section_entry.first)); - return STATUS_SUCCESS; - } - } - - return STATUS_OBJECT_NAME_NOT_FOUND; - } - - NTSTATUS handle_NtMapViewOfSection(const syscall_context& c, const handle section_handle, - const handle process_handle, const emulator_object base_address, - const EMULATOR_CAST(EmulatorTraits::ULONG_PTR, ULONG_PTR) /*zero_bits*/, - const EMULATOR_CAST(EmulatorTraits::SIZE_T, SIZE_T) /*commit_size*/, - const emulator_object /*section_offset*/, - const emulator_object::SIZE_T, SIZE_T)> - view_size, - const SECTION_INHERIT /*inherit_disposition*/, const ULONG /*allocation_type*/, - const ULONG /*win32_protect*/) - { - if (process_handle != CURRENT_PROCESS) - { - return STATUS_INVALID_HANDLE; - } - - if (section_handle == SHARED_SECTION) - { - constexpr auto shared_section_size = 0x10000; - - const auto address = c.emu.find_free_allocation_base(shared_section_size); - c.emu.allocate_memory(address, shared_section_size, memory_permission::read_write); - - const std::u16string_view windows_dir = c.proc.kusd.get().NtSystemRoot.arr; - const auto windows_dir_size = windows_dir.size() * 2; - - constexpr auto windows_dir_offset = 0x10; - c.emu.write_memory(address + 8, windows_dir_offset); - - const auto obj_address = address + windows_dir_offset; - - const emulator_object>> windir_obj{c.emu, obj_address}; - windir_obj.access([&](UNICODE_STRING>& ucs) - { - const auto dir_address = kusd_mmio::address() + offsetof(KUSER_SHARED_DATA64, NtSystemRoot); - - ucs.Buffer = dir_address - obj_address; - ucs.Length = static_cast(windows_dir_size); - ucs.MaximumLength = ucs.Length; - }); - - - const emulator_object>> sysdir_obj{ - c.emu, windir_obj.value() + windir_obj.size() - }; - sysdir_obj.access([&](UNICODE_STRING>& ucs) - - { - c.proc.base_allocator.make_unicode_string(ucs, u"C:\\WINDOWS\\System32"); - ucs.Buffer = ucs.Buffer - obj_address; - }); - - const emulator_object>> base_dir_obj{ - c.emu, sysdir_obj.value() + sysdir_obj.size() - }; - base_dir_obj.access([&](UNICODE_STRING>& ucs) - { - c.proc.base_allocator.make_unicode_string(ucs, u"\\Sessions\\1\\BaseNamedObjects"); - ucs.Buffer = ucs.Buffer - obj_address; - }); - - if (view_size) - { - view_size.write(shared_section_size); - } - - base_address.write(address); - - return STATUS_SUCCESS; - } - - const auto section_entry = c.proc.sections.get(section_handle); - if (!section_entry) - { - return STATUS_INVALID_HANDLE; - } - - if (section_entry->is_image()) - { - const auto binary = c.proc.mod_manager.map_module(section_entry->file_name, c.win_emu.log); - if (!binary) - { - return STATUS_FILE_INVALID; - } - - std::u16string wide_name(binary->name.begin(), binary->name.end()); - section_entry->name = utils::string::to_lower_consume(wide_name); - - if (view_size.value()) - { - view_size.write(binary->size_of_image); - } - - base_address.write(binary->image_base); - - return STATUS_SUCCESS; - } - - uint64_t size = section_entry->maximum_size; - std::vector file_data{}; - - if (!section_entry->file_name.empty()) - { - if (!utils::io::read_file(section_entry->file_name, &file_data)) - { - return STATUS_INVALID_PARAMETER; - } - - size = page_align_up(file_data.size()); - } - - const auto protection = map_nt_to_emulator_protection(section_entry->section_page_protection); - const auto address = c.emu.allocate_memory(size, protection); - - if (!file_data.empty()) - { - c.emu.write_memory(address, file_data.data(), file_data.size()); - } - - if (view_size) - { - view_size.write(size); - } - - base_address.write(address); - return STATUS_SUCCESS; - } - - - NTSTATUS handle_NtCreateIoCompletion(const syscall_context& c, const emulator_object event_handle, - const ACCESS_MASK desired_access, - const emulator_object>> - object_attributes, - const uint32_t /*number_of_concurrent_threads*/) - { - return handle_NtCreateEvent(c, event_handle, desired_access, object_attributes, NotificationEvent, FALSE); - } - - NTSTATUS handle_NtCreateWaitCompletionPacket(const syscall_context& c, const emulator_object event_handle, - const ACCESS_MASK desired_access, - const emulator_object>> - object_attributes) - { - return handle_NtCreateEvent(c, event_handle, desired_access, object_attributes, NotificationEvent, FALSE); - } - - NTSTATUS handle_NtQueryVirtualMemory(const syscall_context& c, const handle process_handle, - const uint64_t base_address, const uint32_t info_class, - const uint64_t memory_information, const uint32_t memory_information_length, - const emulator_object return_length) - { - if (process_handle != CURRENT_PROCESS) - { - return STATUS_NOT_SUPPORTED; - } - - if (info_class == MemoryWorkingSetExInformation - || info_class == MemoryImageExtensionInformation) - { - return STATUS_NOT_SUPPORTED; - } - - if (info_class == MemoryBasicInformation) - { - if (return_length) - { - return_length.write(sizeof(EMU_MEMORY_BASIC_INFORMATION64)); - } - - if (memory_information_length != sizeof(EMU_MEMORY_BASIC_INFORMATION64)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object info{c.emu, memory_information}; - - info.access([&](EMU_MEMORY_BASIC_INFORMATION64& image_info) - { - const auto region_info = c.emu.get_region_info(base_address); - - assert(!region_info.is_committed || region_info.is_reserved); - - image_info.BaseAddress = reinterpret_cast(region_info.start); - image_info.AllocationBase = reinterpret_cast(region_info.allocation_base); - image_info.AllocationProtect = 0; - image_info.PartitionId = 0; - image_info.RegionSize = region_info.length; - image_info.State = region_info.is_committed - ? MEM_COMMIT - : (region_info.is_reserved - ? MEM_RESERVE - : MEM_FREE); - image_info.Protect = map_emulator_to_nt_protection(region_info.permissions); - image_info.Type = MEM_PRIVATE; - }); - - return STATUS_SUCCESS; - } - - if (info_class == MemoryImageInformation) - { - if (return_length) - { - return_length.write(sizeof(MEMORY_IMAGE_INFORMATION64)); - } - - if (memory_information_length != sizeof(MEMORY_IMAGE_INFORMATION64)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const auto mod = c.proc.mod_manager.find_by_address(base_address); - if (!mod) - { - printf("Bad address for memory image request: 0x%" PRIx64 "\n", base_address); - return STATUS_INVALID_ADDRESS; - } - - const emulator_object info{c.emu, memory_information}; - - info.access([&](MEMORY_IMAGE_INFORMATION64& image_info) - { - image_info.ImageBase = reinterpret_cast(mod->image_base); - image_info.SizeOfImage = mod->size_of_image; - image_info.ImageFlags = 0; - }); - - return STATUS_SUCCESS; - } - - if (info_class == MemoryRegionInformation) - { - if (return_length) - { - return_length.write(sizeof(MEMORY_REGION_INFORMATION64)); - } - - if (memory_information_length != sizeof(MEMORY_REGION_INFORMATION64)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const auto region_info = c.emu.get_region_info(base_address); - if (!region_info.is_reserved) - { - return STATUS_INVALID_ADDRESS; - } - - const emulator_object info{c.emu, memory_information}; - - info.access([&](MEMORY_REGION_INFORMATION64& image_info) - { - memset(&image_info, 0, sizeof(image_info)); - - image_info.AllocationBase = reinterpret_cast(region_info.allocation_base); - image_info.AllocationProtect = 0; - image_info.PartitionId = 0; - image_info.RegionSize = region_info.allocation_length; - image_info.Reserved = 0x10; - }); - - return STATUS_SUCCESS; - } - - printf("Unsupported memory info class: %X\n", info_class); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtQuerySystemInformation(const syscall_context& c, const uint32_t info_class, - const uint64_t system_information, - const uint32_t system_information_length, - const emulator_object return_length) - { - if (info_class == SystemFlushInformation - || info_class == SystemHypervisorSharedPageInformation - || info_class == 250 // Build 27744 - ) - { - return STATUS_NOT_SUPPORTED; - } - - if (info_class == SystemTimeOfDayInformation) - { - if (return_length) - { - return_length.write(sizeof(SYSTEM_TIMEOFDAY_INFORMATION64)); - } - - if (system_information_length != sizeof(SYSTEM_TIMEOFDAY_INFORMATION64)) - { - return STATUS_BUFFER_TOO_SMALL; - } - - const emulator_object info_obj{c.emu, system_information}; - - info_obj.access([&](SYSTEM_TIMEOFDAY_INFORMATION64& info) - { - info.BootTime.QuadPart = 0; - // TODO: Fill - }); - - return STATUS_SUCCESS; - } - - if (info_class == SystemRangeStartInformation) - { - if (return_length) - { - return_length.write(sizeof(SYSTEM_RANGE_START_INFORMATION64)); - } - - if (system_information_length != sizeof(SYSTEM_RANGE_START_INFORMATION64)) - { - return STATUS_BUFFER_TOO_SMALL; - } - - const emulator_object info_obj{c.emu, system_information}; - - info_obj.access([&](SYSTEM_RANGE_START_INFORMATION64& info) - { - info.SystemRangeStart = 0xFFFF800000000000; - }); - - return STATUS_SUCCESS; - } - - if (info_class == SystemProcessorInformation) - { - if (return_length) - { - return_length.write(sizeof(SYSTEM_PROCESSOR_INFORMATION64)); - } - - if (system_information_length != sizeof(SYSTEM_PROCESSOR_INFORMATION64)) - { - return STATUS_BUFFER_TOO_SMALL; - } - - const emulator_object info_obj{c.emu, system_information}; - - info_obj.access([&](SYSTEM_PROCESSOR_INFORMATION64& info) - { - memset(&info, 0, sizeof(info)); - info.MaximumProcessors = 2; - info.ProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64; - }); - - return STATUS_SUCCESS; - } - - if (info_class == SystemNumaProcessorMap) - { - if (return_length) - { - return_length.write(sizeof(SYSTEM_NUMA_INFORMATION64)); - } - - if (system_information_length != sizeof(SYSTEM_NUMA_INFORMATION64)) - { - return STATUS_BUFFER_TOO_SMALL; - } - - const emulator_object info_obj{c.emu, system_information}; - - info_obj.access([&](SYSTEM_NUMA_INFORMATION64& info) - { - memset(&info, 0, sizeof(info)); - info.ActiveProcessorsGroupAffinity->Mask = 0xFFF; - info.AvailableMemory[0] = 0xFFF; - info.Pad[0] = 0xFFF; - }); - - return STATUS_SUCCESS; - } - - if (info_class == SystemErrorPortTimeouts) - { - if (return_length) - { - return_length.write(sizeof(SYSTEM_ERROR_PORT_TIMEOUTS)); - } - - if (system_information_length != sizeof(SYSTEM_ERROR_PORT_TIMEOUTS)) - { - return STATUS_BUFFER_TOO_SMALL; - } - - const emulator_object info_obj{c.emu, system_information}; - - info_obj.access([&](SYSTEM_ERROR_PORT_TIMEOUTS& info) - { - info.StartTimeout = 0; - info.CommTimeout = 0; - }); - - return STATUS_SUCCESS; - } - - if (info_class != SystemBasicInformation && info_class != SystemEmulationBasicInformation) - { - printf("Unsupported system info class: %X\n", info_class); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - if (return_length) - { - return_length.write(sizeof(SYSTEM_BASIC_INFORMATION64)); - } - - if (system_information_length != sizeof(SYSTEM_BASIC_INFORMATION64)) - { - return STATUS_BUFFER_TOO_SMALL; - } - - const emulator_object info{c.emu, system_information}; - - info.access([&](SYSTEM_BASIC_INFORMATION64& basic_info) - { - basic_info.Reserved = 0; - basic_info.TimerResolution = 0x0002625a; - basic_info.PageSize = 0x1000; - basic_info.LowestPhysicalPageNumber = 0x00000001; - basic_info.HighestPhysicalPageNumber = 0x00c9c7ff; - basic_info.AllocationGranularity = 0x10000; - basic_info.MinimumUserModeAddress = 0x0000000000010000; - basic_info.MaximumUserModeAddress = 0x00007ffffffeffff; - basic_info.ActiveProcessorsAffinityMask = 0x0000000000000fff; - basic_info.NumberOfProcessors = 1; - }); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtDuplicateObject(const syscall_context& /*c*/, const handle source_process_handle, - const handle source_handle, const handle target_process_handle, - const emulator_object target_handle, const ACCESS_MASK /*desired_access*/, - const ULONG /*handle_attributes*/, const ULONG /*options*/) - { - if (source_process_handle != CURRENT_PROCESS || target_process_handle != CURRENT_PROCESS) - { - return STATUS_NOT_SUPPORTED; - } - - if (source_handle.value.is_pseudo) - { - target_handle.write(source_handle); - return STATUS_SUCCESS; - } - - puts("Duplicating non-pseudo object not supported yet!"); - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtQuerySystemInformationEx(const syscall_context& c, const uint32_t info_class, - const uint64_t input_buffer, - const uint32_t input_buffer_length, - const uint64_t system_information, - const uint32_t system_information_length, - const emulator_object return_length) - { - if (info_class == SystemFlushInformation - || info_class == SystemFeatureConfigurationInformation - || info_class == SystemSupportedProcessorArchitectures2 - || info_class == SystemFeatureConfigurationSectionInformation) - { - //printf("Unsupported, but allowed system info class: %X\n", info_class); - return STATUS_NOT_SUPPORTED; - } - - if (info_class == SystemLogicalProcessorAndGroupInformation) - { - void* buffer = calloc(1, input_buffer_length); - void* res_buff = calloc(1, system_information_length); - c.emu.read_memory(input_buffer, buffer, input_buffer_length); - - NTSTATUS code = STATUS_SUCCESS; - - return_length.access([&](uint32_t& len) - { - (void)len; + NTSTATUS handle_NtQueryPerformanceCounter(const syscall_context& c, + const emulator_object performance_counter, + const emulator_object performance_frequency) + { + try + { + if (performance_counter) + { + performance_counter.access([&](LARGE_INTEGER& value) { + if (c.win_emu.time_is_relative()) + { + value.QuadPart = static_cast(c.proc.executed_instructions); + } + else + { + value.QuadPart = std::chrono::steady_clock::now().time_since_epoch().count(); + } + }); + } + + if (performance_frequency) + { + performance_frequency.access( + [&](LARGE_INTEGER& value) { value.QuadPart = c.proc.kusd.get().QpcFrequency; }); + } + + return STATUS_SUCCESS; + } + catch (...) + { + return STATUS_ACCESS_VIOLATION; + } + } + + NTSTATUS handle_NtManageHotPatch() + { + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtCreateWorkerFactory() + { + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtOpenKey(const syscall_context& c, const emulator_object key_handle, + const ACCESS_MASK /*desired_access*/, + const emulator_object>> object_attributes) + { + const auto attributes = object_attributes.read(); + auto key = + read_unicode_string(c.emu, reinterpret_cast>*>(attributes.ObjectName)); + + if (attributes.RootDirectory) + { + const auto* parent_handle = c.proc.registry_keys.get(attributes.RootDirectory); + if (!parent_handle) + { + return STATUS_INVALID_HANDLE; + } + + const std::filesystem::path full_path = parent_handle->hive / parent_handle->path / key; + key = full_path.u16string(); + } + + c.win_emu.log.print(color::dark_gray, "--> Registry key: %s\n", u16_to_u8(key).c_str()); + + auto entry = c.proc.registry.get_key(key); + if (!entry.has_value()) + { + return STATUS_OBJECT_NAME_NOT_FOUND; + } + + const auto handle = c.proc.registry_keys.store(std::move(entry.value())); + key_handle.write(handle); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtOpenKeyEx(const syscall_context& c, const emulator_object key_handle, + const ACCESS_MASK desired_access, + const emulator_object>> object_attributes, + ULONG /*open_options*/) + { + return handle_NtOpenKey(c, key_handle, desired_access, object_attributes); + } + + NTSTATUS handle_NtQueryKey(const syscall_context& c, const handle key_handle, + const KEY_INFORMATION_CLASS key_information_class, const uint64_t key_information, + const ULONG length, const emulator_object result_length) + { + const auto* key = c.proc.registry_keys.get(key_handle); + if (!key) + { + return STATUS_INVALID_HANDLE; + } + + if (key_information_class == KeyNameInformation) + { + auto key_name = (key->hive / key->path).wstring(); + while (key_name.ends_with('/') || key_name.ends_with('\\')) + { + key_name.pop_back(); + } + + std::ranges::transform(key_name, key_name.begin(), std::towupper); + + const auto required_size = sizeof(KEY_NAME_INFORMATION) + (key_name.size() * 2) - 1; + result_length.write(static_cast(required_size)); + + if (required_size > length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + KEY_NAME_INFORMATION info{}; + info.NameLength = static_cast(key_name.size() * 2); + + const emulator_object info_obj{c.emu, key_information}; + info_obj.write(info); + + c.emu.write_memory(key_information + offsetof(KEY_NAME_INFORMATION, Name), key_name.data(), + info.NameLength); + + return STATUS_SUCCESS; + } + + if (key_information_class == KeyHandleTagsInformation) + { + constexpr auto required_size = sizeof(KEY_HANDLE_TAGS_INFORMATION); + result_length.write(required_size); + + if (required_size > length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + KEY_HANDLE_TAGS_INFORMATION info{}; + info.HandleTags = 0; // ? + + const emulator_object info_obj{c.emu, key_information}; + info_obj.write(info); + + return STATUS_SUCCESS; + } + + c.win_emu.log.print(color::gray, "Unsupported registry class: %X\n", key_information_class); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtQueryValueKey(const syscall_context& c, const handle key_handle, + const emulator_object>> value_name, + const KEY_VALUE_INFORMATION_CLASS key_value_information_class, + const uint64_t key_value_information, const ULONG length, + const emulator_object result_length) + { + const auto* key = c.proc.registry_keys.get(key_handle); + if (!key) + { + return STATUS_INVALID_HANDLE; + } + + const auto query_name = read_unicode_string(c.emu, value_name); + + const auto value = c.proc.registry.get_value(*key, u16_to_u8(query_name)); + if (!value) + { + return STATUS_OBJECT_NAME_NOT_FOUND; + } + + const std::wstring original_name(value->name.begin(), value->name.end()); + + if (key_value_information_class == KeyValueBasicInformation) + { + constexpr auto base_size = offsetof(KEY_VALUE_BASIC_INFORMATION, Name); + const auto required_size = base_size + (original_name.size() * 2) - 1; + result_length.write(static_cast(required_size)); + + KEY_VALUE_BASIC_INFORMATION info{}; + info.TitleIndex = 0; + info.Type = value->type; + info.NameLength = static_cast(original_name.size() * 2); + + if (base_size <= length) + { + c.emu.write_memory(key_value_information, &info, base_size); + } + + if (required_size > length) + { + return STATUS_BUFFER_OVERFLOW; + } + + c.emu.write_memory(key_value_information + base_size, original_name.data(), info.NameLength); + + return STATUS_SUCCESS; + } + + if (key_value_information_class == KeyValuePartialInformation) + { + constexpr auto base_size = offsetof(KEY_VALUE_PARTIAL_INFORMATION, Data); + const auto required_size = base_size + value->data.size(); + result_length.write(static_cast(required_size)); + + KEY_VALUE_PARTIAL_INFORMATION info{}; + info.TitleIndex = 0; + info.Type = value->type; + info.DataLength = static_cast(value->data.size()); + + if (base_size <= length) + { + c.emu.write_memory(key_value_information, &info, base_size); + } + + if (required_size > length) + { + return STATUS_BUFFER_OVERFLOW; + } + + c.emu.write_memory(key_value_information + base_size, value->data.data(), value->data.size()); + + return STATUS_SUCCESS; + } + + if (key_value_information_class == KeyValueFullInformation) + { + constexpr auto base_size = offsetof(KEY_VALUE_FULL_INFORMATION, Name); + const auto name_size = original_name.size() * 2; + const auto value_size = value->data.size(); + const auto required_size = base_size + name_size + value_size + -1; + result_length.write(static_cast(required_size)); + + KEY_VALUE_FULL_INFORMATION info{}; + info.TitleIndex = 0; + info.Type = value->type; + info.DataLength = static_cast(value->data.size()); + info.NameLength = static_cast(original_name.size() * 2); + + if (base_size <= length) + { + c.emu.write_memory(key_value_information, &info, base_size); + } + + if (required_size > length) + { + return STATUS_BUFFER_OVERFLOW; + } + + c.emu.write_memory(key_value_information + base_size, original_name.data(), info.NameLength); + + c.emu.write_memory(key_value_information + base_size + info.NameLength, value->data.data(), + value->data.size()); + + return STATUS_SUCCESS; + } + + c.win_emu.log.print(color::gray, "Unsupported registry value class: %X\n", key_value_information_class); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtCreateKey() + { + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtNotifyChangeKey() + { + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtSetInformationThread(const syscall_context& c, const handle thread_handle, + const THREADINFOCLASS info_class, const uint64_t thread_information, + const uint32_t thread_information_length) + { + auto* thread = thread_handle == CURRENT_THREAD ? c.proc.active_thread : c.proc.threads.get(thread_handle); + + if (!thread) + { + return STATUS_INVALID_HANDLE; + } + + if (info_class == ThreadSchedulerSharedDataSlot) + { + return STATUS_SUCCESS; + } + + if (info_class == ThreadHideFromDebugger) + { + c.win_emu.log.print(color::pink, "--> Hiding thread %X from debugger!\n", thread->id); + return STATUS_SUCCESS; + } + + if (info_class == ThreadNameInformation) + { + if (thread_information_length != sizeof(THREAD_NAME_INFORMATION>)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object>> info{c.emu, thread_information}; + const auto i = info.read(); + thread->name = read_unicode_string(c.emu, i.ThreadName); + + c.win_emu.log.print(color::blue, "Setting thread (%d) name: %s\n", thread->id, + u16_to_u8(thread->name).c_str()); + + return STATUS_SUCCESS; + } + + if (info_class == ThreadImpersonationToken) + { + if (thread_information_length != sizeof(handle)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object info{c.emu, thread_information}; + info.write(DUMMY_IMPERSONATION_TOKEN); + + return STATUS_SUCCESS; + } + + if (info_class == ThreadZeroTlsCell) + { + if (thread_information_length != sizeof(ULONG)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const auto tls_index = c.emu.read_memory(thread_information); + const auto teb = thread->teb->read(); + + auto* tls_vector = teb.ThreadLocalStoragePointer; + c.emu.write_memory(tls_vector + tls_index, nullptr); + + return STATUS_SUCCESS; + } + + printf("Unsupported thread set info class: %X\n", info_class); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtSetEvent(const syscall_context& c, const uint64_t handle, + const emulator_object previous_state) + { + const auto entry = c.proc.events.get(handle); + if (!entry) + { + return STATUS_INVALID_HANDLE; + } + + if (previous_state.value()) + { + previous_state.write(entry->signaled ? 1ULL : 0ULL); + } + + entry->signaled = true; + return STATUS_SUCCESS; + } + + generic_handle_store* get_handle_store(process_context& proc, const handle h) + { + switch (h.value.type) + { + case handle_types::thread: + return &proc.threads; + case handle_types::event: + return &proc.events; + case handle_types::file: + return &proc.files; + case handle_types::device: + return &proc.devices; + case handle_types::semaphore: + return &proc.semaphores; + case handle_types::registry: + return &proc.registry_keys; + case handle_types::mutant: + return &proc.mutants; + case handle_types::port: + return &proc.ports; + case handle_types::section: + return &proc.sections; + default: + return nullptr; + } + } + + NTSTATUS handle_NtClose(const syscall_context& c, const handle h) + { + const auto value = h.value; + if (value.is_pseudo) + { + return STATUS_SUCCESS; + } + + auto* handle_store = get_handle_store(c.proc, h); + if (handle_store && handle_store->erase(h)) + { + return STATUS_SUCCESS; + } + + return STATUS_INVALID_HANDLE; + } + + NTSTATUS handle_NtTraceEvent() + { + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtReleaseMutant(const syscall_context& c, const handle mutant_handle, + const emulator_object previous_count) + { + if (mutant_handle.value.type != handle_types::mutant) + { + c.win_emu.log.error("Bad handle type for NtReleaseMutant\n"); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + auto* mutant = c.proc.mutants.get(mutant_handle); + if (!mutant) + { + return STATUS_INVALID_HANDLE; + } + + const auto old_count = mutant->release(); + + if (previous_count) + { + previous_count.write(static_cast(old_count)); + } + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtCreateMutant(const syscall_context& c, const emulator_object mutant_handle, + const ACCESS_MASK /*desired_access*/, + const emulator_object>> object_attributes, + const BOOLEAN initial_owner) + { + std::u16string name{}; + if (object_attributes) + { + const auto attributes = object_attributes.read(); + if (attributes.ObjectName) + { + name = read_unicode_string( + c.emu, emulator_object>>{c.emu, attributes.ObjectName}); + } + } + + if (!name.empty()) + { + for (const auto& mutant : c.proc.mutants) + { + if (mutant.second.name == name) + { + return STATUS_OBJECT_NAME_EXISTS; + } + } + } + + mutant e{}; + e.name = std::move(name); + + if (initial_owner) + { + e.try_lock(c.win_emu.current_thread().id); + } + + const auto handle = c.proc.mutants.store(std::move(e)); + mutant_handle.write(handle); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtCreateEvent(const syscall_context& c, const emulator_object event_handle, + const ACCESS_MASK /*desired_access*/, + const emulator_object>> object_attributes, + const EVENT_TYPE event_type, const BOOLEAN initial_state) + { + std::u16string name{}; + if (object_attributes) + { + const auto attributes = object_attributes.read(); + if (attributes.ObjectName) + { + name = read_unicode_string( + c.emu, reinterpret_cast>*>(attributes.ObjectName)); + } + } + + if (!name.empty()) + { + for (const auto& event : c.proc.events) + { + if (event.second.name == name) + { + return STATUS_OBJECT_NAME_EXISTS; + } + } + } + + event e{}; + e.type = event_type; + e.signaled = initial_state != FALSE; + e.name = std::move(name); + + const auto handle = c.proc.events.store(std::move(e)); + event_handle.write(handle); + + static_assert(sizeof(EVENT_TYPE) == sizeof(uint32_t)); + static_assert(sizeof(ACCESS_MASK) == sizeof(uint32_t)); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtOpenEvent(const syscall_context& c, const emulator_object event_handle, + const ACCESS_MASK /*desired_access*/, + const emulator_object>> object_attributes) + { + const auto attributes = object_attributes.read(); + const auto name = + read_unicode_string(c.emu, reinterpret_cast>*>(attributes.ObjectName)); + + for (auto& entry : c.proc.events) + { + if (entry.second.name == name) + { + ++entry.second.ref_count; + event_handle.write(c.proc.events.make_handle(entry.first).bits); + return STATUS_SUCCESS; + } + } + + return STATUS_NOT_FOUND; + } + + NTSTATUS handle_NtQueryVolumeInformationFile(const syscall_context& c, const handle file_handle, + const uint64_t /*io_status_block*/, const uint64_t fs_information, + const ULONG /*length*/, + const FS_INFORMATION_CLASS fs_information_class) + { + if (fs_information_class != FileFsDeviceInformation) + { + printf("Unsupported fs info class: %X\n", fs_information_class); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + const emulator_object info_obj{c.emu, fs_information}; + info_obj.access([&](FILE_FS_DEVICE_INFORMATION& info) { + if (file_handle == STDOUT_HANDLE.bits && !c.win_emu.buffer_stdout) + { + info.DeviceType = FILE_DEVICE_CONSOLE; + info.Characteristics = 0x20000; + } + else + { + info.DeviceType = FILE_DEVICE_DISK; + info.Characteristics = 0x20020; + } + }); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtOpenSection(const syscall_context& c, const emulator_object section_handle, + const ACCESS_MASK /*desired_access*/, + const emulator_object>> object_attributes) + { + const auto attributes = object_attributes.read(); + + auto filename = + read_unicode_string(c.emu, reinterpret_cast>*>(attributes.ObjectName)); + c.win_emu.log.print(color::dark_gray, "--> Opening section: %s\n", u16_to_u8(filename).c_str()); + + if (filename == u"\\Windows\\SharedSection") + { + section_handle.write(SHARED_SECTION); + return STATUS_SUCCESS; + } + + if (attributes.RootDirectory != KNOWN_DLLS_DIRECTORY) + { + puts("Unsupported section"); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + utils::string::to_lower_inplace(filename); + + for (auto& section_entry : c.proc.sections) + { + if (section_entry.second.is_image() && section_entry.second.name == filename) + { + section_handle.write(c.proc.sections.make_handle(section_entry.first)); + return STATUS_SUCCESS; + } + } + + return STATUS_OBJECT_NAME_NOT_FOUND; + } + + NTSTATUS handle_NtMapViewOfSection( + const syscall_context& c, const handle section_handle, const handle process_handle, + const emulator_object base_address, + const EMULATOR_CAST(EmulatorTraits::ULONG_PTR, ULONG_PTR) /*zero_bits*/, + const EMULATOR_CAST(EmulatorTraits::SIZE_T, SIZE_T) /*commit_size*/, + const emulator_object /*section_offset*/, + const emulator_object::SIZE_T, SIZE_T)> view_size, + const SECTION_INHERIT /*inherit_disposition*/, const ULONG /*allocation_type*/, const ULONG /*win32_protect*/) + { + if (process_handle != CURRENT_PROCESS) + { + return STATUS_INVALID_HANDLE; + } + + if (section_handle == SHARED_SECTION) + { + constexpr auto shared_section_size = 0x10000; + + const auto address = c.emu.find_free_allocation_base(shared_section_size); + c.emu.allocate_memory(address, shared_section_size, memory_permission::read_write); + + const std::u16string_view windows_dir = c.proc.kusd.get().NtSystemRoot.arr; + const auto windows_dir_size = windows_dir.size() * 2; + + constexpr auto windows_dir_offset = 0x10; + c.emu.write_memory(address + 8, windows_dir_offset); + + const auto obj_address = address + windows_dir_offset; + + const emulator_object>> windir_obj{c.emu, obj_address}; + windir_obj.access([&](UNICODE_STRING>& ucs) { + const auto dir_address = kusd_mmio::address() + offsetof(KUSER_SHARED_DATA64, NtSystemRoot); + + ucs.Buffer = dir_address - obj_address; + ucs.Length = static_cast(windows_dir_size); + ucs.MaximumLength = ucs.Length; + }); + + const emulator_object>> sysdir_obj{c.emu, windir_obj.value() + + windir_obj.size()}; + sysdir_obj.access([&](UNICODE_STRING>& ucs) + + { + c.proc.base_allocator.make_unicode_string(ucs, u"C:\\WINDOWS\\System32"); + ucs.Buffer = ucs.Buffer - obj_address; + }); + + const emulator_object>> base_dir_obj{c.emu, sysdir_obj.value() + + sysdir_obj.size()}; + base_dir_obj.access([&](UNICODE_STRING>& ucs) { + c.proc.base_allocator.make_unicode_string(ucs, u"\\Sessions\\1\\BaseNamedObjects"); + ucs.Buffer = ucs.Buffer - obj_address; + }); + + if (view_size) + { + view_size.write(shared_section_size); + } + + base_address.write(address); + + return STATUS_SUCCESS; + } + + const auto section_entry = c.proc.sections.get(section_handle); + if (!section_entry) + { + return STATUS_INVALID_HANDLE; + } + + if (section_entry->is_image()) + { + const auto binary = c.proc.mod_manager.map_module(section_entry->file_name, c.win_emu.log); + if (!binary) + { + return STATUS_FILE_INVALID; + } + + std::u16string wide_name(binary->name.begin(), binary->name.end()); + section_entry->name = utils::string::to_lower_consume(wide_name); + + if (view_size.value()) + { + view_size.write(binary->size_of_image); + } + + base_address.write(binary->image_base); + + return STATUS_SUCCESS; + } + + uint64_t size = section_entry->maximum_size; + std::vector file_data{}; + + if (!section_entry->file_name.empty()) + { + if (!utils::io::read_file(section_entry->file_name, &file_data)) + { + return STATUS_INVALID_PARAMETER; + } + + size = page_align_up(file_data.size()); + } + + const auto protection = map_nt_to_emulator_protection(section_entry->section_page_protection); + const auto address = c.emu.allocate_memory(size, protection); + + if (!file_data.empty()) + { + c.emu.write_memory(address, file_data.data(), file_data.size()); + } + + if (view_size) + { + view_size.write(size); + } + + base_address.write(address); + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtCreateIoCompletion( + const syscall_context& c, const emulator_object event_handle, const ACCESS_MASK desired_access, + const emulator_object>> object_attributes, + const uint32_t /*number_of_concurrent_threads*/) + { + return handle_NtCreateEvent(c, event_handle, desired_access, object_attributes, NotificationEvent, FALSE); + } + + NTSTATUS handle_NtCreateWaitCompletionPacket( + const syscall_context& c, const emulator_object event_handle, const ACCESS_MASK desired_access, + const emulator_object>> object_attributes) + { + return handle_NtCreateEvent(c, event_handle, desired_access, object_attributes, NotificationEvent, FALSE); + } + + NTSTATUS handle_NtQueryVirtualMemory(const syscall_context& c, const handle process_handle, + const uint64_t base_address, const uint32_t info_class, + const uint64_t memory_information, const uint32_t memory_information_length, + const emulator_object return_length) + { + if (process_handle != CURRENT_PROCESS) + { + return STATUS_NOT_SUPPORTED; + } + + if (info_class == MemoryWorkingSetExInformation || info_class == MemoryImageExtensionInformation) + { + return STATUS_NOT_SUPPORTED; + } + + if (info_class == MemoryBasicInformation) + { + if (return_length) + { + return_length.write(sizeof(EMU_MEMORY_BASIC_INFORMATION64)); + } + + if (memory_information_length != sizeof(EMU_MEMORY_BASIC_INFORMATION64)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object info{c.emu, memory_information}; + + info.access([&](EMU_MEMORY_BASIC_INFORMATION64& image_info) { + const auto region_info = c.emu.get_region_info(base_address); + + assert(!region_info.is_committed || region_info.is_reserved); + + image_info.BaseAddress = reinterpret_cast(region_info.start); + image_info.AllocationBase = reinterpret_cast(region_info.allocation_base); + image_info.AllocationProtect = 0; + image_info.PartitionId = 0; + image_info.RegionSize = region_info.length; + image_info.State = + region_info.is_committed ? MEM_COMMIT : (region_info.is_reserved ? MEM_RESERVE : MEM_FREE); + image_info.Protect = map_emulator_to_nt_protection(region_info.permissions); + image_info.Type = MEM_PRIVATE; + }); + + return STATUS_SUCCESS; + } + + if (info_class == MemoryImageInformation) + { + if (return_length) + { + return_length.write(sizeof(MEMORY_IMAGE_INFORMATION64)); + } + + if (memory_information_length != sizeof(MEMORY_IMAGE_INFORMATION64)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const auto mod = c.proc.mod_manager.find_by_address(base_address); + if (!mod) + { + printf("Bad address for memory image request: 0x%" PRIx64 "\n", base_address); + return STATUS_INVALID_ADDRESS; + } + + const emulator_object info{c.emu, memory_information}; + + info.access([&](MEMORY_IMAGE_INFORMATION64& image_info) { + image_info.ImageBase = reinterpret_cast(mod->image_base); + image_info.SizeOfImage = mod->size_of_image; + image_info.ImageFlags = 0; + }); + + return STATUS_SUCCESS; + } + + if (info_class == MemoryRegionInformation) + { + if (return_length) + { + return_length.write(sizeof(MEMORY_REGION_INFORMATION64)); + } + + if (memory_information_length != sizeof(MEMORY_REGION_INFORMATION64)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const auto region_info = c.emu.get_region_info(base_address); + if (!region_info.is_reserved) + { + return STATUS_INVALID_ADDRESS; + } + + const emulator_object info{c.emu, memory_information}; + + info.access([&](MEMORY_REGION_INFORMATION64& image_info) { + memset(&image_info, 0, sizeof(image_info)); + + image_info.AllocationBase = reinterpret_cast(region_info.allocation_base); + image_info.AllocationProtect = 0; + image_info.PartitionId = 0; + image_info.RegionSize = region_info.allocation_length; + image_info.Reserved = 0x10; + }); + + return STATUS_SUCCESS; + } + + printf("Unsupported memory info class: %X\n", info_class); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtQuerySystemInformation(const syscall_context& c, const uint32_t info_class, + const uint64_t system_information, + const uint32_t system_information_length, + const emulator_object return_length) + { + if (info_class == SystemFlushInformation || info_class == SystemHypervisorSharedPageInformation || + info_class == 250 // Build 27744 + ) + { + return STATUS_NOT_SUPPORTED; + } + + if (info_class == SystemTimeOfDayInformation) + { + if (return_length) + { + return_length.write(sizeof(SYSTEM_TIMEOFDAY_INFORMATION64)); + } + + if (system_information_length != sizeof(SYSTEM_TIMEOFDAY_INFORMATION64)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + const emulator_object info_obj{c.emu, system_information}; + + info_obj.access([&](SYSTEM_TIMEOFDAY_INFORMATION64& info) { + info.BootTime.QuadPart = 0; + // TODO: Fill + }); + + return STATUS_SUCCESS; + } + + if (info_class == SystemRangeStartInformation) + { + if (return_length) + { + return_length.write(sizeof(SYSTEM_RANGE_START_INFORMATION64)); + } + + if (system_information_length != sizeof(SYSTEM_RANGE_START_INFORMATION64)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + const emulator_object info_obj{c.emu, system_information}; + + info_obj.access( + [&](SYSTEM_RANGE_START_INFORMATION64& info) { info.SystemRangeStart = 0xFFFF800000000000; }); + + return STATUS_SUCCESS; + } + + if (info_class == SystemProcessorInformation) + { + if (return_length) + { + return_length.write(sizeof(SYSTEM_PROCESSOR_INFORMATION64)); + } + + if (system_information_length != sizeof(SYSTEM_PROCESSOR_INFORMATION64)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + const emulator_object info_obj{c.emu, system_information}; + + info_obj.access([&](SYSTEM_PROCESSOR_INFORMATION64& info) { + memset(&info, 0, sizeof(info)); + info.MaximumProcessors = 2; + info.ProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64; + }); + + return STATUS_SUCCESS; + } + + if (info_class == SystemNumaProcessorMap) + { + if (return_length) + { + return_length.write(sizeof(SYSTEM_NUMA_INFORMATION64)); + } + + if (system_information_length != sizeof(SYSTEM_NUMA_INFORMATION64)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + const emulator_object info_obj{c.emu, system_information}; + + info_obj.access([&](SYSTEM_NUMA_INFORMATION64& info) { + memset(&info, 0, sizeof(info)); + info.ActiveProcessorsGroupAffinity->Mask = 0xFFF; + info.AvailableMemory[0] = 0xFFF; + info.Pad[0] = 0xFFF; + }); + + return STATUS_SUCCESS; + } + + if (info_class == SystemErrorPortTimeouts) + { + if (return_length) + { + return_length.write(sizeof(SYSTEM_ERROR_PORT_TIMEOUTS)); + } + + if (system_information_length != sizeof(SYSTEM_ERROR_PORT_TIMEOUTS)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + const emulator_object info_obj{c.emu, system_information}; + + info_obj.access([&](SYSTEM_ERROR_PORT_TIMEOUTS& info) { + info.StartTimeout = 0; + info.CommTimeout = 0; + }); + + return STATUS_SUCCESS; + } + + if (info_class != SystemBasicInformation && info_class != SystemEmulationBasicInformation) + { + printf("Unsupported system info class: %X\n", info_class); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + if (return_length) + { + return_length.write(sizeof(SYSTEM_BASIC_INFORMATION64)); + } + + if (system_information_length != sizeof(SYSTEM_BASIC_INFORMATION64)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + const emulator_object info{c.emu, system_information}; + + info.access([&](SYSTEM_BASIC_INFORMATION64& basic_info) { + basic_info.Reserved = 0; + basic_info.TimerResolution = 0x0002625a; + basic_info.PageSize = 0x1000; + basic_info.LowestPhysicalPageNumber = 0x00000001; + basic_info.HighestPhysicalPageNumber = 0x00c9c7ff; + basic_info.AllocationGranularity = 0x10000; + basic_info.MinimumUserModeAddress = 0x0000000000010000; + basic_info.MaximumUserModeAddress = 0x00007ffffffeffff; + basic_info.ActiveProcessorsAffinityMask = 0x0000000000000fff; + basic_info.NumberOfProcessors = 1; + }); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtDuplicateObject(const syscall_context& /*c*/, const handle source_process_handle, + const handle source_handle, const handle target_process_handle, + const emulator_object target_handle, const ACCESS_MASK /*desired_access*/, + const ULONG /*handle_attributes*/, const ULONG /*options*/) + { + if (source_process_handle != CURRENT_PROCESS || target_process_handle != CURRENT_PROCESS) + { + return STATUS_NOT_SUPPORTED; + } + + if (source_handle.value.is_pseudo) + { + target_handle.write(source_handle); + return STATUS_SUCCESS; + } + + puts("Duplicating non-pseudo object not supported yet!"); + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtQuerySystemInformationEx(const syscall_context& c, const uint32_t info_class, + const uint64_t input_buffer, const uint32_t input_buffer_length, + const uint64_t system_information, + const uint32_t system_information_length, + const emulator_object return_length) + { + if (info_class == SystemFlushInformation || info_class == SystemFeatureConfigurationInformation || + info_class == SystemSupportedProcessorArchitectures2 || + info_class == SystemFeatureConfigurationSectionInformation) + { + // printf("Unsupported, but allowed system info class: %X\n", info_class); + return STATUS_NOT_SUPPORTED; + } + + if (info_class == SystemLogicalProcessorAndGroupInformation) + { + void* buffer = calloc(1, input_buffer_length); + void* res_buff = calloc(1, system_information_length); + c.emu.read_memory(input_buffer, buffer, input_buffer_length); + + NTSTATUS code = STATUS_SUCCESS; + + return_length.access([&](uint32_t& len) { + (void)len; #ifdef OS_WINDOWS - code = NtQuerySystemInformationEx(static_cast(info_class), buffer, - input_buffer_length, - res_buff, - system_information_length, reinterpret_cast(&len)); + code = NtQuerySystemInformationEx(static_cast(info_class), buffer, + input_buffer_length, res_buff, system_information_length, + reinterpret_cast(&len)); #else - // TODO: unsupported - code = STATUS_SUCCESS; + // TODO: unsupported + code = STATUS_SUCCESS; #endif - }); - - if (code == 0) - { - c.emu.write_memory(system_information, res_buff, return_length.read()); - } - - free(buffer); - free(res_buff); - - return code; - } - - if (info_class != SystemBasicInformation && info_class != SystemEmulationBasicInformation) - { - printf("Unsupported system info ex class: %X\n", info_class); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - if (return_length) - { - return_length.write(sizeof(SYSTEM_BASIC_INFORMATION64)); - } - - if (system_information_length != sizeof(SYSTEM_BASIC_INFORMATION64)) - { - return STATUS_BUFFER_TOO_SMALL; - } - - const emulator_object info{c.emu, system_information}; - - info.access([&](SYSTEM_BASIC_INFORMATION64& basic_info) - { - basic_info.Reserved = 0; - basic_info.TimerResolution = 0x0002625a; - basic_info.PageSize = 0x1000; - basic_info.LowestPhysicalPageNumber = 0x00000001; - basic_info.HighestPhysicalPageNumber = 0x00c9c7ff; - basic_info.AllocationGranularity = 0x10000; - basic_info.MinimumUserModeAddress = 0x0000000000010000; - basic_info.MaximumUserModeAddress = 0x00007ffffffeffff; - basic_info.ActiveProcessorsAffinityMask = 0x0000000000000fff; - basic_info.NumberOfProcessors = 1; - }); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtQueryInformationProcess(const syscall_context& c, const handle process_handle, - const uint32_t info_class, const uint64_t process_information, - const uint32_t process_information_length, - const emulator_object return_length) - { - if (process_handle != CURRENT_PROCESS) - { - return STATUS_NOT_SUPPORTED; - } - - if (info_class == ProcessImageInformation) - { - if (return_length) - { - return_length.write(sizeof(SECTION_IMAGE_INFORMATION>)); - } - - if (process_information_length != sizeof(SECTION_IMAGE_INFORMATION>)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object>> info{c.emu, process_information}; - info.access([&](SECTION_IMAGE_INFORMATION>& i) - { - const auto& mod = *c.proc.executable; - - const emulator_object dos_header_obj{c.emu, mod.image_base}; - const auto dos_header = dos_header_obj.read(); - - const emulator_object> nt_headers_obj{ - c.emu, mod.image_base + dos_header.e_lfanew - }; - const auto nt_headers = nt_headers_obj.read(); - - const auto& file_header = nt_headers.FileHeader; - const auto& optional_header = nt_headers.OptionalHeader; - - i.TransferAddress = 0; - i.MaximumStackSize = optional_header.SizeOfStackReserve; - i.CommittedStackSize = optional_header.SizeOfStackCommit; - i.SubSystemType = optional_header.Subsystem; - i.SubSystemMajorVersion = optional_header.MajorSubsystemVersion; - i.SubSystemMinorVersion = optional_header.MinorSubsystemVersion; - i.MajorOperatingSystemVersion = optional_header.MajorOperatingSystemVersion; - i.MinorOperatingSystemVersion = optional_header.MinorOperatingSystemVersion; - i.ImageCharacteristics = file_header.Characteristics; - i.DllCharacteristics = optional_header.DllCharacteristics; - i.Machine = file_header.Machine; - i.ImageContainsCode = TRUE; - i.ImageFlags = 0; // TODO - i.ImageFileSize = optional_header.SizeOfImage; - i.LoaderFlags = optional_header.LoaderFlags; - i.CheckSum = optional_header.CheckSum; - }); - - return STATUS_SUCCESS; - } - - if (info_class == ProcessCookie) - { - if (return_length) - { - return_length.write(sizeof(uint32_t)); - } - - if (process_information_length != sizeof(uint32_t)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object info{c.emu, process_information}; - info.write(0x01234567); - - return STATUS_SUCCESS; - } - - if (info_class == ProcessDebugPort) - { - if (return_length) - { - return_length.write(sizeof(EmulatorTraits::PVOID)); - } - - if (process_information_length != sizeof(EmulatorTraits::PVOID)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object::PVOID> info{c.emu, process_information}; - info.write(0); - - return STATUS_SUCCESS; - } - - if (info_class == ProcessDefaultHardErrorMode || info_class == ProcessWx86Information) - { - if (return_length) - { - return_length.write(sizeof(ULONG)); - } - - if (process_information_length != sizeof(ULONG)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object info{c.emu, process_information}; - info.write(0); - - return STATUS_SUCCESS; - } - - if (info_class == ProcessEnclaveInformation - || info_class == ProcessMitigationPolicy) - { - return STATUS_NOT_SUPPORTED; - } - - if (info_class == ProcessTimes) - { - if (return_length) - { - return_length.write(sizeof(KERNEL_USER_TIMES)); - } - - if (process_information_length != sizeof(KERNEL_USER_TIMES)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object info{c.emu, process_information}; - info.write(KERNEL_USER_TIMES{}); - - return STATUS_SUCCESS; - } - - if (info_class == ProcessBasicInformation) - { - if (return_length) - { - return_length.write(sizeof(PROCESS_BASIC_INFORMATION64)); - } - - if (process_information_length != sizeof(PROCESS_BASIC_INFORMATION64)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object info{c.emu, process_information}; - info.access([&](PROCESS_BASIC_INFORMATION64& basic_info) - { - basic_info.PebBaseAddress = c.proc.peb.ptr(); - basic_info.UniqueProcessId = 1; - }); - - return STATUS_SUCCESS; - } - - if (info_class == ProcessImageFileNameWin32) - { - const auto peb = c.proc.peb.read(); - emulator_object proc_params{c.emu, peb.ProcessParameters}; - const auto params = proc_params.read(); - const auto length = params.ImagePathName.Length + sizeof(UNICODE_STRING>) + 2; - - if (return_length) - { - return_length.write(static_cast(length)); - } - - if (process_information_length < length) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object>> info{c.emu, process_information}; - info.access([&](UNICODE_STRING>& str) - { - const auto buffer_start = static_cast(process_information) + sizeof(UNICODE_STRING< - EmulatorTraits>); - const auto string = read_unicode_string(c.emu, params.ImagePathName); - c.emu.write_memory(buffer_start, string.c_str(), (string.size() + 1) * 2); - str.Length = params.ImagePathName.Length; - str.MaximumLength = str.Length; - str.Buffer = buffer_start; - }); - - return STATUS_SUCCESS; - } - - printf("Unsupported process info class: %X\n", info_class); - c.emu.stop(); - - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtQueryInformationThread(const syscall_context& c, const handle thread_handle, - const uint32_t info_class, const uint64_t thread_information, - const uint32_t thread_information_length, - const emulator_object return_length) - { - const auto* thread = thread_handle == CURRENT_THREAD - ? c.proc.active_thread - : c.proc.threads.get(thread_handle); - - if (!thread) - { - return STATUS_INVALID_HANDLE; - } - - if (info_class == ThreadBasicInformation) - { - if (return_length) - { - return_length.write(sizeof(THREAD_BASIC_INFORMATION64)); - } - - if (thread_information_length != sizeof(THREAD_BASIC_INFORMATION64)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object info{c.emu, thread_information}; - info.access([&](THREAD_BASIC_INFORMATION64& i) - { - i.TebBaseAddress = thread->teb->ptr(); - i.ClientId = thread->teb->read().ClientId; - }); - - return STATUS_SUCCESS; - } - - if (info_class == ThreadAmILastThread) - { - if (return_length) - { - return_length.write(sizeof(ULONG)); - } - - if (thread_information_length != sizeof(ULONG)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object info{c.emu, thread_information}; - info.write(c.proc.threads.size() <= 1); - - return STATUS_SUCCESS; - } - - if (info_class == ThreadQuerySetWin32StartAddress) - { - if (return_length) - { - return_length.write(sizeof(EmulatorTraits::PVOID)); - } - - if (thread_information_length != sizeof(EmulatorTraits::PVOID)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object::PVOID> info{c.emu, thread_information}; - info.write(thread->start_address); - - return STATUS_SUCCESS; - } - - printf("Unsupported thread query info class: %X\n", info_class); - c.emu.stop(); - - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtSetInformationFile(const syscall_context& c, const handle file_handle, - const emulator_object>> io_status_block, - const uint64_t file_information, - const ULONG length, const FILE_INFORMATION_CLASS info_class) - { - const auto* f = c.proc.files.get(file_handle); - if (!f) - { - return STATUS_INVALID_HANDLE; - } - - if (info_class == FilePositionInformation) - { - if (!f->handle) - { - return STATUS_NOT_SUPPORTED; - } - - if (io_status_block) - { - IO_STATUS_BLOCK> block{}; - block.Information = sizeof(FILE_POSITION_INFORMATION); - io_status_block.write(block); - } - - if (length != sizeof(FILE_POSITION_INFORMATION)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object info{c.emu, file_information}; - const auto i = info.read(); - - if (!f->handle.seek_to(i.CurrentByteOffset.QuadPart)) - { - return STATUS_INVALID_PARAMETER; - } - - return STATUS_SUCCESS; - } - - printf("Unsupported set file info class: %X\n", info_class); - c.emu.stop(); - - return STATUS_NOT_SUPPORTED; - } - - std::vector scan_directory(const std::filesystem::path& dir) - { - std::vector files{ - {"."}, - {".."}, - }; - - for (const auto& file : std::filesystem::directory_iterator(dir)) - { - files.emplace_back(file_entry{.file_path = file.path().filename(),}); - } - - return files; - } - - template - NTSTATUS handle_file_enumeration(const syscall_context& c, - const emulator_object>> io_status_block, - const uint64_t file_information, const uint32_t length, const ULONG query_flags, - file* f) - { - if (!f->enumeration_state || query_flags & SL_RESTART_SCAN) - { - f->enumeration_state.emplace(file_enumeration_state{}); - f->enumeration_state->files = scan_directory(f->name); - } - - auto& enum_state = *f->enumeration_state; - - size_t current_offset{0}; - emulator_object object{c.emu}; - - size_t current_index = enum_state.current_index; - - do - { - if (current_index >= enum_state.files.size()) - { - break; - } - - const auto new_offset = align_up(current_offset, 8); - const auto& current_file = enum_state.files[current_index]; - const auto file_name = current_file.file_path.u16string(); - const auto required_size = sizeof(T) + (file_name.size() * 2) - 2; - const auto end_offset = new_offset + required_size; - - if (end_offset > length) - { - if (current_offset == 0) - { - IO_STATUS_BLOCK> block{}; - block.Information = end_offset; - io_status_block.write(block); - - return STATUS_BUFFER_OVERFLOW; - } - - break; - } - - if (object) - { - const auto object_offset = object.value() - file_information; - - object.access([&](T& dir_info) - { - dir_info.NextEntryOffset = static_cast(new_offset - object_offset); - }); - } - - T info{}; - info.NextEntryOffset = 0; - info.FileIndex = static_cast(current_index); - info.FileAttributes = FILE_ATTRIBUTE_NORMAL; - info.FileNameLength = static_cast(file_name.size() * 2); - - object.set_address(file_information + new_offset); - object.write(info); - - c.emu.write_memory(object.value() + offsetof(T, FileName), file_name.data(), - info.FileNameLength); - - ++current_index; - current_offset = end_offset; - } - while ((query_flags & SL_RETURN_SINGLE_ENTRY) == 0); - - if ((query_flags & SL_NO_CURSOR_UPDATE) == 0) - { - enum_state.current_index = current_index; - } - - IO_STATUS_BLOCK> block{}; - block.Information = current_offset; - io_status_block.write(block); - - return current_index < enum_state.files.size() ? STATUS_SUCCESS : STATUS_NO_MORE_FILES; - } - - NTSTATUS handle_NtQueryDirectoryFileEx(const syscall_context& c, const handle file_handle, - const handle /*event_handle*/, - const emulator_pointer /*PIO_APC_ROUTINE*/ /*apc_routine*/, - const emulator_pointer /*apc_context*/, - const emulator_object>> - io_status_block, - const uint64_t file_information, const uint32_t length, - const uint32_t info_class, const ULONG query_flags, - const emulator_object>> /*file_name*/) - { - auto* f = c.proc.files.get(file_handle); - if (!f || !f->is_directory()) - { - return STATUS_INVALID_HANDLE; - } - - if (info_class == FileDirectoryInformation) - { - return handle_file_enumeration(c, io_status_block, file_information, length, - query_flags, f); - } - - if (info_class == FileFullDirectoryInformation) - { - return handle_file_enumeration(c, io_status_block, file_information, length, - query_flags, f); - } - - if (info_class == FileBothDirectoryInformation) - { - return handle_file_enumeration(c, io_status_block, file_information, length, - query_flags, f); - } - - printf("Unsupported query directory file info class: %X\n", info_class); - c.emu.stop(); - - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtQueryInformationFile(const syscall_context& c, const handle file_handle, - const emulator_object>> - io_status_block, - const uint64_t file_information, const uint32_t length, - const uint32_t info_class) - { - const auto* f = c.proc.files.get(file_handle); - if (!f) - { - return STATUS_INVALID_HANDLE; - } - - if (info_class == FileNameInformation) - { - const auto required_length = sizeof(FILE_NAME_INFORMATION) + (f->name.size() * 2); - - if (io_status_block) - { - IO_STATUS_BLOCK> block{}; - block.Information = sizeof(FILE_NAME_INFORMATION) + required_length; - io_status_block.write(block); - } - - if (length != required_length) - { - return STATUS_BUFFER_OVERFLOW; - } - - c.emu.write_memory(file_information, FILE_NAME_INFORMATION{ - .FileNameLength = static_cast(f->name.size() * 2), - .FileName = {}, - }); - - c.emu.write_memory(file_information + offsetof(FILE_NAME_INFORMATION, FileName), f->name.c_str(), - (f->name.size() + 1) * 2); - - return STATUS_SUCCESS; - } - - if (info_class == FileStandardInformation) - { - if (io_status_block) - { - IO_STATUS_BLOCK> block{}; - block.Information = sizeof(FILE_STANDARD_INFORMATION); - io_status_block.write(block); - } - - if (length != sizeof(FILE_STANDARD_INFORMATION)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object info{c.emu, file_information}; - FILE_STANDARD_INFORMATION i{}; - i.Directory = f->is_directory() ? TRUE : FALSE; - - if (f->handle) - { - i.EndOfFile.QuadPart = f->handle.size(); - } - - info.write(i); - - return STATUS_SUCCESS; - } - - if (info_class == FilePositionInformation) - { - if (!f->handle) - { - return STATUS_NOT_SUPPORTED; - } - - if (io_status_block) - { - IO_STATUS_BLOCK> block{}; - block.Information = sizeof(FILE_POSITION_INFORMATION); - io_status_block.write(block); - } - - if (length != sizeof(FILE_POSITION_INFORMATION)) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object info{c.emu, file_information}; - FILE_POSITION_INFORMATION i{}; - - i.CurrentByteOffset.QuadPart = f->handle.tell(); - - info.write(i); - - return STATUS_SUCCESS; - } - - printf("Unsupported query file info class: %X\n", info_class); - c.emu.stop(); - - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtSetInformationProcess(const syscall_context& c, const handle process_handle, - const uint32_t info_class, const uint64_t process_information, - const uint32_t process_information_length) - { - if (process_handle != CURRENT_PROCESS) - { - return STATUS_NOT_SUPPORTED; - } - - if (info_class == ProcessSchedulerSharedData - || info_class == ProcessConsoleHostProcess - || info_class == ProcessFaultInformation - || info_class == ProcessDefaultHardErrorMode - || info_class == ProcessRaiseUMExceptionOnInvalidHandleClose) - { - return STATUS_SUCCESS; - } - - if (info_class == ProcessTlsInformation) - { - constexpr auto thread_data_offset = offsetof(PROCESS_TLS_INFO, ThreadData); - if (process_information_length < thread_data_offset) - { - return STATUS_BUFFER_OVERFLOW; - } - - const emulator_object data{c.emu, process_information + thread_data_offset}; - - PROCESS_TLS_INFO tls_info{}; - c.emu.read_memory(process_information, &tls_info, thread_data_offset); - - for (uint32_t i = 0; i < tls_info.ThreadDataCount; ++i) - { - auto entry = data.read(i); - - const auto _ = utils::finally([&] - { - data.write(entry, i); - }); - - if (i >= c.proc.threads.size()) - { - entry.Flags = 0; - continue; - } - - auto thread_iterator = c.proc.threads.begin(); - std::advance(thread_iterator, i); - - entry.Flags = 2; - - thread_iterator->second.teb->access([&](TEB64& teb) - { - entry.ThreadId = teb.ClientId.UniqueThread; - - const auto tls_vector = teb.ThreadLocalStoragePointer; - - if (tls_info.TlsRequest == ProcessTlsReplaceIndex) - { - const auto tls_entry_ptr = tls_vector + tls_info.TlsIndex; - - const auto old_entry = c.emu.read_memory::PVOID>(tls_entry_ptr); - c.emu.write_memory::PVOID>(tls_entry_ptr, entry.TlsModulePointer); - - entry.TlsModulePointer = old_entry; - } - else if (tls_info.TlsRequest == ProcessTlsReplaceVector) - { - const auto new_tls_vector = entry.TlsVector; - - for (uint32_t index = 0; index < tls_info.TlsVectorLength; ++index) - { - const auto old_entry = c.emu.read_memory(tls_vector + index); - c.emu.write_memory(new_tls_vector + index, old_entry); - } - - teb.ThreadLocalStoragePointer = new_tls_vector; - entry.TlsVector = tls_vector; - } - }); - } - - return STATUS_SUCCESS; - } - - printf("Unsupported info process class: %X\n", info_class); - c.emu.stop(); - - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtSetInformationKey() - { - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtApphelpCacheControl() - { - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtProtectVirtualMemory(const syscall_context& c, const handle process_handle, - const emulator_object base_address, - const emulator_object bytes_to_protect, - const uint32_t protection, - const emulator_object old_protection) - { - if (process_handle != CURRENT_PROCESS) - { - return STATUS_NOT_SUPPORTED; - } - - const auto orig_start = base_address.read(); - const auto orig_length = bytes_to_protect.read(); - - const auto aligned_start = page_align_down(orig_start); - const auto aligned_length = page_align_up(orig_start + orig_length) - aligned_start; - - base_address.write(aligned_start); - bytes_to_protect.write(static_cast(aligned_length)); - - const auto requested_protection = map_nt_to_emulator_protection(protection); - - c.win_emu.log.print(color::dark_gray, "--> Changing protection at 0x%" PRIx64 "-0x%" PRIx64 " to %s\n", - aligned_start, - aligned_start + aligned_length, get_permission_string(requested_protection).c_str()); - - memory_permission old_protection_value{}; - - try - { - c.emu.protect_memory(aligned_start, aligned_length, requested_protection, &old_protection_value); - } - catch (...) - { - return STATUS_INVALID_ADDRESS; - } - - const auto current_protection = map_emulator_to_nt_protection(old_protection_value); - old_protection.write(current_protection); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtOpenDirectoryObject(const syscall_context& c, - const emulator_object directory_handle, - const ACCESS_MASK /*desired_access*/, - const emulator_object>> - object_attributes) - { - const auto attributes = object_attributes.read(); - const auto object_name = read_unicode_string( - c.emu, reinterpret_cast>*>(attributes.ObjectName)); - - if (object_name == u"\\KnownDlls") - { - directory_handle.write(KNOWN_DLLS_DIRECTORY); - return STATUS_SUCCESS; - } - - if (object_name == u"\\Sessions\\1\\BaseNamedObjects") - { - directory_handle.write(BASE_NAMED_OBJECTS_DIRECTORY); - return STATUS_SUCCESS; - } - - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtOpenSymbolicLinkObject(const syscall_context& c, const emulator_object link_handle, - ACCESS_MASK /*desired_access*/, - const emulator_object>> - object_attributes) - { - const auto attributes = object_attributes.read(); - const auto object_name = read_unicode_string( - c.emu, reinterpret_cast>*>(attributes.ObjectName)); - - if (object_name == u"KnownDllPath") - { - link_handle.write(KNOWN_DLLS_SYMLINK); - return STATUS_SUCCESS; - } - - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtQuerySymbolicLinkObject(const syscall_context& c, const handle link_handle, - const emulator_object>> - link_target, - const emulator_object returned_length) - { - if (link_handle == KNOWN_DLLS_SYMLINK) - { - constexpr std::u16string_view system32 = u"C:\\WINDOWS\\System32"; - constexpr auto str_length = system32.size() * 2; - constexpr auto max_length = str_length + 2; - - returned_length.write(max_length); - - bool too_small = false; - link_target.access([&](UNICODE_STRING>& str) - { - if (str.MaximumLength < max_length) - { - too_small = true; - return; - } - - str.Length = str_length; - c.emu.write_memory(str.Buffer, system32.data(), max_length); - }); - - return too_small - ? STATUS_BUFFER_TOO_SMALL - : STATUS_SUCCESS; - } - - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtAllocateVirtualMemoryEx(const syscall_context& c, const handle process_handle, - const emulator_object base_address, - const emulator_object bytes_to_allocate, - const uint32_t allocation_type, - const uint32_t page_protection) - { - if (process_handle != CURRENT_PROCESS) - { - return STATUS_NOT_SUPPORTED; - } - - auto allocation_bytes = bytes_to_allocate.read(); - allocation_bytes = page_align_up(allocation_bytes); - bytes_to_allocate.write(allocation_bytes); - - const auto protection = map_nt_to_emulator_protection(page_protection); - - auto potential_base = base_address.read(); - if (!potential_base) - { - potential_base = c.emu.find_free_allocation_base(allocation_bytes); - } - - if (!potential_base) - { - return STATUS_MEMORY_NOT_ALLOCATED; - } - - base_address.write(potential_base); - - const bool reserve = allocation_type & MEM_RESERVE; - const bool commit = allocation_type & MEM_COMMIT; - - if ((allocation_type & ~(MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN)) || (!commit && !reserve)) - { - throw std::runtime_error("Unsupported allocation type!"); - } - - if (commit && !reserve && c.emu.commit_memory(potential_base, allocation_bytes, protection)) - { - return STATUS_SUCCESS; - } - - return c.emu.allocate_memory(potential_base, allocation_bytes, protection, !commit) - ? STATUS_SUCCESS - : STATUS_MEMORY_NOT_ALLOCATED; - } - - NTSTATUS handle_NtAllocateVirtualMemory(const syscall_context& c, const handle process_handle, - const emulator_object base_address, const uint64_t /*zero_bits*/, - const emulator_object bytes_to_allocate, - const uint32_t allocation_type, const uint32_t page_protection) - { - return handle_NtAllocateVirtualMemoryEx(c, process_handle, base_address, bytes_to_allocate, allocation_type, - page_protection); - } - - NTSTATUS handle_NtFreeVirtualMemory(const syscall_context& c, const handle process_handle, - const emulator_object base_address, - const emulator_object bytes_to_allocate, const uint32_t free_type) - { - if (process_handle != CURRENT_PROCESS) - { - return STATUS_NOT_SUPPORTED; - } - - const auto allocation_base = base_address.read(); - const auto allocation_size = bytes_to_allocate.read(); - - if (free_type & MEM_RELEASE) - { - return c.emu.release_memory(allocation_base, allocation_size) - ? STATUS_SUCCESS - : STATUS_MEMORY_NOT_ALLOCATED; - } - - if (free_type & MEM_DECOMMIT) - { - return c.emu.decommit_memory(allocation_base, allocation_size) - ? STATUS_SUCCESS - : STATUS_MEMORY_NOT_ALLOCATED; - } - - throw std::runtime_error("Bad free type"); - } - - NTSTATUS handle_NtCreateSection(const syscall_context& c, const emulator_object section_handle, - const ACCESS_MASK /*desired_access*/, - const emulator_object>> object_attributes, - const emulator_object maximum_size, - const ULONG section_page_protection, const ULONG allocation_attributes, - const handle file_handle) - { - section s{}; - s.section_page_protection = section_page_protection; - s.allocation_attributes = allocation_attributes; - - const auto* file = c.proc.files.get(file_handle); - if (file) - { - c.win_emu.log.print(color::dark_gray, "--> Section for file %s\n", u16_to_u8(file->name).c_str()); - s.file_name = file->name; - } - - if (object_attributes) - { - const auto attributes = object_attributes.read(); - if (attributes.ObjectName) - { - const auto name = read_unicode_string( - c.emu, reinterpret_cast>*>(attributes.ObjectName)); - c.win_emu.log.print(color::dark_gray, "--> Section with name %s\n", u16_to_u8(name).c_str()); - s.name = std::move(name); - } - } - - if (maximum_size) - { - maximum_size.access([&](ULARGE_INTEGER& large_int) - { - large_int.QuadPart = page_align_up(large_int.QuadPart); - s.maximum_size = large_int.QuadPart; - }); - } - else if (!file) - { - return STATUS_INVALID_PARAMETER; - } - - const auto h = c.proc.sections.store(std::move(s)); - section_handle.write(h); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtConnectPort(const syscall_context& c, const emulator_object client_port_handle, - const emulator_object>> server_port_name, - const emulator_object /*security_qos*/, - const emulator_object client_shared_memory, - const emulator_object /*server_shared_memory*/, - const emulator_object /*maximum_message_length*/, - const emulator_pointer connection_info, - const emulator_object connection_info_length) - { - auto port_name = read_unicode_string(c.emu, server_port_name); - c.win_emu.log.print(color::dark_gray, "NtConnectPort: %s\n", u16_to_u8(port_name).c_str()); - - port p{}; - p.name = std::move(port_name); - - if (connection_info) - { - std::vector zero_mem{}; - zero_mem.resize(connection_info_length.read(), 0); - c.emu.write_memory(connection_info, zero_mem.data(), zero_mem.size()); - } - - client_shared_memory.access([&](PORT_VIEW64& view) - { - p.view_base = c.emu.allocate_memory(view.ViewSize, memory_permission::read_write); - view.ViewBase = p.view_base; - view.ViewRemoteBase = view.ViewBase; - }); - - const auto handle = c.proc.ports.store(std::move(p)); - client_port_handle.write(handle); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtReadVirtualMemory(const syscall_context& c, const handle process_handle, - const emulator_pointer base_address, - const emulator_pointer buffer, const ULONG number_of_bytes_to_read, - const emulator_object number_of_bytes_read) - { - number_of_bytes_read.write(0); - - if (process_handle != CURRENT_PROCESS) - { - return STATUS_NOT_SUPPORTED; - } - - std::vector memory{}; - memory.resize(number_of_bytes_read); - - if (!c.emu.try_read_memory(base_address, memory.data(), memory.size())) - { - return STATUS_INVALID_ADDRESS; - } - - c.emu.write_memory(buffer, memory.data(), memory.size()); - number_of_bytes_read.write(number_of_bytes_to_read); - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtDeviceIoControlFile(const syscall_context& c, const handle file_handle, - const handle event, - const emulator_pointer /*PIO_APC_ROUTINE*/ apc_routine, - const emulator_pointer apc_context, - const emulator_object>> io_status_block, - const ULONG io_control_code, - const emulator_pointer input_buffer, - const ULONG input_buffer_length, const emulator_pointer output_buffer, - const ULONG output_buffer_length) - { - auto* device = c.proc.devices.get(file_handle); - if (!device) - { - return STATUS_INVALID_HANDLE; - } - - io_device_context context{c.emu}; - context.event = event; - context.apc_routine = apc_routine; - context.apc_context = apc_context; - context.io_status_block = io_status_block; - context.io_control_code = io_control_code; - context.input_buffer = input_buffer; - context.input_buffer_length = input_buffer_length; - context.output_buffer = output_buffer; - context.output_buffer_length = output_buffer_length; - - return device->execute_ioctl(c.win_emu, context); - } - - NTSTATUS handle_NtQueryWnfStateData() - { - //puts("NtQueryWnfStateData not supported"); - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtQueryWnfStateNameInformation() - { - //puts("NtQueryWnfStateNameInformation not supported"); - //return STATUS_NOT_SUPPORTED; - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtOpenThreadToken(const syscall_context&, const handle thread_handle, - const ACCESS_MASK /*desired_access*/, const BOOLEAN /*open_as_self*/, - const emulator_object token_handle) - { - if (thread_handle != CURRENT_THREAD) - { - return STATUS_NOT_SUPPORTED; - } - - token_handle.write(CURRENT_THREAD_TOKEN); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtOpenThreadTokenEx(const syscall_context& c, const handle thread_handle, - const ACCESS_MASK desired_access, const BOOLEAN open_as_self, - const ULONG /*handle_attributes*/, - const emulator_object token_handle) - { - return handle_NtOpenThreadToken(c, thread_handle, desired_access, open_as_self, token_handle); - } - - NTSTATUS handle_NtOpenProcessToken(const syscall_context&, const handle process_handle, - const ACCESS_MASK /*desired_access*/, const emulator_object token_handle) - { - if (process_handle != CURRENT_PROCESS) - { - return STATUS_NOT_SUPPORTED; - } - - token_handle.write(CURRENT_PROCESS_TOKEN); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtOpenProcessTokenEx(const syscall_context& c, const handle process_handle, - const ACCESS_MASK desired_access, const ULONG /*handle_attributes*/, - const emulator_object token_handle) - { - return handle_NtOpenProcessToken(c, process_handle, desired_access, token_handle); - } - - NTSTATUS handle_NtQuerySecurityAttributesToken() - { - //puts("NtQuerySecurityAttributesToken not supported"); - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtQueryLicenseValue() - { - //puts("NtQueryLicenseValue not supported"); - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtTestAlert() - { - //puts("NtTestAlert not supported"); - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtUserSystemParametersInfo() - { - return STATUS_NOT_SUPPORTED; - } - - TOKEN_TYPE get_token_type(const handle token_handle) - { - return token_handle == DUMMY_IMPERSONATION_TOKEN // - ? TokenImpersonation - : TokenPrimary; - } - - NTSTATUS handle_NtDuplicateToken(const syscall_context&, const handle existing_token_handle, - ACCESS_MASK /*desired_access*/, - const emulator_object>> - /*object_attributes*/, - const BOOLEAN /*effective_only*/, const TOKEN_TYPE type, - const emulator_object new_token_handle) - { - if (get_token_type(existing_token_handle) == type) - { - new_token_handle.write(existing_token_handle); - } - else if (type == TokenPrimary) - { - new_token_handle.write(CURRENT_PROCESS_TOKEN); - } - else - { - new_token_handle.write(DUMMY_IMPERSONATION_TOKEN); - } - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtQueryTimerResolution(const syscall_context&, const emulator_object maximum_time, - const emulator_object minimum_time, - const emulator_object current_time) - { - maximum_time.write_if_valid(0x0002625a); - minimum_time.write_if_valid(0x00001388); - current_time.write_if_valid(0x00002710); - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtQueryInformationToken(const syscall_context& c, const handle token_handle, - const TOKEN_INFORMATION_CLASS token_information_class, - const uint64_t token_information, const ULONG token_information_length, - const emulator_object return_length) - { - if (token_handle != CURRENT_PROCESS_TOKEN - && token_handle != CURRENT_THREAD_TOKEN - && token_handle != CURRENT_THREAD_EFFECTIVE_TOKEN - && token_handle != DUMMY_IMPERSONATION_TOKEN - ) - { - return STATUS_NOT_SUPPORTED; - } - - const uint8_t sid[] = - { - 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x05, 0x15, 0x00, 0x00, 0x00, 0x84, 0x94, - 0xD4, 0x04, 0x4B, 0x68, 0x42, 0x34, 0x23, - 0xBE, 0x69, 0x4E, 0xE9, 0x03, 0x00, 0x00, - }; - - if (token_information_class == TokenUser) - { - constexpr auto required_size = sizeof(sid) + 0x10; - return_length.write(required_size); - - if (required_size > token_information_length) - { - return STATUS_BUFFER_TOO_SMALL; - } - - TOKEN_USER64 user{}; - user.User.Attributes = 0; - user.User.Sid = token_information + 0x10; - - emulator_object{c.emu, token_information}.write(user); - c.emu.write_memory(token_information + 0x10, sid, sizeof(sid)); - return STATUS_SUCCESS; - } - - if (token_information_class == TokenType) - { - constexpr auto required_size = sizeof(TOKEN_TYPE); - return_length.write(required_size); - - if (required_size > token_information_length) - { - return STATUS_BUFFER_TOO_SMALL; - } - - emulator_object{c.emu, token_information}.write(get_token_type(token_handle)); - return STATUS_SUCCESS; - } - - if (token_information_class == TokenSessionId) - { - constexpr auto required_size = sizeof(ULONG); - return_length.write(required_size); - - if (required_size > token_information_length) - { - return STATUS_BUFFER_TOO_SMALL; - } - - emulator_object{c.emu, token_information}.write(1); - return STATUS_SUCCESS; - } - - if (token_information_class == TokenPrivateNameSpace) - { - constexpr auto required_size = sizeof(ULONG); - return_length.write(required_size); - - if (required_size > token_information_length) - { - return STATUS_BUFFER_TOO_SMALL; - } - - emulator_object{c.emu, token_information}.write(0); - return STATUS_SUCCESS; - } - - if (token_information_class == TokenUIAccess) - { - constexpr auto required_size = sizeof(ULONG); - return_length.write(required_size); - - if (required_size > token_information_length) - { - return STATUS_BUFFER_TOO_SMALL; - } - - emulator_object{c.emu, token_information}.write(1); - return STATUS_SUCCESS; - } - - if (token_information_class == TokenElevation) - { - constexpr auto required_size = sizeof(TOKEN_ELEVATION); - return_length.write(required_size); - - if (required_size > token_information_length) - { - return STATUS_BUFFER_TOO_SMALL; - } - - c.emu.write_memory(token_information, TOKEN_ELEVATION{ - .TokenIsElevated = 0, - }); - return STATUS_SUCCESS; - } - - if (token_information_class == TokenIsAppContainer) - { - constexpr auto required_size = sizeof(ULONG); - return_length.write(required_size); - - if (required_size > token_information_length) - { - return STATUS_BUFFER_TOO_SMALL; - } - - emulator_object{c.emu, token_information}.write(0); - return STATUS_SUCCESS; - } - - if (token_information_class == TokenStatistics) - { - constexpr auto required_size = sizeof(TOKEN_STATISTICS); - return_length.write(required_size); - - if (required_size > token_information_length) - { - return STATUS_BUFFER_TOO_SMALL; - } - - c.emu.write_memory(token_information, TOKEN_STATISTICS{}); - - return STATUS_SUCCESS; - } - - if (token_information_class == TokenSecurityAttributes) - { - constexpr auto required_size = sizeof(TOKEN_SECURITY_ATTRIBUTES_INFORMATION); - return_length.write(required_size); - - if (required_size > token_information_length) - { - return STATUS_BUFFER_TOO_SMALL; - } - - c.emu.write_memory(token_information, TOKEN_SECURITY_ATTRIBUTES_INFORMATION{ - .Version = 0, - .Reserved = {}, - .AttributeCount = 0, - .Attribute = {}, - }); - - return STATUS_SUCCESS; - } - - if (token_information_class == TokenIntegrityLevel) - { - constexpr auto required_size = sizeof(sid) + sizeof(TOKEN_MANDATORY_LABEL64); - return_length.write(required_size); - - if (required_size > token_information_length) - { - return STATUS_BUFFER_TOO_SMALL; - } - - TOKEN_MANDATORY_LABEL64 label{}; - label.Label.Attributes = 0; - label.Label.Sid = token_information + sizeof(TOKEN_MANDATORY_LABEL64); - - emulator_object{c.emu, token_information}.write(label); - c.emu.write_memory(token_information + sizeof(TOKEN_MANDATORY_LABEL64), sid, sizeof(sid)); - return STATUS_SUCCESS; - } - - if (token_information_class == TokenBnoIsolation) - { - constexpr auto required_size = sizeof(TOKEN_BNO_ISOLATION_INFORMATION64); - return_length.write(required_size); - - if (required_size > token_information_length) - { - return STATUS_BUFFER_TOO_SMALL; - } - - c.emu.write_memory(token_information, TOKEN_BNO_ISOLATION_INFORMATION64{ - .IsolationPrefix = 0, - .IsolationEnabled = 0, - }); - - return STATUS_SUCCESS; - } - - printf("Unsupported token info class: %X\n", token_information_class); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtDxgkIsFeatureEnabled() - { - //puts("NtDxgkIsFeatureEnabled not supported"); - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtQueryInstallUILanguage() - { - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtUserDisplayConfigGetDeviceInfo() - { - //puts("NtUserDisplayConfigGetDeviceInfo not supported"); - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtGdiInit(const syscall_context& c) - { - c.proc.peb.access([&](PEB64& peb) - { - if (!peb.GdiSharedHandleTable) - { - peb.GdiSharedHandleTable = reinterpret_cast::PVOID*>(c.proc.base_allocator.reserve - ().ptr()); - } - }); - - return STATUS_WAIT_1; - } - - NTSTATUS handle_NtGdiInit2(const syscall_context& c) - { - handle_NtGdiInit(c); - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtGetMUIRegistryInfo() - { - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtUserRegisterWindowMessage() - { - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtUserGetThreadState() - { - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtIsUILanguageComitted() - { - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtUpdateWnfStateData() - { - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtGetNlsSectionPtr() - { - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtAlpcSendWaitReceivePort(const syscall_context& c, const handle port_handle, - const ULONG /*flags*/, - const emulator_object /*send_message*/, - const emulator_object - /*send_message_attributes*/ - , - const emulator_object receive_message, - const emulator_object::SIZE_T> /*buffer_length*/, - const emulator_object - /*receive_message_attributes*/, - const emulator_object /*timeout*/) - { - const auto* port = c.proc.ports.get(port_handle); - if (!port) - { - return STATUS_INVALID_HANDLE; - } - - if (port->name != u"\\Windows\\ApiPort") - { - puts("!!! BAD PORT"); - return STATUS_NOT_SUPPORTED; - } - - // TODO: Fix this. This is broken and wrong. - - const emulator_object>> data{c.emu, receive_message.value() + 0x48}; - const auto dest = data.read(); - const auto base = dest.Base; - - const auto value = base + 0x10; - c.emu.write_memory(base + 8, &value, sizeof(value)); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtInitializeNlsFiles(const syscall_context& c, const emulator_object base_address, - const emulator_object default_locale_id, - const emulator_object /*default_casing_table_size*/) - { - const auto locale_file = utils::io::read_file(R"(C:\Windows\System32\locale.nls)"); - if (locale_file.empty()) - { - return STATUS_FILE_INVALID; - } - - const auto size = page_align_up(locale_file.size()); - const auto base = c.emu.allocate_memory(size, memory_permission::read); - c.emu.write_memory(base, locale_file.data(), locale_file.size()); - - base_address.write(base); - default_locale_id.write(0x407); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtContinue(const syscall_context& c, const emulator_object thread_context, - const BOOLEAN /*raise_alert*/) - { - c.write_status = false; - - const auto context = thread_context.read(); - context_frame::restore(c.emu, context); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtTerminateProcess(const syscall_context& c, const handle process_handle, - NTSTATUS exit_status) - { - if (process_handle == 0) - { - for (auto& thread : c.proc.threads | std::views::values) - { - if (&thread != c.proc.active_thread) - { - thread.exit_status = exit_status; - } - } - - return STATUS_SUCCESS; - } - - if (process_handle == CURRENT_PROCESS) - { - c.proc.exit_status = exit_status; - c.emu.stop(); - return STATUS_SUCCESS; - } - - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtReadFile(const syscall_context& c, const handle file_handle, const uint64_t /*event*/, - const uint64_t /*apc_routine*/, - const uint64_t /*apc_context*/, - const emulator_object>> io_status_block, - uint64_t buffer, const ULONG length, - const emulator_object /*byte_offset*/, - const emulator_object /*key*/) - { - const auto* f = c.proc.files.get(file_handle); - if (!f) - { - return STATUS_INVALID_HANDLE; - } - - std::string temp_buffer{}; - temp_buffer.resize(length); - - const auto bytes_read = fread(temp_buffer.data(), 1, temp_buffer.size(), f->handle); - - if (io_status_block) - { - IO_STATUS_BLOCK> block{}; - block.Information = bytes_read; - io_status_block.write(block); - } - - c.emu.write_memory(buffer, temp_buffer.data(), temp_buffer.size()); - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtWriteFile(const syscall_context& c, const handle file_handle, const uint64_t /*event*/, - const uint64_t /*apc_routine*/, - const uint64_t /*apc_context*/, - const emulator_object>> io_status_block, - uint64_t buffer, const ULONG length, - const emulator_object /*byte_offset*/, - const emulator_object /*key*/) - { - std::string temp_buffer{}; - temp_buffer.resize(length); - c.emu.read_memory(buffer, temp_buffer.data(), temp_buffer.size()); - - - if (file_handle == STDOUT_HANDLE) - { - if (io_status_block) - { - IO_STATUS_BLOCK> block{}; - block.Information = length; - io_status_block.write(block); - } - - if (!temp_buffer.ends_with("\n")) - { - temp_buffer.push_back('\n'); - } - - c.win_emu.on_stdout(temp_buffer); - c.win_emu.log.info("%.*s", static_cast(temp_buffer.size()), temp_buffer.data()); - - return STATUS_SUCCESS; - } - - const auto* f = c.proc.files.get(file_handle); - if (!f) - { - return STATUS_INVALID_HANDLE; - } - - const auto bytes_written = fwrite(temp_buffer.data(), 1, temp_buffer.size(), f->handle); - - if (io_status_block) - { - IO_STATUS_BLOCK> block{}; - block.Information = bytes_written; - io_status_block.write(block); - } - - return STATUS_SUCCESS; - } - - constexpr std::u16string map_mode(const ACCESS_MASK desired_access, const ULONG create_disposition) - { - std::u16string mode = u""; - - switch (create_disposition) - { - case FILE_CREATE: - case FILE_SUPERSEDE: - if (desired_access & GENERIC_WRITE) - { - mode = u"wb"; - } - break; - - case FILE_OPEN: - case FILE_OPEN_IF: - if (desired_access & GENERIC_WRITE) - { - mode = u"r+b"; - } - else if (desired_access & GENERIC_READ || desired_access & SYNCHRONIZE) - { - mode = u"rb"; - } - break; - - case FILE_OVERWRITE: - case FILE_OVERWRITE_IF: - if (desired_access & GENERIC_WRITE) - { - mode = u"w+b"; - } - break; - - default: - mode = u""; - break; - } - - if (desired_access & FILE_APPEND_DATA) - { - mode = u"a+b"; - } - - return mode; - } - - NTSTATUS handle_NtCreateFile(const syscall_context& c, const emulator_object file_handle, - ACCESS_MASK desired_access, - const emulator_object>> object_attributes, - const emulator_object>> /*io_status_block*/, - const emulator_object /*allocation_size*/, ULONG /*file_attributes*/, - ULONG /*share_access*/, ULONG create_disposition, ULONG create_options, - uint64_t ea_buffer, - ULONG ea_length) - { - const auto attributes = object_attributes.read(); - auto filename = read_unicode_string( - c.emu, reinterpret_cast>*>(attributes.ObjectName)); - - auto printer = utils::finally([&] - { - c.win_emu.log.print(color::dark_gray, "--> Opening file: %s\n", u16_to_u8(filename).c_str()); - }); - - constexpr std::u16string_view device_prefix = u"\\Device\\"; - if (filename.starts_with(device_prefix)) - { - const io_device_creation_data data{ - .buffer = ea_buffer, - .length = ea_length, - }; - - auto device_name = filename.substr(device_prefix.size()); - io_device_container container{std::move(device_name), c.win_emu, data}; - - const auto handle = c.proc.devices.store(std::move(container)); - file_handle.write(handle); - - return STATUS_SUCCESS; - } - - handle root_handle{}; - root_handle.bits = attributes.RootDirectory; - if (root_handle.value.is_pseudo && (filename == u"\\Reference" || filename == u"\\Connect")) - { - file_handle.write(root_handle); - return STATUS_SUCCESS; - } - - file f{}; - f.name = std::move(filename); - - if (attributes.RootDirectory) - { - const auto* root = c.proc.files.get(attributes.RootDirectory); - if (!root) - { - return STATUS_INVALID_HANDLE; - } - - f.name = root->name + f.name; - } - - printer.cancel(); - - if (f.name.ends_with(u"\\") || create_options & FILE_DIRECTORY_FILE) - { - c.win_emu.log.print(color::dark_gray, "--> Opening folder: %s\n", u16_to_u8(f.name).c_str()); - - if (create_disposition & FILE_CREATE) - { - std::error_code ec{}; - std::filesystem::create_directory(f.name, ec); - - if (ec) - { - return STATUS_ACCESS_DENIED; - } - } - else if (!std::filesystem::is_directory(f.name)) - { - return STATUS_OBJECT_NAME_NOT_FOUND; - } - - const auto handle = c.proc.files.store(std::move(f)); - file_handle.write(handle); - - return STATUS_SUCCESS; - } - - c.win_emu.log.print(color::dark_gray, "--> Opening file: %s\n", u16_to_u8(f.name).c_str()); - - std::u16string mode = map_mode(desired_access, create_disposition); - - if (mode.empty()) - { - return STATUS_NOT_SUPPORTED; - } - - FILE* file{}; - - const auto error = open_unicode(&file, f.name, mode); - - if (!file) - { - switch (error) - { - case ENOENT: - return STATUS_OBJECT_NAME_NOT_FOUND; - case EACCES: - return STATUS_ACCESS_DENIED; - case EISDIR: - return STATUS_FILE_IS_A_DIRECTORY; - default: - return STATUS_NOT_SUPPORTED; - } - } - - f.handle = file; - - const auto handle = c.proc.files.store(std::move(f)); - file_handle.write(handle); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtQueryAttributesFile(const syscall_context& c, - const emulator_object>> - object_attributes, - const emulator_object file_information) - { - if (!object_attributes) - { - return STATUS_INVALID_PARAMETER; - } - - const auto attributes = object_attributes.read(); - if (!attributes.ObjectName) - { - return STATUS_INVALID_PARAMETER; - } - - const auto filename = read_unicode_string( - c.emu, emulator_object>>{c.emu, attributes.ObjectName}); - const auto u8_filename = u16_to_u8(filename); - - struct _stat64 file_stat{}; - if (_stat64(u8_filename.c_str(), &file_stat) != 0) - { - return STATUS_OBJECT_NAME_NOT_FOUND; - } - - file_information.access([&](FILE_BASIC_INFORMATION& info) - { - info.CreationTime = convert_unix_to_windows_time(file_stat.st_atime); - info.LastAccessTime = convert_unix_to_windows_time(file_stat.st_atime); - info.LastWriteTime = convert_unix_to_windows_time(file_stat.st_mtime); - info.ChangeTime = info.LastWriteTime; - info.FileAttributes = FILE_ATTRIBUTE_NORMAL; - }); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtOpenFile(const syscall_context& c, - const emulator_object file_handle, - const ACCESS_MASK desired_access, - const emulator_object>> object_attributes, - const emulator_object>> io_status_block, - const ULONG share_access, - const ULONG open_options) - { - return handle_NtCreateFile(c, file_handle, desired_access, object_attributes, io_status_block, {c.emu}, 0, - share_access, FILE_OPEN, open_options, 0, 0); - } - - NTSTATUS handle_NtQueryObject(const syscall_context&, const handle /*handle*/, - const OBJECT_INFORMATION_CLASS /*object_information_class*/, - const emulator_pointer /*object_information*/, - const ULONG /*object_information_length*/, - const emulator_object /*return_length*/) - { - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtQueryInformationJobObject() - { - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtSetSystemInformation() - { - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtAccessCheck() - { - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtUserGetKeyboardLayout() - { - return STATUS_NOT_SUPPORTED; - } - - NTSTATUS handle_NtRaiseHardError(const syscall_context& c, const NTSTATUS error_status, - const ULONG /*number_of_parameters*/, - const emulator_object>> - /*unicode_string_parameter_mask*/, - const emulator_object /*parameters*/, - const HARDERROR_RESPONSE_OPTION /*valid_response_option*/, - const emulator_object response) - { - if (response) - { - response.write(ResponseAbort); - } - - c.proc.exit_status = error_status; - c.proc.exception_rip = c.emu.read_instruction_pointer(); - c.emu.stop(); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtRaiseException(const syscall_context& c, - const emulator_object>> - /*exception_record*/, - const emulator_object thread_context, BOOLEAN handle_exception) - { - if (handle_exception) - { - puts("Unhandled exceptions not supported yet!"); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - c.proc.exception_rip = thread_context.read().Rip; - c.emu.stop(); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtOpenSemaphore(const syscall_context& c, const emulator_object semaphore_handle, - const ACCESS_MASK /*desired_access*/, - const emulator_object>> object_attributes) - { - if (!object_attributes) - { - return STATUS_INVALID_PARAMETER; - } - - const auto attributes = object_attributes.read(); - if (!attributes.ObjectName) - { - return STATUS_INVALID_PARAMETER; - } - - const auto name = read_unicode_string( - c.emu, emulator_object>>{c.emu, attributes.ObjectName}); - if (name.empty()) - { - return STATUS_INVALID_PARAMETER; - } - - for (const auto& semaphore : c.proc.semaphores) - { - if (semaphore.second.name == name) - { - semaphore_handle.write(c.proc.semaphores.make_handle(semaphore.first)); - return STATUS_SUCCESS; - } - } - - return STATUS_OBJECT_NAME_NOT_FOUND; - } - - NTSTATUS handle_NtCreateSemaphore(const syscall_context& c, const emulator_object semaphore_handle, - const ACCESS_MASK /*desired_access*/, - const emulator_object>> object_attributes, - const ULONG initial_count, const ULONG maximum_count) - { - semaphore s{}; - s.current_count = initial_count; - s.max_count = maximum_count; - - if (object_attributes) - { - const auto attributes = object_attributes.read(); - if (attributes.ObjectName) - { - s.name = read_unicode_string( - c.emu, reinterpret_cast>*>(attributes.ObjectName)); - } - } - - if (!s.name.empty()) - { - for (const auto& semaphore : c.proc.semaphores) - { - if (semaphore.second.name == s.name) - { - return STATUS_OBJECT_NAME_EXISTS; - } - } - } - - const auto handle = c.proc.semaphores.store(std::move(s)); - semaphore_handle.write(handle); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtAddAtomEx(const syscall_context& c, const uint64_t atom_name, const ULONG length, - const emulator_object atom, const ULONG /*flags*/) - { - std::wstring name{}; - name.resize(length / 2); - - c.emu.read_memory(atom_name, name.data(), length); - - uint16_t index = 0; - if (!c.proc.atoms.empty()) - { - auto i = c.proc.atoms.end(); - --i; - index = i->first + 1; - } - - std::optional last_entry{}; - for (auto& entry : c.proc.atoms) - { - if (entry.second == name) - { - if (atom) - { - atom.write(entry.first); - return STATUS_SUCCESS; - } - } - - if (entry.first > 0) - { - if (!last_entry) - { - index = 0; - } - else - { - const auto diff = entry.first - *last_entry; - if (diff > 1) - { - index = *last_entry + 1; - } - } - } - - last_entry = entry.first; - } - - c.proc.atoms[index] = std::move(name); - atom.write(index); - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtUnmapViewOfSection(const syscall_context& c, const handle process_handle, - const uint64_t base_address) - { - if (process_handle != CURRENT_PROCESS) - { - return STATUS_NOT_SUPPORTED; - } - - const auto* mod = c.proc.mod_manager.find_by_address(base_address); - if (!mod) - { - puts("Unmapping non-module section not supported!"); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - if (c.proc.mod_manager.unmap(base_address)) - { - return STATUS_SUCCESS; - } - - return STATUS_INVALID_PARAMETER; - } - - NTSTATUS handle_NtUnmapViewOfSectionEx(const syscall_context& c, const handle process_handle, - const uint64_t base_address, const ULONG /*flags*/) - { - return handle_NtUnmapViewOfSection(c, process_handle, base_address); - } - - NTSTATUS handle_NtCreateThreadEx(const syscall_context& c, const emulator_object thread_handle, - const ACCESS_MASK /*desired_access*/, - const emulator_object>> - /*object_attributes*/, - const handle process_handle, const uint64_t start_routine, - const uint64_t argument, const ULONG /*create_flags*/, - const EmulatorTraits::SIZE_T /*zero_bits*/, - const EmulatorTraits::SIZE_T stack_size, - const EmulatorTraits::SIZE_T /*maximum_stack_size*/, - const emulator_object>> attribute_list) - { - if (process_handle != CURRENT_PROCESS) - { - return STATUS_NOT_SUPPORTED; - } - - const auto h = c.proc.create_thread(c.emu, start_routine, argument, stack_size); - thread_handle.write(h); - - if (!attribute_list) - { - return STATUS_SUCCESS; - } - - const auto* thread = c.proc.threads.get(h); - - const emulator_object>> attributes{ - c.emu, attribute_list.value() + offsetof(PS_ATTRIBUTE_LIST>, Attributes) - }; - - const auto total_length = attribute_list.read().TotalLength; - - constexpr auto entry_size = sizeof(PS_ATTRIBUTE>); - constexpr auto header_size = sizeof(PS_ATTRIBUTE_LIST>) - entry_size; - const auto attribute_count = (total_length - header_size) / entry_size; - - for (size_t i = 0; i < attribute_count; ++i) - { - attributes.access([&](const PS_ATTRIBUTE>& attribute) - { - const auto type = attribute.Attribute & ~PS_ATTRIBUTE_THREAD; - - if (type == PsAttributeClientId) - { - const auto client_id = thread->teb->read().ClientId; - write_attribute(c.emu, attribute, client_id); - } - else if (type == PsAttributeTebAddress) - { - write_attribute(c.emu, attribute, thread->teb->ptr()); - } - else - { - printf("Unsupported thread attribute type: %" PRIx64 "\n", type); - } - }, i); - } - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtQueryDebugFilterState() - { - return FALSE; - } - - bool is_awaitable_object_type(const handle h) - { - return h.value.type == handle_types::thread // - || h.value.type == handle_types::mutant // - || h.value.type == handle_types::event; - } - - NTSTATUS handle_NtWaitForMultipleObjects(const syscall_context& c, const ULONG count, - const emulator_object handles, const WAIT_TYPE wait_type, - const BOOLEAN alertable, const emulator_object timeout) - { - if (alertable) - { - c.win_emu.log.print(color::gray, "Alertable NtWaitForMultipleObjects not supported yet!\n"); - } - - if (wait_type != WaitAny && wait_type != WaitAll) - { - puts("Wait type not supported!"); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - auto& t = c.win_emu.current_thread(); - t.await_objects.clear(); - t.await_any = wait_type == WaitAny; - - for (ULONG i = 0; i < count; ++i) - { - const auto h = handles.read(i); - - if (!is_awaitable_object_type(h)) - { - c.win_emu.log.print(color::gray, "Unsupported handle type for NtWaitForMultipleObjects: %d!\n", - h.value.type); - return STATUS_NOT_SUPPORTED; - } - } - - if (timeout.value() && !t.await_time.has_value()) - { - t.await_time = convert_delay_interval_to_time_point(timeout.read()); - } - - c.win_emu.yield_thread(); - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtWaitForSingleObject(const syscall_context& c, const handle h, - const BOOLEAN alertable, - const emulator_object timeout) - { - if (alertable) - { - c.win_emu.log.print(color::gray, "Alertable NtWaitForSingleObject not supported yet!\n"); - } - - if (!is_awaitable_object_type(h)) - { - c.win_emu.log.print(color::gray, - "Unsupported handle type for NtWaitForSingleObject: %d!\n", h.value.type); - return STATUS_NOT_SUPPORTED; - } - - auto& t = c.win_emu.current_thread(); - t.await_objects = {h}; - t.await_any = false; - - if (timeout.value() && !t.await_time.has_value()) - { - t.await_time = convert_delay_interval_to_time_point(timeout.read()); - } - - c.win_emu.yield_thread(); - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtTerminateThread(const syscall_context& c, const handle thread_handle, - const NTSTATUS exit_status) - { - auto* thread = !thread_handle.bits - ? c.proc.active_thread - : c.proc.threads.get(thread_handle); - - if (!thread) - { - return STATUS_INVALID_HANDLE; - } - - thread->exit_status = exit_status; - if (thread == c.proc.active_thread) - { - c.win_emu.yield_thread(); - } - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtDelayExecution(const syscall_context& c, const BOOLEAN alertable, - const emulator_object delay_interval) - { - if (alertable) - { - puts("Alertable NtDelayExecution not supported yet!"); - c.emu.stop(); - return STATUS_NOT_SUPPORTED; - } - - auto& t = c.win_emu.current_thread(); - t.await_time = convert_delay_interval_to_time_point(delay_interval.read()); - - c.win_emu.yield_thread(); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtAlertThreadByThreadId(const syscall_context& c, const uint64_t thread_id) - { - for (auto& t : c.proc.threads) - { - if (t.second.id == thread_id) - { - t.second.alerted = true; - return STATUS_SUCCESS; - } - } - - return STATUS_INVALID_HANDLE; - } - - NTSTATUS handle_NtAlertThreadByThreadIdEx(const syscall_context& c, const uint64_t thread_id, - const emulator_object>> lock) - { - if (lock.value()) - { - c.win_emu.log.print(color::gray, "NtAlertThreadByThreadIdEx with lock not supported yet!"); - //c.emu.stop(); - //return STATUS_NOT_SUPPORTED; - } - - return handle_NtAlertThreadByThreadId(c, thread_id); - } - - NTSTATUS handle_NtWaitForAlertByThreadId(const syscall_context& c, const uint64_t, - const emulator_object timeout) - { - auto& t = c.win_emu.current_thread(); - t.waiting_for_alert = true; - - if (timeout.value() && !t.await_time.has_value()) - { - t.await_time = convert_delay_interval_to_time_point(timeout.read()); - } - - c.win_emu.yield_thread(); - - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtGetCurrentProcessorNumberEx(const syscall_context&, - const emulator_object processor_number) - { - constexpr PROCESSOR_NUMBER number{}; - processor_number.write(number); - return STATUS_SUCCESS; - } - - NTSTATUS handle_NtGetContextThread(const syscall_context& c, handle thread_handle, - const emulator_object thread_context) - { - const auto* thread = thread_handle == CURRENT_THREAD - ? c.proc.active_thread - : c.proc.threads.get(thread_handle); - - if (!thread) - { - return STATUS_INVALID_HANDLE; - } - - c.proc.active_thread->save(c.emu); - const auto _ = utils::finally([&] - { - c.proc.active_thread->restore(c.emu); - }); - - thread->restore(c.emu); - - thread_context.access([&](CONTEXT64& context) - { - if (context.ContextFlags & CONTEXT_DEBUG_REGISTERS_64) - { - c.win_emu.log.print(color::pink, "--> Reading debug registers!\n"); - } - - context_frame::save(c.emu, context); - }); - - return STATUS_SUCCESS; - } + }); + + if (code == 0) + { + c.emu.write_memory(system_information, res_buff, return_length.read()); + } + + free(buffer); + free(res_buff); + + return code; + } + + if (info_class != SystemBasicInformation && info_class != SystemEmulationBasicInformation) + { + printf("Unsupported system info ex class: %X\n", info_class); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + if (return_length) + { + return_length.write(sizeof(SYSTEM_BASIC_INFORMATION64)); + } + + if (system_information_length != sizeof(SYSTEM_BASIC_INFORMATION64)) + { + return STATUS_BUFFER_TOO_SMALL; + } + + const emulator_object info{c.emu, system_information}; + + info.access([&](SYSTEM_BASIC_INFORMATION64& basic_info) { + basic_info.Reserved = 0; + basic_info.TimerResolution = 0x0002625a; + basic_info.PageSize = 0x1000; + basic_info.LowestPhysicalPageNumber = 0x00000001; + basic_info.HighestPhysicalPageNumber = 0x00c9c7ff; + basic_info.AllocationGranularity = 0x10000; + basic_info.MinimumUserModeAddress = 0x0000000000010000; + basic_info.MaximumUserModeAddress = 0x00007ffffffeffff; + basic_info.ActiveProcessorsAffinityMask = 0x0000000000000fff; + basic_info.NumberOfProcessors = 1; + }); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtQueryInformationProcess(const syscall_context& c, const handle process_handle, + const uint32_t info_class, const uint64_t process_information, + const uint32_t process_information_length, + const emulator_object return_length) + { + if (process_handle != CURRENT_PROCESS) + { + return STATUS_NOT_SUPPORTED; + } + + if (info_class == ProcessImageInformation) + { + if (return_length) + { + return_length.write(sizeof(SECTION_IMAGE_INFORMATION>)); + } + + if (process_information_length != sizeof(SECTION_IMAGE_INFORMATION>)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object>> info{c.emu, process_information}; + info.access([&](SECTION_IMAGE_INFORMATION>& i) { + const auto& mod = *c.proc.executable; + + const emulator_object dos_header_obj{c.emu, mod.image_base}; + const auto dos_header = dos_header_obj.read(); + + const emulator_object> nt_headers_obj{c.emu, + mod.image_base + dos_header.e_lfanew}; + const auto nt_headers = nt_headers_obj.read(); + + const auto& file_header = nt_headers.FileHeader; + const auto& optional_header = nt_headers.OptionalHeader; + + i.TransferAddress = 0; + i.MaximumStackSize = optional_header.SizeOfStackReserve; + i.CommittedStackSize = optional_header.SizeOfStackCommit; + i.SubSystemType = optional_header.Subsystem; + i.SubSystemMajorVersion = optional_header.MajorSubsystemVersion; + i.SubSystemMinorVersion = optional_header.MinorSubsystemVersion; + i.MajorOperatingSystemVersion = optional_header.MajorOperatingSystemVersion; + i.MinorOperatingSystemVersion = optional_header.MinorOperatingSystemVersion; + i.ImageCharacteristics = file_header.Characteristics; + i.DllCharacteristics = optional_header.DllCharacteristics; + i.Machine = file_header.Machine; + i.ImageContainsCode = TRUE; + i.ImageFlags = 0; // TODO + i.ImageFileSize = optional_header.SizeOfImage; + i.LoaderFlags = optional_header.LoaderFlags; + i.CheckSum = optional_header.CheckSum; + }); + + return STATUS_SUCCESS; + } + + if (info_class == ProcessCookie) + { + if (return_length) + { + return_length.write(sizeof(uint32_t)); + } + + if (process_information_length != sizeof(uint32_t)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object info{c.emu, process_information}; + info.write(0x01234567); + + return STATUS_SUCCESS; + } + + if (info_class == ProcessDebugPort) + { + if (return_length) + { + return_length.write(sizeof(EmulatorTraits::PVOID)); + } + + if (process_information_length != sizeof(EmulatorTraits::PVOID)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object::PVOID> info{c.emu, process_information}; + info.write(0); + + return STATUS_SUCCESS; + } + + if (info_class == ProcessDefaultHardErrorMode || info_class == ProcessWx86Information) + { + if (return_length) + { + return_length.write(sizeof(ULONG)); + } + + if (process_information_length != sizeof(ULONG)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object info{c.emu, process_information}; + info.write(0); + + return STATUS_SUCCESS; + } + + if (info_class == ProcessEnclaveInformation || info_class == ProcessMitigationPolicy) + { + return STATUS_NOT_SUPPORTED; + } + + if (info_class == ProcessTimes) + { + if (return_length) + { + return_length.write(sizeof(KERNEL_USER_TIMES)); + } + + if (process_information_length != sizeof(KERNEL_USER_TIMES)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object info{c.emu, process_information}; + info.write(KERNEL_USER_TIMES{}); + + return STATUS_SUCCESS; + } + + if (info_class == ProcessBasicInformation) + { + if (return_length) + { + return_length.write(sizeof(PROCESS_BASIC_INFORMATION64)); + } + + if (process_information_length != sizeof(PROCESS_BASIC_INFORMATION64)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object info{c.emu, process_information}; + info.access([&](PROCESS_BASIC_INFORMATION64& basic_info) { + basic_info.PebBaseAddress = c.proc.peb.ptr(); + basic_info.UniqueProcessId = 1; + }); + + return STATUS_SUCCESS; + } + + if (info_class == ProcessImageFileNameWin32) + { + const auto peb = c.proc.peb.read(); + emulator_object proc_params{c.emu, peb.ProcessParameters}; + const auto params = proc_params.read(); + const auto length = params.ImagePathName.Length + sizeof(UNICODE_STRING>) + 2; + + if (return_length) + { + return_length.write(static_cast(length)); + } + + if (process_information_length < length) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object>> info{c.emu, process_information}; + info.access([&](UNICODE_STRING>& str) { + const auto buffer_start = + static_cast(process_information) + sizeof(UNICODE_STRING>); + const auto string = read_unicode_string(c.emu, params.ImagePathName); + c.emu.write_memory(buffer_start, string.c_str(), (string.size() + 1) * 2); + str.Length = params.ImagePathName.Length; + str.MaximumLength = str.Length; + str.Buffer = buffer_start; + }); + + return STATUS_SUCCESS; + } + + printf("Unsupported process info class: %X\n", info_class); + c.emu.stop(); + + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtQueryInformationThread(const syscall_context& c, const handle thread_handle, + const uint32_t info_class, const uint64_t thread_information, + const uint32_t thread_information_length, + const emulator_object return_length) + { + const auto* thread = thread_handle == CURRENT_THREAD ? c.proc.active_thread : c.proc.threads.get(thread_handle); + + if (!thread) + { + return STATUS_INVALID_HANDLE; + } + + if (info_class == ThreadBasicInformation) + { + if (return_length) + { + return_length.write(sizeof(THREAD_BASIC_INFORMATION64)); + } + + if (thread_information_length != sizeof(THREAD_BASIC_INFORMATION64)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object info{c.emu, thread_information}; + info.access([&](THREAD_BASIC_INFORMATION64& i) { + i.TebBaseAddress = thread->teb->ptr(); + i.ClientId = thread->teb->read().ClientId; + }); + + return STATUS_SUCCESS; + } + + if (info_class == ThreadAmILastThread) + { + if (return_length) + { + return_length.write(sizeof(ULONG)); + } + + if (thread_information_length != sizeof(ULONG)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object info{c.emu, thread_information}; + info.write(c.proc.threads.size() <= 1); + + return STATUS_SUCCESS; + } + + if (info_class == ThreadQuerySetWin32StartAddress) + { + if (return_length) + { + return_length.write(sizeof(EmulatorTraits::PVOID)); + } + + if (thread_information_length != sizeof(EmulatorTraits::PVOID)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object::PVOID> info{c.emu, thread_information}; + info.write(thread->start_address); + + return STATUS_SUCCESS; + } + + printf("Unsupported thread query info class: %X\n", info_class); + c.emu.stop(); + + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtSetInformationFile(const syscall_context& c, const handle file_handle, + const emulator_object>> io_status_block, + const uint64_t file_information, const ULONG length, + const FILE_INFORMATION_CLASS info_class) + { + const auto* f = c.proc.files.get(file_handle); + if (!f) + { + return STATUS_INVALID_HANDLE; + } + + if (info_class == FilePositionInformation) + { + if (!f->handle) + { + return STATUS_NOT_SUPPORTED; + } + + if (io_status_block) + { + IO_STATUS_BLOCK> block{}; + block.Information = sizeof(FILE_POSITION_INFORMATION); + io_status_block.write(block); + } + + if (length != sizeof(FILE_POSITION_INFORMATION)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object info{c.emu, file_information}; + const auto i = info.read(); + + if (!f->handle.seek_to(i.CurrentByteOffset.QuadPart)) + { + return STATUS_INVALID_PARAMETER; + } + + return STATUS_SUCCESS; + } + + printf("Unsupported set file info class: %X\n", info_class); + c.emu.stop(); + + return STATUS_NOT_SUPPORTED; + } + + std::vector scan_directory(const std::filesystem::path& dir) + { + std::vector files{ + {"."}, + {".."}, + }; + + for (const auto& file : std::filesystem::directory_iterator(dir)) + { + files.emplace_back(file_entry{ + .file_path = file.path().filename(), + }); + } + + return files; + } + + template + NTSTATUS handle_file_enumeration(const syscall_context& c, + const emulator_object>> io_status_block, + const uint64_t file_information, const uint32_t length, const ULONG query_flags, + file* f) + { + if (!f->enumeration_state || query_flags & SL_RESTART_SCAN) + { + f->enumeration_state.emplace(file_enumeration_state{}); + f->enumeration_state->files = scan_directory(f->name); + } + + auto& enum_state = *f->enumeration_state; + + size_t current_offset{0}; + emulator_object object{c.emu}; + + size_t current_index = enum_state.current_index; + + do + { + if (current_index >= enum_state.files.size()) + { + break; + } + + const auto new_offset = align_up(current_offset, 8); + const auto& current_file = enum_state.files[current_index]; + const auto file_name = current_file.file_path.u16string(); + const auto required_size = sizeof(T) + (file_name.size() * 2) - 2; + const auto end_offset = new_offset + required_size; + + if (end_offset > length) + { + if (current_offset == 0) + { + IO_STATUS_BLOCK> block{}; + block.Information = end_offset; + io_status_block.write(block); + + return STATUS_BUFFER_OVERFLOW; + } + + break; + } + + if (object) + { + const auto object_offset = object.value() - file_information; + + object.access( + [&](T& dir_info) { dir_info.NextEntryOffset = static_cast(new_offset - object_offset); }); + } + + T info{}; + info.NextEntryOffset = 0; + info.FileIndex = static_cast(current_index); + info.FileAttributes = FILE_ATTRIBUTE_NORMAL; + info.FileNameLength = static_cast(file_name.size() * 2); + + object.set_address(file_information + new_offset); + object.write(info); + + c.emu.write_memory(object.value() + offsetof(T, FileName), file_name.data(), info.FileNameLength); + + ++current_index; + current_offset = end_offset; + } while ((query_flags & SL_RETURN_SINGLE_ENTRY) == 0); + + if ((query_flags & SL_NO_CURSOR_UPDATE) == 0) + { + enum_state.current_index = current_index; + } + + IO_STATUS_BLOCK> block{}; + block.Information = current_offset; + io_status_block.write(block); + + return current_index < enum_state.files.size() ? STATUS_SUCCESS : STATUS_NO_MORE_FILES; + } + + NTSTATUS handle_NtQueryDirectoryFileEx( + const syscall_context& c, const handle file_handle, const handle /*event_handle*/, + const emulator_pointer /*PIO_APC_ROUTINE*/ /*apc_routine*/, const emulator_pointer /*apc_context*/, + const emulator_object>> io_status_block, const uint64_t file_information, + const uint32_t length, const uint32_t info_class, const ULONG query_flags, + const emulator_object>> /*file_name*/) + { + auto* f = c.proc.files.get(file_handle); + if (!f || !f->is_directory()) + { + return STATUS_INVALID_HANDLE; + } + + if (info_class == FileDirectoryInformation) + { + return handle_file_enumeration(c, io_status_block, file_information, length, + query_flags, f); + } + + if (info_class == FileFullDirectoryInformation) + { + return handle_file_enumeration(c, io_status_block, file_information, length, + query_flags, f); + } + + if (info_class == FileBothDirectoryInformation) + { + return handle_file_enumeration(c, io_status_block, file_information, length, + query_flags, f); + } + + printf("Unsupported query directory file info class: %X\n", info_class); + c.emu.stop(); + + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtQueryInformationFile( + const syscall_context& c, const handle file_handle, + const emulator_object>> io_status_block, const uint64_t file_information, + const uint32_t length, const uint32_t info_class) + { + const auto* f = c.proc.files.get(file_handle); + if (!f) + { + return STATUS_INVALID_HANDLE; + } + + if (info_class == FileNameInformation) + { + const auto required_length = sizeof(FILE_NAME_INFORMATION) + (f->name.size() * 2); + + if (io_status_block) + { + IO_STATUS_BLOCK> block{}; + block.Information = sizeof(FILE_NAME_INFORMATION) + required_length; + io_status_block.write(block); + } + + if (length != required_length) + { + return STATUS_BUFFER_OVERFLOW; + } + + c.emu.write_memory(file_information, FILE_NAME_INFORMATION{ + .FileNameLength = static_cast(f->name.size() * 2), + .FileName = {}, + }); + + c.emu.write_memory(file_information + offsetof(FILE_NAME_INFORMATION, FileName), f->name.c_str(), + (f->name.size() + 1) * 2); + + return STATUS_SUCCESS; + } + + if (info_class == FileStandardInformation) + { + if (io_status_block) + { + IO_STATUS_BLOCK> block{}; + block.Information = sizeof(FILE_STANDARD_INFORMATION); + io_status_block.write(block); + } + + if (length != sizeof(FILE_STANDARD_INFORMATION)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object info{c.emu, file_information}; + FILE_STANDARD_INFORMATION i{}; + i.Directory = f->is_directory() ? TRUE : FALSE; + + if (f->handle) + { + i.EndOfFile.QuadPart = f->handle.size(); + } + + info.write(i); + + return STATUS_SUCCESS; + } + + if (info_class == FilePositionInformation) + { + if (!f->handle) + { + return STATUS_NOT_SUPPORTED; + } + + if (io_status_block) + { + IO_STATUS_BLOCK> block{}; + block.Information = sizeof(FILE_POSITION_INFORMATION); + io_status_block.write(block); + } + + if (length != sizeof(FILE_POSITION_INFORMATION)) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object info{c.emu, file_information}; + FILE_POSITION_INFORMATION i{}; + + i.CurrentByteOffset.QuadPart = f->handle.tell(); + + info.write(i); + + return STATUS_SUCCESS; + } + + printf("Unsupported query file info class: %X\n", info_class); + c.emu.stop(); + + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtSetInformationProcess(const syscall_context& c, const handle process_handle, + const uint32_t info_class, const uint64_t process_information, + const uint32_t process_information_length) + { + if (process_handle != CURRENT_PROCESS) + { + return STATUS_NOT_SUPPORTED; + } + + if (info_class == ProcessSchedulerSharedData || info_class == ProcessConsoleHostProcess || + info_class == ProcessFaultInformation || info_class == ProcessDefaultHardErrorMode || + info_class == ProcessRaiseUMExceptionOnInvalidHandleClose) + { + return STATUS_SUCCESS; + } + + if (info_class == ProcessTlsInformation) + { + constexpr auto thread_data_offset = offsetof(PROCESS_TLS_INFO, ThreadData); + if (process_information_length < thread_data_offset) + { + return STATUS_BUFFER_OVERFLOW; + } + + const emulator_object data{c.emu, process_information + thread_data_offset}; + + PROCESS_TLS_INFO tls_info{}; + c.emu.read_memory(process_information, &tls_info, thread_data_offset); + + for (uint32_t i = 0; i < tls_info.ThreadDataCount; ++i) + { + auto entry = data.read(i); + + const auto _ = utils::finally([&] { data.write(entry, i); }); + + if (i >= c.proc.threads.size()) + { + entry.Flags = 0; + continue; + } + + auto thread_iterator = c.proc.threads.begin(); + std::advance(thread_iterator, i); + + entry.Flags = 2; + + thread_iterator->second.teb->access([&](TEB64& teb) { + entry.ThreadId = teb.ClientId.UniqueThread; + + const auto tls_vector = teb.ThreadLocalStoragePointer; + + if (tls_info.TlsRequest == ProcessTlsReplaceIndex) + { + const auto tls_entry_ptr = tls_vector + tls_info.TlsIndex; + + const auto old_entry = c.emu.read_memory::PVOID>(tls_entry_ptr); + c.emu.write_memory::PVOID>(tls_entry_ptr, entry.TlsModulePointer); + + entry.TlsModulePointer = old_entry; + } + else if (tls_info.TlsRequest == ProcessTlsReplaceVector) + { + const auto new_tls_vector = entry.TlsVector; + + for (uint32_t index = 0; index < tls_info.TlsVectorLength; ++index) + { + const auto old_entry = c.emu.read_memory(tls_vector + index); + c.emu.write_memory(new_tls_vector + index, old_entry); + } + + teb.ThreadLocalStoragePointer = new_tls_vector; + entry.TlsVector = tls_vector; + } + }); + } + + return STATUS_SUCCESS; + } + + printf("Unsupported info process class: %X\n", info_class); + c.emu.stop(); + + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtSetInformationKey() + { + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtApphelpCacheControl() + { + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtProtectVirtualMemory(const syscall_context& c, const handle process_handle, + const emulator_object base_address, + const emulator_object bytes_to_protect, const uint32_t protection, + const emulator_object old_protection) + { + if (process_handle != CURRENT_PROCESS) + { + return STATUS_NOT_SUPPORTED; + } + + const auto orig_start = base_address.read(); + const auto orig_length = bytes_to_protect.read(); + + const auto aligned_start = page_align_down(orig_start); + const auto aligned_length = page_align_up(orig_start + orig_length) - aligned_start; + + base_address.write(aligned_start); + bytes_to_protect.write(static_cast(aligned_length)); + + const auto requested_protection = map_nt_to_emulator_protection(protection); + + c.win_emu.log.print(color::dark_gray, "--> Changing protection at 0x%" PRIx64 "-0x%" PRIx64 " to %s\n", + aligned_start, aligned_start + aligned_length, + get_permission_string(requested_protection).c_str()); + + memory_permission old_protection_value{}; + + try + { + c.emu.protect_memory(aligned_start, aligned_length, requested_protection, &old_protection_value); + } + catch (...) + { + return STATUS_INVALID_ADDRESS; + } + + const auto current_protection = map_emulator_to_nt_protection(old_protection_value); + old_protection.write(current_protection); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtOpenDirectoryObject( + const syscall_context& c, const emulator_object directory_handle, const ACCESS_MASK /*desired_access*/, + const emulator_object>> object_attributes) + { + const auto attributes = object_attributes.read(); + const auto object_name = + read_unicode_string(c.emu, reinterpret_cast>*>(attributes.ObjectName)); + + if (object_name == u"\\KnownDlls") + { + directory_handle.write(KNOWN_DLLS_DIRECTORY); + return STATUS_SUCCESS; + } + + if (object_name == u"\\Sessions\\1\\BaseNamedObjects") + { + directory_handle.write(BASE_NAMED_OBJECTS_DIRECTORY); + return STATUS_SUCCESS; + } + + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtOpenSymbolicLinkObject( + const syscall_context& c, const emulator_object link_handle, ACCESS_MASK /*desired_access*/, + const emulator_object>> object_attributes) + { + const auto attributes = object_attributes.read(); + const auto object_name = + read_unicode_string(c.emu, reinterpret_cast>*>(attributes.ObjectName)); + + if (object_name == u"KnownDllPath") + { + link_handle.write(KNOWN_DLLS_SYMLINK); + return STATUS_SUCCESS; + } + + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtQuerySymbolicLinkObject(const syscall_context& c, const handle link_handle, + const emulator_object>> link_target, + const emulator_object returned_length) + { + if (link_handle == KNOWN_DLLS_SYMLINK) + { + constexpr std::u16string_view system32 = u"C:\\WINDOWS\\System32"; + constexpr auto str_length = system32.size() * 2; + constexpr auto max_length = str_length + 2; + + returned_length.write(max_length); + + bool too_small = false; + link_target.access([&](UNICODE_STRING>& str) { + if (str.MaximumLength < max_length) + { + too_small = true; + return; + } + + str.Length = str_length; + c.emu.write_memory(str.Buffer, system32.data(), max_length); + }); + + return too_small ? STATUS_BUFFER_TOO_SMALL : STATUS_SUCCESS; + } + + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtAllocateVirtualMemoryEx(const syscall_context& c, const handle process_handle, + const emulator_object base_address, + const emulator_object bytes_to_allocate, + const uint32_t allocation_type, const uint32_t page_protection) + { + if (process_handle != CURRENT_PROCESS) + { + return STATUS_NOT_SUPPORTED; + } + + auto allocation_bytes = bytes_to_allocate.read(); + allocation_bytes = page_align_up(allocation_bytes); + bytes_to_allocate.write(allocation_bytes); + + const auto protection = map_nt_to_emulator_protection(page_protection); + + auto potential_base = base_address.read(); + if (!potential_base) + { + potential_base = c.emu.find_free_allocation_base(allocation_bytes); + } + + if (!potential_base) + { + return STATUS_MEMORY_NOT_ALLOCATED; + } + + base_address.write(potential_base); + + const bool reserve = allocation_type & MEM_RESERVE; + const bool commit = allocation_type & MEM_COMMIT; + + if ((allocation_type & ~(MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN)) || (!commit && !reserve)) + { + throw std::runtime_error("Unsupported allocation type!"); + } + + if (commit && !reserve && c.emu.commit_memory(potential_base, allocation_bytes, protection)) + { + return STATUS_SUCCESS; + } + + return c.emu.allocate_memory(potential_base, allocation_bytes, protection, !commit) + ? STATUS_SUCCESS + : STATUS_MEMORY_NOT_ALLOCATED; + } + + NTSTATUS handle_NtAllocateVirtualMemory(const syscall_context& c, const handle process_handle, + const emulator_object base_address, const uint64_t /*zero_bits*/, + const emulator_object bytes_to_allocate, + const uint32_t allocation_type, const uint32_t page_protection) + { + return handle_NtAllocateVirtualMemoryEx(c, process_handle, base_address, bytes_to_allocate, allocation_type, + page_protection); + } + + NTSTATUS handle_NtFreeVirtualMemory(const syscall_context& c, const handle process_handle, + const emulator_object base_address, + const emulator_object bytes_to_allocate, const uint32_t free_type) + { + if (process_handle != CURRENT_PROCESS) + { + return STATUS_NOT_SUPPORTED; + } + + const auto allocation_base = base_address.read(); + const auto allocation_size = bytes_to_allocate.read(); + + if (free_type & MEM_RELEASE) + { + return c.emu.release_memory(allocation_base, allocation_size) ? STATUS_SUCCESS + : STATUS_MEMORY_NOT_ALLOCATED; + } + + if (free_type & MEM_DECOMMIT) + { + return c.emu.decommit_memory(allocation_base, allocation_size) ? STATUS_SUCCESS + : STATUS_MEMORY_NOT_ALLOCATED; + } + + throw std::runtime_error("Bad free type"); + } + + NTSTATUS handle_NtCreateSection(const syscall_context& c, const emulator_object section_handle, + const ACCESS_MASK /*desired_access*/, + const emulator_object>> object_attributes, + const emulator_object maximum_size, + const ULONG section_page_protection, const ULONG allocation_attributes, + const handle file_handle) + { + section s{}; + s.section_page_protection = section_page_protection; + s.allocation_attributes = allocation_attributes; + + const auto* file = c.proc.files.get(file_handle); + if (file) + { + c.win_emu.log.print(color::dark_gray, "--> Section for file %s\n", u16_to_u8(file->name).c_str()); + s.file_name = file->name; + } + + if (object_attributes) + { + const auto attributes = object_attributes.read(); + if (attributes.ObjectName) + { + const auto name = read_unicode_string( + c.emu, reinterpret_cast>*>(attributes.ObjectName)); + c.win_emu.log.print(color::dark_gray, "--> Section with name %s\n", u16_to_u8(name).c_str()); + s.name = std::move(name); + } + } + + if (maximum_size) + { + maximum_size.access([&](ULARGE_INTEGER& large_int) { + large_int.QuadPart = page_align_up(large_int.QuadPart); + s.maximum_size = large_int.QuadPart; + }); + } + else if (!file) + { + return STATUS_INVALID_PARAMETER; + } + + const auto h = c.proc.sections.store(std::move(s)); + section_handle.write(h); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtConnectPort(const syscall_context& c, const emulator_object client_port_handle, + const emulator_object>> server_port_name, + const emulator_object /*security_qos*/, + const emulator_object client_shared_memory, + const emulator_object /*server_shared_memory*/, + const emulator_object /*maximum_message_length*/, + const emulator_pointer connection_info, + const emulator_object connection_info_length) + { + auto port_name = read_unicode_string(c.emu, server_port_name); + c.win_emu.log.print(color::dark_gray, "NtConnectPort: %s\n", u16_to_u8(port_name).c_str()); + + port p{}; + p.name = std::move(port_name); + + if (connection_info) + { + std::vector zero_mem{}; + zero_mem.resize(connection_info_length.read(), 0); + c.emu.write_memory(connection_info, zero_mem.data(), zero_mem.size()); + } + + client_shared_memory.access([&](PORT_VIEW64& view) { + p.view_base = c.emu.allocate_memory(view.ViewSize, memory_permission::read_write); + view.ViewBase = p.view_base; + view.ViewRemoteBase = view.ViewBase; + }); + + const auto handle = c.proc.ports.store(std::move(p)); + client_port_handle.write(handle); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtReadVirtualMemory(const syscall_context& c, const handle process_handle, + const emulator_pointer base_address, const emulator_pointer buffer, + const ULONG number_of_bytes_to_read, + const emulator_object number_of_bytes_read) + { + number_of_bytes_read.write(0); + + if (process_handle != CURRENT_PROCESS) + { + return STATUS_NOT_SUPPORTED; + } + + std::vector memory{}; + memory.resize(number_of_bytes_read); + + if (!c.emu.try_read_memory(base_address, memory.data(), memory.size())) + { + return STATUS_INVALID_ADDRESS; + } + + c.emu.write_memory(buffer, memory.data(), memory.size()); + number_of_bytes_read.write(number_of_bytes_to_read); + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtDeviceIoControlFile(const syscall_context& c, const handle file_handle, const handle event, + const emulator_pointer /*PIO_APC_ROUTINE*/ apc_routine, + const emulator_pointer apc_context, + const emulator_object>> io_status_block, + const ULONG io_control_code, const emulator_pointer input_buffer, + const ULONG input_buffer_length, const emulator_pointer output_buffer, + const ULONG output_buffer_length) + { + auto* device = c.proc.devices.get(file_handle); + if (!device) + { + return STATUS_INVALID_HANDLE; + } + + io_device_context context{c.emu}; + context.event = event; + context.apc_routine = apc_routine; + context.apc_context = apc_context; + context.io_status_block = io_status_block; + context.io_control_code = io_control_code; + context.input_buffer = input_buffer; + context.input_buffer_length = input_buffer_length; + context.output_buffer = output_buffer; + context.output_buffer_length = output_buffer_length; + + return device->execute_ioctl(c.win_emu, context); + } + + NTSTATUS handle_NtQueryWnfStateData() + { + // puts("NtQueryWnfStateData not supported"); + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtQueryWnfStateNameInformation() + { + // puts("NtQueryWnfStateNameInformation not supported"); + // return STATUS_NOT_SUPPORTED; + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtOpenThreadToken(const syscall_context&, const handle thread_handle, + const ACCESS_MASK /*desired_access*/, const BOOLEAN /*open_as_self*/, + const emulator_object token_handle) + { + if (thread_handle != CURRENT_THREAD) + { + return STATUS_NOT_SUPPORTED; + } + + token_handle.write(CURRENT_THREAD_TOKEN); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtOpenThreadTokenEx(const syscall_context& c, const handle thread_handle, + const ACCESS_MASK desired_access, const BOOLEAN open_as_self, + const ULONG /*handle_attributes*/, const emulator_object token_handle) + { + return handle_NtOpenThreadToken(c, thread_handle, desired_access, open_as_self, token_handle); + } + + NTSTATUS handle_NtOpenProcessToken(const syscall_context&, const handle process_handle, + const ACCESS_MASK /*desired_access*/, const emulator_object token_handle) + { + if (process_handle != CURRENT_PROCESS) + { + return STATUS_NOT_SUPPORTED; + } + + token_handle.write(CURRENT_PROCESS_TOKEN); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtOpenProcessTokenEx(const syscall_context& c, const handle process_handle, + const ACCESS_MASK desired_access, const ULONG /*handle_attributes*/, + const emulator_object token_handle) + { + return handle_NtOpenProcessToken(c, process_handle, desired_access, token_handle); + } + + NTSTATUS handle_NtQuerySecurityAttributesToken() + { + // puts("NtQuerySecurityAttributesToken not supported"); + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtQueryLicenseValue() + { + // puts("NtQueryLicenseValue not supported"); + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtTestAlert() + { + // puts("NtTestAlert not supported"); + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtUserSystemParametersInfo() + { + return STATUS_NOT_SUPPORTED; + } + + TOKEN_TYPE get_token_type(const handle token_handle) + { + return token_handle == DUMMY_IMPERSONATION_TOKEN // + ? TokenImpersonation + : TokenPrimary; + } + + NTSTATUS handle_NtDuplicateToken(const syscall_context&, const handle existing_token_handle, + ACCESS_MASK /*desired_access*/, + const emulator_object>> + /*object_attributes*/, + const BOOLEAN /*effective_only*/, const TOKEN_TYPE type, + const emulator_object new_token_handle) + { + if (get_token_type(existing_token_handle) == type) + { + new_token_handle.write(existing_token_handle); + } + else if (type == TokenPrimary) + { + new_token_handle.write(CURRENT_PROCESS_TOKEN); + } + else + { + new_token_handle.write(DUMMY_IMPERSONATION_TOKEN); + } + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtQueryTimerResolution(const syscall_context&, const emulator_object maximum_time, + const emulator_object minimum_time, + const emulator_object current_time) + { + maximum_time.write_if_valid(0x0002625a); + minimum_time.write_if_valid(0x00001388); + current_time.write_if_valid(0x00002710); + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtQueryInformationToken(const syscall_context& c, const handle token_handle, + const TOKEN_INFORMATION_CLASS token_information_class, + const uint64_t token_information, const ULONG token_information_length, + const emulator_object return_length) + { + if (token_handle != CURRENT_PROCESS_TOKEN && token_handle != CURRENT_THREAD_TOKEN && + token_handle != CURRENT_THREAD_EFFECTIVE_TOKEN && token_handle != DUMMY_IMPERSONATION_TOKEN) + { + return STATUS_NOT_SUPPORTED; + } + + const uint8_t sid[] = { + 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x84, 0x94, + 0xD4, 0x04, 0x4B, 0x68, 0x42, 0x34, 0x23, 0xBE, 0x69, 0x4E, 0xE9, 0x03, 0x00, 0x00, + }; + + if (token_information_class == TokenUser) + { + constexpr auto required_size = sizeof(sid) + 0x10; + return_length.write(required_size); + + if (required_size > token_information_length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + TOKEN_USER64 user{}; + user.User.Attributes = 0; + user.User.Sid = token_information + 0x10; + + emulator_object{c.emu, token_information}.write(user); + c.emu.write_memory(token_information + 0x10, sid, sizeof(sid)); + return STATUS_SUCCESS; + } + + if (token_information_class == TokenType) + { + constexpr auto required_size = sizeof(TOKEN_TYPE); + return_length.write(required_size); + + if (required_size > token_information_length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + emulator_object{c.emu, token_information}.write(get_token_type(token_handle)); + return STATUS_SUCCESS; + } + + if (token_information_class == TokenSessionId) + { + constexpr auto required_size = sizeof(ULONG); + return_length.write(required_size); + + if (required_size > token_information_length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + emulator_object{c.emu, token_information}.write(1); + return STATUS_SUCCESS; + } + + if (token_information_class == TokenPrivateNameSpace) + { + constexpr auto required_size = sizeof(ULONG); + return_length.write(required_size); + + if (required_size > token_information_length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + emulator_object{c.emu, token_information}.write(0); + return STATUS_SUCCESS; + } + + if (token_information_class == TokenUIAccess) + { + constexpr auto required_size = sizeof(ULONG); + return_length.write(required_size); + + if (required_size > token_information_length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + emulator_object{c.emu, token_information}.write(1); + return STATUS_SUCCESS; + } + + if (token_information_class == TokenElevation) + { + constexpr auto required_size = sizeof(TOKEN_ELEVATION); + return_length.write(required_size); + + if (required_size > token_information_length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + c.emu.write_memory(token_information, TOKEN_ELEVATION{ + .TokenIsElevated = 0, + }); + return STATUS_SUCCESS; + } + + if (token_information_class == TokenIsAppContainer) + { + constexpr auto required_size = sizeof(ULONG); + return_length.write(required_size); + + if (required_size > token_information_length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + emulator_object{c.emu, token_information}.write(0); + return STATUS_SUCCESS; + } + + if (token_information_class == TokenStatistics) + { + constexpr auto required_size = sizeof(TOKEN_STATISTICS); + return_length.write(required_size); + + if (required_size > token_information_length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + c.emu.write_memory(token_information, TOKEN_STATISTICS{}); + + return STATUS_SUCCESS; + } + + if (token_information_class == TokenSecurityAttributes) + { + constexpr auto required_size = sizeof(TOKEN_SECURITY_ATTRIBUTES_INFORMATION); + return_length.write(required_size); + + if (required_size > token_information_length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + c.emu.write_memory(token_information, TOKEN_SECURITY_ATTRIBUTES_INFORMATION{ + .Version = 0, + .Reserved = {}, + .AttributeCount = 0, + .Attribute = {}, + }); + + return STATUS_SUCCESS; + } + + if (token_information_class == TokenIntegrityLevel) + { + constexpr auto required_size = sizeof(sid) + sizeof(TOKEN_MANDATORY_LABEL64); + return_length.write(required_size); + + if (required_size > token_information_length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + TOKEN_MANDATORY_LABEL64 label{}; + label.Label.Attributes = 0; + label.Label.Sid = token_information + sizeof(TOKEN_MANDATORY_LABEL64); + + emulator_object{c.emu, token_information}.write(label); + c.emu.write_memory(token_information + sizeof(TOKEN_MANDATORY_LABEL64), sid, sizeof(sid)); + return STATUS_SUCCESS; + } + + if (token_information_class == TokenBnoIsolation) + { + constexpr auto required_size = sizeof(TOKEN_BNO_ISOLATION_INFORMATION64); + return_length.write(required_size); + + if (required_size > token_information_length) + { + return STATUS_BUFFER_TOO_SMALL; + } + + c.emu.write_memory(token_information, TOKEN_BNO_ISOLATION_INFORMATION64{ + .IsolationPrefix = 0, + .IsolationEnabled = 0, + }); + + return STATUS_SUCCESS; + } + + printf("Unsupported token info class: %X\n", token_information_class); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtDxgkIsFeatureEnabled() + { + // puts("NtDxgkIsFeatureEnabled not supported"); + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtQueryInstallUILanguage() + { + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtUserDisplayConfigGetDeviceInfo() + { + // puts("NtUserDisplayConfigGetDeviceInfo not supported"); + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtGdiInit(const syscall_context& c) + { + c.proc.peb.access([&](PEB64& peb) { + if (!peb.GdiSharedHandleTable) + { + peb.GdiSharedHandleTable = reinterpret_cast::PVOID*>( + c.proc.base_allocator.reserve().ptr()); + } + }); + + return STATUS_WAIT_1; + } + + NTSTATUS handle_NtGdiInit2(const syscall_context& c) + { + handle_NtGdiInit(c); + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtGetMUIRegistryInfo() + { + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtUserRegisterWindowMessage() + { + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtUserGetThreadState() + { + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtIsUILanguageComitted() + { + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtUpdateWnfStateData() + { + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtGetNlsSectionPtr() + { + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtAlpcSendWaitReceivePort(const syscall_context& c, const handle port_handle, const ULONG /*flags*/, + const emulator_object /*send_message*/, + const emulator_object + /*send_message_attributes*/ + , + const emulator_object receive_message, + const emulator_object::SIZE_T> /*buffer_length*/, + const emulator_object + /*receive_message_attributes*/, + const emulator_object /*timeout*/) + { + const auto* port = c.proc.ports.get(port_handle); + if (!port) + { + return STATUS_INVALID_HANDLE; + } + + if (port->name != u"\\Windows\\ApiPort") + { + puts("!!! BAD PORT"); + return STATUS_NOT_SUPPORTED; + } + + // TODO: Fix this. This is broken and wrong. + + const emulator_object>> data{c.emu, receive_message.value() + 0x48}; + const auto dest = data.read(); + const auto base = dest.Base; + + const auto value = base + 0x10; + c.emu.write_memory(base + 8, &value, sizeof(value)); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtInitializeNlsFiles(const syscall_context& c, const emulator_object base_address, + const emulator_object default_locale_id, + const emulator_object /*default_casing_table_size*/) + { + const auto locale_file = utils::io::read_file(R"(C:\Windows\System32\locale.nls)"); + if (locale_file.empty()) + { + return STATUS_FILE_INVALID; + } + + const auto size = page_align_up(locale_file.size()); + const auto base = c.emu.allocate_memory(size, memory_permission::read); + c.emu.write_memory(base, locale_file.data(), locale_file.size()); + + base_address.write(base); + default_locale_id.write(0x407); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtContinue(const syscall_context& c, const emulator_object thread_context, + const BOOLEAN /*raise_alert*/) + { + c.write_status = false; + + const auto context = thread_context.read(); + context_frame::restore(c.emu, context); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtTerminateProcess(const syscall_context& c, const handle process_handle, NTSTATUS exit_status) + { + if (process_handle == 0) + { + for (auto& thread : c.proc.threads | std::views::values) + { + if (&thread != c.proc.active_thread) + { + thread.exit_status = exit_status; + } + } + + return STATUS_SUCCESS; + } + + if (process_handle == CURRENT_PROCESS) + { + c.proc.exit_status = exit_status; + c.emu.stop(); + return STATUS_SUCCESS; + } + + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtReadFile(const syscall_context& c, const handle file_handle, const uint64_t /*event*/, + const uint64_t /*apc_routine*/, const uint64_t /*apc_context*/, + const emulator_object>> io_status_block, + uint64_t buffer, const ULONG length, + const emulator_object /*byte_offset*/, + const emulator_object /*key*/) + { + const auto* f = c.proc.files.get(file_handle); + if (!f) + { + return STATUS_INVALID_HANDLE; + } + + std::string temp_buffer{}; + temp_buffer.resize(length); + + const auto bytes_read = fread(temp_buffer.data(), 1, temp_buffer.size(), f->handle); + + if (io_status_block) + { + IO_STATUS_BLOCK> block{}; + block.Information = bytes_read; + io_status_block.write(block); + } + + c.emu.write_memory(buffer, temp_buffer.data(), temp_buffer.size()); + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtWriteFile(const syscall_context& c, const handle file_handle, const uint64_t /*event*/, + const uint64_t /*apc_routine*/, const uint64_t /*apc_context*/, + const emulator_object>> io_status_block, + uint64_t buffer, const ULONG length, + const emulator_object /*byte_offset*/, + const emulator_object /*key*/) + { + std::string temp_buffer{}; + temp_buffer.resize(length); + c.emu.read_memory(buffer, temp_buffer.data(), temp_buffer.size()); + + if (file_handle == STDOUT_HANDLE) + { + if (io_status_block) + { + IO_STATUS_BLOCK> block{}; + block.Information = length; + io_status_block.write(block); + } + + if (!temp_buffer.ends_with("\n")) + { + temp_buffer.push_back('\n'); + } + + c.win_emu.on_stdout(temp_buffer); + c.win_emu.log.info("%.*s", static_cast(temp_buffer.size()), temp_buffer.data()); + + return STATUS_SUCCESS; + } + + const auto* f = c.proc.files.get(file_handle); + if (!f) + { + return STATUS_INVALID_HANDLE; + } + + const auto bytes_written = fwrite(temp_buffer.data(), 1, temp_buffer.size(), f->handle); + + if (io_status_block) + { + IO_STATUS_BLOCK> block{}; + block.Information = bytes_written; + io_status_block.write(block); + } + + return STATUS_SUCCESS; + } + + constexpr std::u16string map_mode(const ACCESS_MASK desired_access, const ULONG create_disposition) + { + std::u16string mode = u""; + + switch (create_disposition) + { + case FILE_CREATE: + case FILE_SUPERSEDE: + if (desired_access & GENERIC_WRITE) + { + mode = u"wb"; + } + break; + + case FILE_OPEN: + case FILE_OPEN_IF: + if (desired_access & GENERIC_WRITE) + { + mode = u"r+b"; + } + else if (desired_access & GENERIC_READ || desired_access & SYNCHRONIZE) + { + mode = u"rb"; + } + break; + + case FILE_OVERWRITE: + case FILE_OVERWRITE_IF: + if (desired_access & GENERIC_WRITE) + { + mode = u"w+b"; + } + break; + + default: + mode = u""; + break; + } + + if (desired_access & FILE_APPEND_DATA) + { + mode = u"a+b"; + } + + return mode; + } + + NTSTATUS handle_NtCreateFile(const syscall_context& c, const emulator_object file_handle, + ACCESS_MASK desired_access, + const emulator_object>> object_attributes, + const emulator_object>> /*io_status_block*/, + const emulator_object /*allocation_size*/, ULONG /*file_attributes*/, + ULONG /*share_access*/, ULONG create_disposition, ULONG create_options, + uint64_t ea_buffer, ULONG ea_length) + { + const auto attributes = object_attributes.read(); + auto filename = + read_unicode_string(c.emu, reinterpret_cast>*>(attributes.ObjectName)); + + auto printer = utils::finally( + [&] { c.win_emu.log.print(color::dark_gray, "--> Opening file: %s\n", u16_to_u8(filename).c_str()); }); + + constexpr std::u16string_view device_prefix = u"\\Device\\"; + if (filename.starts_with(device_prefix)) + { + const io_device_creation_data data{ + .buffer = ea_buffer, + .length = ea_length, + }; + + auto device_name = filename.substr(device_prefix.size()); + io_device_container container{std::move(device_name), c.win_emu, data}; + + const auto handle = c.proc.devices.store(std::move(container)); + file_handle.write(handle); + + return STATUS_SUCCESS; + } + + handle root_handle{}; + root_handle.bits = attributes.RootDirectory; + if (root_handle.value.is_pseudo && (filename == u"\\Reference" || filename == u"\\Connect")) + { + file_handle.write(root_handle); + return STATUS_SUCCESS; + } + + file f{}; + f.name = std::move(filename); + + if (attributes.RootDirectory) + { + const auto* root = c.proc.files.get(attributes.RootDirectory); + if (!root) + { + return STATUS_INVALID_HANDLE; + } + + f.name = root->name + f.name; + } + + printer.cancel(); + + if (f.name.ends_with(u"\\") || create_options & FILE_DIRECTORY_FILE) + { + c.win_emu.log.print(color::dark_gray, "--> Opening folder: %s\n", u16_to_u8(f.name).c_str()); + + if (create_disposition & FILE_CREATE) + { + std::error_code ec{}; + std::filesystem::create_directory(f.name, ec); + + if (ec) + { + return STATUS_ACCESS_DENIED; + } + } + else if (!std::filesystem::is_directory(f.name)) + { + return STATUS_OBJECT_NAME_NOT_FOUND; + } + + const auto handle = c.proc.files.store(std::move(f)); + file_handle.write(handle); + + return STATUS_SUCCESS; + } + + c.win_emu.log.print(color::dark_gray, "--> Opening file: %s\n", u16_to_u8(f.name).c_str()); + + std::u16string mode = map_mode(desired_access, create_disposition); + + if (mode.empty()) + { + return STATUS_NOT_SUPPORTED; + } + + FILE* file{}; + + const auto error = open_unicode(&file, f.name, mode); + + if (!file) + { + switch (error) + { + case ENOENT: + return STATUS_OBJECT_NAME_NOT_FOUND; + case EACCES: + return STATUS_ACCESS_DENIED; + case EISDIR: + return STATUS_FILE_IS_A_DIRECTORY; + default: + return STATUS_NOT_SUPPORTED; + } + } + + f.handle = file; + + const auto handle = c.proc.files.store(std::move(f)); + file_handle.write(handle); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtQueryAttributesFile( + const syscall_context& c, const emulator_object>> object_attributes, + const emulator_object file_information) + { + if (!object_attributes) + { + return STATUS_INVALID_PARAMETER; + } + + const auto attributes = object_attributes.read(); + if (!attributes.ObjectName) + { + return STATUS_INVALID_PARAMETER; + } + + const auto filename = read_unicode_string( + c.emu, emulator_object>>{c.emu, attributes.ObjectName}); + const auto u8_filename = u16_to_u8(filename); + + struct _stat64 file_stat{}; + if (_stat64(u8_filename.c_str(), &file_stat) != 0) + { + return STATUS_OBJECT_NAME_NOT_FOUND; + } + + file_information.access([&](FILE_BASIC_INFORMATION& info) { + info.CreationTime = convert_unix_to_windows_time(file_stat.st_atime); + info.LastAccessTime = convert_unix_to_windows_time(file_stat.st_atime); + info.LastWriteTime = convert_unix_to_windows_time(file_stat.st_mtime); + info.ChangeTime = info.LastWriteTime; + info.FileAttributes = FILE_ATTRIBUTE_NORMAL; + }); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtOpenFile(const syscall_context& c, const emulator_object file_handle, + const ACCESS_MASK desired_access, + const emulator_object>> object_attributes, + const emulator_object>> io_status_block, + const ULONG share_access, const ULONG open_options) + { + return handle_NtCreateFile(c, file_handle, desired_access, object_attributes, io_status_block, {c.emu}, 0, + share_access, FILE_OPEN, open_options, 0, 0); + } + + NTSTATUS handle_NtQueryObject(const syscall_context&, const handle /*handle*/, + const OBJECT_INFORMATION_CLASS /*object_information_class*/, + const emulator_pointer /*object_information*/, + const ULONG /*object_information_length*/, + const emulator_object /*return_length*/) + { + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtQueryInformationJobObject() + { + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtSetSystemInformation() + { + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtAccessCheck() + { + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtUserGetKeyboardLayout() + { + return STATUS_NOT_SUPPORTED; + } + + NTSTATUS handle_NtRaiseHardError(const syscall_context& c, const NTSTATUS error_status, + const ULONG /*number_of_parameters*/, + const emulator_object>> + /*unicode_string_parameter_mask*/, + const emulator_object /*parameters*/, + const HARDERROR_RESPONSE_OPTION /*valid_response_option*/, + const emulator_object response) + { + if (response) + { + response.write(ResponseAbort); + } + + c.proc.exit_status = error_status; + c.proc.exception_rip = c.emu.read_instruction_pointer(); + c.emu.stop(); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtRaiseException(const syscall_context& c, + const emulator_object>> + /*exception_record*/, + const emulator_object thread_context, BOOLEAN handle_exception) + { + if (handle_exception) + { + puts("Unhandled exceptions not supported yet!"); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + c.proc.exception_rip = thread_context.read().Rip; + c.emu.stop(); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtOpenSemaphore(const syscall_context& c, const emulator_object semaphore_handle, + const ACCESS_MASK /*desired_access*/, + const emulator_object>> object_attributes) + { + if (!object_attributes) + { + return STATUS_INVALID_PARAMETER; + } + + const auto attributes = object_attributes.read(); + if (!attributes.ObjectName) + { + return STATUS_INVALID_PARAMETER; + } + + const auto name = read_unicode_string( + c.emu, emulator_object>>{c.emu, attributes.ObjectName}); + if (name.empty()) + { + return STATUS_INVALID_PARAMETER; + } + + for (const auto& semaphore : c.proc.semaphores) + { + if (semaphore.second.name == name) + { + semaphore_handle.write(c.proc.semaphores.make_handle(semaphore.first)); + return STATUS_SUCCESS; + } + } + + return STATUS_OBJECT_NAME_NOT_FOUND; + } + + NTSTATUS handle_NtCreateSemaphore(const syscall_context& c, const emulator_object semaphore_handle, + const ACCESS_MASK /*desired_access*/, + const emulator_object>> object_attributes, + const ULONG initial_count, const ULONG maximum_count) + { + semaphore s{}; + s.current_count = initial_count; + s.max_count = maximum_count; + + if (object_attributes) + { + const auto attributes = object_attributes.read(); + if (attributes.ObjectName) + { + s.name = read_unicode_string( + c.emu, reinterpret_cast>*>(attributes.ObjectName)); + } + } + + if (!s.name.empty()) + { + for (const auto& semaphore : c.proc.semaphores) + { + if (semaphore.second.name == s.name) + { + return STATUS_OBJECT_NAME_EXISTS; + } + } + } + + const auto handle = c.proc.semaphores.store(std::move(s)); + semaphore_handle.write(handle); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtAddAtomEx(const syscall_context& c, const uint64_t atom_name, const ULONG length, + const emulator_object atom, const ULONG /*flags*/) + { + std::wstring name{}; + name.resize(length / 2); + + c.emu.read_memory(atom_name, name.data(), length); + + uint16_t index = 0; + if (!c.proc.atoms.empty()) + { + auto i = c.proc.atoms.end(); + --i; + index = i->first + 1; + } + + std::optional last_entry{}; + for (auto& entry : c.proc.atoms) + { + if (entry.second == name) + { + if (atom) + { + atom.write(entry.first); + return STATUS_SUCCESS; + } + } + + if (entry.first > 0) + { + if (!last_entry) + { + index = 0; + } + else + { + const auto diff = entry.first - *last_entry; + if (diff > 1) + { + index = *last_entry + 1; + } + } + } + + last_entry = entry.first; + } + + c.proc.atoms[index] = std::move(name); + atom.write(index); + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtUnmapViewOfSection(const syscall_context& c, const handle process_handle, + const uint64_t base_address) + { + if (process_handle != CURRENT_PROCESS) + { + return STATUS_NOT_SUPPORTED; + } + + const auto* mod = c.proc.mod_manager.find_by_address(base_address); + if (!mod) + { + puts("Unmapping non-module section not supported!"); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + if (c.proc.mod_manager.unmap(base_address)) + { + return STATUS_SUCCESS; + } + + return STATUS_INVALID_PARAMETER; + } + + NTSTATUS handle_NtUnmapViewOfSectionEx(const syscall_context& c, const handle process_handle, + const uint64_t base_address, const ULONG /*flags*/) + { + return handle_NtUnmapViewOfSection(c, process_handle, base_address); + } + + NTSTATUS handle_NtCreateThreadEx(const syscall_context& c, const emulator_object thread_handle, + const ACCESS_MASK /*desired_access*/, + const emulator_object>> + /*object_attributes*/, + const handle process_handle, const uint64_t start_routine, const uint64_t argument, + const ULONG /*create_flags*/, const EmulatorTraits::SIZE_T /*zero_bits*/, + const EmulatorTraits::SIZE_T stack_size, + const EmulatorTraits::SIZE_T /*maximum_stack_size*/, + const emulator_object>> attribute_list) + { + if (process_handle != CURRENT_PROCESS) + { + return STATUS_NOT_SUPPORTED; + } + + const auto h = c.proc.create_thread(c.emu, start_routine, argument, stack_size); + thread_handle.write(h); + + if (!attribute_list) + { + return STATUS_SUCCESS; + } + + const auto* thread = c.proc.threads.get(h); + + const emulator_object>> attributes{ + c.emu, attribute_list.value() + offsetof(PS_ATTRIBUTE_LIST>, Attributes)}; + + const auto total_length = attribute_list.read().TotalLength; + + constexpr auto entry_size = sizeof(PS_ATTRIBUTE>); + constexpr auto header_size = sizeof(PS_ATTRIBUTE_LIST>) - entry_size; + const auto attribute_count = (total_length - header_size) / entry_size; + + for (size_t i = 0; i < attribute_count; ++i) + { + attributes.access( + [&](const PS_ATTRIBUTE>& attribute) { + const auto type = attribute.Attribute & ~PS_ATTRIBUTE_THREAD; + + if (type == PsAttributeClientId) + { + const auto client_id = thread->teb->read().ClientId; + write_attribute(c.emu, attribute, client_id); + } + else if (type == PsAttributeTebAddress) + { + write_attribute(c.emu, attribute, thread->teb->ptr()); + } + else + { + printf("Unsupported thread attribute type: %" PRIx64 "\n", type); + } + }, + i); + } + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtQueryDebugFilterState() + { + return FALSE; + } + + bool is_awaitable_object_type(const handle h) + { + return h.value.type == handle_types::thread // + || h.value.type == handle_types::mutant // + || h.value.type == handle_types::event; + } + + NTSTATUS handle_NtWaitForMultipleObjects(const syscall_context& c, const ULONG count, + const emulator_object handles, const WAIT_TYPE wait_type, + const BOOLEAN alertable, const emulator_object timeout) + { + if (alertable) + { + c.win_emu.log.print(color::gray, "Alertable NtWaitForMultipleObjects not supported yet!\n"); + } + + if (wait_type != WaitAny && wait_type != WaitAll) + { + puts("Wait type not supported!"); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + auto& t = c.win_emu.current_thread(); + t.await_objects.clear(); + t.await_any = wait_type == WaitAny; + + for (ULONG i = 0; i < count; ++i) + { + const auto h = handles.read(i); + + if (!is_awaitable_object_type(h)) + { + c.win_emu.log.print(color::gray, "Unsupported handle type for NtWaitForMultipleObjects: %d!\n", + h.value.type); + return STATUS_NOT_SUPPORTED; + } + } + + if (timeout.value() && !t.await_time.has_value()) + { + t.await_time = convert_delay_interval_to_time_point(timeout.read()); + } + + c.win_emu.yield_thread(); + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtWaitForSingleObject(const syscall_context& c, const handle h, const BOOLEAN alertable, + const emulator_object timeout) + { + if (alertable) + { + c.win_emu.log.print(color::gray, "Alertable NtWaitForSingleObject not supported yet!\n"); + } + + if (!is_awaitable_object_type(h)) + { + c.win_emu.log.print(color::gray, "Unsupported handle type for NtWaitForSingleObject: %d!\n", h.value.type); + return STATUS_NOT_SUPPORTED; + } + + auto& t = c.win_emu.current_thread(); + t.await_objects = {h}; + t.await_any = false; + + if (timeout.value() && !t.await_time.has_value()) + { + t.await_time = convert_delay_interval_to_time_point(timeout.read()); + } + + c.win_emu.yield_thread(); + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtTerminateThread(const syscall_context& c, const handle thread_handle, const NTSTATUS exit_status) + { + auto* thread = !thread_handle.bits ? c.proc.active_thread : c.proc.threads.get(thread_handle); + + if (!thread) + { + return STATUS_INVALID_HANDLE; + } + + thread->exit_status = exit_status; + if (thread == c.proc.active_thread) + { + c.win_emu.yield_thread(); + } + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtDelayExecution(const syscall_context& c, const BOOLEAN alertable, + const emulator_object delay_interval) + { + if (alertable) + { + puts("Alertable NtDelayExecution not supported yet!"); + c.emu.stop(); + return STATUS_NOT_SUPPORTED; + } + + auto& t = c.win_emu.current_thread(); + t.await_time = convert_delay_interval_to_time_point(delay_interval.read()); + + c.win_emu.yield_thread(); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtAlertThreadByThreadId(const syscall_context& c, const uint64_t thread_id) + { + for (auto& t : c.proc.threads) + { + if (t.second.id == thread_id) + { + t.second.alerted = true; + return STATUS_SUCCESS; + } + } + + return STATUS_INVALID_HANDLE; + } + + NTSTATUS handle_NtAlertThreadByThreadIdEx(const syscall_context& c, const uint64_t thread_id, + const emulator_object>> lock) + { + if (lock.value()) + { + c.win_emu.log.print(color::gray, "NtAlertThreadByThreadIdEx with lock not supported yet!"); + // c.emu.stop(); + // return STATUS_NOT_SUPPORTED; + } + + return handle_NtAlertThreadByThreadId(c, thread_id); + } + + NTSTATUS handle_NtWaitForAlertByThreadId(const syscall_context& c, const uint64_t, + const emulator_object timeout) + { + auto& t = c.win_emu.current_thread(); + t.waiting_for_alert = true; + + if (timeout.value() && !t.await_time.has_value()) + { + t.await_time = convert_delay_interval_to_time_point(timeout.read()); + } + + c.win_emu.yield_thread(); + + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtGetCurrentProcessorNumberEx(const syscall_context&, + const emulator_object processor_number) + { + constexpr PROCESSOR_NUMBER number{}; + processor_number.write(number); + return STATUS_SUCCESS; + } + + NTSTATUS handle_NtGetContextThread(const syscall_context& c, handle thread_handle, + const emulator_object thread_context) + { + const auto* thread = thread_handle == CURRENT_THREAD ? c.proc.active_thread : c.proc.threads.get(thread_handle); + + if (!thread) + { + return STATUS_INVALID_HANDLE; + } + + c.proc.active_thread->save(c.emu); + const auto _ = utils::finally([&] { c.proc.active_thread->restore(c.emu); }); + + thread->restore(c.emu); + + thread_context.access([&](CONTEXT64& context) { + if (context.ContextFlags & CONTEXT_DEBUG_REGISTERS_64) + { + c.win_emu.log.print(color::pink, "--> Reading debug registers!\n"); + } + + context_frame::save(c.emu, context); + }); + + return STATUS_SUCCESS; + } } void syscall_dispatcher::add_handlers(std::map& handler_mapping) { #define add_handler(syscall) \ - do \ - { \ - handler_mapping[#syscall] = make_syscall_handler(); \ - } while(0) + do \ + { \ + handler_mapping[#syscall] = make_syscall_handler(); \ + } while (0) - add_handler(NtSetInformationThread); - add_handler(NtSetEvent); - add_handler(NtClose); - add_handler(NtOpenKey); - add_handler(NtAllocateVirtualMemory); - add_handler(NtQueryInformationProcess); - add_handler(NtSetInformationProcess); - add_handler(NtFreeVirtualMemory); - add_handler(NtQueryVirtualMemory); - add_handler(NtOpenThreadToken); - add_handler(NtOpenThreadTokenEx); - add_handler(NtQueryPerformanceCounter); - add_handler(NtQuerySystemInformation); - add_handler(NtCreateEvent); - add_handler(NtProtectVirtualMemory); - add_handler(NtOpenDirectoryObject); - add_handler(NtTraceEvent); - add_handler(NtAllocateVirtualMemoryEx); - add_handler(NtCreateIoCompletion); - add_handler(NtCreateWaitCompletionPacket); - add_handler(NtCreateWorkerFactory); - add_handler(NtManageHotPatch); - add_handler(NtOpenSection); - add_handler(NtMapViewOfSection); - add_handler(NtOpenSymbolicLinkObject); - add_handler(NtQuerySymbolicLinkObject); - add_handler(NtQuerySystemInformationEx); - add_handler(NtOpenFile); - add_handler(NtQueryVolumeInformationFile); - add_handler(NtApphelpCacheControl); - add_handler(NtCreateSection); - add_handler(NtConnectPort); - add_handler(NtCreateFile); - add_handler(NtDeviceIoControlFile); - add_handler(NtQueryWnfStateData); - add_handler(NtOpenProcessToken); - add_handler(NtOpenProcessTokenEx); - add_handler(NtQuerySecurityAttributesToken); - add_handler(NtQueryLicenseValue); - add_handler(NtTestAlert); - add_handler(NtContinue); - add_handler(NtTerminateProcess); - add_handler(NtWriteFile); - add_handler(NtRaiseHardError); - add_handler(NtCreateSemaphore); - add_handler(NtOpenSemaphore); - add_handler(NtReadVirtualMemory); - add_handler(NtQueryInformationToken); - add_handler(NtDxgkIsFeatureEnabled); - add_handler(NtAddAtomEx); - add_handler(NtInitializeNlsFiles); - add_handler(NtUnmapViewOfSection); - add_handler(NtUnmapViewOfSectionEx); - add_handler(NtDuplicateObject); - add_handler(NtQueryInformationThread); - add_handler(NtQueryWnfStateNameInformation); - add_handler(NtAlpcSendWaitReceivePort); - add_handler(NtGdiInit); - add_handler(NtGdiInit2); - add_handler(NtUserGetThreadState); - add_handler(NtOpenKeyEx); - add_handler(NtUserDisplayConfigGetDeviceInfo); - add_handler(NtOpenEvent); - add_handler(NtGetMUIRegistryInfo); - add_handler(NtIsUILanguageComitted); - add_handler(NtQueryInstallUILanguage); - add_handler(NtUpdateWnfStateData); - add_handler(NtRaiseException); - add_handler(NtQueryInformationJobObject); - add_handler(NtSetSystemInformation); - add_handler(NtQueryInformationFile); - add_handler(NtCreateThreadEx); - add_handler(NtQueryDebugFilterState); - add_handler(NtWaitForSingleObject); - add_handler(NtTerminateThread); - add_handler(NtDelayExecution); - add_handler(NtWaitForAlertByThreadId); - add_handler(NtAlertThreadByThreadIdEx); - add_handler(NtAlertThreadByThreadId); - add_handler(NtReadFile); - add_handler(NtSetInformationFile); - add_handler(NtUserRegisterWindowMessage); - add_handler(NtQueryValueKey); - add_handler(NtQueryKey); - add_handler(NtGetNlsSectionPtr); - add_handler(NtAccessCheck); - add_handler(NtCreateKey); - add_handler(NtNotifyChangeKey); - add_handler(NtGetCurrentProcessorNumberEx); - add_handler(NtQueryObject); - add_handler(NtQueryAttributesFile); - add_handler(NtWaitForMultipleObjects); - add_handler(NtCreateMutant); - add_handler(NtReleaseMutant); - add_handler(NtDuplicateToken); - add_handler(NtQueryTimerResolution); - add_handler(NtSetInformationKey); - add_handler(NtUserGetKeyboardLayout); - add_handler(NtQueryDirectoryFileEx); - add_handler(NtUserSystemParametersInfo); - add_handler(NtGetContextThread); + add_handler(NtSetInformationThread); + add_handler(NtSetEvent); + add_handler(NtClose); + add_handler(NtOpenKey); + add_handler(NtAllocateVirtualMemory); + add_handler(NtQueryInformationProcess); + add_handler(NtSetInformationProcess); + add_handler(NtFreeVirtualMemory); + add_handler(NtQueryVirtualMemory); + add_handler(NtOpenThreadToken); + add_handler(NtOpenThreadTokenEx); + add_handler(NtQueryPerformanceCounter); + add_handler(NtQuerySystemInformation); + add_handler(NtCreateEvent); + add_handler(NtProtectVirtualMemory); + add_handler(NtOpenDirectoryObject); + add_handler(NtTraceEvent); + add_handler(NtAllocateVirtualMemoryEx); + add_handler(NtCreateIoCompletion); + add_handler(NtCreateWaitCompletionPacket); + add_handler(NtCreateWorkerFactory); + add_handler(NtManageHotPatch); + add_handler(NtOpenSection); + add_handler(NtMapViewOfSection); + add_handler(NtOpenSymbolicLinkObject); + add_handler(NtQuerySymbolicLinkObject); + add_handler(NtQuerySystemInformationEx); + add_handler(NtOpenFile); + add_handler(NtQueryVolumeInformationFile); + add_handler(NtApphelpCacheControl); + add_handler(NtCreateSection); + add_handler(NtConnectPort); + add_handler(NtCreateFile); + add_handler(NtDeviceIoControlFile); + add_handler(NtQueryWnfStateData); + add_handler(NtOpenProcessToken); + add_handler(NtOpenProcessTokenEx); + add_handler(NtQuerySecurityAttributesToken); + add_handler(NtQueryLicenseValue); + add_handler(NtTestAlert); + add_handler(NtContinue); + add_handler(NtTerminateProcess); + add_handler(NtWriteFile); + add_handler(NtRaiseHardError); + add_handler(NtCreateSemaphore); + add_handler(NtOpenSemaphore); + add_handler(NtReadVirtualMemory); + add_handler(NtQueryInformationToken); + add_handler(NtDxgkIsFeatureEnabled); + add_handler(NtAddAtomEx); + add_handler(NtInitializeNlsFiles); + add_handler(NtUnmapViewOfSection); + add_handler(NtUnmapViewOfSectionEx); + add_handler(NtDuplicateObject); + add_handler(NtQueryInformationThread); + add_handler(NtQueryWnfStateNameInformation); + add_handler(NtAlpcSendWaitReceivePort); + add_handler(NtGdiInit); + add_handler(NtGdiInit2); + add_handler(NtUserGetThreadState); + add_handler(NtOpenKeyEx); + add_handler(NtUserDisplayConfigGetDeviceInfo); + add_handler(NtOpenEvent); + add_handler(NtGetMUIRegistryInfo); + add_handler(NtIsUILanguageComitted); + add_handler(NtQueryInstallUILanguage); + add_handler(NtUpdateWnfStateData); + add_handler(NtRaiseException); + add_handler(NtQueryInformationJobObject); + add_handler(NtSetSystemInformation); + add_handler(NtQueryInformationFile); + add_handler(NtCreateThreadEx); + add_handler(NtQueryDebugFilterState); + add_handler(NtWaitForSingleObject); + add_handler(NtTerminateThread); + add_handler(NtDelayExecution); + add_handler(NtWaitForAlertByThreadId); + add_handler(NtAlertThreadByThreadIdEx); + add_handler(NtAlertThreadByThreadId); + add_handler(NtReadFile); + add_handler(NtSetInformationFile); + add_handler(NtUserRegisterWindowMessage); + add_handler(NtQueryValueKey); + add_handler(NtQueryKey); + add_handler(NtGetNlsSectionPtr); + add_handler(NtAccessCheck); + add_handler(NtCreateKey); + add_handler(NtNotifyChangeKey); + add_handler(NtGetCurrentProcessorNumberEx); + add_handler(NtQueryObject); + add_handler(NtQueryAttributesFile); + add_handler(NtWaitForMultipleObjects); + add_handler(NtCreateMutant); + add_handler(NtReleaseMutant); + add_handler(NtDuplicateToken); + add_handler(NtQueryTimerResolution); + add_handler(NtSetInformationKey); + add_handler(NtUserGetKeyboardLayout); + add_handler(NtQueryDirectoryFileEx); + add_handler(NtUserSystemParametersInfo); + add_handler(NtGetContextThread); #undef add_handler } diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index 042b4aa5..04f537ff 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -10,1080 +10,1029 @@ constexpr auto MAX_INSTRUCTIONS_PER_TIME_SLICE = 100000; namespace { - template - emulator_object allocate_object_on_stack(x64_emulator& emu) - { - const auto old_sp = emu.reg(x64_register::rsp); - const auto new_sp = align_down(old_sp - sizeof(CONTEXT64), - std::max(alignof(CONTEXT64), alignof(x64_emulator::pointer_type))); - emu.reg(x64_register::rsp, new_sp); + template + emulator_object allocate_object_on_stack(x64_emulator& emu) + { + const auto old_sp = emu.reg(x64_register::rsp); + const auto new_sp = + align_down(old_sp - sizeof(CONTEXT64), std::max(alignof(CONTEXT64), alignof(x64_emulator::pointer_type))); + emu.reg(x64_register::rsp, new_sp); - return {emu, new_sp}; - } + return {emu, new_sp}; + } - void unalign_stack(x64_emulator& emu) - { - auto sp = emu.reg(x64_register::rsp); - sp = align_down(sp - 0x10, 0x10) + 8; - emu.reg(x64_register::rsp, sp); - } + void unalign_stack(x64_emulator& emu) + { + auto sp = emu.reg(x64_register::rsp); + sp = align_down(sp - 0x10, 0x10) + 8; + emu.reg(x64_register::rsp, sp); + } - void setup_stack(x64_emulator& emu, const uint64_t stack_base, const size_t stack_size) - { - const uint64_t stack_end = stack_base + stack_size; - emu.reg(x64_register::rsp, stack_end); - } + void setup_stack(x64_emulator& emu, const uint64_t stack_base, const size_t stack_size) + { + const uint64_t stack_end = stack_base + stack_size; + emu.reg(x64_register::rsp, stack_end); + } - void setup_gs_segment(x64_emulator& emu, const emulator_allocator& allocator) - { - struct msr_value - { - uint32_t id; - uint64_t value; - }; + void setup_gs_segment(x64_emulator& emu, const emulator_allocator& allocator) + { + struct msr_value + { + uint32_t id; + uint64_t value; + }; - const msr_value value{ - IA32_GS_BASE_MSR, - allocator.get_base() - }; + const msr_value value{IA32_GS_BASE_MSR, allocator.get_base()}; - emu.write_register(x64_register::msr, &value, sizeof(value)); - } + emu.write_register(x64_register::msr, &value, sizeof(value)); + } - uint64_t copy_string(x64_emulator& emu, emulator_allocator& allocator, const void* base_ptr, const uint64_t offset, - const size_t length) - { - if (!length) - { - return 0; - } + uint64_t copy_string(x64_emulator& emu, emulator_allocator& allocator, const void* base_ptr, const uint64_t offset, + const size_t length) + { + if (!length) + { + return 0; + } - const auto length_to_allocate = length + 2; - const auto str_obj = allocator.reserve(length_to_allocate); - emu.write_memory(str_obj, static_cast(base_ptr) + offset, length); + const auto length_to_allocate = length + 2; + const auto str_obj = allocator.reserve(length_to_allocate); + emu.write_memory(str_obj, static_cast(base_ptr) + offset, length); - return str_obj; - } + return str_obj; + } - ULONG copy_string_as_relative(x64_emulator& emu, emulator_allocator& allocator, const uint64_t result_base, - const void* base_ptr, const uint64_t offset, - const size_t length) - { - const auto address = copy_string(emu, allocator, base_ptr, offset, length); - if (!address) - { - return 0; - } + ULONG copy_string_as_relative(x64_emulator& emu, emulator_allocator& allocator, const uint64_t result_base, + const void* base_ptr, const uint64_t offset, const size_t length) + { + const auto address = copy_string(emu, allocator, base_ptr, offset, length); + if (!address) + { + return 0; + } - assert(address > result_base); - return static_cast(address - result_base); - } + assert(address > result_base); + return static_cast(address - result_base); + } - emulator_object clone_api_set_map(x64_emulator& emu, emulator_allocator& allocator, - const API_SET_NAMESPACE& orig_api_set_map) - { - const auto api_set_map_obj = allocator.reserve(); - const auto ns_entries_obj = allocator.reserve(orig_api_set_map.Count); - const auto hash_entries_obj = allocator.reserve(orig_api_set_map.Count); + emulator_object clone_api_set_map(x64_emulator& emu, emulator_allocator& allocator, + const API_SET_NAMESPACE& orig_api_set_map) + { + const auto api_set_map_obj = allocator.reserve(); + const auto ns_entries_obj = allocator.reserve(orig_api_set_map.Count); + const auto hash_entries_obj = allocator.reserve(orig_api_set_map.Count); - api_set_map_obj.access([&](API_SET_NAMESPACE& api_set) - { - api_set = orig_api_set_map; - api_set.EntryOffset = static_cast(ns_entries_obj.value() - api_set_map_obj.value()); - api_set.HashOffset = static_cast(hash_entries_obj.value() - api_set_map_obj.value()); - }); + api_set_map_obj.access([&](API_SET_NAMESPACE& api_set) { + api_set = orig_api_set_map; + api_set.EntryOffset = static_cast(ns_entries_obj.value() - api_set_map_obj.value()); + api_set.HashOffset = static_cast(hash_entries_obj.value() - api_set_map_obj.value()); + }); - const auto orig_ns_entries = offset_pointer(&orig_api_set_map, - orig_api_set_map.EntryOffset); - const auto orig_hash_entries = offset_pointer(&orig_api_set_map, - orig_api_set_map.HashOffset); + const auto orig_ns_entries = + offset_pointer(&orig_api_set_map, orig_api_set_map.EntryOffset); + const auto orig_hash_entries = + offset_pointer(&orig_api_set_map, orig_api_set_map.HashOffset); - for (ULONG i = 0; i < orig_api_set_map.Count; ++i) - { - auto ns_entry = orig_ns_entries[i]; - const auto hash_entry = orig_hash_entries[i]; + for (ULONG i = 0; i < orig_api_set_map.Count; ++i) + { + auto ns_entry = orig_ns_entries[i]; + const auto hash_entry = orig_hash_entries[i]; - ns_entry.NameOffset = copy_string_as_relative(emu, allocator, api_set_map_obj.value(), &orig_api_set_map, - ns_entry.NameOffset, ns_entry.NameLength); + ns_entry.NameOffset = copy_string_as_relative(emu, allocator, api_set_map_obj.value(), &orig_api_set_map, + ns_entry.NameOffset, ns_entry.NameLength); - if (!ns_entry.ValueCount) - { - continue; - } + if (!ns_entry.ValueCount) + { + continue; + } - const auto values_obj = allocator.reserve(ns_entry.ValueCount); - const auto orig_values = offset_pointer(&orig_api_set_map, - ns_entry.ValueOffset); + const auto values_obj = allocator.reserve(ns_entry.ValueCount); + const auto orig_values = offset_pointer(&orig_api_set_map, ns_entry.ValueOffset); - ns_entry.ValueOffset = static_cast(values_obj.value() - api_set_map_obj.value()); + ns_entry.ValueOffset = static_cast(values_obj.value() - api_set_map_obj.value()); - for (ULONG j = 0; j < ns_entry.ValueCount; ++j) - { - auto value = orig_values[j]; + for (ULONG j = 0; j < ns_entry.ValueCount; ++j) + { + auto value = orig_values[j]; - value.ValueOffset = copy_string_as_relative(emu, allocator, api_set_map_obj.value(), &orig_api_set_map, - value.ValueOffset, value.ValueLength); + value.ValueOffset = copy_string_as_relative(emu, allocator, api_set_map_obj.value(), &orig_api_set_map, + value.ValueOffset, value.ValueLength); - if (value.NameLength) - { - value.NameOffset = copy_string_as_relative(emu, allocator, api_set_map_obj.value(), - &orig_api_set_map, - value.NameOffset, value.NameLength); - } + if (value.NameLength) + { + value.NameOffset = copy_string_as_relative(emu, allocator, api_set_map_obj.value(), + &orig_api_set_map, value.NameOffset, value.NameLength); + } - values_obj.write(value, j); - } + values_obj.write(value, j); + } - ns_entries_obj.write(ns_entry, i); - hash_entries_obj.write(hash_entry, i); - } + ns_entries_obj.write(ns_entry, i); + hash_entries_obj.write(hash_entry, i); + } - return api_set_map_obj; - } + return api_set_map_obj; + } - emulator_object build_api_set_map(x64_emulator& emu, emulator_allocator& allocator) - { - // TODO: fix + emulator_object build_api_set_map(x64_emulator& emu, emulator_allocator& allocator) + { + // TODO: fix #ifdef OS_WINDOWS - const auto& orig_api_set_map = *NtCurrentTeb64()->ProcessEnvironmentBlock->ApiSetMap; - return clone_api_set_map(emu, allocator, orig_api_set_map); + const auto& orig_api_set_map = *NtCurrentTeb64()->ProcessEnvironmentBlock->ApiSetMap; + return clone_api_set_map(emu, allocator, orig_api_set_map); #else - return clone_api_set_map(emu, allocator, {}); + return clone_api_set_map(emu, allocator, {}); #endif - } - - emulator_allocator create_allocator(emulator& emu, const size_t size) - { - const auto base = emu.find_free_allocation_base(size); - emu.allocate_memory(base, size, memory_permission::read_write); - - return emulator_allocator{emu, base, size}; - } - - void setup_gdt(x64_emulator& emu) - { - constexpr uint64_t gdtr[4] = {0, GDT_ADDR, GDT_LIMIT, 0}; - emu.write_register(x64_register::gdtr, &gdtr, sizeof(gdtr)); - emu.allocate_memory(GDT_ADDR, GDT_LIMIT, memory_permission::read); - - emu.write_memory(GDT_ADDR + 6 * (sizeof(uint64_t)), 0xEFFE000000FFFF); - emu.reg(x64_register::cs, 0x33); - - emu.write_memory(GDT_ADDR + 5 * (sizeof(uint64_t)), 0xEFF6000000FFFF); - emu.reg(x64_register::ss, 0x2B); - } - - std::filesystem::path canonicalize_path(const std::filesystem::path& path) - { - return canonical(absolute(path)).make_preferred(); - } - - void setup_context(windows_emulator& win_emu, const emulator_settings& settings) - { - auto& emu = win_emu.emu(); - auto& context = win_emu.process(); - - setup_gdt(emu); - - context.registry = registry_manager(settings.registry_directory); - - context.kusd.setup(settings.use_relative_time); - - context.base_allocator = create_allocator(emu, PEB_SEGMENT_SIZE); - auto& allocator = context.base_allocator; - - context.peb = allocator.reserve(); - - /* Values of the following fields must be - * allocated relative to the process_params themselves - * and included in the length: - * - * CurrentDirectory - * DllPath - * ImagePathName - * CommandLine - * WindowTitle - * DesktopInfo - * ShellInfo - * RuntimeData - * RedirectionDllName - */ - - context.process_params = allocator.reserve(); - - context.process_params.access([&](RTL_USER_PROCESS_PARAMETERS64& proc_params) - { - proc_params.Flags = 0x6001; //| 0x80000000; // Prevent CsrClientConnectToServer - - proc_params.ConsoleHandle = CONSOLE_HANDLE.h; - proc_params.StandardOutput = STDOUT_HANDLE.h; - proc_params.StandardInput = STDIN_HANDLE.h; - proc_params.StandardError = proc_params.StandardOutput; - - proc_params.Environment = reinterpret_cast(allocator.copy_string(u"=::=::\\")); - allocator.copy_string(u"EMULATOR=1"); - allocator.copy_string(u"COMPUTERNAME=momo"); - allocator.copy_string(u"SystemRoot=C:\\WINDOWS"); - allocator.copy_string(u""); - - std::u16string command_line = u"\"" + settings.application.u16string() + u"\""; - - for (const auto& arg : settings.arguments) - { - command_line.push_back(u' '); - command_line.append(arg); - } - - std::u16string current_folder{}; - if (!settings.working_directory.empty()) - { - current_folder = canonicalize_path(settings.working_directory).u16string() + u"\\"; - } - else - { - current_folder = canonicalize_path(settings.application).parent_path().u16string() + u"\\"; - } - - allocator.make_unicode_string(proc_params.CommandLine, command_line); - allocator.make_unicode_string(proc_params.CurrentDirectory.DosPath, current_folder); - allocator.make_unicode_string(proc_params.ImagePathName, - canonicalize_path(settings.application).u16string()); - - const auto total_length = allocator.get_next_address() - context.process_params.value(); - - proc_params.Length = static_cast(std::max(static_cast(sizeof(proc_params)), - total_length)); - proc_params.MaximumLength = proc_params.Length; - }); - - context.peb.access([&](PEB64& peb) - { - peb.ImageBaseAddress = nullptr; - peb.ProcessParameters = context.process_params.ptr(); - peb.ApiSetMap = build_api_set_map(emu, allocator).ptr(); - - peb.ProcessHeap = nullptr; - peb.ProcessHeaps = nullptr; - peb.HeapSegmentReserve = 0x0000000000100000; // TODO: Read from executable - peb.HeapSegmentCommit = 0x0000000000002000; - peb.HeapDeCommitTotalFreeThreshold = 0x0000000000010000; - peb.HeapDeCommitFreeBlockThreshold = 0x0000000000001000; - peb.NumberOfHeaps = 0x00000000; - peb.MaximumNumberOfHeaps = 0x00000010; - - peb.OSPlatformId = 2; - peb.OSMajorVersion = 0x0000000a; - peb.OSBuildNumber = 0x00006c51; - }); - } - - using exception_record_map = std::unordered_map< - const EMU_EXCEPTION_RECORD>*, emulator_object>>>; - - emulator_object>> save_exception_record(emulator_allocator& allocator, - const EMU_EXCEPTION_RECORD>& record, - exception_record_map& record_mapping) - { - const auto record_obj = allocator.reserve>>(); - record_obj.write(record); - - if (record.ExceptionRecord) - { - record_mapping.emplace(&record, record_obj); - - emulator_object>> nested_record_obj{allocator.get_emulator()}; - const auto nested_record = record_mapping.find( - reinterpret_cast>*>(record.ExceptionRecord)); - - if (nested_record != record_mapping.end()) - { - nested_record_obj = nested_record->second; - } - else - { - nested_record_obj = save_exception_record( - allocator, *reinterpret_cast>*>(record.ExceptionRecord), - record_mapping); - } - - record_obj.access([&](EMU_EXCEPTION_RECORD>& r) - { - r.ExceptionRecord = reinterpret_cast::PVOID>(nested_record_obj.ptr()); - }); - } - - return record_obj; - } - - emulator_object>> save_exception_record(emulator_allocator& allocator, - const EMU_EXCEPTION_RECORD>& record) - { - exception_record_map record_mapping{}; - return save_exception_record(allocator, record, record_mapping); - } - - uint32_t map_violation_operation_to_parameter(const memory_operation operation) - { - switch (operation) - { - default: - case memory_operation::read: - return 0; - case memory_operation::write: - case memory_operation::exec: - return 1; - } - } - - size_t calculate_exception_record_size(const EMU_EXCEPTION_RECORD>& record) - { - std::unordered_set>*> records{}; - size_t total_size = 0; - - const EMU_EXCEPTION_RECORD>* current_record = &record; - while (current_record) - { - if (!records.insert(current_record).second) - { - break; - } - - total_size += sizeof(*current_record); - current_record = reinterpret_cast>*>(record.ExceptionRecord); - } - - return total_size; - } - - struct machine_frame - { - uint64_t rip; - uint64_t cs; - uint64_t eflags; - uint64_t rsp; - uint64_t ss; - }; - - void dispatch_exception_pointers(x64_emulator& emu, const uint64_t dispatcher, - const EMU_EXCEPTION_POINTERS> pointers) - { - constexpr auto mach_frame_size = 0x40; - constexpr auto context_record_size = 0x4F0; - const auto exception_record_size = calculate_exception_record_size( - *reinterpret_cast>*>(pointers.ExceptionRecord)); - const auto combined_size = align_up(exception_record_size + context_record_size, 0x10); - - assert(combined_size == 0x590); - - const auto allocation_size = combined_size + mach_frame_size; - - const auto initial_sp = emu.reg(x64_register::rsp); - const auto new_sp = align_down(initial_sp - allocation_size, 0x100); - - const auto total_size = initial_sp - new_sp; - assert(total_size >= allocation_size); - - std::vector zero_memory{}; - zero_memory.resize(total_size, 0); - - emu.write_memory(new_sp, zero_memory.data(), zero_memory.size()); - - emu.reg(x64_register::rsp, new_sp); - emu.reg(x64_register::rip, dispatcher); - - const emulator_object context_record_obj{emu, new_sp}; - context_record_obj.write(*reinterpret_cast(pointers.ContextRecord)); - - emulator_allocator allocator{emu, new_sp + context_record_size, exception_record_size}; - const auto exception_record_obj = save_exception_record( - allocator, *reinterpret_cast>*>(pointers.ExceptionRecord)); - - if (exception_record_obj.value() != allocator.get_base()) - { - throw std::runtime_error("Bad exception record position on stack"); - } - - const emulator_object machine_frame_obj{emu, new_sp + combined_size}; - machine_frame_obj.access([&](machine_frame& frame) - { - const auto& record = *reinterpret_cast(pointers.ContextRecord); - frame.rip = record.Rip; - frame.rsp = record.Rsp; - frame.ss = record.SegSs; - frame.cs = record.SegCs; - frame.eflags = record.EFlags; - }); - } - - void dispatch_access_violation(x64_emulator& emu, const uint64_t dispatcher, const uint64_t address, - const memory_operation operation) - { - CONTEXT64 ctx{}; - ctx.ContextFlags = CONTEXT64_ALL; - context_frame::save(emu, ctx); - - EMU_EXCEPTION_RECORD> record{}; - memset(&record, 0, sizeof(record)); - record.ExceptionCode = static_cast(STATUS_ACCESS_VIOLATION); - record.ExceptionFlags = 0; - record.ExceptionRecord = 0; - record.ExceptionAddress = static_cast::PVOID>(emu.read_instruction_pointer()); - record.NumberParameters = 2; - record.ExceptionInformation[0] = map_violation_operation_to_parameter(operation); - record.ExceptionInformation[1] = address; - - EMU_EXCEPTION_POINTERS> pointers{}; - pointers.ContextRecord = reinterpret_cast::PVOID>(&ctx); - pointers.ExceptionRecord = reinterpret_cast::PVOID>(&record); - - dispatch_exception_pointers(emu, dispatcher, pointers); - } - - void dispatch_illegal_instruction_violation(x64_emulator& emu, const uint64_t dispatcher) - { - CONTEXT64 ctx{}; - ctx.ContextFlags = CONTEXT64_ALL; - context_frame::save(emu, ctx); - - EMU_EXCEPTION_RECORD> record{}; - memset(&record, 0, sizeof(record)); - record.ExceptionCode = static_cast(STATUS_ILLEGAL_INSTRUCTION); - record.ExceptionFlags = 0; - record.ExceptionRecord = 0; - record.ExceptionAddress = static_cast::PVOID>(emu.read_instruction_pointer()); - record.NumberParameters = 0; - - EMU_EXCEPTION_POINTERS> pointers{}; - pointers.ContextRecord = reinterpret_cast::PVOID>(&ctx); - pointers.ExceptionRecord = reinterpret_cast::PVOID>(&record); - - dispatch_exception_pointers(emu, dispatcher, pointers); - } - - void perform_context_switch_work(windows_emulator& win_emu) - { - auto& devices = win_emu.process().devices; - - // Crappy mechanism to prevent mutation while iterating. - const auto was_blocked = devices.block_mutation(true); - const auto _ = utils::finally([&] - { - devices.block_mutation(was_blocked); - }); - - for (auto& device : devices) - { - device.second.work(win_emu); - } - } - - bool switch_to_thread(windows_emulator& win_emu, emulator_thread& thread) - { - auto& emu = win_emu.emu(); - auto& context = win_emu.process(); - - if (!thread.is_thread_ready(win_emu)) - { - return false; - } - - auto* active_thread = context.active_thread; - - if (active_thread == &thread) - { - thread.setup_if_necessary(emu, context); - return true; - } - - if (active_thread) - { - win_emu.log.print(color::dark_gray, "Performing thread switch...\n"); - active_thread->save(emu); - } - - context.active_thread = &thread; - - - thread.restore(emu); - thread.setup_if_necessary(emu, context); - - return true; - } - - bool switch_to_thread(windows_emulator& win_emu, const handle thread_handle) - { - auto* thread = win_emu.process().threads.get(thread_handle); - if (!thread) - { - throw std::runtime_error("Bad thread handle"); - } - - return switch_to_thread(win_emu, *thread); - } - - bool switch_to_next_thread(windows_emulator& win_emu) - { - perform_context_switch_work(win_emu); - - auto& context = win_emu.process(); - - bool next_thread = false; - - for (auto& thread : context.threads) - { - if (next_thread) - { - if (switch_to_thread(win_emu, thread.second)) - { - return true; - } - - continue; - } - - if (&thread.second == context.active_thread) - { - next_thread = true; - } - } - - for (auto& thread : context.threads) - { - if (switch_to_thread(win_emu, thread.second)) - { - return true; - } - } - - return false; - } - - bool is_object_signaled(process_context& c, const handle h, uint32_t current_thread_id) - { - const auto type = h.value.type; - - switch (type) - { - default: - break; - - case handle_types::event: - { - auto* e = c.events.get(h); - if (e) - { - return e->is_signaled(); - } - - break; - } - - case handle_types::mutant: - { - auto* e = c.mutants.get(h); - if (e) - { - return e->try_lock(current_thread_id); - } - - break; - } - - case handle_types::thread: - { - const auto* t = c.threads.get(h); - if (t) - { - return t->exit_status.has_value(); - } - - break; - } - } - - throw std::runtime_error("Bad object"); - } + } + + emulator_allocator create_allocator(emulator& emu, const size_t size) + { + const auto base = emu.find_free_allocation_base(size); + emu.allocate_memory(base, size, memory_permission::read_write); + + return emulator_allocator{emu, base, size}; + } + + void setup_gdt(x64_emulator& emu) + { + constexpr uint64_t gdtr[4] = {0, GDT_ADDR, GDT_LIMIT, 0}; + emu.write_register(x64_register::gdtr, &gdtr, sizeof(gdtr)); + emu.allocate_memory(GDT_ADDR, GDT_LIMIT, memory_permission::read); + + emu.write_memory(GDT_ADDR + 6 * (sizeof(uint64_t)), 0xEFFE000000FFFF); + emu.reg(x64_register::cs, 0x33); + + emu.write_memory(GDT_ADDR + 5 * (sizeof(uint64_t)), 0xEFF6000000FFFF); + emu.reg(x64_register::ss, 0x2B); + } + + std::filesystem::path canonicalize_path(const std::filesystem::path& path) + { + return canonical(absolute(path)).make_preferred(); + } + + void setup_context(windows_emulator& win_emu, const emulator_settings& settings) + { + auto& emu = win_emu.emu(); + auto& context = win_emu.process(); + + setup_gdt(emu); + + context.registry = registry_manager(settings.registry_directory); + + context.kusd.setup(settings.use_relative_time); + + context.base_allocator = create_allocator(emu, PEB_SEGMENT_SIZE); + auto& allocator = context.base_allocator; + + context.peb = allocator.reserve(); + + /* Values of the following fields must be + * allocated relative to the process_params themselves + * and included in the length: + * + * CurrentDirectory + * DllPath + * ImagePathName + * CommandLine + * WindowTitle + * DesktopInfo + * ShellInfo + * RuntimeData + * RedirectionDllName + */ + + context.process_params = allocator.reserve(); + + context.process_params.access([&](RTL_USER_PROCESS_PARAMETERS64& proc_params) { + proc_params.Flags = 0x6001; //| 0x80000000; // Prevent CsrClientConnectToServer + + proc_params.ConsoleHandle = CONSOLE_HANDLE.h; + proc_params.StandardOutput = STDOUT_HANDLE.h; + proc_params.StandardInput = STDIN_HANDLE.h; + proc_params.StandardError = proc_params.StandardOutput; + + proc_params.Environment = reinterpret_cast(allocator.copy_string(u"=::=::\\")); + allocator.copy_string(u"EMULATOR=1"); + allocator.copy_string(u"COMPUTERNAME=momo"); + allocator.copy_string(u"SystemRoot=C:\\WINDOWS"); + allocator.copy_string(u""); + + std::u16string command_line = u"\"" + settings.application.u16string() + u"\""; + + for (const auto& arg : settings.arguments) + { + command_line.push_back(u' '); + command_line.append(arg); + } + + std::u16string current_folder{}; + if (!settings.working_directory.empty()) + { + current_folder = canonicalize_path(settings.working_directory).u16string() + u"\\"; + } + else + { + current_folder = canonicalize_path(settings.application).parent_path().u16string() + u"\\"; + } + + allocator.make_unicode_string(proc_params.CommandLine, command_line); + allocator.make_unicode_string(proc_params.CurrentDirectory.DosPath, current_folder); + allocator.make_unicode_string(proc_params.ImagePathName, + canonicalize_path(settings.application).u16string()); + + const auto total_length = allocator.get_next_address() - context.process_params.value(); + + proc_params.Length = + static_cast(std::max(static_cast(sizeof(proc_params)), total_length)); + proc_params.MaximumLength = proc_params.Length; + }); + + context.peb.access([&](PEB64& peb) { + peb.ImageBaseAddress = nullptr; + peb.ProcessParameters = context.process_params.ptr(); + peb.ApiSetMap = build_api_set_map(emu, allocator).ptr(); + + peb.ProcessHeap = nullptr; + peb.ProcessHeaps = nullptr; + peb.HeapSegmentReserve = 0x0000000000100000; // TODO: Read from executable + peb.HeapSegmentCommit = 0x0000000000002000; + peb.HeapDeCommitTotalFreeThreshold = 0x0000000000010000; + peb.HeapDeCommitFreeBlockThreshold = 0x0000000000001000; + peb.NumberOfHeaps = 0x00000000; + peb.MaximumNumberOfHeaps = 0x00000010; + + peb.OSPlatformId = 2; + peb.OSMajorVersion = 0x0000000a; + peb.OSBuildNumber = 0x00006c51; + }); + } + + using exception_record_map = std::unordered_map>*, + emulator_object>>>; + + emulator_object>> save_exception_record( + emulator_allocator& allocator, const EMU_EXCEPTION_RECORD>& record, + exception_record_map& record_mapping) + { + const auto record_obj = allocator.reserve>>(); + record_obj.write(record); + + if (record.ExceptionRecord) + { + record_mapping.emplace(&record, record_obj); + + emulator_object>> nested_record_obj{allocator.get_emulator()}; + const auto nested_record = record_mapping.find( + reinterpret_cast>*>(record.ExceptionRecord)); + + if (nested_record != record_mapping.end()) + { + nested_record_obj = nested_record->second; + } + else + { + nested_record_obj = save_exception_record( + allocator, *reinterpret_cast>*>(record.ExceptionRecord), + record_mapping); + } + + record_obj.access([&](EMU_EXCEPTION_RECORD>& r) { + r.ExceptionRecord = reinterpret_cast::PVOID>(nested_record_obj.ptr()); + }); + } + + return record_obj; + } + + emulator_object>> save_exception_record( + emulator_allocator& allocator, const EMU_EXCEPTION_RECORD>& record) + { + exception_record_map record_mapping{}; + return save_exception_record(allocator, record, record_mapping); + } + + uint32_t map_violation_operation_to_parameter(const memory_operation operation) + { + switch (operation) + { + default: + case memory_operation::read: + return 0; + case memory_operation::write: + case memory_operation::exec: + return 1; + } + } + + size_t calculate_exception_record_size(const EMU_EXCEPTION_RECORD>& record) + { + std::unordered_set>*> records{}; + size_t total_size = 0; + + const EMU_EXCEPTION_RECORD>* current_record = &record; + while (current_record) + { + if (!records.insert(current_record).second) + { + break; + } + + total_size += sizeof(*current_record); + current_record = reinterpret_cast>*>(record.ExceptionRecord); + } + + return total_size; + } + + struct machine_frame + { + uint64_t rip; + uint64_t cs; + uint64_t eflags; + uint64_t rsp; + uint64_t ss; + }; + + void dispatch_exception_pointers(x64_emulator& emu, const uint64_t dispatcher, + const EMU_EXCEPTION_POINTERS> pointers) + { + constexpr auto mach_frame_size = 0x40; + constexpr auto context_record_size = 0x4F0; + const auto exception_record_size = calculate_exception_record_size( + *reinterpret_cast>*>(pointers.ExceptionRecord)); + const auto combined_size = align_up(exception_record_size + context_record_size, 0x10); + + assert(combined_size == 0x590); + + const auto allocation_size = combined_size + mach_frame_size; + + const auto initial_sp = emu.reg(x64_register::rsp); + const auto new_sp = align_down(initial_sp - allocation_size, 0x100); + + const auto total_size = initial_sp - new_sp; + assert(total_size >= allocation_size); + + std::vector zero_memory{}; + zero_memory.resize(total_size, 0); + + emu.write_memory(new_sp, zero_memory.data(), zero_memory.size()); + + emu.reg(x64_register::rsp, new_sp); + emu.reg(x64_register::rip, dispatcher); + + const emulator_object context_record_obj{emu, new_sp}; + context_record_obj.write(*reinterpret_cast(pointers.ContextRecord)); + + emulator_allocator allocator{emu, new_sp + context_record_size, exception_record_size}; + const auto exception_record_obj = save_exception_record( + allocator, *reinterpret_cast>*>(pointers.ExceptionRecord)); + + if (exception_record_obj.value() != allocator.get_base()) + { + throw std::runtime_error("Bad exception record position on stack"); + } + + const emulator_object machine_frame_obj{emu, new_sp + combined_size}; + machine_frame_obj.access([&](machine_frame& frame) { + const auto& record = *reinterpret_cast(pointers.ContextRecord); + frame.rip = record.Rip; + frame.rsp = record.Rsp; + frame.ss = record.SegSs; + frame.cs = record.SegCs; + frame.eflags = record.EFlags; + }); + } + + void dispatch_access_violation(x64_emulator& emu, const uint64_t dispatcher, const uint64_t address, + const memory_operation operation) + { + CONTEXT64 ctx{}; + ctx.ContextFlags = CONTEXT64_ALL; + context_frame::save(emu, ctx); + + EMU_EXCEPTION_RECORD> record{}; + memset(&record, 0, sizeof(record)); + record.ExceptionCode = static_cast(STATUS_ACCESS_VIOLATION); + record.ExceptionFlags = 0; + record.ExceptionRecord = 0; + record.ExceptionAddress = static_cast::PVOID>(emu.read_instruction_pointer()); + record.NumberParameters = 2; + record.ExceptionInformation[0] = map_violation_operation_to_parameter(operation); + record.ExceptionInformation[1] = address; + + EMU_EXCEPTION_POINTERS> pointers{}; + pointers.ContextRecord = reinterpret_cast::PVOID>(&ctx); + pointers.ExceptionRecord = reinterpret_cast::PVOID>(&record); + + dispatch_exception_pointers(emu, dispatcher, pointers); + } + + void dispatch_illegal_instruction_violation(x64_emulator& emu, const uint64_t dispatcher) + { + CONTEXT64 ctx{}; + ctx.ContextFlags = CONTEXT64_ALL; + context_frame::save(emu, ctx); + + EMU_EXCEPTION_RECORD> record{}; + memset(&record, 0, sizeof(record)); + record.ExceptionCode = static_cast(STATUS_ILLEGAL_INSTRUCTION); + record.ExceptionFlags = 0; + record.ExceptionRecord = 0; + record.ExceptionAddress = static_cast::PVOID>(emu.read_instruction_pointer()); + record.NumberParameters = 0; + + EMU_EXCEPTION_POINTERS> pointers{}; + pointers.ContextRecord = reinterpret_cast::PVOID>(&ctx); + pointers.ExceptionRecord = reinterpret_cast::PVOID>(&record); + + dispatch_exception_pointers(emu, dispatcher, pointers); + } + + void perform_context_switch_work(windows_emulator& win_emu) + { + auto& devices = win_emu.process().devices; + + // Crappy mechanism to prevent mutation while iterating. + const auto was_blocked = devices.block_mutation(true); + const auto _ = utils::finally([&] { devices.block_mutation(was_blocked); }); + + for (auto& device : devices) + { + device.second.work(win_emu); + } + } + + bool switch_to_thread(windows_emulator& win_emu, emulator_thread& thread) + { + auto& emu = win_emu.emu(); + auto& context = win_emu.process(); + + if (!thread.is_thread_ready(win_emu)) + { + return false; + } + + auto* active_thread = context.active_thread; + + if (active_thread == &thread) + { + thread.setup_if_necessary(emu, context); + return true; + } + + if (active_thread) + { + win_emu.log.print(color::dark_gray, "Performing thread switch...\n"); + active_thread->save(emu); + } + + context.active_thread = &thread; + + thread.restore(emu); + thread.setup_if_necessary(emu, context); + + return true; + } + + bool switch_to_thread(windows_emulator& win_emu, const handle thread_handle) + { + auto* thread = win_emu.process().threads.get(thread_handle); + if (!thread) + { + throw std::runtime_error("Bad thread handle"); + } + + return switch_to_thread(win_emu, *thread); + } + + bool switch_to_next_thread(windows_emulator& win_emu) + { + perform_context_switch_work(win_emu); + + auto& context = win_emu.process(); + + bool next_thread = false; + + for (auto& thread : context.threads) + { + if (next_thread) + { + if (switch_to_thread(win_emu, thread.second)) + { + return true; + } + + continue; + } + + if (&thread.second == context.active_thread) + { + next_thread = true; + } + } + + for (auto& thread : context.threads) + { + if (switch_to_thread(win_emu, thread.second)) + { + return true; + } + } + + return false; + } + + bool is_object_signaled(process_context& c, const handle h, uint32_t current_thread_id) + { + const auto type = h.value.type; + + switch (type) + { + default: + break; + + case handle_types::event: { + auto* e = c.events.get(h); + if (e) + { + return e->is_signaled(); + } + + break; + } + + case handle_types::mutant: { + auto* e = c.mutants.get(h); + if (e) + { + return e->try_lock(current_thread_id); + } + + break; + } + + case handle_types::thread: { + const auto* t = c.threads.get(h); + if (t) + { + return t->exit_status.has_value(); + } + + break; + } + } + + throw std::runtime_error("Bad object"); + } } -emulator_thread::emulator_thread(x64_emulator& emu, const process_context& context, - const uint64_t start_address, - const uint64_t argument, - const uint64_t stack_size, const uint32_t id) - : emu_ptr(&emu) - , stack_size(page_align_up(std::max(stack_size, static_cast(STACK_SIZE)))) - , start_address(start_address) - , argument(argument) - , id(id) - , last_registers(context.default_register_set) +emulator_thread::emulator_thread(x64_emulator& emu, const process_context& context, const uint64_t start_address, + const uint64_t argument, const uint64_t stack_size, const uint32_t id) + : emu_ptr(&emu), + stack_size(page_align_up(std::max(stack_size, static_cast(STACK_SIZE)))), + start_address(start_address), + argument(argument), + id(id), + last_registers(context.default_register_set) { - this->stack_base = emu.allocate_memory(this->stack_size, memory_permission::read_write); + this->stack_base = emu.allocate_memory(this->stack_size, memory_permission::read_write); - this->gs_segment = emulator_allocator{ - emu, - emu.allocate_memory(GS_SEGMENT_SIZE, memory_permission::read_write), - GS_SEGMENT_SIZE, - }; + this->gs_segment = emulator_allocator{ + emu, + emu.allocate_memory(GS_SEGMENT_SIZE, memory_permission::read_write), + GS_SEGMENT_SIZE, + }; - this->teb = this->gs_segment->reserve(); + this->teb = this->gs_segment->reserve(); - this->teb->access([&](TEB64& teb_obj) - { - teb_obj.ClientId.UniqueProcess = 1ul; - teb_obj.ClientId.UniqueThread = static_cast(this->id); - teb_obj.NtTib.StackLimit = reinterpret_cast(this->stack_base); - teb_obj.NtTib.StackBase = reinterpret_cast(this->stack_base + this->stack_size); - teb_obj.NtTib.Self = &this->teb->ptr()->NtTib; - teb_obj.ProcessEnvironmentBlock = context.peb.ptr(); - }); + this->teb->access([&](TEB64& teb_obj) { + teb_obj.ClientId.UniqueProcess = 1ul; + teb_obj.ClientId.UniqueThread = static_cast(this->id); + teb_obj.NtTib.StackLimit = reinterpret_cast(this->stack_base); + teb_obj.NtTib.StackBase = reinterpret_cast(this->stack_base + this->stack_size); + teb_obj.NtTib.Self = &this->teb->ptr()->NtTib; + teb_obj.ProcessEnvironmentBlock = context.peb.ptr(); + }); } void emulator_thread::mark_as_ready(const NTSTATUS status) { - this->pending_status = status; - this->await_time = {}; - this->await_objects = {}; + this->pending_status = status; + this->await_time = {}; + this->await_objects = {}; - // TODO: Find out if this is correct - if (this->waiting_for_alert) - { - this->alerted = false; - } + // TODO: Find out if this is correct + if (this->waiting_for_alert) + { + this->alerted = false; + } - this->waiting_for_alert = false; + this->waiting_for_alert = false; } bool emulator_thread::is_thread_ready(windows_emulator& win_emu) { - if (this->exit_status.has_value()) - { - return false; - } + if (this->exit_status.has_value()) + { + return false; + } - if (this->waiting_for_alert) - { - if (this->alerted) - { - this->mark_as_ready(STATUS_ALERTED); - return true; - } - if (this->is_await_time_over()) - { - this->mark_as_ready(STATUS_TIMEOUT); - return true; - } + if (this->waiting_for_alert) + { + if (this->alerted) + { + this->mark_as_ready(STATUS_ALERTED); + return true; + } + if (this->is_await_time_over()) + { + this->mark_as_ready(STATUS_TIMEOUT); + return true; + } - return false; - } + return false; + } - if (!this->await_objects.empty()) - { - bool all_signaled = true; - for (uint32_t i = 0; i < this->await_objects.size(); ++i) - { - const auto& obj = this->await_objects[i]; + if (!this->await_objects.empty()) + { + bool all_signaled = true; + for (uint32_t i = 0; i < this->await_objects.size(); ++i) + { + const auto& obj = this->await_objects[i]; - const auto signaled = is_object_signaled(win_emu.process(), obj, this->id); - all_signaled &= signaled; + const auto signaled = is_object_signaled(win_emu.process(), obj, this->id); + all_signaled &= signaled; - if (signaled && this->await_any) - { - this->mark_as_ready(STATUS_WAIT_0 + i); - return true; - } - } + if (signaled && this->await_any) + { + this->mark_as_ready(STATUS_WAIT_0 + i); + return true; + } + } - if (!this->await_any && all_signaled) - { - this->mark_as_ready(STATUS_SUCCESS); - return true; - } + if (!this->await_any && all_signaled) + { + this->mark_as_ready(STATUS_SUCCESS); + return true; + } - if (this->is_await_time_over()) - { - this->mark_as_ready(STATUS_TIMEOUT); - return true; - } + if (this->is_await_time_over()) + { + this->mark_as_ready(STATUS_TIMEOUT); + return true; + } - return false; - } + return false; + } - if (this->await_time.has_value()) - { - if (this->is_await_time_over()) - { - this->mark_as_ready(STATUS_SUCCESS); - return true; - } + if (this->await_time.has_value()) + { + if (this->is_await_time_over()) + { + this->mark_as_ready(STATUS_SUCCESS); + return true; + } - return false; - } + return false; + } - return true; + return true; } void emulator_thread::setup_registers(x64_emulator& emu, const process_context& context) const { - setup_stack(emu, this->stack_base, this->stack_size); - setup_gs_segment(emu, *this->gs_segment); + setup_stack(emu, this->stack_base, this->stack_size); + setup_gs_segment(emu, *this->gs_segment); - CONTEXT64 ctx{}; - ctx.ContextFlags = CONTEXT64_ALL; + CONTEXT64 ctx{}; + ctx.ContextFlags = CONTEXT64_ALL; - unalign_stack(emu); - context_frame::save(emu, ctx); + unalign_stack(emu); + context_frame::save(emu, ctx); - ctx.Rip = context.rtl_user_thread_start; - ctx.Rcx = this->start_address; - ctx.Rdx = this->argument; + ctx.Rip = context.rtl_user_thread_start; + ctx.Rcx = this->start_address; + ctx.Rdx = this->argument; - const auto ctx_obj = allocate_object_on_stack(emu); - ctx_obj.write(ctx); + const auto ctx_obj = allocate_object_on_stack(emu); + ctx_obj.write(ctx); - unalign_stack(emu); + unalign_stack(emu); - emu.reg(x64_register::rcx, ctx_obj.value()); - emu.reg(x64_register::rdx, context.ntdll->image_base); - emu.reg(x64_register::rip, context.ldr_initialize_thunk); + emu.reg(x64_register::rcx, ctx_obj.value()); + emu.reg(x64_register::rdx, context.ntdll->image_base); + emu.reg(x64_register::rip, context.ldr_initialize_thunk); } std::unique_ptr create_default_x64_emulator() { - return unicorn::create_x64_emulator(); + return unicorn::create_x64_emulator(); } -windows_emulator::windows_emulator(emulator_settings settings, - std::unique_ptr emu) - : windows_emulator(std::move(emu)) +windows_emulator::windows_emulator(emulator_settings settings, std::unique_ptr emu) + : windows_emulator(std::move(emu)) { - this->silent_until_main_ = settings.silent_until_main && !settings.disable_logging; - this->stdout_callback_ = std::move(settings.stdout_callback); - this->use_relative_time_ = settings.use_relative_time; - this->log.disable_output(settings.disable_logging || this->silent_until_main_); - this->setup_process(settings); + this->silent_until_main_ = settings.silent_until_main && !settings.disable_logging; + this->stdout_callback_ = std::move(settings.stdout_callback); + this->use_relative_time_ = settings.use_relative_time; + this->log.disable_output(settings.disable_logging || this->silent_until_main_); + this->setup_process(settings); } windows_emulator::windows_emulator(std::unique_ptr emu) - : emu_(std::move(emu)) - , process_(*emu_) + : emu_(std::move(emu)), + process_(*emu_) { - this->setup_hooks(); + this->setup_hooks(); } void windows_emulator::setup_process(const emulator_settings& settings) { - auto& emu = this->emu(); + auto& emu = this->emu(); - auto& context = this->process(); - context.mod_manager = module_manager(emu); // TODO: Cleanup module manager + auto& context = this->process(); + context.mod_manager = module_manager(emu); // TODO: Cleanup module manager - setup_context(*this, settings); + setup_context(*this, settings); - context.executable = context.mod_manager.map_module(settings.application, this->log); + context.executable = context.mod_manager.map_module(settings.application, this->log); - context.peb.access([&](PEB64& peb) - { - peb.ImageBaseAddress = reinterpret_cast(context.executable->image_base); - }); + context.peb.access( + [&](PEB64& peb) { peb.ImageBaseAddress = reinterpret_cast(context.executable->image_base); }); - context.ntdll = context.mod_manager.map_module(R"(C:\Windows\System32\ntdll.dll)", this->log); - context.win32u = context.mod_manager.map_module(R"(C:\Windows\System32\win32u.dll)", this->log); + context.ntdll = context.mod_manager.map_module(R"(C:\Windows\System32\ntdll.dll)", this->log); + context.win32u = context.mod_manager.map_module(R"(C:\Windows\System32\win32u.dll)", this->log); - const auto ntdll_data = emu.read_memory(context.ntdll->image_base, context.ntdll->size_of_image); - const auto win32u_data = emu.read_memory(context.win32u->image_base, context.win32u->size_of_image); + const auto ntdll_data = emu.read_memory(context.ntdll->image_base, context.ntdll->size_of_image); + const auto win32u_data = emu.read_memory(context.win32u->image_base, context.win32u->size_of_image); - this->dispatcher_.setup(context.ntdll->exports, ntdll_data, context.win32u->exports, win32u_data); + this->dispatcher_.setup(context.ntdll->exports, ntdll_data, context.win32u->exports, win32u_data); - context.ldr_initialize_thunk = context.ntdll->find_export("LdrInitializeThunk"); - context.rtl_user_thread_start = context.ntdll->find_export("RtlUserThreadStart"); - context.ki_user_exception_dispatcher = context.ntdll->find_export("KiUserExceptionDispatcher"); + context.ldr_initialize_thunk = context.ntdll->find_export("LdrInitializeThunk"); + context.rtl_user_thread_start = context.ntdll->find_export("RtlUserThreadStart"); + context.ki_user_exception_dispatcher = context.ntdll->find_export("KiUserExceptionDispatcher"); - context.default_register_set = emu.save_registers(); + context.default_register_set = emu.save_registers(); - const auto main_thread_id = context.create_thread(emu, context.executable->entry_point, 0, 0); - switch_to_thread(*this, main_thread_id); + const auto main_thread_id = context.create_thread(emu, context.executable->entry_point, 0, 0); + switch_to_thread(*this, main_thread_id); } void windows_emulator::yield_thread() { - this->switch_thread = true; - this->emu().stop(); + this->switch_thread = true; + this->emu().stop(); } void windows_emulator::perform_thread_switch() { - this->switch_thread = false; - while (!switch_to_next_thread(*this)) - { - // TODO: Optimize that - std::this_thread::sleep_for(1ms); - } + this->switch_thread = false; + while (!switch_to_next_thread(*this)) + { + // TODO: Optimize that + std::this_thread::sleep_for(1ms); + } } void windows_emulator::on_instruction_execution(uint64_t address) { - auto& process = this->process(); - auto& thread = this->current_thread(); + auto& process = this->process(); + auto& thread = this->current_thread(); - ++process.executed_instructions; - const auto thread_insts = ++thread.executed_instructions; - if (thread_insts % MAX_INSTRUCTIONS_PER_TIME_SLICE == 0) - { - this->switch_thread = true; - this->emu().stop(); - } + ++process.executed_instructions; + const auto thread_insts = ++thread.executed_instructions; + if (thread_insts % MAX_INSTRUCTIONS_PER_TIME_SLICE == 0) + { + this->switch_thread = true; + this->emu().stop(); + } - process.previous_ip = process.current_ip; - process.current_ip = this->emu().read_instruction_pointer(); + process.previous_ip = process.current_ip; + process.current_ip = this->emu().read_instruction_pointer(); - const auto is_main_exe = process.executable->is_within(address); - const auto is_interesting_call = process.executable->is_within(process.previous_ip) || is_main_exe; + const auto is_main_exe = process.executable->is_within(address); + const auto is_interesting_call = process.executable->is_within(process.previous_ip) || is_main_exe; - if (this->silent_until_main_ && is_main_exe) - { - this->silent_until_main_ = false; - this->log.disable_output(false); - } + if (this->silent_until_main_ && is_main_exe) + { + this->silent_until_main_ = false; + this->log.disable_output(false); + } - if (!this->verbose && !this->verbose_calls && !is_interesting_call) - { - return; - } + if (!this->verbose && !this->verbose_calls && !is_interesting_call) + { + return; + } - const auto* binary = this->process().mod_manager.find_by_address(address); + const auto* binary = this->process().mod_manager.find_by_address(address); - if (binary) - { - const auto export_entry = binary->address_names.find(address); - if (export_entry != binary->address_names.end()) - { - log.print(is_interesting_call ? color::yellow : color::dark_gray, - "Executing function: %s - %s (0x%" PRIx64 ")\n", - binary->name.c_str(), - export_entry->second.c_str(), address); - } - else if (address == binary->entry_point) - { - log.print(is_interesting_call ? color::yellow : color::gray, - "Executing entry point: %s (0x%" PRIx64 ")\n", - binary->name.c_str(), - address); - } - } + if (binary) + { + const auto export_entry = binary->address_names.find(address); + if (export_entry != binary->address_names.end()) + { + log.print(is_interesting_call ? color::yellow : color::dark_gray, + "Executing function: %s - %s (0x%" PRIx64 ")\n", binary->name.c_str(), + export_entry->second.c_str(), address); + } + else if (address == binary->entry_point) + { + log.print(is_interesting_call ? color::yellow : color::gray, "Executing entry point: %s (0x%" PRIx64 ")\n", + binary->name.c_str(), address); + } + } - if (!this->verbose) - { - return; - } + if (!this->verbose) + { + return; + } - auto& emu = this->emu(); + auto& emu = this->emu(); - printf( - "Inst: %16" PRIx64 " - RAX: %16" PRIx64 " - RBX: %16" PRIx64 " - RCX: %16" PRIx64 " - RDX: %16" PRIx64 - " - R8: %16" PRIx64 " - R9: %16" PRIx64 " - RDI: %16" PRIx64 " - RSI: %16" PRIx64 " - %s\n", - address, - emu.reg(x64_register::rax), emu.reg(x64_register::rbx), - emu.reg(x64_register::rcx), - emu.reg(x64_register::rdx), emu.reg(x64_register::r8), - emu.reg(x64_register::r9), - emu.reg(x64_register::rdi), emu.reg(x64_register::rsi), - binary ? binary->name.c_str() : ""); + printf("Inst: %16" PRIx64 " - RAX: %16" PRIx64 " - RBX: %16" PRIx64 " - RCX: %16" PRIx64 " - RDX: %16" PRIx64 + " - R8: %16" PRIx64 " - R9: %16" PRIx64 " - RDI: %16" PRIx64 " - RSI: %16" PRIx64 " - %s\n", + address, emu.reg(x64_register::rax), emu.reg(x64_register::rbx), emu.reg(x64_register::rcx), + emu.reg(x64_register::rdx), emu.reg(x64_register::r8), emu.reg(x64_register::r9), emu.reg(x64_register::rdi), + emu.reg(x64_register::rsi), binary ? binary->name.c_str() : ""); } void windows_emulator::setup_hooks() { - this->emu().hook_instruction(x64_hookable_instructions::syscall, [&] - { - for (const auto& hook : this->syscall_hooks_) - { - if (hook() == instruction_hook_continuation::skip_instruction) - { - return instruction_hook_continuation::skip_instruction; - } - } + this->emu().hook_instruction(x64_hookable_instructions::syscall, [&] { + for (const auto& hook : this->syscall_hooks_) + { + if (hook() == instruction_hook_continuation::skip_instruction) + { + return instruction_hook_continuation::skip_instruction; + } + } - this->dispatcher_.dispatch(*this); - return instruction_hook_continuation::skip_instruction; - }); + this->dispatcher_.dispatch(*this); + return instruction_hook_continuation::skip_instruction; + }); - this->emu().hook_instruction(x64_hookable_instructions::rdtsc, [&] - { - const auto instructions = this->process().executed_instructions; - this->emu().reg(x64_register::rax, instructions & 0xFFFFFFFF); - this->emu().reg(x64_register::rdx, (instructions >> 32) & 0xFFFFFFFF); - return instruction_hook_continuation::skip_instruction; - }); + this->emu().hook_instruction(x64_hookable_instructions::rdtsc, [&] { + const auto instructions = this->process().executed_instructions; + this->emu().reg(x64_register::rax, instructions & 0xFFFFFFFF); + this->emu().reg(x64_register::rdx, (instructions >> 32) & 0xFFFFFFFF); + return instruction_hook_continuation::skip_instruction; + }); - this->emu().hook_instruction(x64_hookable_instructions::invalid, [&] - { - const auto ip = this->emu().read_instruction_pointer(); + this->emu().hook_instruction(x64_hookable_instructions::invalid, [&] { + const auto ip = this->emu().read_instruction_pointer(); - this->log.print(color::gray, "Invalid instruction at: 0x%" PRIx64 "\n", ip); + this->log.print(color::gray, "Invalid instruction at: 0x%" PRIx64 "\n", ip); - return instruction_hook_continuation::skip_instruction; - }); + return instruction_hook_continuation::skip_instruction; + }); - this->emu().hook_interrupt([&](const int interrupt) - { - if (interrupt == 6) - { - dispatch_illegal_instruction_violation(this->emu(), this->process().ki_user_exception_dispatcher); - return; - } + this->emu().hook_interrupt([&](const int interrupt) { + if (interrupt == 6) + { + dispatch_illegal_instruction_violation(this->emu(), this->process().ki_user_exception_dispatcher); + return; + } - const auto rip = this->emu().read_instruction_pointer(); - this->log.print(color::gray, "Interrupt: %i 0x%" PRIx64 "\n", interrupt, rip); + const auto rip = this->emu().read_instruction_pointer(); + this->log.print(color::gray, "Interrupt: %i 0x%" PRIx64 "\n", interrupt, rip); - if (this->fuzzing || true) // TODO: Fix - { - this->process().exception_rip = rip; - this->emu().stop(); - } - }); + if (this->fuzzing || true) // TODO: Fix + { + this->process().exception_rip = rip; + this->emu().stop(); + } + }); - this->emu().hook_memory_violation([&](const uint64_t address, const size_t size, const memory_operation operation, - const memory_violation_type type) - { - const auto permission = get_permission_string(operation); - const auto ip = this->emu().read_instruction_pointer(); - const char* name = this->process().mod_manager.find_name(ip); + this->emu().hook_memory_violation([&](const uint64_t address, const size_t size, const memory_operation operation, + const memory_violation_type type) { + const auto permission = get_permission_string(operation); + const auto ip = this->emu().read_instruction_pointer(); + const char* name = this->process().mod_manager.find_name(ip); - if (type == memory_violation_type::protection) - { - this->log.print(color::gray, "Protection violation: 0x%" PRIx64 " (%zX) - %s at 0x%" PRIx64 " (%s)\n", - address, size, - permission.c_str(), ip, - name); - } - else if (type == memory_violation_type::unmapped) - { - this->log.print(color::gray, "Mapping violation: 0x%" PRIx64 " (%zX) - %s at 0x%" PRIx64 " (%s)\n", address, - size, - permission.c_str(), ip, - name); - } + if (type == memory_violation_type::protection) + { + this->log.print(color::gray, "Protection violation: 0x%" PRIx64 " (%zX) - %s at 0x%" PRIx64 " (%s)\n", + address, size, permission.c_str(), ip, name); + } + else if (type == memory_violation_type::unmapped) + { + this->log.print(color::gray, "Mapping violation: 0x%" PRIx64 " (%zX) - %s at 0x%" PRIx64 " (%s)\n", address, + size, permission.c_str(), ip, name); + } - if (this->fuzzing) - { - this->process().exception_rip = ip; - this->emu().stop(); - return memory_violation_continuation::stop; - } + if (this->fuzzing) + { + this->process().exception_rip = ip; + this->emu().stop(); + return memory_violation_continuation::stop; + } - dispatch_access_violation(this->emu(), this->process().ki_user_exception_dispatcher, address, operation); - return memory_violation_continuation::resume; - }); + dispatch_access_violation(this->emu(), this->process().ki_user_exception_dispatcher, address, operation); + return memory_violation_continuation::resume; + }); - this->emu().hook_memory_execution( - 0, std::numeric_limits::max(), - [&](const uint64_t address, const size_t, const uint64_t) - { - this->on_instruction_execution(address); - }); + this->emu().hook_memory_execution( + 0, std::numeric_limits::max(), + [&](const uint64_t address, const size_t, const uint64_t) { this->on_instruction_execution(address); }); } void windows_emulator::start(std::chrono::nanoseconds timeout, size_t count) { - const auto use_count = count > 0; - const auto use_timeout = timeout != std::chrono::nanoseconds{}; + const auto use_count = count > 0; + const auto use_timeout = timeout != std::chrono::nanoseconds{}; - const auto start_time = std::chrono::high_resolution_clock::now(); - const auto start_instructions = this->process().executed_instructions; + const auto start_time = std::chrono::high_resolution_clock::now(); + const auto start_instructions = this->process().executed_instructions; - const auto target_time = start_time + timeout; - const auto target_instructions = start_instructions + count; + const auto target_time = start_time + timeout; + const auto target_instructions = start_instructions + count; - while (true) - { - if (this->switch_thread) - { - this->perform_thread_switch(); - } + while (true) + { + if (this->switch_thread) + { + this->perform_thread_switch(); + } - this->emu().start_from_ip(timeout, count); + this->emu().start_from_ip(timeout, count); - if (!this->switch_thread && !this->emu().has_violation()) - { - break; - } + if (!this->switch_thread && !this->emu().has_violation()) + { + break; + } - if (use_timeout) - { - const auto now = std::chrono::high_resolution_clock::now(); + if (use_timeout) + { + const auto now = std::chrono::high_resolution_clock::now(); - if (now >= target_time) - { - break; - } + if (now >= target_time) + { + break; + } - timeout = target_time - now; - } + timeout = target_time - now; + } - if (use_count) - { - const auto current_instructions = this->process().executed_instructions; + if (use_count) + { + const auto current_instructions = this->process().executed_instructions; - if (current_instructions >= target_instructions) - { - break; - } + if (current_instructions >= target_instructions) + { + break; + } - count = target_instructions - current_instructions; - } - } + count = target_instructions - current_instructions; + } + } } void windows_emulator::serialize(utils::buffer_serializer& buffer) const { - buffer.write(this->use_relative_time_); - this->emu().serialize(buffer); - this->process_.serialize(buffer); - this->dispatcher_.serialize(buffer); + buffer.write(this->use_relative_time_); + this->emu().serialize(buffer); + this->process_.serialize(buffer); + this->dispatcher_.serialize(buffer); } void windows_emulator::deserialize(utils::buffer_deserializer& buffer) { - buffer.register_factory([this] - { - return x64_emulator_wrapper{this->emu()}; - }); + buffer.register_factory([this] { return x64_emulator_wrapper{this->emu()}; }); - buffer.register_factory([this] - { - return windows_emulator_wrapper{*this}; - }); + buffer.register_factory([this] { return windows_emulator_wrapper{*this}; }); - buffer.read(this->use_relative_time_); + buffer.read(this->use_relative_time_); - this->emu().deserialize(buffer); - this->process_.deserialize(buffer); - this->dispatcher_.deserialize(buffer); + this->emu().deserialize(buffer); + this->process_.deserialize(buffer); + this->dispatcher_.deserialize(buffer); } void windows_emulator::save_snapshot() { - this->emu().save_snapshot(); + this->emu().save_snapshot(); - utils::buffer_serializer serializer{}; - this->process_.serialize(serializer); + utils::buffer_serializer serializer{}; + this->process_.serialize(serializer); - this->process_snapshot_ = serializer.move_buffer(); + this->process_snapshot_ = serializer.move_buffer(); - // TODO: Make process copyable - //this->process_snapshot_ = this->process(); + // TODO: Make process copyable + // this->process_snapshot_ = this->process(); } void windows_emulator::restore_snapshot() { - if (this->process_snapshot_.empty()) - { - assert(false); - return; - } + if (this->process_snapshot_.empty()) + { + assert(false); + return; + } - this->emu().restore_snapshot(); + this->emu().restore_snapshot(); - utils::buffer_deserializer deserializer{this->process_snapshot_}; - this->process_.deserialize(deserializer); - //this->process_ = *this->process_snapshot_; + utils::buffer_deserializer deserializer{this->process_snapshot_}; + this->process_.deserialize(deserializer); + // this->process_ = *this->process_snapshot_; } diff --git a/src/windows-emulator/windows_emulator.hpp b/src/windows-emulator/windows_emulator.hpp index 6c46f5ec..d4e35f96 100644 --- a/src/windows-emulator/windows_emulator.hpp +++ b/src/windows-emulator/windows_emulator.hpp @@ -12,120 +12,119 @@ std::unique_ptr create_default_x64_emulator(); // TODO: Split up into application and emulator settings struct emulator_settings { - std::filesystem::path application{}; - std::filesystem::path working_directory{}; - std::filesystem::path registry_directory{"./registry"}; - std::vector arguments{}; - std::function stdout_callback{}; - bool disable_logging{false}; - bool silent_until_main{false}; - bool use_relative_time{false}; + std::filesystem::path application{}; + std::filesystem::path working_directory{}; + std::filesystem::path registry_directory{"./registry"}; + std::vector arguments{}; + std::function stdout_callback{}; + bool disable_logging{false}; + bool silent_until_main{false}; + bool use_relative_time{false}; }; class windows_emulator { -public: - windows_emulator(std::unique_ptr emu = create_default_x64_emulator()); - windows_emulator(emulator_settings settings, - std::unique_ptr emu = create_default_x64_emulator()); + public: + windows_emulator(std::unique_ptr emu = create_default_x64_emulator()); + windows_emulator(emulator_settings settings, std::unique_ptr emu = create_default_x64_emulator()); - windows_emulator(windows_emulator&&) = delete; - windows_emulator(const windows_emulator&) = delete; - windows_emulator& operator=(windows_emulator&&) = delete; - windows_emulator& operator=(const windows_emulator&) = delete; + windows_emulator(windows_emulator&&) = delete; + windows_emulator(const windows_emulator&) = delete; + windows_emulator& operator=(windows_emulator&&) = delete; + windows_emulator& operator=(const windows_emulator&) = delete; - ~windows_emulator() = default; + ~windows_emulator() = default; - x64_emulator& emu() - { - return *this->emu_; - } + x64_emulator& emu() + { + return *this->emu_; + } - const x64_emulator& emu() const - { - return *this->emu_; - } + const x64_emulator& emu() const + { + return *this->emu_; + } - process_context& process() - { - return this->process_; - } + process_context& process() + { + return this->process_; + } - const process_context& process() const - { - return this->process_; - } + const process_context& process() const + { + return this->process_; + } - syscall_dispatcher& dispatcher() - { - return this->dispatcher_; - } + syscall_dispatcher& dispatcher() + { + return this->dispatcher_; + } - const syscall_dispatcher& dispatcher() const - { - return this->dispatcher_; - } + const syscall_dispatcher& dispatcher() const + { + return this->dispatcher_; + } - emulator_thread& current_thread() const - { - if (!this->process_.active_thread) - { - throw std::runtime_error("No active thread!"); - } + emulator_thread& current_thread() const + { + if (!this->process_.active_thread) + { + throw std::runtime_error("No active thread!"); + } - return *this->process_.active_thread; - } + return *this->process_.active_thread; + } - void start(std::chrono::nanoseconds timeout = {}, size_t count = 0); + void start(std::chrono::nanoseconds timeout = {}, size_t count = 0); - void serialize(utils::buffer_serializer& buffer) const; - void deserialize(utils::buffer_deserializer& buffer); + void serialize(utils::buffer_serializer& buffer) const; + void deserialize(utils::buffer_deserializer& buffer); - void save_snapshot(); - void restore_snapshot(); + void save_snapshot(); + void restore_snapshot(); - void add_syscall_hook(instruction_hook_callback callback) - { - this->syscall_hooks_.push_back(std::move(callback)); - } + void add_syscall_hook(instruction_hook_callback callback) + { + this->syscall_hooks_.push_back(std::move(callback)); + } - void on_stdout(const std::string_view data) const - { - if (this->stdout_callback_) - { - this->stdout_callback_(data); - } - } + void on_stdout(const std::string_view data) const + { + if (this->stdout_callback_) + { + this->stdout_callback_(data); + } + } - logger log{}; - bool verbose{false}; - bool verbose_calls{false}; - bool buffer_stdout{false}; - bool fuzzing{false}; - bool switch_thread{false}; + logger log{}; + bool verbose{false}; + bool verbose_calls{false}; + bool buffer_stdout{false}; + bool fuzzing{false}; + bool switch_thread{false}; - void yield_thread(); - void perform_thread_switch(); + void yield_thread(); + void perform_thread_switch(); - bool time_is_relative() const - { - return this->use_relative_time_; - } + bool time_is_relative() const + { + return this->use_relative_time_; + } -private: - bool use_relative_time_{false}; - bool silent_until_main_{false}; - std::unique_ptr emu_{}; - std::vector syscall_hooks_{}; - std::function stdout_callback_{}; + private: + bool use_relative_time_{false}; + bool silent_until_main_{false}; + std::unique_ptr emu_{}; + std::vector syscall_hooks_{}; + std::function stdout_callback_{}; - process_context process_; - syscall_dispatcher dispatcher_; + process_context process_; + syscall_dispatcher dispatcher_; - std::vector process_snapshot_{}; - //std::optional process_snapshot_{}; + std::vector process_snapshot_{}; + // std::optional process_snapshot_{}; - void setup_hooks(); - void setup_process(const emulator_settings& settings); - void on_instruction_execution(uint64_t address); + void setup_hooks(); + void setup_process(const emulator_settings& settings); + void on_instruction_execution(uint64_t address); };