diff options
author | Milian Wolff <milian.wolff@kdab.com> | 2017-01-31 16:25:37 +0100 |
---|---|---|
committer | Milian Wolff <milian.wolff@kdab.com> | 2017-02-01 12:27:52 +0000 |
commit | c85a07c6152ac23ecacd420f461a18617c465291 (patch) | |
tree | 2b36a67ad1988a74d4e35b12ecda0f9e503f7d8e /tests | |
parent | 7bd8996d52937e3ee8cebca0962763e23af3d22e (diff) |
Resolve kernel addresses to symbols using /proc/kallsyms mapping
Doing that ourselves is much easier than getting libdwfl to do it
for us as far as I can see. Most notably, it is trivial to parse
the mapping from any path that the user specifies. This will be
required to support mappings from other machines.
The benchmark shows that this is takes some time, but it's not
too bad. On my machine, parsing the file takes about ~60ms. This
could be optimized somewhat to around ~40ms by using raw C API,
but it will probably be less safe then. I decided against that,
since the file will only be parsed once.
Change-Id: I8ef53406fcd295676f07618676a8679bdd13b621
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/auto/auto.pro | 4 | ||||
-rw-r--r-- | tests/auto/auto.qbs | 2 | ||||
-rw-r--r-- | tests/auto/kallsyms/kallsyms.pro | 14 | ||||
-rw-r--r-- | tests/auto/kallsyms/kallsyms.qbs | 11 | ||||
-rw-r--r-- | tests/auto/kallsyms/tst_kallsyms.cpp | 119 |
5 files changed, 148 insertions, 2 deletions
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 6f71b2a..a5dcc9b 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -1,2 +1,4 @@ TEMPLATE = subdirs -SUBDIRS = elfmap +SUBDIRS = \ + elfmap \ + kallsyms diff --git a/tests/auto/auto.qbs b/tests/auto/auto.qbs index 5b18b6e..a815e4f 100644 --- a/tests/auto/auto.qbs +++ b/tests/auto/auto.qbs @@ -4,6 +4,6 @@ Project { name: "PerfParserAutotests" condition: project.withAutotests references: [ - "elfmap" + "elfmap", "kallsyms" ] } diff --git a/tests/auto/kallsyms/kallsyms.pro b/tests/auto/kallsyms/kallsyms.pro new file mode 100644 index 0000000..129435b --- /dev/null +++ b/tests/auto/kallsyms/kallsyms.pro @@ -0,0 +1,14 @@ +QT += testlib + +CONFIG += testcase strict_flags warn_on + +INCLUDEPATH += ../../../app + +TARGET = tst_kallsyms + +SOURCES += \ + tst_kallsyms.cpp \ + ../../../app/perfkallsyms.cpp + +HEADERS += \ + ../../../app/perfkallsyms.h diff --git a/tests/auto/kallsyms/kallsyms.qbs b/tests/auto/kallsyms/kallsyms.qbs new file mode 100644 index 0000000..6953497 --- /dev/null +++ b/tests/auto/kallsyms/kallsyms.qbs @@ -0,0 +1,11 @@ +import qbs + +QtcAutotest { + name: "Kallsyms Autotest" + files: [ + "tst_perfkallsyms.cpp", + "../../../app/perfkallsyms.cpp", + "../../../app/perfkallsyms.h" + ] + cpp.includePaths: base.concat(["../../../app"]) +} diff --git a/tests/auto/kallsyms/tst_kallsyms.cpp b/tests/auto/kallsyms/tst_kallsyms.cpp new file mode 100644 index 0000000..0411f6b --- /dev/null +++ b/tests/auto/kallsyms/tst_kallsyms.cpp @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com> +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Enterprise Perf Profiler Add-on. +** +** GNU General Public License Usage +** This file may be used under the terms of the GNU General Public License +** version 3 as published by the Free Software Foundation and appearing in +** the file LICENSE.GPLv3 included in the packaging of this file. Please +** review the following information to ensure the GNU General Public License +** requirements will be met: https://www.gnu.org/licenses/gpl.html. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#include <QObject> +#include <QTest> +#include <QDebug> +#include <QTemporaryFile> + +#include "perfkallsyms.h" + +class TestKallsyms : public QObject +{ + Q_OBJECT +private slots: + void testResolve_data() + { + QTest::addColumn<QByteArray>("kallsymsContents"); + QTest::addColumn<quint64>("address"); + QTest::addColumn<quint64>("expectedAddress"); + QTest::addColumn<QByteArray>("expectedSymbol"); + QTest::addColumn<QByteArray>("expectedModule"); + + { + const QByteArray kallsyms = + "0000000000000000 A irq_stack_union\n" + "0000000000000000 A __per_cpu_start\n" + "ffffffff810002b8 T _stext\n" + "ffffffff81001000 T hypercall_page\n" + "ffffffff81001000 t xen_hypercall_set_trap_table\n" + "ffffffff81001020 t xen_hypercall_mmu_update\n" + "ffffffff81001040 t xen_hypercall_set_gdt\n" + "ffffffffa0000e80 T serio_interrupt\t[serio]\n" + "ffffffffa0000de0 T serio_unregister_driver\t[serio]\n"; + + QTest::newRow("__per_cpu_start:0") << kallsyms << 0x0ull + << 0x0ull << QByteArrayLiteral("__per_cpu_start") << QByteArray(); + QTest::newRow("_stext:0") << kallsyms << 0xffffffff810002b8ull + << 0xffffffff810002b8ull << QByteArrayLiteral("_stext") << QByteArray(); + QTest::newRow("_stext:2") << kallsyms << (0xffffffff810002b8ll + 0x2ull) + << 0xffffffff810002b8ll << QByteArrayLiteral("_stext") << QByteArray(); + QTest::newRow("xen_hypercall_set_gdt:0") << kallsyms << 0xffffffff81001040ull + << 0xffffffff81001040ull << QByteArrayLiteral("xen_hypercall_set_gdt") << QByteArray(); + QTest::newRow("xen_hypercall_set_gdt:256") << kallsyms << (0xffffffff81001040ull + 0x100ull) + << 0xffffffff81001040ull << QByteArrayLiteral("xen_hypercall_set_gdt") << QByteArray(); + QTest::newRow("xen_hypercall_set_gdt:256") << kallsyms << (0xffffffff81001040ull + 0x100ull) + << 0xffffffff81001040ull << QByteArrayLiteral("xen_hypercall_set_gdt") << QByteArray(); + QTest::newRow("serio_interrupt:0") << kallsyms << 0xffffffffa0000e80ull + << 0xffffffffa0000e80ull << QByteArrayLiteral("serio_interrupt") << QByteArrayLiteral("[serio]"); + } + } + + void testResolve() + { + QFETCH(QByteArray, kallsymsContents); + QFETCH(quint64, address); + QFETCH(quint64, expectedAddress); + QFETCH(QByteArray, expectedSymbol); + QFETCH(QByteArray, expectedModule); + + QTemporaryFile file; + QVERIFY(file.open()); + file.write(kallsymsContents); + file.flush(); + + PerfKallsyms kallsyms(file.fileName()); + + const auto entry = kallsyms.findEntry(address); + QCOMPARE(entry.address, expectedAddress); + QCOMPARE(entry.symbol, expectedSymbol); + QCOMPARE(entry.module, expectedModule); + } + + void testProc() + { + const auto path = QStringLiteral("/proc/kallsyms"); + if (!QFile::exists(path)) + QSKIP("/proc/kallsysms not available"); + + PerfKallsyms kallsyms(path); + + // just check that we find any entry + const auto addr = std::numeric_limits<quint64>::max(); + const auto entry = kallsyms.findEntry(addr); + QVERIFY(entry.address); + QVERIFY(!entry.symbol.isEmpty()); + } + + void benchmarkProc() + { + const auto path = QStringLiteral("/proc/kallsyms"); + if (!QFile::exists(path)) + QSKIP("/proc/kallsysms not available"); + + QBENCHMARK { + PerfKallsyms kallsyms(path); + Q_UNUSED(kallsyms); + } + } +}; + +QTEST_MAIN(TestKallsyms) + +#include "tst_kallsyms.moc" |