disassembleragent.cpp 9.69 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
// DisassemblerAgent
63 64 65 66 67 68 69 70
//
///////////////////////////////////////////////////////////////////////

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 DisassemblerAgentPrivate
95
{
96
public:
97 98
    DisassemblerAgentPrivate();
    ~DisassemblerAgentPrivate();
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
DisassemblerAgentPrivate::DisassemblerAgentPrivate()
115
  : editor(0),
116
    tryMixed(true),
117
    setMarker(true),
118 119
    locationMark(new LocationMark2),
    mimeType(_("text/x-qtcreator-generic-asm"))
120
{
121
}
122

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

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

     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 142
DisassemblerAgent::DisassemblerAgent(DebuggerEngine *engine)
    : QObject(0), d(new DisassemblerAgentPrivate)
143
{
144
    d->engine = engine;
145 146
}

147
DisassemblerAgent::~DisassemblerAgent()
148 149
{
    delete d;
150
    d = 0;
151 152
}

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

158
void DisassemblerAgent::resetLocation()
159
{
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
const StackFrame &DisassemblerAgent::frame() const
171 172 173 174
{
    return d->frame;
}

175
bool DisassemblerAgent::isMixed() const
176 177 178 179 180 181 182
{
    return d->tryMixed
        && d->frame.line > 0
        && !d->frame.function.isEmpty()
        && d->frame.function != _("??");
}

183
void DisassemblerAgent::setFrame(const StackFrame &frame,
184
    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
void DisassemblerAgentPrivate::configureMimeType()
206 207 208
{
    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
        qWarning("Assembler mimetype '%s' not found.", qPrintable(mimeType));
}

225
QString DisassemblerAgent::mimeType() const
226 227 228 229
{
    return d->mimeType;
}

230
void DisassemblerAgent::setMimeType(const QString &mt)
231 232 233 234 235 236 237 238
{
    if (mt == d->mimeType)
        return;
    d->mimeType = mt;
    if (d->editor)
       d->configureMimeType();
}

239
void DisassemblerAgent::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
    d->editor->setDisplayName(_("Disassembler (%1)").arg(d->frame.function));

    updateBreakpointMarkers();
    updateLocationMarker();
}

290
void DisassemblerAgent::updateLocationMarker()
291 292
{
    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
void DisassemblerAgent::updateBreakpointMarkers()
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
{
    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 DisassemblerAgent::address() const
341
{
342
    return d->frame.address;
343 344
}

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

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