OSDN Git Service

Debugger/various plugins: Fix memory leaks.
[qt-creator-jp/qt-creator-jp.git] / src / plugins / debugger / debuggeragents.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** Commercial Usage
10 **
11 ** Licensees holding valid Qt Commercial licenses may use this file in
12 ** accordance with the Qt Commercial License Agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and Nokia.
15 **
16 ** GNU Lesser General Public License Usage
17 **
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** If you are unsure which license is appropriate for your use, please
26 ** contact the sales department at http://qt.nokia.com/contact.
27 **
28 **************************************************************************/
29
30 #include "debuggeragents.h"
31 #include "debuggerstringutils.h"
32 #include "idebuggerengine.h"
33
34 #include <coreplugin/coreconstants.h>
35 #include <coreplugin/editormanager/editormanager.h>
36 #include <coreplugin/editormanager/ieditor.h>
37 #include <coreplugin/icore.h>
38
39 #include <texteditor/basetexteditor.h>
40 #include <texteditor/basetextmark.h>
41 #include <texteditor/itexteditor.h>
42 #include <texteditor/texteditorconstants.h>
43
44 #include <utils/qtcassert.h>
45
46 #include <QtCore/QDebug>
47 #include <QtGui/QPlainTextEdit>
48 #include <QtGui/QTextCursor>
49 #include <QtGui/QSyntaxHighlighter>
50
51 #include <limits.h>
52
53 namespace Debugger {
54 namespace Internal {
55
56 ///////////////////////////////////////////////////////////////////////
57 //
58 // MemoryViewAgent
59 //
60 ///////////////////////////////////////////////////////////////////////
61
62 /*!
63     \class MemoryViewAgent
64
65     Objects form this class are created in response to user actions in
66     the Gui for showing raw memory from the inferior. After creation
67     it handles communication between the engine and the bineditor.
68 */
69
70 MemoryViewAgent::MemoryViewAgent(DebuggerManager *manager, quint64 addr)
71     : QObject(manager), m_engine(manager->currentEngine())
72 {
73     init(addr);
74 }
75
76 MemoryViewAgent::MemoryViewAgent(DebuggerManager *manager, const QString &addr)
77     : QObject(manager), m_engine(manager->currentEngine())
78 {
79     bool ok = true;
80     init(addr.toULongLong(&ok, 0));
81     //qDebug() <<  " ADDRESS: " << addr <<  addr.toUInt(&ok, 0);
82 }
83
84 MemoryViewAgent::~MemoryViewAgent()
85 {
86     if (m_editor)
87         m_editor->deleteLater();
88 }
89
90 void MemoryViewAgent::init(quint64 addr)
91 {
92     Core::EditorManager *editorManager = Core::EditorManager::instance();
93     QString titlePattern = tr("Memory $");
94     m_editor = editorManager->openEditorWithContents(
95         Core::Constants::K_DEFAULT_BINARY_EDITOR,
96         &titlePattern);
97     connect(m_editor->widget(), SIGNAL(lazyDataRequested(quint64,bool)),
98         this, SLOT(fetchLazyData(quint64,bool)));
99     editorManager->activateEditor(m_editor);
100     QMetaObject::invokeMethod(m_editor->widget(), "setLazyData",
101         Q_ARG(quint64, addr), Q_ARG(int, 1024 * 1024), Q_ARG(int, BinBlockSize));
102 }
103
104 void MemoryViewAgent::fetchLazyData(quint64 block, bool sync)
105 {
106     Q_UNUSED(sync); // FIXME: needed support for incremental searching
107     if (m_engine)
108         m_engine->fetchMemory(this, BinBlockSize * block, BinBlockSize);
109 }
110
111 void MemoryViewAgent::addLazyData(quint64 addr, const QByteArray &ba)
112 {
113     if (m_editor && m_editor->widget())
114         QMetaObject::invokeMethod(m_editor->widget(), "addLazyData",
115             Q_ARG(quint64, addr / BinBlockSize), Q_ARG(QByteArray, ba));
116 }
117
118
119 ///////////////////////////////////////////////////////////////////////
120 //
121 // DisassemblerViewAgent
122 //
123 ///////////////////////////////////////////////////////////////////////
124
125 static QIcon locationMarkIcon()
126 {
127     static const QIcon icon(":/debugger/images/location.svg");
128     return icon;
129 }
130
131 // Used for the disassembler view
132 class LocationMark2 : public TextEditor::ITextMark
133 {
134 public:
135     LocationMark2() {}
136
137     QIcon icon() const { return locationMarkIcon(); }
138     void updateLineNumber(int /*lineNumber*/) {}
139     void updateBlock(const QTextBlock & /*block*/) {}
140     void removedFromEditor() {}
141     void documentClosing() {}
142 };
143
144 struct DisassemblerViewAgentPrivate
145 {
146     QPointer<TextEditor::ITextEditor> editor;
147     StackFrame frame;
148     QPointer<DebuggerManager> manager;
149     LocationMark2 *locationMark;
150     QHash<QString, QString> cache;
151 };
152
153 /*!
154     \class DisassemblerSyntaxHighlighter
155
156      Simple syntax highlighter to make the disassembler text less prominent.
157 */
158
159 class DisassemblerHighlighter : public QSyntaxHighlighter
160 {
161 public:
162     DisassemblerHighlighter(QPlainTextEdit *parent)
163         : QSyntaxHighlighter(parent->document())
164     {}
165
166 private:
167     void highlightBlock(const QString &text)
168     {
169         if (!text.isEmpty() && text.at(0) != ' ') {
170             QTextCharFormat format;
171             format.setForeground(QColor(128, 128, 128));
172             setFormat(0, text.size(), format);
173         }
174     }
175 };
176
177 /*!
178     \class DisassemblerViewAgent
179
180      Objects from this class are created in response to user actions in
181      the Gui for showing disassembled memory from the inferior. After creation
182      it handles communication between the engine and the editor.
183 */
184
185 DisassemblerViewAgent::DisassemblerViewAgent(DebuggerManager *manager)
186     : QObject(0), d(new DisassemblerViewAgentPrivate)
187 {
188     d->editor = 0;
189     d->locationMark = new LocationMark2();
190     d->manager = manager;
191 }
192
193 DisassemblerViewAgent::~DisassemblerViewAgent()
194 {
195     if (d->editor)
196         d->editor->deleteLater();
197     d->editor = 0;
198     delete d->locationMark;
199     d->locationMark = 0;
200     delete d;
201     d = 0;
202 }
203
204 void DisassemblerViewAgent::cleanup()
205 {
206     d->cache.clear();
207     //if (d->editor)
208     //    d->editor->deleteLater();
209     //d->editor = 0;
210 }
211
212 void DisassemblerViewAgent::resetLocation()
213 {
214     if (d->editor)
215         d->editor->markableInterface()->removeMark(d->locationMark);
216 }
217
218 QString frameKey(const StackFrame &frame)
219 {
220     return _("%1:%2:%3").arg(frame.function).arg(frame.file).arg(frame.from);
221 }
222
223 void DisassemblerViewAgent::setFrame(const StackFrame &frame)
224 {
225     d->frame = frame;
226     if (!frame.function.isEmpty() && frame.function != _("??")) {
227         QHash<QString, QString>::ConstIterator it = d->cache.find(frameKey(frame));
228         if (it != d->cache.end()) {
229             QString msg = _("Use cache dissassembler for '%1' in '%2'")
230                 .arg(frame.function).arg(frame.file);
231             d->manager->showDebuggerOutput(msg);
232             setContents(*it);
233             return;
234         }
235     } 
236     IDebuggerEngine *engine = d->manager->currentEngine();
237     QTC_ASSERT(engine, return);
238     engine->fetchDisassembler(this, frame);
239 }
240
241 void DisassemblerViewAgent::setContents(const QString &contents)
242 {
243     QTC_ASSERT(d, return);
244     using namespace Core;
245     using namespace TextEditor;
246
247     d->cache.insert(frameKey(d->frame), contents);
248     QPlainTextEdit *plainTextEdit = 0;
249     EditorManager *editorManager = EditorManager::instance();
250     if (!d->editor) {
251         QString titlePattern = "Disassembler";
252         d->editor = qobject_cast<ITextEditor *>(
253             editorManager->openEditorWithContents(
254                 Core::Constants::K_DEFAULT_TEXT_EDITOR,
255                 &titlePattern));
256         QTC_ASSERT(d->editor, return);
257         if ((plainTextEdit = qobject_cast<QPlainTextEdit *>(d->editor->widget())))
258             (void) new DisassemblerHighlighter(plainTextEdit);
259     }
260
261     editorManager->activateEditor(d->editor);
262
263     plainTextEdit = qobject_cast<QPlainTextEdit *>(d->editor->widget());
264     if (plainTextEdit)
265         plainTextEdit->setPlainText(contents);
266
267     d->editor->markableInterface()->removeMark(d->locationMark);
268     d->editor->setDisplayName(_("Disassembler (%1)").arg(d->frame.function));
269
270     for (int pos = 0, line = 0; ; ++line, ++pos) {
271         if (contents.midRef(pos, d->frame.address.size()) == d->frame.address) {
272             d->editor->markableInterface()->addMark(d->locationMark, line + 1);
273             if (plainTextEdit) {
274                 QTextCursor tc = plainTextEdit->textCursor();
275                 tc.setPosition(pos);
276                 plainTextEdit->setTextCursor(tc);
277             }
278             break;
279         }
280         pos = contents.indexOf('\n', pos + 1);
281         if (pos == -1)
282             break;
283     }
284 }
285
286 bool DisassemblerViewAgent::contentsCoversAddress(const QString &contents) const
287 {
288     QTC_ASSERT(d, return false);
289     for (int pos = 0, line = 0; ; ++line, ++pos) { 
290         if (contents.midRef(pos, d->frame.address.size()) == d->frame.address)
291             return true;
292         pos = contents.indexOf('\n', pos + 1);
293         if (pos == -1)
294             break;
295     }
296     return false;
297 }
298
299 QString DisassemblerViewAgent::address() const
300 {
301     return d->frame.address;
302 }
303
304 } // namespace Internal
305 } // namespace Debugger