File indexing completed on 2024-04-28 16:44:10

0001 /******************************************************************
0002  *
0003  * kdbgwin - Helper application for DrKonqi
0004  *
0005  * This file is part of the KDE project
0006  *
0007  * SPDX-FileCopyrightText: 2010 Ilie Halip <lupuroshu@gmail.com>
0008  *
0009  * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0010  *****************************************************************/
0011 
0012 #include "abstract_generator.h"
0013 #include "callbacks.h"
0014 
0015 #include <QStringList>
0016 
0017 AbstractBTGenerator::AbstractBTGenerator(const Process &process)
0018     : m_process(process)
0019 {
0020     assert(process.IsValid());
0021 }
0022 
0023 AbstractBTGenerator::~AbstractBTGenerator()
0024 {
0025 }
0026 
0027 QString AbstractBTGenerator::GetModuleName()
0028 {
0029     IMAGEHLP_MODULE64 module;
0030     ZeroMemory(&module, sizeof(module));
0031     module.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
0032 
0033     if (!SymGetModuleInfo64(m_process.GetHandle(), m_currentFrame.AddrPC.Offset, &module)) {
0034         qCCritical(DRKONQI_LOG) << "SymGetModuleInfo64 failed: " << GetLastError();
0035         return QLatin1String(DEFAULT_MODULE);
0036     }
0037 
0038     QStringList list = QString(QLatin1String(module.ImageName)).split(QStringLiteral("\\"));
0039     return list[list.size() - 1];
0040 }
0041 
0042 QString AbstractBTGenerator::GetModulePath()
0043 {
0044     IMAGEHLP_MODULE64 module;
0045     ZeroMemory(&module, sizeof(module));
0046     module.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
0047 
0048     if (!SymGetModuleInfo64(m_process.GetHandle(), m_currentFrame.AddrPC.Offset, &module)) {
0049         qCCritical(DRKONQI_LOG) << "SymGetModuleInfo64 failed: " << GetLastError();
0050         return QLatin1String(DEFAULT_MODULE);
0051     }
0052 
0053     return QString(QLatin1String(module.ImageName));
0054 }
0055 
0056 void AbstractBTGenerator::Run(HANDLE hThread, bool bFaultingThread)
0057 {
0058     assert(m_process.IsValid());
0059     assert(hThread);
0060 
0061     if (!Init()) {
0062         assert(false);
0063         return;
0064     }
0065 
0066     // HANDLE hFile = CreateFile(L"C:\\test\\test.dmp", FILE_ALL_ACCESS, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
0067     // if (!MiniDumpWriteDump(m_process.GetHandle(), m_process.GetId(), hFile,
0068     //    MiniDumpNormal, NULL, NULL, NULL))
0069     //{
0070     //    HRESULT hres = (HRESULT) GetLastError();
0071     //    printf("%08X\n\n", hres);
0072     //}
0073     // SafeCloseHandle(hFile);
0074 
0075     DWORD dw = SuspendThread(hThread);
0076     assert(dw != DWORD(-1));
0077     if (dw == DWORD(-1)) {
0078         qCCritical(DRKONQI_LOG) << "SuspendThread() failed: " << GetLastError();
0079         return;
0080     }
0081 
0082     CONTEXT context;
0083     ZeroMemory(&context, sizeof(context));
0084     if (!bFaultingThread) {
0085         // if it's not the faulting thread, get its context
0086         context.ContextFlags = CONTEXT_FULL;
0087         if (!GetThreadContext(hThread, &context)) {
0088             ResumeThread(hThread);
0089             assert(false);
0090             qCCritical(DRKONQI_LOG) << "GetThreadContext() failed: " << GetLastError();
0091             return;
0092         }
0093     } else {
0094         // if it is, get it from KCrash
0095         HANDLE hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, L"Local\\KCrashShared");
0096         if (hMapFile == NULL) {
0097             qCCritical(DRKONQI_LOG) << "OpenFileMapping() failed: " << GetLastError();
0098             return;
0099         }
0100         CONTEXT *othercontext = (CONTEXT *)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(CONTEXT));
0101         if (othercontext == NULL) {
0102             qCCritical(DRKONQI_LOG) << "MapViewOfFile() failed: " << GetLastError();
0103             SafeCloseHandle(hMapFile);
0104             return;
0105         }
0106         CopyMemory(&context, othercontext, sizeof(CONTEXT));
0107         UnmapViewOfFile(othercontext); // continue even if it fails
0108         SafeCloseHandle(hMapFile);
0109     }
0110 
0111     // some of this stuff is taken from StackWalker
0112     ZeroMemory(&m_currentFrame, sizeof(m_currentFrame));
0113     DWORD machineType = IMAGE_FILE_MACHINE_UNKNOWN;
0114 #if defined(_M_IX86)
0115     machineType = IMAGE_FILE_MACHINE_I386;
0116     m_currentFrame.AddrPC.Offset = context.Eip;
0117     m_currentFrame.AddrFrame.Offset = context.Ebp;
0118     m_currentFrame.AddrStack.Offset = context.Esp;
0119 #elif defined(_M_X64)
0120     machineType = IMAGE_FILE_MACHINE_AMD64;
0121     m_currentFrame.AddrPC.Offset = context.Rip;
0122     m_currentFrame.AddrFrame.Offset = context.Rbp;
0123     m_currentFrame.AddrStack.Offset = context.Rsp;
0124 #else
0125 #error This architecture is not supported.
0126 #endif
0127     m_currentFrame.AddrPC.Mode = AddrModeFlat;
0128     m_currentFrame.AddrFrame.Mode = AddrModeFlat;
0129     m_currentFrame.AddrStack.Mode = AddrModeFlat;
0130 
0131     SymSetOptions(SymGetOptions() | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES);
0132     SymInitialize(m_process.GetHandle(), NULL, FALSE);
0133 
0134     LoadSymbols();
0135 
0136     for (int i = 0; /*nothing*/; i++) {
0137         SetLastError(0);
0138 
0139         if (!StackWalk64(machineType,
0140                          m_process.GetHandle(),
0141                          hThread,
0142                          &m_currentFrame,
0143                          &context,
0144                          &Callbacks::ReadProcessMemory,
0145                          &Callbacks::SymFunctionTableAccess64,
0146                          &Callbacks::SymGetModuleBase64,
0147                          NULL)) {
0148             Q_EMIT Finished();
0149             qCDebug(DRKONQI_LOG) << "Stackwalk finished; GetLastError=" << GetLastError();
0150             break;
0151         }
0152 
0153         FrameChanged();
0154 
0155         QString modulename = GetModuleName();
0156         QString functionname = GetFunctionName();
0157         QString file = GetFile();
0158         int line = GetLine();
0159         QString address = QString::number(m_currentFrame.AddrPC.Offset, 16);
0160 
0161         QString debugLine = QString::fromLatin1(BACKTRACE_FORMAT).arg(modulename).arg(functionname).arg(file).arg(line).arg(address);
0162 
0163         Q_EMIT DebugLine(debugLine);
0164     }
0165 
0166     // Resume the target thread now, or else the crashing process will not
0167     // be terminated
0168     ResumeThread(hThread);
0169 
0170     SymCleanup(m_process.GetHandle());
0171 }
0172 
0173 bool AbstractBTGenerator::IsSymbolLoaded(const QString &module)
0174 {
0175     if (m_symbolsMap.contains(module)) {
0176         return m_symbolsMap[module];
0177     }
0178     return false;
0179 }
0180 
0181 void AbstractBTGenerator::LoadSymbols()
0182 {
0183     TModulesMap modules = m_process.GetModules();
0184     for (TModulesMap::iterator i = modules.begin(); i != modules.end(); i++) {
0185         MODULEINFO modInfo;
0186         ZeroMemory(&modInfo, sizeof(modInfo));
0187 
0188         QString strModule = i.key();
0189 
0190         GetModuleInformation(m_process.GetHandle(), i.value(), &modInfo, sizeof(modInfo));
0191         SymLoadModuleEx(m_process.GetHandle(),
0192                         NULL,
0193                         (CHAR *)i.key().toLatin1().constData(),
0194                         (CHAR *)i.key().toLatin1().constData(),
0195                         (DWORD64)modInfo.lpBaseOfDll,
0196                         modInfo.SizeOfImage,
0197                         NULL,
0198                         0);
0199 
0200         LoadSymbol(strModule, (DWORD64)modInfo.lpBaseOfDll);
0201 
0202         if (!IsSymbolLoaded(strModule)) {
0203             Q_EMIT MissingSymbol(strModule);
0204         }
0205     }
0206     Q_EMIT DebugLine(QString());
0207     Q_EMIT DebugLine(QString());
0208 }