Temp adding required types to utils to unblock development

Fix printing style
Add Dump options
This commit is contained in:
Gustavo Varo 2025-03-08 16:46:19 -05:00
parent 8edce30c17
commit 922720b2af
4 changed files with 109 additions and 25 deletions

View file

@ -67,7 +67,17 @@ extern "C" __declspec(dllexport) HRESULT CALLBACK DebugExtensionInitialize(PULON
nullptr); nullptr);
// Print the mimalloc base address, this indicates extension was load successfully // Print the mimalloc base address, this indicates extension was load successfully
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "mimalloc.dll base address found: 0x%llx\n", g_MiMallocBase); g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "mimalloc.dll base address found: 0x%llx\n\n", g_MiMallocBase);
// show version
const int vermajor = MI_MALLOC_VERSION / 100;
const int verminor = (MI_MALLOC_VERSION % 100) / 10;
const int verpatch = (MI_MALLOC_VERSION % 10);
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "mimalloc %s\n", std::format("v{}.{}.{} (built on {}, {})\n", vermajor, verminor, verpatch, __DATE__, __TIME__).c_str());
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "Start here:\n");
g_DebugControl->ControlledOutput(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL, "<link cmd=\"!mi_dump_options\">Dump Options</link>\n");
g_DebugControl->ControlledOutput(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL, "<link cmd=\"!mi_dump_arenas\">Dump Arenas</link>\n");
return S_OK; return S_OK;
} }

View file

@ -15,29 +15,26 @@ extern "C" __declspec(dllexport) HRESULT CALLBACK mi_dump_arenas(PDEBUG_CLIENT c
ULONG64 subprocMainAddr = 0; ULONG64 subprocMainAddr = 0;
hr = GetSymbolOffset("subproc_main", subprocMainAddr); hr = GetSymbolOffset("subproc_main", subprocMainAddr);
if (FAILED(hr) || subprocMainAddr == 0) { if (FAILED(hr) || subprocMainAddr == 0) {
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, "ERROR: Could not locate mi_subproc_t.\n"); g_DebugControl->Output(DEBUG_OUTPUT_ERROR, "ERROR: Could not locate subproc_main.\n");
return E_FAIL; return E_FAIL;
} }
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "mi_subproc_t found at 0x%llx\n\n", subprocMainAddr); PrintLink(subprocMainAddr, std::format("dx -r1 (*((mimalloc!mi_subproc_s *)0x{:016X}))", subprocMainAddr), "subproc_main");
mi_subproc_t subprocMain {}; mi_subproc_t subprocMain {};
hr = ReadMemory(subprocMainAddr, &subprocMain, sizeof(mi_subproc_t)); hr = ReadMemory(subprocMainAddr, &subprocMain, sizeof(mi_subproc_t));
if (FAILED(hr)) { if (FAILED(hr)) {
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, "ERROR: Failed to read mi_subproc_t at 0x%llx.\n", subprocMainAddr); g_DebugControl->Output(DEBUG_OUTPUT_ERROR, "ERROR: Failed to read subproc_main at 0x%llx.\n", subprocMainAddr);
return hr; return hr;
} }
// Print results // Print results
size_t arenaCount = subprocMain.arena_count.load(); size_t arenaCount = subprocMain.arena_count.load();
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "Arena count: %llu\n\n", arenaCount); g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "Arena count: %llu\n", arenaCount);
for (size_t i = 0; i < arenaCount; ++i) { for (size_t i = 0; i < arenaCount; ++i) {
ULONG64 arenaAddr = subprocMainAddr + offsetof(mi_subproc_t, arenas) + (i * sizeof(std::atomic<mi_arena_t*>)); ULONG64 arenaAddr = subprocMainAddr + offsetof(mi_subproc_t, arenas) + (i * sizeof(std::atomic<mi_arena_t*>));
PrintLink(arenaAddr, std::format("!mi_dump_arena 0x{:016X}", arenaAddr), std::format("Arena {}", i));
// Print clickable Arena Index link
g_DebugControl->ControlledOutput(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL,
"[0x%p] [<link cmd=\"!mi_dump_arena %p\">Arena %llu</link>]\n", (void*)arenaAddr, (void*)arenaAddr, i);
} }
return S_OK; return S_OK;
@ -55,21 +52,31 @@ extern "C" __declspec(dllexport) HRESULT CALLBACK mi_dump_arena(PDEBUG_CLIENT cl
return E_INVALIDARG; return E_INVALIDARG;
} }
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "Dumping Arena at Address: 0x%016llx\n\n", arenaAddr); ULONG64 arenaValueAddr = 0;
HRESULT hr = ReadMemory(arenaAddr, &arenaValueAddr, sizeof(ULONG64));
if (FAILED(hr) || arenaValueAddr == 0) {
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, "ERROR: Failed to read mi_arena_t pointer at 0x%016llx.\n", arenaAddr);
return hr;
}
//// Read the `mi_arena_t` structure from the memory PrintLink(arenaAddr, std::format("dx -r1 ((mimalloc!mi_arena_s *)0x{:016X})", arenaValueAddr), std::format("Dumping Arena at Address: 0x{:016X}\n", arenaAddr));
// mi_arena_t arena{};
// HRESULT hr = ReadMemory(arenaAddr, &arena, sizeof(mi_arena_t)); // Read the `mi_arena_t` structure from the memory
// if (FAILED(hr)) mi_arena_t arena {};
//{ hr = ReadMemory(arenaValueAddr, &arena, sizeof(mi_arena_t));
// g_DebugControl->Output(DEBUG_OUTPUT_ERROR, "ERROR: Failed to read mi_arena_t at 0x%016llx.\n", arenaAddr); if (FAILED(hr)) {
// return hr; g_DebugControl->Output(DEBUG_OUTPUT_ERROR, "ERROR: Failed to read mi_arena_t at 0x%016llx.\n", arenaAddr);
// } return hr;
}
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "[0x%p] - Slice Count: %llu\n", arenaAddr + offsetof(mi_arena_t, slice_count), arena.slice_count);
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "[0x%p] - Info Slices: %llu\n", arenaAddr + offsetof(mi_arena_t, info_slices), arena.info_slices);
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "[0x%p] - NUMA Node: %d\n", arenaAddr + offsetof(mi_arena_t, numa_node), arena.numa_node);
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "[0x%p] - Exclusive: %s\n", arenaAddr + offsetof(mi_arena_t, is_exclusive), arena.is_exclusive ? "Yes" : "No");
g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "[0x%p] - Purge Expire: %d\n", arenaAddr + offsetof(mi_arena_t, purge_expire), arena.purge_expire.load());
// g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "[0x%p] - Slices Free (Count): %d\n", arena.slices_free->chunk_count.load());
// g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, "[0x%p] - Slices Committed (Max Accessed): %d\n", arena.slices_committed.load());
// g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, " - Slice Count: %llu\n", arena.slice_count);
// g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, " - Info Slices: %llu\n", arena.info_slices);
// g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, " - NUMA Node: %d\n", arena.numa_node);
// g_DebugControl->Output(DEBUG_OUTPUT_NORMAL, " - Exclusive: %s\n", arena.is_exclusive ? "Yes" : "No");
//
return S_OK; return S_OK;
} }

View file

@ -12,5 +12,30 @@ extern "C" __declspec(dllexport) HRESULT CALLBACK mi_dump_options(PDEBUG_CLIENT
HRESULT hr = S_OK; HRESULT hr = S_OK;
ULONG64 optionsAddr = 0;
hr = GetSymbolOffset("options", optionsAddr);
if (FAILED(hr) || optionsAddr == 0) {
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, "ERROR: Could not locate optionsAddr.\n");
return E_FAIL;
}
const int optionsSize = static_cast<int>(mi_option_e::_mi_option_last);
PrintLink(optionsAddr, std::format("dx -r1 (*((mimalloc!mi_option_desc_s (*)[{}])0x{:016X}))", optionsSize, optionsAddr),
std::format("Dumping Options at Address: 0x{:016X}\n", optionsAddr));
for (size_t i = 0; i < optionsSize; ++i) {
ULONG64 optionItemAddr = optionsAddr + (i * sizeof(mi_option_desc_t));
mi_option_desc_t optionDesc {};
hr = ReadMemory(optionItemAddr, &optionDesc, sizeof(mi_option_desc_t));
if (FAILED(hr)) {
g_DebugControl->Output(DEBUG_OUTPUT_ERROR, "ERROR: Failed to read mi_option_desc_t at 0x%llx.\n", optionItemAddr);
return hr;
}
PrintLink(optionItemAddr, std::format("dx -r1 (*((mimalloc!mi_option_desc_s *)0x{:016X}))", optionItemAddr), std::to_string(i),
std::format(" {}: {}", optionDesc.name, optionDesc.value));
}
return S_OK; return S_OK;
} }

View file

@ -10,11 +10,13 @@ terms of the MIT license. A copy of the license can be found in the file
#include <DbgEng.h> #include <DbgEng.h>
#include <Windows.h> #include <Windows.h>
#include <format>
#include <string> #include <string>
#include <vector> #include <vector>
#include "mimalloc.h" #include <mimalloc.h>
#include "mimalloc/internal.h" #include <mimalloc/internal.h>
#include "../src/bitmap.h"
extern ULONG64 g_MiMallocBase; extern ULONG64 g_MiMallocBase;
@ -29,4 +31,44 @@ HRESULT ReadMemory(const char* symbolName, void* outBuffer, size_t bufferSize);
HRESULT ReadMemory(ULONG64 address, void* outBuffer, size_t bufferSize); HRESULT ReadMemory(ULONG64 address, void* outBuffer, size_t bufferSize);
HRESULT ReadString(const char* symbolName, std::string& outBuffer); HRESULT ReadString(const char* symbolName, std::string& outBuffer);
inline void PrintLink(ULONG64 addr, std::string cmd, std::string linkText, std::string extraText = "") {
g_DebugControl->ControlledOutput(DEBUG_OUTCTL_AMBIENT_DML, DEBUG_OUTPUT_NORMAL,
std::format("[0x{:016X}] <link cmd=\"{}\">{}</link> {}\n", addr, cmd, linkText, extraText).c_str());
}
typedef struct mi_arena_s {
mi_memid_t memid; // memid of the memory area
mi_subproc_t* subproc; // subprocess this arena belongs to (`this 'in' this->subproc->arenas`)
size_t slice_count; // total size of the area in arena slices (of `MI_ARENA_SLICE_SIZE`)
size_t info_slices; // initial slices reserved for the arena bitmaps
int numa_node; // associated NUMA node
bool is_exclusive; // only allow allocations if specifically for this arena
_Atomic(mi_msecs_t) purge_expire; // expiration time when slices can be purged from `slices_purge`.
mi_bbitmap_t* slices_free; // is the slice free? (a binned bitmap with size classes)
mi_bitmap_t* slices_committed; // is the slice committed? (i.e. accessible)
mi_bitmap_t* slices_dirty; // is the slice potentially non-zero?
mi_bitmap_t* slices_purge; // slices that can be purged
mi_bitmap_t* pages; // all registered pages (abandoned and owned)
mi_bitmap_t* pages_abandoned[MI_BIN_COUNT]; // abandoned pages per size bin (a set bit means the start of the page)
// the full queue contains abandoned full pages
// followed by the bitmaps (whose sizes depend on the arena size)
// note: when adding bitmaps revise `mi_arena_info_slices_needed`
} mi_arena_t;
typedef enum mi_init_e {
UNINIT, // not yet initialized
DEFAULTED, // not found in the environment, use default value
INITIALIZED // found in environment or set explicitly
} mi_init_t;
typedef struct mi_option_desc_s {
long value; // the value
mi_init_t init; // is it initialized yet? (from the environment)
mi_option_t option; // for debugging: the option index should match the option
const char* name; // option name without `mimalloc_` prefix
const char* legacy_name; // potential legacy option name
} mi_option_desc_t;
#endif // MIMALLOC_WINDBG_UTILS_H #endif // MIMALLOC_WINDBG_UTILS_H