File indexing completed on 2024-04-21 04:36:03
0001 /* 0002 Copyright 2009 Niko Sams <niko.sams@gmail.com> 0003 0004 This library is free software; you can redistribute it and/or 0005 modify it under the terms of the GNU Library General Public 0006 License version 2 as published by the Free Software Foundation. 0007 0008 This library is distributed in the hope that it will be useful, 0009 but WITHOUT ANY WARRANTY; without even the implied warranty of 0010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0011 Library General Public License for more details. 0012 0013 You should have received a copy of the GNU Library General Public License 0014 along with this library; see the file COPYING.LIB. If not, write to 0015 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0016 Boston, MA 02110-1301, USA. 0017 */ 0018 0019 #include "breakpointcontroller.h" 0020 0021 #include <QDomElement> 0022 #include <QDebug> 0023 #include <KLocalizedString> 0024 0025 #include <debugger/breakpoint/breakpoint.h> 0026 0027 #include "debugsession.h" 0028 #include "connection.h" 0029 #include "debuggerdebug.h" 0030 0031 namespace XDebug { 0032 BreakpointController::BreakpointController(DebugSession* parent) 0033 : IBreakpointController(parent) 0034 { 0035 connect(debugSession(), &DebugSession::stateChanged, this, 0036 &BreakpointController::stateChanged); 0037 } 0038 0039 void BreakpointController::sendMaybe(KDevelop::Breakpoint* breakpoint) 0040 { 0041 if (!debugSession()->connection()) { 0042 return; 0043 } 0044 0045 if (breakpoint->deleted()) { 0046 auto it = m_ids.find(breakpoint); 0047 if (it != m_ids.end()) { 0048 QString cmd("breakpoint_remove"); 0049 QStringList args; 0050 args << "-d " + m_ids[breakpoint]; 0051 debugSession()->connection()->sendCommand(cmd, args); 0052 m_ids.erase(it); 0053 } 0054 } else if (m_dirty[breakpoint].contains(KDevelop::Breakpoint::LocationColumn)) { 0055 if (breakpoint->enabled()) { 0056 QString cmd = m_ids.contains(breakpoint) ? "breakpoint_update" : "breakpoint_set"; 0057 QStringList args; 0058 qCDebug(KDEV_PHP_DEBUGGER) << "breakpoint kind" << breakpoint->kind(); 0059 if (breakpoint->kind() == KDevelop::Breakpoint::CodeBreakpoint) { 0060 if (m_ids.contains(breakpoint)) { 0061 args << "-d " + m_ids[breakpoint]; 0062 } else if (breakpoint->line() != -1) { 0063 args << "-t line"; 0064 } else { 0065 args << "-t call"; 0066 } 0067 if (breakpoint->line() != -1) { 0068 QPair<QUrl, int> u = qMakePair(breakpoint->url(), breakpoint->line()); 0069 u = debugSession()->convertToRemoteUrl(u); 0070 args << "-f " + u.first.url(); 0071 args << "-n " + QString::number(u.second + 1); 0072 } else { 0073 args << "-m " + breakpoint->expression(); 0074 } 0075 } else if (breakpoint->kind() == KDevelop::Breakpoint::WriteBreakpoint) { 0076 args << "-t watch"; 0077 args << "-m " + breakpoint->expression(); 0078 } else { 0079 error(breakpoint, i18n("breakpoint type is not supported"), KDevelop::Breakpoint::LocationColumn); 0080 return; 0081 } 0082 if (breakpoint->ignoreHits()) { 0083 args << "-h " + QString::number(breakpoint->ignoreHits() + 1); 0084 args << "-o >="; 0085 } 0086 CallbackWithCookie<BreakpointController, KDevelop::Breakpoint>* cb = 0087 new CallbackWithCookie<BreakpointController, KDevelop::Breakpoint> 0088 (this, &BreakpointController::handleSetBreakpoint, breakpoint, true); 0089 debugSession()->connection()->sendCommand(cmd, args, breakpoint->condition().toUtf8(), cb); 0090 } 0091 } else if (m_dirty[breakpoint].contains(KDevelop::Breakpoint::EnableColumn)) { 0092 Q_ASSERT(m_ids.contains(breakpoint)); 0093 QString cmd = "breakpoint_update"; 0094 QStringList args; 0095 args << "-d " + m_ids[breakpoint]; 0096 args << QString("-s %0").arg(breakpoint->enabled() ? "enabled" : "disabled"); 0097 debugSession()->connection()->sendCommand(cmd, args); 0098 } 0099 m_dirty[breakpoint].clear(); 0100 } 0101 0102 void BreakpointController::handleSetBreakpoint(KDevelop::Breakpoint* breakpoint, const QDomDocument& xml) 0103 { 0104 Q_ASSERT(xml.documentElement().attribute("command") == "breakpoint_set" 0105 || xml.documentElement().attribute("command") == "breakpoint_update"); 0106 Q_ASSERT(breakpoint); 0107 if (xml.documentElement().attribute("command") == "breakpoint_set") { 0108 m_ids[breakpoint] = xml.documentElement().attribute("id"); 0109 } 0110 if (!xml.documentElement().firstChildElement("error").isNull()) { 0111 qCWarning(KDEV_PHP_DEBUGGER) << "breakpoint error" << xml.documentElement().firstChildElement("error").text(); 0112 error(breakpoint, xml.documentElement().firstChildElement("error").text(), KDevelop::Breakpoint::LocationColumn); 0113 } 0114 } 0115 0116 DebugSession* BreakpointController::debugSession() 0117 { 0118 return static_cast<DebugSession*>(KDevelop::IBreakpointController::debugSession()); 0119 } 0120 0121 void BreakpointController::stateChanged(KDevelop::IDebugSession::DebuggerState state) 0122 { 0123 qCDebug(KDEV_PHP_DEBUGGER) << state; 0124 if (state == KDevelop::IDebugSession::StartingState) { 0125 m_ids.clear(); 0126 sendMaybeAll(); 0127 } else if (state == KDevelop::IDebugSession::PausedState) { 0128 Callback<BreakpointController>* cb = 0129 new Callback<BreakpointController>(this, &BreakpointController::handleBreakpointList); 0130 debugSession()->connection()->sendCommand("breakpoint_list", QStringList(), QByteArray(), cb); 0131 } 0132 } 0133 0134 void BreakpointController::handleBreakpointList(const QDomDocument& xml) 0135 { 0136 Q_ASSERT(xml.firstChildElement().attribute("command") == "breakpoint_list"); 0137 0138 QDomElement el = xml.documentElement().firstChildElement("breakpoint"); 0139 while (!el.isNull()) { 0140 // the breakpoint may have been removed in the meantime, if so, ignore it 0141 if (auto* b = m_ids.key(el.attribute("id"))) { 0142 setHitCount(b, el.attribute("hit_count").toInt()); 0143 } 0144 el = el.nextSiblingElement("breakpoint"); 0145 } 0146 } 0147 }