disassembleragent.cpp 9.8 KB
Newer Older
1 2 3 4
/**************************************************************************
**
** This file is part of Qt Creator
**
hjk's avatar
hjk committed
5
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
hjk's avatar
hjk committed
26
** contact the sales department at http://qt.nokia.com/contact.
27 28 29
**
**************************************************************************/

30
#include "disassembleragent.h"
31

32
#include "breakhandler.h"
33
#include "debuggerengine.h"
34
#include "debuggercore.h"
35
#include "debuggerstringutils.h"
36
#include "stackframe.h"
37

38 39 40
#include <coreplugin/coreconstants.h>
#include <coreplugin/editormanager/ieditor.h>
#include <coreplugin/icore.h>
41
#include <coreplugin/mimedatabase.h>
42

43
#include <texteditor/basetextdocument.h>
44 45
#include <texteditor/basetexteditor.h>
#include <texteditor/basetextmark.h>
46
#include <texteditor/plaintexteditor.h>
47 48 49 50
#include <texteditor/texteditorconstants.h>

#include <utils/qtcassert.h>

51
#include <QtGui/QTextBlock>
52
#include <QtGui/QIcon>
53

Bradley T. Hughes's avatar
Compile  
Bradley T. Hughes committed
54

55 56
using namespace Core;

57 58 59
namespace Debugger {
namespace Internal {

60 61 62 63 64 65 66 67 68 69 70
///////////////////////////////////////////////////////////////////////
//
// DisassemblerViewAgent
//
///////////////////////////////////////////////////////////////////////

class LocationMark2 : public TextEditor::ITextMark
{
public:
    LocationMark2() {}

71
    QIcon icon() const { return debuggerCore()->locationMarkIcon(); }
72 73 74 75 76 77
    void updateLineNumber(int /*lineNumber*/) {}
    void updateBlock(const QTextBlock & /*block*/) {}
    void removedFromEditor() {}
    void documentClosing() {}
};

78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
class BreakpointMarker2 : public TextEditor::ITextMark
{
public:
    BreakpointMarker2(const QIcon &icon) : m_icon(icon) {}

    QIcon icon() const { return m_icon; }
    void updateLineNumber(int) {}
    void updateBlock(const QTextBlock &) {}
    void removedFromEditor() {}
    void documentClosing() {}

private:
    QIcon m_icon;
};


94
class DisassemblerViewAgentPrivate
95
{
96
public:
97
    DisassemblerViewAgentPrivate();
98
    ~DisassemblerViewAgentPrivate();
99
    void configureMimeType();
100

101
public:
102
    QPointer<TextEditor::ITextEditor> editor;
103
    StackFrame frame;
104
    bool tryMixed;
105
    bool setMarker;
106
    QPointer<DebuggerEngine> engine;
107 108 109
    TextEditor::ITextMark *locationMark;
    QList<TextEditor::ITextMark *> breakpointMarks;
    
110
    QHash<QString, DisassemblerLines> cache;
111
    QString mimeType;
112 113
};

114 115
DisassemblerViewAgentPrivate::DisassemblerViewAgentPrivate()
  : editor(0),
116
    tryMixed(true),
117
    setMarker(true),
118 119
    locationMark(new LocationMark2),
    mimeType(_("text/x-qtcreator-generic-asm"))
120
{
121
}
122

123 124 125 126 127 128 129 130 131
DisassemblerViewAgentPrivate::~DisassemblerViewAgentPrivate()
{
    if (editor) {
        EditorManager *editorManager = EditorManager::instance();
        editorManager->closeEditors(QList<IEditor *>() << editor);
    }
    editor = 0;
    delete locationMark;
}
132

133 134 135 136 137 138 139 140
/*!
    \class DisassemblerViewAgent

     Objects from this class are created in response to user actions in
     the Gui for showing disassembled memory from the inferior. After creation
     it handles communication between the engine and the editor.
*/

141
DisassemblerViewAgent::DisassemblerViewAgent(DebuggerEngine *engine)
hjk's avatar
hjk committed
142
    : QObject(0), d(new DisassemblerViewAgentPrivate)
143
{
144
    d->engine = engine;
145 146 147 148 149
}

DisassemblerViewAgent::~DisassemblerViewAgent()
{
    delete d;
150
    d = 0;
151 152
}

153 154 155 156 157
void DisassemblerViewAgent::cleanup()
{
    d->cache.clear();
}

158 159
void DisassemblerViewAgent::resetLocation()
{
160 161 162
    if (!d->editor)
        return;
    d->editor->markableInterface()->removeMark(d->locationMark);
163 164
}

165 166 167 168 169
QString frameKey(const StackFrame &frame)
{
    return _("%1:%2:%3").arg(frame.function).arg(frame.file).arg(frame.from);
}

170 171 172 173 174 175 176 177 178 179 180 181 182
const StackFrame &DisassemblerViewAgent::frame() const
{
    return d->frame;
}

bool DisassemblerViewAgent::isMixed() const
{
    return d->tryMixed
        && d->frame.line > 0
        && !d->frame.function.isEmpty()
        && d->frame.function != _("??");
}

183 184
void DisassemblerViewAgent::setFrame(const StackFrame &frame,
    bool tryMixed, bool setMarker)
185
{
186
    d->frame = frame;
187
    d->tryMixed = tryMixed;
hjk's avatar
hjk committed
188
    d->setMarker = setMarker;
189
    if (isMixed()) {
190 191
        QHash<QString, DisassemblerLines>::ConstIterator it =
            d->cache.find(frameKey(frame));
192
        if (it != d->cache.end()) {
Tobias Hunger's avatar
Tobias Hunger committed
193
            QString msg = _("Use cache disassembler for '%1' in '%2'")
194
                .arg(frame.function).arg(frame.file);
195
            d->engine->showMessage(msg);
196
            setContents(*it);
197 198
            updateBreakpointMarkers();
            updateLocationMarker();
199 200
            return;
        }
201
    }
202
    d->engine->fetchDisassembler(this);
203 204
}

205 206 207 208
void DisassemblerViewAgentPrivate::configureMimeType()
{
    QTC_ASSERT(editor, return);

209 210
    TextEditor::BaseTextDocument *doc =
        qobject_cast<TextEditor::BaseTextDocument *>(editor->file());
211 212 213
    QTC_ASSERT(doc, return);
    doc->setMimeType(mimeType);

214 215
    TextEditor::PlainTextEditor *pe =
        qobject_cast<TextEditor::PlainTextEditor *>(editor->widget());
216 217
    QTC_ASSERT(pe, return);

218 219
    MimeType mtype = ICore::instance()->mimeDatabase()->findByType(mimeType);
    if (mtype)
220
        pe->configure(mtype);
221
    else
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
        qWarning("Assembler mimetype '%s' not found.", qPrintable(mimeType));
}

QString DisassemblerViewAgent::mimeType() const
{
    return d->mimeType;
}

void DisassemblerViewAgent::setMimeType(const QString &mt)
{
    if (mt == d->mimeType)
        return;
    d->mimeType = mt;
    if (d->editor)
       d->configureMimeType();
}

239
void DisassemblerViewAgent::setContents(const DisassemblerLines &contents)
240
{
241
    QTC_ASSERT(d, return);
242 243 244 245 246 247 248 249
    using namespace Core;
    using namespace TextEditor;

    EditorManager *editorManager = EditorManager::instance();
    if (!d->editor) {
        QString titlePattern = "Disassembler";
        d->editor = qobject_cast<ITextEditor *>(
            editorManager->openEditorWithContents(
250
                Core::Constants::K_DEFAULT_TEXT_EDITOR_ID,
251
                &titlePattern));
252
        QTC_ASSERT(d->editor, return);
253 254
        d->editor->setProperty(Debugger::Constants::OPENED_BY_DEBUGGER, true);
        d->editor->setProperty(Debugger::Constants::OPENED_WITH_DISASSEMBLY, true);
255
        d->configureMimeType();
256 257 258 259 260

        BaseTextEditor *baseTextEdit =
                qobject_cast<BaseTextEditor *>(d->editor->widget());
        if (baseTextEdit)
            baseTextEdit->setRequestMarkEnabled(true);
261 262
    }

263
    editorManager->activateEditor(d->editor);
264

265 266 267 268 269 270 271 272 273 274 275 276 277 278
    QPlainTextEdit *plainTextEdit =
        qobject_cast<QPlainTextEdit *>(d->editor->widget());
    QTC_ASSERT(plainTextEdit, return);

    QString str;
    for (int i = 0, n = contents.size(); i != n; ++i) {
        const DisassemblerLine &dl = contents.at(i);
        if (dl.address) {
            str += QString("0x");
            str += QString::number(dl.address, 16);
            str += "  ";
        }
        str += dl.data;
        str += "\n";
279
    }
280 281
    plainTextEdit->setPlainText(str);
    plainTextEdit->setReadOnly(true);
282

283
    d->cache.insert(frameKey(d->frame), contents);
284 285 286 287 288 289 290 291 292
    d->editor->setDisplayName(_("Disassembler (%1)").arg(d->frame.function));

    updateBreakpointMarkers();
    updateLocationMarker();
}

void DisassemblerViewAgent::updateLocationMarker()
{
    QTC_ASSERT(d->editor, return);
293

294
    const DisassemblerLines &contents = d->cache.value(frameKey(d->frame));
hjk's avatar
hjk committed
295
    int lineNumber = contents.lineForAddress(d->frame.address);
296

297 298 299 300 301 302 303 304 305
    if (d->setMarker) {
        d->editor->markableInterface()->removeMark(d->locationMark);
        if (lineNumber)
            d->editor->markableInterface()->addMark(d->locationMark, lineNumber);
    }

    QPlainTextEdit *plainTextEdit =
        qobject_cast<QPlainTextEdit *>(d->editor->widget());
    QTC_ASSERT(plainTextEdit, return); 
306 307 308 309
    QTextCursor tc = plainTextEdit->textCursor();
    QTextBlock block = tc.document()->findBlockByNumber(lineNumber - 1);
    tc.setPosition(block.position());
    plainTextEdit->setTextCursor(tc);
310 311
}

312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
void DisassemblerViewAgent::updateBreakpointMarkers()
{
    if (!d->editor)
        return;

    BreakHandler *handler = breakHandler();
    BreakpointIds ids = handler->engineBreakpointIds(d->engine);
    if (ids.isEmpty())
        return;

    const DisassemblerLines &contents = d->cache.value(frameKey(d->frame));

    foreach (TextEditor::ITextMark *marker, d->breakpointMarks)
        d->editor->markableInterface()->removeMark(marker);
    d->breakpointMarks.clear();
    foreach (BreakpointId id, ids) {
        const quint64 address = handler->address(id);
        if (!address)
            continue;
        const int lineNumber = contents.lineForAddress(address);
hjk's avatar
hjk committed
332 333
        if (!lineNumber)
            continue;
334 335 336 337 338 339
        BreakpointMarker2 *marker = new BreakpointMarker2(handler->icon(id));
        d->breakpointMarks.append(marker);
        d->editor->markableInterface()->addMark(marker, lineNumber);
    }
}

340
quint64 DisassemblerViewAgent::address() const
341
{
342
    return d->frame.address;
343 344
}

345 346
// Return address of an assembly line "0x0dfd  bla"
quint64 DisassemblerViewAgent::addressFromDisassemblyLine(const QString &line)
347 348 349 350
{
    return DisassemblerLine(line).address;
}

351 352
} // namespace Internal
} // namespace Debugger