summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMilian Wolff <milian.wolff@kdab.com>2020-06-07 11:57:18 +0200
committerMilian Wolff <milian.wolff@kdab.com>2020-06-15 08:24:07 +0000
commitca022c0aac0e66b172306c2d6e4b9adfa9be81cc (patch)
tree89e6e42a6dad0ed593ea9469a2c0522e7ab63195
parenta695b3b8d4cd755fe11152cc5e33a45be2f13490 (diff)
Fix symbol resolution for pgoff = 0 in executable mapping
When we encounter multiple mmap events for a DSO we only used the base address when the following mmaps had pgoff != 0. Apparently that is not always a valid assumption, for example I have run into: ``` cpp-inlining 34357 1865.127721: PERF_RECORD_MMAP2 34357/34357: [0x5605a604e000(0x5000) @ 0 08:04 19007514 1373382085]: r--p ...hotspot/tests/test-clients/cpp-inlining/cpp-inlining cpp-inlining 34357 1865.127728: PERF_RECORD_MMAP2 34357/34357: [0x5605a604f000(0x1000) @ 0 08:04 19007514 1373382085]: r-xp ...hotspot/tests/test-clients/cpp-inlining/cpp-inlining cpp-inlining 34357 1865.127732: PERF_RECORD_MMAP2 34357/34357: [0x5605a6050000(0x2000) @ 0 08:04 19007514 1373382085]: rw-p ...hotspot/tests/test-clients/cpp-inlining/cpp-inlining cpp-inlining 34357 1865.127734: PERF_RECORD_MMAP2 34357/34357: [0x5605a6052000(0x1000) @ 0x1000 08:04 19007514 1373382085]: rw-p ...hotspot/tests/test-clients/cpp-inlining/cpp-inlining ``` Here, the executable part corresponds to the second mmap event. Note that it has pgoff = 0, so we tried to use that directly which means that we use its address 0x5605a604f000 as base. For reporting to elfutils. Then, when we try to resolve the sybol at e.g. 0x5605a604fd72 we didn't find anything. This can be confirmed by {eu-,}addr2line by using the computed difference 0xd72 - nothing can be found there. Instead, the base address 0x5605a604e000 from the very first mmap event has to be used, yielding a difference of 0x1d72 which does show symbols again. Change-Id: Icaa3db310237c6f616dc23659a65e13dd5ff017b Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r--app/perfelfmap.cpp12
-rw-r--r--app/perfelfmap.h5
-rw-r--r--app/perfsymboltable.cpp6
-rw-r--r--tests/auto/elfmap/tst_elfmap.cpp28
4 files changed, 33 insertions, 18 deletions
diff --git a/app/perfelfmap.cpp b/app/perfelfmap.cpp
index 54e9e1e..5fad1ee 100644
--- a/app/perfelfmap.cpp
+++ b/app/perfelfmap.cpp
@@ -121,10 +121,14 @@ void PerfElfMap::registerElf(quint64 addr, quint64 len, quint64 pgoff,
ElfInfo elf(fullPath, addr, len, pgoff, originalFileName, originalPath);
- if (!pgoff)
- m_lastBase = elf;
- else if (m_lastBase.originalPath == originalPath)
- elf.baseAddr = m_lastBase.addr;
+ if (elf.isFile()) {
+ if (m_lastBase.originalPath == originalPath && elf.addr > m_lastBase.addr)
+ elf.baseAddr = m_lastBase.addr;
+ else if (!pgoff)
+ m_lastBase = elf;
+ else
+ m_lastBase = ElfInfo();
+ }
newElfs.push_back(elf);
diff --git a/app/perfelfmap.h b/app/perfelfmap.h
index 9480f61..cb8c8fd 100644
--- a/app/perfelfmap.h
+++ b/app/perfelfmap.h
@@ -73,6 +73,11 @@ public:
&& baseAddr == rhs.baseAddr;
}
+ bool operator!=(const ElfInfo& rhs) const
+ {
+ return !operator==(rhs);
+ }
+
QFileInfo localFile;
QByteArray originalFileName;
QByteArray originalPath;
diff --git a/app/perfsymboltable.cpp b/app/perfsymboltable.cpp
index 8383b47..bedee81 100644
--- a/app/perfsymboltable.cpp
+++ b/app/perfsymboltable.cpp
@@ -549,9 +549,9 @@ Dwfl_Module *PerfSymbolTable::module(quint64 addr, const PerfElfMap::ElfInfo &el
if (!m_dwfl)
return nullptr;
- if (elf.pgoff && elf.hasBaseAddr()) {
+ if (elf.hasBaseAddr() && elf.baseAddr != elf.addr) {
const auto base = m_elfs.findElf(elf.baseAddr);
- if (base.addr == elf.baseAddr && !base.pgoff && elf.originalPath == base.originalPath)
+ if (base.addr == elf.baseAddr && !base.pgoff && elf.originalPath == base.originalPath && elf.addr != base.addr)
return module(addr, base);
qWarning() << "stale base mapping referenced:" << elf << base << dec << m_pid << hex << addr;
}
@@ -909,7 +909,7 @@ int PerfSymbolTable::lookupFrame(Dwarf_Addr ip, bool isKernel,
if (elf.isValid()) {
binaryId = m_unwind->resolveString(elf.originalFileName);
binaryPathId = m_unwind->resolveString(elf.originalPath);
- elfStart = elf.addr;
+ elfStart = elf.hasBaseAddr() ? elf.baseAddr : elf.addr;
}
Dwfl_Module *mod = module(ip, elf);
diff --git a/tests/auto/elfmap/tst_elfmap.cpp b/tests/auto/elfmap/tst_elfmap.cpp
index c961b58..a255930 100644
--- a/tests/auto/elfmap/tst_elfmap.cpp
+++ b/tests/auto/elfmap/tst_elfmap.cpp
@@ -48,7 +48,7 @@ private slots:
PerfElfMap map;
QVERIFY(map.isEmpty());
- const PerfElfMap::ElfInfo first({}, 100, 10, 0);
+ const PerfElfMap::ElfInfo first({}, 100, 10, 0, "foo", "/foo");
QVERIFY(registerElf(&map, first).isEmpty());
QVERIFY(!map.isEmpty());
@@ -59,7 +59,7 @@ private slots:
QCOMPARE(map.findElf(109), first);
QCOMPARE(map.findElf(110), invalid);
- const PerfElfMap::ElfInfo second({}, 0, 10, 0);
+ const PerfElfMap::ElfInfo second({}, 0, 10, 0, "bar", "/bar");
QVERIFY(registerElf(&map, second).isEmpty());
QCOMPARE(map.findElf(0), second);
@@ -99,8 +99,10 @@ private slots:
QVERIFY(registerElf(&map, first).isEmpty());
QCOMPARE(map.findElf(110), first);
- const PerfElfMap::ElfInfo second(file1, 105, 20, 0);
+ PerfElfMap::ElfInfo second(file1, 105, 20, 0);
QCOMPARE(registerElf(&map, second), QVector<PerfElfMap::ElfInfo>{first});
+ if (firstIsFile)
+ second.baseAddr = first.addr;
QCOMPARE(map.findElf(110), second);
const PerfElfMap::ElfInfo fragment1(file1, 95, 10, 0);
@@ -156,41 +158,45 @@ private slots:
void testExtendMapping()
{
+ QTemporaryFile file;
+ QVERIFY(file.open());
+ const auto fileInfo = QFileInfo(file.fileName());
+
PerfElfMap map;
- const PerfElfMap::ElfInfo first({}, 0, 5000, 0, "lalala.so", "/tmp/lalala.so");
+ const PerfElfMap::ElfInfo first(fileInfo, 0, 5000, 0);
registerElf(&map, first);
QCOMPARE(map.findElf(100), first);
// fully contained in the first mapping
- const PerfElfMap::ElfInfo second({}, 20, 500, 20, "lalala.so", "/tmp/lalala.so");
+ const PerfElfMap::ElfInfo second(fileInfo, 20, 500, 20);
registerElf(&map, second);
QCOMPARE(map.findElf(100), first);
// extend the first mapping
- const PerfElfMap::ElfInfo third({}, 2000, 8000, 2000, "lalala.so", "/tmp/lalala.so");
+ const PerfElfMap::ElfInfo third(fileInfo, 2000, 8000, 2000);
registerElf(&map, third);
- const PerfElfMap::ElfInfo extended({}, 0, 10000, 0, "lalala.so", "/tmp/lalala.so");
+ const PerfElfMap::ElfInfo extended(fileInfo, 0, 10000, 0);
QCOMPARE(map.findElf(100), extended);
QCOMPARE(map.findElf(2200), extended);
// this has a gap, so don't extend directly
- PerfElfMap::ElfInfo fourth({}, 12000, 100, 100, "lalala.so", "/tmp/lalala.so");
+ PerfElfMap::ElfInfo fourth(fileInfo, 12000, 100, 100);
registerElf(&map, fourth);
QVERIFY(!fourth.hasBaseAddr());
fourth.baseAddr = 0;
QVERIFY(fourth.hasBaseAddr());
QCOMPARE(map.findElf(12000), fourth);
- PerfElfMap::ElfInfo fifth({}, 2000, 500, 3000, "lalala.so", "/tmp/lalala.so");
+ PerfElfMap::ElfInfo fifth(fileInfo, 2000, 500, 3000);
QVERIFY(!fifth.hasBaseAddr()); // base addr will be set on registering based on first mmap.
registerElf(&map, fifth);
fifth.baseAddr = 0;
QCOMPARE(map.findElf(2200), fifth);
- const PerfElfMap::ElfInfo remainder1({}, 0, 2000, 0, "lalala.so", "/tmp/lalala.so");
+ const PerfElfMap::ElfInfo remainder1(fileInfo, 0, 2000, 0);
QCOMPARE(map.findElf(100), remainder1);
- const PerfElfMap::ElfInfo remainder2({}, 2500, 7500, 2500, "lalala.so", "/tmp/lalala.so");
+ const PerfElfMap::ElfInfo remainder2(fileInfo, 2500, 7500, 2500);
QCOMPARE(map.findElf(3000), remainder2);
}