summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMilian Wolff <milian.wolff@kdab.com>2017-03-06 23:29:18 +0100
committerMilian Wolff <milian.wolff@kdab.com>2017-03-29 14:53:50 +0000
commit17a5d15977856617979e08e68985123af3f7229a (patch)
tree471575a0712c37a25221ce5dd396062f8f73b3b1
parent3cf404e0fdf25297cb4ed3dee5105fb073844e31 (diff)
Pass an explicit Elf* to deduce the target architecture
Instead of reporting a random elf map, open the first elf manually and pass that to dwfl_attach_state. This will then be used to deduce the target architecture and thus gives us more control about what is going on, without influencing the actual mappings. A perf record for a runtime-attached profile could potentially contain mmap events for files first. This happened when attaching to KDevelop, which opens files internally using mmap. In such cases, we would try to guess the architecture from a text file containing code in text form, instead of a binary ELF, which of course did not work. Instead, validate the ELF we pass to dwfl_attach_state to guess the architecture via elf_kind. If that returns ELF_K_NONE, the file is not a valid ELF object and can thus not be used to guess the architecture. We simply silently skip this and try with the next elf file we encounter, until it hopefully works. Change-Id: I00ec7fa1da669c4b5ed9156654818b64bdf050ef Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r--app/perfelfmap.h13
-rw-r--r--app/perfsymboltable.cpp34
-rw-r--r--app/perfsymboltable.h3
-rw-r--r--tests/auto/elfmap/tst_elfmap.cpp7
4 files changed, 23 insertions, 34 deletions
diff --git a/app/perfelfmap.h b/app/perfelfmap.h
index 952ecde..936858c 100644
--- a/app/perfelfmap.h
+++ b/app/perfelfmap.h
@@ -58,9 +58,6 @@ public:
quint64 pgoff;
};
- using Map = QVector<ElfInfo>;
- using ConstIterator = Map::ConstIterator;
-
bool registerElf(quint64 addr, quint64 len, quint64 pgoff,
const QFileInfo &fullPath);
ElfInfo findElf(quint64 ip) const;
@@ -70,16 +67,6 @@ public:
return m_elfs.isEmpty();
}
- ConstIterator begin() const
- {
- return m_elfs.constBegin();
- }
-
- ConstIterator end() const
- {
- return m_elfs.constEnd();
- }
-
bool isAddressInRange(quint64 addr) const;
private:
diff --git a/app/perfsymboltable.cpp b/app/perfsymboltable.cpp
index da31c17..41f9c1e 100644
--- a/app/perfsymboltable.cpp
+++ b/app/perfsymboltable.cpp
@@ -35,8 +35,7 @@
PerfSymbolTable::PerfSymbolTable(quint32 pid, Dwfl_Callbacks *callbacks, PerfUnwind *parent) :
m_perfMapFile(QString::fromLatin1("/tmp/perf-%1.map").arg(pid)),
- m_unwind(parent), m_callbacks(callbacks),
- m_pid(pid)
+ m_unwind(parent), m_firstElf(nullptr), m_callbacks(callbacks), m_pid(pid)
{
m_dwfl = dwfl_begin(m_callbacks);
}
@@ -44,6 +43,7 @@ PerfSymbolTable::PerfSymbolTable(quint32 pid, Dwfl_Callbacks *callbacks, PerfUnw
PerfSymbolTable::~PerfSymbolTable()
{
dwfl_end(m_dwfl);
+ elf_end(m_firstElf);
}
static pid_t nextThread(Dwfl *dwfl, void *arg, void **threadArg)
@@ -197,6 +197,23 @@ void PerfSymbolTable::registerElf(const PerfRecordMmap &mmap, const QString &app
if (!found)
fullPath.setFile(systemRoot + filePath);
}
+
+ if (!m_firstElfFile.isOpen() && fullPath.exists()) {
+ m_firstElfFile.setFileName(fullPath.absoluteFilePath());
+ if (!m_firstElfFile.open(QIODevice::ReadOnly)) {
+ qWarning() << "Failed to open file:" << m_firstElfFile.errorString();
+ } else {
+ m_firstElf = elf_begin(m_firstElfFile.handle(), ELF_C_READ, nullptr);
+ if (!m_firstElf) {
+ qWarning() << "Failed to begin elf:" << elf_errmsg(elf_errno());
+ m_firstElfFile.close();
+ } else if (m_firstElf && elf_kind(m_firstElf) == ELF_K_NONE) {
+ // not actually an elf object
+ m_firstElf = nullptr;
+ m_firstElfFile.close();
+ }
+ }
+ }
} else { // kernel
fullPath.setFile(systemRoot + filePath);
}
@@ -537,18 +554,7 @@ Dwfl *PerfSymbolTable::attachDwfl(void *arg)
if (static_cast<pid_t>(m_pid) == dwfl_pid(m_dwfl))
return m_dwfl; // Already attached, nothing to do
- // Report some random elf, so that dwfl guesses the target architecture.
- for (const auto &elf : m_elfs) {
- if (!elf.isFile())
- continue;
- if (dwfl_report_elf(m_dwfl, elf.file.fileName().toLocal8Bit().constData(),
- elf.file.absoluteFilePath().toLocal8Bit().constData(), -1,
- elf.addr, false)) {
- break;
- }
- }
-
- if (!dwfl_attach_state(m_dwfl, 0, m_pid, &threadCallbacks, arg)) {
+ if (!dwfl_attach_state(m_dwfl, m_firstElf, m_pid, &threadCallbacks, arg)) {
qWarning() << m_pid << "failed to attach state" << dwfl_errmsg(dwfl_errno());
return nullptr;
}
diff --git a/app/perfsymboltable.h b/app/perfsymboltable.h
index 054404f..167489a 100644
--- a/app/perfsymboltable.h
+++ b/app/perfsymboltable.h
@@ -85,6 +85,9 @@ private:
PerfUnwind *m_unwind;
Dwfl *m_dwfl;
+ // elf used to detect architecture
+ QFile m_firstElfFile;
+ Elf *m_firstElf;
PerfElfMap m_elfs;
Dwfl_Callbacks *m_callbacks;
diff --git a/tests/auto/elfmap/tst_elfmap.cpp b/tests/auto/elfmap/tst_elfmap.cpp
index 7024f67..313c1b7 100644
--- a/tests/auto/elfmap/tst_elfmap.cpp
+++ b/tests/auto/elfmap/tst_elfmap.cpp
@@ -58,9 +58,6 @@ private slots:
QVERIFY(!registerElf(&map, first));
QVERIFY(!map.isEmpty());
- QCOMPARE(std::distance(map.begin(), map.end()), 1l);
- QCOMPARE(*map.begin(), first);
-
QCOMPARE(map.findElf(99), invalid);
QCOMPARE(map.findElf(100), first);
QCOMPARE(map.findElf(105), first);
@@ -70,10 +67,6 @@ private slots:
const PerfElfMap::ElfInfo second({}, 0, 10, 0);
QVERIFY(!registerElf(&map, second));
- QCOMPARE(std::distance(map.begin(), map.end()), 2l);
- QCOMPARE(*map.begin(), second);
- QCOMPARE(*(map.begin()+1), first);
-
QCOMPARE(map.findElf(0), second);
QCOMPARE(map.findElf(5), second);
QCOMPARE(map.findElf(9), second);