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"