diff --git a/src/plugins/debugger/debuggeractions.cpp b/src/plugins/debugger/debuggeractions.cpp index 52a483d9521942c80e0988e4cd740eb0a3952182..38b431696e8b53255f91145717e06bc2e849968c 100644 --- a/src/plugins/debugger/debuggeractions.cpp +++ b/src/plugins/debugger/debuggeractions.cpp @@ -248,6 +248,14 @@ DebuggerSettings *DebuggerSettings::instance() item->setText(tr("Synchronize breakpoints")); instance->insertItem(SynchronizeBreakpoints, item); + item = new SavedAction(instance); + item->setText(tr("Use precise breakpoints")); + item->setCheckable(true); + item->setDefaultValue(true); + item->setValue(true); + item->setSettingsKey(debugModeGroup, QLatin1String("UsePreciseBreakpoints")); + instance->insertItem(UsePreciseBreakpoints, item); + // // Settings // diff --git a/src/plugins/debugger/debuggeractions.h b/src/plugins/debugger/debuggeractions.h index 234cf21731ccd3eb20b79c75742ba903a534733f..faa2e3e6b11d9390c9f09fcfb4e782a12217d40e 100644 --- a/src/plugins/debugger/debuggeractions.h +++ b/src/plugins/debugger/debuggeractions.h @@ -126,6 +126,7 @@ enum DebuggerActionCode SelectedPluginBreakpoints, NoPluginBreakpoints, SelectedPluginBreakpointsPattern, + UsePreciseBreakpoints }; // singleton access diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index bd51db043f40ce9c316520d92b405c99e0809bbd..58148c9831953711d13efa1c682fc5528f5792d2 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -360,6 +360,7 @@ QWidget *CommonOptionsPage::createPage(QWidget *parent) m_group.insert(theDebuggerAction(MaximalStackDepth), m_ui.spinBoxMaximalStackDepth); m_group.insert(theDebuggerAction(LogTimeStamps), 0); + m_group.insert(theDebuggerAction(UsePreciseBreakpoints), 0); #ifdef USE_REVERSE_DEBUGGING m_ui.checkBoxEnableReverseDebugging->hide(); diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 9a1e9da89eac6b2a6d4a99d11fbfee6801dfdce0..6b44001fbae12600e99123dc00dbf8178c7760e2 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -271,8 +271,9 @@ void GdbEngine::initializeVariables() m_shortToFullName.clear(); m_varToType.clear(); - m_modulesListOutdated = m_sourcesListOutdated = true; + invalidateSourcesList(); m_sourcesListUpdating = false; + m_breakListUpdating = false; m_oldestAcceptableToken = -1; m_outputCodec = QTextCodec::codecForLocale(); m_pendingRequests = 0; @@ -439,14 +440,14 @@ void GdbEngine::handleResponse(const QByteArray &buff) QByteArray id = result.findChild("id").data(); if (!id.isEmpty()) showStatusMessage(tr("Library %1 loaded.").arg(_(id))); - m_modulesListOutdated = m_sourcesListOutdated = true; + invalidateSourcesList(); } else if (asyncClass == "library-unloaded") { // Archer has 'id="/usr/lib/libdrm.so.2", // target-name="/usr/lib/libdrm.so.2", // host-name="/usr/lib/libdrm.so.2" QByteArray id = result.findChild("id").data(); showStatusMessage(tr("Library %1 unloaded.").arg(_(id))); - m_modulesListOutdated = m_sourcesListOutdated = true; + invalidateSourcesList(); } else if (asyncClass == "thread-group-created") { // Archer has "{id="28902"}" QByteArray id = result.findChild("id").data(); @@ -475,7 +476,7 @@ void GdbEngine::handleResponse(const QByteArray &buff) #if defined(Q_OS_MAC) } else if (asyncClass == "shlibs-updated") { // MAC announces updated libs - m_modulesListOutdated = m_sourcesListOutdated = true; + invalidateSourcesList(); } else if (asyncClass == "shlibs-added") { // MAC announces added libs // {shlib-info={num="2", name="libmathCommon.A_debug.dylib", @@ -483,7 +484,7 @@ void GdbEngine::handleResponse(const QByteArray &buff) // state="Y", path="/usr/lib/system/libmathCommon.A_debug.dylib", // description="/usr/lib/system/libmathCommon.A_debug.dylib", // loaded_addr="0x7f000", slide="0x7f000", prefix=""}} - m_modulesListOutdated = m_sourcesListOutdated = true; + invalidateSourcesList(); #endif } else { qDebug() << "IGNORED ASYNC OUTPUT" @@ -517,7 +518,7 @@ void GdbEngine::handleResponse(const QByteArray &buff) // Show some messages to give the impression something happens. if (data.startsWith("Reading symbols from ")) { showStatusMessage(tr("Reading %1...").arg(_(data.mid(21))), 1000); - m_modulesListOutdated = m_sourcesListOutdated = true; + invalidateSourcesList(); } else if (data.startsWith("[New ") || data.startsWith("[Thread ")) { if (data.endsWith('\n')) data.chop(1); @@ -988,6 +989,8 @@ void GdbEngine::updateAll() void GdbEngine::handleQuerySources(const GdbResponse &response) { + m_sourcesListUpdating = false; + m_sourcesListOutdated = false; if (response.resultClass == GdbResultDone) { QMap<QString, QString> oldShortToFull = m_shortToFullName; m_shortToFullName.clear(); @@ -1161,7 +1164,7 @@ void GdbEngine::handleStopResponse(const GdbMi &data) // on Windows it simply forgets about it. Thus, we identify the response // based on it having no frame information. if (!data.findChild("frame").isValid()) { - m_modulesListOutdated = m_sourcesListOutdated = true; + invalidateSourcesList(); // Each stop causes a roundtrip and button flicker, so prevent // a flood of useless stops. Will be automatically re-enabled. postCommand(_("set stop-on-solib-events 0")); @@ -1273,14 +1276,17 @@ void GdbEngine::handleStop1(const GdbMi &data) { if (m_modulesListOutdated) reloadModulesInternal(); // This is for display only - if (m_sourcesListOutdated) + if (m_sourcesListOutdated && theDebuggerBoolSetting(UsePreciseBreakpoints)) reloadSourceFilesInternal(); // This needs to be done before fullName() may need it - // Older gdb versions do not produce "library loaded" messages - // so the breakpoint update is not triggered. - if (m_gdbVersion < 70000 && !m_isMacGdb && !m_sourcesListUpdating - && manager()->breakHandler()->size() > 0) - postCommand(_("-break-list"), CB(handleBreakList)); + if (m_breakListOutdated) + reloadBreakListInternal(); + else + // Older gdb versions do not produce "library loaded" messages + // so the breakpoint update is not triggered. + if (m_gdbVersion < 70000 && !m_isMacGdb && !m_breakListUpdating + && manager()->breakHandler()->size() > 0) + reloadBreakListInternal(); QByteArray reason = data.findChild("reason").data(); if (reason == "breakpoint-hit") { @@ -1876,8 +1882,8 @@ void GdbEngine::breakpointDataFromOutput(BreakpointData *data, const GdbMi &bkpt QString GdbEngine::breakLocation(const QString &file) const { - QTC_ASSERT(!m_sourcesListOutdated, /* */) - QTC_ASSERT(!m_sourcesListUpdating, /* */) + QTC_ASSERT(!m_breakListOutdated, /* */) + QTC_ASSERT(!m_breakListUpdating, /* */) QString where = m_fullToShortName.value(file); if (where.isEmpty()) return QFileInfo(file).fileName(); @@ -1912,10 +1918,14 @@ void GdbEngine::sendInsertBreakpoint(int index) postCommand(cmd, NeedsStop, CB(handleBreakInsert), index); } -void GdbEngine::handleBreakList(const GdbResponse &response) +void GdbEngine::reloadBreakListInternal() { - m_sourcesListUpdating = false; + m_breakListUpdating = true; + postCommand(_("-break-list"), CB(handleBreakList)); +} +void GdbEngine::handleBreakList(const GdbResponse &response) +{ // 45^done,BreakpointTable={nr_rows="2",nr_cols="6",hdr=[ // {width="3",alignment="-1",col_name="number",colhdr="Num"}, ... // body=[bkpt={number="1",type="breakpoint",disp="keep",enabled="y", @@ -1962,6 +1972,8 @@ void GdbEngine::handleBreakList(const GdbMi &table) //qDebug() << "CANNOT HANDLE RESPONSE" << bkpts.at(index).toString(); } + m_breakListUpdating = false; + m_breakListOutdated = false; attemptBreakpointSynchronization(); } @@ -2118,6 +2130,11 @@ void GdbEngine::handleBreakInsert1(const GdbResponse &response) void GdbEngine::attemptBreakpointSynchronization() { + //QTC_ASSERT(!m_breakListUpdating, + // qDebug() << "BREAK LIST CURRENTLY UPDATING"; return); + QTC_ASSERT(!m_sourcesListUpdating, + qDebug() << "SOURCES LIST CURRENTLY UPDATING"; return); + switch (state()) { case InferiorStarting: case InferiorRunningRequested: @@ -2132,10 +2149,13 @@ void GdbEngine::attemptBreakpointSynchronization() // For best results, we rely on an up-to-date fullname mapping. // The listing completion will retrigger us, so no futher action is needed. - if (m_sourcesListOutdated) { + if (m_sourcesListOutdated && theDebuggerBoolSetting(UsePreciseBreakpoints)) { reloadSourceFilesInternal(); + reloadBreakListInternal(); return; - } else if (m_sourcesListUpdating) { + } + if (m_breakListOutdated) { + reloadBreakListInternal(); return; } @@ -2318,6 +2338,13 @@ void GdbEngine::handleModulesList(const GdbResponse &response) // ////////////////////////////////////////////////////////////////////// +void GdbEngine::invalidateSourcesList() +{ + m_modulesListOutdated = true; + m_sourcesListOutdated = true; + m_breakListOutdated = true; +} + void GdbEngine::reloadSourceFiles() { if ((state() == InferiorRunning || state() == InferiorStopped) @@ -2327,10 +2354,9 @@ void GdbEngine::reloadSourceFiles() void GdbEngine::reloadSourceFilesInternal() { + QTC_ASSERT(!m_sourcesListUpdating, /**/); m_sourcesListUpdating = true; - m_sourcesListOutdated = false; postCommand(_("-file-list-exec-source-files"), NeedsStop, CB(handleQuerySources)); - postCommand(_("-break-list"), CB(handleBreakList)); #if 0 if (m_gdbVersion < 70000 && !m_isMacGdb) postCommand(_("set stop-on-solib-events 1")); @@ -4192,7 +4218,8 @@ QString GdbEngine::parseDisassembler(const GdbMi &lines) // mixed mode if (!fileLoaded) { QString fileName = QFile::decodeName(child.findChild("file").data()); - QFile file(fullName(fileName)); + fileName = cleanupFullName(fileName); + QFile file(fileName); file.open(QIODevice::ReadOnly); fileContents = file.readAll().split('\n'); fileLoaded = true; diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index dc1acf68fcc3feb27b3a642d0a8eca215b499d16..519df6b31711d4c8a2e8ce75d28ca8ffd601ff15 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -328,6 +328,7 @@ private: ////////// View & Data Stuff ////////// void breakpointDataFromOutput(BreakpointData *data, const GdbMi &bkpt); void sendInsertBreakpoint(int index); QString breakLocation(const QString &file) const; + void reloadBreakListInternal(); // // Modules specific stuff @@ -379,8 +380,11 @@ private: ////////// View & Data Stuff ////////// QMap<QString, QString> m_shortToFullName; QMap<QString, QString> m_fullToShortName; + void invalidateSourcesList(); bool m_sourcesListOutdated; bool m_sourcesListUpdating; + bool m_breakListOutdated; + bool m_breakListUpdating; // // Stack specific stuff diff --git a/src/plugins/debugger/gdb/gdboptionspage.cpp b/src/plugins/debugger/gdb/gdboptionspage.cpp index b030e44977f0abe3bba41ea6b6f8e19e7eb2118a..44e2624d5577a1984479600668374efbbb8f83ee 100644 --- a/src/plugins/debugger/gdb/gdboptionspage.cpp +++ b/src/plugins/debugger/gdb/gdboptionspage.cpp @@ -50,6 +50,8 @@ QWidget *GdbOptionsPage::createPage(QWidget *parent) m_ui.scriptFileChooser); m_group.insert(theDebuggerAction(GdbEnvironment), m_ui.environmentEdit); + m_group.insert(theDebuggerAction(UsePreciseBreakpoints), + m_ui.checkBoxUsePreciseBreakpoints); #if 1 m_ui.groupBoxPluginDebugging->hide(); diff --git a/src/plugins/debugger/gdb/gdboptionspage.ui b/src/plugins/debugger/gdb/gdboptionspage.ui index 01900e9763248b411234360f70c5349d63c65628..d2b4c18bcfdf66f70e90f2c2ec79088cb2418c79 100644 --- a/src/plugins/debugger/gdb/gdboptionspage.ui +++ b/src/plugins/debugger/gdb/gdboptionspage.ui @@ -62,6 +62,19 @@ <item row="0" column="1"> <widget class="Utils::PathChooser" name="gdbLocationChooser" native="true"/> </item> + <item row="3" column="0" colspan="2"> + <widget class="QCheckBox" name="checkBoxUsePreciseBreakpoints"> + <property name="text"> + <string>Use full path information to set breakpoints</string> + </property> + <property name="toolTip"> + <string>When this option is checked, the debugger plugin attempts +to extract full path information for all source files from gdb. This is a +slow process but enables setting breakpoints in files with the same file +name in different directories.</string> + </property> + </widget> + </item> </layout> </widget> </item>