diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d77d26..e552159 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,12 @@ -cmake_minimum_required (VERSION 3.6) -project (ArmaScriptProfiler) +cmake_minimum_required (VERSION 3.13) +project (ArmaScriptProfiler CXX ASM) find_package (Threads) option(USE_64BIT_BUILD "USE_64BIT_BUILD" OFF) option(USE_STATIC_LINKING "USE_STATIC_LINKING" ON) +option(WITH_BROFILER "WITH_BROFILER" OFF) +option(WITH_CHROME "WITH_CHROME" OFF) if(USE_STATIC_LINKING) message("WARNING: Linking statically") @@ -14,13 +16,13 @@ else() set(INTERCEPT_LINK_TYPE "dynamic") endif() -if("${CMAKE_GENERATOR}" MATCHES "Visual Studio 15 2017 Win64") +if(MSVC AND CMAKE_CL_64) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++latest" ) set( USE_64BIT_BUILD ON) -elseif("${CMAKE_GENERATOR}" MATCHES "Visual Studio 15 2017") +elseif(MSVC) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++latest" ) -elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "MSVC") - message(FATAL_ERROR "ERROR: You need a C++17 compatible compiler") +#elseif(MSVC) +# message(FATAL_ERROR "ERROR: You need a C++17 compatible compiler") endif() message("GENERATOR USED: '${CMAKE_GENERATOR}'") @@ -29,9 +31,9 @@ message("COMPILER USED: '${CMAKE_CXX_COMPILER_ID}'") set(CMAKE_CL_64 ${USE_64BIT_BUILD}) if(USE_64BIT_BUILD) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/build/win64/") + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/release/@ArmaScriptProfiler/intercept") else() - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/build/win32/") + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/release/@ArmaScriptProfiler/intercept") endif() set(CMAKE_CXX_STANDARD 17) diff --git a/intercept b/intercept index 4f44667..2634cda 160000 --- a/intercept +++ b/intercept @@ -1 +1 @@ -Subproject commit 4f4466762145a8dbd3872cad35f9c8094f4131ab +Subproject commit 2634cda0b81c909fa3c68808ec6652db1020e31b diff --git a/src/AdapterArmaDiag.cpp b/src/AdapterArmaDiag.cpp index 6901ea3..e235a93 100644 --- a/src/AdapterArmaDiag.cpp +++ b/src/AdapterArmaDiag.cpp @@ -4,16 +4,11 @@ #include "scriptProfiler.hpp" #include -extern scriptProfiler profiler; - AdapterArmaDiag::AdapterArmaDiag() { frames.resize(framesToGo + 1); type = AdapterType::ArmaDiag; } - -AdapterArmaDiag::~AdapterArmaDiag() {} - std::shared_ptr AdapterArmaDiag::createScope(intercept::types::r_string name, intercept::types::r_string filename, uint32_t fileline) { @@ -132,7 +127,7 @@ void AdapterArmaDiag::addLog(intercept::types::r_string message) { } -void AdapterArmaDiag::iterateElementTree(const frameData& frame, std::function func) { +void AdapterArmaDiag::iterateElementTree(const frameData& frame, const std::function& func) { //https://stackoverflow.com/a/5988138 for (auto& element : frame.elements) { profileElement* node = element.get(); @@ -163,7 +158,7 @@ intercept::types::r_string AdapterArmaDiag::dumpLog() { if (frames.size() == 1 && frames[currentFrame].elements.empty() || frames[currentFrame].scopes.empty()) return intercept::types::r_string(); std::stringstream output; auto baseTimeReference = frameStart; - chrono::milliseconds totalRuntime = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - baseTimeReference); + auto totalRuntime = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - baseTimeReference); output.precision(4); output << "* THREAD! YEAH!\n"; output << std::fixed << "total; " << 0.0 << "; " << totalRuntime.count() << ";\"Frame " << intercept::sqf::diag_frameno() << "\"\n"; @@ -173,7 +168,7 @@ intercept::types::r_string AdapterArmaDiag::dumpLog() { for (size_t i = 0; i < depth; ++i) { output << " "; } - chrono::milliseconds startTime = std::chrono::duration_cast(element->getStartTime() - baseTimeReference); + auto startTime = std::chrono::duration_cast(element->getStartTime() - baseTimeReference); switch (element->type) { case profileElementType::scope: @@ -191,7 +186,7 @@ intercept::types::r_string AdapterArmaDiag::dumpLog() { }; - for (int i = 0; i < frames.size(); ++i) { + for (auto i = 0u; i < frames.size(); ++i) { output << "* Frame " << i << "\n"; iterateElementTree(frames[i], iterateFunc); } diff --git a/src/AdapterArmaDiag.hpp b/src/AdapterArmaDiag.hpp index cadfcf6..87a246f 100644 --- a/src/AdapterArmaDiag.hpp +++ b/src/AdapterArmaDiag.hpp @@ -18,7 +18,7 @@ class ScopeInfoArmaDiag final : public ScopeInfo { class ScopeTempStorageArmaDiag final : public ScopeTempStorage { public: - uint64_t scopeID; + uint64_t scopeID = -1; std::chrono::high_resolution_clock::time_point startTime; }; @@ -36,7 +36,7 @@ class profileElement { std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now(); profileElement(profileElementType _type) : type(_type) {} - virtual ~profileElement() {} + virtual ~profileElement() = default; virtual intercept::types::r_string getAsString() = 0; virtual std::chrono::high_resolution_clock::time_point getStartTime() { return start; } @@ -46,7 +46,7 @@ class profileElement { class profileScope : public profileElement { public: - ~profileScope() override {}; + ~profileScope() override = default; explicit profileScope(uint64_t _scopeID) : profileElement(profileElementType::scope), scopeID(_scopeID) {} intercept::types::r_string getAsString() override { return info->name; }; std::chrono::microseconds getRunTime() override { return runtime; } @@ -58,7 +58,7 @@ class profileScope : public profileElement { class profileLog : public profileElement { public: explicit profileLog(intercept::types::r_string&& _message) : profileElement(profileElementType::log), message(_message) {} - ~profileLog() override {}; + ~profileLog() override = default; intercept::types::r_string getAsString() override { return message; } std::chrono::microseconds getRunTime() override { return std::chrono::microseconds(0); } intercept::types::r_string message; @@ -75,7 +75,7 @@ class AdapterArmaDiag final : public ProfilerAdapter { public: AdapterArmaDiag(); - virtual ~AdapterArmaDiag(); + virtual ~AdapterArmaDiag() = default; std::shared_ptr createScope(intercept::types::r_string name, intercept::types::r_string filename, uint32_t fileline) override; @@ -123,7 +123,7 @@ class AdapterArmaDiag final : public ProfilerAdapter std::chrono::high_resolution_clock::time_point frameStart; uint32_t framesToGo = 0; - void iterateElementTree(const frameData& frame, std::function func); + static void iterateElementTree(const frameData& frame, const std::function& func); }; diff --git a/src/AdapterBrofiler.hpp b/src/AdapterBrofiler.hpp index fa94445..a75e1aa 100644 --- a/src/AdapterBrofiler.hpp +++ b/src/AdapterBrofiler.hpp @@ -1,6 +1,6 @@ #pragma once #include "ProfilerAdapter.hpp" - +#ifdef WITH_BROFILER namespace Brofiler { struct EventData; @@ -38,3 +38,4 @@ class AdapterBrofiler final : public ProfilerAdapter Brofiler::EventData* frameEvent = nullptr; }; +#endif diff --git a/src/AdapterChrome.cpp b/src/AdapterChrome.cpp index 662f966..875d53e 100644 --- a/src/AdapterChrome.cpp +++ b/src/AdapterChrome.cpp @@ -1,6 +1,4 @@ #include "AdapterChrome.hpp" -#include - #include void printClean(std::ofstream& str, intercept::types::r_string string) { @@ -45,9 +43,6 @@ AdapterChrome::AdapterChrome() { type = AdapterType::Chrome; } - -AdapterChrome::~AdapterChrome() {} - void AdapterChrome::perFrame() {} std::shared_ptr AdapterChrome::createScope(intercept::types::r_string name, diff --git a/src/AdapterChrome.hpp b/src/AdapterChrome.hpp index a480976..46c6573 100644 --- a/src/AdapterChrome.hpp +++ b/src/AdapterChrome.hpp @@ -1,4 +1,5 @@ #pragma once +#ifdef WITH_CHROME #include "ProfilerAdapter.hpp" #include @@ -11,7 +12,7 @@ class ScopeInfoChrome final: public ScopeInfo { public: intercept::types::r_string name; intercept::types::r_string file; - uint32_t line; + uint32_t line = 0; }; enum class ChromeEventCategory { @@ -54,7 +55,7 @@ class AdapterChrome final : public ProfilerAdapter { public: AdapterChrome(); - ~AdapterChrome(); + ~AdapterChrome() = default; void perFrame() override; std::shared_ptr createScope(intercept::types::r_string name, intercept::types::r_string filename, uint32_t fileline) override; @@ -73,3 +74,4 @@ class AdapterChrome final : public ProfilerAdapter std::vector storedEvents; }; +#endif \ No newline at end of file diff --git a/src/AdapterTracy.cpp b/src/AdapterTracy.cpp index 8b34a47..0b3aa50 100644 --- a/src/AdapterTracy.cpp +++ b/src/AdapterTracy.cpp @@ -42,7 +42,7 @@ std::shared_ptr AdapterTracy::createScope(intercept::types::r_string auto info = std::make_shared(); info->info = tracy::SourceLocationData{nullptr, std::get<0>(tuple).c_str(), std::get<1>(tuple).c_str(), std::get<2>(tuple), 0}; - auto res = scopeCache.insert({tuple, info}); + scopeCache.insert({tuple, info}); return info; } return found->second; @@ -79,7 +79,7 @@ void AdapterTracy::setCounter(intercept::types::r_string name, float val) { tracy::Profiler::PlotData(name.c_str(), val); } -std::shared_ptr AdapterTracy::createScopeStatic(const char* name, const char* filename, uint32_t fileline) { +std::shared_ptr AdapterTracy::createScopeStatic(const char* name, const char* filename, uint32_t fileline) const { auto info = std::make_shared(); info->info = tracy::SourceLocationData{nullptr, name, filename,fileline, 0}; return info; diff --git a/src/AdapterTracy.hpp b/src/AdapterTracy.hpp index e619a49..54906af 100644 --- a/src/AdapterTracy.hpp +++ b/src/AdapterTracy.hpp @@ -17,11 +17,11 @@ class AdapterTracy final : public ProfilerAdapter void addLog(intercept::types::r_string message) override; void setCounter(intercept::types::r_string name, float val) override; - std::shared_ptr createScopeStatic(const char* name, const char* filename, uint32_t fileline); - bool isConnected(); + std::shared_ptr createScopeStatic(const char* name, const char* filename, uint32_t fileline) const; + static bool isConnected(); private: - void ensureReady(); + static void ensureReady(); using scopeCacheKey = std::tuple; struct ScopeCacheFastEqual { diff --git a/src/ArmaScriptProfiler.vcxproj b/src/ArmaScriptProfiler.vcxproj index 2a72892..aa640db 100644 --- a/src/ArmaScriptProfiler.vcxproj +++ b/src/ArmaScriptProfiler.vcxproj @@ -234,7 +234,9 @@ - + + true + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2f7c37e..b68a6a6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required (VERSION 3.0) +cmake_minimum_required (VERSION 3.13) set(INTERCEPT_CLIENT_PATH "${CMAKE_SOURCE_DIR}/intercept/src/client") set(BROFILER_BASE_PATH "${CMAKE_SOURCE_DIR}/brofiler") @@ -22,31 +22,64 @@ add_definitions(/D_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS) #No I don't cheat! #set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/rv/${INTERCEPT_PLUGIN_NAME}/intercept") -file(GLOB_RECURSE INTERCEPT_ASP_SOURCES *.h *.hpp *.c *.cpp) +file(GLOB_RECURSE INTERCEPT_ASP_SOURCES *.h *.hpp *.c *.cpp *.asm *.s) SOURCE_GROUP("src" FILES ${INTERCEPT_ASP_SOURCES}) file(GLOB INTERCEPT_SOURCES "${INTERCEPT_CLIENT_PATH}/intercept/client/*.cpp" "${INTERCEPT_CLIENT_PATH}/intercept/client/sqf/*.cpp" "${INTERCEPT_CLIENT_PATH}/intercept/shared/*.cpp") SOURCE_GROUP("intercept" FILES ${INTERCEPT_SOURCES}) -file(GLOB BROFILER_SOURCES -"${BROFILER_BASE_PATH}/ThirdParty/TaskScheduler/Scheduler/Source/" -#"${BROFILER_BASE_PATH}/BrofilerCore/CallstackCollector.cpp" -#"${BROFILER_BASE_PATH}/BrofilerCore/Core.cpp" -#"${BROFILER_BASE_PATH}/BrofilerCore/Event.cpp" -#"${BROFILER_BASE_PATH}/BrofilerCore/EventDescriptionBoard.cpp" -#"${BROFILER_BASE_PATH}/BrofilerCore/Message.cpp" -#"${BROFILER_BASE_PATH}/BrofilerCore/ProfilerServer.cpp" -#"${BROFILER_BASE_PATH}/BrofilerCore/Serialization.cpp" -#"${BROFILER_BASE_PATH}/BrofilerCore/SysCallCollector.cpp" -"${BROFILER_BASE_PATH}/BrofilerCore/*.cpp" -"${BROFILER_BASE_PATH}/BrofilerCore/Platform/*.cpp" -) -SOURCE_GROUP("src/brofiler" FILES ${BROFILER_SOURCES}) +if (WITH_BROFILER) + add_compile_definitions(WITH_BROFILER) + file(GLOB BROFILER_SOURCES + "${BROFILER_BASE_PATH}/ThirdParty/TaskScheduler/Scheduler/Source/" + #"${BROFILER_BASE_PATH}/BrofilerCore/CallstackCollector.cpp" + #"${BROFILER_BASE_PATH}/BrofilerCore/Core.cpp" + #"${BROFILER_BASE_PATH}/BrofilerCore/Event.cpp" + #"${BROFILER_BASE_PATH}/BrofilerCore/EventDescriptionBoard.cpp" + #"${BROFILER_BASE_PATH}/BrofilerCore/Message.cpp" + #"${BROFILER_BASE_PATH}/BrofilerCore/ProfilerServer.cpp" + #"${BROFILER_BASE_PATH}/BrofilerCore/Serialization.cpp" + #"${BROFILER_BASE_PATH}/BrofilerCore/SysCallCollector.cpp" + "${BROFILER_BASE_PATH}/BrofilerCore/*.cpp" + "${BROFILER_BASE_PATH}/BrofilerCore/Platform/*.cpp" + "${BROFILER_BASE_PATH}/BrofilerCore/Platform/Windows/*.cpp" + ) + SOURCE_GROUP("src/brofiler" FILES ${BROFILER_SOURCES}) +else() + SET(BROFILER_SOURCES "") + list(REMOVE_ITEM INTERCEPT_ASP_SOURCES "${CMAKE_SOURCE_DIR}/src/AdapterBrofiler.cpp") +endif() + +if (WITH_CHROME) + add_compile_definitions(WITH_CHROME) +else() + list(REMOVE_ITEM INTERCEPT_ASP_SOURCES "${CMAKE_SOURCE_DIR}/src/AdapterChrome.cpp") +endif() + + +if(CMAKE_COMPILER_IS_GNUCXX) + list(REMOVE_ITEM INTERCEPT_ASP_SOURCES "${CMAKE_SOURCE_DIR}/src/hooks.asm") +endif() set(library_sources ${INTERCEPT_ASP_SOURCES}) add_library( ${INTERCEPT_PLUGIN_NAME} SHARED ${library_sources} ${INTERCEPT_SOURCES} ${BROFILER_SOURCES}) + + +if (MSVC AND CMAKE_CL_64) + add_custom_command(TARGET ${INTERCEPT_PLUGIN_NAME} + PRE_BUILD + COMMAND "ml64" /c /W2 /nologo /errorReport:none /Zf + /Fo${CMAKE_BINARY_DIR}/src/CMakeFiles/ArmaScriptProfiler_x64.dir/hooks.asm.obj + #${CMAKE_PROJECT_NAME}.dir/Debug/ + #/Fo"C:/MYPROJECT/Build/Main_ms100_64/MYPROJECT.dir/Debug/" + ${CMAKE_SOURCE_DIR}/src/hooks.asm + COMMENT "Building asm file") +endif() + + + include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${INTERCEPT_INCLUDE_PATH} ) include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${BROFILER_INCLUDE_PATH} ) include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${TRACY_INCLUDE_PATH} ) @@ -58,15 +91,40 @@ target_link_libraries(${INTERCEPT_PLUGIN_NAME} ${LINK_LIBS}) target_link_libraries(${INTERCEPT_PLUGIN_NAME} ${LINK_LIBS}) set_target_properties(${INTERCEPT_PLUGIN_NAME} PROPERTIES PREFIX "") set_target_properties(${INTERCEPT_PLUGIN_NAME} PROPERTIES FOLDER ArmaScriptProfiler) - +message("${CONFIGURATION}") if(CMAKE_COMPILER_IS_GNUCXX) - SET(CMAKE_CXX_FLAGS "-std=c++1z -O2 -s -fPIC -fpermissive -static-libgcc -static-libstdc++")#-march=i686 -m32 + set_source_files_properties(hooks.s PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp") + add_compile_definitions(__linux__) + list(REMOVE_ITEM INTERCEPT_ASP_SOURCES "${CMAKE_SOURCE_DIR}/src/hooks.asm") + + target_compile_options( + ${INTERCEPT_PLUGIN_NAME} PRIVATE + "-std=c++1z" + "-O2" + "-s" + "-fPIC" + "-fpermissive" + "-static-libgcc" + "-static-libstdc++" + "-march=i686" + "-m32" + "-Wno-ignored-attributes" + "-static" + ) + target_link_options(${INTERCEPT_PLUGIN_NAME} PRIVATE "-m32" "-fPIC" "-static" "-static-libgcc" "-static-libstdc++") set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") - set(CMAKE_SHARED_LINKER_FLAGS "-static -static-libgcc -static-libstdc++") else() - set(CMAKE_CXX_FLAGS_DEBUG "/D _DEBUG /MTd /Zi /Ob0 /Od /RTC1 /MP /EHsc") - set(CMAKE_CXX_FLAGS_RELEASE "/MT /Zi /O2 /Ob1 /EHsc /MP") #with debug info - set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "/OPT:REF /DEBUG:FULL") + + target_compile_options( + ${INTERCEPT_PLUGIN_NAME} PRIVATE + "/MP" "/Zi" + "$<$,$>:/MT>" + "$<$,$>:/Ox>" + "$<$,$>:/Ob2>" + "$<$,$>:/Oi>" + "$<$,$>:/Ot>" + ) + target_link_options(${INTERCEPT_PLUGIN_NAME} PRIVATE "/OPT:REF" "/OPT:ICF" "/DEBUG:FULL") endif() diff --git a/src/EngineProfiling.cpp b/src/EngineProfiling.cpp index 23d17f1..8e93b21 100644 --- a/src/EngineProfiling.cpp +++ b/src/EngineProfiling.cpp @@ -118,7 +118,7 @@ EngineProfiling::EngineProfiling() { auto stuffByte = found + 0x2 + 2; - uint32_t offs = *((uint32_t*)stuffByte); + uint32_t offs = *reinterpret_cast(stuffByte); uint64_t addr = stuffByte + 4+1 + offs; uint64_t base = addr - 0x121; @@ -128,18 +128,8 @@ EngineProfiling::EngineProfiling() { armaP->capture = true; //disable captureSlowFrame because it can set forceCapture to false - static auto stuff = intercept::client::host::register_sqf_command("diag_captureSlowFrame", "", [](uintptr_t, game_value_parameter) -> game_value - { - return {}; - }, game_data_type::NOTHING, game_data_type::ARRAY); + //static auto stuff = intercept::client::host::register_sqf_command("diag_captureSlowFrame"sv, ""sv, [](const game_state&, game_value_parameter) -> game_value + // { + // return {}; + // }, game_data_type::NOTHING, game_data_type::ARRAY); } - - -EngineProfiling::~EngineProfiling() {} - - -extern "C" { - - - -} \ No newline at end of file diff --git a/src/EngineProfiling.h b/src/EngineProfiling.h index a9446ba..b69f5a1 100644 --- a/src/EngineProfiling.h +++ b/src/EngineProfiling.h @@ -12,7 +12,7 @@ class PCounter { const char* cat; int slot, stuff2; - __declspec(noinline) bool shouldTime(); + bool shouldTime(); }; @@ -33,14 +33,14 @@ class ScopeProf { bool enabled, other; intercept::types::r_string stuffz; - __declspec(noinline) void doEnd(); + void doEnd(); }; class ArmaProf { friend class PCounter; public: - __declspec(noinline) void scopeCompleted(int64_t start, int64_t end, intercept::types::r_string* stuff, PCounter* stuff2); + void scopeCompleted(int64_t start, int64_t end, intercept::types::r_string* stuff, PCounter* stuff2); public: @@ -101,7 +101,7 @@ class ArmaProf { class EngineProfiling { public: EngineProfiling(); - ~EngineProfiling(); + ~EngineProfiling() = default; ArmaProf* armaP; HookManager hooks; diff --git a/src/HookManager.cpp b/src/HookManager.cpp index dcef513..449e2c9 100644 --- a/src/HookManager.cpp +++ b/src/HookManager.cpp @@ -1,15 +1,33 @@ #include "HookManager.hpp" -#include -#include +#define __linux__ +#ifndef __linux__ +#include +#include #pragma comment (lib, "Psapi.lib")//GetModuleInformation +#else +#include +#endif //This is here because I want to keep includes of windows.h low HookManager::HookManager() { - MODULEINFO modInfo = { 0 }; - HMODULE hModule = GetModuleHandle(NULL); - GetModuleInformation(GetCurrentProcess(), hModule, &modInfo, sizeof(MODULEINFO)); - engineBase = reinterpret_cast(modInfo.lpBaseOfDll); - engineSize = static_cast(modInfo.SizeOfImage); + #ifdef __linux__ + std::ifstream maps("/proc/self/maps"); + uintptr_t start; + uintptr_t end; + char placeholder; + maps >> std::hex >> start >> placeholder >> end; + //link_map *lm = (link_map*) dlopen(0, RTLD_NOW); + //uintptr_t baseAddress = reinterpret_cast(lm->l_addr); + //uintptr_t moduleSize = 35000000; //35MB hardcoded till I find out how to detect it properly + engineBase = start; + engineSize = end - start; + #else + MODULEINFO modInfo = { 0 }; + HMODULE hModule = GetModuleHandle(NULL); + GetModuleInformation(GetCurrentProcess(), hModule, &modInfo, sizeof(MODULEINFO)); + engineBase = reinterpret_cast(modInfo.lpBaseOfDll); + engineSize = static_cast(modInfo.SizeOfImage); + #endif } bool HookManager::placeHook(hookTypes type, const Pattern& pat, uintptr_t jmpTo, uintptr_t & jmpBackRef, uint8_t jmpBackOffset, bool taintRax) { @@ -43,7 +61,7 @@ uintptr_t HookManager::placeHook(uintptr_t offset, uintptr_t jmpTo, uint8_t jmpB } uintptr_t HookManager::placeHookTotalOffs(uintptr_t totalOffset, uintptr_t jmpTo, bool taintRax) { - DWORD dwVirtualProtectBackup; + unsigned long dwVirtualProtectBackup; /* @@ -67,8 +85,9 @@ uintptr_t HookManager::placeHookTotalOffs(uintptr_t totalOffset, uintptr_t jmpTo push rax ret */ - +#ifndef __linux__ VirtualProtect(reinterpret_cast(totalOffset), 12u, 0x40u, &dwVirtualProtectBackup); +#endif auto memberRax = reinterpret_cast(totalOffset); auto jmpInstr1 = reinterpret_cast(totalOffset+1); auto jmpInstr2 = reinterpret_cast(totalOffset+2); @@ -81,10 +100,14 @@ uintptr_t HookManager::placeHookTotalOffs(uintptr_t totalOffset, uintptr_t jmpTo auto pushInstr = reinterpret_cast(totalOffset + 11); *pushInstr = 0x50; //push rax *reinterpret_cast(totalOffset + 12) = 0xc3;//ret + #ifndef __linux__ VirtualProtect(reinterpret_cast(totalOffset), 12u, dwVirtualProtectBackup, &dwVirtualProtectBackup); + #endif return totalOffset + 12; } else { + #ifndef __linux__ VirtualProtect(reinterpret_cast(totalOffset), 14u, 0x40u, &dwVirtualProtectBackup); + #endif auto jmpInstr = reinterpret_cast(totalOffset); auto addrOffs = reinterpret_cast(totalOffset + 1); *jmpInstr = 0x68; //push DWORD @@ -92,18 +115,24 @@ uintptr_t HookManager::placeHookTotalOffs(uintptr_t totalOffset, uintptr_t jmpTo *reinterpret_cast(totalOffset + 5) = 0x042444C7; //MOV [RSP+4], *reinterpret_cast(totalOffset + 9) = static_cast(jmpTo) >> 32;//DWORD *reinterpret_cast(totalOffset + 13) = 0xc3;//ret + #ifndef __linux__ VirtualProtect(reinterpret_cast(totalOffset), 14u, dwVirtualProtectBackup, &dwVirtualProtectBackup); + #endif return totalOffset + 14; } #else + #ifndef __linux__ VirtualProtect(reinterpret_cast(totalOffset), 5u, 0x40u, &dwVirtualProtectBackup); + #endif auto jmpInstr = reinterpret_cast(totalOffset); auto addrOffs = reinterpret_cast(totalOffset + 1); *jmpInstr = 0xE9; *addrOffs = jmpTo - totalOffset - 5; + #ifndef __linux__ VirtualProtect(reinterpret_cast(totalOffset), 5u, dwVirtualProtectBackup, &dwVirtualProtectBackup); + #endif return totalOffset + 5; #endif @@ -111,24 +140,24 @@ uintptr_t HookManager::placeHookTotalOffs(uintptr_t totalOffset, uintptr_t jmpTo } -bool HookManager::MatchPattern(uintptr_t addr, const char* pattern, const char* mask) { - size_t size = strlen(mask); - if (IsBadReadPtr((void*) addr, size)) +bool HookManager::MatchPattern(uintptr_t addr, std::string_view pattern, std::string_view mask) { + size_t size = mask.length(); + #ifndef __linux__ + if (IsBadReadPtr(reinterpret_cast(addr), size)) return false; + #endif bool found = true; for (size_t j = 0; j < size; j++) { - found &= mask[j] == '?' || pattern[j] == *(char*) (addr + j); + found &= mask[j] == '?' || pattern[j] == *reinterpret_cast(addr + j); } - if (found) - return true; - return false; + return found; } -uintptr_t HookManager::findPattern(const char* pattern, const char* mask, uintptr_t offset /*= 0*/) { +uintptr_t HookManager::findPattern(std::string_view pattern, std::string_view mask, uintptr_t offset /*= 0*/) const { uintptr_t base = engineBase; uint32_t size = engineSize; - uintptr_t patternLength = (DWORD) strlen(mask); + uintptr_t patternLength = mask.length(); for (uintptr_t i = 0; i < size - patternLength; i++) { bool found = true; @@ -143,7 +172,7 @@ uintptr_t HookManager::findPattern(const char* pattern, const char* mask, uintpt return 0x0; } -uintptr_t HookManager::findPattern(const Pattern & pat, uintptr_t offset) { +uintptr_t HookManager::findPattern(const Pattern & pat, uintptr_t offset) const { if (pat.offsetFunc) { auto found = findPattern(pat.pattern, pat.mask, pat.offset + offset); if (found) @@ -152,4 +181,4 @@ uintptr_t HookManager::findPattern(const Pattern & pat, uintptr_t offset) { } return findPattern(pat.pattern, pat.mask, pat.offset + offset); -} \ No newline at end of file +} diff --git a/src/HookManager.hpp b/src/HookManager.hpp index 18142ce..ce1d8c7 100644 --- a/src/HookManager.hpp +++ b/src/HookManager.hpp @@ -18,13 +18,13 @@ class HookManager {//Implementation in dllmain public: struct Pattern { - Pattern(const char* _mask, const char* _pattern) : mask(_mask), pattern(_pattern) {} - Pattern(const char* _mask, const char* _pattern, int64_t _offset) : mask(_mask), pattern(_pattern), offset(static_cast(_offset)) {} - Pattern(const char* _mask, const char* _pattern, std::function _offset) : mask(_mask), pattern(_pattern), offsetFunc( + Pattern(std::string_view _mask, std::string_view _pattern) : mask(_mask), pattern(_pattern) {} + Pattern(std::string_view _mask, std::string_view _pattern, int64_t _offset) : mask(_mask), pattern(_pattern), offset(static_cast(_offset)) {} + Pattern(std::string_view _mask, std::string_view _pattern, std::function _offset) : mask(_mask), pattern(_pattern), offsetFunc( std::move( _offset)) {} - const char* mask; - const char* pattern; + std::string_view mask; + std::string_view pattern; uintptr_t offset{ 0 }; std::function offsetFunc; }; @@ -35,9 +35,9 @@ class HookManager {//Implementation in dllmain bool placeHook(hookTypes, const Pattern& pat, uintptr_t jmpTo); uintptr_t placeHook(uintptr_t offset, uintptr_t jmpTo, uint8_t jmpBackOffset = 0); uintptr_t placeHookTotalOffs(uintptr_t offset, uintptr_t jmpTo, bool taintRax = false); - bool MatchPattern(uintptr_t addr, const char* pattern, const char* mask); - uintptr_t findPattern(const char* pattern, const char* mask, uintptr_t offset = 0); - uintptr_t findPattern(const Pattern& pat, uintptr_t offset = 0); + static bool MatchPattern(uintptr_t addr, std::string_view pattern, std::string_view mask); + uintptr_t findPattern(std::string_view pattern, std::string_view mask, uintptr_t offset = 0) const; + uintptr_t findPattern(const Pattern& pat, uintptr_t offset = 0) const; struct PlacedHook { diff --git a/src/hooks.asm b/src/hooks.asm index bf39bee..29d867a 100644 --- a/src/hooks.asm +++ b/src/hooks.asm @@ -1,4 +1,6 @@ option casemap :none +.intel_syntax noprefix + _TEXT SEGMENT ;https://msdn.microsoft.com/en-us/library/windows/hardware/ff561499(v=vs.85).aspx diff --git a/src/hooks.s b/src/hooks.s new file mode 100644 index 0000000..3ab3817 --- /dev/null +++ b/src/hooks.s @@ -0,0 +1,14 @@ +.intel_syntax noprefix +.global _start + + +.text + ########### + .global shouldTime + shouldTime: + jmp _ZN8PCounter10shouldTimeEv + + ########### + .global scopeCompleted + scopeCompleted: + jmp _ZN8ArmaProf14scopeCompletedExxPvPx diff --git a/src/scriptProfiler.cpp b/src/scriptProfiler.cpp index 39461fd..5072b83 100644 --- a/src/scriptProfiler.cpp +++ b/src/scriptProfiler.cpp @@ -2,7 +2,11 @@ #include #include #include +#ifndef __linux__ #include +#else +#include +#endif #include "ProfilerAdapter.hpp" #include "AdapterArmaDiag.hpp" #include "AdapterBrofiler.hpp" @@ -26,7 +30,7 @@ class GameDataProfileScope : public game_data { if (!scopeInfo) return; scopeTempStorage = GProfilerAdapter->enterScope(scopeInfo); - GProfilerAdapter->setThisArgs(scopeTempStorage, thisArgs); + GProfilerAdapter->setThisArgs(scopeTempStorage, std::move(thisArgs)); } ~scopeData() { GProfilerAdapter->leaveScope(scopeTempStorage); @@ -35,14 +39,11 @@ class GameDataProfileScope : public game_data { r_string name; }; - GameDataProfileScope() {} - GameDataProfileScope(std::shared_ptr&& _data) : data(std::move(_data)) {} + GameDataProfileScope() = default; + GameDataProfileScope(std::shared_ptr&& _data) noexcept : data(std::move(_data)) {} void lastRefDeleted() const override { delete this; } const sqf_script_type& type() const override { return GameDataProfileScope_type; } - ~GameDataProfileScope() override { - - } - + ~GameDataProfileScope() override = default; bool get_as_bool() const override { return true; } float get_as_number() const override { return 0.f; } const r_string& get_as_string() const override { return data->name; } @@ -79,42 +80,45 @@ class GameInstructionProfileScopeStart : public game_instruction { } bool exec(game_state& state, vm_context& ctx) override { - static r_string lastScopeStart = ""; + static r_string lastScopeStart; if ((!GProfilerAdapter->IsScheduledSupported() &&/*ctx.scheduled || */sqf::can_suspend()) || (lastScopeStart.length() && lastScopeStart == name)) return false; auto data = std::make_shared(name, +#ifdef __linux__ + game_value(), +#else state.eval->local->variables.get("_this").value, +#endif scopeInfo); - state.eval->local->variables.insert( - game_variable("1scp"sv, game_value(new GameDataProfileScope(std::move(data))), false) - ); - lastScopeStart = name; - - +#ifdef WITH_CHROME if (GProfilerAdapter->IsScheduledSupported() && sqf::can_suspend()) { if (auto chromeStorage = std::dynamic_pointer_cast(data->scopeTempStorage)) chromeStorage->threadID = reinterpret_cast(&ctx); } +#endif - + state.eval->local->variables.insert( + game_variable("1scp"sv, game_value(new GameDataProfileScope(std::move(data))), false) + ); + lastScopeStart = name; return false; } int stack_size(void* t) const override { return 0; } r_string get_name() const override { return "GameInstructionProfileScopeStart"sv; } - ~GameInstructionProfileScopeStart() override {} + ~GameInstructionProfileScopeStart() override = default; }; -game_value createProfileScope(uintptr_t st, game_value_parameter name) { +game_value createProfileScope(const game_state& state, game_value_parameter name) { if (sqf::can_suspend()) return {}; static r_string profName("scriptProfiler.cpp"); - game_state* state = (game_state*) st; auto data = std::make_shared(name, - sqf::str(state->eval->local->variables.get("_this").value), //#TODO remove this. We don't want this - GProfilerAdapter->createScope((r_string)name, profName, __LINE__) + //sqf::str(state.eval->local->variables.get("_this").value), //#TODO remove this. We don't want this + game_value(), + GProfilerAdapter->createScope(static_cast(name), profName, __LINE__) ); //#TODO retrieve line from callstack return game_value(new GameDataProfileScope(std::move(data))); @@ -165,18 +169,18 @@ game_value profilerLog(uintptr_t, game_value_parameter message) { return {}; } -game_value profilerSetOutputFile(uintptr_t st, game_value_parameter file) { - +game_value profilerSetOutputFile(const game_state& state, game_value_parameter file) { +#ifdef WITH_CHROME auto chromeAdapter = std::dynamic_pointer_cast(GProfilerAdapter); if (!chromeAdapter) { - game_state* state = reinterpret_cast(st); - state->eval->_errorMessage = "not using ChromeAdapter"; - state->eval->_errorType = game_state::game_evaluator::evaluator_error_type::tg90; //No idea what tg90 is.. + state.eval->_errorMessage = "not using ChromeAdapter"; + state.eval->_errorType = game_state::game_evaluator::evaluator_error_type::tg90; //No idea what tg90 is.. return {}; } chromeAdapter->setTargetFile(static_cast(static_cast(file))); +#endif return {}; } @@ -194,8 +198,7 @@ game_value profilerSetCounter(uintptr_t st, game_value_parameter name, game_valu } //profiles script like diag_codePerformance -game_value profileScript(uintptr_t stat, game_value_parameter par) { - game_state* state = (game_state*) stat; +game_value profileScript(const game_state& state, game_value_parameter par) { code _code = par[0]; int runs = par.get(2).value_or(10000); @@ -204,7 +207,7 @@ game_value profileScript(uintptr_t stat, game_value_parameter par) { //CBA fastForEach if (par.get(1) && !par[1].is_nil()) { - state->eval->local->variables.insert({ "_this"sv, par[1] }); + state.eval->local->variables.insert({ "_this"sv, par[1] }); } //prep for action @@ -363,7 +366,7 @@ std::string getScriptFromFirstLine(sourcedocpos& pos, bool compact) {//https://g else if (output.front() == '\n') { output.erase(0, 1); } else { - output.replace(0, output.find("\n"), 1, '\n'); + output.replace(0, output.find('\n'), 1, '\n'); } } }; @@ -386,7 +389,7 @@ std::string getScriptFromFirstLine(sourcedocpos& pos, bool compact) {//https://g if (number < curLine) removeEmptyLines((curLine - number)); curLine = number; } - if (*(nameEnd + 1) == '\r') nameEnd++; + if (*(nameEnd + 1) == '\r') ++nameEnd; curPos = nameEnd + 2; //if (inWantedFile && *curPos == '\n') { // curPos++; @@ -401,8 +404,7 @@ std::string getScriptFromFirstLine(sourcedocpos& pos, bool compact) {//https://g } - if (curPos > end) return false; - return true; + return curPos <= end; }; auto readLine = [&]() { if (curPos > end) return false; @@ -419,7 +421,7 @@ std::string getScriptFromFirstLine(sourcedocpos& pos, bool compact) {//https://g while (readLine()) {}; if (compact) { //http://stackoverflow.com/a/24315631 - size_t start_pos = 0; + size_t start_pos; while ((start_pos = output.find("\n\n\n", 0)) != std::string::npos) { output.replace(start_pos, 3, "\n"); } @@ -454,7 +456,8 @@ static struct { class GameInstructionConst : public game_instruction { public: game_value value; - virtual bool exec(game_state& state, vm_context& t) { + + bool exec(game_state& state, vm_context& t) override { //static const r_string InstrName = "I_Const"sv; //static Brofiler::EventDescription* autogenerated_description = ::Brofiler::EventDescription::Create(InstrName, __FILE__, __LINE__); //Brofiler::Event autogenerated_event_639(*autogenerated_description); @@ -462,19 +465,26 @@ class GameInstructionConst : public game_instruction { //if (autogenerated_event_639.data) // autogenerated_event_639.data->thisArgs = value; - typedef bool(__thiscall *OrigEx)(game_instruction*, game_state&, vm_context&); + typedef bool( +#ifndef __linux__ + __thiscall +#endif + *OrigEx)(game_instruction*, game_state&, vm_context&); return reinterpret_cast(oldFunc.vt_GameInstructionConst)(this, state, t); } - virtual int stack_size(void* t) const { return 0; } - virtual r_string get_name() const { return ""sv; } + + int stack_size(void* t) const override { return 0; } + r_string get_name() const override { return ""sv; } }; -void addScopeInstruction(game_data_code* bodyCode, std::string scriptName) { +void addScopeInstruction(game_data_code* bodyCode, const std::string& scriptName) { +#ifndef __linux__ #ifndef _WIN64 #error "no x64 hash codes yet" +#endif #endif auto lt = typeid(bodyCode->instructions->data()[0]).hash_code(); auto rt = typeid(GameInstructionProfileScopeStart).hash_code(); @@ -484,7 +494,7 @@ void addScopeInstruction(game_data_code* bodyCode, std::string scriptName) { auto& funcPath = bodyCode->instructions->front()->sdp.sourcefile; - r_string src = getScriptFromFirstLine(bodyCode->instructions->front()->sdp, false); + //r_string src = getScriptFromFirstLine(bodyCode->instructions->front()->sdp, false); @@ -507,14 +517,23 @@ void addScopeInstruction(game_data_code* bodyCode, std::string scriptName) { bodyCode->instructions = newInstr; - - static const size_t ConstTypeIDHash = 0x0a56f03038a03360; +#ifdef __linux__ + static const size_t ConstTypeIDHash = 600831349; +#else + static const size_t ConstTypeIDHash = 0x0a56f03038a03360ull; +#endif for (auto& it : *bodyCode->instructions) { auto typeHash = typeid(*it.get()).hash_code(); - auto typeN = typeid(*it.get()).raw_name(); + + //linux + //auto typeN = typeid(*it.get()).name(); + //std::string stuff = std::to_string(typeHash) + " " + typeN; + //sqf::diag_log(stuff); + + if (typeHash != ConstTypeIDHash) continue; - GameInstructionConst* inst = static_cast(it.get()); - if (inst->value.type_enum() != GameDataType::CODE) continue; + auto inst = static_cast(it.get()); + if (inst->value.type_enum() != game_data_type::CODE) continue; auto bodyCode = static_cast(inst->value.data.get()); if (bodyCode->instructions && bodyCode->instructions->size() > 20) @@ -523,7 +542,7 @@ void addScopeInstruction(game_data_code* bodyCode, std::string scriptName) { } -game_value compileRedirect2(uintptr_t st, game_value_parameter message) { +game_value compileRedirect2(const game_state& state, game_value_parameter message) { if (!profiler.compileScope) { static r_string compileEventText("compile"); static r_string profName("scriptProfiler.cpp"); @@ -532,7 +551,6 @@ game_value compileRedirect2(uintptr_t st, game_value_parameter message) { auto tempData = GProfilerAdapter->enterScope(profiler.compileScope); - game_state* state = reinterpret_cast(st); r_string str = message; auto comp = sqf::compile(str); @@ -542,10 +560,12 @@ game_value compileRedirect2(uintptr_t st, game_value_parameter message) { return comp; } +#ifdef WITH_BROFILER if (auto brofilerData = std::dynamic_pointer_cast(tempData)) { r_string src = getScriptFromFirstLine(bodyCode->instructions->front()->sdp, false); brofilerData->evtDt->sourceCode = src; } +#endif GProfilerAdapter->leaveScope(tempData); @@ -570,10 +590,12 @@ game_value callExtensionRedirect(uintptr_t st, game_value_parameter ext, game_va auto res = sqf::call_extension(ext,msg); +#ifdef WITH_BROFILER if (auto brofilerData = std::dynamic_pointer_cast(tempData)) { brofilerData->evtDt->thisArgs = ext; brofilerData->evtDt->sourceCode = msg; } +#endif GProfilerAdapter->leaveScope(tempData); @@ -581,21 +603,34 @@ game_value callExtensionRedirect(uintptr_t st, game_value_parameter ext, game_va } game_value diag_logRedirect(uintptr_t st, game_value_parameter msg) { - r_string str = (r_string)msg; + r_string str = static_cast(msg); GProfilerAdapter->addLog(str); sqf::diag_log(msg); return {}; } - +std::string get_command_line() { +#if __linux__ + std::ifstream cmdline("/proc/self/cmdline"); + std::string file_contents; + std::string line; + while (std::getline(cmdline, line)) { + file_contents += line; + file_contents.push_back('\n'); //#TODO can linux even have more than one line? + } + return file_contents; +#else + return GetCommandLineA(); +#endif +} std::optional getCommandLineParam(std::string_view needle) { - std::string commandLine = GetCommandLineA(); - auto found = commandLine.find(needle); + std::string commandLine = get_command_line(); + const auto found = commandLine.find(needle); if (found != std::string::npos) { - auto spacePos = commandLine.find(' ', found + needle.length() + 1); - auto valueLength = spacePos - (found + needle.length() + 1); + const auto spacePos = commandLine.find(' ', found + needle.length() + 1); + const auto valueLength = spacePos - (found + needle.length() + 1); auto adapterStr = commandLine.substr(found + needle.length() + 1, valueLength); if (adapterStr.back() == '"') adapterStr = adapterStr.substr(0, adapterStr.length() - 1); @@ -605,8 +640,6 @@ std::optional getCommandLineParam(std::string_view needle) { } scriptProfiler::scriptProfiler() { - std::string commandLine = GetCommandLineA(); - if (getCommandLineParam("-profilerEnableInstruction"sv)) { instructionLevelProfiling = true; } @@ -614,15 +647,20 @@ scriptProfiler::scriptProfiler() { auto startAdapter = getCommandLineParam("-profilerAdapter"sv); if (startAdapter) { - if (*startAdapter == "Chrome"sv) { + if (false) { +#ifdef WITH_CHROME + } else if (*startAdapter == "Chrome"sv) { auto chromeAdapter = std::make_shared(); GProfilerAdapter = chromeAdapter; auto chromeOutput = getCommandLineParam("-profilerOutput"sv); if (chromeOutput) chromeAdapter->setTargetFile(*chromeOutput); +#endif +#ifdef WITH_BROFILER } else if (*startAdapter == "Brofiler"sv) { GProfilerAdapter = std::make_shared(); +#endif } else if (*startAdapter == "Arma"sv) { GProfilerAdapter = std::make_shared(); } else if (*startAdapter == "Tracy"sv) { @@ -634,10 +672,7 @@ scriptProfiler::scriptProfiler() { } - - -scriptProfiler::~scriptProfiler() {} - +#ifndef __linux__ #pragma region Instructions namespace intercept::__internal { @@ -715,7 +750,7 @@ namespace intercept::__internal { class game_functions : public auto_array, public gsFuncBase { public: - game_functions(std::string name) : _name(name.c_str()) {} + game_functions(r_string name) : _name(std::move(name)) {} r_string _name; game_functions() noexcept {} const char *get_map_key() const noexcept { return _name.data(); } @@ -723,7 +758,7 @@ namespace intercept::__internal { class game_operators : public auto_array, public gsFuncBase { public: - game_operators(std::string name) : _name(name.c_str()) {} + game_operators(r_string name) : _name(std::move(name)) {} r_string _name; int32_t placeholder10{ 4 }; //0x2C Small int 0-5 priority game_operators() noexcept {} @@ -943,13 +978,13 @@ class GameInstructionNewExpression : public game_instruction { }; #pragma endregion Instructions - +#endif void scriptProfiler::preStart() { - + #ifndef __linux__ if (getCommandLineParam("-profilerEnableEngine"sv)) { engineProf = std::make_shared(); } - + #endif static auto codeType = client::host::register_sqf_type("ProfileScope"sv, "ProfileScope"sv, "Dis is a profile scope. It profiles things."sv, "ProfileScope"sv, createGameDataProfileScope); GameDataProfileScope_type = codeType.second; static auto _createProfileScope = client::host::register_sqf_command("createProfileScope", "Creates a ProfileScope", createProfileScope, codeType.first, game_data_type::STRING); @@ -973,7 +1008,7 @@ void scriptProfiler::preStart() { static auto _profilerDiagLog = client::host::register_sqf_command("diag_log", "Profiler redirect", diag_logRedirect, game_data_type::NOTHING, game_data_type::ANY); static auto _profilerProfScript = client::host::register_sqf_command("profileScript", "Profiler redirect", profileScript, game_data_type::ARRAY, game_data_type::ARRAY); - +#ifndef __linux__ auto iface = client::host::request_plugin_interface("sqf_asm_devIf", 1); if (iface) { GVt = *static_cast(*iface); @@ -1030,7 +1065,7 @@ void scriptProfiler::preStart() { //VirtualProtect(reinterpret_cast(GVt.vt_GameInstructionNewExpression), 14u, dwVirtualProtectBackup, &dwVirtualProtectBackup); //delete ins; } - +#endif } @@ -1041,13 +1076,17 @@ void scriptProfiler::perFrame() { GProfilerAdapter->perFrame(); if (!waitForAdapter.empty()) { - if (waitForAdapter == "Chrome") { + if (false) { +#ifdef WITH_CHROME + } else if (waitForAdapter == "Chrome") { auto chromeAdapter = std::dynamic_pointer_cast(GProfilerAdapter); if (!chromeAdapter) { std::shared_ptr newAdapter = std::make_shared(); GProfilerAdapter.swap(newAdapter); newAdapter->cleanup(); } +#endif +#ifdef WITH_BROFILER } else if (waitForAdapter == "Brofiler") { auto brofilerAdapter = std::dynamic_pointer_cast(GProfilerAdapter); if (!brofilerAdapter) { @@ -1055,6 +1094,7 @@ void scriptProfiler::perFrame() { GProfilerAdapter.swap(newAdapter); newAdapter->cleanup(); } +#endif } else if (waitForAdapter == "Arma") { auto armaAdapter = std::dynamic_pointer_cast(GProfilerAdapter); if (!armaAdapter) { diff --git a/src/scriptProfiler.hpp b/src/scriptProfiler.hpp index aa3f8f4..833e92a 100644 --- a/src/scriptProfiler.hpp +++ b/src/scriptProfiler.hpp @@ -7,7 +7,7 @@ class scriptProfiler { public: scriptProfiler(); - ~scriptProfiler(); + ~scriptProfiler() = default; void preStart(); void perFrame(); void preInit(); diff --git a/tracy b/tracy index f474669..39680ad 160000 --- a/tracy +++ b/tracy @@ -1 +1 @@ -Subproject commit f474669ab5f6bb7a2e0c9c43245be3960699e441 +Subproject commit 39680ad315447827ed69946eac93433890b5f1e1