diff options
author | Milian Wolff <milian.wolff@kdab.com> | 2017-03-06 23:29:18 +0100 |
---|---|---|
committer | Milian Wolff <milian.wolff@kdab.com> | 2017-03-29 14:53:50 +0000 |
commit | 17a5d15977856617979e08e68985123af3f7229a (patch) | |
tree | 471575a0712c37a25221ce5dd396062f8f73b3b1 | |
parent | 3cf404e0fdf25297cb4ed3dee5105fb073844e31 (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.h | 13 | ||||
-rw-r--r-- | app/perfsymboltable.cpp | 34 | ||||
-rw-r--r-- | app/perfsymboltable.h | 3 | ||||
-rw-r--r-- | tests/auto/elfmap/tst_elfmap.cpp | 7 |
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); |