OSDN Git Service

It's 2011 now.
[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 };
82
83 class BreakpointMarker2 : public TextEditor::ITextMark
84 {
85 public:
86     BreakpointMarker2(const QIcon &icon) : m_icon(icon) {}
87
88     QIcon icon() const { return m_icon; }
89     void updateLineNumber(int) {}
90     void updateBlock(const QTextBlock &) {}
91     void removedFromEditor() {}
92     void documentClosing() {}
93
94 private:
95     QIcon m_icon;
96 };
97
98
99 class DisassemblerAgentPrivate
100 {
101 public:
102     DisassemblerAgentPrivate();
103     ~DisassemblerAgentPrivate();
104     void configureMimeType();
105
106 public:
107     QPointer<TextEditor::ITextEditor> editor;
108     Location location;
109     bool tryMixed;
110     QPointer<DebuggerEngine> engine;
111     TextEditor::ITextMark *locationMark;
112     QList<TextEditor::ITextMark *> breakpointMarks;
113     
114     QHash<QString, DisassemblerLines> cache;
115     QString mimeType;
116 };
117
118 DisassemblerAgentPrivate::DisassemblerAgentPrivate()
119   : editor(0),
120     tryMixed(true),
121     locationMark(new LocationMark2),
122     mimeType(_("text/x-qtcreator-generic-asm"))
123 {
124 }
125
126 DisassemblerAgentPrivate::~DisassemblerAgentPrivate()
127 {
128     if (editor) {
129         EditorManager *editorManager = EditorManager::instance();
130         editorManager->closeEditors(QList<IEditor *>() << editor);
131     }
132     editor = 0;
133     delete locationMark;
134 }
135
136 /*!
137     \class DisassemblerAgent
138
139      Objects from this class are created in response to user actions in
140      the Gui for showing disassembled memory from the inferior. After creation
141      it handles communication between the engine and the editor.
142 */
143
144 DisassemblerAgent::DisassemblerAgent(DebuggerEngine *engine)
145     : QObject(0), d(new DisassemblerAgentPrivate)
146 {
147     d->engine = engine;
148 }
149
150 DisassemblerAgent::~DisassemblerAgent()
151 {
152     delete d;
153     d = 0;
154 }
155
156 void DisassemblerAgent::cleanup()
157 {
158     d->cache.clear();
159 }
160
161 void DisassemblerAgent::resetLocation()
162 {
163     if (!d->editor)
164         return;
165     d->editor->markableInterface()->removeMark(d->locationMark);
166 }
167
168 static QString frameKey(const Location &loc)
169 {
170     return _("%1:%2:%3").arg(loc.functionName())
171         .arg(loc.fileName()).arg(loc.address());
172 }
173
174 const Location &DisassemblerAgent::location() const
175 {
176     return d->location;
177 }
178
179 bool DisassemblerAgent::isMixed() const
180 {
181     return d->tryMixed
182         && d->location.lineNumber() > 0
183         && !d->location.functionName().isEmpty()
184         && d->location.functionName() != _("??");
185 }
186
187 void DisassemblerAgent::setLocation(const Location &loc)
188 {
189     d->location = loc;
190     if (isMixed()) {
191         QHash<QString, DisassemblerLines>::ConstIterator it =
192             d->cache.find(frameKey(loc));
193         if (it != d->cache.end()) {
194             QString msg = _("Use cache disassembler for '%1' in '%2'")
195                 .arg(loc.functionName()).arg(loc.fileName());
196             d->engine->showMessage(msg);
197             setContents(*it);
198             updateBreakpointMarkers();
199             updateLocationMarker();
200             return;
201         }
202     }
203     d->engine->fetchDisassembler(this);
204 }
205
206 void DisassemblerAgentPrivate::configureMimeType()
207 {
208     QTC_ASSERT(editor, return);
209
210     TextEditor::BaseTextDocument *doc =
211         qobject_cast<TextEditor::BaseTextDocument *>(editor->file());
212     QTC_ASSERT(doc, return);
213     doc->setMimeType(mimeType);
214
215     TextEditor::PlainTextEditor *pe =
216         qobject_cast<TextEditor::PlainTextEditor *>(editor->widget());
217     QTC_ASSERT(pe, return);
218
219     MimeType mtype = ICore::instance()->mimeDatabase()->findByType(mimeType);
220     if (mtype)
221         pe->configure(mtype);
222     else
223         qWarning("Assembler mimetype '%s' not found.", qPrintable(mimeType));
224 }
225
226 QString DisassemblerAgent::mimeType() const
227 {
228     return d->mimeType;
229 }
230
231 void DisassemblerAgent::setMimeType(const QString &mt)
232 {
233     if (mt == d->mimeType)
234         return;
235     d->mimeType = mt;
236     if (d->editor)
237        d->configureMimeType();
238 }
239
240 void DisassemblerAgent::setContents(const DisassemblerLines &contents)
241 {
242     QTC_ASSERT(d, return);
243     using namespace Core;
244     using namespace TextEditor;
245
246     EditorManager *editorManager = EditorManager::instance();
247     if (!d->editor) {
248         QString titlePattern = "Disassembler";
249         d->editor = qobject_cast<ITextEditor *>(
250             editorManager->openEditorWithContents(
251                 Core::Constants::K_DEFAULT_TEXT_EDITOR_ID,
252                 &titlePattern));
253         QTC_ASSERT(d->editor, return);
254         d->editor->setProperty(Debugger::Constants::OPENED_BY_DEBUGGER, true);
255         d->editor->setProperty(Debugger::Constants::OPENED_WITH_DISASSEMBLY, true);
256         d->configureMimeType();
257
258         BaseTextEditor *baseTextEdit =
259                 qobject_cast<BaseTextEditor *>(d->editor->widget());
260         if (baseTextEdit)
261             baseTextEdit->setRequestMarkEnabled(true);
262     }
263
264     editorManager->activateEditor(d->editor);
265
266     QPlainTextEdit *plainTextEdit =
267         qobject_cast<QPlainTextEdit *>(d->editor->widget());
268     QTC_ASSERT(plainTextEdit, return);
269
270     QString str;
271     for (int i = 0, n = contents.size(); i != n; ++i) {
272         const DisassemblerLine &dl = contents.at(i);
273         if (dl.address) {
274             str += QString("0x");
275             str += QString::number(dl.address, 16);
276             str += "  ";
277         }
278         str += dl.data;
279         str += "\n";
280     }
281     plainTextEdit->setPlainText(str);
282     plainTextEdit->setReadOnly(true);
283
284     d->cache.insert(frameKey(d->location), contents);
285     d->editor->setDisplayName(_("Disassembler (%1)")
286         .arg(d->location.functionName()));
287
288     updateBreakpointMarkers();
289     updateLocationMarker();
290 }
291
292 void DisassemblerAgent::updateLocationMarker()
293 {
294     QTC_ASSERT(d->editor, return);
295
296     const DisassemblerLines &contents = d->cache.value(frameKey(d->location));
297     int lineNumber = contents.lineForAddress(d->location.address());
298
299     if (d->location.needsMarker()) {
300         d->editor->markableInterface()->removeMark(d->locationMark);
301         if (lineNumber)
302             d->editor->markableInterface()->addMark(d->locationMark, lineNumber);
303     }
304
305     QPlainTextEdit *plainTextEdit =
306         qobject_cast<QPlainTextEdit *>(d->editor->widget());
307     QTC_ASSERT(plainTextEdit, return); 
308     QTextCursor tc = plainTextEdit->textCursor();
309     QTextBlock block = tc.document()->findBlockByNumber(lineNumber - 1);
310     tc.setPosition(block.position());
311     plainTextEdit->setTextCursor(tc);
312 }
313
314 void DisassemblerAgent::updateBreakpointMarkers()
315 {
316     if (!d->editor)
317         return;
318
319     BreakHandler *handler = breakHandler();
320     BreakpointIds ids = handler->engineBreakpointIds(d->engine);
321     if (ids.isEmpty())
322         return;
323
324     const DisassemblerLines &contents = d->cache.value(frameKey(d->location));
325
326     foreach (TextEditor::ITextMark *marker, d->breakpointMarks)
327         d->editor->markableInterface()->removeMark(marker);
328     d->breakpointMarks.clear();
329     foreach (BreakpointId id, ids) {
330         const quint64 address = handler->address(id);
331         if (!address)
332             continue;
333         const int lineNumber = contents.lineForAddress(address);
334         if (!lineNumber)
335             continue;
336         BreakpointMarker2 *marker = new BreakpointMarker2(handler->icon(id));
337         d->breakpointMarks.append(marker);
338         d->editor->markableInterface()->addMark(marker, lineNumber);
339     }
340 }
341
342 quint64 DisassemblerAgent::address() const
343 {
344     return d->location.address();
345 }
346
347 // Return address of an assembly line "0x0dfd  bla"
348 quint64 DisassemblerAgent::addressFromDisassemblyLine(const QString &line)
349 {
350     return DisassemblerLine(line).address;
351 }
352
353 void DisassemblerAgent::setTryMixed(bool on)
354 {
355     d->tryMixed = on;
356 }
357
358 } // namespace Internal
359 } // namespace Debugger