File indexing completed on 2024-05-12 04:40:07

0001 /*
0002     SPDX-FileCopyrightText: 2016 Aetf <aetf@unlimitedcodeworks.xyz>
0003 
0004     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005 */
0006 
0007 #include "framestackmodel.h"
0008 
0009 #include "debuglog.h"
0010 #include "debugsession.h"
0011 #include "mi/micommand.h"
0012 
0013 #include <KLocalizedString>
0014 
0015 namespace {
0016 
0017 QString getFunctionOrAddress(const KDevMI::MI::Value &frame)
0018 {
0019     if (frame.hasField(QStringLiteral("func")))
0020         return frame[QStringLiteral("func")].literal();
0021     else
0022         return frame[QStringLiteral("addr")].literal();
0023 }
0024 
0025 }
0026 
0027 using namespace KDevMI::LLDB;
0028 using namespace KDevMI::MI;
0029 using namespace KDevMI;
0030 
0031 LldbFrameStackModel::LldbFrameStackModel(DebugSession *session)
0032     : MIFrameStackModel(session)
0033     , stoppedAtThread(-1)
0034 {
0035     connect(session, &DebugSession::inferiorStopped, this, &LldbFrameStackModel::inferiorStopped);
0036 }
0037 
0038 DebugSession* LldbFrameStackModel::session()
0039 {
0040     return static_cast<DebugSession *>(FrameStackModel::session());
0041 }
0042 
0043 void LldbFrameStackModel::inferiorStopped(const MI::AsyncRecord& r)
0044 {
0045     if (session()->debuggerStateIsOn(s_shuttingDown)) return;
0046 
0047     if (r.hasField(QStringLiteral("thread-id"))) {
0048         stoppedAtThread = r[QStringLiteral("thread-id")].toInt();
0049     }
0050 }
0051 
0052 void LldbFrameStackModel::fetchThreads()
0053 {
0054     // TODO: preliminary test shows there might be a bug in lldb-mi
0055     // that's causing std::logic_error when executing -thread-info with
0056     // more than one threads. Find a workaround for this (and report bug
0057     // if it truly is).
0058     session()->addCommand(ThreadInfo, QString(), this, &LldbFrameStackModel::handleThreadInfo);
0059 }
0060 
0061 void LldbFrameStackModel::handleThreadInfo(const ResultRecord& r)
0062 {
0063     const Value& threads = r[QStringLiteral("threads")];
0064 
0065     QVector<FrameStackModel::ThreadItem> threadsList;
0066     threadsList.reserve(threads.size());
0067     for (int gidx = 0; gidx != threads.size(); ++gidx) {
0068         FrameStackModel::ThreadItem i;
0069         const Value & threadMI = threads[gidx];
0070         i.nr = threadMI[QStringLiteral("id")].toInt();
0071         if (threadMI[QStringLiteral("state")].literal() == QLatin1String("stopped")) {
0072             // lldb-mi returns multiple frame entry for each thread
0073             // so can't directly use threadMI["frame"]
0074             auto &th = static_cast<const TupleValue&>(threadMI);
0075             Value *topFrame = nullptr;
0076             for (auto res : th.results) {
0077                 if (res->variable == QLatin1String("frame")) {
0078                     if (!topFrame || (*res->value)[QStringLiteral("level")].toInt() < (*topFrame)[QStringLiteral("level")].toInt()) {
0079                         topFrame = res->value;
0080                     }
0081                 }
0082             }
0083             i.name = getFunctionOrAddress(*topFrame);
0084         } else {
0085             i.name = i18n("(running)");
0086         }
0087         threadsList << i;
0088     }
0089     setThreads(threadsList);
0090     if (r.hasField(QStringLiteral("current-thread-id"))) {
0091         int currentThreadId = r[QStringLiteral("current-thread-id")].toInt();
0092 
0093         setCurrentThread(currentThreadId);
0094 
0095         if (session()->hasCrashed()) {
0096             setCrashedThreadIndex(currentThreadId);
0097         }
0098     }
0099     // lldb-mi doesn't have current-thread-id field. Use the thread-id field when inferiorStopped
0100     if (stoppedAtThread != -1) {
0101         setCurrentThread(stoppedAtThread);
0102     }
0103     stoppedAtThread = -1;
0104 }
0105 
0106 #include "moc_framestackmodel.cpp"