Chocobo1
3 years ago
committed by
GitHub
11 changed files with 122 additions and 534 deletions
@ -0,0 +1,36 @@
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent. |
||||
* Copyright (C) 2022 Mike Tzou (Chocobo1) |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License |
||||
* as published by the Free Software Foundation; either version 2 |
||||
* of the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
* |
||||
* In addition, as a special exception, the copyright holders give permission to |
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with |
||||
* modified versions of it that use the same license as the "OpenSSL" library), |
||||
* and distribute the linked executables. You must obey the GNU General Public |
||||
* License in all respects for all of the code used other than "OpenSSL". If you |
||||
* modify file(s), you may extend this exception to your version of the file(s), |
||||
* but you are not obligated to do so. If you do not wish to do so, delete this |
||||
* exception statement from your version. |
||||
*/ |
||||
|
||||
#include "stacktrace.h" |
||||
|
||||
#include <boost/stacktrace.hpp> |
||||
|
||||
std::string getStacktrace() |
||||
{ |
||||
return boost::stacktrace::to_string(boost::stacktrace::stacktrace()); |
||||
} |
@ -1,116 +1,33 @@
@@ -1,116 +1,33 @@
|
||||
// stacktrace.h (c) 2008, Timo Bingmann from http://idlebox.net/
|
||||
// published under the WTFPL v2.0
|
||||
|
||||
#ifndef _STACKTRACE_H_ |
||||
#define _STACKTRACE_H_ |
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <execinfo.h> |
||||
#include <cxxabi.h> |
||||
|
||||
#include <vector> |
||||
|
||||
/** Print a demangled stack backtrace of the caller function to FILE* out. */ |
||||
static inline void print_stacktrace(FILE *out = stderr, const int max_frames = 63) |
||||
{ |
||||
fprintf(out, "Stack trace:\n"); |
||||
|
||||
// storage array for stack trace address data
|
||||
std::vector<void *> addrlist(max_frames + 1); |
||||
|
||||
// retrieve current stack addresses
|
||||
int addrlen = backtrace(addrlist.data(), addrlist.size()); |
||||
|
||||
if (addrlen == 0) |
||||
{ |
||||
fprintf(out, " <empty, possibly corrupt>\n"); |
||||
return; |
||||
} |
||||
|
||||
// resolve addresses into strings containing "filename(function+address)",
|
||||
// this array must be free()-ed
|
||||
char * *symbollist = backtrace_symbols(addrlist.data(), addrlen); |
||||
|
||||
// allocate string which will be filled with the demangled function name
|
||||
size_t funcnamesize = 256; |
||||
char *funcname = static_cast<char *>(malloc(funcnamesize)); |
||||
|
||||
int functionNamesFound = 0; |
||||
// iterate over the returned symbol lines. skip the first, it is the
|
||||
// address of this function.
|
||||
for (int i = 2; i < addrlen; i++) |
||||
{ |
||||
char *begin_name = 0, *begin_offset = 0, *end_offset = 0; |
||||
|
||||
// find parentheses and +address offset surrounding the mangled name:
|
||||
// ./module(function+0x15c) [0x8048a6d]
|
||||
// fprintf(out, "%s TT\n", symbollist[i]);
|
||||
for (char *p = symbollist[i]; *p; ++p) |
||||
{ |
||||
if (*p == '(') |
||||
{ |
||||
begin_name = p; |
||||
} |
||||
else if (*p == '+') |
||||
{ |
||||
begin_offset = p; |
||||
} |
||||
else if ((*p == ')') && begin_offset) |
||||
{ |
||||
end_offset = p; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (begin_name && begin_offset && end_offset |
||||
&& (begin_name < begin_offset)) |
||||
{ |
||||
*begin_name++ = '\0'; |
||||
*begin_offset++ = '\0'; |
||||
*end_offset = '\0'; |
||||
|
||||
// mangled name is now in [begin_name, begin_offset) and caller
|
||||
// offset in [begin_offset, end_offset). now apply
|
||||
// __cxa_demangle():
|
||||
|
||||
int status; |
||||
char *ret = abi::__cxa_demangle(begin_name, |
||||
funcname, &funcnamesize, &status); |
||||
if (status == 0) |
||||
{ |
||||
funcname = ret; // use possibly realloc()-ed string
|
||||
fprintf(out, " %s : %s+%s %s\n", |
||||
symbollist[i], funcname, begin_offset, ++end_offset); |
||||
} |
||||
else |
||||
{ |
||||
// demangling failed. Output function name as a C function with
|
||||
// no arguments.
|
||||
fprintf(out, " %s : %s()+%s %s\n", |
||||
symbollist[i], begin_name, begin_offset, ++end_offset); |
||||
} |
||||
++functionNamesFound; |
||||
} |
||||
else |
||||
{ |
||||
// couldn't parse the line? print the whole line.
|
||||
fprintf(out, " %s\n", symbollist[i]); |
||||
} |
||||
} |
||||
|
||||
if (!functionNamesFound) |
||||
{ |
||||
fprintf(out, "There were no function names found in the stack trace\n." |
||||
"Seems like debug symbols are not installed, and the stack trace is useless.\n"); |
||||
} |
||||
if (functionNamesFound < addrlen - 2) |
||||
{ |
||||
fprintf(out, "Consider installing debug symbols for packages containing files with empty" |
||||
" function names (i.e. empty braces \"()\") to make your stack trace more useful\n"); |
||||
} |
||||
free(funcname); |
||||
free(symbollist); |
||||
} |
||||
|
||||
#endif // _STACKTRACE_H_
|
||||
/*
|
||||
* Bittorrent Client using Qt and libtorrent. |
||||
* Copyright (C) 2022 Mike Tzou (Chocobo1) |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License |
||||
* as published by the Free Software Foundation; either version 2 |
||||
* of the License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
* |
||||
* In addition, as a special exception, the copyright holders give permission to |
||||
* link this program with the OpenSSL project's "OpenSSL" library (or with |
||||
* modified versions of it that use the same license as the "OpenSSL" library), |
||||
* and distribute the linked executables. You must obey the GNU General Public |
||||
* License in all respects for all of the code used other than "OpenSSL". If you |
||||
* modify file(s), you may extend this exception to your version of the file(s), |
||||
* but you are not obligated to do so. If you do not wish to do so, delete this |
||||
* exception statement from your version. |
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <string> |
||||
|
||||
std::string getStacktrace(); |
||||
|
@ -1,360 +0,0 @@
@@ -1,360 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2005-09 by the Quassel Project * |
||||
* devel@quassel-irc.org * |
||||
* * |
||||
* This program is free software; you can redistribute it and/or modify * |
||||
* it under the terms of the GNU General Public License as published by * |
||||
* the Free Software Foundation; either version 2 of the License, or * |
||||
* (at your option) version 3. * |
||||
* * |
||||
* This program is distributed in the hope that it will be useful, * |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of * |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
||||
* GNU General Public License for more details. * |
||||
* * |
||||
* You should have received a copy of the GNU General Public License * |
||||
* along with this program; if not, write to the * |
||||
* Free Software Foundation, Inc., * |
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * |
||||
***************************************************************************/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <windows.h> |
||||
#include <dbghelp.h> |
||||
#include <stdio.h> |
||||
|
||||
#include <QCoreApplication> |
||||
#include <QDir> |
||||
#include <QTextStream> |
||||
#ifdef __MINGW32__ |
||||
#include <cxxabi.h> |
||||
#endif |
||||
|
||||
#include "base/global.h" |
||||
|
||||
namespace straceWin |
||||
{ |
||||
void loadHelpStackFrame(IMAGEHLP_STACK_FRAME&, const STACKFRAME64&); |
||||
BOOL CALLBACK EnumSymbolsCB(PSYMBOL_INFO, ULONG, PVOID); |
||||
BOOL CALLBACK EnumModulesCB(LPCSTR, DWORD64, PVOID); |
||||
const QString getBacktrace(); |
||||
struct EnumModulesContext; |
||||
// Also works for MinGW64
|
||||
#ifdef __MINGW32__ |
||||
void demangle(QString& str); |
||||
#endif |
||||
|
||||
QString getSourcePathAndLineNumber(HANDLE hProcess, DWORD64 addr); |
||||
bool makeRelativePath(const QString& dir, QString& file); |
||||
} |
||||
|
||||
#ifdef __MINGW32__ |
||||
void straceWin::demangle(QString& str) |
||||
{ |
||||
char const* inStr = qPrintable(u"_" + str); // Really need that underline or demangling will fail
|
||||
int status = 0; |
||||
size_t outSz = 0; |
||||
char* demangled_name = abi::__cxa_demangle(inStr, 0, &outSz, &status); |
||||
if (status == 0) |
||||
{ |
||||
str = QString::fromLocal8Bit(demangled_name); |
||||
if (outSz > 0) |
||||
free(demangled_name); |
||||
} |
||||
} |
||||
#endif |
||||
|
||||
void straceWin::loadHelpStackFrame(IMAGEHLP_STACK_FRAME& ihsf, const STACKFRAME64& stackFrame) |
||||
{ |
||||
ZeroMemory(&ihsf, sizeof(IMAGEHLP_STACK_FRAME)); |
||||
ihsf.InstructionOffset = stackFrame.AddrPC.Offset; |
||||
ihsf.FrameOffset = stackFrame.AddrFrame.Offset; |
||||
} |
||||
|
||||
BOOL CALLBACK straceWin::EnumSymbolsCB(PSYMBOL_INFO symInfo, ULONG size, PVOID user) |
||||
{ |
||||
Q_UNUSED(size) |
||||
auto params = static_cast<QStringList *>(user); |
||||
if (symInfo->Flags & SYMFLAG_PARAMETER) |
||||
params->append(QString::fromUtf8(symInfo->Name)); |
||||
return TRUE; |
||||
} |
||||
|
||||
|
||||
struct straceWin::EnumModulesContext |
||||
{ |
||||
HANDLE hProcess; |
||||
QTextStream& stream; |
||||
EnumModulesContext(HANDLE hProcess, QTextStream& stream): hProcess(hProcess), stream(stream) {} |
||||
}; |
||||
|
||||
BOOL CALLBACK straceWin::EnumModulesCB(LPCSTR ModuleName, DWORD64 BaseOfDll, PVOID UserContext) |
||||
{ |
||||
Q_UNUSED(ModuleName) |
||||
IMAGEHLP_MODULE64 mod; |
||||
auto context = static_cast<EnumModulesContext *>(UserContext); |
||||
mod.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); |
||||
if(SymGetModuleInfo64(context->hProcess, BaseOfDll, &mod)) |
||||
{ |
||||
QString moduleBase = u"0x%1"_qs.arg(BaseOfDll, 16, 16, QChar(u'0')); |
||||
QString line = u"%1 %2 Image: %3"_qs |
||||
.arg(QString::fromUtf8(mod.ModuleName), -25) |
||||
.arg(moduleBase, -13) |
||||
.arg(QString::fromUtf8(mod.LoadedImageName)); |
||||
context->stream << line << '\n'; |
||||
|
||||
const auto pdbName = QString::fromUtf8(mod.LoadedPdbName); |
||||
if(!pdbName.isEmpty()) |
||||
{ |
||||
QString line2 = u"%1 %2"_qs |
||||
.arg(u""_qs, 35) |
||||
.arg(pdbName); |
||||
context->stream << line2 << '\n'; |
||||
} |
||||
} |
||||
return TRUE; |
||||
} |
||||
|
||||
|
||||
/**
|
||||
* Cuts off leading 'dir' path from 'file' path, otherwise leaves it unchanged |
||||
* returns true if 'dir' is an ancestor of 'file', otherwise - false |
||||
*/ |
||||
bool straceWin::makeRelativePath(const QString &dir, QString &file) |
||||
{ |
||||
QString d = QDir::toNativeSeparators(QDir(dir).absolutePath()); |
||||
QString f = QDir::toNativeSeparators(QFileInfo(file).absoluteFilePath()); |
||||
|
||||
// append separator at the end of dir
|
||||
QChar separator = QDir::separator(); |
||||
if (!d.isEmpty() && (d[d.length() - 1] != separator)) |
||||
d += separator; |
||||
|
||||
if (f.startsWith(d, Qt::CaseInsensitive)) |
||||
{ |
||||
f.remove(0, d.length()); |
||||
file.swap(f); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
QString straceWin::getSourcePathAndLineNumber(HANDLE hProcess, DWORD64 addr) |
||||
{ |
||||
IMAGEHLP_LINE64 line {}; |
||||
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); |
||||
DWORD dwDisplacement = 0; |
||||
|
||||
if (SymGetLineFromAddr64(hProcess, addr, &dwDisplacement, &line)) |
||||
{ |
||||
auto path = QString::fromUtf8(line.FileName); |
||||
|
||||
#if defined STACKTRACE_WIN_PROJECT_PATH || defined STACKTRACE_WIN_MAKEFILE_PATH |
||||
|
||||
#define STACKTRACE_WIN_QUOTE(x) #x |
||||
#define STACKTRACE_WIN_STRING(x) STACKTRACE_WIN_QUOTE(x) |
||||
|
||||
//prune leading project directory path or build target directory path
|
||||
|
||||
bool success = false; |
||||
#ifdef STACKTRACE_WIN_PROJECT_PATH |
||||
const auto projectPath = QStringLiteral(STACKTRACE_WIN_STRING(STACKTRACE_WIN_PROJECT_PATH)); |
||||
success = makeRelativePath(projectPath, path); |
||||
#endif |
||||
|
||||
#ifdef STACKTRACE_WIN_MAKEFILE_PATH |
||||
if (!success) |
||||
{ |
||||
const auto targetPath = QStringLiteral(STACKTRACE_WIN_STRING(STACKTRACE_WIN_MAKEFILE_PATH)); |
||||
makeRelativePath(targetPath, path); |
||||
} |
||||
#endif |
||||
#endif |
||||
return u"%1 : %2"_qs.arg(path).arg(line.LineNumber); |
||||
} |
||||
|
||||
return QString(); |
||||
} |
||||
|
||||
|
||||
#if defined( _M_IX86 ) && defined(Q_CC_MSVC) |
||||
// Disable global optimization and ignore /GS waning caused by
|
||||
// inline assembly.
|
||||
// not needed with mingw cause we can tell mingw which registers we use
|
||||
#pragma optimize("g", off) |
||||
#pragma warning(push) |
||||
#pragma warning(disable : 4748) |
||||
#endif |
||||
const QString straceWin::getBacktrace() |
||||
{ |
||||
DWORD MachineType; |
||||
CONTEXT Context; |
||||
STACKFRAME64 StackFrame; |
||||
|
||||
#ifdef _M_IX86 |
||||
ZeroMemory(&Context, sizeof(CONTEXT)); |
||||
Context.ContextFlags = CONTEXT_CONTROL; |
||||
|
||||
|
||||
#ifdef __MINGW32__ |
||||
asm ("Label:\n\t" |
||||
"movl %%ebp,%0;\n\t" |
||||
"movl %%esp,%1;\n\t" |
||||
"movl $Label,%%eax;\n\t" |
||||
"movl %%eax,%2;\n\t" |
||||
: "=r" (Context.Ebp),"=r" (Context.Esp),"=r" (Context.Eip) |
||||
: //no input
|
||||
: "eax"); |
||||
#else |
||||
_asm |
||||
{ |
||||
Label: |
||||
mov [Context.Ebp], ebp; |
||||
mov [Context.Esp], esp; |
||||
mov eax, [Label]; |
||||
mov [Context.Eip], eax; |
||||
} |
||||
#endif |
||||
#else |
||||
RtlCaptureContext(&Context); |
||||
#endif |
||||
|
||||
ZeroMemory(&StackFrame, sizeof(STACKFRAME64)); |
||||
#ifdef _M_IX86 |
||||
MachineType = IMAGE_FILE_MACHINE_I386; |
||||
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 |
||||
MachineType = IMAGE_FILE_MACHINE_AMD64; |
||||
StackFrame.AddrPC.Offset = Context.Rip; |
||||
StackFrame.AddrPC.Mode = AddrModeFlat; |
||||
StackFrame.AddrFrame.Offset = Context.Rsp; |
||||
StackFrame.AddrFrame.Mode = AddrModeFlat; |
||||
StackFrame.AddrStack.Offset = Context.Rsp; |
||||
StackFrame.AddrStack.Mode = AddrModeFlat; |
||||
#elif _M_IA64 |
||||
MachineType = IMAGE_FILE_MACHINE_IA64; |
||||
StackFrame.AddrPC.Offset = Context.StIIP; |
||||
StackFrame.AddrPC.Mode = AddrModeFlat; |
||||
StackFrame.AddrFrame.Offset = Context.IntSp; |
||||
StackFrame.AddrFrame.Mode = AddrModeFlat; |
||||
StackFrame.AddrBStore.Offset = Context.RsBSP; |
||||
StackFrame.AddrBStore.Mode = AddrModeFlat; |
||||
StackFrame.AddrStack.Offset = Context.IntSp; |
||||
StackFrame.AddrStack.Mode = AddrModeFlat; |
||||
#else |
||||
#error "Unsupported platform" |
||||
#endif |
||||
|
||||
QString log; |
||||
QTextStream logStream(&log); |
||||
logStream << "```\n"; |
||||
|
||||
const std::wstring appPath = QCoreApplication::applicationDirPath().toStdWString(); |
||||
HANDLE hProcess = GetCurrentProcess(); |
||||
HANDLE hThread = GetCurrentThread(); |
||||
SymInitializeW(hProcess, appPath.c_str(), TRUE); |
||||
|
||||
DWORD64 dwDisplacement; |
||||
|
||||
ULONG64 buffer[(sizeof(SYMBOL_INFO) + |
||||
MAX_SYM_NAME * sizeof(TCHAR) + |
||||
sizeof(ULONG64) - 1) / sizeof(ULONG64)]; |
||||
auto pSymbol = reinterpret_cast<PSYMBOL_INFO>(buffer); |
||||
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); |
||||
pSymbol->MaxNameLen = MAX_SYM_NAME; |
||||
|
||||
IMAGEHLP_MODULE64 mod; |
||||
mod.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); |
||||
|
||||
IMAGEHLP_STACK_FRAME ihsf; |
||||
ZeroMemory(&ihsf, sizeof(IMAGEHLP_STACK_FRAME)); |
||||
|
||||
int i = 0; |
||||
|
||||
while(StackWalk64(MachineType, hProcess, hThread, &StackFrame, &Context, NULL, NULL, NULL, NULL)) |
||||
{ |
||||
if(i == 128) |
||||
break; |
||||
|
||||
loadHelpStackFrame(ihsf, StackFrame); |
||||
if(StackFrame.AddrPC.Offset != 0) |
||||
{ // Valid frame.
|
||||
|
||||
auto fileName = u"???"_qs; |
||||
if(SymGetModuleInfo64(hProcess, ihsf.InstructionOffset, &mod)) |
||||
{ |
||||
fileName = QString::fromUtf8(mod.ImageName); |
||||
int slashPos = fileName.lastIndexOf(u'\\'); |
||||
if(slashPos != -1) |
||||
fileName = fileName.mid(slashPos + 1); |
||||
} |
||||
QString funcName; |
||||
QString sourceFile; |
||||
if(SymFromAddr(hProcess, ihsf.InstructionOffset, &dwDisplacement, pSymbol)) |
||||
{ |
||||
funcName = QString::fromUtf8(pSymbol->Name); |
||||
#ifdef __MINGW32__ |
||||
demangle(funcName); |
||||
#endif |
||||
|
||||
// now ihsf.InstructionOffset points to the instruction that follows CALL instruction
|
||||
// decrease the query address by one byte to point somewhere in the CALL instruction byte sequence
|
||||
sourceFile = getSourcePathAndLineNumber(hProcess, ihsf.InstructionOffset - 1); |
||||
} |
||||
else |
||||
{ |
||||
funcName = u"0x%1"_qs.arg(ihsf.InstructionOffset, 8, 16, QChar(u'0')); |
||||
} |
||||
SymSetContext(hProcess, &ihsf, NULL); |
||||
#ifndef __MINGW32__ |
||||
QStringList params; |
||||
SymEnumSymbols(hProcess, 0, NULL, EnumSymbolsCB, (PVOID)¶ms); |
||||
#endif |
||||
|
||||
QString insOffset = u"0x%1"_qs.arg(ihsf.InstructionOffset, 16, 16, QChar(u'0')); |
||||
auto formatLine = u"#%1 %2 %3 %4"_qs; |
||||
#ifndef __MINGW32__ |
||||
formatLine += u"(%5)"_qs; |
||||
#endif |
||||
QString debugLine = formatLine |
||||
.arg(i, 3, 10) |
||||
.arg(fileName, -20) |
||||
.arg(insOffset, -11) |
||||
.arg(funcName) |
||||
#ifndef __MINGW32__ |
||||
.arg(params.join(u", ")); |
||||
|
||||
if (!sourceFile.isEmpty()) |
||||
debugLine += u"[ %1 ]"_qs.arg(sourceFile); |
||||
#else |
||||
; |
||||
#endif |
||||
logStream << debugLine << '\n'; |
||||
i++; |
||||
} |
||||
else |
||||
{ |
||||
break; // we're at the end.
|
||||
} |
||||
} |
||||
|
||||
//logStream << "\n\nList of linked Modules:\n";
|
||||
//EnumModulesContext modulesContext(hProcess, logStream);
|
||||
//SymEnumerateModules64(hProcess, EnumModulesCB, (PVOID)&modulesContext);
|
||||
SymCleanup(hProcess); |
||||
|
||||
logStream << "```"; |
||||
return log; |
||||
} |
||||
#if defined(_M_IX86) && defined(Q_CC_MSVC) |
||||
#pragma warning(pop) |
||||
#pragma optimize("g", on) |
||||
#endif |
Loading…
Reference in new issue