Changeset View
Changeset View
Standalone View
Standalone View
debuggers/common/miframestackmodel.cpp
- This file was copied from debuggers/gdb/gdbframestackmodel.cpp.
1 | /* | 1 | /* | ||
---|---|---|---|---|---|
2 | * GDB-specific implementation of thread and frame model. | 2 | * Implementation of thread and frame model that are common to debuggers using MI. | ||
3 | * | 3 | * | ||
4 | * Copyright 2009 Vladimir Prus <ghost@cs.msu.su> | 4 | * Copyright 2009 Vladimir Prus <ghost@cs.msu.su> | ||
5 | * | 5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as | 7 | * it under the terms of the GNU General Public License as | ||
8 | * published by the Free Software Foundation; either version 2 of the | 8 | * published by the Free Software Foundation; either version 2 of the | ||
9 | * License, or (at your option) any later version. | 9 | * License, or (at your option) any later version. | ||
10 | * | 10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | 11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | 14 | * GNU General Public License for more details. | ||
15 | * | 15 | * | ||
16 | * You should have received a copy of the GNU General Public | 16 | * You should have received a copy of the GNU General Public | ||
17 | * License along with this program; if not, write to the | 17 | * License along with this program; if not, write to the | ||
18 | * Free Software Foundation, Inc., | 18 | * Free Software Foundation, Inc., | ||
19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
20 | */ | 20 | */ | ||
21 | 21 | | |||
22 | #include "gdbframestackmodel.h" | 22 | #include "miframestackmodel.h" | ||
23 | #include "gdbcommand.h" | 23 | | ||
24 | #include "midebugsession.h" | ||||
25 | #include "mi/micommand.h" | ||||
24 | 26 | | |||
25 | #include <KLocalizedString> | 27 | #include <KLocalizedString> | ||
26 | 28 | | |||
27 | using namespace KDevelop; | 29 | using namespace KDevelop; | ||
30 | using namespace KDevMI; | ||||
31 | using namespace KDevMI::MI; | ||||
28 | 32 | | |||
29 | QString getFunctionOrAddress(const GDBMI::Value &frame) | 33 | QString getFunctionOrAddress(const Value &frame) | ||
30 | { | 34 | { | ||
31 | if (frame.hasField("func")) | 35 | if (frame.hasField("func")) | ||
32 | return frame["func"].literal(); | 36 | return frame["func"].literal(); | ||
33 | else | 37 | else | ||
34 | return frame["addr"].literal(); | 38 | return frame["addr"].literal(); | ||
35 | } | 39 | } | ||
36 | 40 | | |||
37 | QPair<QString, int> getSource(const GDBMI::Value &frame) | 41 | QPair<QString, int> getSource(const Value &frame) | ||
38 | { | 42 | { | ||
39 | QPair<QString, int> ret(QString(), -1); | 43 | QPair<QString, int> ret(QString(), -1); | ||
40 | if (frame.hasField("fullname")) | 44 | if (frame.hasField("fullname")) | ||
41 | ret=qMakePair(frame["fullname"].literal(), frame["line"].toInt()-1); | 45 | ret=qMakePair(frame["fullname"].literal(), frame["line"].toInt()-1); | ||
42 | else if (frame.hasField("file")) | 46 | else if (frame.hasField("file")) | ||
43 | ret=qMakePair(frame["file"].literal(), frame["line"].toInt()-1); | 47 | ret=qMakePair(frame["file"].literal(), frame["line"].toInt()-1); | ||
44 | else if (frame.hasField("from")) | 48 | else if (frame.hasField("from")) | ||
45 | ret.first=frame["from"].literal(); | 49 | ret.first=frame["from"].literal(); | ||
46 | 50 | | |||
47 | return ret; | 51 | return ret; | ||
48 | } | 52 | } | ||
49 | 53 | | |||
50 | void GdbFrameStackModel::fetchThreads() | 54 | MIFrameStackModel::MIFrameStackModel(MIDebugSession * session) | ||
55 | : FrameStackModel(session) | ||||
56 | { | ||||
57 | } | ||||
58 | | ||||
59 | MIDebugSession * MIFrameStackModel::session() | ||||
60 | { | ||||
61 | return static_cast<MIDebugSession *>(FrameStackModel::session()); | ||||
62 | } | ||||
63 | | ||||
64 | void MIFrameStackModel::fetchThreads() | ||||
51 | { | 65 | { | ||
66 | // TODO: preliminary test shows there might be a bug in lldb-mi | ||||
67 | // that's causing std::logic_error when executing -thread-info with | ||||
68 | // more than one threads. Find a workaround for this (and report bug | ||||
69 | // if it truely is). | ||||
52 | session()->addCommand( | 70 | session()->addCommand( | ||
53 | new GDBCommand(GDBMI::ThreadInfo, "", | 71 | new MICommand(ThreadInfo, "", | ||
54 | this, | 72 | this, &MIFrameStackModel::handleThreadInfo)); | ||
55 | &GdbFrameStackModel::handleThreadInfo)); | | |||
56 | } | 73 | } | ||
57 | 74 | | |||
58 | void GdbFrameStackModel::handleThreadInfo(const GDBMI::ResultRecord& r) | 75 | void MIFrameStackModel::handleThreadInfo(const ResultRecord& r) | ||
59 | { | 76 | { | ||
60 | const GDBMI::Value& threads = r["threads"]; | 77 | const Value& threads = r["threads"]; | ||
61 | 78 | | |||
62 | // Traverse GDB threads in backward order -- since GDB | 79 | // Traverse GDB threads in backward order -- since GDB | ||
63 | // reports them in backward order. We want UI to | 80 | // reports them in backward order. We want UI to | ||
64 | // show thread IDs in the natural order. | 81 | // show thread IDs in the natural order. | ||
65 | // FIXME: make the code independent of whatever craziness | 82 | // FIXME: at least GDB 7.11 is reporting in the right order, | ||
66 | // gdb might have tomorrow. | 83 | // consider sort the list afterwards. | ||
67 | 84 | | |||
68 | QList<KDevelop::FrameStackModel::ThreadItem> threadsList; | 85 | QList<KDevelop::FrameStackModel::ThreadItem> threadsList; | ||
69 | int gidx = threads.size()-1; | 86 | int gidx = threads.size()-1; | ||
70 | for (; gidx >= 0; --gidx) { | 87 | for (; gidx >= 0; --gidx) { | ||
71 | KDevelop::FrameStackModel::ThreadItem i; | 88 | KDevelop::FrameStackModel::ThreadItem i; | ||
72 | const GDBMI::Value & threadMI = threads[gidx]; | 89 | const Value & threadMI = threads[gidx]; | ||
73 | i.nr = threadMI["id"].toInt(); | 90 | i.nr = threadMI["id"].toInt(); | ||
74 | if (threadMI["state"].literal() == "stopped") { | 91 | if (threadMI["state"].literal() == "stopped") { | ||
75 | i.name = getFunctionOrAddress(threads[gidx]["frame"]); | 92 | i.name = getFunctionOrAddress(threads[gidx]["frame"]); | ||
76 | } else { | 93 | } else { | ||
77 | i.name = i18n("(running)"); | 94 | i.name = i18n("(running)"); | ||
78 | } | 95 | } | ||
79 | threadsList << i; | 96 | threadsList << i; | ||
80 | } | 97 | } | ||
81 | setThreads(threadsList); | 98 | setThreads(threadsList); | ||
82 | if (r.hasField("current-thread-id")) { | 99 | if (r.hasField("current-thread-id")) { | ||
83 | int currentThreadId = r["current-thread-id"].toInt(); | 100 | int currentThreadId = r["current-thread-id"].toInt(); | ||
84 | 101 | | |||
85 | setCurrentThread(currentThreadId); | 102 | setCurrentThread(currentThreadId); | ||
86 | 103 | | |||
87 | if (session()->hasCrashed()) { | 104 | if (session()->hasCrashed()) { | ||
88 | setCrashedThreadIndex(currentThreadId); | 105 | setCrashedThreadIndex(currentThreadId); | ||
89 | } | 106 | } | ||
90 | } | 107 | } | ||
91 | } | 108 | } | ||
92 | 109 | | |||
93 | struct FrameListHandler : public GDBCommandHandler | 110 | struct FrameListHandler : public MICommandHandler | ||
94 | { | 111 | { | ||
95 | FrameListHandler(GdbFrameStackModel* model, int thread, int to) | 112 | FrameListHandler(MIFrameStackModel* model, int thread, int to) | ||
96 | : model(model), m_thread(thread) , m_to(to) {} | 113 | : model(model), m_thread(thread) , m_to(to) {} | ||
97 | 114 | | |||
98 | void handle(const GDBMI::ResultRecord &r) override | 115 | void handle(const ResultRecord &r) override | ||
99 | { | 116 | { | ||
100 | const GDBMI::Value& stack = r["stack"]; | 117 | const Value& stack = r["stack"]; | ||
101 | int first = stack[0]["level"].toInt(); | 118 | int first = stack[0]["level"].toInt(); | ||
102 | QList<KDevelop::FrameStackModel::FrameItem> frames; | 119 | QList<KDevelop::FrameStackModel::FrameItem> frames; | ||
103 | for (int i = 0; i< stack.size(); ++i) { | 120 | for (int i = 0; i< stack.size(); ++i) { | ||
104 | const GDBMI::Value& frame = stack[i]; | 121 | const Value& frame = stack[i]; | ||
105 | KDevelop::FrameStackModel::FrameItem f; | 122 | KDevelop::FrameStackModel::FrameItem f; | ||
106 | f.nr = frame["level"].toInt(); | 123 | f.nr = frame["level"].toInt(); | ||
107 | f.name = getFunctionOrAddress(frame); | 124 | f.name = getFunctionOrAddress(frame); | ||
108 | QPair<QString, int> loc = getSource(frame); | 125 | QPair<QString, int> loc = getSource(frame); | ||
109 | f.file = QUrl::fromLocalFile(loc.first); | 126 | f.file = QUrl::fromLocalFile(loc.first); | ||
110 | f.line = loc.second; | 127 | f.line = loc.second; | ||
111 | frames << f; | 128 | frames << f; | ||
112 | } | 129 | } | ||
113 | bool hasMore = false; | 130 | bool hasMore = false; | ||
114 | if (!frames.isEmpty()) { | 131 | if (!frames.isEmpty()) { | ||
115 | if (frames.last().nr == m_to+1) { | 132 | if (frames.last().nr == m_to+1) { | ||
116 | frames.takeLast(); | 133 | frames.takeLast(); | ||
117 | hasMore = true; | 134 | hasMore = true; | ||
118 | } | 135 | } | ||
119 | } | 136 | } | ||
120 | if (first == 0) { | 137 | if (first == 0) { | ||
121 | model->setFrames(m_thread, frames); | 138 | model->setFrames(m_thread, frames); | ||
122 | } else { | 139 | } else { | ||
123 | model->insertFrames(m_thread, frames); | 140 | model->insertFrames(m_thread, frames); | ||
124 | } | 141 | } | ||
125 | model->setHasMoreFrames(m_thread, hasMore); | 142 | model->setHasMoreFrames(m_thread, hasMore); | ||
126 | } | 143 | } | ||
127 | private: | 144 | private: | ||
128 | GdbFrameStackModel* model; | 145 | MIFrameStackModel* model; | ||
129 | int m_thread; | 146 | int m_thread; | ||
130 | int m_to; | 147 | int m_to; | ||
131 | }; | 148 | }; | ||
132 | 149 | | |||
133 | void GdbFrameStackModel::fetchFrames(int threadNumber, int from, int to) | 150 | void MIFrameStackModel::fetchFrames(int threadNumber, int from, int to) | ||
134 | { | 151 | { | ||
135 | //to+1 so we know if there are more | 152 | //to+1 so we know if there are more | ||
136 | QString arg = QString("%1 %2").arg(from).arg(to+1); | 153 | QString arg = QString("%1 %2").arg(from).arg(to+1); | ||
137 | GDBCommand *c = new GDBCommand(GDBMI::StackListFrames, arg, | 154 | MICommand *c = new MICommand(StackListFrames, arg, | ||
138 | new FrameListHandler(this, threadNumber, to)); | 155 | new FrameListHandler(this, threadNumber, to)); | ||
139 | c->setThread(threadNumber); | 156 | c->setThread(threadNumber); | ||
140 | session()->addCommand(c); | 157 | session()->addCommand(c); | ||
141 | } | 158 | } |