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() {}
81 TextEditor::ITextMark::Priority priority() const
82 { return TextEditor::ITextMark::HighPriority; }
85 class BreakpointMarker2 : public TextEditor::ITextMark
88 BreakpointMarker2(const QIcon &icon) : m_icon(icon) {}
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; }
103 class DisassemblerAgentPrivate
106 DisassemblerAgentPrivate();
107 ~DisassemblerAgentPrivate();
108 void configureMimeType();
111 QPointer<TextEditor::ITextEditor> editor;
114 QPointer<DebuggerEngine> engine;
115 TextEditor::ITextMark *locationMark;
116 QList<TextEditor::ITextMark *> breakpointMarks;
118 QHash<QString, DisassemblerLines> cache;
120 bool m_resetLocationScheduled;
123 DisassemblerAgentPrivate::DisassemblerAgentPrivate()
126 locationMark(new LocationMark2),
127 mimeType(_("text/x-qtcreator-generic-asm")),
128 m_resetLocationScheduled(false)
132 DisassemblerAgentPrivate::~DisassemblerAgentPrivate()
135 EditorManager *editorManager = EditorManager::instance();
136 editorManager->closeEditors(QList<IEditor *>() << editor);
143 \class Debugger::Internal::DisassemblerAgent
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.
150 DisassemblerAgent::DisassemblerAgent(DebuggerEngine *engine)
151 : QObject(0), d(new DisassemblerAgentPrivate)
156 DisassemblerAgent::~DisassemblerAgent()
162 void DisassemblerAgent::cleanup()
167 void DisassemblerAgent::scheduleResetLocation()
169 d->m_resetLocationScheduled = true;
172 void DisassemblerAgent::resetLocation()
176 if (d->m_resetLocationScheduled) {
177 d->m_resetLocationScheduled = false;
178 d->editor->markableInterface()->removeMark(d->locationMark);
182 static QString frameKey(const Location &loc)
184 return _("%1:%2:%3").arg(loc.functionName())
185 .arg(loc.fileName()).arg(loc.address());
188 const Location &DisassemblerAgent::location() const
193 bool DisassemblerAgent::isMixed() const
196 && d->location.lineNumber() > 0
197 && !d->location.functionName().isEmpty()
198 && d->location.functionName() != _("??");
201 void DisassemblerAgent::setLocation(const Location &loc)
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);
212 updateBreakpointMarkers();
213 updateLocationMarker();
217 d->engine->fetchDisassembler(this);
220 void DisassemblerAgentPrivate::configureMimeType()
222 QTC_ASSERT(editor, return);
224 TextEditor::BaseTextDocument *doc =
225 qobject_cast<TextEditor::BaseTextDocument *>(editor->file());
226 QTC_ASSERT(doc, return);
227 doc->setMimeType(mimeType);
229 TextEditor::PlainTextEditorWidget *pe =
230 qobject_cast<TextEditor::PlainTextEditorWidget *>(editor->widget());
231 QTC_ASSERT(pe, return);
233 MimeType mtype = ICore::instance()->mimeDatabase()->findByType(mimeType);
235 pe->configure(mtype);
237 qWarning("Assembler mimetype '%s' not found.", qPrintable(mimeType));
240 QString DisassemblerAgent::mimeType() const
245 void DisassemblerAgent::setMimeType(const QString &mt)
247 if (mt == d->mimeType)
251 d->configureMimeType();
254 void DisassemblerAgent::setContents(const DisassemblerLines &contents)
256 QTC_ASSERT(d, return);
257 using namespace Core;
258 using namespace TextEditor;
260 EditorManager *editorManager = EditorManager::instance();
262 QString titlePattern = "Disassembler";
263 d->editor = qobject_cast<ITextEditor *>(
264 editorManager->openEditorWithContents(
265 Core::Constants::K_DEFAULT_TEXT_EDITOR_ID,
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();
272 BaseTextEditorWidget *baseTextEdit =
273 qobject_cast<BaseTextEditorWidget *>(d->editor->widget());
275 baseTextEdit->setRequestMarkEnabled(true);
278 editorManager->activateEditor(d->editor);
280 QPlainTextEdit *plainTextEdit =
281 qobject_cast<QPlainTextEdit *>(d->editor->widget());
282 QTC_ASSERT(plainTextEdit, return);
285 for (int i = 0, n = contents.size(); i != n; ++i) {
286 const DisassemblerLine &dl = contents.at(i);
288 str += QLatin1String("0x");
289 str += QString::number(dl.address, 16);
290 str += QLatin1String(" ");
293 str += QLatin1Char('\n');
295 plainTextEdit->setPlainText(str);
296 plainTextEdit->setReadOnly(true);
298 d->cache.insert(frameKey(d->location), contents);
299 d->editor->setDisplayName(_("Disassembler (%1)")
300 .arg(d->location.functionName()));
302 updateBreakpointMarkers();
303 updateLocationMarker();
306 void DisassemblerAgent::updateLocationMarker()
308 QTC_ASSERT(d->editor, return);
310 const DisassemblerLines &contents = d->cache.value(frameKey(d->location));
311 int lineNumber = contents.lineForAddress(d->location.address());
313 if (d->location.needsMarker()) {
314 d->editor->markableInterface()->removeMark(d->locationMark);
316 d->editor->markableInterface()->addMark(d->locationMark, lineNumber);
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);
328 void DisassemblerAgent::updateBreakpointMarkers()
333 BreakHandler *handler = breakHandler();
334 BreakpointIds ids = handler->engineBreakpointIds(d->engine);
338 const DisassemblerLines &contents = d->cache.value(frameKey(d->location));
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;
347 const int lineNumber = contents.lineForAddress(address);
350 BreakpointMarker2 *marker = new BreakpointMarker2(handler->icon(id));
351 d->breakpointMarks.append(marker);
352 d->editor->markableInterface()->addMark(marker, lineNumber);
356 quint64 DisassemblerAgent::address() const
358 return d->location.address();
361 // Return address of an assembly line "0x0dfd bla"
362 quint64 DisassemblerAgent::addressFromDisassemblyLine(const QString &line)
364 return DisassemblerLine(line).address;
367 void DisassemblerAgent::setTryMixed(bool on)
372 } // namespace Internal
373 } // namespace Debugger