File indexing completed on 2024-04-28 04:38:35
0001 /* 0002 SPDX-FileCopyrightText: 2009 Vladimir Prus <ghost@cs.msu.su> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "miframestackmodel.h" 0008 0009 #include "midebugsession.h" 0010 #include "mi/micommand.h" 0011 0012 #include <KLocalizedString> 0013 0014 #include <algorithm> 0015 0016 using namespace KDevelop; 0017 using namespace KDevMI; 0018 using namespace KDevMI::MI; 0019 0020 QString getFunctionOrAddress(const Value &frame) 0021 { 0022 if (frame.hasField(QStringLiteral("func"))) 0023 return frame[QStringLiteral("func")].literal(); 0024 else 0025 return frame[QStringLiteral("addr")].literal(); 0026 } 0027 0028 QPair<QString, int> getSource(const Value &frame) 0029 { 0030 QPair<QString, int> ret(QString(), -1); 0031 if (frame.hasField(QStringLiteral("fullname"))) 0032 ret=qMakePair(frame[QStringLiteral("fullname")].literal(), frame[QStringLiteral("line")].toInt()-1); 0033 else if (frame.hasField(QStringLiteral("file"))) 0034 ret=qMakePair(frame[QStringLiteral("file")].literal(), frame[QStringLiteral("line")].toInt()-1); 0035 else if (frame.hasField(QStringLiteral("from"))) 0036 ret.first=frame[QStringLiteral("from")].literal(); 0037 0038 return ret; 0039 } 0040 0041 MIFrameStackModel::MIFrameStackModel(MIDebugSession * session) 0042 : FrameStackModel(session) 0043 { 0044 } 0045 0046 MIDebugSession * MIFrameStackModel::session() 0047 { 0048 return static_cast<MIDebugSession *>(FrameStackModel::session()); 0049 } 0050 0051 void MIFrameStackModel::fetchThreads() 0052 { 0053 session()->addCommand(ThreadInfo, QString(), this, &MIFrameStackModel::handleThreadInfo); 0054 } 0055 0056 void MIFrameStackModel::handleThreadInfo(const ResultRecord& r) 0057 { 0058 const Value& threads = r[QStringLiteral("threads")]; 0059 0060 QVector<FrameStackModel::ThreadItem> threadsList; 0061 threadsList.reserve(threads.size()); 0062 for (int i = 0; i!= threads.size(); ++i) { 0063 const auto &threadMI = threads[i]; 0064 FrameStackModel::ThreadItem threadItem; 0065 threadItem.nr = threadMI[QStringLiteral("id")].toInt(); 0066 if (threadMI[QStringLiteral("state")].literal() == QLatin1String("stopped")) { 0067 threadItem.name = getFunctionOrAddress(threadMI[QStringLiteral("frame")]); 0068 } else { 0069 threadItem.name = i18n("(running)"); 0070 } 0071 threadsList << threadItem; 0072 } 0073 // Sort the list by id, some old version of GDB 0074 // reports them in backward order. We want UI to 0075 // show thread IDs in the natural order. 0076 std::sort(threadsList.begin(), threadsList.end(), 0077 [](const FrameStackModel::ThreadItem &a, const FrameStackModel::ThreadItem &b){ 0078 return a.nr < b.nr; 0079 }); 0080 0081 setThreads(threadsList); 0082 if (r.hasField(QStringLiteral("current-thread-id"))) { 0083 int currentThreadId = r[QStringLiteral("current-thread-id")].toInt(); 0084 0085 setCurrentThread(currentThreadId); 0086 0087 if (session()->hasCrashed()) { 0088 setCrashedThreadIndex(currentThreadId); 0089 } 0090 } 0091 } 0092 0093 struct FrameListHandler : public MICommandHandler 0094 { 0095 FrameListHandler(MIFrameStackModel* model, int thread, int to) 0096 : model(model), m_thread(thread) , m_to(to) {} 0097 0098 void handle(const ResultRecord &r) override 0099 { 0100 const Value& stack = r[QStringLiteral("stack")]; 0101 int first = stack[0][QStringLiteral("level")].toInt(); 0102 QVector<KDevelop::FrameStackModel::FrameItem> frames; 0103 frames.reserve(stack.size()); 0104 for (int i = 0; i< stack.size(); ++i) { 0105 const Value& frame = stack[i]; 0106 KDevelop::FrameStackModel::FrameItem f; 0107 f.nr = frame[QStringLiteral("level")].toInt(); 0108 f.name = getFunctionOrAddress(frame); 0109 QPair<QString, int> loc = getSource(frame); 0110 f.file = QUrl::fromLocalFile(loc.first).adjusted(QUrl::NormalizePathSegments); 0111 f.line = loc.second; 0112 frames << f; 0113 } 0114 bool hasMore = false; 0115 if (!frames.isEmpty()) { 0116 if (frames.last().nr == m_to+1) { 0117 frames.removeLast(); 0118 hasMore = true; 0119 } 0120 } 0121 if (first == 0) { 0122 model->setFrames(m_thread, frames); 0123 } else { 0124 model->insertFrames(m_thread, frames); 0125 } 0126 model->setHasMoreFrames(m_thread, hasMore); 0127 } 0128 private: 0129 MIFrameStackModel* model; 0130 int m_thread; 0131 int m_to; 0132 }; 0133 0134 void MIFrameStackModel::fetchFrames(int threadNumber, int from, int to) 0135 { 0136 //to+1 so we know if there are more 0137 QString arg = QStringLiteral("%1 %2").arg(from).arg(to+1); 0138 auto c = session()->createCommand(StackListFrames, arg); 0139 c->setHandler(new FrameListHandler(this, threadNumber, to)); 0140 c->setThread(threadNumber); 0141 session()->addCommand(std::move(c)); 0142 } 0143 0144 #include "moc_miframestackmodel.cpp"