Skip to content

Commit

Permalink
Support multi heap managers (#45)
Browse files Browse the repository at this point in the history
* add init function in each heap manager

* add ptmalloc glibc version detection

* fix ptmalloc glibc 2.27 + gdb9.2 on Ubuntu 18.04

* move get_glibc_version to heap_ptmalloc files

* rename gHeapInitFuncs to gHeapRegistrationFuncs

* heap.cpp: add macro to check CA_HEAP and enhance its error message

Co-authored-by: Michael Yan <myan@microstrategy.com>
Former-commit-id: ed32610
  • Loading branch information
yanqi27 and Michael Yan authored May 29, 2022
1 parent 67d084c commit baba787
Show file tree
Hide file tree
Showing 28 changed files with 4,696 additions and 122 deletions.
1 change: 1 addition & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ FROM mcr.microsoft.com/vscode/devcontainers/cpp:0-${VARIANT}
# [Optional] Uncomment this section to install additional packages.
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
&& apt install -y texinfo \
&& apt install -y libgmp-dev \
&& apt install -y build-essential \
&& apt install -y wget \
&& apt install -y python-dev \
Expand Down
2 changes: 2 additions & 0 deletions gdbplus/gdb-12.1/gdb/Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,8 @@ COMMON_SFILES = \
go-typeprint.c \
go-valprint.c \
heap.c \
heap_ptmalloc_2_27.c \
heap_ptmalloc_2_31.c \
heap_ptmalloc_2_35.c \
heapcmd.c \
i386-decode.c \
Expand Down
37 changes: 32 additions & 5 deletions gdbplus/gdb-12.1/gdb/gdb_dep.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,37 @@ inferior_memory_read (address_t addr, void* buffer, size_t sz)
return false;
}

void ca_switch_to_thread(struct thread_info *info)
{
switch_to_thread (info);
}

int ca_num_fields(struct type *type)
{
return type->num_fields();
}

const char *ca_field_name(struct type *type, int i)
{
return type->field(i).name();
}

bool get_gv_value(const char *varname, char *buf, size_t bufsz)
{
struct symbol *sym;

sym = lookup_static_symbol(varname, VAR_DOMAIN).symbol;
if (sym) {
struct value *val = value_of_variable(sym, 0);
if (bufsz >= TYPE_LENGTH(value_type(val))) {
gdb::array_view<const gdb_byte> content = value_contents(val);
memcpy(buf, content.data(), TYPE_LENGTH(value_type(val)));
return true;
}
}
return false;
}

static int
thread_callback (struct thread_info *info, void *data)
{
Expand Down Expand Up @@ -379,8 +410,6 @@ build_segments(void)
bool
update_memory_segments_and_heaps(void)
{
bool rc = true;

/* reset internal quit flag */
g_quit = false;

Expand Down Expand Up @@ -422,9 +451,7 @@ update_memory_segments_and_heaps(void)
return false;
}
/* Probe for heap segments */
CA_HEAP->init_heap();

return rc;
return init_heap_managers();
}

int
Expand Down
1 change: 0 additions & 1 deletion gdbplus/gdb-12.1/gdb/heap_ptmalloc.c

This file was deleted.

1 change: 1 addition & 0 deletions gdbplus/gdb-12.1/gdb/heap_ptmalloc_2_27.c
1 change: 1 addition & 0 deletions gdbplus/gdb-12.1/gdb/heap_ptmalloc_2_31.c
5 changes: 4 additions & 1 deletion gdbplus/gdb-12.1/gdb/heapcmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,10 @@ display_help_command (const char *arg, int from_tty)
static void
switch_heap_command(const char *arg, int from_tty)
{
/* Ensure heap manager is initialized */
if (!update_memory_segments_and_heaps())
return;

if (!arg) {
auto supported_heaps = get_supported_heaps();
CA_PRINT("Please provide the heap manager name, currently supported heap managers: %s.\n", supported_heaps.c_str());
Expand Down Expand Up @@ -292,7 +296,6 @@ void _initialize_heapcmd ();
void
_initialize_heapcmd ()
{
register_heap_managers(); // todo: find a better place to register heaps. maybe update_memory_segments_and_heaps is better than here.
add_cmd("ref", class_info, ref_command, _("Search for references to a given object.\nref <addr_exp>\nref [/thread or /t] <addr_exp> <size> [level]"), &cmdlist);
add_cmd("obj", class_info, obj_command, _("Search for object and reference to object of the same type as the input expression\nobj <type|variable>"), &cmdlist);
add_cmd("shrobj", class_info, shrobj_command, _("Find objects that currently referenced from multiple threads\nshrobj [tid0] [tid1] [...]"), &cmdlist);
Expand Down
4 changes: 3 additions & 1 deletion gdbplus/gdb-9.2/gdb/Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -1063,7 +1063,9 @@ COMMON_SFILES = \
go-typeprint.c \
go-valprint.c \
heap.c \
heap_ptmalloc.c \
heap_ptmalloc_2_27.c \
heap_ptmalloc_2_31.c \
heap_ptmalloc_2_35.c \
heap_tcmalloc.c \
heapcmd.c \
i386-decode.c \
Expand Down
37 changes: 32 additions & 5 deletions gdbplus/gdb-9.2/gdb/gdb_dep.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,37 @@ inferior_memory_read (address_t addr, void* buffer, size_t sz)
return false;
}

void ca_switch_to_thread(struct thread_info *info)
{
switch_to_thread (info->ptid);
}

int ca_num_fields(struct type *type)
{
return TYPE_NFIELDS (type);
}

const char *ca_field_name(struct type *type, int i)
{
return TYPE_FIELD_NAME (type, i);
}

bool get_gv_value(const char *varname, char *buf, size_t bufsz)
{
struct symbol *sym;

sym = lookup_static_symbol(varname, VAR_DOMAIN).symbol;
if (sym) {
struct value *val = value_of_variable(sym, 0);
if (bufsz >= TYPE_LENGTH(value_type(val))) {
const gdb_byte *content = value_contents(val);
memcpy(buf, content, TYPE_LENGTH(value_type(val)));
return true;
}
}
return false;
}

static int
thread_callback (struct thread_info *info, void *data)
{
Expand Down Expand Up @@ -382,8 +413,6 @@ build_segments(void)
bool
update_memory_segments_and_heaps(void)
{
bool rc = true;

/* reset internal quit flag */
g_quit = false;

Expand Down Expand Up @@ -425,9 +454,7 @@ update_memory_segments_and_heaps(void)
return false;
}
/* Probe for heap segments */
CA_HEAP->init_heap();

return rc;
return init_heap_managers();
}

int
Expand Down
1 change: 0 additions & 1 deletion gdbplus/gdb-9.2/gdb/heap_ptmalloc.c

This file was deleted.

1 change: 1 addition & 0 deletions gdbplus/gdb-9.2/gdb/heap_ptmalloc_2_27.c
1 change: 1 addition & 0 deletions gdbplus/gdb-9.2/gdb/heap_ptmalloc_2_31.c
1 change: 1 addition & 0 deletions gdbplus/gdb-9.2/gdb/heap_ptmalloc_2_35.c
1 change: 0 additions & 1 deletion gdbplus/gdb-9.2/gdb/heapcmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,6 @@ switch_heap_command(const char *arg, int from_tty)
void
_initialize_heapcmd (void)
{
register_heap_managers(); // todo: find a better place to register heaps. maybe update_memory_segments_and_heaps is better than here.
add_cmd("ref", class_info, ref_command, _("Search for references to a given object.\nref <addr_exp>\nref [/thread or /t] <addr_exp> <size> [level]"), &cmdlist);
add_cmd("obj", class_info, obj_command, _("Search for object and reference to object of the same type as the input expression\nobj <type|variable>"), &cmdlist);
add_cmd("shrobj", class_info, shrobj_command, _("Find objects that currently referenced from multiple threads\nshrobj [tid0] [tid1] [...]"), &cmdlist);
Expand Down
2 changes: 1 addition & 1 deletion gdbplus/gdb-9.2/gdb/i386-decode.c.REMOVED.git-id
Original file line number Diff line number Diff line change
@@ -1 +1 @@
d2f46fb1f1e55c960eedabbc1b9150bf1fae008b
8a5aa1178b538f607392a2d584f5c82acf226932
3 changes: 1 addition & 2 deletions src/core_elf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -793,7 +793,6 @@ static bool InitLinkMap_32(MmapFile& irExec, MmapFile& irCore)
//////////////////////////////////////////////////////////////
bool InitCoreAnalyzer(MmapFile& irExec, MmapFile& irCore)
{
register_heap_managers();
int ptr_bit = g_ptr_bit;
bool rc;
if (ptr_bit == 64)
Expand All @@ -812,7 +811,7 @@ bool InitCoreAnalyzer(MmapFile& irExec, MmapFile& irCore)
else
rc = InitLinkMap_32 (irExec, irCore);

return rc;
return init_heap_managers();
}

static bool VerifyELFHeader(Elf64_Ehdr* elfhdr )
Expand Down
3 changes: 1 addition & 2 deletions src/core_pe_x86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -688,10 +688,9 @@ extern bool g_dbgheap;

bool InitCoreAnalyzer(MmapFile& irExec, MmapFile& irCore)
{
register_heap_managers();
bool rc = BuildSegments(irCore) /*&& test_segments(true)*/;

return rc;
return init_heap_managers();
}

static struct ca_segment*
Expand Down
64 changes: 50 additions & 14 deletions src/heap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,63 @@
#include "search.h"


CoreAnalyzerHeapInterface* gCAHeap;

#define ENSURE_CA_HEAP() \
do { \
if (!CA_HEAP) { \
CA_PRINT("No heap manager is detedted or selected.\n"); \
return false; \
} \
} while (0)

std::map<std::string, CoreAnalyzerHeapInterface*> gCoreAnalyzerHeaps;

CoreAnalyzerHeapInterface* gCAHeap;
void register_heap_managers() {
static std::vector<void(*)()> gHeapRegistrationFuncs = {
#ifdef WIN32
gCoreAnalyzerHeaps[HeapManagerMscrtMalloc] = get_mscrt_malloc_heap_manager();
gCAHeap = get_mscrt_malloc_heap_manager();
register_mscrt_malloc,
#else
// heap.cpp is used by ref.dll, and we only support switching heap in Linux currently.
//gCoreAnalyzerHeaps.emplace(std::make_pair<std::string, CoreAnalyzerHeapInterface*>("pt", get_pt_malloc_heap_manager()));
//gCoreAnalyzerHeaps.emplace(std::make_pair<std::string, CoreAnalyzerHeapInterface*>("tc",get_tc_malloc_heap_manager()));
gCoreAnalyzerHeaps.emplace(std::make_pair<std::string, CoreAnalyzerHeapInterface*>("pt 2.35", get_pt_malloc_2_35_heap_manager()));
// default is pt malloc heap, in the future we will auto detect the heap.
gCAHeap = get_pt_malloc_2_35_heap_manager();
#endif
register_pt_malloc_2_27,
register_pt_malloc_2_31,
register_pt_malloc_2_35,
//register_tc_malloc,
#endif
};

bool init_heap_managers() {
gCoreAnalyzerHeaps.clear();
gCAHeap = nullptr;

for (auto f: gHeapRegistrationFuncs)
f();

if (gCAHeap) {
CA_HEAP->init_heap();
return true;
}
CA_PRINT("failed to parse heap data\n");
return false;
}

void register_heap_manager(std::string name, CoreAnalyzerHeapInterface* heapIntf, bool detected) {
gCoreAnalyzerHeaps[name] = heapIntf;
if (detected) {
/* TODO we need to resolve the scenario that multi heap managers are present */
gCAHeap = heapIntf;
}
}

std::string get_supported_heaps() {
std::string lSupportedHeaps;
bool first_entry = true;
for (const auto&[k, v] : gCoreAnalyzerHeaps) {
for (const auto &itr : gCoreAnalyzerHeaps) {
if (!first_entry)
{
lSupportedHeaps += ", ";
}
lSupportedHeaps +=k;
if (itr.second == gCAHeap)
lSupportedHeaps += "(current)";
lSupportedHeaps += itr.first;
first_entry = false;
}
return lSupportedHeaps;
Expand Down Expand Up @@ -128,6 +159,8 @@ char ca_help_msg[] = "Commands of core_analyzer " CA_VERSION_STRING "\n"
*/
bool heap_command_impl(const char* args)
{
ENSURE_CA_HEAP();

bool rc = true;

address_t addr = 0;
Expand Down Expand Up @@ -320,6 +353,8 @@ bool heap_command_impl(const char* args)
*/
bool ref_command_impl(const char* args)
{
ENSURE_CA_HEAP();

int rc;
bool threadref = false;
address_t addr = 0;
Expand Down Expand Up @@ -542,6 +577,8 @@ bool segment_command_impl(const char* args)
*/
bool pattern_command_impl(const char* args)
{
ENSURE_CA_HEAP();

address_t lo = 0, hi = 0;
// Parse user input options
// argument is in the form of <start> <end>
Expand Down Expand Up @@ -1293,7 +1330,6 @@ bool display_heap_leak_candidates(void)
*/
void display_mem_histogram(const char* prefix)
{

if (!g_mem_hist.num_buckets || !g_mem_hist.bucket_sizes
|| !g_mem_hist.inuse_cnt || !g_mem_hist.inuse_bytes
|| !g_mem_hist.free_cnt || !g_mem_hist.free_bytes)
Expand Down
28 changes: 23 additions & 5 deletions src/heap.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,30 @@ extern std::map<std::string, CoreAnalyzerHeapInterface*> gCoreAnalyzerHeaps;

extern CoreAnalyzerHeapInterface* gCAHeap;
#define CA_HEAP gCAHeap
extern void register_heap_managers();

extern CoreAnalyzerHeapInterface* get_pt_malloc_heap_manager();
extern CoreAnalyzerHeapInterface* get_pt_malloc_2_35_heap_manager();
extern CoreAnalyzerHeapInterface* get_tc_malloc_heap_manager();
extern CoreAnalyzerHeapInterface* get_mscrt_malloc_heap_manager();
/*
* This function is called at bootstrap or when target is changed
* and after target memory layout is scanned.
*/
extern bool init_heap_managers();

/*
* Individual heap manager calls this function in its init function
* to declare its name, heap interface, and whether it detects its heap data in the target.
*/
extern void register_heap_manager(std::string, CoreAnalyzerHeapInterface*, bool);

/*
* Each heap manager implements an init function
* Maybe we don't need to explicitly expose them. We may scape these functions at compile time
* the same way gdb commands initializers are collected.
*/
extern void register_pt_malloc_2_27();
extern void register_pt_malloc_2_31();
extern void register_pt_malloc_2_35();
extern void register_tc_malloc();
extern void register_mscrt_malloc();

extern std::string get_supported_heaps();

extern struct inuse_block* build_inuse_heap_blocks(unsigned long*);
Expand Down
4 changes: 2 additions & 2 deletions src/heap_mscrt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,8 @@ CoreAnalyzerHeapInterface sMscrtMallocHeap = {
get_biggest_blocks,
walk_inuse_blocks,
};
CoreAnalyzerHeapInterface* get_mscrt_malloc_heap_manager() {
return &sMscrtMallocHeap;
void register_mscrt_malloc() {
register_heap_manager(HeapManagerMscrtMalloc, &sMscrtMallocHeap, true);
}
/////////////////////////////////////////////////////
// Implementation of heap walk
Expand Down
4 changes: 2 additions & 2 deletions src/heap_ptmalloc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -665,8 +665,8 @@ static CoreAnalyzerHeapInterface sPtMallHeapManager = {
walk_inuse_blocks,
};

CoreAnalyzerHeapInterface* get_pt_malloc_heap_manager() {
return &sPtMallHeapManager;
void register_pt_malloc() {
return register_heap_manager("pt", &sPtMallHeapManager, true);
}
/***************************************************************************
* Ptmalloc Helper Functions
Expand Down
Loading

0 comments on commit baba787

Please sign in to comment.