Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions addr2sym.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <string>
#include <vector>

#if __unix__
# include <cxxabi.h>
Expand Down Expand Up @@ -114,3 +115,11 @@ inline std::string addr2sym(void *addr) {
return oss.str();
}
#endif

inline std::vector<std::string> addrList2symList(std::vector<void*> addrList) {
std::vector<std::string> symList;
for(auto addr : addrList) {
symList.push_back(addr2sym(addr));
}
return symList;
}
3 changes: 2 additions & 1 deletion alloc_action.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <cstddef>
#include <cstdint>
#include <vector>

enum class AllocOp {
New,
Expand All @@ -23,7 +24,7 @@ struct AllocAction {
void *ptr;
size_t size;
size_t align;
void *caller;
std::vector<void *> call_stack;
int64_t time;
};

Expand Down
80 changes: 71 additions & 9 deletions malloc_hook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,14 +192,14 @@ struct EnableGuard {
}

void on(AllocOp op, void *ptr, size_t size, size_t align,
void *caller) const {
std::vector<void *> call_stack) const {
if (ptr) {
auto now = std::chrono::high_resolution_clock::now();
int64_t time = std::chrono::duration_cast<std::chrono::nanoseconds>(
now.time_since_epoch())
.count();
per_thread->actions.push_back(
AllocAction{op, tid, ptr, size, align, caller, time});
AllocAction{op, tid, ptr, size, align, call_stack, time});
}
}

Expand All @@ -222,6 +222,13 @@ extern "C" void *__libc_reallocarray(void *ptr, size_t nmemb,
size_t size) noexcept;
extern "C" void *__libc_valloc(size_t size) noexcept;
extern "C" void *__libc_memalign(size_t align, size_t size) noexcept;

static std::vector<void*> return_call_stack(){
std::vector<void*> callStack(1024);
callStack.resize(backtrace(callStack.data(), callStack.size()));
return {callStack.begin() + 1, callStack.end()};
}

# define REAL_LIBC(name) __libc_##name
# ifndef MAY_OVERRIDE_MALLOC
# define MAY_OVERRIDE_MALLOC 1
Expand All @@ -230,20 +237,25 @@ extern "C" void *__libc_memalign(size_t align, size_t size) noexcept;
# define MAY_SUPPORT_MEMALIGN 1
# endif
# undef RETURN_ADDRESS
#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1)
# define RETURN_ADDRESS return_call_stack()
#endif
# ifndef RETURN_ADDRESS
# ifdef __has_builtin
# if __has_builtin(__builtin_return_address)
# if __has_builtin(__builtin_extract_return_addr)
# define RETURN_ADDRESS \
__builtin_extract_return_addr(__builtin_return_address(0))
std::vector<void *>{__builtin_extract_return_addr(__builtin_return_address(0))}
# else
# define RETURN_ADDRESS __builtin_return_address(0)
# define RETURN_ADDRESS std::vector<void *>{__builtin_return_address(0)}
# endif
# endif
# elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
# define RETURN_ADDRESS __builtin_return_address(0)
# define RETURN_ADDRESS std::vector<void *>{__builtin_return_address(0)}
# endif
# endif
# ifndef RETURN_ADDRESS
# define RETURN_ADDRESS ((void *)0)
# define RETURN_ADDRESS (std::vector<void *>{0})
# pragma message("Cannot find __builtin_return_address")
# endif
# define CSTDLIB_NOEXCEPT noexcept
Expand Down Expand Up @@ -278,8 +290,58 @@ static void *msvc_reallocarray(void *ptr, size_t nmemb, size_t size) noexcept {

# include <intrin.h>

# pragma intrinsic(_ReturnAddress)
# define RETURN_ADDRESS _ReturnAddress()
static std::vector<void*> return_call_stack(){
std::vector<void*> callStack;

// 获取当前上下文
CONTEXT context;
RtlCaptureContext(&context);

// 初始化 STACKFRAME64
STACKFRAME64 stackFrame;
ZeroMemory(&stackFrame, sizeof(STACKFRAME64));

#ifdef _M_IX86
stackFrame.AddrPC.Offset = context.Eip;
stackFrame.AddrPC.Mode = AddrModeFlat;
stackFrame.AddrFrame.Offset = context.Ebp;
stackFrame.AddrFrame.Mode = AddrModeFlat;
stackFrame.AddrStack.Offset = context.Esp;
stackFrame.AddrStack.Mode = AddrModeFlat;
#elif _M_X64
stackFrame.AddrPC.Offset = context.Rip;
stackFrame.AddrPC.Mode = AddrModeFlat;
stackFrame.AddrFrame.Offset = context.Rbp;
stackFrame.AddrFrame.Mode = AddrModeFlat;
stackFrame.AddrStack.Offset = context.Rsp;
stackFrame.AddrStack.Mode = AddrModeFlat;
#endif

// 遍历堆栈
while (StackWalk64(
#ifdef _M_IX86
IMAGE_FILE_MACHINE_I386,
#elif _M_X64
IMAGE_FILE_MACHINE_AMD64,
#endif
GetCurrentProcess(),
GetCurrentThread(),
&stackFrame,
&context,
NULL,
SymFunctionTableAccess64,
SymGetModuleBase64,
NULL)) {
if (stackFrame.AddrPC.Offset == 0) {
break; // 结束遍历
}
callStack.push_back((void*)stackFrame.AddrPC.Offset);
}

return {callStack.begin() + 1, callStack.end()};
}

# define RETURN_ADDRESS return_call_stack()
# define CSTDLIB_NOEXCEPT

#else
Expand All @@ -290,7 +352,7 @@ static void *msvc_reallocarray(void *ptr, size_t nmemb, size_t size) noexcept {
# ifndef MAY_OVERRIDE_MEMALIGN
# define MAY_SUPPORT_MEMALIGN 0
# endif
# define RETURN_ADDRESS ((void *)1)
# define RETURN_ADDRESS (std::vector<void *>{1})
# define CSTDLIB_NOEXCEPT
#endif

Expand Down
93 changes: 65 additions & 28 deletions plot_actions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ struct LifeBlock {
uint32_t end_tid;
void *ptr;
size_t size;
void *start_caller;
void *end_caller;
std::vector<void *> start_call_stack;
std::vector<void *> end_call_stack;
int64_t start_time;
int64_t end_time;
};
Expand Down Expand Up @@ -131,7 +131,7 @@ struct SvgWriter {
}

void text(double x, double y, std::string const &color,
std::string const &alignment, std::string const &text) {
std::string const &alignment, std::string const &text, std::string const &title) {
x += margin;
// HTML escape text:
std::string html;
Expand All @@ -146,8 +146,21 @@ struct SvgWriter {
default: html += c; break;
}
}
std::string html_title;
html_title.reserve(title.size());
for (auto c: title) {
switch (c) {
case '&': html_title += "&amp;"; break;
case '<': html_title += "&lt;"; break;
case '>': html_title += "&gt;"; break;
case '"': html_title += "&quot;"; break;
case '\'': html_title += "&apos;"; break;
default: html_title += c; break;
}
}
out << "<text x=\"" << x << "\" y=\"" << y << "\" fill=\"" << color
<< "\"" << alignment << ">" << html << "</text>\n";
<< "\"" << alignment << ">" << "<title>" << html_title << "</title>"
<< html << "</text>\n";
}

SvgWriter(SvgWriter &&) = delete;
Expand Down Expand Up @@ -470,15 +483,15 @@ void mallocvis_plot_alloc_actions(std::vector<AllocAction> actions) {
if (kAllocOpIsAllocation[(size_t)action.op]) {
living.insert({action.ptr,
{action.op, action.op, action.tid, action.tid,
action.ptr, action.size, action.caller,
action.caller, action.time, action.time}});
action.ptr, action.size, action.call_stack,
action.call_stack, action.time, action.time}});
} else {
auto it = living.find(action.ptr);
if (it != living.end()) {
it->second.end_op = action.op;
it->second.end_tid = action.tid;
it->second.end_time = action.time;
it->second.end_caller = action.caller;
it->second.end_call_stack = action.call_stack;
dead.insert(it->second);
living.erase(it);
}
Expand Down Expand Up @@ -513,10 +526,10 @@ void mallocvis_plot_alloc_actions(std::vector<AllocAction> actions) {
if (block.end_time > block.start_time) {
end_time = std::max(end_time, block.end_time);
}
start_caller = std::min(start_caller, (uintptr_t)block.start_caller);
end_caller = std::max(end_caller, (uintptr_t)block.start_caller);
start_caller = std::min(start_caller, (uintptr_t)block.end_caller);
end_caller = std::max(end_caller, (uintptr_t)block.end_caller);
start_caller = std::min(start_caller, (uintptr_t)block.start_call_stack[0]);
end_caller = std::max(end_caller, (uintptr_t)block.start_call_stack[0]);
start_caller = std::min(start_caller, (uintptr_t)block.end_call_stack[0]);
end_caller = std::max(end_caller, (uintptr_t)block.end_call_stack[0]);
start_ptr = std::min(start_ptr, (uintptr_t)block.ptr);
end_ptr = std::max(end_ptr, (uintptr_t)block.ptr + block.size);
tids.insert({block.start_tid, tids.size()});
Expand All @@ -527,11 +540,11 @@ void mallocvis_plot_alloc_actions(std::vector<AllocAction> actions) {
for (auto &[_, block]: living) {
start_time = std::min(start_time, block.start_time);
block.end_time = end_time;
block.end_caller = nullptr;
start_caller = std::min(start_caller, (uintptr_t)block.start_caller);
end_caller = std::max(end_caller, (uintptr_t)block.start_caller);
start_caller = std::min(start_caller, (uintptr_t)block.end_caller);
end_caller = std::max(end_caller, (uintptr_t)block.end_caller);
block.end_call_stack[0] = nullptr;
start_caller = std::min(start_caller, (uintptr_t)block.start_call_stack[0]);
end_caller = std::max(end_caller, (uintptr_t)block.start_call_stack[0]);
start_caller = std::min(start_caller, (uintptr_t)block.end_call_stack[0]);
end_caller = std::max(end_caller, (uintptr_t)block.end_call_stack[0]);
start_ptr = std::min(start_ptr, (uintptr_t)block.ptr);
end_ptr = std::max(end_ptr, (uintptr_t)block.ptr + block.size);
tids.insert({block.start_tid, tids.size()});
Expand Down Expand Up @@ -562,10 +575,10 @@ void mallocvis_plot_alloc_actions(std::vector<AllocAction> actions) {
double z0 = 0;
double z1 = 0;
if (options.z_indicates == PlotOptions::Caller) {
z0 = ((uintptr_t)block.start_caller - start_caller) *
z0 = ((uintptr_t)block.start_call_stack[0] - start_caller) *
caller_scale;
z1 =
((uintptr_t)block.end_caller - start_caller) * caller_scale;
((uintptr_t)block.end_call_stack[0] - start_caller) * caller_scale;
} else if (options.z_indicates == PlotOptions::Thread) {
z0 = tids.at(block.start_tid);
z1 = tids.at(block.end_tid);
Expand Down Expand Up @@ -600,8 +613,8 @@ void mallocvis_plot_alloc_actions(std::vector<AllocAction> actions) {
for (auto const &block: dead) {
double height = eval_height(block);
total_height += height;
callers.insert(block.start_caller);
callers.insert(block.end_caller);
callers.insert(block.start_call_stack[0]);
callers.insert(block.end_call_stack[0]);
}
if (options.layout == PlotOptions::Address) {
total_height = end_ptr - start_ptr;
Expand Down Expand Up @@ -634,13 +647,13 @@ void mallocvis_plot_alloc_actions(std::vector<AllocAction> actions) {

auto eval_color =
[&](LifeBlock const &block) -> std::pair<std::string, std::string> {
return {caller_color(block.start_caller),
caller_color(block.end_caller)};
return {caller_color(block.start_call_stack[0]),
caller_color(block.end_call_stack[0])};
};

auto eval_text =
[](LifeBlock const &block) -> std::pair<std::string, std::string> {
return {addr2sym(block.start_caller), addr2sym(block.end_caller)};
[](LifeBlock const &block) -> std::pair<std::vector<std::string>, std::vector<std::string>> {
return {addrList2symList(block.start_call_stack), addrList2symList(block.end_call_stack)};
};

SvgWriter svg(options.path.empty() ? "malloc.html" : options.path,
Expand Down Expand Up @@ -669,12 +682,18 @@ void mallocvis_plot_alloc_actions(std::vector<AllocAction> actions) {
fontHeight1 *=
max_width / (fontHeight * 0.5 * text1.size());
}
std::string title;
for(auto &ti : text1)
{
title += ti;
title += '\n';
}
svg.text(
x, y + height * 0.5, color1,
" style=\"dominant-baseline:central;text-anchor:"
"end;font-size:" +
std::to_string(fontHeight1) + "px;\"",
text1);
text1[0], title);
}
if (!text2.empty()) {
auto max_width =
Expand All @@ -684,12 +703,18 @@ void mallocvis_plot_alloc_actions(std::vector<AllocAction> actions) {
fontHeight1 *=
max_width / (fontHeight * 0.5 * text2.size());
}
std::string title;
for(auto &ti : text2)
{
title += ti;
title += '\n';
}
svg.text(
x + width, y + height * 0.5, color2,
" style=\"dominant-baseline:central;text-anchor:"
"start;font-size:" +
std::to_string(fontHeight1) + "px;\"",
text2);
text2[0], title);
}
}
}
Expand All @@ -714,12 +739,18 @@ void mallocvis_plot_alloc_actions(std::vector<AllocAction> actions) {
fontHeight1 *=
max_width / (fontHeight * 0.5 * text1.size());
}
std::string title;
for(auto &ti : text1)
{
title += ti;
title += '\n';
}
svg.text(
x, y + height * 0.5, color1,
" style=\"dominant-baseline:central;text-anchor:"
"end;font-size:" +
std::to_string(fontHeight1) + "px;\"",
text1);
text1[0], title);
}
if (!text2.empty()) {
auto max_width =
Expand All @@ -729,12 +760,18 @@ void mallocvis_plot_alloc_actions(std::vector<AllocAction> actions) {
fontHeight1 *=
max_width / (fontHeight * 0.5 * text2.size());
}
std::string title;
for(auto &ti : text2)
{
title += ti;
title += '\n';
}
svg.text(
x + width, y + height * 0.5, color2,
" style=\"dominant-baseline:central;text-anchor:"
"start;font-size:" +
std::to_string(fontHeight1) + "px;\"",
text2);
text2[0], title);
}
}
y += height;
Expand Down