aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/valgrind/memchecktool.cpp
diff options
context:
space:
mode:
authorHannes Domani <ssbssa@yahoo.de>2017-12-08 20:27:21 +0100
committerHannes Domani <ssbssa@yahoo.de>2018-01-16 11:31:33 +0000
commiteecc26f40ea8b1c558fd4edeedc4fea6fbe69d10 (patch)
tree43db4df50be385dfd609bd38cc88f8040dd6e807 /src/plugins/valgrind/memchecktool.cpp
parente5d1fe6620e01927a1c67194daa620b0e624b394 (diff)
Valgrind: Add heob support
Change-Id: Ia5957058c59ae2a607620915c2c68f2cfd5ac5f1 Reviewed-by: Orgad Shaneh <orgads@gmail.com> Reviewed-by: David Schulz <david.schulz@qt.io> Reviewed-by: André Hartmann <aha_1980@gmx.de> Reviewed-by: hjk <hjk@qt.io>
Diffstat (limited to 'src/plugins/valgrind/memchecktool.cpp')
-rw-r--r--src/plugins/valgrind/memchecktool.cpp570
1 files changed, 568 insertions, 2 deletions
diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp
index 0aa48bfe04..9bd184fd4e 100644
--- a/src/plugins/valgrind/memchecktool.cpp
+++ b/src/plugins/valgrind/memchecktool.cpp
@@ -69,6 +69,7 @@
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/icore.h>
#include <coreplugin/id.h>
+#include <coreplugin/modemanager.h>
#include <ssh/sshconnection.h>
@@ -86,6 +87,18 @@
#include <QToolButton>
#include <QSortFilterProxyModel>
+#ifdef Q_OS_WIN
+#include <QCheckBox>
+#include <QComboBox>
+#include <QLineEdit>
+#include <QPushButton>
+#include <QSpinBox>
+#include <QStandardPaths>
+#include <QWinEventNotifier>
+
+#include <windows.h>
+#endif
+
using namespace Core;
using namespace Debugger;
using namespace ProjectExplorer;
@@ -406,6 +419,8 @@ public:
RunWorker *createRunWorker(RunControl *runControl);
+ void loadShowXmlLogFile(const QString &filePath, const QString &exitMsg);
+
private:
void updateRunActions();
void settingsDestroyed(QObject *settings);
@@ -419,6 +434,7 @@ private:
void updateErrorFilter();
void loadExternalXmlLogFile();
+ void loadXmlLogFile(const QString &filePath);
void setBusyCursor(bool busy);
@@ -426,6 +442,8 @@ private:
void updateFromSettings();
int updateUiAfterFinishedHelper();
+ void heobAction();
+
private:
ValgrindBaseSettings *m_settings;
QMenu *m_filterMenu = 0;
@@ -445,7 +463,56 @@ private:
QAction *m_goBack;
QAction *m_goNext;
bool m_toolBusy = false;
+
+ QString m_exitMsg;
+};
+
+#ifdef Q_OS_WIN
+class HeobDialog : public QDialog
+{
+public:
+ HeobDialog(QWidget *parent);
+
+ QString arguments() const;
+ QString xmlName() const;
+
+private:
+ void updateEnabled();
+
+private:
+ QLineEdit *m_xmlEdit = nullptr;
+ QCheckBox *m_pidWaitCheck = nullptr;
+ QComboBox *m_handleExceptionCombo = nullptr;
+ QComboBox *m_pageProtectionCombo = nullptr;
+ QCheckBox *m_freedProtectionCheck = nullptr;
+ QCheckBox *m_breakpointCheck = nullptr;
+ QComboBox *m_leakDetailCombo = nullptr;
+ QSpinBox *m_leakSizeSpin = nullptr;
+ QComboBox *m_leakRecordingCombo = nullptr;
+ QLineEdit *m_extraArgsEdit = nullptr;
+};
+
+class HeobData : public QObject
+{
+public:
+ HeobData(MemcheckTool *mcTool, const QString &xmlPath);
+ ~HeobData();
+
+ bool createErrorPipe(DWORD heobPid);
+ void readExitData();
+
+private:
+ void processFinished();
+
+private:
+ HANDLE m_errorPipe = INVALID_HANDLE_VALUE;
+ OVERLAPPED m_ov;
+ unsigned m_data[2];
+ QWinEventNotifier *m_processFinishedNotifier = nullptr;
+ MemcheckTool *m_mcTool = nullptr;
+ QString m_xmlPath;
};
+#endif
MemcheckTool::MemcheckTool()
{
@@ -589,6 +656,12 @@ MemcheckTool::MemcheckTool()
QObject::connect(m_startWithGdbAction, &QAction::changed, action, [action, this] {
action->setEnabled(m_startWithGdbAction->isEnabled());
});
+ } else {
+ action = new QAction(tr("heob"), this);
+ Core::Command *cmd = Core::ActionManager::registerAction(action, "Memcheck.Local");
+ cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+H")));
+ connect(action, &QAction::triggered, this, &MemcheckTool::heobAction);
+ menu->addAction(cmd, Debugger::Constants::G_ANALYZER_TOOLS);
}
action = new QAction(this);
@@ -629,6 +702,147 @@ MemcheckTool::MemcheckTool()
maybeActiveRunConfigurationChanged();
}
+void MemcheckTool::heobAction()
+{
+#ifdef Q_OS_WIN
+ StandardRunnable sr;
+ Abi abi;
+ bool hasLocalRc = false;
+ if (Project *project = SessionManager::startupProject()) {
+ if (Target *target = project->activeTarget()) {
+ if (RunConfiguration *rc = target->activeRunConfiguration()) {
+ if (Kit *kit = target->kit()) {
+ abi = ToolChainKitInformation::targetAbi(kit);
+
+ const Runnable runnable = rc->runnable();
+ if (runnable.is<StandardRunnable>()) {
+ sr = runnable.as<StandardRunnable>();
+ const IDevice::ConstPtr device = sr.device;
+ hasLocalRc = device && device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE;
+ if (!hasLocalRc)
+ hasLocalRc = DeviceTypeKitInformation::deviceTypeId(kit) == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE;
+ }
+ }
+ }
+ }
+ }
+ if (!hasLocalRc) {
+ const QString msg = tr("heob: No local run configuration available");
+ TaskHub::addTask(Task::Error, msg, Debugger::Constants::ANALYZERTASK_ID);
+ TaskHub::requestPopup();
+ return;
+ }
+ if (abi.architecture() != Abi::X86Architecture
+ || abi.os() != Abi::WindowsOS
+ || abi.binaryFormat() != Abi::PEFormat
+ || (abi.wordWidth() != 32 && abi.wordWidth() != 64)) {
+ const QString msg = tr("heob: No toolchain available");
+ TaskHub::addTask(Task::Error, msg, Debugger::Constants::ANALYZERTASK_ID);
+ TaskHub::requestPopup();
+ return;
+ }
+
+ QString executable = sr.executable;
+ const QString workingDirectory = Utils::FileUtils::normalizePathName(sr.workingDirectory);
+ const QString commandLineArguments = sr.commandLineArguments;
+ const QStringList envStrings = sr.environment.toStringList();
+
+ // target executable
+ if (executable.isEmpty()) {
+ const QString msg = tr("heob: No executable set");
+ TaskHub::addTask(Task::Error, msg, Debugger::Constants::ANALYZERTASK_ID);
+ TaskHub::requestPopup();
+ return;
+ }
+ if (!QFile::exists(executable)) {
+ const QString msg = tr("heob: Can't find %1").arg(executable);
+ TaskHub::addTask(Task::Error, msg, Debugger::Constants::ANALYZERTASK_ID);
+ TaskHub::requestPopup();
+ return;
+ }
+
+ // heob executable
+ const QString heob = QString("heob%1.exe").arg(abi.wordWidth());
+ const QString heobPath = QStandardPaths::findExecutable(heob);
+ if (heobPath.isEmpty()) {
+ const QString msg = tr("heob: Can't find %1").arg(heob);
+ TaskHub::addTask(Task::Error, msg, Debugger::Constants::ANALYZERTASK_ID);
+ TaskHub::requestPopup();
+ return;
+ }
+
+ // make executable a relative path if possible
+ const QString wdSlashed = workingDirectory + '/';
+ if (executable.startsWith(wdSlashed, Qt::CaseInsensitive))
+ executable.remove(0, wdSlashed.size());
+
+ // heob arguments
+ HeobDialog dialog(Core::ICore::mainWindow());
+ if (!dialog.exec())
+ return;
+ const QString heobArguments = dialog.arguments();
+
+ // output xml file
+ QDir wdDir(workingDirectory);
+ const QString xmlPath = wdDir.absoluteFilePath(dialog.xmlName());
+ QFile::remove(xmlPath);
+
+ // full command line
+ QString arguments = heob + heobArguments + " \"" + executable + '\"';
+ if (!commandLineArguments.isEmpty())
+ arguments += ' ' + commandLineArguments;
+ QByteArray argumentsCopy(reinterpret_cast<const char *>(arguments.utf16()), arguments.size() * 2 + 2);
+
+ // process environment
+ QByteArray env;
+ void *envPtr = nullptr;
+ if (!envStrings.isEmpty()) {
+ uint pos = 0;
+ for (const QString &par : envStrings) {
+ uint parsize = par.size() * 2 + 2;
+ env.resize(env.size() + parsize);
+ memcpy(env.data() + pos, par.utf16(), parsize);
+ pos += parsize;
+ }
+ env.resize(env.size() + 2);
+ env[pos++] = 0;
+ env[pos++] = 0;
+
+ envPtr = env.data();
+ }
+
+ // heob process
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ memset(&si, 0, sizeof(STARTUPINFO));
+ si.cb = sizeof(STARTUPINFO);
+ if (!CreateProcess(reinterpret_cast<LPCWSTR>(heobPath.utf16()),
+ reinterpret_cast<LPWSTR>(argumentsCopy.data()), 0, 0, FALSE,
+ CREATE_UNICODE_ENVIRONMENT | CREATE_SUSPENDED | CREATE_NEW_CONSOLE, envPtr,
+ reinterpret_cast<LPCWSTR>(workingDirectory.utf16()), &si, &pi)) {
+ DWORD e = GetLastError();
+ const QString msg = tr("heob: Can't create %1 process (%2)").arg(heob).arg(qt_error_string(e));
+ TaskHub::addTask(Task::Error, msg, Debugger::Constants::ANALYZERTASK_ID);
+ TaskHub::requestPopup();
+ return;
+ }
+
+ // heob finished signal handler
+ HeobData *hd = new HeobData(this, xmlPath);
+ if (!hd->createErrorPipe(pi.dwProcessId)) {
+ delete hd;
+ hd = nullptr;
+ }
+
+ ResumeThread(pi.hThread);
+ CloseHandle(pi.hThread);
+ CloseHandle(pi.hProcess);
+
+ if (hd)
+ hd->readExitData();
+#endif
+}
+
void MemcheckTool::updateRunActions()
{
if (m_toolBusy) {
@@ -750,6 +964,18 @@ RunWorker *MemcheckTool::createRunWorker(RunControl *runControl)
return runTool;
}
+void MemcheckTool::loadShowXmlLogFile(const QString &filePath, const QString &exitMsg)
+{
+ clearErrorView();
+ m_settings->setFilterExternalIssues(false);
+ m_filterProjectAction->setChecked(true);
+ Debugger::selectPerspective(MemcheckPerspectiveId);
+ Core::ModeManager::activateMode(Debugger::Constants::MODE_DEBUG);
+
+ m_exitMsg = exitMsg;
+ loadXmlLogFile(filePath);
+}
+
void MemcheckTool::loadExternalXmlLogFile()
{
const QString filePath = QFileDialog::getOpenFileName(
@@ -760,12 +986,20 @@ void MemcheckTool::loadExternalXmlLogFile()
if (filePath.isEmpty())
return;
+ m_exitMsg.clear();
+ loadXmlLogFile(filePath);
+}
+
+void MemcheckTool::loadXmlLogFile(const QString &filePath)
+{
QFile *logFile = new QFile(filePath);
if (!logFile->open(QIODevice::ReadOnly | QIODevice::Text)) {
delete logFile;
QString msg = tr("Memcheck: Failed to open file for reading: %1").arg(filePath);
TaskHub::addTask(Task::Error, msg, Debugger::Constants::ANALYZERTASK_ID);
TaskHub::requestPopup();
+ if (!m_exitMsg.isEmpty())
+ Debugger::showPermanentStatusMessage(m_exitMsg);
return;
}
@@ -854,8 +1088,10 @@ void MemcheckTool::engineFinished()
void MemcheckTool::loadingExternalXmlLogFileFinished()
{
const int issuesFound = updateUiAfterFinishedHelper();
- Debugger::showPermanentStatusMessage(
- tr("Log file processed, %n issues were found.", 0, issuesFound));
+ QString statusMessage = tr("Log file processed, %n issues were found.", 0, issuesFound);
+ if (!m_exitMsg.isEmpty())
+ statusMessage += ' ' + m_exitMsg;
+ Debugger::showPermanentStatusMessage(statusMessage);
}
void MemcheckTool::setBusyCursor(bool busy)
@@ -882,6 +1118,336 @@ void destroyMemcheckTool()
theMemcheckTool = nullptr;
}
+
+#ifdef Q_OS_WIN
+static QString upperHexNum(unsigned num)
+{
+ return QString("%1").arg(num, 8, 16, QChar('0')).toUpper();
+}
+
+HeobDialog::HeobDialog(QWidget *parent) :
+ QDialog(parent)
+{
+ QVBoxLayout *layout = new QVBoxLayout;
+ // disable resizing
+ layout->setSizeConstraint(QLayout::SetFixedSize);
+
+ QHBoxLayout *xmlLayout = new QHBoxLayout;
+ QLabel *xmlLabel = new QLabel(tr("xml output file:"));
+ xmlLayout->addWidget(xmlLabel);
+ m_xmlEdit = new QLineEdit;
+ m_xmlEdit->setText("leaks.xml");
+ xmlLayout->addWidget(m_xmlEdit);
+ layout->addLayout(xmlLayout);
+
+ m_pidWaitCheck = new QCheckBox(tr("show process ID and wait"));
+ layout->addWidget(m_pidWaitCheck);
+
+ QHBoxLayout *handleExceptionLayout = new QHBoxLayout;
+ QLabel *handleExceptionLabel = new QLabel(tr("handle exceptions:"));
+ handleExceptionLayout->addWidget(handleExceptionLabel);
+ m_handleExceptionCombo = new QComboBox;
+ m_handleExceptionCombo->addItem(tr("off"));
+ m_handleExceptionCombo->addItem(tr("on"));
+ m_handleExceptionCombo->addItem(tr("only"));
+ m_handleExceptionCombo->setCurrentIndex(1);
+ connect(m_handleExceptionCombo, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+ this, &HeobDialog::updateEnabled);
+ handleExceptionLayout->addWidget(m_handleExceptionCombo);
+ layout->addLayout(handleExceptionLayout);
+
+ QHBoxLayout *pageProtectionLayout = new QHBoxLayout;
+ QLabel *pageProtectionLabel = new QLabel(tr("page protection:"));
+ pageProtectionLayout->addWidget(pageProtectionLabel);
+ m_pageProtectionCombo = new QComboBox;
+ m_pageProtectionCombo->addItem(tr("off"));
+ m_pageProtectionCombo->addItem(tr("after"));
+ m_pageProtectionCombo->addItem(tr("before"));
+ connect(m_pageProtectionCombo, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+ this, &HeobDialog::updateEnabled);
+ pageProtectionLayout->addWidget(m_pageProtectionCombo);
+ layout->addLayout(pageProtectionLayout);
+
+ m_freedProtectionCheck = new QCheckBox(tr("freed memory protection"));
+ layout->addWidget(m_freedProtectionCheck);
+
+ m_breakpointCheck = new QCheckBox(tr("raise breakpoint exception on error"));
+ layout->addWidget(m_breakpointCheck);
+
+ QHBoxLayout *leakDetailLayout = new QHBoxLayout;
+ QLabel *leakDetailLabel = new QLabel(tr("leak details:"));
+ leakDetailLayout->addWidget(leakDetailLabel);
+ m_leakDetailCombo = new QComboBox;
+ m_leakDetailCombo->addItem(tr("none"));
+ m_leakDetailCombo->addItem(tr("simple"));
+ m_leakDetailCombo->addItem(tr("detect leak types"));
+ m_leakDetailCombo->addItem(tr("detect leak types (show reachable)"));
+ m_leakDetailCombo->addItem(tr("fuzzy detect leak types"));
+ m_leakDetailCombo->addItem(tr("fuzzy detect leak types (show reachable)"));
+ m_leakDetailCombo->setCurrentIndex(1);
+ connect(m_leakDetailCombo, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+ this, &HeobDialog::updateEnabled);
+ leakDetailLayout->addWidget(m_leakDetailCombo);
+ layout->addLayout(leakDetailLayout);
+
+ QHBoxLayout *leakSizeLayout = new QHBoxLayout;
+ QLabel *leakSizeLabel = new QLabel(tr("minimum leak size:"));
+ leakSizeLayout->addWidget(leakSizeLabel);
+ m_leakSizeSpin = new QSpinBox;
+ m_leakSizeSpin->setMinimum(0);
+ m_leakSizeSpin->setMaximum(INT_MAX);
+ m_leakSizeSpin->setSingleStep(1000);
+ m_leakSizeSpin->setValue(0);
+ leakSizeLayout->addWidget(m_leakSizeSpin);
+ layout->addLayout(leakSizeLayout);
+
+ QHBoxLayout *leakRecordingLayout = new QHBoxLayout;
+ QLabel *leakRecordingLabel = new QLabel(tr("control leak recording:"));
+ leakRecordingLayout->addWidget(leakRecordingLabel);
+ m_leakRecordingCombo = new QComboBox;
+ m_leakRecordingCombo->addItem(tr("off"));
+ m_leakRecordingCombo->addItem(tr("on (start disabled)"));
+ m_leakRecordingCombo->addItem(tr("on (start enabled)"));
+ m_leakRecordingCombo->setCurrentIndex(2);
+ leakRecordingLayout->addWidget(m_leakRecordingCombo);
+ layout->addLayout(leakRecordingLayout);
+
+ QHBoxLayout *extraArgsLayout = new QHBoxLayout;
+ QLabel *extraArgsLabel = new QLabel(tr("extra arguments:"));
+ extraArgsLayout->addWidget(extraArgsLabel);
+ m_extraArgsEdit = new QLineEdit;
+ extraArgsLayout->addWidget(m_extraArgsEdit);
+ layout->addLayout(extraArgsLayout);
+
+ QHBoxLayout *okLayout = new QHBoxLayout;
+ okLayout->addStretch(1);
+ QPushButton *okButton = new QPushButton(tr("OK"));
+ connect(okButton, &QAbstractButton::clicked, this, &QDialog::accept);
+ okLayout->addWidget(okButton);
+ okLayout->addStretch(1);
+ layout->addLayout(okLayout);
+
+ setLayout(layout);
+
+ updateEnabled();
+
+ setWindowTitle(tr("heob"));
+
+ // disable context help button
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+}
+
+QString HeobDialog::arguments() const
+{
+ QString args;
+
+ args += " -A";
+
+ const QString xml = xmlName();
+ if (!xml.isEmpty())
+ args += " -x" + xml;
+
+ int pidWait = m_pidWaitCheck->isChecked() ? 1 : 0;
+ args += QString(" -P%1").arg(pidWait);
+
+ int handleException = m_handleExceptionCombo->currentIndex();
+ args += QString(" -h%1").arg(handleException);
+
+ int pageProtection = m_pageProtectionCombo->currentIndex();
+ args += QString(" -p%1").arg(pageProtection);
+
+ int freedProtection = m_freedProtectionCheck->isChecked() ? 1 : 0;
+ args += QString(" -f%1").arg(freedProtection);
+
+ int breakpoint = m_breakpointCheck->isChecked() ? 1 : 0;
+ args += QString(" -r%1").arg(breakpoint);
+
+ int leakDetail = m_leakDetailCombo->currentIndex();
+ args += QString(" -l%1").arg(leakDetail);
+
+ int leakSize = m_leakSizeSpin->value();
+ args += QString(" -z%1").arg(leakSize);
+
+ int leakRecording = m_leakRecordingCombo->currentIndex();
+ args += QString(" -k%1").arg(leakRecording);
+
+ const QString extraArgs = m_extraArgsEdit->text();
+ if (!extraArgs.isEmpty())
+ args += ' ' + extraArgs;
+
+ return args;
+}
+
+QString HeobDialog::xmlName() const
+{
+ return m_xmlEdit->text().replace(' ', '_');
+}
+
+void HeobDialog::updateEnabled()
+{
+ bool enableHeob = m_handleExceptionCombo->currentIndex() < 2;
+ bool enableLeakDetection = enableHeob && m_leakDetailCombo->currentIndex() > 0;
+ bool enablePageProtection = enableHeob && m_pageProtectionCombo->currentIndex() > 0;
+
+ m_leakDetailCombo->setEnabled(enableHeob);
+ m_pageProtectionCombo->setEnabled(enableHeob);
+ m_breakpointCheck->setEnabled(enableHeob);
+
+ m_leakSizeSpin->setEnabled(enableLeakDetection);
+ m_leakRecordingCombo->setEnabled(enableLeakDetection);
+
+ m_freedProtectionCheck->setEnabled(enablePageProtection);
+}
+
+HeobData::HeobData(MemcheckTool *mcTool, const QString &xmlPath)
+ : m_mcTool(mcTool), m_xmlPath(xmlPath), m_ov(), m_data()
+{
+}
+
+HeobData::~HeobData()
+{
+ delete m_processFinishedNotifier;
+ if (m_errorPipe != INVALID_HANDLE_VALUE)
+ CloseHandle(m_errorPipe);
+ if (m_ov.hEvent)
+ CloseHandle(m_ov.hEvent);
+}
+
+bool HeobData::createErrorPipe(DWORD heobPid)
+{
+ const QString pipeName = QString("\\\\.\\Pipe\\heob.error.%1").arg(upperHexNum(heobPid));
+ DWORD access = PIPE_ACCESS_INBOUND;
+ m_errorPipe = CreateNamedPipe(reinterpret_cast<LPCWSTR>(pipeName.utf16()),
+ access | FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_BYTE, 1, 1024, 1024, 0, NULL);
+ return m_errorPipe != INVALID_HANDLE_VALUE;
+}
+
+void HeobData::readExitData()
+{
+ m_ov.Offset = m_ov.OffsetHigh = 0;
+ m_ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ bool pipeConnected = ConnectNamedPipe(m_errorPipe, &m_ov);
+ if (!pipeConnected) {
+ DWORD error = GetLastError();
+ if (error == ERROR_PIPE_CONNECTED) {
+ pipeConnected = true;
+ } else if (error == ERROR_IO_PENDING) {
+ if (WaitForSingleObject(m_ov.hEvent, 1000) == WAIT_OBJECT_0)
+ pipeConnected = true;
+ else
+ CancelIo(m_errorPipe);
+ }
+ }
+ if (pipeConnected) {
+ if (ReadFile(m_errorPipe, m_data, sizeof(m_data), NULL, &m_ov)
+ || GetLastError() == ERROR_IO_PENDING) {
+ m_processFinishedNotifier = new QWinEventNotifier(m_ov.hEvent);
+ connect(m_processFinishedNotifier, &QWinEventNotifier::activated, this, &HeobData::processFinished);
+ m_processFinishedNotifier->setEnabled(true);
+ return;
+ }
+ }
+
+ // connection to heob error pipe failed
+ delete this;
+}
+
+enum
+{
+ HEOB_OK,
+ HEOB_HELP,
+ HEOB_BAD_ARG,
+ HEOB_PROCESS_FAIL,
+ HEOB_WRONG_BITNESS,
+ HEOB_PROCESS_KILLED,
+ HEOB_NO_CRT,
+ HEOB_EXCEPTION,
+ HEOB_OUT_OF_MEMORY,
+ HEOB_UNEXPECTED_END,
+ HEOB_TRACE,
+ HEOB_CONSOLE,
+ HEOB_PID_ATTACH = 0x10000000,
+};
+
+void HeobData::processFinished()
+{
+ m_processFinishedNotifier->setEnabled(false);
+
+ QString exitMsg;
+ bool needErrorMsg = true;
+ DWORD didread;
+ if (GetOverlappedResult(m_errorPipe, &m_ov, &didread, TRUE) && didread == sizeof(m_data)) {
+ switch (m_data[0]) {
+ case HEOB_OK:
+ exitMsg = tr("Process finished with exit code %1 (0x%2).").arg(m_data[1]).arg(upperHexNum(m_data[1]));
+ needErrorMsg = false;
+ break;
+
+ case HEOB_BAD_ARG:
+ exitMsg = tr("Unknown argument: -%1").arg((char)m_data[1]);
+ break;
+
+ case HEOB_PROCESS_FAIL:
+ exitMsg = tr("Can't create target process");
+ if (m_data[1])
+ exitMsg += " (" + qt_error_string(m_data[1]) + ')';
+ break;
+
+ case HEOB_WRONG_BITNESS:
+ exitMsg = tr("Wrong bitness");
+ break;
+
+ case HEOB_PROCESS_KILLED:
+ exitMsg = tr("Process killed");
+ break;
+
+ case HEOB_NO_CRT:
+ exitMsg = tr("Only works with dynamically linked CRT");
+ break;
+
+ case HEOB_EXCEPTION:
+ exitMsg = tr("Process stopped with unhandled exception code 0x%1.").arg(upperHexNum(m_data[1]));
+ needErrorMsg = false;
+ break;
+
+ case HEOB_OUT_OF_MEMORY:
+ exitMsg = tr("Not enough memory to keep track of allocations");
+ break;
+
+ case HEOB_UNEXPECTED_END:
+ exitMsg = tr("Unexpected end of application");
+ break;
+
+ case HEOB_CONSOLE:
+ exitMsg = tr("Extra console");
+ break;
+
+ case HEOB_HELP:
+ case HEOB_TRACE:
+ deleteLater();
+ return;
+
+ default:
+ exitMsg = tr("Unknown exit reason");
+ break;
+ }
+ } else {
+ exitMsg = tr("Unexpected end of heob");
+ }
+
+ if (needErrorMsg) {
+ const QString msg = tr("heob: %1").arg(exitMsg);
+ TaskHub::addTask(Task::Error, msg, Debugger::Constants::ANALYZERTASK_ID);
+ TaskHub::requestPopup();
+ } else {
+ m_mcTool->loadShowXmlLogFile(m_xmlPath, exitMsg);
+ }
+
+ deleteLater();
+}
+#endif
+
} // namespace Internal
} // namespace Valgrind