27 #include <QCoreApplication>
29 #include <QTextStream>
43 void demangle(QString& str);
51 void straceWin::demangle(QString& str)
53 char const* inStr = qPrintable(
"_" + str);
56 char* demangled_name = abi::__cxa_demangle(inStr, 0, &outSz, &status);
59 str = QString::fromLocal8Bit(demangled_name);
68 ZeroMemory(&ihsf,
sizeof(IMAGEHLP_STACK_FRAME));
69 ihsf.InstructionOffset = stackFrame.AddrPC.Offset;
70 ihsf.FrameOffset = stackFrame.AddrFrame.Offset;
76 auto params =
static_cast<QStringList *
>(user);
77 if (symInfo->Flags & SYMFLAG_PARAMETER)
78 params->append(symInfo->Name);
93 IMAGEHLP_MODULE64 mod;
95 mod.SizeOfStruct =
sizeof(IMAGEHLP_MODULE64);
96 if(SymGetModuleInfo64(context->hProcess, BaseOfDll, &mod))
98 QString moduleBase = QString::fromLatin1(
"0x%1").arg(BaseOfDll, 16, 16, QLatin1Char(
'0'));
99 QString line = QString::fromLatin1(
"%1 %2 Image: %3")
100 .arg(mod.ModuleName, -25)
101 .arg(moduleBase, -13)
102 .arg(mod.LoadedImageName);
103 context->
stream << line <<
'\n';
105 QString pdbName(mod.LoadedPdbName);
106 if(!pdbName.isEmpty())
108 QString line2 = QString::fromLatin1(
"%1 %2")
111 context->stream << line2 <<
'\n';
124 QString d = QDir::toNativeSeparators(QDir(dir).absolutePath());
125 QString
f = QDir::toNativeSeparators(QFileInfo(
file).absoluteFilePath());
128 QChar separator = QDir::separator();
129 if (!d.isEmpty() && (d[d.length() - 1] != separator))
132 if (
f.startsWith(d, Qt::CaseInsensitive))
134 f.remove(0, d.length());
145 IMAGEHLP_LINE64 line {};
146 line.SizeOfStruct =
sizeof(IMAGEHLP_LINE64);
147 DWORD dwDisplacement = 0;
149 if (SymGetLineFromAddr64(hProcess, addr, &dwDisplacement, &line))
151 QString path(line.FileName);
153 #if defined STACKTRACE_WIN_PROJECT_PATH || defined STACKTRACE_WIN_MAKEFILE_PATH
155 #define STACKTRACE_WIN_QUOTE(x) #x
156 #define STACKTRACE_WIN_STRING(x) STACKTRACE_WIN_QUOTE(x)
160 bool success =
false;
161 #ifdef STACKTRACE_WIN_PROJECT_PATH
162 QString projectPath(STACKTRACE_WIN_STRING(STACKTRACE_WIN_PROJECT_PATH));
166 #ifdef STACKTRACE_WIN_MAKEFILE_PATH
169 QString targetPath(STACKTRACE_WIN_STRING(STACKTRACE_WIN_MAKEFILE_PATH));
174 return QString::fromLatin1(
"%1 : %2").arg(path).arg(line.LineNumber);
181 #if defined( _M_IX86 ) && defined(Q_CC_MSVC)
185 #pragma optimize("g", off)
186 #pragma warning(push)
187 #pragma warning(disable : 4748)
193 STACKFRAME64 StackFrame;
196 ZeroMemory(&Context,
sizeof(CONTEXT));
197 Context.ContextFlags = CONTEXT_CONTROL;
204 "movl $Label,%%eax;\n\t"
206 :
"=r" (Context.Ebp),
"=r" (Context.Esp),
"=r" (Context.Eip)
213 mov [Context.Ebp], ebp;
214 mov [Context.Esp], esp;
216 mov [Context.Eip], eax;
220 RtlCaptureContext(&Context);
223 ZeroMemory(&StackFrame,
sizeof(STACKFRAME64));
225 MachineType = IMAGE_FILE_MACHINE_I386;
226 StackFrame.AddrPC.Offset = Context.Eip;
227 StackFrame.AddrPC.Mode = AddrModeFlat;
228 StackFrame.AddrFrame.Offset = Context.Ebp;
229 StackFrame.AddrFrame.Mode = AddrModeFlat;
230 StackFrame.AddrStack.Offset = Context.Esp;
231 StackFrame.AddrStack.Mode = AddrModeFlat;
233 MachineType = IMAGE_FILE_MACHINE_AMD64;
234 StackFrame.AddrPC.Offset = Context.Rip;
235 StackFrame.AddrPC.Mode = AddrModeFlat;
236 StackFrame.AddrFrame.Offset = Context.Rsp;
237 StackFrame.AddrFrame.Mode = AddrModeFlat;
238 StackFrame.AddrStack.Offset = Context.Rsp;
239 StackFrame.AddrStack.Mode = AddrModeFlat;
241 MachineType = IMAGE_FILE_MACHINE_IA64;
242 StackFrame.AddrPC.Offset = Context.StIIP;
243 StackFrame.AddrPC.Mode = AddrModeFlat;
244 StackFrame.AddrFrame.Offset = Context.IntSp;
245 StackFrame.AddrFrame.Mode = AddrModeFlat;
246 StackFrame.AddrBStore.Offset = Context.RsBSP;
247 StackFrame.AddrBStore.Mode = AddrModeFlat;
248 StackFrame.AddrStack.Offset = Context.IntSp;
249 StackFrame.AddrStack.Mode = AddrModeFlat;
251 #error "Unsupported platform"
255 QTextStream logStream(&log);
256 logStream <<
"```\n";
258 HANDLE hProcess = GetCurrentProcess();
259 HANDLE hThread = GetCurrentThread();
260 SymInitializeW(hProcess, QCoreApplication::applicationDirPath().toStdWString().c_str(), TRUE);
262 DWORD64 dwDisplacement;
264 ULONG64 buffer[(
sizeof(SYMBOL_INFO) +
265 MAX_SYM_NAME *
sizeof(TCHAR) +
266 sizeof(ULONG64) - 1) /
sizeof(ULONG64)];
267 auto pSymbol =
reinterpret_cast<PSYMBOL_INFO
>(buffer);
268 pSymbol->SizeOfStruct =
sizeof(SYMBOL_INFO);
269 pSymbol->MaxNameLen = MAX_SYM_NAME;
271 IMAGEHLP_MODULE64 mod;
272 mod.SizeOfStruct =
sizeof(IMAGEHLP_MODULE64);
274 IMAGEHLP_STACK_FRAME ihsf;
275 ZeroMemory(&ihsf,
sizeof(IMAGEHLP_STACK_FRAME));
279 while(StackWalk64(MachineType, hProcess, hThread, &StackFrame, &Context, NULL, NULL, NULL, NULL))
285 if(StackFrame.AddrPC.Offset != 0)
289 if(SymGetModuleInfo64(hProcess, ihsf.InstructionOffset, &mod))
292 int slashPos =
fileName.lastIndexOf(
'\\');
298 if(SymFromAddr(hProcess, ihsf.InstructionOffset, &dwDisplacement, pSymbol))
300 funcName = QString(pSymbol->Name);
311 funcName = QString::fromLatin1(
"0x%1").arg(ihsf.InstructionOffset, 8, 16, QLatin1Char(
'0'));
313 SymSetContext(hProcess, &ihsf, NULL);
316 SymEnumSymbols(hProcess, 0, NULL,
EnumSymbolsCB, (PVOID)¶ms);
319 QString insOffset = QString::fromLatin1(
"0x%1").arg(ihsf.InstructionOffset, 16, 16, QLatin1Char(
'0'));
320 QString formatLine =
"#%1 %2 %3 %4";
322 formatLine +=
"(%5)";
324 QString debugLine = formatLine
330 .arg(params.join(
", "));
332 if (!sourceFile.isEmpty())
333 debugLine += QString::fromLatin1(
"[ %1 ]").arg(sourceFile);
337 logStream << debugLine <<
'\n';
349 SymCleanup(hProcess);
354 #if defined(_M_IX86) && defined(Q_CC_MSVC)
356 #pragma optimize("g", on)
QString fileName(const QString &filePath)
BOOL CALLBACK EnumSymbolsCB(PSYMBOL_INFO, ULONG, PVOID)
BOOL CALLBACK EnumModulesCB(LPCSTR, DWORD64, PVOID)
bool makeRelativePath(const QString &dir, QString &file)
QString getSourcePathAndLineNumber(HANDLE hProcess, DWORD64 addr)
void loadHelpStackFrame(IMAGEHLP_STACK_FRAME &, const STACKFRAME64 &)
const QString getBacktrace()
file(GLOB QBT_TS_FILES "${qBittorrent_SOURCE_DIR}/src/lang/*.ts") set_source_files_properties($
EnumModulesContext(HANDLE hProcess, QTextStream &stream)