OSDN Git Service

5b354aa1eaf4181f38137f8121a9f474e32e5ed7
[qt-creator-jp/qt-creator-jp.git] / src / plugins / debugger / disassembleragent.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
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 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include "disassembleragent.h"
35
36 #include "disassemblerlines.h"
37 #include "breakhandler.h"
38 #include "debuggerengine.h"
39 #include "debuggercore.h"
40 #include "debuggerstringutils.h"
41 #include "stackframe.h"
42
43 #include <coreplugin/coreconstants.h>
44 #include <coreplugin/editormanager/ieditor.h>
45 #include <coreplugin/icore.h>
46 #include <coreplugin/mimedatabase.h>
47
48 #include <texteditor/basetextdocument.h>
49 #include <texteditor/basetexteditor.h>
50 #include <texteditor/basetextmark.h>
51 #include <texteditor/plaintexteditor.h>
52 #include <texteditor/texteditorconstants.h>
53
54 #include <utils/qtcassert.h>
55
56 #include <QtGui/QTextBlock>
57 #include <QtGui/QIcon>
58 #include <QtCore/QPointer>
59
60 using namespace Core;
61
62 namespace Debugger {
63 namespace Internal {
64
65 ///////////////////////////////////////////////////////////////////////
66 //
67 // DisassemblerAgent
68 //
69 ///////////////////////////////////////////////////////////////////////
70
71 class LocationMark2 : public TextEditor::ITextMark
72 {
73 public:
74     LocationMark2() {}
75
76     QIcon icon() const { return debuggerCore()->locationMarkIcon(); }
77     void updateLineNumber(int /*lineNumber*/) {}
78     void updateBlock(const QTextBlock & /*block*/) {}
79     void removedFromEditor() {}
80     void documentClosing() {}
81     TextEditor::ITextMark::Priority priority() const
82         { return TextEditor::ITextMark::HighPriority; }
83 };
84
85 class BreakpointMarker2 : public TextEditor::ITextMark
86 {
87 public:
88     BreakpointMarker2(const QIcon &icon) : m_icon(icon) {}
89
90     QIcon icon() const { return m_icon; }
91     void updateLineNumber(int) {}
92     void updateBlock(const QTextBlock &) {}
93     void removedFromEditor() {}
94     void documentClosing() {}
95     TextEditor::ITextMark::Priority priority() const
96         { return TextEditor::ITextMark::NormalPriority; }
97
98 private:
99     QIcon m_icon;
100 };
101
102
103 class DisassemblerAgentPrivate
104 {
105 public:
106     DisassemblerAgentPrivate();
107     ~DisassemblerAgentPrivate();
108     void configureMimeType();
109
110 public:
111     QPointer<TextEditor::ITextEditor> editor;
112     Location location;
113     bool tryMixed;
114     QPointer<DebuggerEngine> engine;
115     TextEditor::ITextMark *locationMark;
116     QList<TextEditor::ITextMark *> breakpointMarks;
117     
118     QHash<QString, DisassemblerLines> cache;
119     QString mimeType;
120     bool m_resetLocationScheduled;
121 };
122
123 DisassemblerAgentPrivate::DisassemblerAgentPrivate()
124   : editor(0),
125     tryMixed(true),
126     locationMark(new LocationMark2),
127     mimeType(_("text/x-qtcreator-generic-asm")),
128     m_resetLocationScheduled(false)
129 {
130 }
131
132 DisassemblerAgentPrivate::~DisassemblerAgentPrivate()
133 {
134     if (editor) {
135         EditorManager *editorManager = EditorManager::instance();
136         editorManager->closeEditors(QList<IEditor *>() << editor);
137     }
138     editor = 0;
139     delete locationMark;
140 }
141
142 /*!
143     \class Debugger::Internal::DisassemblerAgent
144
145      Objects from this class are created in response to user actions in
146      the Gui for showing disassembled memory from the inferior. After creation
147      it handles communication between the engine and the editor.
148 */
149
150 DisassemblerAgent::DisassemblerAgent(DebuggerEngine *engine)
151     : QObject(0), d(new DisassemblerAgentPrivate)
152 {
153     d->engine = engine;
154 }
155
156 DisassemblerAgent::~DisassemblerAgent()
157 {
158     delete d;
159     d = 0;
160 }
161
162 void DisassemblerAgent::cleanup()
163 {
164     d->cache.clear();
165 }
166
167 void DisassemblerAgent::scheduleResetLocation()
168 {
169     d->m_resetLocationScheduled = true;
170 }
171
172 void DisassemblerAgent::resetLocation()
173 {
174     if (!d->editor)
175         return;
176     if (d->m_resetLocationScheduled) {
177         d->m_resetLocationScheduled = false;
178         d->editor->markableInterface()->removeMark(d->locationMark);
179     }
180 }
181
182 static QString frameKey(const Location &loc)
183 {
184     return _("%1:%2:%3").arg(loc.functionName())
185         .arg(loc.fileName()).arg(loc.address());
186 }
187
188 const Location &DisassemblerAgent::location() const
189 {
190     return d->location;
191 }
192
193 bool DisassemblerAgent::isMixed() const
194 {
195     return d->tryMixed
196         && d->location.lineNumber() > 0
197         && !d->location.functionName().isEmpty()
198         && d->location.functionName() != _("??");
199 }
200
201 void DisassemblerAgent::setLocation(const Location &loc)
202 {
203     d->location = loc;
204     if (isMixed()) {
205         QHash<QString, DisassemblerLines>::ConstIterator it =
206             d->cache.find(frameKey(loc));
207         if (it != d->cache.end()) {
208             QString msg = _("Use cache disassembler for '%1' in '%2'")
209                 .arg(loc.functionName()).arg(loc.fileName());
210             d->engine->showMessage(msg);
211             setContents(*it);
212             updateBreakpointMarkers();
213             updateLocationMarker();
214             return;
215         }
216     }
217     d->engine->fetchDisassembler(this);
218 }
219
220 void DisassemblerAgentPrivate::configureMimeType()
221 {
222     QTC_ASSERT(editor, return);
223
224     TextEditor::BaseTextDocument *doc =
225         qobject_cast<TextEditor::BaseTextDocument *>(editor->file());
226     QTC_ASSERT(doc, return);
227     doc->setMimeType(mimeType);
228
229     TextEditor::PlainTextEditorWidget *pe =
230         qobject_cast<TextEditor::PlainTextEditorWidget *>(editor->widget());
231     QTC_ASSERT(pe, return);
232
233     MimeType mtype = ICore::instance()->mimeDatabase()->findByType(mimeType);
234     if (mtype)
235         pe->configure(mtype);
236     else
237         qWarning("Assembler mimetype '%s' not found.", qPrintable(mimeType));
238 }
239
240 QString DisassemblerAgent::mimeType() const
241 {
242     return d->mimeType;
243 }
244
245 void DisassemblerAgent::setMimeType(const QString &mt)
246 {
247     if (mt == d->mimeType)
248         return;
249     d->mimeType = mt;
250     if (d->editor)
251        d->configureMimeType();
252 }
253
254 void DisassemblerAgent::setContents(const DisassemblerLines &contents)
255 {
256     QTC_ASSERT(d, return);
257     using namespace Core;
258     using namespace TextEditor;
259
260     EditorManager *editorManager = EditorManager::instance();
261     if (!d->editor) {
262         QString titlePattern = "Disassembler";
263         d->editor = qobject_cast<ITextEditor *>(
264             editorManager->openEditorWithContents(
265                 Core::Constants::K_DEFAULT_TEXT_EDITOR_ID,
266                 &titlePattern));
267         QTC_ASSERT(d->editor, return);
268         d->editor->setProperty(Debugger::Constants::OPENED_BY_DEBUGGER, true);
269         d->editor->setProperty(Debugger::Constants::OPENED_WITH_DISASSEMBLY, true);
270         d->configureMimeType();
271
272         BaseTextEditorWidget *baseTextEdit =
273                 qobject_cast<BaseTextEditorWidget *>(d->editor->widget());
274         if (baseTextEdit)
275             baseTextEdit->setRequestMarkEnabled(true);
276     }
277
278     editorManager->activateEditor(d->editor);
279
280     QPlainTextEdit *plainTextEdit =
281         qobject_cast<QPlainTextEdit *>(d->editor->widget());
282     QTC_ASSERT(plainTextEdit, return);
283
284     QString str;
285     for (int i = 0, n = contents.size(); i != n; ++i) {
286         const DisassemblerLine &dl = contents.at(i);
287         if (dl.address) {
288             str += QLatin1String("0x");
289             str += QString::number(dl.address, 16);
290             str += QLatin1String("  ");
291         }
292         str += dl.data;
293         str += QLatin1Char('\n');
294     }
295     plainTextEdit->setPlainText(str);
296     plainTextEdit->setReadOnly(true);
297
298     d->cache.insert(frameKey(d->location), contents);
299     d->editor->setDisplayName(_("Disassembler (%1)")
300         .arg(d->location.functionName()));
301
302     updateBreakpointMarkers();
303     updateLocationMarker();
304 }
305
306 void DisassemblerAgent::updateLocationMarker()
307 {
308     QTC_ASSERT(d->editor, return);
309
310     const DisassemblerLines &contents = d->cache.value(frameKey(d->location));
311     int lineNumber = contents.lineForAddress(d->location.address());
312
313     if (d->location.needsMarker()) {
314         d->editor->markableInterface()->removeMark(d->locationMark);
315         if (lineNumber)
316             d->editor->markableInterface()->addMark(d->locationMark, lineNumber);
317     }
318
319     QPlainTextEdit *plainTextEdit =
320         qobject_cast<QPlainTextEdit *>(d->editor->widget());
321     QTC_ASSERT(plainTextEdit, return); 
322     QTextCursor tc = plainTextEdit->textCursor();
323     QTextBlock block = tc.document()->findBlockByNumber(lineNumber - 1);
324     tc.setPosition(block.position());
325     plainTextEdit->setTextCursor(tc);
326 }
327
328 void DisassemblerAgent::updateBreakpointMarkers()
329 {
330     if (!d->editor)
331         return;
332
333     BreakHandler *handler = breakHandler();
334     BreakpointIds ids = handler->engineBreakpointIds(d->engine);
335     if (ids.isEmpty())
336         return;
337
338     const DisassemblerLines &contents = d->cache.value(frameKey(d->location));
339
340     foreach (TextEditor::ITextMark *marker, d->breakpointMarks)
341         d->editor->markableInterface()->removeMark(marker);
342     d->breakpointMarks.clear();
343     foreach (BreakpointId id, ids) {
344         const quint64 address = handler->response(id).address;
345         if (!address)
346             continue;
347         const int lineNumber = contents.lineForAddress(address);
348         if (!lineNumber)
349             continue;
350         BreakpointMarker2 *marker = new BreakpointMarker2(handler->icon(id));
351         d->breakpointMarks.append(marker);
352         d->editor->markableInterface()->addMark(marker, lineNumber);
353     }
354 }
355
356 quint64 DisassemblerAgent::address() const
357 {
358     return d->location.address();
359 }
360
361 // Return address of an assembly line "0x0dfd  bla"
362 quint64 DisassemblerAgent::addressFromDisassemblyLine(const QString &line)
363 {
364     return DisassemblerLine(line).address;
365 }
366
367 void DisassemblerAgent::setTryMixed(bool on)
368 {
369     d->tryMixed = on;
370 }
371
372 } // namespace Internal
373 } // namespace Debugger