diff --git a/src/plugins/debugger/disassemblerlines.cpp b/src/plugins/debugger/disassemblerlines.cpp index f125d72448eecb53a3b675ebca8a08387085849e..8768e28483585f16ab3fb357ca48e37da117d567 100644 --- a/src/plugins/debugger/disassemblerlines.cpp +++ b/src/plugins/debugger/disassemblerlines.cpp @@ -142,6 +142,13 @@ void DisassemblerLines::appendSourceLine(const QString &fileName, uint lineNumbe appendLine(dl); } +void DisassemblerLines::appendComment(const QString &line) +{ + DisassemblerLine dl; + dl.data = line; + appendLine(dl); +} + void DisassemblerLines::appendUnparsed(const QString &unparsed) { QString line = unparsed.trimmed(); @@ -162,15 +169,24 @@ void DisassemblerLines::appendUnparsed(const QString &unparsed) if (line.startsWith(QLatin1String("=> "))) line = line.mid(3); if (line.startsWith(QLatin1String("0x"))) { - // Address line. - int pos1 = line.indexOf(QLatin1Char('<')) + 1; - int posc = line.indexOf(QLatin1Char(':')); + // Address line. Split at the tab. + int tab = line.indexOf(QLatin1Char('\t')); + if (tab == -1) { + appendComment(line); + return; + } + QString address = line.left(tab); + if (address.endsWith(QLatin1Char(':'))) + address.chop(1); + int pos1 = address.indexOf(QLatin1Char('<')) + 1; DisassemblerLine dl; - if (pos1 && line.indexOf(QLatin1String("<UNDEFINED> instruction:")) == -1) { - int pos2 = line.indexOf(QLatin1Char('+'), pos1); - int pos3 = line.indexOf(QLatin1Char('>'), pos1); - if (pos1 < pos2 && pos2 < pos3) { - QString function = line.mid(pos1, pos2 - pos1); + dl.data = line.mid(tab).trimmed(); + if (pos1 && address.indexOf(QLatin1String("<UNDEFINED> instruction:")) == -1) { + if (address.endsWith(QLatin1Char('>'))) + address.chop(1); + int pos2 = address.indexOf(QLatin1Char('+'), pos1); + if (pos1 < pos2) { + QString function = address.mid(pos1, pos2 - pos1); if (function != m_lastFunction) { DisassemblerLine dl; dl.data = _("Function: ") + function; @@ -178,16 +194,14 @@ void DisassemblerLines::appendUnparsed(const QString &unparsed) m_lastFunction = function; } } - dl.address = line.left(pos1 - 1).toULongLong(0, 0); + dl.address = address.left(pos1 - 1).toULongLong(0, 0); dl.function = m_lastFunction; - dl.offset = line.mid(pos2, pos3 - pos2).toUInt(); - dl.data = line.mid(pos3 + 3).trimmed(); + dl.offset = address.mid(pos2).toUInt(); } else { // Plain data like "0x0000cd64:\tadd\tlr, pc, lr\n" - dl.address = line.left(posc).toULongLong(0, 0); + dl.address = address.toULongLong(0, 0); dl.function = m_lastFunction; dl.offset = 0; - dl.data = line.mid(posc + 1).trimmed(); } m_rowCache[dl.address] = m_data.size() + 1; m_data.append(dl); @@ -205,8 +219,11 @@ QString DisassemblerLine::toString() const QString str; if (isAssembler()) { if (address) - str += _("0x%1 <+0x%2> ").arg(address, 0, 16) - .arg(offset, 4, 16, QLatin1Char('0')); + str += _("0x%1 ").arg(address, 0, 16); + if (offset) + str += _("<+0x%2> ").arg(offset, 4, 16, QLatin1Char('0')); + else + str += _(" "); str += _(" "); str += data; } else if (isCode()) { diff --git a/src/plugins/debugger/disassemblerlines.h b/src/plugins/debugger/disassemblerlines.h index 1026d10fba43b9c6be03e17190f1725b54682440..4ce9caad3a2dd414b8cbe882f24b648e92f4ffb9 100644 --- a/src/plugins/debugger/disassemblerlines.h +++ b/src/plugins/debugger/disassemblerlines.h @@ -73,6 +73,7 @@ public: bool coversAddress(quint64 address) const; void appendUnparsed(const QString &line); void appendLine(const DisassemblerLine &dl); + void appendComment(const QString &line); // Mixed source/assembly: Retrieve contents of source (cached) void appendSourceLine(const QString &fileName, uint line); diff --git a/tests/auto/debugger/debugger.pro b/tests/auto/debugger/debugger.pro index b280e393524417699ee63bcb0fcb77f50d7840ef..0111d79d72cb93ff8ff102176930cbd481c6a0ef 100644 --- a/tests/auto/debugger/debugger.pro +++ b/tests/auto/debugger/debugger.pro @@ -5,4 +5,5 @@ SUBDIRS += gdb.pro SUBDIRS += dumpers.pro SUBDIRS += namedemangler.pro SUBDIRS += simplifytypes.pro +SUBDIRS += disassembler.pro diff --git a/tests/auto/debugger/debugger.qbs b/tests/auto/debugger/debugger.qbs index 64230f1a0ec8a2e6e02c4dd50bb383e9214ff53e..502a54751733abc81c63517e68e27abe11b3d8b5 100644 --- a/tests/auto/debugger/debugger.qbs +++ b/tests/auto/debugger/debugger.qbs @@ -7,6 +7,7 @@ Project { "dumpers.qbs", "gdb.qbs", "namedemangler.qbs", - "simplifytypes.qbs" + "simplifytypes.qbs", + "disassembler.qbs" ] } diff --git a/tests/auto/debugger/disassembler.pro b/tests/auto/debugger/disassembler.pro new file mode 100644 index 0000000000000000000000000000000000000000..8f85fba5c32ab8b3ef4093cd4b8c1982489b713a --- /dev/null +++ b/tests/auto/debugger/disassembler.pro @@ -0,0 +1,12 @@ +QTC_LIB_DEPENDS += utils +QT = core network +include(../qttest.pri) + +DEBUGGERDIR = $$IDE_SOURCE_TREE/src/plugins/debugger + +INCLUDEPATH += $$DEBUGGERDIR + +SOURCES += \ + tst_disassembler.cpp \ + $$DEBUGGERDIR/disassemblerlines.cpp \ + diff --git a/tests/auto/debugger/disassembler.qbs b/tests/auto/debugger/disassembler.qbs new file mode 100644 index 0000000000000000000000000000000000000000..94245181b10c4d68af98ad2be07775f8d6d6dad5 --- /dev/null +++ b/tests/auto/debugger/disassembler.qbs @@ -0,0 +1,17 @@ +import qbs +import "../autotest.qbs" as Autotest + +Autotest { + name: "disassembler autotest" + Depends { name: "Qt.network" } // For QHostAddress + Group { + name: "Sources from Debugger plugin" + prefix: project.debuggerDir + files: "disassemblerlines.cpp" + } + Group { + name: "Test sources" + files: "tst_disassembler.cpp" + } + cpp.includePaths: base.concat([project.debuggerDir]) +} diff --git a/tests/auto/debugger/tst_disassembler.cpp b/tests/auto/debugger/tst_disassembler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..899ef8c6a49e6025a38fd62bbb1173d4c5520e11 --- /dev/null +++ b/tests/auto/debugger/tst_disassembler.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "disassemblerlines.h" + +#include <QtTest> + +//TESTED_COMPONENT=src/plugins/debugger/gdb + +Q_DECLARE_METATYPE(Debugger::Internal::DisassemblerLine) + +using namespace Debugger::Internal; + +class tst_disassembler : public QObject +{ + Q_OBJECT + +public: + tst_disassembler() {} + +private slots: + void parse(); + void parse_data(); + +private: + DisassemblerLines lines; +}; + +void tst_disassembler::parse() +{ + QFETCH(QString, raw); + QFETCH(QString, cooked); + QFETCH(Debugger::Internal::DisassemblerLine, line); + + lines.appendUnparsed(raw); + DisassemblerLine parsed = lines.at(lines.size() - 1); + + QCOMPARE(parsed.address, line.address); + QCOMPARE(parsed.function, line.function); + QCOMPARE(parsed.offset, line.offset); + QCOMPARE(parsed.lineNumber, line.lineNumber); + QCOMPARE(parsed.rawData, line.rawData); + QCOMPARE(parsed.data, line.data); + + QString out___ = parsed.toString(); + QCOMPARE(out___, cooked); +} + +void tst_disassembler::parse_data() +{ + QTest::addColumn<QString>("raw"); + QTest::addColumn<QString>("cooked"); + QTest::addColumn<Debugger::Internal::DisassemblerLine>("line"); + + DisassemblerLine line; + + line.address = 0x40f39e; + line.offset = 18; + line.data = "mov %rax,%rdi"; + QTest::newRow("plain") + << "0x000000000040f39e <+18>:\tmov %rax,%rdi" + << "0x40f39e <+0x0012> mov %rax,%rdi" + << line; + + line.address = 0x40f3a1; + line.offset = 21; + line.data = "callq 0x420d2c <_ZN7qobject5Names3Bar10TestObjectC2EPN4Myns7QObjectE>"; + QTest::newRow("call") + << "0x000000000040f3a1 <+21>:\tcallq 0x420d2c <_ZN7qobject5Names3Bar10TestObjectC2EPN4Myns7QObjectE>" + << "0x40f3a1 <+0x0015> callq 0x420d2c <_ZN7qobject5Names3Bar10TestObjectC2EPN4Myns7QObjectE>" + << line; + + + line.address = 0x000000000041cd73; + line.offset = 0; + line.data = "mov %rax,%rdi"; + QTest::newRow("set print max-symbolic-offset 1, plain") + << "0x000000000041cd73:\tmov %rax,%rdi" + << "0x41cd73 mov %rax,%rdi" + << line; + + line.address = 0x000000000041cd73; + line.offset = 0; + line.data = "callq 0x420d2c <_ZN4Myns12QApplicationC1ERiPPci@plt>"; + QTest::newRow("set print max-symbolic-offset 1, call") + << "0x00000000041cd73:\tcallq 0x420d2c <_ZN4Myns12QApplicationC1ERiPPci@plt>" + << "0x41cd73 callq 0x420d2c <_ZN4Myns12QApplicationC1ERiPPci@plt>" + << line; + } + + +QTEST_APPLESS_MAIN(tst_disassembler); + +#include "tst_disassembler.moc" +