qBittorrent
straceWin Namespace Reference

Classes

struct  EnumModulesContext
 

Functions

void loadHelpStackFrame (IMAGEHLP_STACK_FRAME &, const STACKFRAME64 &)
 
BOOL CALLBACK EnumSymbolsCB (PSYMBOL_INFO, ULONG, PVOID)
 
BOOL CALLBACK EnumModulesCB (LPCSTR, DWORD64, PVOID)
 
const QString getBacktrace ()
 
QString getSourcePathAndLineNumber (HANDLE hProcess, DWORD64 addr)
 
bool makeRelativePath (const QString &dir, QString &file)
 

Function Documentation

◆ EnumModulesCB()

BOOL CALLBACK straceWin::EnumModulesCB ( LPCSTR  ModuleName,
DWORD64  BaseOfDll,
PVOID  UserContext 
)

Definition at line 90 of file stacktrace_win.h.

91 {
92  Q_UNUSED(ModuleName)
93  IMAGEHLP_MODULE64 mod;
94  auto context = static_cast<EnumModulesContext *>(UserContext);
95  mod.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
96  if(SymGetModuleInfo64(context->hProcess, BaseOfDll, &mod))
97  {
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';
104 
105  QString pdbName(mod.LoadedPdbName);
106  if(!pdbName.isEmpty())
107  {
108  QString line2 = QString::fromLatin1("%1 %2")
109  .arg("", 35)
110  .arg(pdbName);
111  context->stream << line2 << '\n';
112  }
113  }
114  return TRUE;
115 }

References straceWin::EnumModulesContext::stream.

◆ EnumSymbolsCB()

BOOL CALLBACK straceWin::EnumSymbolsCB ( PSYMBOL_INFO  symInfo,
ULONG  size,
PVOID  user 
)

Definition at line 73 of file stacktrace_win.h.

74 {
75  Q_UNUSED(size)
76  auto params = static_cast<QStringList *>(user);
77  if (symInfo->Flags & SYMFLAG_PARAMETER)
78  params->append(symInfo->Name);
79  return TRUE;
80 }

Referenced by getBacktrace().

Here is the caller graph for this function:

◆ getBacktrace()

const QString straceWin::getBacktrace ( )

Definition at line 189 of file stacktrace_win.h.

190 {
191  DWORD MachineType;
192  CONTEXT Context;
193  STACKFRAME64 StackFrame;
194 
195 #ifdef _M_IX86
196  ZeroMemory(&Context, sizeof(CONTEXT));
197  Context.ContextFlags = CONTEXT_CONTROL;
198 
199 
200 #ifdef __MINGW32__
201  asm ("Label:\n\t"
202  "movl %%ebp,%0;\n\t"
203  "movl %%esp,%1;\n\t"
204  "movl $Label,%%eax;\n\t"
205  "movl %%eax,%2;\n\t"
206  : "=r" (Context.Ebp),"=r" (Context.Esp),"=r" (Context.Eip)
207  : //no input
208  : "eax");
209 #else
210  _asm
211  {
212  Label:
213  mov [Context.Ebp], ebp;
214  mov [Context.Esp], esp;
215  mov eax, [Label];
216  mov [Context.Eip], eax;
217  }
218 #endif
219 #else
220  RtlCaptureContext(&Context);
221 #endif
222 
223  ZeroMemory(&StackFrame, sizeof(STACKFRAME64));
224 #ifdef _M_IX86
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;
232 #elif _M_X64
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;
240 #elif _M_IA64
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;
250 #else
251 #error "Unsupported platform"
252 #endif
253 
254  QString log;
255  QTextStream logStream(&log);
256  logStream << "```\n";
257 
258  HANDLE hProcess = GetCurrentProcess();
259  HANDLE hThread = GetCurrentThread();
260  SymInitializeW(hProcess, QCoreApplication::applicationDirPath().toStdWString().c_str(), TRUE);
261 
262  DWORD64 dwDisplacement;
263 
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;
270 
271  IMAGEHLP_MODULE64 mod;
272  mod.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
273 
274  IMAGEHLP_STACK_FRAME ihsf;
275  ZeroMemory(&ihsf, sizeof(IMAGEHLP_STACK_FRAME));
276 
277  int i = 0;
278 
279  while(StackWalk64(MachineType, hProcess, hThread, &StackFrame, &Context, NULL, NULL, NULL, NULL))
280  {
281  if(i == 128)
282  break;
283 
284  loadHelpStackFrame(ihsf, StackFrame);
285  if(StackFrame.AddrPC.Offset != 0)
286  { // Valid frame.
287 
288  QString fileName("???");
289  if(SymGetModuleInfo64(hProcess, ihsf.InstructionOffset, &mod))
290  {
291  fileName = QString(mod.ImageName);
292  int slashPos = fileName.lastIndexOf('\\');
293  if(slashPos != -1)
294  fileName = fileName.mid(slashPos + 1);
295  }
296  QString funcName;
297  QString sourceFile;
298  if(SymFromAddr(hProcess, ihsf.InstructionOffset, &dwDisplacement, pSymbol))
299  {
300  funcName = QString(pSymbol->Name);
301 #ifdef __MINGW32__
302  demangle(funcName);
303 #endif
304 
305  // now ihsf.InstructionOffset points to the instruction that follows CALL instruction
306  // decrease the query address by one byte to point somewhere in the CALL instruction byte sequence
307  sourceFile = getSourcePathAndLineNumber(hProcess, ihsf.InstructionOffset - 1);
308  }
309  else
310  {
311  funcName = QString::fromLatin1("0x%1").arg(ihsf.InstructionOffset, 8, 16, QLatin1Char('0'));
312  }
313  SymSetContext(hProcess, &ihsf, NULL);
314 #ifndef __MINGW32__
315  QStringList params;
316  SymEnumSymbols(hProcess, 0, NULL, EnumSymbolsCB, (PVOID)&params);
317 #endif
318 
319  QString insOffset = QString::fromLatin1("0x%1").arg(ihsf.InstructionOffset, 16, 16, QLatin1Char('0'));
320  QString formatLine = "#%1 %2 %3 %4";
321 #ifndef __MINGW32__
322  formatLine += "(%5)";
323 #endif
324  QString debugLine = formatLine
325  .arg(i, 3, 10)
326  .arg(fileName, -20)
327  .arg(insOffset, -11)
328  .arg(funcName)
329 #ifndef __MINGW32__
330  .arg(params.join(", "));
331 
332  if (!sourceFile.isEmpty())
333  debugLine += QString::fromLatin1("[ %1 ]").arg(sourceFile);
334 #else
335  ;
336 #endif
337  logStream << debugLine << '\n';
338  i++;
339  }
340  else
341  {
342  break; // we're at the end.
343  }
344  }
345 
346  //logStream << "\n\nList of linked Modules:\n";
347  //EnumModulesContext modulesContext(hProcess, logStream);
348  //SymEnumerateModules64(hProcess, EnumModulesCB, (PVOID)&modulesContext);
349  SymCleanup(hProcess);
350 
351  logStream << "```";
352  return log;
353 }
QString fileName(const QString &filePath)
Definition: fs.cpp:87
BOOL CALLBACK EnumSymbolsCB(PSYMBOL_INFO, ULONG, PVOID)
QString getSourcePathAndLineNumber(HANDLE hProcess, DWORD64 addr)
void loadHelpStackFrame(IMAGEHLP_STACK_FRAME &, const STACKFRAME64 &)

References EnumSymbolsCB(), Utils::Fs::fileName(), getSourcePathAndLineNumber(), and loadHelpStackFrame().

Here is the call graph for this function:

◆ getSourcePathAndLineNumber()

QString straceWin::getSourcePathAndLineNumber ( HANDLE  hProcess,
DWORD64  addr 
)

Definition at line 143 of file stacktrace_win.h.

144 {
145  IMAGEHLP_LINE64 line {};
146  line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
147  DWORD dwDisplacement = 0;
148 
149  if (SymGetLineFromAddr64(hProcess, addr, &dwDisplacement, &line))
150  {
151  QString path(line.FileName);
152 
153 #if defined STACKTRACE_WIN_PROJECT_PATH || defined STACKTRACE_WIN_MAKEFILE_PATH
154 
155 #define STACKTRACE_WIN_QUOTE(x) #x
156 #define STACKTRACE_WIN_STRING(x) STACKTRACE_WIN_QUOTE(x)
157 
158  //prune leading project directory path or build target directory path
159 
160  bool success = false;
161 #ifdef STACKTRACE_WIN_PROJECT_PATH
162  QString projectPath(STACKTRACE_WIN_STRING(STACKTRACE_WIN_PROJECT_PATH));
163  success = makeRelativePath(projectPath, path);
164 #endif
165 
166 #ifdef STACKTRACE_WIN_MAKEFILE_PATH
167  if (!success)
168  {
169  QString targetPath(STACKTRACE_WIN_STRING(STACKTRACE_WIN_MAKEFILE_PATH));
170  makeRelativePath(targetPath, path);
171  }
172 #endif
173 #endif
174  return QString::fromLatin1("%1 : %2").arg(path).arg(line.LineNumber);
175  }
176 
177  return QString();
178 }
bool makeRelativePath(const QString &dir, QString &file)

References makeRelativePath().

Referenced by getBacktrace().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ loadHelpStackFrame()

void straceWin::loadHelpStackFrame ( IMAGEHLP_STACK_FRAME &  ihsf,
const STACKFRAME64 &  stackFrame 
)

Definition at line 66 of file stacktrace_win.h.

67 {
68  ZeroMemory(&ihsf, sizeof(IMAGEHLP_STACK_FRAME));
69  ihsf.InstructionOffset = stackFrame.AddrPC.Offset;
70  ihsf.FrameOffset = stackFrame.AddrFrame.Offset;
71 }

Referenced by getBacktrace().

Here is the caller graph for this function:

◆ makeRelativePath()

bool straceWin::makeRelativePath ( const QString &  dir,
QString &  file 
)

Cuts off leading 'dir' path from 'file' path, otherwise leaves it unchanged returns true if 'dir' is an ancestor of 'file', otherwise - false

Definition at line 122 of file stacktrace_win.h.

123 {
124  QString d = QDir::toNativeSeparators(QDir(dir).absolutePath());
125  QString f = QDir::toNativeSeparators(QFileInfo(file).absoluteFilePath());
126 
127  // append separator at the end of dir
128  QChar separator = QDir::separator();
129  if (!d.isEmpty() && (d[d.length() - 1] != separator))
130  d += separator;
131 
132  if (f.startsWith(d, Qt::CaseInsensitive))
133  {
134  f.remove(0, d.length());
135  file.swap(f);
136 
137  return true;
138  }
139 
140  return false;
141 }
file(GLOB QBT_TS_FILES "${qBittorrent_SOURCE_DIR}/src/lang/*.ts") set_source_files_properties($
Definition: CMakeLists.txt:5
void f()
Definition: test2.c:1

References f(), and file().

Referenced by getSourcePathAndLineNumber().

Here is the call graph for this function:
Here is the caller graph for this function: