mirror of
https://github.com/microsoft/mimalloc.git
synced 2025-05-03 14:09:31 +03:00
Add Process Info
This commit is contained in:
parent
38f139b0a5
commit
13b27252c1
6 changed files with 189 additions and 0 deletions
|
@ -295,6 +295,7 @@ if(WIN32 AND MI_WIN_DBG_EXTS)
|
|||
list(APPEND mi_sources ${PROJECT_SOURCE_DIR}/src/prim/windows/windbg/mimalloc_windbg_arenas.cpp)
|
||||
list(APPEND mi_sources ${PROJECT_SOURCE_DIR}/src/prim/windows/windbg/mimalloc_windbg_help.cpp)
|
||||
list(APPEND mi_sources ${PROJECT_SOURCE_DIR}/src/prim/windows/windbg/mimalloc_windbg_options.cpp)
|
||||
list(APPEND mi_sources ${PROJECT_SOURCE_DIR}/src/prim/windows/windbg/mimalloc_windbg_process_info.cpp)
|
||||
list(APPEND mi_sources ${PROJECT_SOURCE_DIR}/src/prim/windows/windbg/mimalloc_windbg_settings.cpp)
|
||||
list(APPEND mi_sources ${PROJECT_SOURCE_DIR}/src/prim/windows/windbg/mimalloc_windbg_stats.cpp)
|
||||
list(APPEND mi_sources ${PROJECT_SOURCE_DIR}/src/prim/windows/windbg/mimalloc_windbg_utils.cpp)
|
||||
|
|
|
@ -52,6 +52,17 @@ extern "C" __declspec(dllexport) HRESULT CALLBACK DebugExtensionInitialize(PULON
|
|||
return hr;
|
||||
}
|
||||
|
||||
// Query for the IDebugSystemObjects4 interface
|
||||
hr = g_DebugClient->QueryInterface(__uuidof(IDebugSystemObjects4), (void**)&g_DebugSystemObjects);
|
||||
if (FAILED(hr)) {
|
||||
g_DebugSymbols->Release();
|
||||
g_DebugControl->Release();
|
||||
g_DebugClient->Release();
|
||||
g_DataSpaces->Release();
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
// Find mimalloc base address at startup
|
||||
hr = FindMimallocBase();
|
||||
if (FAILED(hr) || g_MiMallocBase == 0) {
|
||||
|
@ -80,6 +91,7 @@ extern "C" __declspec(dllexport) HRESULT CALLBACK DebugExtensionInitialize(PULON
|
|||
g_DebugControl->ControlledOutput(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL, "<link cmd=\"!mi_dump_arenas\">Dump Arenas</link>\n");
|
||||
g_DebugControl->ControlledOutput(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL, "<link cmd=\"!mi_dump_stats\">Dump Statistics</link>\n");
|
||||
g_DebugControl->ControlledOutput(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL, "<link cmd=\"!mi_show_extension_settings\">Show Extension Settings</link>\n");
|
||||
g_DebugControl->ControlledOutput(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL, "<link cmd=\"!mi_dump_process_info\">Dump Process Info</link>\n");
|
||||
g_DebugControl->ControlledOutput(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL, "<link cmd=\"!mi_show_help\">Show Help commands</link>\n");
|
||||
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "\n");
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@ extern "C" __declspec(dllexport) HRESULT CALLBACK mi_dump_options(PDEBUG_CLIENT
|
|||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "\n");
|
||||
|
||||
ULONG64 optionsAddr = 0;
|
||||
hr = GetSymbolOffset("mi_options", optionsAddr);
|
||||
if (FAILED(hr) || optionsAddr == 0) {
|
||||
|
|
115
src/prim/windows/windbg/mimalloc_windbg_process_info.cpp
Normal file
115
src/prim/windows/windbg/mimalloc_windbg_process_info.cpp
Normal file
|
@ -0,0 +1,115 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
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 "mimalloc_windbg_utils.h"
|
||||
|
||||
/*
|
||||
Command: !mi_dump_process_info
|
||||
*/
|
||||
extern "C" __declspec(dllexport) HRESULT CALLBACK mi_dump_process_info(PDEBUG_CLIENT client, PCSTR args) {
|
||||
UNREFERENCED_PARAMETER(args);
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "\n");
|
||||
|
||||
// Get process handle
|
||||
ULONG64 processHandle = 0;
|
||||
hr = g_DebugSystemObjects->GetCurrentProcessHandle(&processHandle);
|
||||
if (FAILED(hr)) {
|
||||
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, "ERROR: Failed to get Process Handle.\n");
|
||||
return hr;
|
||||
}
|
||||
|
||||
// Get process ID
|
||||
ULONG processId = 0;
|
||||
hr = g_DebugSystemObjects->GetCurrentProcessSystemId(&processId);
|
||||
if (FAILED(hr)) {
|
||||
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, "ERROR: Failed to get Process ID.\n");
|
||||
return hr;
|
||||
}
|
||||
|
||||
// Get executable arguments
|
||||
ULONG64 pebAddr = 0;
|
||||
hr = g_DebugSystemObjects->GetCurrentProcessPeb(&pebAddr);
|
||||
if (FAILED(hr) || pebAddr == 0) {
|
||||
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, "ERROR: Failed to get PEB address.\n");
|
||||
return hr;
|
||||
}
|
||||
|
||||
// Get offset of ProcessParameters
|
||||
ULONG processParametersOffset = 0;
|
||||
hr = GetNtSymbolOffset("_PEB", "ProcessParameters", processParametersOffset);
|
||||
if (FAILED(hr)) {
|
||||
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, "ERROR: Failed to get ProcessParameters offset.\n");
|
||||
return hr;
|
||||
}
|
||||
|
||||
ULONG64 processParametersAddr = 0;
|
||||
hr = ReadMemory(pebAddr + processParametersOffset, &processParametersAddr, sizeof(ULONG64));
|
||||
if (FAILED(hr)) {
|
||||
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, "ERROR: Failed to read ProcessParameters address from PEB.\n");
|
||||
return hr;
|
||||
}
|
||||
|
||||
// Get offset of CommandLine
|
||||
ULONG commandLineOffset = 0;
|
||||
hr = GetNtSymbolOffset("_RTL_USER_PROCESS_PARAMETERS", "CommandLine", commandLineOffset);
|
||||
if (FAILED(hr)) {
|
||||
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, "ERROR: Failed to get CommandLine offset.\n");
|
||||
return hr;
|
||||
}
|
||||
|
||||
UNICODE_STRING cmdLine {};
|
||||
hr = ReadMemory(processParametersAddr + commandLineOffset, &cmdLine, sizeof(cmdLine));
|
||||
if (FAILED(hr) || cmdLine.Buffer == 0 || cmdLine.Length == 0) {
|
||||
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, "ERROR: Failed to read CommandLine struct.\n");
|
||||
return hr;
|
||||
}
|
||||
|
||||
// Read the command line string
|
||||
std::wstring commandLine;
|
||||
hr = ReadWideString(cmdLine.Buffer, commandLine, cmdLine.Length / sizeof(WCHAR));
|
||||
if (FAILED(hr)) {
|
||||
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, "ERROR: Failed to read CommandLine string.\n");
|
||||
return hr;
|
||||
}
|
||||
|
||||
// Get Processor Type (x86, x64, ARM64, etc.)
|
||||
ULONG processorType = 0;
|
||||
hr = g_DebugControl->GetActualProcessorType(&processorType);
|
||||
const char* arch = (processorType == IMAGE_FILE_MACHINE_AMD64) ? "x64"
|
||||
: (processorType == IMAGE_FILE_MACHINE_I386) ? "x86"
|
||||
: (processorType == IMAGE_FILE_MACHINE_ARM64) ? "ARM64"
|
||||
: "Unknown";
|
||||
|
||||
// Read NUMA node count
|
||||
ULONG64 numaNodeOffSet = 0;
|
||||
hr = GetSymbolOffset("_mi_numa_node_count", numaNodeOffSet);
|
||||
if (FAILED(hr)) {
|
||||
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, "ERROR: Failed to get NUMA node count address.\n");
|
||||
return hr;
|
||||
}
|
||||
|
||||
ULONG numaNodeCount = 0;
|
||||
hr = ReadMemory(numaNodeOffSet, &numaNodeCount, sizeof(ULONG));
|
||||
if (FAILED(hr)) {
|
||||
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, "ERROR: Failed to read NUMA node count.\n");
|
||||
return hr;
|
||||
}
|
||||
|
||||
// Output debuggee process info
|
||||
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "Debugging Process (From Debuggee Context):\n");
|
||||
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, " Process ID : %u (0x%X)\n", processId, processId);
|
||||
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, " Command Line : %s\n", commandLine.c_str());
|
||||
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, " Architecture : %s\n", arch);
|
||||
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, " NUMA Node : %u\n", numaNodeCount);
|
||||
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, " Process Handle : %p\n", processHandle);
|
||||
|
||||
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "\n");
|
||||
return S_OK;
|
||||
}
|
|
@ -14,6 +14,7 @@ IDebugClient* g_DebugClient = nullptr;
|
|||
IDebugControl4* g_DebugControl = nullptr;
|
||||
IDebugSymbols3* g_DebugSymbols = nullptr;
|
||||
IDebugDataSpaces* g_DataSpaces = nullptr;
|
||||
IDebugSystemObjects4* g_DebugSystemObjects = nullptr;
|
||||
|
||||
// Function to find mimalloc.dll base address at startup
|
||||
HRESULT FindMimallocBase() {
|
||||
|
@ -45,6 +46,37 @@ HRESULT GetSymbolOffset(const char* symbolName, ULONG64& outOffset) {
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
// Function to get the offset of a nt symbol in the debuggee process
|
||||
HRESULT GetNtSymbolOffset(const char* typeName, const char* fieldName, ULONG& outOffset) {
|
||||
// Ensure debug interfaces are valid
|
||||
if (!g_DebugSymbols || g_MiMallocBase == 0) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
ULONG index = 0;
|
||||
ULONG64 base = 0;
|
||||
HRESULT hr = g_DebugSymbols->GetModuleByModuleName("ntdll", 0, &index, &base);
|
||||
if (FAILED(hr) || index == 0 || base == 0) {
|
||||
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, "ERROR: Failed to locate module name for ntdll");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
ULONG typeId = 0;
|
||||
hr = g_DebugSymbols->GetTypeId(base, typeName, &typeId);
|
||||
if (FAILED(hr) || typeId == 0) {
|
||||
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, "ERROR: Failed to locate type id for: %s\n", typeName);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
hr = g_DebugSymbols->GetFieldTypeAndOffset(base, typeId, fieldName, nullptr, &outOffset);
|
||||
if (FAILED(hr) || outOffset == 0) {
|
||||
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, "ERROR: Failed to locate symbol: %s\n", fieldName);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Function to read memory from the debuggee process
|
||||
HRESULT ReadMemory(const char* symbolName, void* outBuffer, size_t bufferSize) {
|
||||
if (!g_DataSpaces) {
|
||||
|
@ -122,6 +154,24 @@ HRESULT ReadString(const char* symbolName, std::string& outBuffer) {
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT ReadWideString(ULONG64 address, std::wstring& outString, size_t maxLength) {
|
||||
if (!g_DataSpaces) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
WCHAR buffer[1025] = {0}; // max 1024 chars + null terminator
|
||||
size_t readLength = min(maxLength, 1024);
|
||||
|
||||
HRESULT hr = g_DataSpaces->ReadVirtual(address, buffer, (ULONG)(readLength * sizeof(WCHAR)), nullptr);
|
||||
if (FAILED(hr)) {
|
||||
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, "ERROR: Failed to read string from address 0x%llx.\n", address);
|
||||
return hr;
|
||||
}
|
||||
|
||||
outString = buffer;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Helper function to count the number of set bits in a mi_bitmap_t.
|
||||
// This implementation assumes that the bitmap is organized into chunks,
|
||||
// and that each chunk contains MI_BCHUNK_FIELDS of type mi_bfield_t (usually a 64-bit word).
|
||||
|
|
|
@ -24,15 +24,18 @@ extern IDebugClient* g_DebugClient;
|
|||
extern IDebugControl4* g_DebugControl;
|
||||
extern IDebugSymbols3* g_DebugSymbols;
|
||||
extern IDebugDataSpaces* g_DataSpaces;
|
||||
extern IDebugSystemObjects4* g_DebugSystemObjects;
|
||||
|
||||
static inline double MinCommittedSlicesPct = 60.0; // if below threshold, potential fragmentation.
|
||||
static inline double MaxAbandonedPagesRatio = 0.4; // If abandoned pages exceed 40% of committed pages.
|
||||
|
||||
HRESULT FindMimallocBase();
|
||||
HRESULT GetSymbolOffset(const char* symbolName, ULONG64& outOffset);
|
||||
HRESULT GetNtSymbolOffset(const char* typeName, const char* fieldName, ULONG& outOffset);
|
||||
HRESULT ReadMemory(const char* symbolName, void* outBuffer, size_t bufferSize);
|
||||
HRESULT ReadMemory(ULONG64 address, void* outBuffer, size_t bufferSize);
|
||||
HRESULT ReadString(const char* symbolName, std::string& outBuffer);
|
||||
HRESULT ReadWideString(ULONG64 address, std::wstring& outString, size_t maxLength = 1024);
|
||||
size_t mi_bitmap_count(mi_bitmap_t* bmp);
|
||||
std::string FormatSize(std::size_t bytes);
|
||||
std::string FormatNumber(double num);
|
||||
|
@ -42,6 +45,12 @@ inline void PrintLink(ULONG64 addr, std::string cmd, std::string linkText, std::
|
|||
std::format("[0x{:016X}] <link cmd=\"{}\">{}</link> {}\n", addr, cmd, linkText, extraText).c_str());
|
||||
}
|
||||
|
||||
struct UNICODE_STRING {
|
||||
USHORT Length;
|
||||
USHORT MaximumLength;
|
||||
ULONG64 Buffer;
|
||||
};
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
static inline int popcount64(uint64_t x) {
|
||||
|
|
Loading…
Add table
Reference in a new issue