summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMilian Wolff <milian.wolff@kdab.com>2018-10-20 12:20:29 +0200
committerMilian Wolff <milian.wolff@kdab.com>2018-10-23 18:35:35 +0000
commitc1c830abb5e87cf0441f6732f5cbd953d59f1c5b (patch)
tree59828bca7c65bd1af675b756c4ef836c9a85f95c
parent573f54d94c7f476d9604e037a7763cab627662a6 (diff)
Report base mapping to dwfl when we need the module for an pgoff mmap
Previously, we would just error out when we encounter an address in an mmaped elf with pgoff != 0. E.g. for the following mmap events: 0x7f5d69432000 to 0x7f5d6957d000, len = 0x14b000, offset = 0, virt start = 0x7f5d69432000 r--p /usr/lib/libQt5Widgets.so.5.11.2 0x7f5d6957d000 to 0x7f5d6990e000, len = 0x391000, offset = 0x14b000, virt start = 0x7f5d69432000 r-xp /usr/lib/libQt5Widgets.so.5.11.2 0x7f5d6990e000 to 0x7f5d69a61000, len = 0x153000, offset = 0x4dc000, virt start = 0x7f5d69432000 r--p /usr/lib/libQt5Widgets.so.5.11.2 0x7f5d69a61000 to 0x7f5d69a93000, len = 0x32000, offset = 0x62e000, virt start = 0x7f5d69433000 r--p /usr/lib/libQt5Widgets.so.5.11.2 0x7f5d69a93000 to 0x7f5d69a94000, len = 0x1000, offset = 0x660000, virt start = 0x7f5d69433000 rw-p /usr/lib/libQt5Widgets.so.5.11.2 We sometimes requested the module for the second to last mmap from memoryRead/accessDsoMem, leading to the dreaded "failed to report" error message due to pgoff != 0. This patch now introduces a trivial time-based association to the base map with pgoff = 0 when the originalPath matches. This allows us to use the address of the first mmap event above when we encounter an address in the second to last mmap, fixing the notorious error and unbreaking some broken backtraces. Task-number: QTCREATORBUG-21260 Change-Id: I4bc5b4e5b23973e4ba8cf68389fa813208d20867 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r--app/perfelfmap.cpp22
-rw-r--r--app/perfelfmap.h16
-rw-r--r--app/perfsymboltable.cpp3
-rw-r--r--app/perfsymboltable.h6
-rw-r--r--tests/auto/elfmap/tst_elfmap.cpp9
5 files changed, 45 insertions, 11 deletions
diff --git a/app/perfelfmap.cpp b/app/perfelfmap.cpp
index d5cf084..45776f0 100644
--- a/app/perfelfmap.cpp
+++ b/app/perfelfmap.cpp
@@ -31,9 +31,16 @@ QDebug operator<<(QDebug stream, const PerfElfMap::ElfInfo& info)
<< "originalFileName=" << info.originalFileName << ", "
<< "originalPath=" << info.originalPath << ", "
<< "addr=" << hex << info.addr<< ", "
- << "len=" << hex << info.length << ", "
- << "pgoff=" << hex << info.pgoff
- << "}";
+ << "len=" << info.length << ", "
+ << "pgoff=" << info.pgoff << ", "
+ << "baseAddr=";
+
+ if (info.hasBaseAddr())
+ stream << info.baseAddr;
+ else
+ stream << "n/a";
+
+ stream << "}" << dec;
return stream.space();
}
@@ -113,7 +120,14 @@ bool PerfElfMap::registerElf(quint64 addr, quint64 len, quint64 pgoff,
for (auto it = removedElfs.rbegin(), end = removedElfs.rend(); it != end; ++it)
m_elfs.remove(*it);
- newElfs.push_back(ElfInfo(fullPath, addr, len, pgoff, originalFileName, originalPath));
+ ElfInfo elf(fullPath, addr, len, pgoff, originalFileName, originalPath);
+
+ if (!pgoff)
+ m_lastBase = elf;
+ else if (m_lastBase.originalPath == originalPath)
+ elf.baseAddr = m_lastBase.addr;
+
+ newElfs.push_back(elf);
for (const auto &elf : newElfs) {
auto it = std::lower_bound(m_elfs.begin(), m_elfs.end(),
diff --git a/app/perfelfmap.h b/app/perfelfmap.h
index 2396046..e9262e4 100644
--- a/app/perfelfmap.h
+++ b/app/perfelfmap.h
@@ -22,11 +22,15 @@
#include <QFileInfo>
#include <QVector>
+#include <limits>
class PerfElfMap
{
public:
struct ElfInfo {
+ enum {
+ INVALID_BASE_ADDR = std::numeric_limits<quint64>::max()
+ };
explicit ElfInfo(const QFileInfo &localFile = QFileInfo(), quint64 addr = 0,
quint64 length = 0, quint64 pgoff = 0,
const QByteArray &originalFileName = {},
@@ -51,6 +55,11 @@ public:
return localFile.isFile();
}
+ bool hasBaseAddr() const
+ {
+ return baseAddr != INVALID_BASE_ADDR;
+ }
+
bool operator==(const ElfInfo& rhs) const
{
return isFile() == rhs.isFile()
@@ -59,7 +68,8 @@ public:
&& originalPath == rhs.originalPath
&& addr == rhs.addr
&& length == rhs.length
- && pgoff == rhs.pgoff;
+ && pgoff == rhs.pgoff
+ && baseAddr == rhs.baseAddr;
}
QFileInfo localFile;
@@ -68,7 +78,7 @@ public:
quint64 addr;
quint64 length;
quint64 pgoff;
-
+ quint64 baseAddr = INVALID_BASE_ADDR;
quint64 dwflStart = 0;
quint64 dwflEnd = 0;
};
@@ -90,6 +100,8 @@ public:
private:
// elf sorted by start address
QVector<ElfInfo> m_elfs;
+ // last registered elf with zero pgoff
+ ElfInfo m_lastBase;
};
QT_BEGIN_NAMESPACE
diff --git a/app/perfsymboltable.cpp b/app/perfsymboltable.cpp
index 136c8c6..50e6fbc 100644
--- a/app/perfsymboltable.cpp
+++ b/app/perfsymboltable.cpp
@@ -496,6 +496,9 @@ Dwfl_Module *PerfSymbolTable::module(quint64 addr, const PerfElfMap::ElfInfo &el
if (!m_dwfl)
return nullptr;
+ if (elf.pgoff && elf.hasBaseAddr())
+ return module(addr, m_elfs.findElf(elf.baseAddr));
+
Dwfl_Module *mod = dwfl_addrmodule(m_dwfl, addr);
if (mod) {
diff --git a/app/perfsymboltable.h b/app/perfsymboltable.h
index c85edaa..b01268a 100644
--- a/app/perfsymboltable.h
+++ b/app/perfsymboltable.h
@@ -58,9 +58,6 @@ public:
PerfElfMap::ElfInfo findElf(quint64 ip) const;
- // Report an mmap to dwfl and parse it for symbols and inlines, or simply return it if dwfl has
- // it already
- Dwfl_Module *reportElf(const PerfElfMap::ElfInfo& elf);
// Find the module for the given address and report it if needed
Dwfl_Module *module(quint64 addr);
Dwfl_Module *module(quint64 addr, const PerfElfMap::ElfInfo &elf);
@@ -80,6 +77,9 @@ public:
bool cacheIsDirty() const { return m_cacheIsDirty; }
private:
+ // Report an mmap to dwfl and parse it for symbols and inlines, or simply return it if dwfl has
+ // it already
+ Dwfl_Module *reportElf(const PerfElfMap::ElfInfo& elf);
QFileInfo findFile(const char *path, const QString &fileName,
const QByteArray &buildId = QByteArray()) const;
diff --git a/tests/auto/elfmap/tst_elfmap.cpp b/tests/auto/elfmap/tst_elfmap.cpp
index f645577..6a38d09 100644
--- a/tests/auto/elfmap/tst_elfmap.cpp
+++ b/tests/auto/elfmap/tst_elfmap.cpp
@@ -187,12 +187,17 @@ private slots:
QCOMPARE(map.findElf(2200), extended);
// this has a gap, so don't extend directly
- const PerfElfMap::ElfInfo fourth({}, 12000, 100, 100, "lalala.so", "/tmp/lalala.so");
+ PerfElfMap::ElfInfo fourth({}, 12000, 100, 100, "lalala.so", "/tmp/lalala.so");
registerElf(&map, fourth);
+ QVERIFY(!fourth.hasBaseAddr());
+ fourth.baseAddr = 0;
+ QVERIFY(fourth.hasBaseAddr());
QCOMPARE(map.findElf(12000), fourth);
- const PerfElfMap::ElfInfo fifth({}, 2000, 500, 3000, "lalala.so", "/tmp/lalala.so");
+ PerfElfMap::ElfInfo fifth({}, 2000, 500, 3000, "lalala.so", "/tmp/lalala.so");
+ 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");