summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorMilian Wolff <milian.wolff@kdab.com>2017-01-31 16:25:37 +0100
committerMilian Wolff <milian.wolff@kdab.com>2017-02-01 12:27:52 +0000
commitc85a07c6152ac23ecacd420f461a18617c465291 (patch)
tree2b36a67ad1988a74d4e35b12ecda0f9e503f7d8e /tests
parent7bd8996d52937e3ee8cebca0962763e23af3d22e (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.pro4
-rw-r--r--tests/auto/auto.qbs2
-rw-r--r--tests/auto/kallsyms/kallsyms.pro14
-rw-r--r--tests/auto/kallsyms/kallsyms.qbs11
-rw-r--r--tests/auto/kallsyms/tst_kallsyms.cpp119
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"