From 37b020e9ba127a9ea193a88bc2c2c05527cb5362 Mon Sep 17 00:00:00 2001 From: InoriRus Date: Mon, 3 Oct 2022 15:33:23 +1000 Subject: [PATCH] add Linux support --- _Build/cmake_LinuxEclipseNinjaClang.sh | 37 + _Build/cmake_LinuxMakeGcc.sh | 37 + appveyor.yml | 2 +- source/3rdparty/cpuinfo/CMakeLists.txt | 112 ++- source/3rdparty/easy_profiler/CMakeLists.txt | 12 +- source/3rdparty/sdl2/CMakeLists.txt | 15 +- source/3rdparty/sqlite/CMakeLists.txt | 2 +- source/3rdparty/vulkan/CMakeLists.txt | 16 +- source/CMakeLists.txt | 64 +- source/emulator/include/Emulator/Common.h | 5 +- .../include/Emulator/Libs/VaContext.h | 4 +- .../include/Emulator/Loader/RuntimeLinker.h | 42 +- source/emulator/src/Graphics/Graphics.cpp | 10 +- source/emulator/src/Graphics/Tile.cpp | 4 +- source/emulator/src/Graphics/Window.cpp | 6 +- source/emulator/src/Kernel/Memory.cpp | 4 +- source/emulator/src/Kernel/Pthread.cpp | 12 + source/emulator/src/Kyty.cpp | 15 +- source/emulator/src/Libs/LibDbgAsan.cpp | 18 +- source/emulator/src/Libs/Printf.cpp | 2 +- source/emulator/src/Loader/RuntimeLinker.cpp | 76 +- source/emulator/src/Loader/VirtualMemory.cpp | 497 ------------- source/include/Kyty/Core/DbgAssert.h | 6 +- source/include/Kyty/Core/Threads.h | 2 +- .../Kyty/Core}/VirtualMemory.h | 33 +- .../Kyty/Sys/{ => Linux}/SysLinuxDbg.h | 1 + .../Kyty/Sys/{ => Linux}/SysLinuxFileIO.h | 26 +- source/include/Kyty/Sys/Linux/SysLinuxHeap.h | 104 +++ .../Kyty/Sys/{ => Linux}/SysLinuxStdio.h | 8 +- .../Kyty/Sys/{ => Linux}/SysLinuxStdlib.h | 6 +- .../Kyty/Sys/{ => Linux}/SysLinuxSync.h | 42 +- .../Kyty/Sys/{ => Linux}/SysLinuxTimer.h | 40 +- .../include/Kyty/Sys/Linux/SysLinuxVirtual.h | 30 + source/include/Kyty/Sys/SysDbg.h | 5 +- source/include/Kyty/Sys/SysFileIO.h | 5 +- source/include/Kyty/Sys/SysHeap.h | 5 +- source/include/Kyty/Sys/SysLinuxHeap.h | 98 --- source/include/Kyty/Sys/SysStdio.h | 5 +- source/include/Kyty/Sys/SysStdlib.h | 5 +- source/include/Kyty/Sys/SysSync.h | 5 +- source/include/Kyty/Sys/SysTimer.h | 5 +- source/include/Kyty/Sys/SysVirtual.h | 8 + .../Kyty/Sys/{ => Windows}/SysWindowsDbg.h | 0 .../Kyty/Sys/{ => Windows}/SysWindowsFileIO.h | 0 .../Kyty/Sys/{ => Windows}/SysWindowsHeap.h | 0 .../Kyty/Sys/{ => Windows}/SysWindowsStdio.h | 0 .../Kyty/Sys/{ => Windows}/SysWindowsStdlib.h | 0 .../Kyty/Sys/{ => Windows}/SysWindowsSync.h | 0 .../Kyty/Sys/{ => Windows}/SysWindowsTimer.h | 0 .../Kyty/Sys/Windows/SysWindowsVirtual.h | 30 + source/launcher/CMakeLists.txt | 35 +- source/launcher/include/MainDialog.h | 2 +- .../launcher/src/ConfigurationListWidget.cpp | 8 + source/launcher/src/MainDialog.cpp | 106 ++- source/launcher/ts/launcher_ru_RU.ts | 42 +- source/lib/Core/src/Core.cpp | 3 +- source/lib/Core/src/DbgAssert.cpp | 32 +- source/lib/Core/src/MemoryAlloc.cpp | 4 + source/lib/Core/src/SDLSubsystem.cpp | 1 + source/lib/Core/src/Threads.cpp | 155 +++- source/lib/Core/src/VirtualMemory.cpp | 324 +++++++++ source/lib/Sys/CMakeLists.txt | 17 +- source/lib/Sys/src/SysLinuxDbg.cpp | 145 ++++ source/lib/Sys/src/SysLinuxFileIO.cpp | 665 ++++++++++++++++++ source/lib/Sys/src/SysLinuxVirtual.cpp | 373 ++++++++++ source/lib/Sys/src/SysWindowsDbg.cpp | 7 +- source/lib/Sys/src/SysWindowsFileIO.cpp | 2 +- source/lib/Sys/src/SysWindowsVirtual.cpp | 259 +++++++ source/utils.cmake | 46 +- 69 files changed, 2716 insertions(+), 971 deletions(-) create mode 100755 _Build/cmake_LinuxEclipseNinjaClang.sh create mode 100755 _Build/cmake_LinuxMakeGcc.sh delete mode 100644 source/emulator/src/Loader/VirtualMemory.cpp rename source/{emulator/include/Emulator/Loader => include/Kyty/Core}/VirtualMemory.h (71%) rename source/include/Kyty/Sys/{ => Linux}/SysLinuxDbg.h (94%) rename source/include/Kyty/Sys/{ => Linux}/SysLinuxFileIO.h (79%) create mode 100644 source/include/Kyty/Sys/Linux/SysLinuxHeap.h rename source/include/Kyty/Sys/{ => Linux}/SysLinuxStdio.h (70%) rename source/include/Kyty/Sys/{ => Linux}/SysLinuxStdlib.h (88%) rename source/include/Kyty/Sys/{ => Linux}/SysLinuxSync.h (50%) rename source/include/Kyty/Sys/{ => Linux}/SysLinuxTimer.h (84%) create mode 100644 source/include/Kyty/Sys/Linux/SysLinuxVirtual.h delete mode 100644 source/include/Kyty/Sys/SysLinuxHeap.h create mode 100644 source/include/Kyty/Sys/SysVirtual.h rename source/include/Kyty/Sys/{ => Windows}/SysWindowsDbg.h (100%) rename source/include/Kyty/Sys/{ => Windows}/SysWindowsFileIO.h (100%) rename source/include/Kyty/Sys/{ => Windows}/SysWindowsHeap.h (100%) rename source/include/Kyty/Sys/{ => Windows}/SysWindowsStdio.h (100%) rename source/include/Kyty/Sys/{ => Windows}/SysWindowsStdlib.h (100%) rename source/include/Kyty/Sys/{ => Windows}/SysWindowsSync.h (100%) rename source/include/Kyty/Sys/{ => Windows}/SysWindowsTimer.h (100%) create mode 100644 source/include/Kyty/Sys/Windows/SysWindowsVirtual.h create mode 100644 source/lib/Core/src/VirtualMemory.cpp create mode 100644 source/lib/Sys/src/SysLinuxVirtual.cpp create mode 100644 source/lib/Sys/src/SysWindowsVirtual.cpp diff --git a/_Build/cmake_LinuxEclipseNinjaClang.sh b/_Build/cmake_LinuxEclipseNinjaClang.sh new file mode 100755 index 0000000..ac6fbcf --- /dev/null +++ b/_Build/cmake_LinuxEclipseNinjaClang.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +PS3='Please enter your choice: ' +options=("Debug" "Debug Final" "Release" "Release Final" "Exit") +select opt in "${options[@]}" +do + case $opt in + "Debug") + DirName=_DebugLinuxEclipseNinjaClang + Options="-DCMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES=FALSE -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -D CMAKE_BUILD_TYPE=Debug -D CMAKE_INSTALL_PREFIX=_bin ../../source" + ;; + "Debug Final") + DirName=_DebugFinalLinuxEclipseNinjaClang + Options="-DCMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES=FALSE -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -D CMAKE_BUILD_TYPE=Debug -D KYTY_FINAL=1 -D CMAKE_INSTALL_PREFIX=_bin ../../source" + ;; + "Release") + DirName=_ReleaseLinuxEclipseNinjaClang + Options="-DCMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES=FALSE -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=_bin ../../source" + ;; + "Release Final") + DirName=_ReleaseFinalLinuxEclipseNinjaClang + Options="-DCMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES=FALSE -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -D CMAKE_BUILD_TYPE=Release -D KYTY_FINAL=1 -D CMAKE_INSTALL_PREFIX=_bin ../../source" + ;; + esac + break +done + +if [ -z "$DirName" ]; then + exit +fi + +mkdir $DirName +cd $DirName +echo ninja >_build +echo ninja install/strip >>_build +chmod +x _build +cmake -G "Eclipse CDT4 - Ninja" $Options diff --git a/_Build/cmake_LinuxMakeGcc.sh b/_Build/cmake_LinuxMakeGcc.sh new file mode 100755 index 0000000..716ca1c --- /dev/null +++ b/_Build/cmake_LinuxMakeGcc.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +PS3='Please enter your choice: ' +options=("Debug" "Debug Final" "Release" "Release Final" "Exit") +select opt in "${options[@]}" +do + case $opt in + "Debug") + DirName=_DebugLinuxMakeGcc + Options="-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -D CMAKE_BUILD_TYPE=Debug -D CMAKE_INSTALL_PREFIX=_bin ../../source" + ;; + "Debug Final") + DirName=_DebugFinalLinuxMakeGcc + Options="-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -D CMAKE_BUILD_TYPE=Debug -D KYTY_FINAL=1 -D CMAKE_INSTALL_PREFIX=_bin ../../source" + ;; + "Release") + DirName=_ReleaseLinuxMakeGcc + Options="-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=_bin ../../source" + ;; + "Release Final") + DirName=_ReleaseFinalLinuxMakeGcc + Options="-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -D CMAKE_BUILD_TYPE=Release -D KYTY_FINAL=1 -D CMAKE_INSTALL_PREFIX=_bin ../../source" + ;; + esac + break +done + +if [ -z "$DirName" ]; then + exit +fi + +mkdir $DirName +cd $DirName +echo make >_build +echo make install/strip >>_build +chmod +x _build +cmake -G "Unix Makefiles" $Options diff --git a/appveyor.yml b/appveyor.yml index 9135f9a..aca8f46 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 0.2.1.build-{build} +version: 0.2.2.build-{build} image: Visual Studio 2019 environment: matrix: diff --git a/source/3rdparty/cpuinfo/CMakeLists.txt b/source/3rdparty/cpuinfo/CMakeLists.txt index d170e84..92d218e 100644 --- a/source/3rdparty/cpuinfo/CMakeLists.txt +++ b/source/3rdparty/cpuinfo/CMakeLists.txt @@ -1,45 +1,97 @@ -file(GLOB cpuinfo_src - src/init.c - src/api.c - src/cache.c - src/x86/init.c - src/x86/info.c - src/x86/vendor.c - src/x86/uarch.c - src/x86/name.c - src/x86/topology.c - src/x86/isa.c - src/x86/cache/init.c - src/x86/cache/descriptor.c - src/x86/cache/deterministic.c - src/x86/windows/init.c - deps/clog/src/clog.c +set(cpuinfo_src + src/init.c + src/api.c + src/cache.c + deps/clog/src/clog.c ) -if (MINGW) - if (CLANG) - set_source_files_properties(${cpuinfo_src} PROPERTIES COMPILE_FLAGS "-Wno-unused-variable -Wno-implicit-function-declaration") +if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(i[3-6]86|AMD64|x86(_64)?)$") + list(APPEND cpuinfo_src + src/x86/init.c + src/x86/info.c + src/x86/vendor.c + src/x86/uarch.c + src/x86/name.c + src/x86/topology.c + src/x86/isa.c + src/x86/cache/init.c + src/x86/cache/descriptor.c + src/x86/cache/deterministic.c) + if(LINUX OR ANDROID) + list(APPEND cpuinfo_src src/x86/linux/init.c src/x86/linux/cpuinfo.c) else() - set_source_files_properties(${cpuinfo_src} PROPERTIES COMPILE_FLAGS "-Wno-maybe-uninitialized -Wno-unused-variable -Wno-implicit-function-declaration -Wno-format -Wno-format-extra-args") + list(APPEND cpuinfo_src src/x86/windows/init.c) endif() + +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(armv[5-8].*|aarch64|arm64)$") + list(APPEND cpuinfo_src src/arm/uarch.c src/arm/cache.c) + + if(LINUX OR ANDROID) + list(APPEND cpuinfo_src + src/arm/linux/init.c + src/arm/linux/cpuinfo.c + src/arm/linux/clusters.c + src/arm/linux/chipset.c + src/arm/linux/midr.c + src/arm/linux/hwcap.c) + + if(CMAKE_SYSTEM_PROCESSOR MATCHES "^armv[5-8]") + list(APPEND cpuinfo_src src/arm/linux/aarch32-isa.c) + + if(ANDROID AND ANDROID_ABI STREQUAL "armeabi") + set_source_files_properties(src/arm/linux/aarch32-isa.c PROPERTIES COMPILE_FLAGS -marm) + endif() + + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64)$") + list(APPEND cpuinfo_src src/arm/linux/aarch64-isa.c) + endif() + + endif() + + if(ANDROID) + list(APPEND cpuinfo_src src/arm/android/properties.c) + endif() + endif() -if (MSVC) - if (CLANG) - set_source_files_properties(${cpuinfo_src} PROPERTIES COMPILE_FLAGS "-Wno-unused-variable -Wno-deprecated-declarations -Wno-implicit-function-declaration") - else() - set_source_files_properties(${cpuinfo_src} PROPERTIES COMPILE_FLAGS "") - endif() +if(LINUX OR ANDROID) + list(APPEND cpuinfo_src + src/linux/smallfile.c + src/linux/multiline.c + src/linux/cpulist.c + src/linux/processors.c) +endif() + +if (LINUX) + set_source_files_properties(${cpuinfo_src} PROPERTIES COMPILE_FLAGS "-D_GNU_SOURCE=1") endif() include_directories(include src deps/clog/include) -#add_library(cpuinfo STATIC ${cpuinfo_src}) -add_library(cpuinfo_obj OBJECT ${cpuinfo_src}) -add_library(cpuinfo STATIC $) +add_library(cpuinfo STATIC ${cpuinfo_src}) + +if (MINGW) + if (CLANG) + target_compile_options(cpuinfo PRIVATE -Wno-unused-variable -Wno-implicit-function-declaration) + else() + target_compile_options(cpuinfo PRIVATE -Wno-maybe-uninitialized -Wno-unused-variable -Wno-implicit-function-declaration -Wno-format -Wno-format-extra-args) + endif() +elseif (LINUX) + if (CLANG) + else() + target_compile_options(cpuinfo PRIVATE -Wno-unused-result) + endif() +elseif (MSVC) + if (CLANG) + target_compile_options(cpuinfo PRIVATE -Wno-unused-variable -Wno-deprecated-declarations -Wno-implicit-function-declaration) + else() + endif() +elseif(ANDROID) + target_compile_options(cpuinfo PRIVATE -Wno-implicit-function-declaration) +endif() target_include_directories(cpuinfo PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") -target_include_directories(cpuinfo_obj PRIVATE $) + diff --git a/source/3rdparty/easy_profiler/CMakeLists.txt b/source/3rdparty/easy_profiler/CMakeLists.txt index 969e6e7..c792fa6 100644 --- a/source/3rdparty/easy_profiler/CMakeLists.txt +++ b/source/3rdparty/easy_profiler/CMakeLists.txt @@ -1,5 +1,5 @@ file(GLOB easy_profiler_src - src/base_block_descriptor.cpp + src/base_block_descriptor.cpp src/block.cpp src/block_descriptor.cpp src/easy_socket.cpp @@ -20,9 +20,13 @@ if (MINGW) else() set_source_files_properties(${easy_profiler_src} PROPERTIES COMPILE_FLAGS "-DWINVER=0x0601 -D_WIN32_WINNT=0x0601 -DBUILD_WITH_EASY_PROFILER -DEASY_PROFILER_STATIC -DEASY_DEFAULT_PORT=28077 -DEASY_PROFILER_VERSION_MAJOR=2 -DEASY_PROFILER_VERSION_MINOR=1 -DEASY_PROFILER_VERSION_PATCH=0 -DSTRSAFE_NO_DEPRECATE -Wno-reorder-ctor -Wno-reorder -Wno-unknown-pragmas -Wno-format -Wno-class-memaccess") endif() -endif() - -if (MSVC) +elseif (LINUX) + if (CLANG) + set_source_files_properties(${easy_profiler_src} PROPERTIES COMPILE_FLAGS "-DBUILD_WITH_EASY_PROFILER -DEASY_PROFILER_STATIC -DEASY_DEFAULT_PORT=28077 -DEASY_PROFILER_VERSION_MAJOR=2 -DEASY_PROFILER_VERSION_MINOR=1 -DEASY_PROFILER_VERSION_PATCH=0 -DSTRSAFE_NO_DEPRECATE -Wno-unused-variable -Wno-writable-strings -Wno-braced-scalar-init -Wno-defaulted-function-deleted -Wno-unknown-pragmas -Wno-reorder-ctor") + else() + set_source_files_properties(${easy_profiler_src} PROPERTIES COMPILE_FLAGS "-DBUILD_WITH_EASY_PROFILER -DEASY_PROFILER_STATIC -DEASY_DEFAULT_PORT=28077 -DEASY_PROFILER_VERSION_MAJOR=2 -DEASY_PROFILER_VERSION_MINOR=1 -DEASY_PROFILER_VERSION_PATCH=0 -DSTRSAFE_NO_DEPRECATE -Wno-reorder-ctor -Wno-reorder -Wno-unknown-pragmas -Wno-format -Wno-class-memaccess") + endif() +elseif (MSVC) if (CLANG) set_source_files_properties(${easy_profiler_src} PROPERTIES COMPILE_FLAGS "-DBUILD_WITH_EASY_PROFILER -DEASY_PROFILER_STATIC -DEASY_DEFAULT_PORT=28077 -DEASY_PROFILER_VERSION_MAJOR=2 -DEASY_PROFILER_VERSION_MINOR=1 -DEASY_PROFILER_VERSION_PATCH=0 -DSTRSAFE_NO_DEPRECATE -Wno-reorder-ctor -Wno-defaulted-function-deleted -Wno-braced-scalar-init -Wno-writable-strings -D_WINSOCK_DEPRECATED_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS -Wno-format") else() diff --git a/source/3rdparty/sdl2/CMakeLists.txt b/source/3rdparty/sdl2/CMakeLists.txt index 25ef90c..98474ca 100644 --- a/source/3rdparty/sdl2/CMakeLists.txt +++ b/source/3rdparty/sdl2/CMakeLists.txt @@ -5,13 +5,22 @@ set(SDL_TEST OFF CACHE BOOL "" FORCE) add_subdirectory(sdl2 build_sdl2) if (CLANG AND NOT ANDROID) - target_compile_options(SDL2-static PRIVATE -Wno-pragma-pack -Wno-unused-command-line-argument -Wno-incompatible-function-pointer-types -Wno-unused-const-variable) + target_compile_options(SDL2-static PRIVATE -Wno-pragma-pack -Wno-unused-command-line-argument -Wno-unused-function -Wno-incompatible-function-pointer-types -Wno-unused-but-set-variable -Wno-unused-const-variable) endif() if (MSVC AND NOT CLANG) - target_compile_options(SDL2-static PRIVATE /wd4028) + target_compile_options(SDL2-static PRIVATE /wd4028) endif() if (ANDROID) - target_compile_options(SDL2-static PRIVATE -Wno-deprecated-declarations) + target_compile_options(SDL2-static PRIVATE -Wno-deprecated-declarations) endif() + +if (LINUX) + if(CLANG) + target_compile_definitions(SDL2-static PRIVATE SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS) + target_compile_options(SDL2-static PRIVATE -Wno-unused-variable) + else() + target_compile_options(SDL2-static PRIVATE -Wno-unused-variable -Wno-unused-function) + endif() +endif() \ No newline at end of file diff --git a/source/3rdparty/sqlite/CMakeLists.txt b/source/3rdparty/sqlite/CMakeLists.txt index ce16616..62397df 100644 --- a/source/3rdparty/sqlite/CMakeLists.txt +++ b/source/3rdparty/sqlite/CMakeLists.txt @@ -3,7 +3,7 @@ file(GLOB sqlite_src ) -if (MINGW) +if (MINGW OR LINUX) if (CLANG) if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 13.0.0) set_source_files_properties(${sqlite_src} PROPERTIES COMPILE_FLAGS "-Wno-unused-but-set-variable -Wno-unused-function -Wno-unknown-pragmas -Wno-unused-variable -Wno-sometimes-uninitialized") diff --git a/source/3rdparty/vulkan/CMakeLists.txt b/source/3rdparty/vulkan/CMakeLists.txt index e14c4b5..0552503 100644 --- a/source/3rdparty/vulkan/CMakeLists.txt +++ b/source/3rdparty/vulkan/CMakeLists.txt @@ -10,6 +10,9 @@ elseif(MSVC AND CLANG) else() set_target_properties(vulkan-1 PROPERTIES IMPORTED_IMPLIB "${CMAKE_CURRENT_SOURCE_DIR}/lib/vulkan-1.lib") endif() +elseif(LINUX) + find_library(Vulkan_Lib vulkan) + set_target_properties(vulkan-1 PROPERTIES IMPORTED_LOCATION ${Vulkan_Lib}) endif() set(SPIRV_SOURCES @@ -335,12 +338,15 @@ set(SPIRV_TOOLS_OPT_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/source/opt/wrap_opkill.cpp ) -if (MSVC) - set_source_files_properties(${SPIRV_SOURCES} PROPERTIES COMPILE_FLAGS "/Os -D_CRT_SECURE_NO_WARNINGS -DSPIRV_WINDOWS") - set_source_files_properties(${SPIRV_TOOLS_OPT_SOURCES} PROPERTIES COMPILE_FLAGS "/Os -D_CRT_SECURE_NO_WARNINGS -DSPIRV_WINDOWS") +if (LINUX) + set_source_files_properties(${SPIRV_SOURCES} PROPERTIES COMPILE_FLAGS "-Os -DSPIRV_LINUX") + set_source_files_properties(${SPIRV_TOOLS_OPT_SOURCES} PROPERTIES COMPILE_FLAGS "-Os -DSPIRV_LINUX") +elseif (MSVC) + set_source_files_properties(${SPIRV_SOURCES} PROPERTIES COMPILE_FLAGS "/Os -D_CRT_SECURE_NO_WARNINGS -DSPIRV_WINDOWS") + set_source_files_properties(${SPIRV_TOOLS_OPT_SOURCES} PROPERTIES COMPILE_FLAGS "/Os -D_CRT_SECURE_NO_WARNINGS -DSPIRV_WINDOWS") else() - set_source_files_properties(${SPIRV_SOURCES} PROPERTIES COMPILE_FLAGS "-Os -DSPIRV_WINDOWS") - set_source_files_properties(${SPIRV_TOOLS_OPT_SOURCES} PROPERTIES COMPILE_FLAGS "-Os -DSPIRV_WINDOWS") + set_source_files_properties(${SPIRV_SOURCES} PROPERTIES COMPILE_FLAGS "-Os -DSPIRV_WINDOWS") + set_source_files_properties(${SPIRV_TOOLS_OPT_SOURCES} PROPERTIES COMPILE_FLAGS "-Os -DSPIRV_WINDOWS") endif() diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 6c404d5..a2c94de 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -2,8 +2,12 @@ cmake_minimum_required(VERSION 3.12) project(Kyty) -if (NOT (WIN32 AND (MINGW OR MSVC))) - message(FATAL_ERROR "only mingw and msvc supported") +if(CMAKE_SYSTEM_NAME MATCHES ".*Linux") + set(LINUX TRUE) +endif() + +if (NOT ((WIN32 AND (MINGW OR MSVC)) OR LINUX)) + message(FATAL_ERROR "only mingw and msvc supported (or linux)") endif() set(CMAKE_CXX_STANDARD 17) @@ -43,9 +47,22 @@ else() set(KYTY_BUILD KYTY_BUILD_RELEASE) endif() -set(KYTY_PLATFORM KYTY_PLATFORM_WINDOWS) +if(LINUX) + set(KYTY_PLATFORM KYTY_PLATFORM_LINUX) +else() + set(KYTY_PLATFORM KYTY_PLATFORM_WINDOWS) +endif() -if(MINGW) +if(LINUX) + if(CMAKE_CXX_COMPILER_ID MATCHES "(C|c?)lang") + set(CLANG 1) + set(KYTY_COMPILER CLANG) + set(KYTY_LINKER LLD) + else() + set(KYTY_COMPILER GCC) + set(KYTY_LINKER LD) + endif() +elseif(MINGW) if(CMAKE_CXX_COMPILER_ID MATCHES "(C|c?)lang") set(CLANG 1) set(KYTY_COMPILER CLANG) @@ -78,11 +95,11 @@ if (CLANG AND (KYTY_LINKER STREQUAL LLD)) set(KYTY_LD_OPTIONS "-fuse-ld=lld") endif() -if (KYTY_LINKER STREQUAL LD) +if (KYTY_LINKER STREQUAL LD AND NOT LINUX) set(KYTY_LD_OPTIONS "-Wl,--image-base=0x100000000000") endif() -project(Kyty${KYTY_PROJECT_NAME}${CMAKE_BUILD_TYPE}${KYTY_COMPILER} VERSION 0.2.1) +project(Kyty${KYTY_PROJECT_NAME}${CMAKE_BUILD_TYPE}${KYTY_COMPILER} VERSION 0.2.2) include(src_script.cmake) @@ -121,7 +138,7 @@ if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 12.0.0) core math_obj scripts - sys_obj + sys #launcher unit_test ) @@ -130,7 +147,7 @@ if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 12.0.0) #core #math_obj #scripts - #sys_obj + #sys launcher #unit_test ) @@ -164,18 +181,20 @@ target_link_libraries(fc_script sys) target_link_libraries(fc_script math) target_link_libraries(fc_script scripts) target_link_libraries(fc_script lua) +if (MSVC OR MINGW) target_link_libraries(fc_script opengl32) target_link_libraries(fc_script iphlpapi) -target_link_libraries(fc_script SDL2-static) target_link_libraries(fc_script setupapi) +target_link_libraries(fc_script ws2_32) +target_link_libraries(fc_script psapi) +endif() +target_link_libraries(fc_script SDL2-static) target_link_libraries(fc_script emulator) target_link_libraries(fc_script rijndael) target_link_libraries(fc_script lzma) target_link_libraries(fc_script sqlite) target_link_libraries(fc_script zstd) target_link_libraries(fc_script easy_profiler) -target_link_libraries(fc_script ws2_32) -target_link_libraries(fc_script psapi) target_link_libraries(fc_script cpuinfo) if (CLANG AND NOT MSVC) target_link_libraries(fc_script pthread) @@ -186,21 +205,16 @@ endif() set(KYTY_SCRIPT_BIN "../../__bin/fc_script") -if(MSVC) +if(LINUX) + set_target_properties(fc_script PROPERTIES LINK_FLAGS "${KYTY_LD_OPTIONS} -Wl,-Map=fc_script_${FYTY_COMPILER_ID}_${KYTY_LINKER_ID}_${KYTY_BITNESS}.map") + #add_custom_command(TARGET fc_script POST_BUILD COMMAND ${KYTY_SCRIPT_BIN} ${PROJECT_SOURCE_DIR}/map_to_csv.lua fc_script ${FYTY_COMPILER_ID} ${KYTY_BITNESS} ${KYTY_LINKER_ID}) +elseif(MSVC) set_target_properties(fc_script PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "$(SolutionDir)$(Configuration)/") - set_target_properties(fc_script - PROPERTIES - LINK_FLAGS "/DYNAMICBASE:NO /MAP:fc_script_msvc_${KYTY_BITNESS}.map" - ) - add_custom_command(TARGET fc_script POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different fc_script_msvc_${KYTY_BITNESS}.map $/fc_script_${KYTY_COMPILER_ID}_${KYTY_LINKER_ID}_${KYTY_BITNESS}.map) - add_custom_command(TARGET fc_script POST_BUILD - COMMAND ${KYTY_SCRIPT_BIN} ${PROJECT_SOURCE_DIR}/map_to_csv.lua $/fc_script ${KYTY_COMPILER_ID} ${KYTY_BITNESS} ${KYTY_LINKER_ID}) - add_custom_command(TARGET fc_script POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different "${PROJECT_SOURCE_DIR}/3rdparty/winpthread/bin/libwinpthread-1.dll" $/libwinpthread-1.dll) -endif() - -if(MINGW) + set_target_properties(fc_script PROPERTIES LINK_FLAGS "/DYNAMICBASE:NO /MAP:fc_script_msvc_${KYTY_BITNESS}.map") + add_custom_command(TARGET fc_script POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different fc_script_msvc_${KYTY_BITNESS}.map $/fc_script_${KYTY_COMPILER_ID}_${KYTY_LINKER_ID}_${KYTY_BITNESS}.map) + add_custom_command(TARGET fc_script POST_BUILD COMMAND ${KYTY_SCRIPT_BIN} ${PROJECT_SOURCE_DIR}/map_to_csv.lua $/fc_script ${KYTY_COMPILER_ID} ${KYTY_BITNESS} ${KYTY_LINKER_ID}) + add_custom_command(TARGET fc_script POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${PROJECT_SOURCE_DIR}/3rdparty/winpthread/bin/libwinpthread-1.dll" $/libwinpthread-1.dll) +elseif(MINGW) set_target_properties(fc_script PROPERTIES LINK_FLAGS "${KYTY_LD_OPTIONS} -Wl,-Map=fc_script_${KYTY_COMPILER_ID}_${KYTY_LINKER_ID}_${KYTY_BITNESS}.map") add_custom_command(TARGET fc_script POST_BUILD COMMAND ${KYTY_SCRIPT_BIN} ${PROJECT_SOURCE_DIR}/map_to_csv.lua fc_script ${KYTY_COMPILER_ID} ${KYTY_BITNESS} ${KYTY_LINKER_ID}) endif() diff --git a/source/emulator/include/Emulator/Common.h b/source/emulator/include/Emulator/Common.h index fba8ed0..00e1a58 100644 --- a/source/emulator/include/Emulator/Common.h +++ b/source/emulator/include/Emulator/Common.h @@ -3,8 +3,9 @@ #include "Kyty/Core/Common.h" -#if (KYTY_COMPILER == KYTY_COMPILER_CLANG || KYTY_COMPILER == KYTY_COMPILER_MINGW) && KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS && \ - KYTY_BITNESS == 64 && KYTY_ENDIAN == KYTY_ENDIAN_LITTLE && KYTY_ABI == KYTY_ABI_X86_64 && KYTY_PROJECT == KYTY_PROJECT_EMULATOR +#if (KYTY_COMPILER == KYTY_COMPILER_CLANG || KYTY_COMPILER == KYTY_COMPILER_MINGW || KYTY_COMPILER == KYTY_COMPILER_GCC) && \ + (KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS || KYTY_PLATFORM == KYTY_PLATFORM_LINUX) && KYTY_BITNESS == 64 && \ + KYTY_ENDIAN == KYTY_ENDIAN_LITTLE && KYTY_ABI == KYTY_ABI_X86_64 && KYTY_PROJECT == KYTY_PROJECT_EMULATOR #define KYTY_EMU_ENABLED #endif diff --git a/source/emulator/include/Emulator/Libs/VaContext.h b/source/emulator/include/Emulator/Libs/VaContext.h index 679024f..392bf4a 100644 --- a/source/emulator/include/Emulator/Libs/VaContext.h +++ b/source/emulator/include/Emulator/Libs/VaContext.h @@ -136,14 +136,14 @@ inline long double VaArg_long_double(VaList* l) return VaArg_overflow_arg_area(l); } -inline wint_t VaArg_wint_t(VaList* l) +/*inline wint_t VaArg_wint_t(VaList* l) { if (l->gp_offset <= 40) { return VaArg_reg_save_area_gp(l); } return VaArg_overflow_arg_area(l); -} +}*/ inline VaCharX16 VaArg_char_x16(VaList* l) { diff --git a/source/emulator/include/Emulator/Loader/RuntimeLinker.h b/source/emulator/include/Emulator/Loader/RuntimeLinker.h index 7be5380..ea99e26 100644 --- a/source/emulator/include/Emulator/Loader/RuntimeLinker.h +++ b/source/emulator/include/Emulator/Loader/RuntimeLinker.h @@ -12,6 +12,10 @@ #ifdef KYTY_EMU_ENABLED +namespace Kyty::Core::VirtualMemory { +class ExceptionHandler; +} // namespace Kyty::Core::VirtualMemory + namespace Kyty::Loader { class Elf64; @@ -19,10 +23,6 @@ struct Elf64_Sym; struct Elf64_Rela; class RuntimeLinker; -namespace VirtualMemory { -class ExceptionHandler; -} // namespace VirtualMemory - using module_func_t = int (*)(size_t args, const void* argp); struct ModuleId @@ -103,23 +103,23 @@ struct DynamicInfo struct Program { - int32_t unique_id = -1; - RuntimeLinker* rt = nullptr; - String file_name; - Elf64* elf = nullptr; - VirtualMemory::ExceptionHandler* exception_handler = nullptr; - DynamicInfo* dynamic_info = nullptr; - uint64_t base_vaddr = 0; - uint64_t base_size = 0; - uint64_t base_size_aligned = 0; - SymbolDatabase* export_symbols = nullptr; - SymbolDatabase* import_symbols = nullptr; - ThreadLocalStorage tls; - bool fail_if_global_not_resolved = true; - bool dbg_print_reloc = false; - uint64_t proc_param_vaddr = 0; - uint64_t custom_call_plt_vaddr = 0; - uint32_t custom_call_plt_num = 0; + int32_t unique_id = -1; + RuntimeLinker* rt = nullptr; + String file_name; + Elf64* elf = nullptr; + Core::VirtualMemory::ExceptionHandler* exception_handler = nullptr; + DynamicInfo* dynamic_info = nullptr; + uint64_t base_vaddr = 0; + uint64_t base_size = 0; + uint64_t base_size_aligned = 0; + SymbolDatabase* export_symbols = nullptr; + SymbolDatabase* import_symbols = nullptr; + ThreadLocalStorage tls; + bool fail_if_global_not_resolved = true; + bool dbg_print_reloc = false; + uint64_t proc_param_vaddr = 0; + uint64_t custom_call_plt_vaddr = 0; + uint32_t custom_call_plt_num = 0; }; class RuntimeLinker diff --git a/source/emulator/src/Graphics/Graphics.cpp b/source/emulator/src/Graphics/Graphics.cpp index 363947a..7a34f2a 100644 --- a/source/emulator/src/Graphics/Graphics.cpp +++ b/source/emulator/src/Graphics/Graphics.cpp @@ -3,6 +3,7 @@ #include "Kyty/Core/DbgAssert.h" #include "Kyty/Core/File.h" #include "Kyty/Core/String.h" +#include "Kyty/Core/VirtualMemory.h" #include "Emulator/Config.h" #include "Emulator/Graphics/GraphicsRender.h" @@ -19,7 +20,6 @@ #include "Emulator/Kernel/Pthread.h" #include "Emulator/Libs/Errno.h" #include "Emulator/Libs/Libs.h" -#include "Emulator/Loader/VirtualMemory.h" #include #include @@ -661,11 +661,11 @@ void* KYTY_SYSV_ABI GraphicsGetTheTessellationFactorRingBufferBaseAddress() { PRINT_NAME(); - auto addr = Loader::VirtualMemory::AllocAligned(0, 0x20000, Loader::VirtualMemory::Mode::ReadWrite, 256); - Loader::VirtualMemory::Free(addr); - bool again = Loader::VirtualMemory::AllocFixed(addr, 0x20000, Loader::VirtualMemory::Mode::ReadWrite); + auto addr = Core::VirtualMemory::AllocAligned(0, 0x20000, Core::VirtualMemory::Mode::ReadWrite, 256); + Core::VirtualMemory::Free(addr); + bool again = Core::VirtualMemory::AllocFixed(addr, 0x20000, Core::VirtualMemory::Mode::ReadWrite); EXIT_NOT_IMPLEMENTED(!again); - Loader::VirtualMemory::Free(addr); + Core::VirtualMemory::Free(addr); printf("\t addr = %016" PRIx64 "\n", addr); diff --git a/source/emulator/src/Graphics/Tile.cpp b/source/emulator/src/Graphics/Tile.cpp index 10284a3..0b61320 100644 --- a/source/emulator/src/Graphics/Tile.cpp +++ b/source/emulator/src/Graphics/Tile.cpp @@ -7,7 +7,7 @@ #include "Emulator/Graphics/AsyncJob.h" #include "Emulator/Profiler.h" -#if KYTY_COMPILER != KYTY_COMPILER_CLANG +#if KYTY_COMPILER != KYTY_COMPILER_CLANG && KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS #include #endif @@ -20,7 +20,7 @@ namespace Kyty::Libs::Graphics { static uint32_t IntLog2(uint32_t i) { -#if KYTY_COMPILER == KYTY_COMPILER_CLANG +#if KYTY_COMPILER == KYTY_COMPILER_CLANG || KYTY_PLATFORM != KYTY_PLATFORM_WINDOWS return 31 - __builtin_clz(i | 1u); #else unsigned long temp; diff --git a/source/emulator/src/Graphics/Window.cpp b/source/emulator/src/Graphics/Window.cpp index c3f2ee4..7deea79 100644 --- a/source/emulator/src/Graphics/Window.cpp +++ b/source/emulator/src/Graphics/Window.cpp @@ -8,6 +8,7 @@ #include "Kyty/Core/Threads.h" #include "Kyty/Core/Timer.h" #include "Kyty/Core/Vector.h" +#include "Kyty/Core/VirtualMemory.h" #include "Emulator/Config.h" #include "Emulator/Controller.h" @@ -17,7 +18,6 @@ #include "Emulator/Graphics/Utils.h" #include "Emulator/Graphics/VideoOut.h" #include "Emulator/Loader/SystemContent.h" -#include "Emulator/Loader/VirtualMemory.h" #include "Emulator/Profiler.h" #include "SDL.h" @@ -444,7 +444,7 @@ void game_event_keyboard(GameApi* game, const EventKeyboard* key) (key->repeat ? "repeat" : ""), key->scan_code, key->key_code, key->mod); #endif -#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS +#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS || KYTY_PLATFORM == KYTY_PLATFORM_LINUX if (key->down && key->key_code == SDLK_ESCAPE) { game->m_game_need_exit = true; @@ -2204,7 +2204,7 @@ static void VulkanCreate(WindowContext* ctx) printf("Select device: %s\n", device_properties.deviceName); memcpy(ctx->device_name, device_properties.deviceName, sizeof(ctx->device_name)); - memcpy(ctx->processor_name, Loader::GetSystemInfo().ProcessorName.C_Str(), sizeof(ctx->processor_name)); + memcpy(ctx->processor_name, Core::GetSystemInfo().ProcessorName.C_Str(), sizeof(ctx->processor_name)); ctx->graphic_ctx.device = VulkanCreateDevice(ctx->graphic_ctx.physical_device, ctx->surface, &r, queues, device_extensions); if (ctx->graphic_ctx.device == nullptr) diff --git a/source/emulator/src/Kernel/Memory.cpp b/source/emulator/src/Kernel/Memory.cpp index 120c06b..4da59a9 100644 --- a/source/emulator/src/Kernel/Memory.cpp +++ b/source/emulator/src/Kernel/Memory.cpp @@ -5,13 +5,13 @@ #include "Kyty/Core/String.h" #include "Kyty/Core/Threads.h" #include "Kyty/Core/Vector.h" +#include "Kyty/Core/VirtualMemory.h" #include "Emulator/Graphics/GraphicsRun.h" #include "Emulator/Graphics/Objects/GpuMemory.h" #include "Emulator/Graphics/Window.h" #include "Emulator/Libs/Errno.h" #include "Emulator/Libs/Libs.h" -#include "Emulator/Loader/VirtualMemory.h" #include @@ -19,7 +19,7 @@ namespace Kyty::Libs::LibKernel::Memory { -namespace VirtualMemory = Loader::VirtualMemory; +namespace VirtualMemory = Core::VirtualMemory; LIB_NAME("libkernel", "libkernel"); diff --git a/source/emulator/src/Kernel/Pthread.cpp b/source/emulator/src/Kernel/Pthread.cpp index c56f227..b88319d 100644 --- a/source/emulator/src/Kernel/Pthread.cpp +++ b/source/emulator/src/Kernel/Pthread.cpp @@ -20,8 +20,16 @@ #ifdef KYTY_EMU_ENABLED +#if KYTY_PLATFORM == KYTY_PLATFORM_LINUX +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + #include + +#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS #include +#endif namespace Kyty::Libs { @@ -2701,4 +2709,8 @@ int KYTY_SYSV_ABI pthread_mutexattr_destroy(LibKernel::PthreadMutexattr* attr) } // namespace Kyty::Libs +#if KYTY_PLATFORM == KYTY_PLATFORM_LINUX +#pragma GCC diagnostic pop +#endif + #endif // KYTY_EMU_ENABLED diff --git a/source/emulator/src/Kyty.cpp b/source/emulator/src/Kyty.cpp index b3b39cd..c5e26b7 100644 --- a/source/emulator/src/Kyty.cpp +++ b/source/emulator/src/Kyty.cpp @@ -6,6 +6,7 @@ #include "Kyty/Core/Subsystems.h" #include "Kyty/Core/Threads.h" #include "Kyty/Core/Vector.h" +#include "Kyty/Core/VirtualMemory.h" #include "Kyty/Scripts/Scripts.h" #include "Kyty/UnitTest.h" @@ -23,7 +24,6 @@ #include "Emulator/Loader/RuntimeLinker.h" #include "Emulator/Loader/SystemContent.h" #include "Emulator/Loader/Timer.h" -#include "Emulator/Loader/VirtualMemory.h" #include "Emulator/Network.h" #include "Emulator/Profiler.h" @@ -57,18 +57,9 @@ static void load_symbols_all(Loader::RuntimeLinker* rt) static void print_system_info() { - Loader::SystemInfo info = Loader::GetSystemInfo(); + Core::SystemInfo info = Core::GetSystemInfo(); - printf("PageSize = %" PRIu32 "\n", info.PageSize); - printf("MinimumApplicationAddress = 0x%016" PRIx64 "\n", info.MinimumApplicationAddress); - printf("MaximumApplicationAddress = 0x%016" PRIx64 "\n", info.MaximumApplicationAddress); - printf("ActiveProcessorMask = 0x%08" PRIx32 "\n", info.ActiveProcessorMask); - printf("NumberOfProcessors = %" PRIu32 "\n", info.NumberOfProcessors); - printf("ProcessorArchitecture = %s\n", Core::EnumName(info.ProcessorArchitecture).C_Str()); - printf("AllocationGranularity = %" PRIu32 "\n", info.AllocationGranularity); - printf("ProcessorLevel = %" PRIu16 "\n", info.ProcessorLevel); - printf("ProcessorRevision = 0x%04" PRIx16 "\n", info.ProcessorRevision); - printf("ProcessorName = %s\n", info.ProcessorName.C_Str()); + printf("ProcessorName = %s\n", info.ProcessorName.C_Str()); } static void kyty_close() diff --git a/source/emulator/src/Libs/LibDbgAsan.cpp b/source/emulator/src/Libs/LibDbgAsan.cpp index bcec28e..17f6883 100644 --- a/source/emulator/src/Libs/LibDbgAsan.cpp +++ b/source/emulator/src/Libs/LibDbgAsan.cpp @@ -3,13 +3,13 @@ #include "Kyty/Core/String.h" #include "Kyty/Core/Threads.h" #include "Kyty/Core/Vector.h" +#include "Kyty/Core/VirtualMemory.h" #include "Kyty/Sys/SysDbg.h" #include "Emulator/Common.h" #include "Emulator/Kernel/Memory.h" #include "Emulator/Libs/Libs.h" #include "Emulator/Loader/SymbolDatabase.h" -#include "Emulator/Loader/VirtualMemory.h" #include @@ -68,8 +68,8 @@ static void AllocShadow(uintptr_t min_addr, uintptr_t max_addr) auto size = max_shadow - min_shadow + page_size; - printf("\t shadow = %016" PRIx64 "\n", reinterpret_cast(min_shadow)); - printf("\t size = %016" PRIx64 "\n", reinterpret_cast(size)); + printf("\t shadow = %016" PRIx64 "\n", static_cast(min_shadow)); + printf("\t size = %016" PRIx64 "\n", static_cast(size)); for (uintptr_t page = min_shadow; page <= max_shadow; page += page_size) { @@ -78,7 +78,7 @@ static void AllocShadow(uintptr_t min_addr, uintptr_t max_addr) g_ctx->shadows[index].count++; } else { - if (!Loader::VirtualMemory::AllocFixed(page, page_size, Loader::VirtualMemory::Mode::ReadWrite)) + if (!Core::VirtualMemory::AllocFixed(page, page_size, Core::VirtualMemory::Mode::ReadWrite)) { EXIT("can't allocate shadow memory\n"); } @@ -104,8 +104,8 @@ static void FreeShadow(uintptr_t min_addr, uintptr_t max_addr) auto size = max_shadow - min_shadow + page_size; - printf("\t shadow = %016" PRIx64 "\n", reinterpret_cast(min_shadow)); - printf("\t size = %016" PRIx64 "\n", reinterpret_cast(size)); + printf("\t shadow = %016" PRIx64 "\n", static_cast(min_shadow)); + printf("\t size = %016" PRIx64 "\n", static_cast(size)); for (uintptr_t page = min_shadow; page <= max_shadow; page += page_size) { @@ -115,7 +115,7 @@ static void FreeShadow(uintptr_t min_addr, uintptr_t max_addr) if (g_ctx->shadows[index].count <= 0) { - if (!Loader::VirtualMemory::Free(page)) + if (!Core::VirtualMemory::Free(page)) { EXIT("can't free shadow memory\n"); } @@ -147,7 +147,11 @@ static void KYTY_SYSV_ABI asan_init() sys_dbg_stack_info_t s {}; sys_stack_usage(s); +#if KYTY_PLATFORM == KYTY_PLATFORM_LINUX + AllocShadow(s.addr, reinterpret_cast(&s)); +#else AllocShadow(s.reserved_addr, reinterpret_cast(&s)); +#endif LibKernel::Memory::RegisterCallbacks(KernelAlloc, KernelFree); } diff --git a/source/emulator/src/Libs/Printf.cpp b/source/emulator/src/Libs/Printf.cpp index 5d73bcd..2883042 100644 --- a/source/emulator/src/Libs/Printf.cpp +++ b/source/emulator/src/Libs/Printf.cpp @@ -405,7 +405,7 @@ static size_t _etoa(out_fct_type out, Vector* buffer, size_t idx, size_t m int expval = static_cast(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168); // now we want to compute 10^expval but we want to be sure it won't overflow // exp2 = static_cast(expval * 3.321928094887362 + 0.5); - exp2 = lround(expval * 3.321928094887362); + exp2 = static_cast(lround(expval * 3.321928094887362)); const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453; const double z2 = z * z; conv.U = static_cast(exp2 + 1023) << 52U; diff --git a/source/emulator/src/Loader/RuntimeLinker.cpp b/source/emulator/src/Loader/RuntimeLinker.cpp index c434dbf..a89c999 100644 --- a/source/emulator/src/Loader/RuntimeLinker.cpp +++ b/source/emulator/src/Loader/RuntimeLinker.cpp @@ -7,6 +7,7 @@ #include "Kyty/Core/Singleton.h" #include "Kyty/Core/String.h" #include "Kyty/Core/Threads.h" +#include "Kyty/Core/VirtualMemory.h" #include "Kyty/Sys/SysDbg.h" #include "Emulator/Config.h" @@ -15,7 +16,6 @@ #include "Emulator/Loader/Elf.h" #include "Emulator/Loader/Jit.h" #include "Emulator/Loader/SymbolDatabase.h" -#include "Emulator/Loader/VirtualMemory.h" #include "Emulator/Profiler.h" #ifdef KYTY_EMU_ENABLED @@ -144,19 +144,19 @@ static void dbg_dump_rela(const String& folder, Elf64_Rela* records, uint64_t si f.Close(); } -static VirtualMemory::Mode get_mode(Elf64_Word flags) +static Core::VirtualMemory::Mode get_mode(Elf64_Word flags) { switch (flags) { - case PF_R: return VirtualMemory::Mode::Read; - case PF_W: return VirtualMemory::Mode::Write; - case PF_R | PF_W: return VirtualMemory::Mode::ReadWrite; - case PF_X: return VirtualMemory::Mode::Execute; - case PF_X | PF_R: return VirtualMemory::Mode::ExecuteRead; - case PF_X | PF_W: return VirtualMemory::Mode::ExecuteWrite; - case PF_X | PF_W | PF_R: return VirtualMemory::Mode::ExecuteReadWrite; + case PF_R: return Core::VirtualMemory::Mode::Read; + case PF_W: return Core::VirtualMemory::Mode::Write; + case PF_R | PF_W: return Core::VirtualMemory::Mode::ReadWrite; + case PF_X: return Core::VirtualMemory::Mode::Execute; + case PF_X | PF_R: return Core::VirtualMemory::Mode::ExecuteRead; + case PF_X | PF_W: return Core::VirtualMemory::Mode::ExecuteWrite; + case PF_X | PF_W | PF_R: return Core::VirtualMemory::Mode::ExecuteReadWrite; - default: return VirtualMemory::Mode::NoAccess; + default: return Core::VirtualMemory::Mode::NoAccess; } } @@ -200,13 +200,13 @@ void KYTY_SYSV_ABI sys_stack_walk_x86(uint64_t rbp, void** stack, int* depth) g_desired_base_addr - (SYSTEM_RESERVED + CODE_BASE_OFFSET)); } -static void kyty_exception_handler(const VirtualMemory::ExceptionHandler::ExceptionInfo* info) +static void kyty_exception_handler(const Core::VirtualMemory::ExceptionHandler::ExceptionInfo* info) { printf("kyty_exception_handler: %016" PRIx64 "\n", info->exception_address); - if (info->type == VirtualMemory::ExceptionHandler::ExceptionType::AccessViolation) + if (info->type == Core::VirtualMemory::ExceptionHandler::ExceptionType::AccessViolation) { - if (info->access_violation_type == VirtualMemory::ExceptionHandler::AccessViolationType::Write && + if (info->access_violation_type == Core::VirtualMemory::ExceptionHandler::AccessViolationType::Write && Libs::Graphics::GpuMemoryCheckAccessViolation(info->access_violation_vaddr, sizeof(uint64_t))) { return; @@ -428,7 +428,7 @@ static void relocate(uint32_t index, Elf64_Rela* r, Program* program, bool jmpre if (ri.resolved) { - patched = VirtualMemory::PatchReplace(ri.vaddr, ri.value); + patched = Core::VirtualMemory::PatchReplace(ri.vaddr, ri.value); } else { uint64_t value = 0; @@ -453,7 +453,7 @@ static void relocate(uint32_t index, Elf64_Rela* r, Program* program, bool jmpre if (value != 0) { - patched = VirtualMemory::PatchReplace(ri.vaddr, value); + patched = Core::VirtualMemory::PatchReplace(ri.vaddr, value); } else { auto dbg_str = String::FromPrintf("[%016" PRIx64 "] <- %s%016" PRIx64 "%s, %s, %s, %s, %s", ri.vaddr, @@ -788,6 +788,7 @@ void RuntimeLinker::Execute() printf(FG_BRIGHT_YELLOW "--- Execute: " BOLD BG_BLUE "%s" BG_DEFAULT NO_BOLD DEFAULT "\n", "Main"); printf(FG_BRIGHT_YELLOW "---" DEFAULT "\n"); +#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS // Reserve some stack. There may be jumps over guard page. To prevent segfault we need to expand committed area. size_t expanded_size = 0; @@ -800,6 +801,7 @@ void RuntimeLinker::Execute() *reinterpret_cast(s.guard_addr) = 0; expanded_size += s.guard_size; } +#endif if (auto entry = GetEntry(); entry != 0) { @@ -1135,11 +1137,11 @@ void RuntimeLinker::LoadProgramToMemory(Program* program) program->base_size = calc_base_size(ehdr, phdr); program->base_size_aligned = (program->base_size & ~(static_cast(0x1000) - 1)) + 0x1000; - uint64_t exception_handler_size = VirtualMemory::ExceptionHandler::GetSize(); + uint64_t exception_handler_size = Core::VirtualMemory::ExceptionHandler::GetSize(); uint64_t tls_handler_size = is_shared ? 0 : Jit::SafeCall::GetSize(); uint64_t alloc_size = program->base_size_aligned + exception_handler_size + tls_handler_size; - program->base_vaddr = VirtualMemory::Alloc(g_desired_base_addr, alloc_size, VirtualMemory::Mode::ExecuteReadWrite); + program->base_vaddr = Core::VirtualMemory::Alloc(g_desired_base_addr, alloc_size, Core::VirtualMemory::Mode::ExecuteReadWrite); if (!is_shared) { @@ -1160,7 +1162,7 @@ void RuntimeLinker::LoadProgramToMemory(Program* program) printf("tls_handler_size = 0x%016" PRIx64 "\n", tls_handler_size); } - program->exception_handler = new VirtualMemory::ExceptionHandler; + program->exception_handler = new Core::VirtualMemory::ExceptionHandler; if (is_shared) { @@ -1175,7 +1177,7 @@ void RuntimeLinker::LoadProgramToMemory(Program* program) // if (Libs::Graphics::GpuMemoryWatcherEnabled()) { - VirtualMemory::ExceptionHandler::InstallVectored(kyty_exception_handler); + Core::VirtualMemory::ExceptionHandler::InstallVectored(kyty_exception_handler); } } @@ -1197,20 +1199,20 @@ void RuntimeLinker::LoadProgramToMemory(Program* program) program->elf->LoadSegment(segment_addr, phdr[i].p_offset, segment_file_size); - bool skip_protect = (phdr[i].p_type == PT_LOAD && is_next_gen && mode == VirtualMemory::Mode::NoAccess); + bool skip_protect = (phdr[i].p_type == PT_LOAD && is_next_gen && mode == Core::VirtualMemory::Mode::NoAccess); - if (VirtualMemory::IsExecute(mode)) + if (Core::VirtualMemory::IsExecute(mode)) { PatchProgram(program, segment_addr, segment_memory_size); } if (!skip_protect) { - VirtualMemory::Protect(segment_addr, segment_memory_size, mode); + Core::VirtualMemory::Protect(segment_addr, segment_memory_size, mode); - if (VirtualMemory::IsExecute(mode)) + if (Core::VirtualMemory::IsExecute(mode)) { - VirtualMemory::FlushInstructionCache(segment_addr, segment_memory_size); + Core::VirtualMemory::FlushInstructionCache(segment_addr, segment_memory_size); } } } @@ -1247,12 +1249,12 @@ void RuntimeLinker::DeleteProgram(Program* p) { if (p->base_vaddr != 0 || p->base_size != 0) { - VirtualMemory::Free(p->base_vaddr); + Core::VirtualMemory::Free(p->base_vaddr); } if (p->custom_call_plt_vaddr != 0 || p->custom_call_plt_num != 0) { - VirtualMemory::Free(p->custom_call_plt_vaddr); + Core::VirtualMemory::Free(p->custom_call_plt_vaddr); } delete p->elf; @@ -1380,17 +1382,17 @@ static void InstallRelocateHandler(Program* program) uint64_t pltgot_size = static_cast(3) * 8; void** pltgot = reinterpret_cast(pltgot_vaddr); - VirtualMemory::Mode old_mode {}; - VirtualMemory::Protect(pltgot_vaddr, pltgot_size, VirtualMemory::Mode::Write, &old_mode); + Core::VirtualMemory::Mode old_mode {}; + Core::VirtualMemory::Protect(pltgot_vaddr, pltgot_size, Core::VirtualMemory::Mode::Write, &old_mode); pltgot[1] = program; pltgot[2] = reinterpret_cast(RelocateHandler); - VirtualMemory::Protect(pltgot_vaddr, pltgot_size, old_mode); + Core::VirtualMemory::Protect(pltgot_vaddr, pltgot_size, old_mode); - if (VirtualMemory::IsExecute(old_mode)) + if (Core::VirtualMemory::IsExecute(old_mode)) { - VirtualMemory::FlushInstructionCache(pltgot_vaddr, pltgot_size); + Core::VirtualMemory::FlushInstructionCache(pltgot_vaddr, pltgot_size); } // TODO(): check if this table already generated by compiler (sometimes it is missing) @@ -1398,12 +1400,12 @@ static void InstallRelocateHandler(Program* program) { program->custom_call_plt_num = program->dynamic_info->jmprela_table_size / sizeof(Elf64_Rela); auto size = Jit::CallPlt::GetSize(program->custom_call_plt_num); - program->custom_call_plt_vaddr = VirtualMemory::Alloc(SYSTEM_RESERVED, size, VirtualMemory::Mode::Write); + program->custom_call_plt_vaddr = Core::VirtualMemory::Alloc(SYSTEM_RESERVED, size, Core::VirtualMemory::Mode::Write); EXIT_NOT_IMPLEMENTED(program->custom_call_plt_vaddr == 0); auto* code = new (reinterpret_cast(program->custom_call_plt_vaddr)) Jit::CallPlt(program->custom_call_plt_num); code->SetPltGot(pltgot_vaddr); - VirtualMemory::Protect(program->custom_call_plt_vaddr, size, VirtualMemory::Mode::Execute); - VirtualMemory::FlushInstructionCache(program->custom_call_plt_vaddr, size); + Core::VirtualMemory::Protect(program->custom_call_plt_vaddr, size, Core::VirtualMemory::Mode::Execute); + Core::VirtualMemory::FlushInstructionCache(program->custom_call_plt_vaddr, size); } } @@ -1415,7 +1417,7 @@ void RuntimeLinker::Relocate(Program* program) if (g_invalid_memory == 0) { - g_invalid_memory = VirtualMemory::Alloc(INVALID_MEMORY, 4096, VirtualMemory::Mode::NoAccess); + g_invalid_memory = Core::VirtualMemory::Alloc(INVALID_MEMORY, 4096, Core::VirtualMemory::Mode::NoAccess); EXIT_NOT_IMPLEMENTED(g_invalid_memory == 0); } @@ -1570,8 +1572,8 @@ void RuntimeLinker::SetupTlsHandler(Program* program) code->SetRegSaveArea(g_tls_reg_save_area); code->SetLockVar(&g_tls_spinlock); - VirtualMemory::Protect(program->tls.handler_vaddr, Jit::SafeCall::GetSize(), VirtualMemory::Mode::Execute); - VirtualMemory::FlushInstructionCache(program->tls.handler_vaddr, Jit::SafeCall::GetSize()); + Core::VirtualMemory::Protect(program->tls.handler_vaddr, Jit::SafeCall::GetSize(), Core::VirtualMemory::Mode::Execute); + Core::VirtualMemory::FlushInstructionCache(program->tls.handler_vaddr, Jit::SafeCall::GetSize()); } void RuntimeLinker::DeleteTlss(int thread_id) diff --git a/source/emulator/src/Loader/VirtualMemory.cpp b/source/emulator/src/Loader/VirtualMemory.cpp deleted file mode 100644 index b02b760..0000000 --- a/source/emulator/src/Loader/VirtualMemory.cpp +++ /dev/null @@ -1,497 +0,0 @@ -#include "Emulator/Loader/VirtualMemory.h" - -#include "Kyty/Core/DbgAssert.h" - -#include "Emulator/Common.h" -#include "Emulator/Loader/Jit.h" -#include "Emulator/Profiler.h" - -#include "cpuinfo.h" - -//#include -//#include - -// NOLINTNEXTLINE -//#define NTDDI_VERSION 0x0A000005 - -#include // IWYU pragma: keep - -// IWYU pragma: no_include -// IWYU pragma: no_include -// IWYU pragma: no_include -// IWYU pragma: no_include -// IWYU pragma: no_include -// IWYU pragma: no_include -// IWYU pragma: no_include -// IWYU pragma: no_include -// IWYU pragma: no_include -// IWYU pragma: no_include -// IWYU pragma: no_include -// IWYU pragma: no_include - -//#include - -#ifdef KYTY_EMU_ENABLED - -namespace Kyty::Loader { - -SystemInfo GetSystemInfo() -{ - SystemInfo ret {}; - - SYSTEM_INFO system_info; - GetSystemInfo(&system_info); - - switch (system_info.wProcessorArchitecture) - { - case PROCESSOR_ARCHITECTURE_AMD64: ret.ProcessorArchitecture = ProcessorArchitecture::Amd64; break; - case PROCESSOR_ARCHITECTURE_UNKNOWN: - default: ret.ProcessorArchitecture = ProcessorArchitecture::Unknown; - } - - ret.PageSize = system_info.dwPageSize; - ret.MinimumApplicationAddress = reinterpret_cast(system_info.lpMinimumApplicationAddress); - ret.MaximumApplicationAddress = reinterpret_cast(system_info.lpMaximumApplicationAddress); - ret.ActiveProcessorMask = system_info.dwActiveProcessorMask; - ret.NumberOfProcessors = system_info.dwNumberOfProcessors; - ret.ProcessorLevel = system_info.wProcessorLevel; - ret.ProcessorRevision = system_info.wProcessorRevision; - - const auto* p = cpuinfo_get_package(0); - - EXIT_IF(p == nullptr); - - ret.ProcessorName = String::FromUtf8(p->name); - - return ret; -} - -namespace VirtualMemory { - -class ExceptionHandlerPrivate -{ -public: -#pragma pack(1) - - struct UnwindInfo - { - uint8_t Version : 3; - uint8_t Flags : 5; - uint8_t SizeOfProlog; - uint8_t CountOfCodes; - uint8_t FrameRegister : 4; - uint8_t FrameOffset : 4; - ULONG ExceptionHandler; - - ExceptionHandlerPrivate* ExceptionData; - }; - - struct HandlerInfo - { - Jit::JmpRax code; - RUNTIME_FUNCTION function_table = {}; - UnwindInfo unwind_info = {}; - }; - -#pragma pack() - - static EXCEPTION_DISPOSITION Handler(PEXCEPTION_RECORD exception_record, ULONG64 /*EstablisherFrame*/, PCONTEXT /*ContextRecord*/, - PDISPATCHER_CONTEXT dispatcher_context) - { - ExceptionHandler::ExceptionInfo info {}; - - info.exception_address = reinterpret_cast(exception_record->ExceptionAddress); - - if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) - { - info.type = ExceptionHandler::ExceptionType::AccessViolation; - switch (exception_record->ExceptionInformation[0]) - { - case 0: info.access_violation_type = ExceptionHandler::AccessViolationType::Read; break; - case 1: info.access_violation_type = ExceptionHandler::AccessViolationType::Write; break; - case 8: info.access_violation_type = ExceptionHandler::AccessViolationType::Execute; break; - default: info.access_violation_type = ExceptionHandler::AccessViolationType::Unknown; break; - } - info.access_violation_vaddr = exception_record->ExceptionInformation[1]; - } - - info.rbp = dispatcher_context->ContextRecord->Rbp; - info.exception_win_code = exception_record->ExceptionCode; - - auto* p = *static_cast(dispatcher_context->HandlerData); - p->func(&info); - - return ExceptionContinueExecution; - } - - void InitHandler() - { - auto* h = new (reinterpret_cast(handler_addr)) HandlerInfo; - auto* code = &h->code; - auto* unwind_info = &h->unwind_info; - - function_table = &h->function_table; - - function_table->BeginAddress = 0; - function_table->EndAddress = image_size; - function_table->UnwindData = reinterpret_cast(unwind_info) - base_address; - - unwind_info->Version = 1; - unwind_info->Flags = UNW_FLAG_EHANDLER; - unwind_info->SizeOfProlog = 0; - unwind_info->CountOfCodes = 0; - unwind_info->FrameRegister = 0; - unwind_info->FrameOffset = 0; - unwind_info->ExceptionHandler = reinterpret_cast(code) - base_address; - unwind_info->ExceptionData = this; - - code->SetFunc(Handler); - - FlushInstructionCache(reinterpret_cast(code), sizeof(h->code)); - } - - uint64_t base_address = 0; - uint64_t handler_addr = 0; - uint64_t image_size = 0; - PRUNTIME_FUNCTION function_table = nullptr; - - ExceptionHandler::handler_func_t func = nullptr; - - static ExceptionHandler::handler_func_t g_vec_func; -}; - -ExceptionHandler::handler_func_t ExceptionHandlerPrivate::g_vec_func = nullptr; - -ExceptionHandler::ExceptionHandler(): m_p(new ExceptionHandlerPrivate) {} - -ExceptionHandler::~ExceptionHandler() -{ - Uninstall(); - delete m_p; -} - -uint64_t ExceptionHandler::GetSize() -{ - return (sizeof(ExceptionHandlerPrivate::HandlerInfo) & ~(static_cast(0x1000) - 1)) + 0x1000; -} - -bool ExceptionHandler::Install(uint64_t base_address, uint64_t handler_addr, uint64_t image_size, handler_func_t func) -{ - if (m_p->function_table == nullptr) - { - m_p->base_address = base_address; - m_p->handler_addr = handler_addr; - m_p->image_size = image_size; - m_p->func = func; - - m_p->InitHandler(); - - if (RtlAddFunctionTable(m_p->function_table, 1, base_address) == FALSE) - { - printf("RtlAddFunctionTable() failed: 0x%08" PRIx32 "\n", static_cast(GetLastError())); - return false; - } - - return true; - } - - return false; -} - -static LONG WINAPI ExceptionFilter(PEXCEPTION_POINTERS exception) -{ - PEXCEPTION_RECORD exception_record = exception->ExceptionRecord; - - ExceptionHandler::ExceptionInfo info {}; - - info.exception_address = reinterpret_cast(exception_record->ExceptionAddress); - - // printf("exception_record->ExceptionCode = %u\n", static_cast(exception_record->ExceptionCode)); - - if (exception_record->ExceptionCode == DBG_PRINTEXCEPTION_C || exception_record->ExceptionCode == DBG_PRINTEXCEPTION_WIDE_C) - { - return EXCEPTION_CONTINUE_EXECUTION; - } - - if (exception_record->ExceptionCode == 0x406D1388) - { - // Set a thread name - return EXCEPTION_CONTINUE_EXECUTION; - } - - if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) - { - info.type = ExceptionHandler::ExceptionType::AccessViolation; - switch (exception_record->ExceptionInformation[0]) - { - case 0: info.access_violation_type = ExceptionHandler::AccessViolationType::Read; break; - case 1: info.access_violation_type = ExceptionHandler::AccessViolationType::Write; break; - case 8: info.access_violation_type = ExceptionHandler::AccessViolationType::Execute; break; - default: info.access_violation_type = ExceptionHandler::AccessViolationType::Unknown; break; - } - info.access_violation_vaddr = exception_record->ExceptionInformation[1]; - } - - info.rbp = exception->ContextRecord->Rbp; - info.exception_win_code = exception_record->ExceptionCode; - - ExceptionHandlerPrivate::g_vec_func(&info); - - return EXCEPTION_CONTINUE_EXECUTION; -} - -bool ExceptionHandler::InstallVectored(handler_func_t func) -{ - if (ExceptionHandlerPrivate::g_vec_func == nullptr) - { - ExceptionHandlerPrivate::g_vec_func = func; - - if (AddVectoredExceptionHandler(1, ExceptionFilter) == nullptr) - { - printf("AddVectoredExceptionHandler() failed\n"); - return false; - } - - return true; - } - return false; -} - -bool ExceptionHandler::Uninstall() -{ - if (m_p->function_table != nullptr) - { - if (RtlDeleteFunctionTable(m_p->function_table) == FALSE) - { - printf("RtlDeleteFunctionTable() failed: 0x%08" PRIx32 "\n", static_cast(GetLastError())); - return false; - } - m_p->function_table = nullptr; - return true; - } - - return false; -} - -static DWORD get_protection_flag(VirtualMemory::Mode mode) -{ - DWORD protect = PAGE_NOACCESS; - switch (mode) - { - case VirtualMemory::Mode::Read: protect = PAGE_READONLY; break; - - case VirtualMemory::Mode::Write: - case VirtualMemory::Mode::ReadWrite: protect = PAGE_READWRITE; break; - - case VirtualMemory::Mode::Execute: protect = PAGE_EXECUTE; break; - - case VirtualMemory::Mode::ExecuteRead: protect = PAGE_EXECUTE_READ; break; - - case VirtualMemory::Mode::ExecuteWrite: - case VirtualMemory::Mode::ExecuteReadWrite: protect = PAGE_EXECUTE_READWRITE; break; - - case VirtualMemory::Mode::NoAccess: - default: protect = PAGE_NOACCESS; break; - } - return protect; -} - -static VirtualMemory::Mode get_protection_flag(DWORD mode) -{ - switch (mode) - { - case PAGE_NOACCESS: return VirtualMemory::Mode::NoAccess; - case PAGE_READONLY: return VirtualMemory::Mode::Read; - case PAGE_READWRITE: return VirtualMemory::Mode::ReadWrite; - case PAGE_EXECUTE: return VirtualMemory::Mode::Execute; - case PAGE_EXECUTE_READ: return VirtualMemory::Mode::ExecuteRead; - case PAGE_EXECUTE_READWRITE: return VirtualMemory::Mode::ExecuteReadWrite; - default: return VirtualMemory::Mode::NoAccess; - } -} - -void Init() -{ - cpuinfo_initialize(); -} - -uint64_t Alloc(uint64_t address, uint64_t size, Mode mode) -{ - auto ptr = (address == 0 ? AllocAligned(address, size, mode, 1) - : reinterpret_cast(VirtualAlloc(reinterpret_cast(static_cast(address)), size, - static_cast(MEM_COMMIT) | static_cast(MEM_RESERVE), - get_protection_flag(mode)))); - if (ptr == 0) - { - auto err = static_cast(GetLastError()); - - if (err != ERROR_INVALID_ADDRESS) - { - printf("VirtualAlloc() failed: 0x%08" PRIx32 "\n", err); - } else - { - return AllocAligned(address, size, mode, 1); - } - } - return ptr; -} - -using VirtualAlloc2_func_t = /*WINBASEAPI*/ PVOID WINAPI (*)(HANDLE, PVOID, SIZE_T, ULONG, ULONG, MEM_EXTENDED_PARAMETER*, ULONG); - -static VirtualAlloc2_func_t ResolveVirtualAlloc2() -{ - HMODULE h = GetModuleHandle("KernelBase"); - if (h != nullptr) - { - return reinterpret_cast(GetProcAddress(h, "VirtualAlloc2")); - } - return nullptr; -} - -uint64_t AllocAligned(uint64_t address, uint64_t size, Mode mode, uint64_t alignment) -{ - if (alignment == 0) - { - printf("VirtualAlloc2 failed: 0x%08" PRIx32 "\n", static_cast(GetLastError())); - return 0; - } - - static constexpr uint64_t SYSTEM_MANAGED_MIN = 0x0000040000u; - static constexpr uint64_t SYSTEM_MANAGED_MAX = 0x07FFFFBFFFu; - static constexpr uint64_t USER_MIN = 0x1000000000u; - static constexpr uint64_t USER_MAX = 0xFBFFFFFFFFu; - - MEM_ADDRESS_REQUIREMENTS req {}; - MEM_EXTENDED_PARAMETER param {}; - req.LowestStartingAddress = (address == 0 ? reinterpret_cast(SYSTEM_MANAGED_MIN) : reinterpret_cast(address)); - req.HighestEndingAddress = (address == 0 ? reinterpret_cast(SYSTEM_MANAGED_MAX) : reinterpret_cast(USER_MAX)); - req.Alignment = alignment; - param.Type = MemExtendedParameterAddressRequirements; - param.Pointer = &req; - - MEM_ADDRESS_REQUIREMENTS req2 {}; - MEM_EXTENDED_PARAMETER param2 {}; - req2.LowestStartingAddress = (address == 0 ? reinterpret_cast(USER_MIN) : reinterpret_cast(address)); - req2.HighestEndingAddress = reinterpret_cast(USER_MAX); - req2.Alignment = alignment; - param2.Type = MemExtendedParameterAddressRequirements; - param2.Pointer = &req2; - - static auto virtual_alloc2 = ResolveVirtualAlloc2(); - - EXIT_NOT_IMPLEMENTED(virtual_alloc2 == nullptr); - - auto ptr = reinterpret_cast(virtual_alloc2(GetCurrentProcess(), nullptr, size, - static_cast(MEM_COMMIT) | static_cast(MEM_RESERVE), - get_protection_flag(mode), ¶m, 1)); - - if (ptr == 0) - { - ptr = reinterpret_cast(virtual_alloc2(GetCurrentProcess(), nullptr, size, - static_cast(MEM_COMMIT) | static_cast(MEM_RESERVE), - get_protection_flag(mode), ¶m2, 1)); - } - - if (ptr == 0) - { - auto err = static_cast(GetLastError()); - if (err != ERROR_INVALID_PARAMETER) - { - printf("VirtualAlloc2(alignment = 0x%016" PRIx64 ") failed: 0x%08" PRIx32 "\n", alignment, err); - } else - { - return AllocAligned(address, size, mode, alignment << 1u); - } - } - return ptr; -} - -bool AllocFixed(uint64_t address, uint64_t size, Mode mode) -{ - auto ptr = reinterpret_cast(VirtualAlloc(reinterpret_cast(static_cast(address)), size, - static_cast(MEM_COMMIT) | static_cast(MEM_RESERVE), - get_protection_flag(mode))); - if (ptr == 0) - { - auto err = static_cast(GetLastError()); - - printf("VirtualAlloc() failed: 0x%08" PRIx32 "\n", err); - - return false; - } - - if (ptr != address) - { - printf("VirtualAlloc() failed: wrong address\n"); - VirtualFree(reinterpret_cast(ptr), 0, MEM_RELEASE); - return false; - } - - return true; -} - -bool Free(uint64_t address) -{ - if (VirtualFree(reinterpret_cast(static_cast(address)), 0, MEM_RELEASE) == 0) - { - printf("VirtualFree() failed: 0x%08" PRIx32 "\n", static_cast(GetLastError())); - return false; - } - return true; -} - -bool Protect(uint64_t address, uint64_t size, Mode mode, Mode* old_mode) -{ - KYTY_PROFILER_FUNCTION(); - - DWORD old_protect = 0; - if (VirtualProtect(reinterpret_cast(static_cast(address)), size, get_protection_flag(mode), &old_protect) == 0) - { - printf("VirtualProtect() failed: 0x%08" PRIx32 "\n", static_cast(GetLastError())); - return false; - } - if (old_mode != nullptr) - { - *old_mode = get_protection_flag(old_protect); - } - return true; -} - -bool FlushInstructionCache(uint64_t address, uint64_t size) -{ - if (::FlushInstructionCache(GetCurrentProcess(), reinterpret_cast(static_cast(address)), size) == 0) - { - printf("FlushInstructionCache() failed: 0x%08" PRIx32 "\n", static_cast(GetLastError())); - return false; - } - return true; -} - -bool PatchReplace(uint64_t vaddr, uint64_t value) -{ - KYTY_PROFILER_FUNCTION(); - - VirtualMemory::Mode old_mode {}; - VirtualMemory::Protect(vaddr, 8, VirtualMemory::Mode::ReadWrite, &old_mode); - - auto* ptr = reinterpret_cast(vaddr); - - bool ret = (*ptr != value); - - *ptr = value; - - VirtualMemory::Protect(vaddr, 8, old_mode); - - if (VirtualMemory::IsExecute(old_mode)) - { - VirtualMemory::FlushInstructionCache(vaddr, 8); - } - - return ret; -} - -} // namespace VirtualMemory - -} // namespace Kyty::Loader - -#endif // KYTY_EMU_ENABLED diff --git a/source/include/Kyty/Core/DbgAssert.h b/source/include/Kyty/Core/DbgAssert.h index 24e014e..9fa085c 100644 --- a/source/include/Kyty/Core/DbgAssert.h +++ b/source/include/Kyty/Core/DbgAssert.h @@ -29,11 +29,7 @@ bool dbg_is_debugger_present(); } // namespace Kyty::Core -//#if KYTY_COMPILER == KYTY_COMPILER_MINGW -//#pragma GCC diagnostic ignored "-Warray-bounds" -//#endif - -#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS +#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS || KYTY_PLATFORM == KYTY_PLATFORM_LINUX #define ASSERT_HALT() \ (Kyty::Core::dbg_is_debugger_present() ? (::fflush(nullptr), *(reinterpret_cast(1)) = 0) \ : (Kyty::Core::dbg_exit(321), 1)) diff --git a/source/include/Kyty/Core/Threads.h b/source/include/Kyty/Core/Threads.h index 3eae2f7..6454879 100644 --- a/source/include/Kyty/Core/Threads.h +++ b/source/include/Kyty/Core/Threads.h @@ -93,7 +93,7 @@ public: virtual ~CondVar(); void Wait(Mutex* mutex); - void WaitFor(Mutex* mutex, uint32_t micros); + bool WaitFor(Mutex* mutex, uint32_t micros); void Signal(); void SignalAll(); diff --git a/source/emulator/include/Emulator/Loader/VirtualMemory.h b/source/include/Kyty/Core/VirtualMemory.h similarity index 71% rename from source/emulator/include/Emulator/Loader/VirtualMemory.h rename to source/include/Kyty/Core/VirtualMemory.h index f7fe815..70b73e8 100644 --- a/source/emulator/include/Emulator/Loader/VirtualMemory.h +++ b/source/include/Kyty/Core/VirtualMemory.h @@ -1,33 +1,14 @@ -#ifndef EMULATOR_INCLUDE_EMULATOR_LOADER_VIRTUALMEMORY_H_ -#define EMULATOR_INCLUDE_EMULATOR_LOADER_VIRTUALMEMORY_H_ +#ifndef INCLUDE_KYTY_CORE_VIRTUALMEMORY_H_ +#define INCLUDE_KYTY_CORE_VIRTUALMEMORY_H_ #include "Kyty/Core/Common.h" #include "Kyty/Core/String.h" -#include "Emulator/Common.h" - -#ifdef KYTY_EMU_ENABLED - -namespace Kyty::Loader { - -enum class ProcessorArchitecture -{ - Unknown, - Amd64, // x64 (AMD or Intel) -}; +namespace Kyty::Core { struct SystemInfo { - uint32_t PageSize; - uint64_t MinimumApplicationAddress; - uint64_t MaximumApplicationAddress; - uint32_t ActiveProcessorMask; - uint32_t NumberOfProcessors; - ProcessorArchitecture ProcessorArchitecture; - uint32_t AllocationGranularity; - uint16_t ProcessorLevel; - uint16_t ProcessorRevision; - String ProcessorName; + String ProcessorName; }; SystemInfo GetSystemInfo(); @@ -110,8 +91,6 @@ bool PatchReplace(uint64_t vaddr, uint64_t value); } // namespace VirtualMemory -} // namespace Kyty::Loader +} // namespace Kyty::Core -#endif // KYTY_EMU_ENABLED - -#endif /* EMULATOR_INCLUDE_EMULATOR_LOADER_VIRTUALMEMORY_H_ */ +#endif /* INCLUDE_KYTY_CORE_VIRTUALMEMORY_H_ */ diff --git a/source/include/Kyty/Sys/SysLinuxDbg.h b/source/include/Kyty/Sys/Linux/SysLinuxDbg.h similarity index 94% rename from source/include/Kyty/Sys/SysLinuxDbg.h rename to source/include/Kyty/Sys/Linux/SysLinuxDbg.h index 9940759..8c68cbb 100644 --- a/source/include/Kyty/Sys/SysLinuxDbg.h +++ b/source/include/Kyty/Sys/Linux/SysLinuxDbg.h @@ -9,6 +9,7 @@ namespace Kyty { +// NOLINTNEXTLINE(readability-identifier-naming) struct sys_dbg_stack_info_t { uintptr_t code_addr; diff --git a/source/include/Kyty/Sys/SysLinuxFileIO.h b/source/include/Kyty/Sys/Linux/SysLinuxFileIO.h similarity index 79% rename from source/include/Kyty/Sys/SysLinuxFileIO.h rename to source/include/Kyty/Sys/Linux/SysLinuxFileIO.h index 385dccc..dddf951 100644 --- a/source/include/Kyty/Sys/SysLinuxFileIO.h +++ b/source/include/Kyty/Sys/Linux/SysLinuxFileIO.h @@ -8,25 +8,28 @@ #else #include "Kyty/Core/String.h" -#include "Kyty/Sys/SysLinuxTimer.h" +#include "Kyty/Sys/Linux/SysLinuxTimer.h" namespace Kyty { +// NOLINTNEXTLINE(readability-identifier-naming) enum sys_file_type_t { - SYS_FILE_ERROR, - SYS_FILE_MEMORY_STAT, - SYS_FILE_FILE, - SYS_FILE_MEMORY_DYN + SYS_FILE_ERROR, // NOLINT(readability-identifier-naming) + SYS_FILE_MEMORY_STAT, // NOLINT(readability-identifier-naming) + SYS_FILE_FILE, // NOLINT(readability-identifier-naming) + SYS_FILE_MEMORY_DYN // NOLINT(readability-identifier-naming) }; +// NOLINTNEXTLINE(readability-identifier-naming) enum sys_file_cache_type_t { - SYS_FILE_CACHE_AUTO = 0, - SYS_FILE_CACHE_RANDOM_ACCESS = 1, - SYS_FILE_CACHE_SEQUENTIAL_SCAN = 2 + SYS_FILE_CACHE_AUTO = 0, // NOLINT(readability-identifier-naming) + SYS_FILE_CACHE_RANDOM_ACCESS = 1, // NOLINT(readability-identifier-naming) + SYS_FILE_CACHE_SEQUENTIAL_SCAN = 2 // NOLINT(readability-identifier-naming) }; +// NOLINTNEXTLINE(readability-identifier-naming) struct sys_file_mem_buf_t { uint8_t* base; @@ -34,6 +37,7 @@ struct sys_file_mem_buf_t uint32_t size; }; +// NOLINTNEXTLINE(readability-identifier-naming) struct sys_file_t { sys_file_type_t type; @@ -44,6 +48,7 @@ struct sys_file_t }; }; +// NOLINTNEXTLINE(readability-identifier-naming) struct sys_file_find_t { String path_with_name; @@ -52,14 +57,15 @@ struct sys_file_find_t uint64_t size; }; +// NOLINTNEXTLINE(readability-identifier-naming) struct sys_dir_entry_t { String name; bool is_file; }; -void sys_file_read(void* data, uint32_t size, sys_file_t& f, uint32_t* bytes_read = 0); -void sys_file_write(const void* data, uint32_t size, sys_file_t& f, uint32_t* bytes_written = 0); +void sys_file_read(void* data, uint32_t size, sys_file_t& f, uint32_t* bytes_read = nullptr); +void sys_file_write(const void* data, uint32_t size, sys_file_t& f, uint32_t* bytes_written = nullptr); void sys_file_read_r(void* data, uint32_t size, sys_file_t& f); void sys_file_write_r(const void* data, uint32_t size, sys_file_t& f); sys_file_t* sys_file_create(const String& file_name); diff --git a/source/include/Kyty/Sys/Linux/SysLinuxHeap.h b/source/include/Kyty/Sys/Linux/SysLinuxHeap.h new file mode 100644 index 0000000..6caeb83 --- /dev/null +++ b/source/include/Kyty/Sys/Linux/SysLinuxHeap.h @@ -0,0 +1,104 @@ +#ifndef SYS_LINUX_INCLUDE_KYTY_SYSHEAP_H_ +#define SYS_LINUX_INCLUDE_KYTY_SYSHEAP_H_ + +// IWYU pragma: private + +#if KYTY_PLATFORM != KYTY_PLATFORM_LINUX +//#error "KYTY_PLATFORM != KYTY_PLATFORM_LINUX" +#else + +#include "Kyty/Sys/Linux/SysLinuxSync.h" + +namespace Kyty { + +using sys_heap_id_t = SysCS*; + +inline sys_heap_id_t sys_heap_create() +{ + return nullptr; +} + +inline sys_heap_id_t sys_heap_deafult() +{ + return nullptr; +} + +inline void* sys_heap_alloc(sys_heap_id_t /*heap_id*/, size_t size) +{ + // NOLINTNEXTLINE(cppcoreguidelines-no-malloc,hicpp-no-malloc) + void* m = malloc(size); + + EXIT_IF(m == nullptr); + + return m; +} + +inline void* sys_heap_realloc(sys_heap_id_t /*heap_id*/, void* p, size_t size) +{ + // NOLINTNEXTLINE(cppcoreguidelines-no-malloc,hicpp-no-malloc) + void* m = p != nullptr ? realloc(p, size) : malloc(size); + + if (m == nullptr) + { + EXIT_IF(m == nullptr); + } + + return m; +} + +inline void sys_heap_free(sys_heap_id_t /*heap_id*/, void* p) +{ + // NOLINTNEXTLINE(cppcoreguidelines-no-malloc,hicpp-no-malloc) + free(p); +} + +inline sys_heap_id_t sys_heap_create_s() +{ + auto* cs = new SysCS; + cs->Init(); + return cs; +} + +inline void* sys_heap_alloc_s(sys_heap_id_t heap_id, size_t size) +{ + heap_id->Enter(); + + // NOLINTNEXTLINE(cppcoreguidelines-no-malloc,hicpp-no-malloc) + void* m = malloc(size); + + heap_id->Leave(); + + EXIT_IF(m == nullptr); + + return m; +} + +inline void* sys_heap_realloc_s(sys_heap_id_t heap_id, void* p, size_t size) +{ + heap_id->Enter(); + + // NOLINTNEXTLINE(cppcoreguidelines-no-malloc,hicpp-no-malloc) + void* m = p != nullptr ? realloc(p, size) : malloc(size); + + heap_id->Leave(); + + EXIT_IF(m == nullptr); + + return m; +} + +inline void sys_heap_free_s(sys_heap_id_t heap_id, void* p) +{ + heap_id->Enter(); + + // NOLINTNEXTLINE(cppcoreguidelines-no-malloc,hicpp-no-malloc) + free(p); + + heap_id->Leave(); +} + +} // namespace Kyty + +#endif + +#endif /* SYS_LINUX_INCLUDE_KYTY_SYSHEAP_H_ */ diff --git a/source/include/Kyty/Sys/SysLinuxStdio.h b/source/include/Kyty/Sys/Linux/SysLinuxStdio.h similarity index 70% rename from source/include/Kyty/Sys/SysLinuxStdio.h rename to source/include/Kyty/Sys/Linux/SysLinuxStdio.h index f85b11d..f188671 100644 --- a/source/include/Kyty/Sys/SysLinuxStdio.h +++ b/source/include/Kyty/Sys/Linux/SysLinuxStdio.h @@ -8,22 +8,22 @@ #else //#include +#include namespace Kyty { inline uint32_t sys_vscprintf(const char* format, va_list argptr) { - int len; va_list argcopy; va_copy(argcopy, argptr); - len = vsnprintf(0, 0, format, argcopy); + int len = vsnprintf(nullptr, 0, format, argcopy); va_end(argcopy); return len < 0 ? 0 : len; } -inline uint32_t sys_vsnprintf(char* Dest, size_t Count, const char* Format, va_list Args) +inline uint32_t sys_vsnprintf(char* dest, size_t count, const char* format, va_list args) { - int len = vsnprintf(Dest, Count + 1, Format, Args); + int len = vsnprintf(dest, count + 1, format, args); return len < 0 ? 0 : len; } diff --git a/source/include/Kyty/Sys/SysLinuxStdlib.h b/source/include/Kyty/Sys/Linux/SysLinuxStdlib.h similarity index 88% rename from source/include/Kyty/Sys/SysLinuxStdlib.h rename to source/include/Kyty/Sys/Linux/SysLinuxStdlib.h index 92b9780..5d63e64 100644 --- a/source/include/Kyty/Sys/SysLinuxStdlib.h +++ b/source/include/Kyty/Sys/Linux/SysLinuxStdlib.h @@ -21,12 +21,12 @@ inline double sys_strtod(const char* nptr, char** endptr) inline int32_t sys_strtoi32(const char* nptr, char** endptr, int base) { - long r = strtol(nptr, endptr, base); - if (r >= static_cast(INT32_MAX)) + int64_t r = strtol(nptr, endptr, base); + if (r >= static_cast(INT32_MAX)) { return INT32_MAX; } - if (r <= static_cast(INT32_MIN)) + if (r <= static_cast(INT32_MIN)) { return INT32_MIN; } diff --git a/source/include/Kyty/Sys/SysLinuxSync.h b/source/include/Kyty/Sys/Linux/SysLinuxSync.h similarity index 50% rename from source/include/Kyty/Sys/SysLinuxSync.h rename to source/include/Kyty/Sys/Linux/SysLinuxSync.h index 56dfb4a..f77fe15 100644 --- a/source/include/Kyty/Sys/SysLinuxSync.h +++ b/source/include/Kyty/Sys/Linux/SysLinuxSync.h @@ -15,64 +15,66 @@ namespace Kyty { class SysCS { public: - SysCS() { check_ptr = 0; } + SysCS() = default; void Init() { - EXIT_IF(check_ptr != 0); + EXIT_IF(m_check_ptr != nullptr); - check_ptr = this; + m_check_ptr = this; - pthread_mutexattr_t attr; + pthread_mutexattr_t attr {}; pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP); - pthread_mutex_init(&m, &attr); + pthread_mutex_init(&m_mutex, &attr); pthread_mutexattr_destroy(&attr); } void Delete() { - EXIT_IF(check_ptr != this); + EXIT_IF(m_check_ptr != this); - check_ptr = 0; - pthread_mutex_destroy(&m); + m_check_ptr = nullptr; + pthread_mutex_destroy(&m_mutex); } - ~SysCS() { EXIT_IF(check_ptr != 0); } + ~SysCS() { EXIT_IF(m_check_ptr != nullptr); } void Enter() { - EXIT_IF(check_ptr != this); + EXIT_IF(m_check_ptr != this); - pthread_mutex_lock(&m); + pthread_mutex_lock(&m_mutex); } bool TryEnter() { - EXIT_IF(check_ptr != this); + EXIT_IF(m_check_ptr != this); - return pthread_mutex_trylock(&m) == 0; + return pthread_mutex_trylock(&m_mutex) == 0; } void Leave() { - EXIT_IF(check_ptr != this); + EXIT_IF(m_check_ptr != this); - pthread_mutex_unlock(&m); + pthread_mutex_unlock(&m_mutex); } KYTY_CLASS_NO_COPY(SysCS); private: - SysCS* check_ptr; - pthread_mutex_t m; + SysCS* m_check_ptr = nullptr; + pthread_mutex_t m_mutex {}; }; inline void sys_sleep(uint32_t ms) { - struct timespec ts; + struct timespec ts + { + }; ts.tv_sec = ms / 1000; - ts.tv_nsec = (ms % 1000) * 1000000; - nanosleep(&ts, 0); + ts.tv_nsec = static_cast(ms % 1000) * 1000000; + nanosleep(&ts, nullptr); } } // namespace Kyty diff --git a/source/include/Kyty/Sys/SysLinuxTimer.h b/source/include/Kyty/Sys/Linux/SysLinuxTimer.h similarity index 84% rename from source/include/Kyty/Sys/SysLinuxTimer.h rename to source/include/Kyty/Sys/Linux/SysLinuxTimer.h index 32065ea..e82bb97 100644 --- a/source/include/Kyty/Sys/SysLinuxTimer.h +++ b/source/include/Kyty/Sys/Linux/SysLinuxTimer.h @@ -31,9 +31,11 @@ struct SysFileTimeStruct inline void sys_file_to_system_time_utc(const SysFileTimeStruct& f, SysTimeStruct& t) { - struct tm i; + struct tm i + { + }; - if (f.is_invalid || !gmtime_r(&f.time, &i)) + if (f.is_invalid || gmtime_r(&f.time, &i) == nullptr) { t.is_invalid = true; return; @@ -51,7 +53,7 @@ inline void sys_file_to_system_time_utc(const SysFileTimeStruct& f, SysTimeStruc inline void sys_time_t_to_system(time_t t, SysTimeStruct& s) { - SysFileTimeStruct ft; + SysFileTimeStruct ft {}; ft.time = t; ft.is_invalid = false; sys_file_to_system_time_utc(ft, s); @@ -66,7 +68,9 @@ inline time_t sys_timegm(struct tm* tm) inline void sys_system_to_file_time_utc(const SysTimeStruct& f, SysFileTimeStruct& t) { - struct tm i; + struct tm i + { + }; i.tm_year = f.Year - 1900; i.tm_mon = f.Month - 1; @@ -75,22 +79,18 @@ inline void sys_system_to_file_time_utc(const SysTimeStruct& f, SysFileTimeStruc i.tm_min = f.Minute; i.tm_sec = f.Second; - if (f.is_invalid || (t.time = sys_timegm(&i)) == (time_t)-1) - { - t.is_invalid = true; - } else - { - t.is_invalid = false; - } + t.is_invalid = (f.is_invalid || (t.time = sys_timegm(&i)) == static_cast(-1)); } // Retrieves the current local date and time inline void sys_get_system_time(SysTimeStruct& t) { - time_t st; - struct tm i; + time_t st {}; + struct tm i + { + }; - if (time(&st) == (time_t)-1 || !localtime_r(&st, &i)) + if (time(&st) == static_cast(-1) || localtime_r(&st, &i) == nullptr) { t.is_invalid = true; return; @@ -109,10 +109,12 @@ inline void sys_get_system_time(SysTimeStruct& t) // Retrieves the current system date and time in Coordinated Universal Time (UTC). inline void sys_get_system_time_utc(SysTimeStruct& t) { - time_t st; - struct tm i; + time_t st {}; + struct tm i + { + }; - if (time(&st) == (time_t)-1 || !gmtime_r(&st, &i)) + if (time(&st) == static_cast(-1) || gmtime_r(&st, &i) == nullptr) { t.is_invalid = true; return; @@ -135,7 +137,9 @@ inline void sys_query_performance_frequency(uint64_t* freq) inline void sys_query_performance_counter(uint64_t* counter) { - struct timespec now; + struct timespec now + { + }; clock_gettime(CLOCK_MONOTONIC, &now); *counter = now.tv_sec * 1000000000LL + now.tv_nsec; } diff --git a/source/include/Kyty/Sys/Linux/SysLinuxVirtual.h b/source/include/Kyty/Sys/Linux/SysLinuxVirtual.h new file mode 100644 index 0000000..dd13720 --- /dev/null +++ b/source/include/Kyty/Sys/Linux/SysLinuxVirtual.h @@ -0,0 +1,30 @@ +#ifndef INCLUDE_KYTY_SYS_LINUX_SYSLINUXVIRTUAL_H_ +#define INCLUDE_KYTY_SYS_LINUX_SYSLINUXVIRTUAL_H_ + +#if KYTY_PLATFORM != KYTY_PLATFORM_LINUX +//#error "KYTY_PLATFORM != KYTY_PLATFORM_LINUX" +#else + +#include "Kyty/Core/Common.h" +#include "Kyty/Core/String.h" +#include "Kyty/Core/VirtualMemory.h" + +namespace Kyty::Core { + +void sys_get_system_info(SystemInfo* info); + +void sys_virtual_init(); + +uint64_t sys_virtual_alloc(uint64_t address, uint64_t size, VirtualMemory::Mode mode); +uint64_t sys_virtual_alloc_aligned(uint64_t address, uint64_t size, VirtualMemory::Mode mode, uint64_t alignment); +bool sys_virtual_alloc_fixed(uint64_t address, uint64_t size, VirtualMemory::Mode mode); +bool sys_virtual_free(uint64_t address); +bool sys_virtual_protect(uint64_t address, uint64_t size, VirtualMemory::Mode mode, VirtualMemory::Mode* old_mode = nullptr); +bool sys_virtual_flush_instruction_cache(uint64_t address, uint64_t size); +bool sys_virtual_patch_replace(uint64_t vaddr, uint64_t value); + +} // namespace Kyty::Core + +#endif + +#endif /* INCLUDE_KYTY_SYS_LINUX_SYSLINUXVIRTUAL_H_ */ diff --git a/source/include/Kyty/Sys/SysDbg.h b/source/include/Kyty/Sys/SysDbg.h index e387650..60394b8 100644 --- a/source/include/Kyty/Sys/SysDbg.h +++ b/source/include/Kyty/Sys/SysDbg.h @@ -2,8 +2,7 @@ #define INCLUDE_KYTY_SYS_SYSDBG_H_ #include "Kyty/Core/Common.h" - -#include "Kyty/Sys/SysLinuxDbg.h" // IWYU pragma: export -#include "Kyty/Sys/SysWindowsDbg.h" // IWYU pragma: export +#include "Kyty/Sys/Linux/SysLinuxDbg.h" // IWYU pragma: export +#include "Kyty/Sys/Windows/SysWindowsDbg.h" // IWYU pragma: export #endif /* INCLUDE_KYTY_SYS_SYSDBG_H_ */ diff --git a/source/include/Kyty/Sys/SysFileIO.h b/source/include/Kyty/Sys/SysFileIO.h index b6312eb..0a8aeb1 100644 --- a/source/include/Kyty/Sys/SysFileIO.h +++ b/source/include/Kyty/Sys/SysFileIO.h @@ -2,8 +2,7 @@ #define INCLUDE_KYTY_SYS_SYSFILEIO_H_ #include "Kyty/Core/Common.h" - -#include "Kyty/Sys/SysLinuxFileIO.h" // IWYU pragma: export -#include "Kyty/Sys/SysWindowsFileIO.h" // IWYU pragma: export +#include "Kyty/Sys/Linux/SysLinuxFileIO.h" // IWYU pragma: export +#include "Kyty/Sys/Windows/SysWindowsFileIO.h" // IWYU pragma: export #endif /* INCLUDE_KYTY_SYS_SYSFILEIO_H_ */ diff --git a/source/include/Kyty/Sys/SysHeap.h b/source/include/Kyty/Sys/SysHeap.h index d77b0a1..dfa9f82 100644 --- a/source/include/Kyty/Sys/SysHeap.h +++ b/source/include/Kyty/Sys/SysHeap.h @@ -2,8 +2,7 @@ #define INCLUDE_KYTY_SYS_SYSHEAP_H_ #include "Kyty/Core/Common.h" - -#include "Kyty/Sys/SysLinuxHeap.h" // IWYU pragma: export -#include "Kyty/Sys/SysWindowsHeap.h" // IWYU pragma: export +#include "Kyty/Sys/Linux/SysLinuxHeap.h" // IWYU pragma: export +#include "Kyty/Sys/Windows/SysWindowsHeap.h" // IWYU pragma: export #endif /* INCLUDE_KYTY_SYS_SYSHEAP_H_ */ diff --git a/source/include/Kyty/Sys/SysLinuxHeap.h b/source/include/Kyty/Sys/SysLinuxHeap.h deleted file mode 100644 index 60cdf53..0000000 --- a/source/include/Kyty/Sys/SysLinuxHeap.h +++ /dev/null @@ -1,98 +0,0 @@ -#ifndef SYS_LINUX_INCLUDE_KYTY_SYSHEAP_H_ -#define SYS_LINUX_INCLUDE_KYTY_SYSHEAP_H_ - -// IWYU pragma: private - -#if KYTY_PLATFORM != KYTY_PLATFORM_LINUX -//#error "KYTY_PLATFORM != KYTY_PLATFORM_LINUX" -#else - -#include "Kyty/Sys/SysLinuxSync.h" - -namespace Kyty { - -typedef SysCS* sys_heap_id_t; - -inline sys_heap_id_t sys_heap_create() -{ - return 0; -} - -inline sys_heap_id_t sys_heap_deafult() -{ - return 0; -} - -inline void* sys_heap_alloc(sys_heap_id_t heap_id, size_t size) -{ - void* m = malloc(size); - - EXIT_IF(m == 0); - - return m; -} - -inline void* sys_heap_realloc(sys_heap_id_t heap_id, void* p, size_t size) -{ - void* m = p ? realloc(p, size) : malloc(size); - - if (m == 0) - { - EXIT_IF(m == 0); - } - - return m; -} - -inline void sys_heap_free(sys_heap_id_t heap_id, void* p) -{ - free(p); -} - -inline sys_heap_id_t sys_heap_create_s() -{ - SysCS* cs = new SysCS; - cs->Init(); - return cs; -} - -inline void* sys_heap_alloc_s(sys_heap_id_t heap_id, size_t size) -{ - heap_id->Enter(); - - void* m = malloc(size); - - heap_id->Leave(); - - EXIT_IF(m == 0); - - return m; -} - -inline void* sys_heap_realloc_s(sys_heap_id_t heap_id, void* p, size_t size) -{ - heap_id->Enter(); - - void* m = p ? realloc(p, size) : malloc(size); - - heap_id->Leave(); - - EXIT_IF(m == 0); - - return m; -} - -inline void sys_heap_free_s(sys_heap_id_t heap_id, void* p) -{ - heap_id->Enter(); - - free(p); - - heap_id->Leave(); -} - -} // namespace Kyty - -#endif - -#endif /* SYS_LINUX_INCLUDE_KYTY_SYSHEAP_H_ */ diff --git a/source/include/Kyty/Sys/SysStdio.h b/source/include/Kyty/Sys/SysStdio.h index 9a5c768..01c1f68 100644 --- a/source/include/Kyty/Sys/SysStdio.h +++ b/source/include/Kyty/Sys/SysStdio.h @@ -2,8 +2,7 @@ #define INCLUDE_KYTY_SYS_SYSSTDIO_H_ #include "Kyty/Core/Common.h" - -#include "Kyty/Sys/SysLinuxStdio.h" // IWYU pragma: export -#include "Kyty/Sys/SysWindowsStdio.h" // IWYU pragma: export +#include "Kyty/Sys/Linux/SysLinuxStdio.h" // IWYU pragma: export +#include "Kyty/Sys/Windows/SysWindowsStdio.h" // IWYU pragma: export #endif /* INCLUDE_KYTY_SYS_SYSSTDIO_H_ */ diff --git a/source/include/Kyty/Sys/SysStdlib.h b/source/include/Kyty/Sys/SysStdlib.h index 56f6e3c..55be2a1 100644 --- a/source/include/Kyty/Sys/SysStdlib.h +++ b/source/include/Kyty/Sys/SysStdlib.h @@ -2,8 +2,7 @@ #define INCLUDE_KYTY_SYS_SYSSTDLIB_H_ #include "Kyty/Core/Common.h" - -#include "Kyty/Sys/SysLinuxStdlib.h" // IWYU pragma: export -#include "Kyty/Sys/SysWindowsStdlib.h" // IWYU pragma: export +#include "Kyty/Sys/Linux/SysLinuxStdlib.h" // IWYU pragma: export +#include "Kyty/Sys/Windows/SysWindowsStdlib.h" // IWYU pragma: export #endif /* INCLUDE_KYTY_SYS_SYSSTDLIB_H_ */ diff --git a/source/include/Kyty/Sys/SysSync.h b/source/include/Kyty/Sys/SysSync.h index a78bf74..cf18c2e 100644 --- a/source/include/Kyty/Sys/SysSync.h +++ b/source/include/Kyty/Sys/SysSync.h @@ -2,8 +2,7 @@ #define INCLUDE_KYTY_SYS_SYSSYNC_H_ #include "Kyty/Core/Common.h" - -#include "Kyty/Sys/SysLinuxSync.h" // IWYU pragma: export -#include "Kyty/Sys/SysWindowsSync.h" // IWYU pragma: export +#include "Kyty/Sys/Linux/SysLinuxSync.h" // IWYU pragma: export +#include "Kyty/Sys/Windows/SysWindowsSync.h" // IWYU pragma: export #endif /* INCLUDE_KYTY_SYS_SYSSYNC_H_ */ diff --git a/source/include/Kyty/Sys/SysTimer.h b/source/include/Kyty/Sys/SysTimer.h index 2de542e..b2c5262 100644 --- a/source/include/Kyty/Sys/SysTimer.h +++ b/source/include/Kyty/Sys/SysTimer.h @@ -2,8 +2,7 @@ #define INCLUDE_KYTY_SYS_SYSTIMER_H_ #include "Kyty/Core/Common.h" - -#include "Kyty/Sys/SysLinuxTimer.h" // IWYU pragma: export -#include "Kyty/Sys/SysWindowsTimer.h" // IWYU pragma: export +#include "Kyty/Sys/Linux/SysLinuxTimer.h" // IWYU pragma: export +#include "Kyty/Sys/Windows/SysWindowsTimer.h" // IWYU pragma: export #endif /* INCLUDE_KYTY_SYS_SYSTIMER_H_ */ diff --git a/source/include/Kyty/Sys/SysVirtual.h b/source/include/Kyty/Sys/SysVirtual.h new file mode 100644 index 0000000..42af285 --- /dev/null +++ b/source/include/Kyty/Sys/SysVirtual.h @@ -0,0 +1,8 @@ +#ifndef INCLUDE_KYTY_SYS_SYSVIRTUAL_H_ +#define INCLUDE_KYTY_SYS_SYSVIRTUAL_H_ + +#include "Kyty/Core/Common.h" +#include "Kyty/Sys/Linux/SysLinuxVirtual.h" // IWYU pragma: export +#include "Kyty/Sys/Windows/SysWindowsVirtual.h" // IWYU pragma: export + +#endif /* INCLUDE_KYTY_SYS_SYSVIRTUAL_H_ */ diff --git a/source/include/Kyty/Sys/SysWindowsDbg.h b/source/include/Kyty/Sys/Windows/SysWindowsDbg.h similarity index 100% rename from source/include/Kyty/Sys/SysWindowsDbg.h rename to source/include/Kyty/Sys/Windows/SysWindowsDbg.h diff --git a/source/include/Kyty/Sys/SysWindowsFileIO.h b/source/include/Kyty/Sys/Windows/SysWindowsFileIO.h similarity index 100% rename from source/include/Kyty/Sys/SysWindowsFileIO.h rename to source/include/Kyty/Sys/Windows/SysWindowsFileIO.h diff --git a/source/include/Kyty/Sys/SysWindowsHeap.h b/source/include/Kyty/Sys/Windows/SysWindowsHeap.h similarity index 100% rename from source/include/Kyty/Sys/SysWindowsHeap.h rename to source/include/Kyty/Sys/Windows/SysWindowsHeap.h diff --git a/source/include/Kyty/Sys/SysWindowsStdio.h b/source/include/Kyty/Sys/Windows/SysWindowsStdio.h similarity index 100% rename from source/include/Kyty/Sys/SysWindowsStdio.h rename to source/include/Kyty/Sys/Windows/SysWindowsStdio.h diff --git a/source/include/Kyty/Sys/SysWindowsStdlib.h b/source/include/Kyty/Sys/Windows/SysWindowsStdlib.h similarity index 100% rename from source/include/Kyty/Sys/SysWindowsStdlib.h rename to source/include/Kyty/Sys/Windows/SysWindowsStdlib.h diff --git a/source/include/Kyty/Sys/SysWindowsSync.h b/source/include/Kyty/Sys/Windows/SysWindowsSync.h similarity index 100% rename from source/include/Kyty/Sys/SysWindowsSync.h rename to source/include/Kyty/Sys/Windows/SysWindowsSync.h diff --git a/source/include/Kyty/Sys/SysWindowsTimer.h b/source/include/Kyty/Sys/Windows/SysWindowsTimer.h similarity index 100% rename from source/include/Kyty/Sys/SysWindowsTimer.h rename to source/include/Kyty/Sys/Windows/SysWindowsTimer.h diff --git a/source/include/Kyty/Sys/Windows/SysWindowsVirtual.h b/source/include/Kyty/Sys/Windows/SysWindowsVirtual.h new file mode 100644 index 0000000..8e0f3c9 --- /dev/null +++ b/source/include/Kyty/Sys/Windows/SysWindowsVirtual.h @@ -0,0 +1,30 @@ +#ifndef INCLUDE_KYTY_SYS_WINDOWS_SYSWINDOWSVIRTUAL_H_ +#define INCLUDE_KYTY_SYS_WINDOWS_SYSWINDOWSVIRTUAL_H_ + +#if KYTY_PLATFORM != KYTY_PLATFORM_WINDOWS +//#error "KYTY_PLATFORM != KYTY_PLATFORM_WINDOWS" +#else + +#include "Kyty/Core/Common.h" +#include "Kyty/Core/String.h" +#include "Kyty/Core/VirtualMemory.h" + +namespace Kyty::Core { + +void sys_get_system_info(SystemInfo* info); + +void sys_virtual_init(); + +uint64_t sys_virtual_alloc(uint64_t address, uint64_t size, VirtualMemory::Mode mode); +uint64_t sys_virtual_alloc_aligned(uint64_t address, uint64_t size, VirtualMemory::Mode mode, uint64_t alignment); +bool sys_virtual_alloc_fixed(uint64_t address, uint64_t size, VirtualMemory::Mode mode); +bool sys_virtual_free(uint64_t address); +bool sys_virtual_protect(uint64_t address, uint64_t size, VirtualMemory::Mode mode, VirtualMemory::Mode* old_mode = nullptr); +bool sys_virtual_flush_instruction_cache(uint64_t address, uint64_t size); +bool sys_virtual_patch_replace(uint64_t vaddr, uint64_t value); + +} // namespace Kyty::Core + +#endif + +#endif /* INCLUDE_KYTY_SYS_WINDOWS_SYSWINDOWSVIRTUAL_H_ */ diff --git a/source/launcher/CMakeLists.txt b/source/launcher/CMakeLists.txt index edede99..eb536ce 100644 --- a/source/launcher/CMakeLists.txt +++ b/source/launcher/CMakeLists.txt @@ -28,8 +28,10 @@ add_executable(launcher WIN32 target_link_libraries(launcher Qt5::Widgets) +if(MSVC OR MINGW) target_link_libraries(launcher psapi) target_link_libraries(launcher setupapi) +endif() if (CLANG AND NOT MSVC) target_link_libraries(launcher pthread) endif() @@ -45,9 +47,11 @@ endif() add_dependencies(launcher KytyGitVersion) -find_program(QT_WINDEPLOYQT NAMES windeployqt PATHS "${Qt5_DIR}/../../../bin") -if(NOT QT_WINDEPLOYQT) - message(FATAL_ERROR "Could not find windeployqt") +if(NOT LINUX) + find_program(QT_WINDEPLOYQT NAMES windeployqt PATHS "${Qt5_DIR}/../../../bin") + if(NOT QT_WINDEPLOYQT) + message(FATAL_ERROR "Could not find windeployqt") + endif() endif() set(launcher_name "launcher") @@ -56,17 +60,19 @@ set_target_properties(launcher PROPERTIES OUTPUT_NAME ${launcher_name}) install(TARGETS launcher DESTINATION .) -install(CODE " - execute_process( - COMMAND ${QT_WINDEPLOYQT} \"\${CMAKE_INSTALL_PREFIX}/${launcher_name}.exe\" +if(NOT LINUX) + install(CODE " + execute_process( + COMMAND ${QT_WINDEPLOYQT} \"\${CMAKE_INSTALL_PREFIX}/${launcher_name}.exe\" --no-svg --no-angle --no-opengl --no-opengl-sw --no-system-d3d-compiler - --no-translations - ) -") + --no-translations + ) + ") +endif() qt5_create_translation(QM_FILES ${launcher_src} ${launcher_forms} ${launcher_ts} OPTIONS -I ${CMAKE_SOURCE_DIR}/launcher/include) @@ -79,10 +85,13 @@ get_property(inc_headers TARGET launcher PROPERTY INCLUDE_DIRECTORIES) list(APPEND inc_headers ${CMAKE_SOURCE_DIR}/launcher ${CMAKE_BINARY_DIR}/launcher/launcher_autogen/include - ${Qt5_DIR}/../../../include - ${Qt5_DIR}/../../../include/QtWidgets - ${Qt5_DIR}/../../../include/QtCore - ${Qt5_DIR}/../../../include/QtGui + ${Qt5Widgets_INCLUDE_DIRS} + ${Qt5Core_INCLUDE_DIRS} + ${Qt5Gui_INCLUDE_DIRS} + #${Qt5_DIR}/../../../include + #${Qt5_DIR}/../../../include/QtWidgets + #${Qt5_DIR}/../../../include/QtCore + #${Qt5_DIR}/../../../include/QtGui ) include_what_you_use_with_mappings(launcher "${inc_headers}" "${iwyu_maps}") diff --git a/source/launcher/include/MainDialog.h b/source/launcher/include/MainDialog.h index 91b73da..8cdf01d 100644 --- a/source/launcher/include/MainDialog.h +++ b/source/launcher/include/MainDialog.h @@ -30,7 +30,7 @@ public: explicit MainDialog(QWidget* parent = nullptr); ~MainDialog() override = default; - void RunInterpreter(QProcess* process, Kyty::Configuration* info, bool con_emu); + void RunInterpreter(QProcess* process, Kyty::Configuration* info, [[maybe_unused]] bool con_emu); static void WriteSettings(QSettings* s); static void ReadSettings(QSettings* s); diff --git a/source/launcher/src/ConfigurationListWidget.cpp b/source/launcher/src/ConfigurationListWidget.cpp index ea5e18a..b467553 100644 --- a/source/launcher/src/ConfigurationListWidget.cpp +++ b/source/launcher/src/ConfigurationListWidget.cpp @@ -64,7 +64,11 @@ void ConfigurationListWidget::WriteSettings() s = new QSettings(CONF_FILE_NAME, QSettings::IniFormat); } else { +#ifdef __linux__ + s = new QSettings(QSettings::IniFormat, QSettings::UserScope, CONF_ORG_NAME, CONF_APP_NAME); +#else s = new QSettings(QSettings::IniFormat, QSettings::SystemScope, CONF_ORG_NAME, CONF_APP_NAME); +#endif } if (s != nullptr) @@ -95,7 +99,11 @@ void ConfigurationListWidget::ReadSettings() s = new QSettings(CONF_FILE_NAME, QSettings::IniFormat); } else { +#ifdef __linux__ + s = new QSettings(QSettings::IniFormat, QSettings::UserScope, CONF_ORG_NAME, CONF_APP_NAME); +#else s = new QSettings(QSettings::IniFormat, QSettings::SystemScope, CONF_ORG_NAME, CONF_APP_NAME); +#endif } if (s != nullptr) diff --git a/source/launcher/src/MainDialog.cpp b/source/launcher/src/MainDialog.cpp index 3993442..e307a05 100644 --- a/source/launcher/src/MainDialog.cpp +++ b/source/launcher/src/MainDialog.cpp @@ -27,7 +27,9 @@ #include "ui_main_dialog.h" +#ifndef __linux__ #include // IWYU pragma: keep +#endif // IWYU pragma: no_include // IWYU pragma: no_include @@ -35,24 +37,39 @@ class QWidget; -constexpr char SCRIPT_EXE[] = "fc_script.exe"; -constexpr char CMD_EXE[] = "cmd.exe"; -constexpr char CONEMU_EXE[] = "C:/Program Files/ConEmu/ConEmu64.exe"; +#ifdef __linux__ +constexpr char SCRIPT_EXE[] = "fc_script"; +#else +constexpr char SCRIPT_EXE[] = "fc_script.exe"; +#endif + +#ifndef __linux__ +constexpr char CMD_EXE[] = "cmd.exe"; +constexpr char CONEMU_EXE[] = "C:/Program Files/ConEmu/ConEmu64.exe"; +#else +constexpr char GNOME[] = "gnome-terminal"; +constexpr char XTERM[] = "xterm"; +constexpr char KYTY_BASH_FILE[] = "kyty_run.sh"; +#endif constexpr char KYTY_MOUNT[] = "kyty_mount"; constexpr char KYTY_EXECUTE[] = "kyty_execute"; constexpr char KYTY_LOAD_ELF[] = "kyty_load_elf"; // constexpr char KYTY_LOAD_SYMBOLS[] = "kyty_load_symbols"; -constexpr char KYTY_LOAD_SYMBOLS_ALL[] = "kyty_load_symbols_all"; -constexpr char KYTY_LOAD_PARAM_SFO[] = "kyty_load_param_sfo"; -constexpr char KYTY_INIT[] = "kyty_init"; -constexpr char KYTY_LUA_FILE[] = "kyty_run.lua"; -constexpr DWORD CMD_X_CHARS = 175; -constexpr DWORD CMD_Y_CHARS = 1000; -constexpr char SETTINGS_MAIN_DIALOG[] = "MainDialog"; -constexpr char SETTINGS_MAIN_LAST_GEOMETRY[] = "geometry"; +constexpr char KYTY_LOAD_SYMBOLS_ALL[] = "kyty_load_symbols_all"; +constexpr char KYTY_LOAD_PARAM_SFO[] = "kyty_load_param_sfo"; +constexpr char KYTY_INIT[] = "kyty_init"; +constexpr char KYTY_LUA_FILE[] = "kyty_run.lua"; +#ifndef __linux__ +constexpr DWORD CMD_X_CHARS = 175; +constexpr DWORD CMD_Y_CHARS = 1000; +#endif +constexpr char SETTINGS_MAIN_DIALOG[] = "MainDialog"; +constexpr char SETTINGS_MAIN_LAST_GEOMETRY[] = "geometry"; class DetachableProcess: public QProcess { + Q_OBJECT; + public: explicit DetachableProcess(QObject* parent = nullptr): QProcess(parent) {} void Detach() @@ -87,10 +104,12 @@ public: private: static QByteArray g_last_geometry; - Ui::MainDialog* m_ui = {nullptr}; - MainDialog* m_main_dialog = nullptr; - QString m_interpreter; - DetachableProcess m_process; + Ui::MainDialog* m_ui = {nullptr}; + MainDialog* m_main_dialog = nullptr; + QString m_interpreter; + + /*DetachableProcess*/ QProcess m_process; + ConfigurationItem* m_running_item = nullptr; }; @@ -135,7 +154,7 @@ void MainDialogPrivate::Setup(MainDialog* main_dialog) Update(); }); - connect(main_dialog, &MainDialog::Quit, [=]() { m_process.Detach(); }); + // connect(main_dialog, &MainDialog::Quit, [=]() { m_process.Detach(); }); m_ui->label_settings_file->setText(tr("Settings file: ") + m_ui->widget->GetSettingsFile()); @@ -196,14 +215,23 @@ void MainDialogPrivate::FindInterpreter() return; } +#ifndef __linux__ QFile console(CONEMU_EXE); bool con_emu = console.exists(); +#else + bool con_emu = true; +#endif m_ui->radioButton_Cmd->setEnabled(true); m_ui->radioButton_Cmd->setChecked(true); m_ui->radioButton_ConEmu->setEnabled(con_emu); m_ui->radioButton_ConEmu->setChecked(false); +#ifdef __linux__ + m_ui->radioButton_Cmd->setText(QCoreApplication::translate("MainDialog", "gnome-terminal", nullptr)); + m_ui->radioButton_ConEmu->setText(QCoreApplication::translate("MainDialog", "xterm", nullptr)); +#endif + Update(); } @@ -265,7 +293,28 @@ static bool CreateLuaScript(Kyty::Configuration* info, const QString& file_name) return false; } -void MainDialog::RunInterpreter(QProcess* process, Kyty::Configuration* info, bool con_emu) +#ifdef __linux__ +static bool CreateBashScript(const QString& interpreter, const QString& lua_file_name, const QString& file_name) +{ + QFile file(file_name); + if (file.open(QIODevice::WriteOnly | QIODevice::Text)) + { + QTextStream s(&file); + + s << "#!/bin/bash\n"; + s << interpreter << " " << lua_file_name << "\n"; + s << "echo Press any key...\n"; + s << "read -n1\n"; + + file.close(); + + return file.setPermissions(file.permissions() | QFile::ExeUser | QFile::ExeOwner | QFile::ExeGroup); + } + return false; +} +#endif + +void MainDialog::RunInterpreter(QProcess* process, Kyty::Configuration* info, [[maybe_unused]] bool con_emu) { const auto& interpreter = m_p->GetInterpreter(); @@ -273,7 +322,6 @@ void MainDialog::RunInterpreter(QProcess* process, Kyty::Configuration* info, bo auto dir = f.absoluteDir(); auto lua_file_name = dir.filePath(KYTY_LUA_FILE); - if (!CreateLuaScript(info, lua_file_name)) { QMessageBox::critical(this, tr("Error"), tr("Can't create file:\n") + lua_file_name); @@ -281,6 +329,25 @@ void MainDialog::RunInterpreter(QProcess* process, Kyty::Configuration* info, bo return; } +#ifdef __linux__ + auto bash_file_name = dir.filePath(KYTY_BASH_FILE); + if (!CreateBashScript(interpreter, lua_file_name, bash_file_name)) + { + QMessageBox::critical(this, tr("Error"), tr("Can't create file:\n") + bash_file_name); + QApplication::quit(); + return; + } + + if (con_emu) + { + process->setProgram(XTERM); + process->setArguments({"-e", "bash", "-c", bash_file_name}); + } else + { + process->setProgram(GNOME); + process->setArguments({"--", "bash", "-c", bash_file_name}); + } +#else if (con_emu) { process->setProgram(CONEMU_EXE); @@ -290,7 +357,9 @@ void MainDialog::RunInterpreter(QProcess* process, Kyty::Configuration* info, bo process->setProgram(CMD_EXE); process->setArguments({"/K", interpreter, lua_file_name}); } +#endif process->setWorkingDirectory(dir.path()); +#ifndef __linux__ process->setCreateProcessArgumentsModifier( [](QProcess::CreateProcessArguments* args) { @@ -303,6 +372,7 @@ void MainDialog::RunInterpreter(QProcess* process, Kyty::Configuration* info, bo // args->startupInfo->dwFillAttribute = // static_cast(BACKGROUND_BLUE) | static_cast(FOREGROUND_RED) | static_cast(FOREGROUND_INTENSITY); }); +#endif process->start(); process->waitForFinished(100); } diff --git a/source/launcher/ts/launcher_ru_RU.ts b/source/launcher/ts/launcher_ru_RU.ts index d72c156..fac8cbb 100644 --- a/source/launcher/ts/launcher_ru_RU.ts +++ b/source/launcher/ts/launcher_ru_RU.ts @@ -258,42 +258,42 @@ - + New configuration - + Edit configuration - + Delete configuration - + Do you want to delete configuration? - + Run - + New... - + Edit... - + Delete @@ -328,12 +328,24 @@ - + + gnome-terminal + + + + + xterm + + + + + Error - + + Can't create file: @@ -342,27 +354,27 @@ MainDialogPrivate - + Settings file: - + Emulator: - + Version: - + Error - + Can't find emulator diff --git a/source/lib/Core/src/Core.cpp b/source/lib/Core/src/Core.cpp index 19627da..4fae857 100644 --- a/source/lib/Core/src/Core.cpp +++ b/source/lib/Core/src/Core.cpp @@ -16,6 +16,7 @@ #include "Kyty/Core/SimpleArray.h" // IWYU pragma: associated #include "Kyty/Core/Singleton.h" // IWYU pragma: associated #include "Kyty/Core/Vector.h" // IWYU pragma: associated +#include "Kyty/Core/VirtualMemory.h" namespace Kyty::Core { @@ -25,8 +26,8 @@ KYTY_SUBSYSTEM_INIT(Core) core_file_init(); core_debug_init(parent->GetArgv()[0]); Language::Init(); - Database::Init(); + VirtualMemory::Init(); } KYTY_SUBSYSTEM_UNEXPECTED_SHUTDOWN(Core) {} diff --git a/source/lib/Core/src/DbgAssert.cpp b/source/lib/Core/src/DbgAssert.cpp index bb0f4fd..5af90d1 100644 --- a/source/lib/Core/src/DbgAssert.cpp +++ b/source/lib/Core/src/DbgAssert.cpp @@ -19,6 +19,36 @@ constexpr int PRINT_STACK_FROM = 4; constexpr int PRINT_STACK_FROM = 2; #endif +#if KYTY_PLATFORM == KYTY_PLATFORM_LINUX +int IsDebuggerPresent() +{ + bool dbg = false; + FILE* f = fopen("/proc/self/status", "r"); + + if (f != nullptr) + { + char str[1024]; + + while (feof(f) == 0) + { + str[1023] = '\0'; + int pid = 0; + + [[maybe_unused]] auto* result = fgets(str, 1023, f); + if (sscanf(str, "TracerPid: %d", &pid) == 1) // NOLINT + { + dbg = (pid != 0); + break; + } + } + + [[maybe_unused]] auto result = fclose(f); + } + + return (dbg ? 1 : 0); +} +#endif + void dbg_print_stack() { DebugStack s; @@ -80,7 +110,7 @@ void dbg_exit(int status) bool dbg_is_debugger_present() { -#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS +#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS || KYTY_PLATFORM == KYTY_PLATFORM_LINUX return !(IsDebuggerPresent() == 0); #endif return false; diff --git a/source/lib/Core/src/MemoryAlloc.cpp b/source/lib/Core/src/MemoryAlloc.cpp index d5259db..7c47f2c 100644 --- a/source/lib/Core/src/MemoryAlloc.cpp +++ b/source/lib/Core/src/MemoryAlloc.cpp @@ -210,7 +210,11 @@ void* mem_alloc(size_t size) { if (size == 0) { +#if KYTY_PLATFORM == KYTY_PLATFORM_LINUX + size = 1; +#else EXIT("size == 0\n"); +#endif } if ((g_mem_max_size != 0u) && size > g_mem_max_size) diff --git a/source/lib/Core/src/SDLSubsystem.cpp b/source/lib/Core/src/SDLSubsystem.cpp index 951d330..19ae07a 100644 --- a/source/lib/Core/src/SDLSubsystem.cpp +++ b/source/lib/Core/src/SDLSubsystem.cpp @@ -9,6 +9,7 @@ // IWYU pragma: no_include "SDL_error.h" // IWYU pragma: no_include "SDL_platform.h" // IWYU pragma: no_include "SDL_stdinc.h" +// IWYU pragma: no_include "begin_code.h" #include "SDL.h" diff --git a/source/lib/Core/src/Threads.cpp b/source/lib/Core/src/Threads.cpp index 811d9a5..b7c29a6 100644 --- a/source/lib/Core/src/Threads.cpp +++ b/source/lib/Core/src/Threads.cpp @@ -8,20 +8,39 @@ #include "Kyty/Core/Vector.h" #include -#include +#include // IWYU pragma: keep #include // IWYU pragma: keep #include -#include -#include -#include #if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS && KYTY_COMPILER == KYTY_COMPILER_CLANG #define KYTY_WIN_CS #endif +#if KYTY_PLATFORM != KYTY_PLATFORM_WINDOWS && KYTY_PLATFORM != KYTY_PLATFORM_LINUX +#define KYTY_SDL_THREADS +#define KYTY_SDL_CS +#endif + //#define KYTY_DEBUG_LOCKS //#define KYTY_DEBUG_LOCKS_TIMED +#ifdef KYTY_SDL_THREADS +#include "SDL_thread.h" +#include "SDL_timer.h" +#else +#include +#include +#include +#endif + +#ifdef KYTY_SDL_CS +#include "SDL_mutex.h" +#endif + +#if defined(KYTY_WIN_CS) && defined(KYTY_SDL_CS) +#error "defined(KYTY_WIN_CS) && defined(KYTY_SDL_CS)" +#endif + #if !(defined(KYTY_DEBUG_LOCKS) || defined(KYTY_DEBUG_LOCKS_TIMED)) && defined(KYTY_WIN_CS) #include // IWYU pragma: keep // IWYU pragma: no_include @@ -30,6 +49,10 @@ constexpr DWORD KYTY_CS_SPIN_COUNT = 4000; // IWYU pragma: no_include // IWYU pragma: no_include // IWYU pragma: no_include +// IWYU pragma: no_include <__mutex_base> +// IWYU pragma: no_include <__threading_support> +// IWYU pragma: no_include +// IWYU pragma: no_include using InitializeConditionVariable_func_t = /*WINBASEAPI*/ VOID WINAPI (*)(PCONDITION_VARIABLE); using WakeConditionVariable_func_t = /*WINBASEAPI*/ VOID WINAPI (*)(PCONDITION_VARIABLE); @@ -38,7 +61,7 @@ using SleepConditionVariableCS_func_t = /*WINBASEAPI*/ BOOL WINAPI (*)(PCO static InitializeConditionVariable_func_t ResolveInitializeConditionVariable() { - if (HMODULE h = GetModuleHandle("KernelBase"); h != nullptr) + if (HMODULE h = GetModuleHandle("KernelBase"); h != nullptr) // @suppress("Invalid arguments") { return reinterpret_cast(GetProcAddress(h, "InitializeConditionVariable")); } @@ -46,7 +69,7 @@ static InitializeConditionVariable_func_t ResolveInitializeConditionVariable() } static WakeConditionVariable_func_t ResolveWakeConditionVariable() { - if (HMODULE h = GetModuleHandle("KernelBase"); h != nullptr) + if (HMODULE h = GetModuleHandle("KernelBase"); h != nullptr) // @suppress("Invalid arguments") { return reinterpret_cast(GetProcAddress(h, "WakeConditionVariable")); } @@ -54,7 +77,7 @@ static WakeConditionVariable_func_t ResolveWakeConditionVariable() } static WakeAllConditionVariable_func_t ResolveWakeAllConditionVariable() { - if (HMODULE h = GetModuleHandle("KernelBase"); h != nullptr) + if (HMODULE h = GetModuleHandle("KernelBase"); h != nullptr) // @suppress("Invalid arguments") { return reinterpret_cast(GetProcAddress(h, "WakeAllConditionVariable")); } @@ -62,7 +85,7 @@ static WakeAllConditionVariable_func_t ResolveWakeAllConditionVariable() } static SleepConditionVariableCS_func_t ResolveSleepConditionVariableCS() { - if (HMODULE h = GetModuleHandle("KernelBase"); h != nullptr) + if (HMODULE h = GetModuleHandle("KernelBase"); h != nullptr) // @suppress("Invalid arguments") { return reinterpret_cast(GetProcAddress(h, "SleepConditionVariableCS")); } @@ -73,7 +96,11 @@ static SleepConditionVariableCS_func_t ResolveSleepConditionVariableCS() namespace Kyty::Core { +#ifdef KYTY_SDL_THREADS +using thread_id_t = uint64_t; +#else using thread_id_t = std::thread::id; +#endif #if defined(KYTY_DEBUG_LOCKS) || defined(KYTY_DEBUG_LOCKS_TIMED) constexpr auto DBG_TRY_SECONDS = std::chrono::seconds(15); @@ -94,7 +121,15 @@ struct MutexPrivate DeleteCriticalSection(&m_cs); } KYTY_CLASS_NO_COPY(MutexPrivate); - CRITICAL_SECTION m_cs {}; + CRITICAL_SECTION m_cs {}; +#elif defined(KYTY_SDL_CS) + MutexPrivate(): sdl(SDL_CreateMutex()) {} + ~MutexPrivate() + { + SDL_DestroyMutex(sdl); + } + KYTY_CLASS_NO_COPY(MutexPrivate); + SDL_mutex* sdl; #else std::recursive_mutex m_mutex; #endif @@ -113,6 +148,14 @@ struct CondVarPrivate ~CondVarPrivate() = default; KYTY_CLASS_NO_COPY(CondVarPrivate); CONDITION_VARIABLE m_cv {}; +#elif !(defined(KYTY_DEBUG_LOCKS) || defined(KYTY_DEBUG_LOCKS_TIMED)) && defined(KYTY_SDL_CS) + CondVarPrivate(): sdl(SDL_CreateCond()) {} + ~CondVarPrivate() + { + SDL_DestroyCond(sdl); + } + KYTY_CLASS_NO_COPY(CondVarPrivate); + SDL_cond* sdl; #else std::condition_variable_any m_cv; #endif @@ -173,7 +216,17 @@ static std::atomic g_wait_for_graph = nullptr; struct ThreadPrivate { - ThreadPrivate(thread_func_t f, void* a): func(f), arg(a), m_thread(&Run, this) {} + ThreadPrivate(thread_func_t f, void* a) + : func(f), arg(a), +#ifdef KYTY_SDL_THREADS + sdl(SDL_CreateThread(SdlThreadRun, "sdl_thread", this)) + { + } +#else + m_thread(&Run, this) + { + } +#endif static void Run(ThreadPrivate* t) { @@ -191,13 +244,23 @@ struct ThreadPrivate } } + static int SdlThreadRun(void* data) + { + Run(static_cast(data)); + return 0; + } + thread_func_t func; void* arg; std::atomic_bool finished = false; std::atomic_bool auto_delete = false; std::atomic_bool started = false; int unique_id = 0; - std::thread m_thread; +#ifdef KYTY_SDL_THREADS + SDL_Thread* sdl; +#else + std::thread m_thread; +#endif }; static thread_id_t g_main_thread; @@ -206,7 +269,11 @@ static std::atomic g_thread_counter = 0; KYTY_SUBSYSTEM_INIT(Threads) { - g_main_thread = std::this_thread::get_id(); +#ifdef KYTY_SDL_THREADS + g_main_thread = SDL_ThreadID(); +#else + g_main_thread = std::this_thread::get_id(); +#endif g_main_thread_int = Thread::GetThreadIdUnique(); g_wait_for_graph = new WaitForGraph; } @@ -468,7 +535,13 @@ void Thread::Join() { EXIT_IF(m_thread->finished || m_thread->auto_delete); +#ifdef KYTY_SDL_THREADS + int status = -1; + SDL_WaitThread(m_thread->sdl, &status); + EXIT_IF(status != 0); +#else m_thread->m_thread.join(); +#endif m_thread->finished = true; } @@ -478,34 +551,58 @@ void Thread::Detach() EXIT_IF(m_thread->finished || m_thread->auto_delete); m_thread->auto_delete = true; +#ifdef KYTY_SDL_THREADS + SDL_DetachThread(m_thread->sdl); +#else m_thread->m_thread.detach(); +#endif } void Thread::Sleep(uint32_t millis) { +#ifdef KYTY_SDL_THREADS + SDL_Delay(millis); +#else std::this_thread::sleep_for(std::chrono::milliseconds(millis)); +#endif } void Thread::SleepMicro(uint32_t micros) { +#ifdef KYTY_SDL_THREADS + SDL_Delay(micros < 1000 && micros != 0 ? 1 : micros / 1000); +#else std::this_thread::sleep_for(std::chrono::microseconds(micros)); +#endif } void Thread::SleepNano(uint64_t nanos) { +#ifdef KYTY_SDL_THREADS + SDL_Delay(nanos < 1000000 && nanos != 0 ? 1 : nanos / 1000000); +#else std::this_thread::sleep_for(std::chrono::nanoseconds(nanos)); +#endif } bool Thread::IsMainThread() { +#ifdef KYTY_SDL_THREADS + return g_main_thread == static_cast(SDL_ThreadID()); +#else return g_main_thread == std::this_thread::get_id(); +#endif } String Thread::GetId() const { +#ifdef KYTY_SDL_THREADS + return String::FromPrintf("%" PRIu64, static_cast(SDL_GetThreadID(m_thread->sdl))); +#else std::stringstream ss; ss << m_thread->m_thread.get_id(); return String::FromUtf8(ss.str().c_str()); +#endif } int Thread::GetUniqueId() const @@ -515,9 +612,13 @@ int Thread::GetUniqueId() const String Thread::GetThreadId() { +#ifdef KYTY_SDL_THREADS + return String::FromPrintf("%" PRIu64, static_cast(SDL_ThreadID())); +#else std::stringstream ss; ss << std::this_thread::get_id(); return String::FromUtf8(ss.str().c_str()); +#endif } Mutex::Mutex(): m_mutex(new MutexPrivate) {} @@ -560,7 +661,7 @@ void Mutex::Lock() } #else #ifdef KYTY_DEBUG_LOCKS_TIMED - bool locked = false; + bool locked = false; do { locked = m_mutex->m_mutex.try_lock_for(DBG_TRY_SECONDS); @@ -573,6 +674,8 @@ void Mutex::Lock() #else #ifdef KYTY_WIN_CS EnterCriticalSection(&m_mutex->m_cs); +#elif defined(KYTY_SDL_CS) + SDL_LockMutex(m_mutex->sdl); #else m_mutex->m_mutex.lock(); #endif @@ -591,6 +694,8 @@ void Mutex::Unlock() #else #if !defined(KYTY_DEBUG_LOCKS_TIMED) && defined(KYTY_WIN_CS) LeaveCriticalSection(&m_mutex->m_cs); +#elif !defined(KYTY_DEBUG_LOCKS_TIMED) && defined(KYTY_SDL_CS) + SDL_UnlockMutex(m_mutex->sdl); #else m_mutex->m_mutex.unlock(); #endif @@ -612,6 +717,8 @@ bool Mutex::TryLock() #else #if !defined(KYTY_DEBUG_LOCKS_TIMED) && defined(KYTY_WIN_CS) return (TryEnterCriticalSection(&m_mutex->m_cs) != 0); +#elif !defined(KYTY_DEBUG_LOCKS_TIMED) && defined(KYTY_SDL_CS) + return (SDL_TryLockMutex(m_mutex->sdl) == 0); #else return m_mutex->m_mutex.try_lock(); #endif @@ -630,7 +737,7 @@ void CondVar::Wait(Mutex* mutex) #if defined(KYTY_DEBUG_LOCKS) || defined(KYTY_DEBUG_LOCKS_TIMED) std::unique_lock cpp_lock(mutex->m_mutex->m_mutex, std::adopt_lock_t()); #else -#ifdef KYTY_WIN_CS +#if defined(KYTY_WIN_CS) || defined(KYTY_SDL_CS) #else std::unique_lock cpp_lock(mutex->m_mutex->m_mutex, std::adopt_lock_t()); #endif @@ -652,22 +759,25 @@ void CondVar::Wait(Mutex* mutex) static auto func = ResolveSleepConditionVariableCS(); EXIT_NOT_IMPLEMENTED(func == nullptr); func(&m_cond_var->m_cv, &mutex->m_mutex->m_cs, INFINITE); +#elif !defined(KYTY_DEBUG_LOCKS_TIMED) && defined(KYTY_SDL_CS) + SDL_CondWait(m_cond_var->sdl, mutex->m_mutex->sdl); #else m_cond_var->m_cv.wait(cpp_lock); #endif #endif -#if !(defined(KYTY_DEBUG_LOCKS) || defined(KYTY_DEBUG_LOCKS_TIMED)) && defined(KYTY_WIN_CS) +#if !(defined(KYTY_DEBUG_LOCKS) || defined(KYTY_DEBUG_LOCKS_TIMED)) && (defined(KYTY_WIN_CS) || defined(KYTY_SDL_CS)) #else cpp_lock.release(); #endif } -void CondVar::WaitFor(Mutex* mutex, uint32_t micros) +bool CondVar::WaitFor(Mutex* mutex, uint32_t micros) { + bool ok = false; #if defined(KYTY_DEBUG_LOCKS) || defined(KYTY_DEBUG_LOCKS_TIMED) std::unique_lock cpp_lock(mutex->m_mutex->m_mutex, std::adopt_lock_t()); #else -#ifdef KYTY_WIN_CS +#if defined(KYTY_WIN_CS) || defined(KYTY_SDL_CS) #else std::unique_lock cpp_lock(mutex->m_mutex->m_mutex, std::adopt_lock_t()); #endif @@ -675,11 +785,14 @@ void CondVar::WaitFor(Mutex* mutex, uint32_t micros) #if !(defined(KYTY_DEBUG_LOCKS) || defined(KYTY_DEBUG_LOCKS_TIMED)) && defined(KYTY_WIN_CS) static auto func = ResolveSleepConditionVariableCS(); EXIT_NOT_IMPLEMENTED(func == nullptr); - func(&m_cond_var->m_cv, &mutex->m_mutex->m_cs, (micros < 1000 ? 1 : micros / 1000)); + ok = !(func(&m_cond_var->m_cv, &mutex->m_mutex->m_cs, (micros < 1000 ? 1 : micros / 1000)) == 0 && GetLastError() == ERROR_TIMEOUT); +#elif !(defined(KYTY_DEBUG_LOCKS) || defined(KYTY_DEBUG_LOCKS_TIMED)) && defined(KYTY_SDL_CS) + ok = !(SDL_CondWaitTimeout(m_cond_var->sdl, mutex->m_mutex->sdl, (micros < 1000 ? 1 : micros / 1000)) == SDL_MUTEX_TIMEDOUT); #else - m_cond_var->m_cv.wait_for(cpp_lock, std::chrono::microseconds(micros)); + ok = (m_cond_var->m_cv.wait_for(cpp_lock, std::chrono::microseconds(micros)) == std::cv_status::no_timeout); cpp_lock.release(); #endif + return ok; } void CondVar::Signal() @@ -688,6 +801,8 @@ void CondVar::Signal() static auto func = ResolveWakeConditionVariable(); EXIT_NOT_IMPLEMENTED(func == nullptr); func(&m_cond_var->m_cv); +#elif !(defined(KYTY_DEBUG_LOCKS) || defined(KYTY_DEBUG_LOCKS_TIMED)) && defined(KYTY_SDL_CS) + SDL_CondSignal(m_cond_var->sdl); #else m_cond_var->m_cv.notify_one(); #endif @@ -699,6 +814,8 @@ void CondVar::SignalAll() static auto func = ResolveWakeAllConditionVariable(); EXIT_NOT_IMPLEMENTED(func == nullptr); func(&m_cond_var->m_cv); +#elif !(defined(KYTY_DEBUG_LOCKS) || defined(KYTY_DEBUG_LOCKS_TIMED)) && defined(KYTY_SDL_CS) + SDL_CondBroadcast(m_cond_var->sdl); #else m_cond_var->m_cv.notify_all(); #endif diff --git a/source/lib/Core/src/VirtualMemory.cpp b/source/lib/Core/src/VirtualMemory.cpp new file mode 100644 index 0000000..eb61605 --- /dev/null +++ b/source/lib/Core/src/VirtualMemory.cpp @@ -0,0 +1,324 @@ +#include "Kyty/Core/VirtualMemory.h" + +#include "Kyty/Sys/SysVirtual.h" + +#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS +#define KYTY_HAS_EXCEPTIONS +#endif + +#ifdef KYTY_HAS_EXCEPTIONS +#include // IWYU pragma: keep +#endif + +// IWYU pragma: no_include +// IWYU pragma: no_include +// IWYU pragma: no_include +// IWYU pragma: no_include +// IWYU pragma: no_include +// IWYU pragma: no_include + +namespace Kyty::Core { + +SystemInfo GetSystemInfo() +{ + SystemInfo ret {}; + + sys_get_system_info(&ret); + + return ret; +} + +namespace VirtualMemory { + +#ifdef KYTY_HAS_EXCEPTIONS + +struct JmpRax +{ + template + void SetFunc(Handler func) + { + *reinterpret_cast(&code[2]) = func; + } + + // mov rax, 0x1122334455667788 + // jmp rax + uint8_t code[16] = {0x48, 0xB8, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0xFF, 0xE0}; +}; + +class ExceptionHandlerPrivate +{ +public: +#pragma pack(1) + + struct UnwindInfo + { + uint8_t Version : 3; + uint8_t Flags : 5; + uint8_t SizeOfProlog; + uint8_t CountOfCodes; + uint8_t FrameRegister : 4; + uint8_t FrameOffset : 4; + ULONG ExceptionHandler; + + ExceptionHandlerPrivate* ExceptionData; + }; + + struct HandlerInfo + { + JmpRax code; + RUNTIME_FUNCTION function_table = {}; + UnwindInfo unwind_info = {}; + }; + +#pragma pack() + + static EXCEPTION_DISPOSITION Handler(PEXCEPTION_RECORD exception_record, ULONG64 /*EstablisherFrame*/, PCONTEXT /*ContextRecord*/, + PDISPATCHER_CONTEXT dispatcher_context) + { + ExceptionHandler::ExceptionInfo info {}; + + info.exception_address = reinterpret_cast(exception_record->ExceptionAddress); + + if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) + { + info.type = ExceptionHandler::ExceptionType::AccessViolation; + switch (exception_record->ExceptionInformation[0]) + { + case 0: info.access_violation_type = ExceptionHandler::AccessViolationType::Read; break; + case 1: info.access_violation_type = ExceptionHandler::AccessViolationType::Write; break; + case 8: info.access_violation_type = ExceptionHandler::AccessViolationType::Execute; break; + default: info.access_violation_type = ExceptionHandler::AccessViolationType::Unknown; break; + } + info.access_violation_vaddr = exception_record->ExceptionInformation[1]; + } + + info.rbp = dispatcher_context->ContextRecord->Rbp; + info.exception_win_code = exception_record->ExceptionCode; + + auto* p = *static_cast(dispatcher_context->HandlerData); + p->func(&info); + + return ExceptionContinueExecution; + } + + void InitHandler() + { + auto* h = new (reinterpret_cast(handler_addr)) HandlerInfo; + auto* code = &h->code; + auto* unwind_info = &h->unwind_info; + + function_table = &h->function_table; + + function_table->BeginAddress = 0; + function_table->EndAddress = image_size; + function_table->UnwindData = reinterpret_cast(unwind_info) - base_address; + + unwind_info->Version = 1; + unwind_info->Flags = UNW_FLAG_EHANDLER; + unwind_info->SizeOfProlog = 0; + unwind_info->CountOfCodes = 0; + unwind_info->FrameRegister = 0; + unwind_info->FrameOffset = 0; + unwind_info->ExceptionHandler = reinterpret_cast(code) - base_address; + unwind_info->ExceptionData = this; + + code->SetFunc(Handler); + + FlushInstructionCache(reinterpret_cast(code), sizeof(h->code)); + } + + uint64_t base_address = 0; + uint64_t handler_addr = 0; + uint64_t image_size = 0; + PRUNTIME_FUNCTION function_table = nullptr; + + ExceptionHandler::handler_func_t func = nullptr; + + static ExceptionHandler::handler_func_t g_vec_func; +}; + +ExceptionHandler::handler_func_t ExceptionHandlerPrivate::g_vec_func = nullptr; + +#else +class ExceptionHandlerPrivate +{ +}; +#endif + +ExceptionHandler::ExceptionHandler(): m_p(new ExceptionHandlerPrivate) {} + +ExceptionHandler::~ExceptionHandler() +{ +#ifdef KYTY_HAS_EXCEPTIONS + Uninstall(); +#endif + delete m_p; +} + +uint64_t ExceptionHandler::GetSize() +{ +#ifdef KYTY_HAS_EXCEPTIONS + return (sizeof(ExceptionHandlerPrivate::HandlerInfo) & ~(static_cast(0x1000) - 1)) + 0x1000; +#else + return 0x1000; +#endif +} + +// NOLINTNEXTLINE(readability-convert-member-functions-to-static, misc-unused-parameters) +bool ExceptionHandler::Install(uint64_t base_address, uint64_t handler_addr, uint64_t image_size, handler_func_t func) +{ +#ifdef KYTY_HAS_EXCEPTIONS + if (m_p->function_table == nullptr) + { + m_p->base_address = base_address; + m_p->handler_addr = handler_addr; + m_p->image_size = image_size; + m_p->func = func; + + m_p->InitHandler(); + + if (RtlAddFunctionTable(m_p->function_table, 1, base_address) == FALSE) + { + printf("RtlAddFunctionTable() failed: 0x%08" PRIx32 "\n", static_cast(GetLastError())); + return false; + } + + return true; + } + + return false; +#else + return true; +#endif +} + +#ifdef KYTY_HAS_EXCEPTIONS +static LONG WINAPI ExceptionFilter(PEXCEPTION_POINTERS exception) +{ + PEXCEPTION_RECORD exception_record = exception->ExceptionRecord; + + ExceptionHandler::ExceptionInfo info {}; + + info.exception_address = reinterpret_cast(exception_record->ExceptionAddress); + + // printf("exception_record->ExceptionCode = %u\n", static_cast(exception_record->ExceptionCode)); + + if (exception_record->ExceptionCode == DBG_PRINTEXCEPTION_C || exception_record->ExceptionCode == DBG_PRINTEXCEPTION_WIDE_C) + { + return EXCEPTION_CONTINUE_EXECUTION; + } + + if (exception_record->ExceptionCode == 0x406D1388) + { + // Set a thread name + return EXCEPTION_CONTINUE_EXECUTION; + } + + if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) + { + info.type = ExceptionHandler::ExceptionType::AccessViolation; + switch (exception_record->ExceptionInformation[0]) + { + case 0: info.access_violation_type = ExceptionHandler::AccessViolationType::Read; break; + case 1: info.access_violation_type = ExceptionHandler::AccessViolationType::Write; break; + case 8: info.access_violation_type = ExceptionHandler::AccessViolationType::Execute; break; + default: info.access_violation_type = ExceptionHandler::AccessViolationType::Unknown; break; + } + info.access_violation_vaddr = exception_record->ExceptionInformation[1]; + } + + info.rbp = exception->ContextRecord->Rbp; + info.exception_win_code = exception_record->ExceptionCode; + + ExceptionHandlerPrivate::g_vec_func(&info); + + return EXCEPTION_CONTINUE_EXECUTION; +} +#endif + +// NOLINTNEXTLINE(readability-convert-member-functions-to-static, misc-unused-parameters) +bool ExceptionHandler::InstallVectored(handler_func_t func) +{ +#ifdef KYTY_HAS_EXCEPTIONS + if (ExceptionHandlerPrivate::g_vec_func == nullptr) + { + ExceptionHandlerPrivate::g_vec_func = func; + + if (AddVectoredExceptionHandler(1, ExceptionFilter) == nullptr) + { + printf("AddVectoredExceptionHandler() failed\n"); + return false; + } + + return true; + } + return false; +#else + return true; +#endif +} + +// NOLINTNEXTLINE(readability-convert-member-functions-to-static, misc-unused-parameters) +bool ExceptionHandler::Uninstall() +{ +#ifdef KYTY_HAS_EXCEPTIONS + if (m_p->function_table != nullptr) + { + if (RtlDeleteFunctionTable(m_p->function_table) == FALSE) + { + printf("RtlDeleteFunctionTable() failed: 0x%08" PRIx32 "\n", static_cast(GetLastError())); + return false; + } + m_p->function_table = nullptr; + return true; + } + + return false; +#else + return true; +#endif +} + +void Init() +{ + sys_virtual_init(); +} + +uint64_t Alloc(uint64_t address, uint64_t size, Mode mode) +{ + return sys_virtual_alloc(address, size, mode); +} + +uint64_t AllocAligned(uint64_t address, uint64_t size, Mode mode, uint64_t alignment) +{ + return sys_virtual_alloc_aligned(address, size, mode, alignment); +} + +bool AllocFixed(uint64_t address, uint64_t size, Mode mode) +{ + return sys_virtual_alloc_fixed(address, size, mode); +} + +bool Free(uint64_t address) +{ + return sys_virtual_free(address); +} + +bool Protect(uint64_t address, uint64_t size, Mode mode, Mode* old_mode) +{ + return sys_virtual_protect(address, size, mode, old_mode); +} + +bool FlushInstructionCache(uint64_t address, uint64_t size) +{ + return sys_virtual_flush_instruction_cache(address, size); +} + +bool PatchReplace(uint64_t vaddr, uint64_t value) +{ + return sys_virtual_patch_replace(vaddr, value); +} + +} // namespace VirtualMemory + +} // namespace Kyty::Core diff --git a/source/lib/Sys/CMakeLists.txt b/source/lib/Sys/CMakeLists.txt index a2e5cd8..47f19d1 100644 --- a/source/lib/Sys/CMakeLists.txt +++ b/source/lib/Sys/CMakeLists.txt @@ -2,22 +2,25 @@ file(GLOB sys_src "src/*.cpp" ) -add_library(sys_obj OBJECT ${sys_src}) -add_library(sys STATIC $) +add_library(sys STATIC ${sys_src}) -target_link_libraries(sys core) +target_link_libraries(sys core cpuinfo) get_property(inc_headers TARGET sys PROPERTY INCLUDE_DIRECTORIES) -target_include_directories(sys_obj PRIVATE ${inc_headers}) - list(APPEND check_headers ${CMAKE_SOURCE_DIR}/include ) -clang_tidy_check(sys_obj "" "${check_headers}" "${inc_headers}") +list(APPEND inc_headers + ${CMAKE_SOURCE_DIR}/3rdparty/sdl2/sdl2/include + ${CMAKE_SOURCE_DIR}/3rdparty/cpuinfo/include +) -include_what_you_use(sys_obj "${inc_headers}") +clang_tidy_check(sys "" "${check_headers}" "${inc_headers}") +#clang_tidy_fix(sys_obj "{Checks: '-*,cppcoreguidelines-init-variables'}" "${check_headers}" "${inc_headers}") + +include_what_you_use(sys "${inc_headers}") diff --git a/source/lib/Sys/src/SysLinuxDbg.cpp b/source/lib/Sys/src/SysLinuxDbg.cpp index 9637a81..cd2788c 100644 --- a/source/lib/Sys/src/SysLinuxDbg.cpp +++ b/source/lib/Sys/src/SysLinuxDbg.cpp @@ -4,4 +4,149 @@ //#error "KYTY_PLATFORM != KYTY_PLATFORM_LINUX" #else +#include "Kyty/Sys/SysDbg.h" + +#include +#include +#include +#include +#include + +namespace Kyty { + +static thread_local sys_dbg_stack_info_t g_stack = {0}; + +void sys_stack_walk(void** /*stack*/, int* depth) +{ + *depth = 0; +} + +void sys_stack_usage_print(sys_dbg_stack_info_t& stack) +{ + printf("stack: (0x%" PRIx64 ", %" PRIu64 ")\n", static_cast(stack.commited_addr), static_cast(stack.commited_size)); + printf("code: (0x%" PRIx64 ", %" PRIu64 ")\n", static_cast(stack.code_addr), static_cast(stack.code_size)); +} + +void sys_stack_usage(sys_dbg_stack_info_t& s) +{ + pid_t pid = getpid(); + + // printf("pid = %"I64"d\n", (int64_t)pid); + + [[maybe_unused]] int result = 0; + + char str[1024]; + char str2[1024]; + result = sprintf(str, "/proc/%d/exe", static_cast(pid)); + + ssize_t buff_len = 0; + if ((buff_len = readlink(str, str2, 1023)) == -1) + { + return; + } + str2[buff_len] = '\0'; + const char* name = basename(str2); + + result = sprintf(str, "/proc/%d/maps", static_cast(pid)); + + memset(&s, 0, sizeof(sys_dbg_stack_info_t)); + + FILE* f = fopen(str, "r"); + + if (f == nullptr) + { + return; + } + + // printf("&str = %"I64"x\n", (uint64_t)&str); + + uint64_t addr = 0; + uint64_t endaddr = 0; + [[maybe_unused]] uint64_t size = 0; + uint64_t offset = 0; + uint64_t inode = 0; + char permissions[8] = {}; + char device[8] = {}; + char filename[MAXPATHLEN] = {}; + + auto check_addr = reinterpret_cast(&f); + + while (true) + { + if (feof(f) != 0) + { + break; + } + + if (fgets(str, sizeof(str), f) == nullptr) + { + break; + } + + filename[0] = 0; + permissions[0] = 0; + addr = 0; + size = 0; + + // printf("%s", str); + + // NOLINTNEXTLINE(cert-err34-c) + result = sscanf(str, "%" SCNx64 "-%" SCNx64 " %s %" SCNx64 " %s %" SCNx64 " %s", &addr, &endaddr, permissions, &offset, device, + &inode, filename); + + size = endaddr - addr; + + bool read = (strchr(permissions, 'r') != nullptr); + bool write = (strchr(permissions, 'w') != nullptr); + bool exec = (strchr(permissions, 'x') != nullptr); + + // printf("%016"I64"x, %"I64"d, %s, %d, %d\n", addr, size, filename, read, write); + + if (read && write && !exec && strncmp(filename, "[stack", 6) == 0) + { + // printf("stack: %016"I64"x, %"I64"d\n", addr, size); + + if (check_addr >= addr && check_addr < addr + size) + { + s.addr = addr; + s.total_size = size; + s.commited_addr = addr; + s.commited_size = size; + + if (s.code_addr != 0) + { + break; + } + } + } + + if (read && !write && exec && strstr(filename, name) != nullptr) + { + s.code_addr = addr; + s.code_size = size; + + if (s.addr != 0) + { + break; + } + } + } + + result = fclose(f); +} + +void sys_get_code_info(uintptr_t* addr, size_t* size) +{ + if (g_stack.code_size == 0) + { + sys_stack_usage(g_stack); + } + + *addr = g_stack.code_addr; + *size = g_stack.code_size; +} + +void sys_set_exception_filter(exception_filter_func_t /*func*/) {} + +} // namespace Kyty #endif diff --git a/source/lib/Sys/src/SysLinuxFileIO.cpp b/source/lib/Sys/src/SysLinuxFileIO.cpp index 9637a81..ab8ba1a 100644 --- a/source/lib/Sys/src/SysLinuxFileIO.cpp +++ b/source/lib/Sys/src/SysLinuxFileIO.cpp @@ -4,4 +4,669 @@ //#error "KYTY_PLATFORM != KYTY_PLATFORM_LINUX" #else +#include "Kyty/Core/DbgAssert.h" +#include "Kyty/Core/MemoryAlloc.h" +#include "Kyty/Core/String.h" +#include "Kyty/Sys/SysFileIO.h" +#include "Kyty/Sys/SysTimer.h" + +#include "SDL_system.h" + +#include +#include +#include +#include + +namespace Kyty { + +template +class Vector; + +static String* g_internal_files_dir = nullptr; + +static String get_internal_name(const String& name) +{ + return name.StartsWith(U"/") ? name : *g_internal_files_dir + U"/" + name; +} + +bool sys_file_io_init() +{ + g_internal_files_dir = new String(); + + *g_internal_files_dir = U"."; + + return !g_internal_files_dir->IsEmpty(); +} + +void sys_file_read(void* data, uint32_t size, sys_file_t& f, uint32_t* bytes_read) +{ + if (f.type == SYS_FILE_FILE) + { + size_t w = fread(data, 1, size, f.f); + if (bytes_read != nullptr) + { + *bytes_read = w; + } + } else if (f.type == SYS_FILE_MEMORY_STAT) + { + uint32_t s = size; + if (f.buf->size != 0) + { + uint32_t l = f.buf->size - (f.buf->ptr - f.buf->base); + if (s > l) + { + s = l; + } + } + memcpy(data, f.buf->ptr, s); + f.buf->ptr += s; + if (bytes_read != nullptr) + { + *bytes_read = s; + } + } else if (f.type == SYS_FILE_MEMORY_DYN) + { + uint32_t s = size; + if (f.buf->size != 0) + { + uint32_t l = f.buf->size - (f.buf->ptr - f.buf->base); + if (s > l) + { + s = l; + } + } else + { + s = 0; + } + memcpy(data, f.buf->ptr, s); + f.buf->ptr += s; + if (bytes_read != nullptr) + { + *bytes_read = s; + } + } +} + +void sys_file_write(const void* data, uint32_t size, sys_file_t& f, uint32_t* bytes_written) +{ + if (f.type == SYS_FILE_FILE) + { + size_t w = fwrite(data, 1, size, f.f); + if (bytes_written != nullptr) + { + *bytes_written = w; + } + } else if (f.type == SYS_FILE_MEMORY_STAT) + { + uint32_t s = size; + if (f.buf->size != 0) + { + uint32_t l = f.buf->size - (f.buf->ptr - f.buf->base); + if (s > l) + { + s = l; + } + } + memcpy(f.buf->ptr, data, s); + f.buf->ptr += s; + if (bytes_written != nullptr) + { + *bytes_written = s; + } + } else if (f.type == SYS_FILE_MEMORY_DYN) + { + uint32_t pos = f.buf->ptr - f.buf->base; + if (f.buf->size < pos + size) + { + f.buf->base = static_cast(Core::mem_realloc(f.buf->base, pos + size)); + f.buf->ptr = f.buf->base + pos; + f.buf->size = pos + size; + } + memcpy(f.buf->ptr, data, size); + f.buf->ptr += size; + if (bytes_written != nullptr) + { + *bytes_written = size; + } + } +} + +void sys_file_read_r(void* data, uint32_t size, sys_file_t& f) +{ + // DWORD w; + // ReadFile(f, data, size, &w, 0); + + sys_file_read(data, size, f); + + for (uint32_t i = 0; i < size / 2; i++) + { + char t = (static_cast(data))[i]; + (static_cast(data))[i] = (static_cast(data))[size - i - 1]; + (static_cast(data))[size - i - 1] = t; + } +} + +void sys_file_write_r(const void* data, uint32_t size, sys_file_t& f) +{ + char* data_r = new char[size]; + for (uint32_t i = 0; i < size; i++) + { + data_r[i] = (static_cast(data))[size - i - 1]; + } + + sys_file_write(data_r, size, f); + + delete[] data_r; +} + +void sys_file_write(uint32_t n, sys_file_t& f) +{ + sys_file_write(&n, 4, f); +} + +void sys_file_write_r(uint32_t n, sys_file_t& f) +{ + sys_file_write_r(&n, 4, f); +} + +sys_file_t* sys_file_create(const String& file_name) +{ + auto* ret = new sys_file_t; + + String real_name = get_internal_name(file_name); + + ret->f = fopen(real_name.utf8_str().GetData(), "w+"); + + if (ret->f == nullptr) + { + printf("can't create file: %s\n", real_name.utf8_str().GetData()); + } + + ret->type = SYS_FILE_FILE; + + return ret; +} + +sys_file_t* sys_file_open_r(const String& file_name, sys_file_cache_type_t /*cache_type*/) +{ + auto* ret = new sys_file_t; + + ret->type = SYS_FILE_FILE; + + String internal_name = get_internal_name(file_name); + ; + + FILE* f = fopen(internal_name.utf8_str().GetData(), "r"); + + if (f == nullptr) + { + ret->type = SYS_FILE_ERROR; + } + + ret->f = f; + + return ret; +} + +sys_file_t* sys_file_open(uint8_t* buf, uint32_t buf_size) +{ + auto* ret = new sys_file_t; + + ret->type = SYS_FILE_MEMORY_STAT; + ret->buf = new sys_file_mem_buf_t; + ret->buf->base = buf; + ret->buf->ptr = buf; + ret->buf->size = buf_size; + + return ret; +} + +sys_file_t* sys_file_create() +{ + auto* ret = new sys_file_t; + + ret->type = SYS_FILE_MEMORY_DYN; + ret->buf = new sys_file_mem_buf_t; + ret->buf->base = nullptr; + ret->buf->ptr = nullptr; + ret->buf->size = 0; + + return ret; +} + +sys_file_t* sys_file_open_w(const String& file_name, sys_file_cache_type_t /*cache_type*/) +{ + auto* ret = new sys_file_t; + + String real_name = get_internal_name(file_name); + ; + + FILE* f = fopen(real_name.utf8_str().GetData(), "r+"); + + if (f == nullptr) + { + ret->type = SYS_FILE_ERROR; + } else + { + ret->type = SYS_FILE_FILE; + } + + ret->f = f; + + return ret; +} + +sys_file_t* sys_file_open_rw(const String& file_name, sys_file_cache_type_t /*cache_type*/) +{ + auto* ret = new sys_file_t; + + String real_name = get_internal_name(file_name); + + FILE* f = fopen(real_name.utf8_str().GetData(), "r+"); + + if (f == nullptr) + { + ret->type = SYS_FILE_ERROR; + } else + { + ret->type = SYS_FILE_FILE; + } + + ret->f = f; + + return ret; +} + +void sys_file_close(sys_file_t* f) +{ + [[maybe_unused]] int result = 0; + + if (f->type == SYS_FILE_FILE && f->f != nullptr) + { + result = fclose(f->f); + } else if (f->type == SYS_FILE_MEMORY_STAT) + { + delete f->buf; + } else if (f->type == SYS_FILE_MEMORY_DYN) + { + Core::mem_free(f->buf->base); + delete f->buf; + } + + // f.type = SYS_FILE_ERROR; + delete f; +} + +uint64_t sys_file_size(sys_file_t& f) +{ + [[maybe_unused]] int result = 0; + + if (f.type == SYS_FILE_FILE) + { + uint32_t pos = ftell(f.f); + result = fseek(f.f, 0, SEEK_END); + uint32_t size = ftell(f.f); + result = fseek(f.f, pos, SEEK_SET); + return size; + } + + if (f.type == SYS_FILE_MEMORY_STAT || f.type == SYS_FILE_MEMORY_DYN) + { + return f.buf->size; + } + + return 0; +} + +uint64_t sys_file_size(const String& file_name) +{ + sys_file_t* f = sys_file_open_r(file_name); + uint64_t size = sys_file_size(*f); + sys_file_close(f); + return size; +} + +bool sys_file_truncate(sys_file_t& /*f*/, uint64_t /*size*/) +{ + return false; +} + +bool sys_file_seek(sys_file_t& f, uint64_t offset) +{ + bool ok = true; + if (f.type == SYS_FILE_FILE) + { + ok = (fseek(f.f, static_cast(offset), SEEK_SET) == 0); + // LARGE_INTEGER s; + // s.QuadPart = offset; + // SetFilePointerEx(f.handle, s, 0, FILE_BEGIN); + // printf("seek: %u\n", offset); + } else if (f.type == SYS_FILE_MEMORY_STAT || f.type == SYS_FILE_MEMORY_DYN) + { + f.buf->ptr = f.buf->base + offset; + } + return ok; +} + +uint64_t sys_file_tell(sys_file_t& f) +{ + if (f.type == SYS_FILE_FILE) + { + return ftell(f.f); + } + + if (f.type == SYS_FILE_MEMORY_STAT || f.type == SYS_FILE_MEMORY_DYN) + { + return f.buf->ptr - f.buf->base; + } + + return 0; +} + +bool sys_file_is_error(sys_file_t& f) +{ + return f.type == SYS_FILE_ERROR || (f.type == SYS_FILE_FILE && f.f == nullptr); +} + +bool sys_file_is_directory_existing(const String& path) +{ + String real_name = get_internal_name(path); + + struct stat s + { + }; + + if (0 != stat(real_name.utf8_str().GetData(), &s)) + { + return false; + } + + return S_ISDIR(s.st_mode); // NOLINT +} + +bool sys_file_is_file_existing(const String& name) +{ + String real_name = get_internal_name(name); + + struct stat s + { + }; + + if (0 != stat(real_name.utf8_str().GetData(), &s)) + { + return false; + } + + return !S_ISDIR(s.st_mode); // NOLINT +} + +bool sys_file_create_directory(const String& path) +{ + String real_name = get_internal_name(path); + + mode_t m = S_IRWXU | S_IRWXG | S_IRWXO; // NOLINT + + String::Utf8 u = real_name.utf8_str(); + + int r = mkdir(u.GetDataConst(), m); + + if (r != 0) + { + int e = errno; + if (e == EEXIST) + { + printf("mkdir(%s, %" PRIx32 ") failed: The named file exists\n", real_name.C_Str(), static_cast(m)); + } else + { + printf("mkdir(%s, %" PRIx32 ") failed: %d\n", real_name.C_Str(), static_cast(m), e); + return false; + } + } + + return true; +} + +bool sys_file_delete_directory(const String& path) +{ + String real_name = get_internal_name(path); + + return 0 == remove(real_name.utf8_str().GetData()); +} + +bool sys_file_delete_file(const String& name) +{ + String real_name = get_internal_name(name); + + return 0 == unlink(real_name.utf8_str().GetData()); +} + +bool sys_file_flush(sys_file_t& f) +{ + if (f.type == SYS_FILE_FILE && f.f != nullptr) + { + return (fflush(f.f) == 0); + } + + return false; +} + +SysFileTimeStruct sys_file_get_last_access_time_utc(const String& name) +{ + SysFileTimeStruct r {}; + + String real_name = get_internal_name(name); + + struct stat s + { + }; + + if (0 != stat(real_name.utf8_str().GetData(), &s)) + { + r.is_invalid = true; + } else + { + r.is_invalid = false; + r.time = s.st_atime; + } + + return r; +} + +SysFileTimeStruct sys_file_get_last_write_time_utc(const String& name) +{ + SysFileTimeStruct r {}; + + String real_name = get_internal_name(name); + + struct stat s + { + }; + + if (0 != stat(real_name.utf8_str().GetData(), &s)) + { + r.is_invalid = true; + } else + { + r.is_invalid = false; + r.time = s.st_mtime; + } + + return r; +} + +void sys_file_get_last_access_and_write_time_utc(const String& name, SysFileTimeStruct& a, SysFileTimeStruct& w) +{ + String real_name = get_internal_name(name); + + struct stat s + { + }; + + if (0 != stat(real_name.utf8_str().GetData(), &s)) + { + a.is_invalid = true; + w.is_invalid = true; + } else + { + a.is_invalid = false; + w.is_invalid = false; + a.time = s.st_atime; + w.time = s.st_mtime; + } +} + +void sys_file_get_last_access_and_write_time_utc(sys_file_t& /*f*/, SysFileTimeStruct& /*a*/, SysFileTimeStruct& /*w*/) +{ + EXIT("not implemented\n"); +} + +bool sys_file_set_last_access_time_utc(const String& name, SysFileTimeStruct& access) +{ + if (access.is_invalid) + { + return false; + } + + String real_name = get_internal_name(name); + + struct stat s + { + }; + + String::Utf8 n = real_name.utf8_str(); + + if (0 != stat(n.GetData(), &s)) + { + return false; + } + + utimbuf times {}; + times.actime = access.time; + times.modtime = s.st_mtime; + + return !(0 != utime(n.GetData(), ×)); + + // if (0 != stat(n.GetData(), &s)) + // { + // return false; + // } + // + // times.actime += times.actime - s.st_atime; + // times.modtime += times.modtime - s.st_mtime; + // + // if (0 != utime(n.GetData(), ×)) + // { + // return false; + // } +} + +bool sys_file_set_last_write_time_utc(const String& name, SysFileTimeStruct& write) +{ + if (write.is_invalid) + { + return false; + } + + String real_name = get_internal_name(name); + + struct stat s + { + }; + + String::Utf8 n = real_name.utf8_str(); + + if (0 != stat(n.GetData(), &s)) + { + return false; + } + + utimbuf times {}; + times.actime = s.st_atime; + times.modtime = write.time; + + return !(0 != utime(n.GetData(), ×)); + + // if (0 != stat(n.GetData(), &s)) + // { + // return false; + // } + // + // times.actime += times.actime - s.st_atime; + // times.modtime += times.modtime - s.st_mtime; + // + // if (0 != utime(n.GetData(), ×)) + // { + // return false; + // } +} + +bool sys_file_set_last_access_and_write_time_utc(const String& name, SysFileTimeStruct& access, SysFileTimeStruct& write) +{ + if (access.is_invalid || write.is_invalid) + { + return false; + } + + String real_name = get_internal_name(name); + + struct stat s + { + }; + + String::Utf8 n = real_name.utf8_str(); + + if (0 != stat(n.GetData(), &s)) + { + return false; + } + + utimbuf times {}; + times.actime = access.time; + times.modtime = write.time; + + return !(0 != utime(n.GetData(), ×)); + + // if (0 != stat(n.GetData(), &s)) + // { + // return false; + // } + // + // times.actime += times.actime - s.st_atime; + // times.modtime += times.modtime - s.st_mtime; + // + // if (0 != utime(n.GetData(), ×)) + // { + // return false; + // } +} + +void sys_file_find_files(const String& /*path*/, Vector& /*out*/) +{ + EXIT("not implemented\n"); +} + +void sys_file_get_dents(const String& /*path*/, Kyty::Vector& /*out*/) +{ + EXIT("not implemented\n"); +} + +bool sys_file_copy_file(const String& /*src*/, const String& /*dst*/) +{ + EXIT("not implemented\n"); + return false; +} + +bool sys_file_move_file(const String& /*src*/, const String& /*dst*/) +{ + EXIT("not implemented\n"); + return false; +} + +void sys_file_remove_readonly(const String& /*name*/) +{ + EXIT("not implemented\n"); +} + +} // namespace Kyty + #endif diff --git a/source/lib/Sys/src/SysLinuxVirtual.cpp b/source/lib/Sys/src/SysLinuxVirtual.cpp new file mode 100644 index 0000000..18c9401 --- /dev/null +++ b/source/lib/Sys/src/SysLinuxVirtual.cpp @@ -0,0 +1,373 @@ +#include "Kyty/Core/Common.h" + +#if KYTY_PLATFORM != KYTY_PLATFORM_LINUX +//#error "KYTY_PLATFORM != KYTY_PLATFORM_LINUX" +#else + +#include "Kyty/Core/DbgAssert.h" +#include "Kyty/Core/String.h" +#include "Kyty/Core/VirtualMemory.h" +#include "Kyty/Sys/SysVirtual.h" + +#include "cpuinfo.h" + +#include +#include +#include +#include + +// IWYU pragma: no_include +// IWYU pragma: no_include +// IWYU pragma: no_include +// IWYU pragma: no_include + +#if defined(MAP_FIXED_NOREPLACE) && KYTY_PLATFORM == KYTY_PLATFORM_LINUX +#define KYTY_FIXED_NOREPLACE +#endif + +namespace Kyty::Core { + +static pthread_mutex_t g_virtual_mutex {}; +static std::map* g_allocs = nullptr; +static std::map* g_protects = nullptr; + +void sys_get_system_info(SystemInfo* info) +{ + EXIT_IF(info == nullptr); + + const auto* p = cpuinfo_get_package(0); + + EXIT_IF(p == nullptr); + + info->ProcessorName = String::FromUtf8(p->name); +} + +void sys_virtual_init() +{ + pthread_mutexattr_t attr {}; + + pthread_mutexattr_init(&attr); +#if KYTY_PLATFORM == KYTY_PLATFORM_LINUX + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_FAST_NP); +#else + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); +#endif + pthread_mutex_init(&g_virtual_mutex, &attr); + pthread_mutexattr_destroy(&attr); + + g_allocs = new std::map; + g_protects = new std::map; + + cpuinfo_initialize(); +} + +static int get_protection_flag(VirtualMemory::Mode mode) +{ + int protect = PROT_NONE; + switch (mode) + { + case VirtualMemory::Mode::Read: protect = PROT_READ; break; + case VirtualMemory::Mode::Write: + case VirtualMemory::Mode::ReadWrite: protect = PROT_READ | PROT_WRITE; break; // NOLINT + case VirtualMemory::Mode::Execute: protect = PROT_EXEC; break; + case VirtualMemory::Mode::ExecuteRead: protect = PROT_EXEC | PROT_READ; break; // NOLINT + case VirtualMemory::Mode::ExecuteWrite: + case VirtualMemory::Mode::ExecuteReadWrite: protect = PROT_EXEC | PROT_WRITE | PROT_READ; break; // NOLINT + case VirtualMemory::Mode::NoAccess: + default: protect = PROT_NONE; break; + } + return protect; +} + +static VirtualMemory::Mode get_protection_flag(int mode) +{ + switch (mode) + { + case PROT_NONE: return VirtualMemory::Mode::NoAccess; + case PROT_READ: return VirtualMemory::Mode::Read; + case PROT_WRITE: return VirtualMemory::Mode::Write; + case PROT_READ | PROT_WRITE: return VirtualMemory::Mode::ReadWrite; // NOLINT + case PROT_EXEC: return VirtualMemory::Mode::Execute; + case PROT_EXEC | PROT_WRITE: return VirtualMemory::Mode::ExecuteWrite; // NOLINT + case PROT_EXEC | PROT_READ: return VirtualMemory::Mode::ExecuteRead; // NOLINT + case PROT_EXEC | PROT_WRITE | PROT_READ: return VirtualMemory::Mode::ExecuteReadWrite; // NOLINT + default: return VirtualMemory::Mode::NoAccess; + } +} + +uint64_t sys_virtual_alloc(uint64_t address, uint64_t size, VirtualMemory::Mode mode) +{ + EXIT_IF(g_allocs == nullptr); + + auto addr = static_cast(address); + + int protect = get_protection_flag(mode); + + void* ptr = mmap(reinterpret_cast(addr), size, protect, MAP_PRIVATE | MAP_ANON, -1, 0); // NOLINT + + auto ret_addr = reinterpret_cast(ptr); + + if (ptr != MAP_FAILED) + { + pthread_mutex_lock(&g_virtual_mutex); + (*g_allocs)[ret_addr] = size; + uintptr_t page_start = ret_addr >> 12u; + uintptr_t page_end = (ret_addr + size - 1) >> 12u; + for (uintptr_t page = page_start; page <= page_end; page++) + { + (*g_protects)[page] = protect; + } + pthread_mutex_unlock(&g_virtual_mutex); + } + + return ret_addr; +} + +static uintptr_t align_up(uintptr_t addr, uint64_t alignment) +{ + return (addr + alignment - 1) & ~(alignment - 1); +} + +uint64_t sys_virtual_alloc_aligned(uint64_t address, uint64_t size, VirtualMemory::Mode mode, uint64_t alignment) +{ + if (alignment == 0) + { + return 0; + } + + EXIT_IF(g_allocs == nullptr); + + auto addr = static_cast(address); + int protect = get_protection_flag(mode); + + void* ptr = mmap(reinterpret_cast(addr), size, protect, MAP_PRIVATE | MAP_ANON, -1, 0); // NOLINT + + auto ret_addr = reinterpret_cast(ptr); + + if (ptr != MAP_FAILED && ((ret_addr & (alignment - 1)) != 0)) + { + munmap(ptr, size); + + ptr = mmap(reinterpret_cast(addr), size + alignment, protect, MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, -1, 0); // NOLINT + ret_addr = reinterpret_cast(ptr); + if (ptr != MAP_FAILED) + { + munmap(ptr, size + alignment); + auto aligned_addr = align_up(ret_addr, alignment); +#ifdef KYTY_FIXED_NOREPLACE + // NOLINTNEXTLINE + ptr = mmap(reinterpret_cast(aligned_addr), size, protect, MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANON, -1, 0); +#else + // NOLINTNEXTLINE + ptr = mmap(reinterpret_cast(aligned_addr), size, protect, MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0); +#endif + ret_addr = reinterpret_cast(ptr); + if (ptr == MAP_FAILED) + { + [[maybe_unused]] int err = errno; + // printf("mmap failed: %d\n", err); + } + if (ptr != MAP_FAILED && ((ret_addr & (alignment - 1)) != 0)) + { + munmap(ptr, size); + ret_addr = 0; + ptr = MAP_FAILED; + } + } + } + + if (ptr == MAP_FAILED) + { + return sys_virtual_alloc_aligned(address, size, mode, alignment << 1u); + } + + pthread_mutex_lock(&g_virtual_mutex); + (*g_allocs)[ret_addr] = size; + uintptr_t page_start = ret_addr >> 12u; + uintptr_t page_end = (ret_addr + size - 1) >> 12u; + for (uintptr_t page = page_start; page <= page_end; page++) + { + (*g_protects)[page] = protect; + } + pthread_mutex_unlock(&g_virtual_mutex); + + return ret_addr; +} + +[[maybe_unused]] static bool is_mmaped(void* ptr, size_t length) +{ + FILE* file = fopen("/proc/self/maps", "r"); + char line[1024]; + bool ret = false; + auto addr = reinterpret_cast(ptr); + + [[maybe_unused]] int result = 0; + + while (feof(file) == 0) + { + if (fgets(line, 1024, file) == nullptr) + { + break; + } + uint64_t start = 0; + uint64_t end = 0; + // NOLINTNEXTLINE(cert-err34-c) + if (sscanf(line, "%" SCNx64 "-%" SCNx64, &start, &end) != 2) + { + continue; + } + if (addr >= start && addr + length <= end) + { + ret = true; + break; + } + } + result = fclose(file); + return ret; +} + +bool sys_virtual_alloc_fixed(uint64_t address, uint64_t size, VirtualMemory::Mode mode) +{ + EXIT_IF(g_allocs == nullptr); + + auto addr = static_cast(address); + int protect = get_protection_flag(mode); + +#ifdef KYTY_FIXED_NOREPLACE + // NOLINTNEXTLINE + void* ptr = mmap(reinterpret_cast(addr), size, protect, MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANON, -1, 0); +#else + // NOLINTNEXTLINE + void* ptr = (is_mmaped(reinterpret_cast(addr), size) + ? MAP_FAILED + : mmap(reinterpret_cast(addr), size, protect, MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0)); +#endif + + auto ret_addr = reinterpret_cast(ptr); + + if (ptr != MAP_FAILED && ret_addr != addr) + { + munmap(ptr, size); + ret_addr = 0; + ptr = MAP_FAILED; + } + + if (ptr != MAP_FAILED) + { + pthread_mutex_lock(&g_virtual_mutex); + (*g_allocs)[ret_addr] = size; + uintptr_t page_start = ret_addr >> 12u; + uintptr_t page_end = (ret_addr + size - 1) >> 12u; + for (uintptr_t page = page_start; page <= page_end; page++) + { + (*g_protects)[page] = protect; + } + pthread_mutex_unlock(&g_virtual_mutex); + + return true; + } + + return false; +} + +bool sys_virtual_free(uint64_t address) +{ + EXIT_IF(g_allocs == nullptr); + size_t size = 0; + + auto addr = static_cast(address & ~static_cast(0xfffu)); + + pthread_mutex_lock(&g_virtual_mutex); + if (auto s = g_allocs->find(addr); s != g_allocs->end()) + { + size = s->second; + g_allocs->erase(s); + } + pthread_mutex_unlock(&g_virtual_mutex); + + if (size == 0) + { + return false; + } + + if (munmap(reinterpret_cast(addr), size) == 0) + { + uintptr_t page_start = addr >> 12u; + uintptr_t page_end = (addr + size - 1) >> 12u; + pthread_mutex_lock(&g_virtual_mutex); + for (uintptr_t page = page_start; page <= page_end; page++) + { + if (auto s = g_protects->find(page); s != g_protects->end()) + { + g_protects->erase(s); + } + } + pthread_mutex_unlock(&g_virtual_mutex); + return true; + } + + return false; +} + +bool sys_virtual_protect(uint64_t address, uint64_t size, VirtualMemory::Mode mode, VirtualMemory::Mode* old_mode) +{ + auto addr = static_cast(address); + + pthread_mutex_lock(&g_virtual_mutex); + if (old_mode != nullptr) + { + if (auto s = g_protects->find(addr >> 12u); s != g_protects->end()) + { + *old_mode = get_protection_flag(s->second); + } else + { + *old_mode = VirtualMemory::Mode::NoAccess; + } + } + pthread_mutex_unlock(&g_virtual_mutex); + + uintptr_t page_start = addr >> 12u; + uintptr_t page_end = (addr + size - 1) >> 12u; + if (mprotect(reinterpret_cast(page_start << 12u), (page_end - page_start + 1) << 12u, get_protection_flag(mode)) == 0) + { + pthread_mutex_lock(&g_virtual_mutex); + for (uintptr_t page = page_start; page <= page_end; page++) + { + (*g_protects)[page] = get_protection_flag(mode); + } + pthread_mutex_unlock(&g_virtual_mutex); + return true; + } + + return false; +} + +bool sys_virtual_flush_instruction_cache(uint64_t /*address*/, uint64_t /*size*/) +{ + return true; +} + +bool sys_virtual_patch_replace(uint64_t vaddr, uint64_t value) +{ + VirtualMemory::Mode old_mode {}; + sys_virtual_protect(vaddr, 8, VirtualMemory::Mode::ReadWrite, &old_mode); + + auto* ptr = reinterpret_cast(vaddr); + + bool ret = (*ptr != value); + + *ptr = value; + + sys_virtual_protect(vaddr, 8, old_mode); + + if (VirtualMemory::IsExecute(old_mode)) + { + sys_virtual_flush_instruction_cache(vaddr, 8); + } + + return ret; +} + +} // namespace Kyty::Core + +#endif diff --git a/source/lib/Sys/src/SysWindowsDbg.cpp b/source/lib/Sys/src/SysWindowsDbg.cpp index 3dcbb76..f75189e 100644 --- a/source/lib/Sys/src/SysWindowsDbg.cpp +++ b/source/lib/Sys/src/SysWindowsDbg.cpp @@ -1,8 +1,6 @@ -#include "Kyty/Sys/SysWindowsDbg.h" +#include "Kyty/Sys/Windows/SysWindowsDbg.h" #include "Kyty/Core/Common.h" -#include "Kyty/Core/DbgAssert.h" -#include "Kyty/Sys/SysDbg.h" // IWYU pragma: no_include // IWYU pragma: no_include @@ -16,6 +14,9 @@ //#error "KYTY_PLATFORM != KYTY_PLATFORM_WINDOWS" #else +#include "Kyty/Core/DbgAssert.h" +#include "Kyty/Sys/SysDbg.h" + #include // IWYU pragma: keep #if KYTY_COMPILER == KYTY_COMPILER_MSVC #include diff --git a/source/lib/Sys/src/SysWindowsFileIO.cpp b/source/lib/Sys/src/SysWindowsFileIO.cpp index 55d7039..ac5203e 100644 --- a/source/lib/Sys/src/SysWindowsFileIO.cpp +++ b/source/lib/Sys/src/SysWindowsFileIO.cpp @@ -1,4 +1,4 @@ -#include "Kyty/Sys/SysWindowsFileIO.h" +#include "Kyty/Sys/Windows/SysWindowsFileIO.h" #include "Kyty/Core/Common.h" diff --git a/source/lib/Sys/src/SysWindowsVirtual.cpp b/source/lib/Sys/src/SysWindowsVirtual.cpp new file mode 100644 index 0000000..e6de202 --- /dev/null +++ b/source/lib/Sys/src/SysWindowsVirtual.cpp @@ -0,0 +1,259 @@ +#include "Kyty/Core/Common.h" + +#if KYTY_PLATFORM != KYTY_PLATFORM_WINDOWS +//#error "KYTY_PLATFORM != KYTY_PLATFORM_WINDOWS" +#else + +#include "Kyty/Core/DbgAssert.h" +#include "Kyty/Core/String.h" +#include "Kyty/Core/VirtualMemory.h" +#include "Kyty/Sys/SysVirtual.h" + +#include "cpuinfo.h" + +#include // IWYU pragma: keep + +// IWYU pragma: no_include +// IWYU pragma: no_include +// IWYU pragma: no_include +// IWYU pragma: no_include +// IWYU pragma: no_include +// IWYU pragma: no_include +// IWYU pragma: no_include +// IWYU pragma: no_include + +namespace Kyty::Core { + +void sys_get_system_info(SystemInfo* info) +{ + EXIT_IF(info == nullptr); + + const auto* p = cpuinfo_get_package(0); + + EXIT_IF(p == nullptr); + + info->ProcessorName = String::FromUtf8(p->name); +} + +static DWORD get_protection_flag(VirtualMemory::Mode mode) +{ + DWORD protect = PAGE_NOACCESS; + switch (mode) + { + case VirtualMemory::Mode::Read: protect = PAGE_READONLY; break; + + case VirtualMemory::Mode::Write: + case VirtualMemory::Mode::ReadWrite: protect = PAGE_READWRITE; break; + + case VirtualMemory::Mode::Execute: protect = PAGE_EXECUTE; break; + + case VirtualMemory::Mode::ExecuteRead: protect = PAGE_EXECUTE_READ; break; + + case VirtualMemory::Mode::ExecuteWrite: + case VirtualMemory::Mode::ExecuteReadWrite: protect = PAGE_EXECUTE_READWRITE; break; + + case VirtualMemory::Mode::NoAccess: + default: protect = PAGE_NOACCESS; break; + } + return protect; +} + +static VirtualMemory::Mode get_protection_flag(DWORD mode) +{ + switch (mode) + { + case PAGE_NOACCESS: return VirtualMemory::Mode::NoAccess; + case PAGE_READONLY: return VirtualMemory::Mode::Read; + case PAGE_READWRITE: return VirtualMemory::Mode::ReadWrite; + case PAGE_EXECUTE: return VirtualMemory::Mode::Execute; + case PAGE_EXECUTE_READ: return VirtualMemory::Mode::ExecuteRead; + case PAGE_EXECUTE_READWRITE: return VirtualMemory::Mode::ExecuteReadWrite; + default: return VirtualMemory::Mode::NoAccess; + } +} + +void sys_virtual_init() +{ + cpuinfo_initialize(); +} + +uint64_t sys_virtual_alloc(uint64_t address, uint64_t size, VirtualMemory::Mode mode) +{ + auto ptr = (address == 0 ? sys_virtual_alloc_aligned(address, size, mode, 1) + : reinterpret_cast(VirtualAlloc(reinterpret_cast(static_cast(address)), size, + static_cast(MEM_COMMIT) | static_cast(MEM_RESERVE), + get_protection_flag(mode)))); + if (ptr == 0) + { + auto err = static_cast(GetLastError()); + + if (err != ERROR_INVALID_ADDRESS) + { + printf("VirtualAlloc() failed: 0x%08" PRIx32 "\n", err); + } else + { + return sys_virtual_alloc_aligned(address, size, mode, 1); + } + } + return ptr; +} + +using VirtualAlloc2_func_t = /*WINBASEAPI*/ PVOID WINAPI (*)(HANDLE, PVOID, SIZE_T, ULONG, ULONG, MEM_EXTENDED_PARAMETER*, ULONG); + +static VirtualAlloc2_func_t ResolveVirtualAlloc2() +{ + HMODULE h = GetModuleHandle("KernelBase"); // @suppress("Invalid arguments") + if (h != nullptr) + { + return reinterpret_cast(GetProcAddress(h, "VirtualAlloc2")); + } + return nullptr; +} + +static uint64_t align_up(uint64_t addr, uint64_t alignment) +{ + return (addr + alignment - 1) & ~(alignment - 1); +} + +uint64_t sys_virtual_alloc_aligned(uint64_t address, uint64_t size, VirtualMemory::Mode mode, uint64_t alignment) +{ + if (alignment == 0) + { + printf("VirtualAlloc2 failed: 0x%08" PRIx32 "\n", static_cast(GetLastError())); + return 0; + } + + static constexpr uint64_t SYSTEM_MANAGED_MIN = 0x0000040000u; + static constexpr uint64_t SYSTEM_MANAGED_MAX = 0x07FFFFBFFFu; + static constexpr uint64_t USER_MIN = 0x1000000000u; + static constexpr uint64_t USER_MAX = 0xFBFFFFFFFFu; + + MEM_ADDRESS_REQUIREMENTS req {}; + MEM_EXTENDED_PARAMETER param {}; + req.LowestStartingAddress = + (address == 0 ? reinterpret_cast(SYSTEM_MANAGED_MIN) : reinterpret_cast(align_up(address, alignment))); + req.HighestEndingAddress = (address == 0 ? reinterpret_cast(SYSTEM_MANAGED_MAX) : reinterpret_cast(USER_MAX)); + req.Alignment = alignment; + param.Type = MemExtendedParameterAddressRequirements; + param.Pointer = &req; + + MEM_ADDRESS_REQUIREMENTS req2 {}; + MEM_EXTENDED_PARAMETER param2 {}; + req2.LowestStartingAddress = (address == 0 ? reinterpret_cast(USER_MIN) : reinterpret_cast(align_up(address, alignment))); + req2.HighestEndingAddress = reinterpret_cast(USER_MAX); + req2.Alignment = alignment; + param2.Type = MemExtendedParameterAddressRequirements; + param2.Pointer = &req2; + + static auto virtual_alloc2 = ResolveVirtualAlloc2(); + + EXIT_NOT_IMPLEMENTED(virtual_alloc2 == nullptr); + + auto ptr = reinterpret_cast(virtual_alloc2(GetCurrentProcess(), nullptr, size, + static_cast(MEM_COMMIT) | static_cast(MEM_RESERVE), + get_protection_flag(mode), ¶m, 1)); + + if (ptr == 0) + { + ptr = reinterpret_cast(virtual_alloc2(GetCurrentProcess(), nullptr, size, + static_cast(MEM_COMMIT) | static_cast(MEM_RESERVE), + get_protection_flag(mode), ¶m2, 1)); + } + + if (ptr == 0) + { + auto err = static_cast(GetLastError()); + if (err != ERROR_INVALID_PARAMETER) + { + printf("VirtualAlloc2(alignment = 0x%016" PRIx64 ") failed: 0x%08" PRIx32 "\n", alignment, err); + } else + { + return sys_virtual_alloc_aligned(address, size, mode, alignment << 1u); + } + } + return ptr; +} + +bool sys_virtual_alloc_fixed(uint64_t address, uint64_t size, VirtualMemory::Mode mode) +{ + auto ptr = reinterpret_cast(VirtualAlloc(reinterpret_cast(static_cast(address)), size, + static_cast(MEM_COMMIT) | static_cast(MEM_RESERVE), + get_protection_flag(mode))); + if (ptr == 0) + { + auto err = static_cast(GetLastError()); + + printf("VirtualAlloc() failed: 0x%08" PRIx32 "\n", err); + + return false; + } + + if (ptr != address) + { + printf("VirtualAlloc() failed: wrong address\n"); + VirtualFree(reinterpret_cast(ptr), 0, MEM_RELEASE); + return false; + } + + return true; +} + +bool sys_virtual_free(uint64_t address) +{ + if (VirtualFree(reinterpret_cast(static_cast(address)), 0, MEM_RELEASE) == 0) + { + printf("VirtualFree() failed: 0x%08" PRIx32 "\n", static_cast(GetLastError())); + return false; + } + return true; +} + +bool sys_virtual_protect(uint64_t address, uint64_t size, VirtualMemory::Mode mode, VirtualMemory::Mode* old_mode) +{ + DWORD old_protect = 0; + if (VirtualProtect(reinterpret_cast(static_cast(address)), size, get_protection_flag(mode), &old_protect) == 0) + { + printf("VirtualProtect() failed: 0x%08" PRIx32 "\n", static_cast(GetLastError())); + return false; + } + if (old_mode != nullptr) + { + *old_mode = get_protection_flag(old_protect); + } + return true; +} + +bool sys_virtual_flush_instruction_cache(uint64_t address, uint64_t size) +{ + if (::FlushInstructionCache(GetCurrentProcess(), reinterpret_cast(static_cast(address)), size) == 0) + { + printf("FlushInstructionCache() failed: 0x%08" PRIx32 "\n", static_cast(GetLastError())); + return false; + } + return true; +} + +bool sys_virtual_patch_replace(uint64_t vaddr, uint64_t value) +{ + VirtualMemory::Mode old_mode {}; + sys_virtual_protect(vaddr, 8, VirtualMemory::Mode::ReadWrite, &old_mode); + + auto* ptr = reinterpret_cast(vaddr); + + bool ret = (*ptr != value); + + *ptr = value; + + sys_virtual_protect(vaddr, 8, old_mode); + + if (VirtualMemory::IsExecute(old_mode)) + { + sys_virtual_flush_instruction_cache(vaddr, 8); + } + + return ret; +} + +} // namespace Kyty::Core + +#endif diff --git a/source/utils.cmake b/source/utils.cmake index 49c7a7f..b41d30f 100644 --- a/source/utils.cmake +++ b/source/utils.cmake @@ -19,7 +19,7 @@ function(add_generator_macros t m v) endfunction() function(include_what_you_use target dirs) - if (CLANG AND ("${target}" IN_LIST KYTY_IWYU)) + if (NOT LINUX AND CLANG AND ("${target}" IN_LIST KYTY_IWYU)) find_program (CLANG_IWYU_EXE NAMES "include-what-you-use") if (CLANG_IWYU_EXE) set_target_properties(${target} PROPERTIES CXX_INCLUDE_WHAT_YOU_USE "${CLANG_IWYU_EXE};-Xiwyu;--cxx17ns;-Qunused-arguments;-Werror") @@ -28,7 +28,7 @@ function(include_what_you_use target dirs) endfunction() function(include_what_you_use_with_mappings target dirs mappings) - if (CLANG AND ("${target}" IN_LIST KYTY_IWYU)) + if (NOT LINUX AND CLANG AND ("${target}" IN_LIST KYTY_IWYU)) find_program (CLANG_IWYU_EXE NAMES "include-what-you-use") if (CLANG_IWYU_EXE) foreach(map ${mappings}) @@ -83,12 +83,8 @@ macro(config_compiler_and_linker) set(KYTY_WARNINGS_ARE_ERRORS ON) +set(KYTY_C_FLAGS "") set(KYTY_CPP_FLAGS "") -set(KYTY_CPP_FLAGS_RELEASE "") -set(KYTY_CPP_FLAGS_DEBUG "") -set(KYTY_EXE_LINKER_FLAGS "") -set(KYTY_EXE_LINKER_FLAGS_RELEASE "") -set(KYTY_EXE_LINKER_FLAGS_DEBUG "") SET(CMAKE_NINJA_FORCE_RESPONSE_FILE 1 CACHE INTERNAL "") @@ -112,41 +108,41 @@ if(MSVC) set(KYTY_CPP_FLAGS "${KYTY_CPP_FLAGS} /Zc:__cplusplus /utf-8 /Oy- /wd4244 /wd4305 /wd4800 /wd4345") endif() - set(KYTY_EXE_LINKER_FLAGS_RELEASE "/OPT:NOREF") + add_link_options("$<$:/OPT:NOREF>") if(KYTY_WARNINGS_ARE_ERRORS) - set(KYTY_CPP_FLAGS "${KYTY_CPP_FLAGS} /WX") + #set(KYTY_CPP_FLAGS "${KYTY_CPP_FLAGS} /WX") + add_compile_options(/WX) endif() -endif() -if(MINGW) + set(KYTY_C_FLAGS "${KYTY_CPP_FLAGS}") + +elseif(MINGW OR LINUX) if (CLANG) - set(KYTY_CPP_FLAGS "${KYTY_CPP_FLAGS} -fno-rtti -fno-exceptions -fcolor-diagnostics -finput-charset=UTF-8 -fexec-charset=UTF-8 -g -static -fno-strict-aliasing -fno-omit-frame-pointer -Wall -fmessage-length=0") + set(KYTY_CPP_FLAGS "${KYTY_CPP_FLAGS} -fno-rtti -fno-exceptions -fcolor-diagnostics -finput-charset=UTF-8 -fexec-charset=UTF-8 -g -fno-strict-aliasing -fno-omit-frame-pointer -Wall -fmessage-length=0") + if (MINGW) + set(KYTY_CPP_FLAGS "${KYTY_CPP_FLAGS} -static") + endif() else() - set(KYTY_CPP_FLAGS "${KYTY_CPP_FLAGS} -fno-exceptions -fdiagnostics-color=always -finput-charset=UTF-8 -fexec-charset=UTF-8 -static-libgcc -static-libstdc++ -g -fno-strict-aliasing -fno-omit-frame-pointer -Wall -fmessage-length=0") + set(KYTY_CPP_FLAGS "${KYTY_CPP_FLAGS} -fno-exceptions -fdiagnostics-color=always -finput-charset=UTF-8 -fexec-charset=UTF-8 -static-libgcc -static-libstdc++ -g -fno-strict-aliasing -fno-omit-frame-pointer -Wall -Wno-unused-value -fmessage-length=0") endif() - set(KYTY_CPP_FLAGS_DEBUG "${KYTY_CPP_FLAGS_DEBUG} -O0") - if(KYTY_WARNINGS_ARE_ERRORS) - set(KYTY_CPP_FLAGS "${KYTY_CPP_FLAGS} -Werror") + #set(KYTY_CPP_FLAGS "${KYTY_CPP_FLAGS} -Werror") + add_compile_options(-Werror) endif() - set(KYTY_EXE_LINKER_FLAGS "${KYTY_EXE_LINKER_FLAGS} -g") + add_link_options("-g") unset(CMAKE_CXX_STANDARD_LIBRARIES CACHE) unset(CMAKE_C_STANDARD_LIBRARIES CACHE) + + set(KYTY_C_FLAGS "${KYTY_CPP_FLAGS}") + endif() -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${KYTY_CPP_FLAGS}") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${KYTY_C_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KYTY_CPP_FLAGS}") -set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${KYTY_CPP_FLAGS_RELEASE}") -set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${KYTY_CPP_FLAGS_RELEASE}") -set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${KYTY_CPP_FLAGS_DEBUG}") -set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${KYTY_CPP_FLAGS_DEBUG}") -set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${KYTY_EXE_LINKER_FLAGS}") -set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${KYTY_EXE_LINKER_FLAGS_RELEASE}") -set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${KYTY_EXE_LINKER_FLAGS_DEBUG}") endmacro() \ No newline at end of file