forked from qt-creator/qt-creator
Valgrind: Run heob process with debugger
Change-Id: Ie026033b04dce73c8f4d7a4adb42f9c08c53cccd Reviewed-by: André Hartmann <aha_1980@gmx.de> Reviewed-by: Orgad Shaneh <orgads@gmail.com>
This commit is contained in:
@@ -475,13 +475,13 @@ public:
|
|||||||
|
|
||||||
QString arguments() const;
|
QString arguments() const;
|
||||||
QString xmlName() const;
|
QString xmlName() const;
|
||||||
|
bool attach() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateEnabled();
|
void updateEnabled();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QLineEdit *m_xmlEdit = nullptr;
|
QLineEdit *m_xmlEdit = nullptr;
|
||||||
QCheckBox *m_pidWaitCheck = nullptr;
|
|
||||||
QComboBox *m_handleExceptionCombo = nullptr;
|
QComboBox *m_handleExceptionCombo = nullptr;
|
||||||
QComboBox *m_pageProtectionCombo = nullptr;
|
QComboBox *m_pageProtectionCombo = nullptr;
|
||||||
QCheckBox *m_freedProtectionCheck = nullptr;
|
QCheckBox *m_freedProtectionCheck = nullptr;
|
||||||
@@ -489,13 +489,14 @@ private:
|
|||||||
QComboBox *m_leakDetailCombo = nullptr;
|
QComboBox *m_leakDetailCombo = nullptr;
|
||||||
QSpinBox *m_leakSizeSpin = nullptr;
|
QSpinBox *m_leakSizeSpin = nullptr;
|
||||||
QComboBox *m_leakRecordingCombo = nullptr;
|
QComboBox *m_leakRecordingCombo = nullptr;
|
||||||
|
QCheckBox *m_attachCheck = nullptr;
|
||||||
QLineEdit *m_extraArgsEdit = nullptr;
|
QLineEdit *m_extraArgsEdit = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
class HeobData : public QObject
|
class HeobData : public QObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HeobData(MemcheckTool *mcTool, const QString &xmlPath);
|
HeobData(MemcheckTool *mcTool, const QString &xmlPath, Kit *kit, bool attach);
|
||||||
~HeobData();
|
~HeobData();
|
||||||
|
|
||||||
bool createErrorPipe(DWORD heobPid);
|
bool createErrorPipe(DWORD heobPid);
|
||||||
@@ -504,6 +505,10 @@ public:
|
|||||||
private:
|
private:
|
||||||
void processFinished();
|
void processFinished();
|
||||||
|
|
||||||
|
void sendHeobAttachPid(DWORD pid);
|
||||||
|
void debugStarted();
|
||||||
|
void debugStopped();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HANDLE m_errorPipe = INVALID_HANDLE_VALUE;
|
HANDLE m_errorPipe = INVALID_HANDLE_VALUE;
|
||||||
OVERLAPPED m_ov;
|
OVERLAPPED m_ov;
|
||||||
@@ -511,6 +516,9 @@ private:
|
|||||||
QWinEventNotifier *m_processFinishedNotifier = nullptr;
|
QWinEventNotifier *m_processFinishedNotifier = nullptr;
|
||||||
MemcheckTool *m_mcTool = nullptr;
|
MemcheckTool *m_mcTool = nullptr;
|
||||||
QString m_xmlPath;
|
QString m_xmlPath;
|
||||||
|
Kit *m_kit = nullptr;
|
||||||
|
bool m_attach = false;
|
||||||
|
RunControl *m_runControl = nullptr;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -708,10 +716,11 @@ void MemcheckTool::heobAction()
|
|||||||
StandardRunnable sr;
|
StandardRunnable sr;
|
||||||
Abi abi;
|
Abi abi;
|
||||||
bool hasLocalRc = false;
|
bool hasLocalRc = false;
|
||||||
|
Kit *kit = nullptr;
|
||||||
if (Project *project = SessionManager::startupProject()) {
|
if (Project *project = SessionManager::startupProject()) {
|
||||||
if (Target *target = project->activeTarget()) {
|
if (Target *target = project->activeTarget()) {
|
||||||
if (RunConfiguration *rc = target->activeRunConfiguration()) {
|
if (RunConfiguration *rc = target->activeRunConfiguration()) {
|
||||||
if (Kit *kit = target->kit()) {
|
if (kit = target->kit()) {
|
||||||
abi = ToolChainKitInformation::targetAbi(kit);
|
abi = ToolChainKitInformation::targetAbi(kit);
|
||||||
|
|
||||||
const Runnable runnable = rc->runnable();
|
const Runnable runnable = rc->runnable();
|
||||||
@@ -828,7 +837,7 @@ void MemcheckTool::heobAction()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// heob finished signal handler
|
// heob finished signal handler
|
||||||
HeobData *hd = new HeobData(this, xmlPath);
|
HeobData *hd = new HeobData(this, xmlPath, kit, dialog.attach());
|
||||||
if (!hd->createErrorPipe(pi.dwProcessId)) {
|
if (!hd->createErrorPipe(pi.dwProcessId)) {
|
||||||
delete hd;
|
delete hd;
|
||||||
hd = nullptr;
|
hd = nullptr;
|
||||||
@@ -1140,9 +1149,6 @@ HeobDialog::HeobDialog(QWidget *parent) :
|
|||||||
xmlLayout->addWidget(m_xmlEdit);
|
xmlLayout->addWidget(m_xmlEdit);
|
||||||
layout->addLayout(xmlLayout);
|
layout->addLayout(xmlLayout);
|
||||||
|
|
||||||
m_pidWaitCheck = new QCheckBox(tr("show process ID and wait"));
|
|
||||||
layout->addWidget(m_pidWaitCheck);
|
|
||||||
|
|
||||||
QHBoxLayout *handleExceptionLayout = new QHBoxLayout;
|
QHBoxLayout *handleExceptionLayout = new QHBoxLayout;
|
||||||
QLabel *handleExceptionLabel = new QLabel(tr("handle exceptions:"));
|
QLabel *handleExceptionLabel = new QLabel(tr("handle exceptions:"));
|
||||||
handleExceptionLayout->addWidget(handleExceptionLabel);
|
handleExceptionLayout->addWidget(handleExceptionLabel);
|
||||||
@@ -1212,6 +1218,9 @@ HeobDialog::HeobDialog(QWidget *parent) :
|
|||||||
leakRecordingLayout->addWidget(m_leakRecordingCombo);
|
leakRecordingLayout->addWidget(m_leakRecordingCombo);
|
||||||
layout->addLayout(leakRecordingLayout);
|
layout->addLayout(leakRecordingLayout);
|
||||||
|
|
||||||
|
m_attachCheck = new QCheckBox(tr("Run with debugger"));
|
||||||
|
layout->addWidget(m_attachCheck);
|
||||||
|
|
||||||
QHBoxLayout *extraArgsLayout = new QHBoxLayout;
|
QHBoxLayout *extraArgsLayout = new QHBoxLayout;
|
||||||
QLabel *extraArgsLabel = new QLabel(tr("extra arguments:"));
|
QLabel *extraArgsLabel = new QLabel(tr("extra arguments:"));
|
||||||
extraArgsLayout->addWidget(extraArgsLabel);
|
extraArgsLayout->addWidget(extraArgsLabel);
|
||||||
@@ -1247,9 +1256,6 @@ QString HeobDialog::arguments() const
|
|||||||
if (!xml.isEmpty())
|
if (!xml.isEmpty())
|
||||||
args += " -x" + xml;
|
args += " -x" + xml;
|
||||||
|
|
||||||
int pidWait = m_pidWaitCheck->isChecked() ? 1 : 0;
|
|
||||||
args += QString(" -P%1").arg(pidWait);
|
|
||||||
|
|
||||||
int handleException = m_handleExceptionCombo->currentIndex();
|
int handleException = m_handleExceptionCombo->currentIndex();
|
||||||
args += QString(" -h%1").arg(handleException);
|
args += QString(" -h%1").arg(handleException);
|
||||||
|
|
||||||
@@ -1283,6 +1289,11 @@ QString HeobDialog::xmlName() const
|
|||||||
return m_xmlEdit->text().replace(' ', '_');
|
return m_xmlEdit->text().replace(' ', '_');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HeobDialog::attach() const
|
||||||
|
{
|
||||||
|
return m_attachCheck->isChecked();
|
||||||
|
}
|
||||||
|
|
||||||
void HeobDialog::updateEnabled()
|
void HeobDialog::updateEnabled()
|
||||||
{
|
{
|
||||||
bool enableHeob = m_handleExceptionCombo->currentIndex() < 2;
|
bool enableHeob = m_handleExceptionCombo->currentIndex() < 2;
|
||||||
@@ -1299,8 +1310,8 @@ void HeobDialog::updateEnabled()
|
|||||||
m_freedProtectionCheck->setEnabled(enablePageProtection);
|
m_freedProtectionCheck->setEnabled(enablePageProtection);
|
||||||
}
|
}
|
||||||
|
|
||||||
HeobData::HeobData(MemcheckTool *mcTool, const QString &xmlPath)
|
HeobData::HeobData(MemcheckTool *mcTool, const QString &xmlPath, Kit *kit, bool attach)
|
||||||
: m_mcTool(mcTool), m_xmlPath(xmlPath), m_ov(), m_data()
|
: m_mcTool(mcTool), m_xmlPath(xmlPath), m_kit(kit), m_attach(attach), m_ov(), m_data()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1316,7 +1327,7 @@ HeobData::~HeobData()
|
|||||||
bool HeobData::createErrorPipe(DWORD heobPid)
|
bool HeobData::createErrorPipe(DWORD heobPid)
|
||||||
{
|
{
|
||||||
const QString pipeName = QString("\\\\.\\Pipe\\heob.error.%1").arg(upperHexNum(heobPid));
|
const QString pipeName = QString("\\\\.\\Pipe\\heob.error.%1").arg(upperHexNum(heobPid));
|
||||||
DWORD access = PIPE_ACCESS_INBOUND;
|
DWORD access = m_attach ? PIPE_ACCESS_DUPLEX : PIPE_ACCESS_INBOUND;
|
||||||
m_errorPipe = CreateNamedPipe(reinterpret_cast<LPCWSTR>(pipeName.utf16()),
|
m_errorPipe = CreateNamedPipe(reinterpret_cast<LPCWSTR>(pipeName.utf16()),
|
||||||
access | FILE_FLAG_OVERLAPPED,
|
access | FILE_FLAG_OVERLAPPED,
|
||||||
PIPE_TYPE_BYTE, 1, 1024, 1024, 0, NULL);
|
PIPE_TYPE_BYTE, 1, 1024, 1024, 0, NULL);
|
||||||
@@ -1370,6 +1381,12 @@ enum
|
|||||||
HEOB_PID_ATTACH = 0x10000000,
|
HEOB_PID_ATTACH = 0x10000000,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
HEOB_CONTROL_NONE,
|
||||||
|
HEOB_CONTROL_ATTACH,
|
||||||
|
};
|
||||||
|
|
||||||
void HeobData::processFinished()
|
void HeobData::processFinished()
|
||||||
{
|
{
|
||||||
m_processFinishedNotifier->setEnabled(false);
|
m_processFinishedNotifier->setEnabled(false);
|
||||||
@@ -1378,6 +1395,31 @@ void HeobData::processFinished()
|
|||||||
bool needErrorMsg = true;
|
bool needErrorMsg = true;
|
||||||
DWORD didread;
|
DWORD didread;
|
||||||
if (GetOverlappedResult(m_errorPipe, &m_ov, &didread, TRUE) && didread == sizeof(m_data)) {
|
if (GetOverlappedResult(m_errorPipe, &m_ov, &didread, TRUE) && didread == sizeof(m_data)) {
|
||||||
|
if (m_data[0] >= HEOB_PID_ATTACH) {
|
||||||
|
m_runControl = new RunControl(nullptr, ProjectExplorer::Constants::DEBUG_RUN_MODE);
|
||||||
|
auto debugger = new DebuggerRunTool(m_runControl, m_kit);
|
||||||
|
debugger->setAttachPid(ProcessHandle(m_data[1]));
|
||||||
|
debugger->setRunControlName(tr("Process %1").arg(m_data[1]));
|
||||||
|
debugger->setInferiorDevice(DeviceKitInformation::device(m_kit));
|
||||||
|
debugger->setStartMode(AttachExternal);
|
||||||
|
debugger->setCloseMode(DetachAtClose);
|
||||||
|
debugger->setContinueAfterAttach(true);
|
||||||
|
|
||||||
|
HANDLE p = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, m_data[1]);
|
||||||
|
if (p != NULL) {
|
||||||
|
wchar_t path[MAX_PATH];
|
||||||
|
DWORD pathLen = MAX_PATH;
|
||||||
|
if (QueryFullProcessImageName(p, 0, path, &pathLen))
|
||||||
|
debugger->setInferiorExecutable(QString::fromWCharArray(path));
|
||||||
|
CloseHandle(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(m_runControl, &RunControl::started, this, &HeobData::debugStarted);
|
||||||
|
connect(m_runControl, &RunControl::stopped, this, &HeobData::debugStopped);
|
||||||
|
debugger->startRunControl();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (m_data[0]) {
|
switch (m_data[0]) {
|
||||||
case HEOB_OK:
|
case HEOB_OK:
|
||||||
exitMsg = tr("Process finished with exit code %1 (0x%2).").arg(m_data[1]).arg(upperHexNum(m_data[1]));
|
exitMsg = tr("Process finished with exit code %1 (0x%2).").arg(m_data[1]).arg(upperHexNum(m_data[1]));
|
||||||
@@ -1446,6 +1488,47 @@ void HeobData::processFinished()
|
|||||||
|
|
||||||
deleteLater();
|
deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HeobData::sendHeobAttachPid(DWORD pid)
|
||||||
|
{
|
||||||
|
m_runControl->disconnect(this);
|
||||||
|
|
||||||
|
m_data[0] = HEOB_CONTROL_ATTACH;
|
||||||
|
m_data[1] = pid;
|
||||||
|
DWORD e = 0;
|
||||||
|
if (WriteFile(m_errorPipe, m_data, sizeof(m_data), NULL, &m_ov)
|
||||||
|
|| (e = GetLastError()) == ERROR_IO_PENDING) {
|
||||||
|
DWORD didwrite;
|
||||||
|
if (GetOverlappedResult(m_errorPipe, &m_ov, &didwrite, TRUE)) {
|
||||||
|
if (didwrite == sizeof(m_data)) {
|
||||||
|
if (ReadFile(m_errorPipe, m_data, sizeof(m_data), NULL, &m_ov)
|
||||||
|
|| (e = GetLastError()) == ERROR_IO_PENDING) {
|
||||||
|
m_processFinishedNotifier->setEnabled(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
e = ERROR_BAD_LENGTH;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
e = GetLastError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString msg = tr("heob: Failure in process attach handshake (%1)").arg(qt_error_string(e));
|
||||||
|
TaskHub::addTask(Task::Error, msg, Debugger::Constants::ANALYZERTASK_ID);
|
||||||
|
TaskHub::requestPopup();
|
||||||
|
deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HeobData::debugStarted()
|
||||||
|
{
|
||||||
|
sendHeobAttachPid(GetCurrentProcessId());
|
||||||
|
}
|
||||||
|
|
||||||
|
void HeobData::debugStopped()
|
||||||
|
{
|
||||||
|
sendHeobAttachPid(0);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|||||||
Reference in New Issue
Block a user