From 7bfb48d6abb248d9739281ae46f8e9f52fcd16e3 Mon Sep 17 00:00:00 2001 From: Tannin Date: Sat, 20 Dec 2014 14:45:08 +0100 Subject: cleanup --- src/shared/leaktrace.cpp | 78 +---------------------- src/shared/shared.pro | 10 +-- src/shared/stackdata.cpp | 163 +++++++++++++++++++++++++++++++++++++++++++++++ src/shared/stackdata.h | 50 +++++++++++++++ 4 files changed, 221 insertions(+), 80 deletions(-) create mode 100644 src/shared/stackdata.cpp create mode 100644 src/shared/stackdata.h (limited to 'src/shared') diff --git a/src/shared/leaktrace.cpp b/src/shared/leaktrace.cpp index 729eb42e..0d99b82e 100644 --- a/src/shared/leaktrace.cpp +++ b/src/shared/leaktrace.cpp @@ -1,4 +1,5 @@ #include "leaktrace.h" +#include "stackdata.h" #include #include #include @@ -8,82 +9,7 @@ #include -static const int FRAMES_TO_SKIP = 3; // StackData::StackData(), __TraceData::regTrace(), TraceAlloc() -static const int FRAMES_TO_CAPTURE = 10; - - -void initDbgIfNecessary() -{ - HANDLE process = ::GetCurrentProcess(); - static std::set initialized; - if (initialized.find(::GetCurrentProcessId()) == initialized.end()) { - static bool firstCall = true; - if (firstCall) { - ::SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS); - firstCall = false; - } - if (!::SymInitialize(process, NULL, TRUE)) { - printf("failed to initialize symbols: %d", ::GetLastError()); - } - initialized.insert(::GetCurrentProcessId()); - } -} - - -class StackData { - friend bool operator==(const StackData &LHS, const StackData &RHS); - friend bool operator<(const StackData &LHS, const StackData &RHS); -public: - - StackData() - : m_Count(0), m_Hash(0UL), m_FunctionName("Dummy"), m_CodeLine(0) - {} - StackData(const char *functionName, int line) { - m_Count = ::CaptureStackBackTrace(FRAMES_TO_SKIP, FRAMES_TO_CAPTURE, m_Stack, &m_Hash); - m_FunctionName = functionName; - m_CodeLine = line; - if (m_Count == 0) { - // TODO in this case the hash doesn't seem to be set. This is of course not a good solution - m_Hash = reinterpret_cast(m_FunctionName) + m_CodeLine; - } - } - std::string toString() const { - initDbgIfNecessary(); - - char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)]; - PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer; - symbol->SizeOfStruct = sizeof(SYMBOL_INFO); - symbol->MaxNameLen = MAX_SYM_NAME; - - std::ostringstream stackStream; - - stackStream << m_FunctionName << " [" << m_CodeLine << "]\n"; - - for(unsigned int i = 0; i < m_Count; ++i) { - DWORD64 displacement = 0; - if (!::SymFromAddr(::GetCurrentProcess(), (DWORD64)m_Stack[i], &displacement, symbol)) { - stackStream << m_Count - i - 1 << ": [" << m_Stack[i] << "]\n"; - } else { - stackStream << m_Count - i - 1 << ": " << symbol->Name << "\n"; - } - } - return stackStream.str(); - } -private: - LPVOID m_Stack[FRAMES_TO_CAPTURE]; - USHORT m_Count; - ULONG m_Hash; - const char *m_FunctionName; - int m_CodeLine; -}; - -bool operator==(const StackData &LHS, const StackData &RHS) { - return LHS.m_Hash == RHS.m_Hash; -} - -bool operator<(const StackData &LHS, const StackData &RHS) { - return LHS.m_Hash < RHS.m_Hash; -} +using namespace MOShared; static struct __TraceData { diff --git a/src/shared/shared.pro b/src/shared/shared.pro index 69f6f2e6..1e26b7c0 100644 --- a/src/shared/shared.pro +++ b/src/shared/shared.pro @@ -28,7 +28,8 @@ SOURCES += \ util.cpp \ skyriminfo.cpp \ appconfig.cpp \ - leaktrace.cpp + leaktrace.cpp \ + stackdata.cpp HEADERS += \ inject.h \ @@ -43,12 +44,13 @@ HEADERS += \ skyriminfo.h \ appconfig.h \ appconfig.inc \ - leaktrace.h + leaktrace.h \ + stackdata.h # only for custom leak detection -DEFINES += TRACE_LEAKS -LIBS += -lDbgHelp +#DEFINES += TRACE_LEAKS +#LIBS += -lDbgHelp CONFIG(debug, debug|release) { diff --git a/src/shared/stackdata.cpp b/src/shared/stackdata.cpp new file mode 100644 index 00000000..7f6f6e52 --- /dev/null +++ b/src/shared/stackdata.cpp @@ -0,0 +1,163 @@ +#include "stackdata.h" + +#include +#include +#include +#include +#include + + +using namespace MOShared; + + +void initDbgIfNecess() +{ + HANDLE process = ::GetCurrentProcess(); + static std::set initialized; + if (initialized.find(::GetCurrentProcessId()) == initialized.end()) { + static bool firstCall = true; + if (firstCall) { + ::SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS); + firstCall = false; + } + if (!::SymInitialize(process, NULL, TRUE)) { + printf("failed to initialize symbols: %d", ::GetLastError()); + } + initialized.insert(::GetCurrentProcessId()); + } +} + + + +StackData::StackData() + : m_Count(0) + , m_Function() + , m_Line(-1) +{ + initTrace(); +} + +StackData::StackData(const char *function, int line) + : m_Count(0) + , m_Function(function) + , m_Line(line) +{ + +} + +std::string StackData::toString() const { + initDbgIfNecess(); + + char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)]; + PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer; + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + symbol->MaxNameLen = MAX_SYM_NAME; + + std::ostringstream stackStream; + + if (m_Function.length() > 0) { + stackStream << "[" << m_Function << ":" << m_Line << "]\n"; + } + + for(unsigned int i = 0; i < m_Count; ++i) { + DWORD64 displacement = 0; + if (!::SymFromAddr(::GetCurrentProcess(), (DWORD64)m_Stack[i], &displacement, symbol)) { + stackStream << m_Count - i - 1 << ": [" << m_Stack[i] << "]\n"; + } else { + stackStream << m_Count - i - 1 << ": " << symbol->Name << "\n"; + } + } + return stackStream.str(); +} + +void StackData::load_modules(HANDLE process, DWORD processID) { + HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, processID); + if (snap == INVALID_HANDLE_VALUE) + return; + + MODULEENTRY32 entry; + entry.dwSize = sizeof(entry); + + if (Module32First(snap, &entry)) { + do { + std::string fileName = ToString(entry.szExePath, false); + std::string moduleName = ToString(entry.szModule, false); + SymLoadModule64(process, NULL, fileName.c_str(), moduleName.c_str(), (DWORD64) entry.modBaseAddr, entry.modBaseSize); + } while (Module32Next(snap, &entry)); + } + CloseHandle(snap); +} + +#include "error_report.h" +#include + +void StackData::initTrace() { + load_modules(::GetCurrentProcess(), ::GetCurrentProcessId()); + CONTEXT context; + std::memset(&context, 0, sizeof(CONTEXT)); + context.ContextFlags = CONTEXT_CONTROL; +#if BOOST_ARCH_X86_64 + ::RtlCaptureContext(&context); +#else + __asm + { + Label: + mov [context.Ebp], ebp; + mov [context.Esp], esp; + mov eax, [Label]; + mov [context.Eip], eax; + } +#endif + + STACKFRAME64 stackFrame; + ::ZeroMemory(&stackFrame, sizeof(STACKFRAME64)); + 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; + m_Count = 0; + while (m_Count < FRAMES_TO_CAPTURE) { + if (!StackWalk64(IMAGE_FILE_MACHINE_I386, ::GetCurrentProcess(), + ::GetCurrentThread(), &stackFrame, &context, NULL, + &SymFunctionTableAccess64, &SymGetModuleBase64, NULL)) { + break; + } + + if (stackFrame.AddrPC.Offset == 0) { + continue; + break; + } + + m_Stack[m_Count++] = reinterpret_cast(stackFrame.AddrPC.Offset); + } +} + + +bool MOShared::operator==(const StackData &LHS, const StackData &RHS) { + if (LHS.m_Count != RHS.m_Count) { + return false; + } else { + for (int i = 0; i < LHS.m_Count; ++i) { + if (LHS.m_Stack[i] != RHS.m_Stack[i]) { + return false; + } + } + } + return true; +} + + +bool MOShared::operator<(const StackData &LHS, const StackData &RHS) { + if (LHS.m_Count != RHS.m_Count) { + return LHS.m_Count < RHS.m_Count; + } else { + for (int i = 0; i < LHS.m_Count; ++i) { + if (LHS.m_Stack[i] != RHS.m_Stack[i]) { + return LHS.m_Stack[i] < RHS.m_Stack[i]; + } + } + } + return false; +} diff --git a/src/shared/stackdata.h b/src/shared/stackdata.h new file mode 100644 index 00000000..7151699c --- /dev/null +++ b/src/shared/stackdata.h @@ -0,0 +1,50 @@ +#ifndef STACKDATA_H +#define STACKDATA_H + + +#include +#include + + +namespace MOShared { + + +class StackData { + friend bool operator==(const StackData &LHS, const StackData &RHS); + friend bool operator<(const StackData &LHS, const StackData &RHS); +public: + + StackData(); + StackData(const char *function, int line); + + std::string toString() const; + +private: + + void load_modules(HANDLE process, DWORD processID); + + void initTrace(); + +private: + + static const int FRAMES_TO_SKIP = 1; + static const int FRAMES_TO_CAPTURE = 20; + +private: + + LPVOID m_Stack[FRAMES_TO_CAPTURE]; + USHORT m_Count; + std::string m_Function; + int m_Line; + +}; + + +bool operator==(const StackData &LHS, const StackData &RHS); + +bool operator<(const StackData &LHS, const StackData &RHS); + +} // namespace MOShared + + +#endif // STACKDATA_H -- cgit v1.3.1