diff --git a/CMakeLists.txt b/CMakeLists.txt index 52844552..2dba9ba1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,6 +74,10 @@ set(mi_sources src/stats.c src/prim/prim.c) +if(WIN32 AND MI_WIN_DBG_EXTS) + list(APPEND mi_sources src/prim/windows/windbg/mimalloc_dbg.cpp) +endif() + set(mi_cflags "") set(mi_cflags_static "") # extra flags for a static library build set(mi_cflags_dynamic "") # extra flags for a shared-object library build @@ -255,6 +259,17 @@ if(MI_TRACK_ETW) endif() endif() +if(MI_WIN_DBG_EXTS) + if(NOT WIN32) + set(MI_WIN_DBG_EXTS OFF) + message(WARNING "Can only enable Windows debbuger extension support on Windows (MI_WIN_DBG_EXTS=OFF)") + endif() + if(MI_WIN_DBG_EXTS) + message(STATUS "Compile with Windows debbuger extension support (MI_WIN_DBG_EXTS=ON)") + list(APPEND mi_defines MI_WIN_DBG_EXTS=1) + endif() +endif() + if(MI_GUARDED) message(STATUS "Compile guard pages behind certain object allocations (MI_GUARDED=ON)") list(APPEND mi_defines MI_GUARDED=1) diff --git a/ide/vs2022/mimalloc-lib.vcxproj b/ide/vs2022/mimalloc-lib.vcxproj index b4bf013e..b5bc9677 100644 --- a/ide/vs2022/mimalloc-lib.vcxproj +++ b/ide/vs2022/mimalloc-lib.vcxproj @@ -211,8 +211,7 @@ - - + dbgeng.lib @@ -477,6 +476,7 @@ true + @@ -493,6 +493,7 @@ + diff --git a/ide/vs2022/mimalloc-lib.vcxproj.filters b/ide/vs2022/mimalloc-lib.vcxproj.filters index 6825f113..c2d7db7b 100644 --- a/ide/vs2022/mimalloc-lib.vcxproj.filters +++ b/ide/vs2022/mimalloc-lib.vcxproj.filters @@ -61,6 +61,9 @@ Sources + + Sources + diff --git a/ide/vs2022/mimalloc-override-dll.vcxproj b/ide/vs2022/mimalloc-override-dll.vcxproj index 556d7926..3904e344 100644 --- a/ide/vs2022/mimalloc-override-dll.vcxproj +++ b/ide/vs2022/mimalloc-override-dll.vcxproj @@ -208,7 +208,7 @@ /Zc:__cplusplus %(AdditionalOptions) - $(ProjectDir)\..\..\bin\mimalloc-redirect.lib;%(AdditionalDependencies) + $(ProjectDir)\..\..\bin\mimalloc-redirect.lib;dbgeng.lib;%(AdditionalDependencies) @@ -441,6 +441,7 @@ + @@ -506,6 +507,7 @@ true + diff --git a/ide/vs2022/mimalloc-override-dll.vcxproj.filters b/ide/vs2022/mimalloc-override-dll.vcxproj.filters index ebcf545a..e09e6bb1 100644 --- a/ide/vs2022/mimalloc-override-dll.vcxproj.filters +++ b/ide/vs2022/mimalloc-override-dll.vcxproj.filters @@ -61,6 +61,9 @@ Sources + + Sources + diff --git a/src/prim/windows/windbg/mimalloc_dbg.cpp b/src/prim/windows/windbg/mimalloc_dbg.cpp new file mode 100644 index 00000000..5bc76372 --- /dev/null +++ b/src/prim/windows/windbg/mimalloc_dbg.cpp @@ -0,0 +1,146 @@ +/* ---------------------------------------------------------------------------- +Copyright (c) Microsoft Research +This is free software; you can redistribute it and/or modify it under the +terms of the MIT license. A copy of the license can be found in the file +"LICENSE" at the root of this distribution. +-----------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#include + +#include "mimalloc.h" +#include "mimalloc/internal.h" + +ULONG64 g_MiMallocBase = 0; +IDebugClient* g_DebugClient = nullptr; +IDebugControl* g_DebugControl = nullptr; +IDebugSymbols3* g_DebugSymbols = nullptr; +IDebugDataSpaces* g_DataSpaces = nullptr; + +// Function to find mimalloc.dll base address at startup +HRESULT FindMimallocBase() +{ + if (g_DebugSymbols == nullptr) + { + return E_FAIL; + } + + return g_DebugSymbols->GetModuleByModuleName("mimalloc", 0, NULL, &g_MiMallocBase); +} + +// Entry point for the extension +extern "C" __declspec(dllexport) HRESULT CALLBACK DebugExtensionInitialize(PULONG version, PULONG flags) +{ + UNREFERENCED_PARAMETER(flags); + + // Ensure Version is valid + if (!version) + { + return E_INVALIDARG; + } + + // Set the version + *version = DEBUG_EXTENSION_VERSION(1, 0); + + HRESULT hr = DebugCreate(__uuidof(IDebugClient), (void**)&g_DebugClient); + if (FAILED(hr)) + { + return hr; + } + + // Query for the IDebugControl interface + hr = g_DebugClient->QueryInterface(__uuidof(IDebugControl), (void**)&g_DebugControl); + if (FAILED(hr)) + { + g_DebugClient->Release(); + + return hr; + } + + hr = g_DebugClient->QueryInterface(__uuidof(IDebugSymbols3), (void**)&g_DebugSymbols); + if (FAILED(hr)) + { + g_DebugControl->Release(); + g_DebugClient->Release(); + + return hr; + } + + hr = g_DebugClient->QueryInterface(__uuidof(IDebugDataSpaces), (void**)&g_DataSpaces); + if (FAILED(hr)) + { + g_DebugSymbols->Release(); + g_DebugControl->Release(); + g_DebugClient->Release(); + + return hr; + } + + // Find mimalloc base address at startup + hr = FindMimallocBase(); + if (FAILED(hr) || g_MiMallocBase == 0) + { + return E_FAIL; // Prevent extension from loading + } + + mi_register_output( + [](const char* msg, void* arg) { + g_DebugControl->Output(DEBUG_OUTPUT_ERROR, msg); + g_DebugControl->Output(DEBUG_OUTPUT_ERROR, "\n"); + }, + nullptr); + + g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "mimalloc.dll base address found: 0x%llx\n", g_MiMallocBase); + + return S_OK; +} + +// Notifies the extension that a debug event has occurred +extern "C" __declspec(dllexport) void CALLBACK DebugExtensionNotify(ULONG notify, ULONG64 argument) +{ + UNREFERENCED_PARAMETER(notify); + UNREFERENCED_PARAMETER(argument); +} + +// Uninitializes the extension +extern "C" __declspec(dllexport) void CALLBACK DebugExtensionUninitialize() +{ + if (g_DebugSymbols) + { + g_DebugSymbols->Release(); + g_DebugSymbols = nullptr; + } + + if (g_DebugControl) + { + g_DebugControl->Release(); + g_DebugControl = nullptr; + } + + if (g_DebugClient) + { + g_DebugClient->Release(); + g_DebugClient = nullptr; + } +} + +// Sample command: !mi_help +extern "C" __declspec(dllexport) HRESULT CALLBACK mi_help(PDEBUG_CLIENT Client, PCSTR args) +{ + UNREFERENCED_PARAMETER(args); + + // Print Help + g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "Hello from MiMalloc WinDbg Extension!\n"); + + return S_OK; +} + +extern "C" __declspec(dllexport) HRESULT CALLBACK mi_dump_arenas(PDEBUG_CLIENT client, PCSTR args) +{ + mi_debug_show_arenas(); + return S_OK; +} \ No newline at end of file