From 01d1f0a250eed1478300ca1bfca8a0a8f616337c Mon Sep 17 00:00:00 2001 From: yyc12345 Date: Wed, 20 Sep 2023 22:26:39 +0800 Subject: [PATCH] add coredump tools --- IronPad/IronPad.cpp | 300 ++++++++++++++++++++++++++++++++ IronPad/IronPad.hpp | 26 +++ IronPad/IronPad.vcxproj | 186 ++++++++++++++++++++ IronPad/IronPad.vcxproj.filters | 27 +++ Unvirt/Unvirt.cpp | 17 +- Unvirt/Unvirt.vcxproj | 24 +-- Unvirt/UnvirtContext.cpp | 3 +- libcmo21.sln | 14 ++ 8 files changed, 574 insertions(+), 23 deletions(-) create mode 100644 IronPad/IronPad.cpp create mode 100644 IronPad/IronPad.hpp create mode 100644 IronPad/IronPad.vcxproj create mode 100644 IronPad/IronPad.vcxproj.filters diff --git a/IronPad/IronPad.cpp b/IronPad/IronPad.cpp new file mode 100644 index 0000000..f9e02d5 --- /dev/null +++ b/IronPad/IronPad.cpp @@ -0,0 +1,300 @@ +#include "IronPad.hpp" +#include +#include +#include +#include +#include + +namespace IronPad { + +#if defined(IRONPAD_ENABLED) + + /** + * @brief true if the exception handler already registered. + * This variable is served for singleton. + */ + static bool g_IsRegistered = false; + /** + * @brief true if a exception handler is running. + * This variable is served for blocking possible infinity recursive exception handling. + */ + static bool g_IsProcessing = false; + /** + * @brief The backup of original exception handler. + */ + LPTOP_LEVEL_EXCEPTION_FILTER g_ProcBackup; + +#pragma region Exception Handler Detail + + static const char* UExceptionGetCodeName(DWORD code) { + switch (code) { + case EXCEPTION_ACCESS_VIOLATION: + return "access violation"; + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + return "array index out of bound"; + case EXCEPTION_BREAKPOINT: + return "breakpoint reached"; + case EXCEPTION_DATATYPE_MISALIGNMENT: + return "misaligned data access"; + case EXCEPTION_FLT_DENORMAL_OPERAND: + return "operand had denormal value"; + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + return "floating-point division by zero"; + case EXCEPTION_FLT_INEXACT_RESULT: + return "no decimal fraction representation for value"; + case EXCEPTION_FLT_INVALID_OPERATION: + return "invalid floating-point operation"; + case EXCEPTION_FLT_OVERFLOW: + return "floating-point overflow"; + case EXCEPTION_FLT_STACK_CHECK: + return "floating-point stack corruption"; + case EXCEPTION_FLT_UNDERFLOW: + return "floating-point underflow"; + case EXCEPTION_ILLEGAL_INSTRUCTION: + return "illegal instruction"; + case EXCEPTION_IN_PAGE_ERROR: + return "inaccessible page"; + case EXCEPTION_INT_DIVIDE_BY_ZERO: + return "integer division by zero"; + case EXCEPTION_INT_OVERFLOW: + return "integer overflow"; + case EXCEPTION_INVALID_DISPOSITION: + return "documentation says this should never happen"; + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + return "can't continue after a noncontinuable exception"; + case EXCEPTION_PRIV_INSTRUCTION: + return "attempted to execute a privileged instruction"; + case EXCEPTION_SINGLE_STEP: + return "one instruction has been executed"; + case EXCEPTION_STACK_OVERFLOW: + return "stack overflow"; + } + return "unknown exception"; + } + + static void UExceptionFormat(std::FILE* fs, const char* fmt, ...) { + // write to file + va_list arg1; + va_start(arg1, fmt); + std::vfprintf(fs, fmt, arg1); + va_end(arg1); + // write to stdout + va_list arg2; + va_start(arg2, fmt); + std::vfprintf(stdout, fmt, arg2); + va_end(arg2); + } + + static void UExceptionPrint(std::FILE* fs, const char* strl) { + // write to file + std::fputs(strl, fs); + // write to stdout + std::fputs(strl, stdout); + } + + static void UExceptionBacktrace(FILE* fs, LPCONTEXT context, int maxdepth) { + // setup loading symbol options + SymSetOptions(SymGetOptions() | SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES); // lazy load symbol, and load line number. + + // setup handle + HANDLE process = GetCurrentProcess(); + HANDLE thread = GetCurrentThread(); + + // init symbol + if (!SymInitialize(process, 0, TRUE)) { + // fail to load. return + UExceptionPrint(fs, "Lost symbol file!\n"); + return; + } + + // ========== CORE DUMP ========== + // prepare frame. setup correct fields + DWORD machine_type = 0; + STACKFRAME64 frame; + memset(&frame, 0, sizeof(frame)); +#if defined(_M_IX86) || defined(__i386__) + machine_type = IMAGE_FILE_MACHINE_I386; + frame.AddrPC.Offset = context->Eip; + frame.AddrStack.Offset = context->Esp; + frame.AddrFrame.Offset = context->Ebp; +#elif defined(_M_IX64) || defined(__amd64__) + machine_type = IMAGE_FILE_MACHINE_AMD64; + frame.AddrPC.Offset = context->Rip; + frame.AddrStack.Offset = context->Rsp; + frame.AddrFrame.Offset = context->Rbp; +#else +#error "Unsupported platform" + //IA-64 anybody? +#endif + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrStack.Mode = AddrModeFlat; + frame.AddrFrame.Mode = AddrModeFlat; + + // other variables + char module_name_raw[MAX_PATH]; + + // stack walker + while (StackWalk64(machine_type, process, thread, &frame, context, + 0, SymFunctionTableAccess64, SymGetModuleBase64, 0)) { + + // depth breaker + --maxdepth; + if (maxdepth < 0) { + UExceptionPrint(fs, "...\n"); // indicate there are some frames not listed + break; + } + + // get module name + DWORD64 module_base = SymGetModuleBase64(process, frame.AddrPC.Offset); + const char* module_name = "[unknown module]"; + if (module_base && GetModuleFileNameA((HINSTANCE)module_base, module_name_raw, MAX_PATH)) { + module_name = module_name_raw; + } + + // get source file and line + const char* source_file = "[unknow_source_file]"; + DWORD64 source_file_line = 0; + DWORD dwDisplacement; + IMAGEHLP_LINE64 winline; + winline.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + if (SymGetLineFromAddr64(process, frame.AddrPC.Offset, &dwDisplacement, &winline)) { + source_file = winline.FileName; + source_file_line = winline.LineNumber; + } + + // write to file + UExceptionFormat(fs, "0x%016llx(rel: 0x%016llx)[%s]\t%s#%llu\n", + frame.AddrPC.Offset, frame.AddrPC.Offset - module_base, module_name, + source_file, source_file_line + ); + + } + + // ========== END CORE DUMP ========== + + // free symbol + SymCleanup(process); + } + + static void UExceptionCoreDump(LPCWSTR filename, LPEXCEPTION_POINTERS info) { + // setup handle + HANDLE hProcess = GetCurrentProcess(); + DWORD dwProcessId = GetCurrentProcessId(); + DWORD dwThreadId = GetCurrentThreadId(); + + // open file and write + if (hProcess != INVALID_HANDLE_VALUE) { + HANDLE hFile = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile != INVALID_HANDLE_VALUE) { + MINIDUMP_EXCEPTION_INFORMATION exception_info; + exception_info.ThreadId = dwThreadId; + exception_info.ExceptionPointers = info; + exception_info.ClientPointers = TRUE; + MiniDumpWriteDump(hProcess, dwProcessId, hFile, MiniDumpWithFullMemory, &exception_info, NULL, NULL); + CloseHandle(hFile); + } + } + } + + static LONG WINAPI UExceptionImpl(LPEXCEPTION_POINTERS info) { + // detect loop calling + if (g_IsProcessing) { + goto end_proc; + } + // start process + g_IsProcessing = true; + + { + // get main folder first + std::filesystem::path ironpad_path; + WCHAR module_path[MAX_PATH]; + std::memset(module_path, 0, sizeof(module_path)); + if (GetModuleFileNameW(NULL, module_path, MAX_PATH) == 0) { + goto failed; + } + ironpad_path = module_path; + ironpad_path = ironpad_path.parent_path(); + + // create 2 filename + auto logfilename = ironpad_path / "IronPad.log"; + auto dmpfilename = ironpad_path / "IronPad.dmp"; + std::fputc('\n', stdout); + std::fprintf(stdout, "Exception Log: %s\n", logfilename.string().c_str()); + std::fprintf(stdout, "Exception Coredump: %s\n", dmpfilename.string().c_str()); + + // output log file + { + std::FILE* fs = _wfopen(logfilename.wstring().c_str(), L"w"); + if (fs == nullptr) { + goto failed; + } + + // record exception type first + PEXCEPTION_RECORD rec = info->ExceptionRecord; + fprintf(fs, "Unhandled exception occured at 0x%08p: %s (%lu).\n", + rec->ExceptionAddress, + UExceptionGetCodeName(rec->ExceptionCode), + rec->ExceptionCode + ); + + // special proc for 2 exceptions + if (rec->ExceptionCode == EXCEPTION_ACCESS_VIOLATION || rec->ExceptionCode == EXCEPTION_IN_PAGE_ERROR) { + if (rec->NumberParameters >= 2) { + const char* op = + rec->ExceptionInformation[0] == 0 ? "read" : + rec->ExceptionInformation[0] == 1 ? "written" : "executed"; + fprintf(fs, "The data at memory address 0x%08x could not be %s.\n", + rec->ExceptionInformation[1], op); + } + } + + // output stacktrace + UExceptionBacktrace(fs, info->ContextRecord, 1024); + + std::fclose(fs); + } + + // output minidump + { + UExceptionCoreDump(dmpfilename.wstring().c_str(), info); + } + + } + + // end process + failed: + g_IsProcessing = false; + // if backup proc can be run, run it + // otherwise directly return. + end_proc: + if (g_ProcBackup != nullptr) { + return g_ProcBackup(info); + } else { + return EXCEPTION_CONTINUE_SEARCH; + } + } + +#pragma endregion + + void IronPadRegister() { + if (g_IsRegistered) return; + g_ProcBackup = SetUnhandledExceptionFilter(UExceptionImpl); + g_IsRegistered = true; + } + + void IronPadUnregister() { + if (!g_IsRegistered) return; + SetUnhandledExceptionFilter(g_ProcBackup); + g_IsRegistered = false; + } + +#else + + // blank implement + + void IronPadRegister() {} + void IronPadUnregister() {} + +#endif + + } diff --git a/IronPad/IronPad.hpp b/IronPad/IronPad.hpp new file mode 100644 index 0000000..67c2874 --- /dev/null +++ b/IronPad/IronPad.hpp @@ -0,0 +1,26 @@ +#pragma once + +// only include VTUtils to get essential macro +#include + +#if defined(LIBCMO_BUILD_RELEASE) && defined(LIBCMO_OS_WIN32) +#define IRONPAD_ENABLED 1 +#endif + +// Debug IronPad used. Force enable IronPad. +#define IRONPAD_ENABLED 1 + +namespace IronPad { + + /** + * @brief Register IronPad. + * @detail This function frequently called at the start of program. + */ + void IronPadRegister(); + /** + * @brief Unregiister IronPad + * @detail This function frequently called at the end of program. + */ + void IronPadUnregister(); + +} diff --git a/IronPad/IronPad.vcxproj b/IronPad/IronPad.vcxproj new file mode 100644 index 0000000..6f4a752 --- /dev/null +++ b/IronPad/IronPad.vcxproj @@ -0,0 +1,186 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {a6454164-2153-45ae-bdb8-19c77014e0cc} + IronPad + 10.0 + + + + StaticLibrary + true + v142 + Unicode + + + StaticLibrary + false + v142 + true + Unicode + + + StaticLibrary + true + v142 + Unicode + + + StaticLibrary + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)temp\$(Platform)\$(Configuration)\$(ProjectName)\ + + + false + $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)temp\$(Platform)\$(Configuration)\$(ProjectName)\ + + + true + $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)temp\$(Platform)\$(Configuration)\$(ProjectName)\ + + + false + $(SolutionDir)out\$(Platform)\$(Configuration)\$(ProjectName)\ + $(SolutionDir)temp\$(Platform)\$(Configuration)\$(ProjectName)\ + + + + Level4 + true + LIBCMO_BUILD_DEBUG;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ZLIB_PATH);../LibCmo;$(STB_PATH);%(AdditionalIncludeDirectories) + stdcpp20 + /utf-8 %(AdditionalOptions) + true + + + Console + true + %(AdditionalDependencies) + + + + + Level4 + true + true + true + LIBCMO_BUILD_RELEASE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ZLIB_PATH);../LibCmo;$(STB_PATH);%(AdditionalIncludeDirectories) + stdcpp20 + /utf-8 %(AdditionalOptions) + true + + + Console + true + true + true + %(AdditionalDependencies) + + + + + Level4 + true + LIBCMO_BUILD_DEBUG;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ZLIB_PATH);../LibCmo;$(STB_PATH);%(AdditionalIncludeDirectories) + stdcpp20 + /utf-8 %(AdditionalOptions) + true + + + Console + true + + + %(AdditionalDependencies) + + + + + Level4 + true + true + true + LIBCMO_BUILD_RELEASE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(ZLIB_PATH);../LibCmo;$(STB_PATH);%(AdditionalIncludeDirectories) + stdcpp20 + /utf-8 %(AdditionalOptions) + true + + + Console + true + true + true + + + %(AdditionalDependencies) + + + + + + + + + + + + \ No newline at end of file diff --git a/IronPad/IronPad.vcxproj.filters b/IronPad/IronPad.vcxproj.filters new file mode 100644 index 0000000..be7e0b3 --- /dev/null +++ b/IronPad/IronPad.vcxproj.filters @@ -0,0 +1,27 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Headers + + + + + Sources + + + \ No newline at end of file diff --git a/Unvirt/Unvirt.cpp b/Unvirt/Unvirt.cpp index 398d08a..631dce9 100644 --- a/Unvirt/Unvirt.cpp +++ b/Unvirt/Unvirt.cpp @@ -1,19 +1,16 @@ #include "UnvirtContext.hpp" +#include int main(int argc, char* argv[]) { - //LibCmo::CK2::CKMinContext vtctx; - //vtctx.SetTempPath("Temp"); - //vtctx.SetEncoding("850"); - - //LibCmo::CK2::CKFile vtfile(&vtctx); - //LibCmo::CK2::CKFileDocument* doc; - //LibCmo::CK2::CKERROR err = vtfile.DeepLoad("Level_02.NMO", &doc); - - //if (doc) - // Unvirt::StructFormatter::PrintCKFileInfo(doc->m_FileInfo); + // start iron pad + IronPad::IronPadRegister(); + Unvirt::Context::UnvirtContext ctx; ctx.Run(); + // stop iron pad + IronPad::IronPadUnregister(); + return 0; } diff --git a/Unvirt/Unvirt.vcxproj b/Unvirt/Unvirt.vcxproj index 2dc91e6..4d9e252 100644 --- a/Unvirt/Unvirt.vcxproj +++ b/Unvirt/Unvirt.vcxproj @@ -100,7 +100,7 @@ true LIBCMO_BUILD_DEBUG;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - $(ZLIB_PATH);../LibCmo;$(STB_PATH);%(AdditionalIncludeDirectories) + $(ZLIB_PATH);../LibCmo;../IronPad;$(STB_PATH);%(AdditionalIncludeDirectories) stdcpp20 /utf-8 %(AdditionalOptions) true @@ -108,8 +108,8 @@ Console true - zlibwapi.lib;LibCmo.lib;%(AdditionalDependencies) - $(ZLIB_PATH)\contrib\vstudio\vc14\x86\ZlibDllReleaseWithoutAsm;$(SolutionDir)out\$(Platform)\$(Configuration)\LibCmo;$(FFMPEG_WIN32_LIB_PATH) + zlibwapi.lib;LibCmo.lib;IronPad.lib;Dbghelp.lib;%(AdditionalDependencies) + $(ZLIB_PATH)\contrib\vstudio\vc14\x86\ZlibDllReleaseWithoutAsm;$(SolutionDir)out\$(Platform)\$(Configuration)\LibCmo;$(SolutionDir)out\$(Platform)\$(Configuration)\IronPad; @@ -120,7 +120,7 @@ true LIBCMO_BUILD_RELEASE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true - $(ZLIB_PATH);../LibCmo;$(STB_PATH);%(AdditionalIncludeDirectories) + $(ZLIB_PATH);../LibCmo;../IronPad;$(STB_PATH);%(AdditionalIncludeDirectories) stdcpp20 /utf-8 %(AdditionalOptions) true @@ -130,8 +130,8 @@ true true true - zlibwapi.lib;LibCmo.lib;%(AdditionalDependencies) - $(ZLIB_PATH)\contrib\vstudio\vc14\x86\ZlibDllReleaseWithoutAsm;$(SolutionDir)out\$(Platform)\$(Configuration)\LibCmo;$(FFMPEG_WIN32_LIB_PATH) + zlibwapi.lib;LibCmo.lib;IronPad.lib;Dbghelp.lib;%(AdditionalDependencies) + $(ZLIB_PATH)\contrib\vstudio\vc14\x86\ZlibDllReleaseWithoutAsm;$(SolutionDir)out\$(Platform)\$(Configuration)\LibCmo;$(SolutionDir)out\$(Platform)\$(Configuration)\IronPad; @@ -140,7 +140,7 @@ true LIBCMO_BUILD_DEBUG;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - $(ZLIB_PATH);../LibCmo;$(STB_PATH);%(AdditionalIncludeDirectories) + $(ZLIB_PATH);../LibCmo;../IronPad;$(STB_PATH);%(AdditionalIncludeDirectories) stdcpp20 /utf-8 %(AdditionalOptions) true @@ -148,8 +148,8 @@ Console true - zlibwapi.lib;LibCmo.lib;%(AdditionalDependencies) - $(ZLIB_PATH)\contrib\vstudio\vc14\x64\ZlibDllReleaseWithoutAsm;$(SolutionDir)out\$(Platform)\$(Configuration)\LibCmo;$(FFMPEG_WIN64_LIB_PATH) + zlibwapi.lib;LibCmo.lib;IronPad.lib;Dbghelp.lib;%(AdditionalDependencies) + $(ZLIB_PATH)\contrib\vstudio\vc14\x64\ZlibDllReleaseWithoutAsm;$(SolutionDir)out\$(Platform)\$(Configuration)\LibCmo;$(SolutionDir)out\$(Platform)\$(Configuration)\IronPad; @@ -160,7 +160,7 @@ true LIBCMO_BUILD_RELEASE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true - $(ZLIB_PATH);../LibCmo;$(STB_PATH);%(AdditionalIncludeDirectories) + $(ZLIB_PATH);../LibCmo;../IronPad;$(STB_PATH);%(AdditionalIncludeDirectories) stdcpp20 /utf-8 %(AdditionalOptions) true @@ -170,8 +170,8 @@ true true true - zlibwapi.lib;LibCmo.lib;%(AdditionalDependencies) - $(ZLIB_PATH)\contrib\vstudio\vc14\x64\ZlibDllReleaseWithoutAsm;$(SolutionDir)out\$(Platform)\$(Configuration)\LibCmo;$(FFMPEG_WIN64_LIB_PATH) + zlibwapi.lib;LibCmo.lib;IronPad.lib;Dbghelp.lib;%(AdditionalDependencies) + $(ZLIB_PATH)\contrib\vstudio\vc14\x64\ZlibDllReleaseWithoutAsm;$(SolutionDir)out\$(Platform)\$(Configuration)\LibCmo;$(SolutionDir)out\$(Platform)\$(Configuration)\IronPad; diff --git a/Unvirt/UnvirtContext.cpp b/Unvirt/UnvirtContext.cpp index 627cf7a..2233a11 100644 --- a/Unvirt/UnvirtContext.cpp +++ b/Unvirt/UnvirtContext.cpp @@ -442,7 +442,8 @@ namespace Unvirt::Context { void Unvirt::Context::UnvirtContext::ProcTest(const CmdHelper::ArgumentsMap* amap) { #if defined(LIBCMO_BUILD_DEBUG) // MARK: Add the debug code here. - + char p = 0; + char a = 1 / p; #else PrintCommonError("Test command only available in Debug mode."); diff --git a/libcmo21.sln b/libcmo21.sln index d2770dc..8097d3a 100644 --- a/libcmo21.sln +++ b/libcmo21.sln @@ -6,6 +6,12 @@ MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibCmo", "LibCmo\LibCmo.vcxproj", "{70F64F8D-099C-4C21-B29C-0A8F1E22FB2E}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Unvirt", "Unvirt\Unvirt.vcxproj", "{77E7ADB6-0D0C-4BA4-8DE7-A284C7F83941}" + ProjectSection(ProjectDependencies) = postProject + {A6454164-2153-45AE-BDB8-19C77014E0CC} = {A6454164-2153-45AE-BDB8-19C77014E0CC} + {70F64F8D-099C-4C21-B29C-0A8F1E22FB2E} = {70F64F8D-099C-4C21-B29C-0A8F1E22FB2E} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IronPad", "IronPad\IronPad.vcxproj", "{A6454164-2153-45AE-BDB8-19C77014E0CC}" ProjectSection(ProjectDependencies) = postProject {70F64F8D-099C-4C21-B29C-0A8F1E22FB2E} = {70F64F8D-099C-4C21-B29C-0A8F1E22FB2E} EndProjectSection @@ -34,6 +40,14 @@ Global {77E7ADB6-0D0C-4BA4-8DE7-A284C7F83941}.Release|x64.Build.0 = Release|x64 {77E7ADB6-0D0C-4BA4-8DE7-A284C7F83941}.Release|x86.ActiveCfg = Release|Win32 {77E7ADB6-0D0C-4BA4-8DE7-A284C7F83941}.Release|x86.Build.0 = Release|Win32 + {A6454164-2153-45AE-BDB8-19C77014E0CC}.Debug|x64.ActiveCfg = Debug|x64 + {A6454164-2153-45AE-BDB8-19C77014E0CC}.Debug|x64.Build.0 = Debug|x64 + {A6454164-2153-45AE-BDB8-19C77014E0CC}.Debug|x86.ActiveCfg = Debug|Win32 + {A6454164-2153-45AE-BDB8-19C77014E0CC}.Debug|x86.Build.0 = Debug|Win32 + {A6454164-2153-45AE-BDB8-19C77014E0CC}.Release|x64.ActiveCfg = Release|x64 + {A6454164-2153-45AE-BDB8-19C77014E0CC}.Release|x64.Build.0 = Release|x64 + {A6454164-2153-45AE-BDB8-19C77014E0CC}.Release|x86.ActiveCfg = Release|Win32 + {A6454164-2153-45AE-BDB8-19C77014E0CC}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE