| 1 | // SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. |
| 2 | // |
| 3 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 4 | |
| 5 | #include "debugmodel.h" |
| 6 | #include "debug.h" |
| 7 | #include "debuggerglobals.h" |
| 8 | |
| 9 | #include <QUuid> |
| 10 | #include <QString> |
| 11 | |
| 12 | #include "stdlib.h" |
| 13 | |
| 14 | namespace DEBUG_NAMESPACE { |
| 15 | DebugModel::DebugModel(dap::optional<dap::array<DebugSession *>> _sessions, QObject *parent) |
| 16 | : QObject(parent) |
| 17 | { |
| 18 | if (_sessions) { |
| 19 | auto sessionArray = _sessions.value(); |
| 20 | sessions.insert(sessions.end(), sessionArray.begin(), sessionArray.end()); |
| 21 | } |
| 22 | } |
| 23 | |
| 24 | dap::array<DebugSession *> DebugModel::getSessions(bool includeInactive) |
| 25 | { |
| 26 | dap::array<DebugSession *> ret; |
| 27 | |
| 28 | std::copy_if(sessions.begin(), sessions.end(), std::back_inserter(ret), [&](const DebugSession *item){ |
| 29 | return (includeInactive || item->state != State::kInactive); |
| 30 | }); |
| 31 | |
| 32 | return ret; |
| 33 | } |
| 34 | |
| 35 | dap::optional<DebugSession *> DebugModel::getSession(dap::optional<dap::string> sessionId, bool includeInactive) |
| 36 | { |
| 37 | if (sessionId) { |
| 38 | auto filteredSessions = getSessions(includeInactive); |
| 39 | for (auto s : filteredSessions) { |
| 40 | if (s->getId() == sessionId.value()) { |
| 41 | return s; |
| 42 | } |
| 43 | } |
| 44 | } |
| 45 | return undefined; |
| 46 | } |
| 47 | |
| 48 | void DebugModel::addSession(DebugSession *session) |
| 49 | { |
| 50 | Q_ASSERT(session); |
| 51 | dap::array<DebugSession *> filterdSessions; |
| 52 | for (auto s = sessions.begin(); s != sessions.end();) { |
| 53 | if ((*s)->getId() == session->getId()) { |
| 54 | s = sessions.erase(s); |
| 55 | return; |
| 56 | } |
| 57 | if ((*s)->state == State::kInactive && (*s)->configuration->name == session->configuration->name) { |
| 58 | s = sessions.erase(s); |
| 59 | return; |
| 60 | } |
| 61 | ++s; |
| 62 | } |
| 63 | int i = 1; |
| 64 | char szBuf[10] = { 0 }; |
| 65 | for (auto s = sessions.begin(); s != sessions.end(); ++s) { |
| 66 | while ((*s)->getLabel() == session->getLabel()) { |
| 67 | sprintf(szBuf, "%d" , i); |
| 68 | auto newName = session->configuration->name + szBuf; |
| 69 | session->setName(newName); |
| 70 | memset(szBuf, 0, sizeof(szBuf)); |
| 71 | } |
| 72 | } |
| 73 | |
| 74 | sessions.push_back(session); |
| 75 | } |
| 76 | |
| 77 | void DebugModel::clear() |
| 78 | { |
| 79 | sessions.clear(); |
| 80 | } |
| 81 | |
| 82 | void DebugModel::rawUpdate(IRawModelUpdate *data) |
| 83 | { |
| 84 | for (auto it : sessions) { |
| 85 | if (it->getId() == data->sessionId) { |
| 86 | it->rawUpdate(data); |
| 87 | // fire event. |
| 88 | } |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | void DebugModel::fetchCallStack(Thread &thread) |
| 93 | { |
| 94 | // fetch whole threads. |
| 95 | thread.fetchCallStack(); |
| 96 | } |
| 97 | |
| 98 | IBreakpoint convertToIBreakpoint(Breakpoint &bp) |
| 99 | { |
| 100 | IBreakpoint ibp; |
| 101 | ibp.condition = bp.condition; |
| 102 | ibp.hitCondition = bp.hitCondition; |
| 103 | ibp.logMessage = bp.logMessage; |
| 104 | ibp.verified = bp.verified(); |
| 105 | ibp.support = bp.supported(); |
| 106 | ibp.message = bp.message(); |
| 107 | ibp.sessionsThatVerified = bp.sessionsThatVerified(); |
| 108 | |
| 109 | ibp.uri = bp.uri(); |
| 110 | ibp.lineNumber = bp.lineNumber(); |
| 111 | ibp.endLineNumber = bp.endLineNumber(); |
| 112 | ibp.column = bp.column(); |
| 113 | ibp.endColumn = bp.endColumn(); |
| 114 | ibp.adapterData = bp.adapterData(); |
| 115 | |
| 116 | return ibp; |
| 117 | } |
| 118 | |
| 119 | dap::array<IBreakpoint> DebugModel::getBreakpoints(dap::optional<QUrl> url, dap::optional<int> lineNumber, dap::optional<int> column, dap::optional<bool> enabledOnly) |
| 120 | { |
| 121 | dap::array<IBreakpoint> ret; |
| 122 | dap::string uriStr = url ? url->toString().toStdString() : "" ; |
| 123 | for (auto it : breakPoints) { |
| 124 | if ((url && it.uri().toString().toStdString() != uriStr) |
| 125 | || (lineNumber && lineNumber.value() != it.lineNumber()) |
| 126 | || (enabledOnly && (!breakpointsActivated || enabledOnly.value() != it.enabled))) { |
| 127 | continue; |
| 128 | } |
| 129 | auto ibp = convertToIBreakpoint(it); |
| 130 | ret.push_back(ibp); |
| 131 | } |
| 132 | return ret; |
| 133 | } |
| 134 | |
| 135 | QMap<QString, dap::array<IBreakpoint>> DebugModel::getAllBreakpoints() |
| 136 | { |
| 137 | QMap<QString, dap::array<IBreakpoint>> allBreakpoints; |
| 138 | for (auto it : breakPoints) { |
| 139 | auto ibp = convertToIBreakpoint(it); |
| 140 | QString path = ibp.uri.path(); |
| 141 | if (allBreakpoints.contains(path)) { |
| 142 | allBreakpoints[path].push_back(ibp); |
| 143 | } else { |
| 144 | allBreakpoints.insert(path, {ibp}); |
| 145 | } |
| 146 | } |
| 147 | return allBreakpoints; |
| 148 | } |
| 149 | |
| 150 | bool DebugModel::areBreakpointsActivated() |
| 151 | { |
| 152 | return breakpointsActivated; |
| 153 | } |
| 154 | |
| 155 | dap::array<IFunctionBreakpoint> DebugModel::getFunctionBreakpoints() |
| 156 | { |
| 157 | return functionBreakpoints; |
| 158 | } |
| 159 | |
| 160 | dap::array<IDataBreakpoint> DebugModel::getDataBreakpoints() |
| 161 | { |
| 162 | return dataBreakpoints; |
| 163 | } |
| 164 | |
| 165 | dap::array<IExceptionBreakpoint> DebugModel::getExceptionBreakpoints() |
| 166 | { |
| 167 | return exceptionBreakpoints; |
| 168 | } |
| 169 | |
| 170 | dap::array<IInstructionBreakpoint> DebugModel::getInstructionBreakpoints() |
| 171 | { |
| 172 | return instructionBreakpoints; |
| 173 | } |
| 174 | |
| 175 | dap::array<IBreakpoint> DebugModel::addBreakpoints( |
| 176 | QUrl &uri, dap::array<IBreakpointData> &rawData, bool fireEvent) |
| 177 | { |
| 178 | Q_UNUSED(uri) |
| 179 | Q_UNUSED(fireEvent) |
| 180 | |
| 181 | dap::array<IBreakpoint> retBreakpoints; |
| 182 | for (auto rawBp : rawData) { |
| 183 | Breakpoint bp(uri, rawBp.lineNumber.value(), rawBp.column, rawBp.enabled, |
| 184 | rawBp.condition, rawBp.hitCondition, rawBp.logMessage, undefined, rawBp.id.value()); |
| 185 | auto ibp = convertToIBreakpoint(bp); |
| 186 | retBreakpoints.push_back(ibp); |
| 187 | breakPoints.push_back(bp); |
| 188 | } |
| 189 | |
| 190 | return retBreakpoints; |
| 191 | } |
| 192 | |
| 193 | dap::array<IBreakpoint> DebugModel::removeBreakpoint(const QString &filePath, int lineNumber) |
| 194 | { |
| 195 | for (auto bp = breakPoints.begin(); bp != breakPoints.end(); ) { |
| 196 | if (bp->lineNumber() == lineNumber |
| 197 | && bp->uri().toString() == filePath) { |
| 198 | bp = breakPoints.erase(bp); |
| 199 | } else { |
| 200 | ++bp; |
| 201 | } |
| 202 | } |
| 203 | |
| 204 | dap::array<IBreakpoint> retBreakpoints; |
| 205 | for (auto bp : breakPoints) { |
| 206 | auto ibp = convertToIBreakpoint(bp); |
| 207 | retBreakpoints.push_back(ibp); |
| 208 | } |
| 209 | return retBreakpoints; |
| 210 | // fire event. |
| 211 | } |
| 212 | |
| 213 | void DebugModel::updateBreakpoints(std::map<dap::string, IBreakpointUpdateData> &data) |
| 214 | { |
| 215 | Q_UNUSED(data) |
| 216 | // dap::array<IBreakpoint> updated; |
| 217 | // for (auto bp : breakPoints) { |
| 218 | // auto bpData = data.find(bp.Enablement::getId()); |
| 219 | // if (bpData != data.end()) { |
| 220 | // bp.update(bpData->second); |
| 221 | // updated.push_back(bp); |
| 222 | // } |
| 223 | // } |
| 224 | } |
| 225 | |
| 226 | IBreakpointSessionData toBreakpointSessionData(dap::Breakpoint &data, dap::Capabilities &capabilities) |
| 227 | { |
| 228 | Q_UNUSED(data) |
| 229 | Q_UNUSED(capabilities) |
| 230 | return {}; |
| 231 | } |
| 232 | |
| 233 | void DebugModel::setBreakpointSessionData(dap::string &sessionId, const dap::Capabilities &capabilites, dap::optional<std::map<dap::string, dap::Breakpoint>> data) |
| 234 | { |
| 235 | for (auto bp : breakPoints) { |
| 236 | if (!data) { |
| 237 | bp.setSessionData(sessionId, undefined); |
| 238 | } else { |
| 239 | auto bpData = data.value().find(bp.getId()); |
| 240 | if (bpData != data->end()) { |
| 241 | // TODO(mozart):write session data. |
| 242 | bp.setSessionData(sessionId, undefined); |
| 243 | } |
| 244 | } |
| 245 | } |
| 246 | } |
| 247 | |
| 248 | dap::optional<dap::Breakpoint> DebugModel::getDebugProtocolBreakpoint( |
| 249 | dap::string &breakpointId, dap::string &sessionId) |
| 250 | { |
| 251 | for (auto bp : breakPoints) { |
| 252 | if (bp.getId() == breakpointId) { |
| 253 | return bp.getDebugProtocolBreakpoint(sessionId); |
| 254 | } |
| 255 | } |
| 256 | return undefined; |
| 257 | } |
| 258 | |
| 259 | void DebugModel::enableOrDisableAllBreakpoints(bool enable) |
| 260 | { |
| 261 | for (auto bp : breakPoints) { |
| 262 | bp.enabled = enable; |
| 263 | } |
| 264 | } |
| 265 | |
| 266 | void DebugModel::setBreakpointsActivated(bool activated) |
| 267 | { |
| 268 | breakpointsActivated = activated; |
| 269 | // fire event. |
| 270 | } |
| 271 | } // end namespace. |
| 272 | |