diff options
author | Milian Wolff <milian.wolff@kdab.com> | 2020-06-07 11:57:18 +0200 |
---|---|---|
committer | Milian Wolff <milian.wolff@kdab.com> | 2020-06-15 08:24:07 +0000 |
commit | ca022c0aac0e66b172306c2d6e4b9adfa9be81cc (patch) | |
tree | 89e6e42a6dad0ed593ea9469a2c0522e7ab63195 | |
parent | a695b3b8d4cd755fe11152cc5e33a45be2f13490 (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.cpp | 12 | ||||
-rw-r--r-- | app/perfelfmap.h | 5 | ||||
-rw-r--r-- | app/perfsymboltable.cpp | 6 | ||||
-rw-r--r-- | tests/auto/elfmap/tst_elfmap.cpp | 28 |
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); } |