1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
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
16 ** GNU Lesser General Public License Usage
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.
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.
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
32 **************************************************************************/
34 #include "disassembleragent.h"
36 #include "disassemblerlines.h"
37 #include "breakhandler.h"
38 #include "debuggerengine.h"
39 #include "debuggercore.h"
40 #include "debuggerstringutils.h"
41 #include "stackframe.h"
43 #include <coreplugin/coreconstants.h>
44 #include <coreplugin/editormanager/ieditor.h>
45 #include <coreplugin/icore.h>
46 #include <coreplugin/mimedatabase.h>
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>
54 #include <utils/qtcassert.h>
56 #include <QtGui/QTextBlock>
57 #include <QtGui/QIcon>
58 #include <QtCore/QPointer>
65 ///////////////////////////////////////////////////////////////////////
69 ///////////////////////////////////////////////////////////////////////
71 class LocationMark2 : public TextEditor::ITextMark
76 QIcon icon() const { return debuggerCore()->locationMarkIcon(); }
77 void updateLineNumber(int /*lineNumber*/) {}
78 void updateBlock(const QTextBlock & /*block*/) {}
79 void removedFromEditor() {}
80 void documentClosing() {}
83 class BreakpointMarker2 : public TextEditor::ITextMark
86 BreakpointMarker2(const QIcon &icon) : m_icon(icon) {}
88 QIcon icon() const { return m_icon; }
89 void updateLineNumber(int) {}
90 void updateBlock(const QTextBlock &) {}
91 void removedFromEditor() {}
92 void documentClosing() {}
99 class DisassemblerAgentPrivate
102 DisassemblerAgentPrivate();
103 ~DisassemblerAgentPrivate();
104 void configureMimeType();
107 QPointer<TextEditor::ITextEditor> editor;
110 QPointer<DebuggerEngine> engine;
111 TextEditor::ITextMark *locationMark;
112 QList<TextEditor::ITextMark *> breakpointMarks;
114 QHash<QString, DisassemblerLines> cache;
118 DisassemblerAgentPrivate::DisassemblerAgentPrivate()
121 locationMark(new LocationMark2),
122 mimeType(_("text/x-qtcreator-generic-asm"))
126 DisassemblerAgentPrivate::~DisassemblerAgentPrivate()
129 EditorManager *editorManager = EditorManager::instance();
130 editorManager->closeEditors(QList<IEditor *>() << editor);
137 \class DisassemblerAgent
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.
144 DisassemblerAgent::DisassemblerAgent(DebuggerEngine *engine)
145 : QObject(0), d(new DisassemblerAgentPrivate)
150 DisassemblerAgent::~DisassemblerAgent()
156 void DisassemblerAgent::cleanup()
161 void DisassemblerAgent::resetLocation()
165 d->editor->markableInterface()->removeMark(d->locationMark);
168 static QString frameKey(const Location &loc)
170 return _("%1:%2:%3").arg(loc.functionName())
171 .arg(loc.fileName()).arg(loc.address());
174 const Location &DisassemblerAgent::location() const
179 bool DisassemblerAgent::isMixed() const
182 && d->location.lineNumber() > 0
183 && !d->location.functionName().isEmpty()
184 && d->location.functionName() != _("??");
187 void DisassemblerAgent::setLocation(const Location &loc)
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);
198 updateBreakpointMarkers();
199 updateLocationMarker();
203 d->engine->fetchDisassembler(this);
206 void DisassemblerAgentPrivate::configureMimeType()
208 QTC_ASSERT(editor, return);
210 TextEditor::BaseTextDocument *doc =
211 qobject_cast<TextEditor::BaseTextDocument *>(editor->file());
212 QTC_ASSERT(doc, return);
213 doc->setMimeType(mimeType);
215 TextEditor::PlainTextEditor *pe =
216 qobject_cast<TextEditor::PlainTextEditor *>(editor->widget());
217 QTC_ASSERT(pe, return);
219 MimeType mtype = ICore::instance()->mimeDatabase()->findByType(mimeType);
221 pe->configure(mtype);
223 qWarning("Assembler mimetype '%s' not found.", qPrintable(mimeType));
226 QString DisassemblerAgent::mimeType() const
231 void DisassemblerAgent::setMimeType(const QString &mt)
233 if (mt == d->mimeType)
237 d->configureMimeType();
240 void DisassemblerAgent::setContents(const DisassemblerLines &contents)
242 QTC_ASSERT(d, return);
243 using namespace Core;
244 using namespace TextEditor;
246 EditorManager *editorManager = EditorManager::instance();
248 QString titlePattern = "Disassembler";
249 d->editor = qobject_cast<ITextEditor *>(
250 editorManager->openEditorWithContents(
251 Core::Constants::K_DEFAULT_TEXT_EDITOR_ID,
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();
258 BaseTextEditor *baseTextEdit =
259 qobject_cast<BaseTextEditor *>(d->editor->widget());
261 baseTextEdit->setRequestMarkEnabled(true);
264 editorManager->activateEditor(d->editor);
266 QPlainTextEdit *plainTextEdit =
267 qobject_cast<QPlainTextEdit *>(d->editor->widget());
268 QTC_ASSERT(plainTextEdit, return);
271 for (int i = 0, n = contents.size(); i != n; ++i) {
272 const DisassemblerLine &dl = contents.at(i);
274 str += QString("0x");
275 str += QString::number(dl.address, 16);
281 plainTextEdit->setPlainText(str);
282 plainTextEdit->setReadOnly(true);
284 d->cache.insert(frameKey(d->location), contents);
285 d->editor->setDisplayName(_("Disassembler (%1)")
286 .arg(d->location.functionName()));
288 updateBreakpointMarkers();
289 updateLocationMarker();
292 void DisassemblerAgent::updateLocationMarker()
294 QTC_ASSERT(d->editor, return);
296 const DisassemblerLines &contents = d->cache.value(frameKey(d->location));
297 int lineNumber = contents.lineForAddress(d->location.address());
299 if (d->location.needsMarker()) {
300 d->editor->markableInterface()->removeMark(d->locationMark);
302 d->editor->markableInterface()->addMark(d->locationMark, lineNumber);
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);
314 void DisassemblerAgent::updateBreakpointMarkers()
319 BreakHandler *handler = breakHandler();
320 BreakpointIds ids = handler->engineBreakpointIds(d->engine);
324 const DisassemblerLines &contents = d->cache.value(frameKey(d->location));
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);
333 const int lineNumber = contents.lineForAddress(address);
336 BreakpointMarker2 *marker = new BreakpointMarker2(handler->icon(id));
337 d->breakpointMarks.append(marker);
338 d->editor->markableInterface()->addMark(marker, lineNumber);
342 quint64 DisassemblerAgent::address() const
344 return d->location.address();
347 // Return address of an assembly line "0x0dfd bla"
348 quint64 DisassemblerAgent::addressFromDisassemblyLine(const QString &line)
350 return DisassemblerLine(line).address;
353 void DisassemblerAgent::setTryMixed(bool on)
358 } // namespace Internal
359 } // namespace Debugger