summaryrefslogtreecommitdiffstats
path: root/app/perfsymboltable.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'app/perfsymboltable.cpp')
-rw-r--r--app/perfsymboltable.cpp436
1 files changed, 148 insertions, 288 deletions
diff --git a/app/perfsymboltable.cpp b/app/perfsymboltable.cpp
index 07d6f3a..7fb19ec 100644
--- a/app/perfsymboltable.cpp
+++ b/app/perfsymboltable.cpp
@@ -25,8 +25,8 @@
#include "perfsymboltable.h"
#include "perfunwind.h"
-
-#include <dwarf.h>
+#include "perfdwarfdiecache.h"
+#include "perfeucompat.h"
#include <QDebug>
#include <QDir>
@@ -34,21 +34,8 @@
#include <tuple>
#include <cstring>
-#include <fcntl.h>
-
-#ifdef Q_OS_WIN
-#include <libeu_compat.h>
-#else
-#include <cxxabi.h>
-#include <unistd.h>
-#define eu_compat_open open
-#define eu_compat_close close
-#define eu_compat_malloc malloc
-#define eu_compat_free free
-#define eu_compat_demangle abi::__cxa_demangle
-#define eu_compat_strdup strdup
-#define O_BINARY 0
-#endif
+
+#include <dwarf.h>
PerfSymbolTable::PerfSymbolTable(qint32 pid, Dwfl_Callbacks *callbacks, PerfUnwind *parent) :
m_perfMapFile(QDir::tempPath() + QDir::separator()
@@ -143,7 +130,7 @@ static bool memoryRead(Dwfl *, Dwarf_Addr addr, Dwarf_Word *result, void *arg)
/* Check overflow. */
if (addr + sizeof(Dwarf_Word) < addr) {
- qDebug() << "Invalid memory read requested by dwfl" << hex << addr;
+ qDebug() << "Invalid memory read requested by dwfl" << Qt::hex << addr;
ui->firstGuessedFrame = ui->frames.length();
return false;
}
@@ -159,7 +146,7 @@ static bool memoryRead(Dwfl *, Dwarf_Addr addr, Dwarf_Word *result, void *arg)
// not stack, try reading from ELF
if (ui->unwind->ipIsInKernelSpace(addr)) {
// DWARF unwinding is not done for the kernel
- qWarning() << "DWARF unwind tried to access kernel space" << hex << addr;
+ qWarning() << "DWARF unwind tried to access kernel space" << Qt::hex << addr;
return false;
}
if (!accessDsoMem(ui, addr, result, wordWidth)) {
@@ -247,7 +234,7 @@ static bool findBuildIdPath(QFileInfo &path, const QString &fileName)
static QStringList splitPath(const QString &path)
{
- return path.split(QDir::listSeparator(), QString::SkipEmptyParts);
+ return path.split(QDir::listSeparator(), Qt::SkipEmptyParts);
}
QFileInfo PerfSymbolTable::findFile(const char *path, const QString &fileName,
@@ -329,41 +316,9 @@ void PerfSymbolTable::registerElf(const PerfRecordMmap &mmap, const QByteArray &
clearCache();
}
-static QByteArray dieName(Dwarf_Die *die)
-{
- Dwarf_Attribute attr;
- Dwarf_Attribute *result = dwarf_attr_integrate(die, DW_AT_MIPS_linkage_name, &attr);
- if (!result)
- result = dwarf_attr_integrate(die, DW_AT_linkage_name, &attr);
-
- const char *name = dwarf_formstring(result);
- if (!name)
- name = dwarf_diename(die);
-
- return name ? name : "";
-}
-
-static QByteArray demangle(const QByteArray &mangledName)
-{
- if (mangledName.length() < 3) {
- return mangledName;
- } else {
- static size_t demangleBufferLength = 0;
- static char *demangleBuffer = nullptr;
-
- // Require GNU v3 ABI by the "_Z" prefix.
- if (mangledName[0] == '_' && mangledName[1] == 'Z') {
- int status = -1;
- char *dsymname = eu_compat_demangle(mangledName, demangleBuffer, &demangleBufferLength,
- &status);
- if (status == 0)
- return demangleBuffer = dsymname;
- }
- }
- return mangledName;
-}
-
-int PerfSymbolTable::insertSubprogram(Dwarf_Die *top, Dwarf_Addr entry, qint32 binaryId, qint32 binaryPathId,
+int PerfSymbolTable::insertSubprogram(CuDieRangeMapping *cudie, Dwarf_Die *top, Dwarf_Addr entry,
+ quint64 offset, quint64 size, quint64 relAddr,
+ qint32 binaryId, qint32 binaryPathId, qint32 actualPathId,
qint32 inlineCallLocationId, bool isKernel)
{
int line = 0;
@@ -373,16 +328,16 @@ int PerfSymbolTable::insertSubprogram(Dwarf_Die *top, Dwarf_Addr entry, qint32 b
const QByteArray file = dwarf_decl_file(top);
qint32 fileId = m_unwind->resolveString(file);
- int locationId = m_unwind->resolveLocation(PerfUnwind::Location(entry, fileId, m_pid, line,
+ int locationId = m_unwind->resolveLocation(PerfUnwind::Location(entry, relAddr, fileId, m_pid, line,
column, inlineCallLocationId));
- qint32 symId = m_unwind->resolveString(demangle(dieName(top)));
- m_unwind->resolveSymbol(locationId, PerfUnwind::Symbol(symId, binaryId, binaryPathId, isKernel));
+ qint32 symId = m_unwind->resolveString(cudie->dieName(top));
+ m_unwind->resolveSymbol(locationId, PerfUnwind::Symbol{symId, offset, size, binaryId, binaryPathId, actualPathId, isKernel});
return locationId;
}
-int PerfSymbolTable::parseDie(Dwarf_Die *top, qint32 binaryId, qint32 binaryPathId, bool isKernel,
- Dwarf_Files *files, Dwarf_Addr entry, qint32 parentLocationId)
+int PerfSymbolTable::parseDie(CuDieRangeMapping *cudie, Dwarf_Die *top, quint64 offset, quint64 size, quint64 relAddr, qint32 binaryId, qint32 binaryPathId, qint32 actualPathId,
+ bool isKernel, Dwarf_Files *files, Dwarf_Addr entry, qint32 parentLocationId)
{
int tag = dwarf_tag(top);
switch (tag) {
@@ -405,38 +360,35 @@ int PerfSymbolTable::parseDie(Dwarf_Die *top, qint32 binaryId, qint32 binaryPath
location.parentLocationId = parentLocationId;
int callLocationId = m_unwind->resolveLocation(location);
- return insertSubprogram(top, entry, binaryId, binaryPathId, callLocationId, isKernel);
+ return insertSubprogram(cudie, top, entry, offset, size, relAddr, binaryId, binaryPathId, actualPathId, callLocationId, isKernel);
}
case DW_TAG_subprogram:
- return insertSubprogram(top, entry, binaryId, binaryPathId, -1, isKernel);
+ return insertSubprogram(cudie, top, entry, offset, size, relAddr, binaryId, binaryPathId, actualPathId, -1, isKernel);
default:
return -1;
}
}
-qint32 PerfSymbolTable::parseDwarf(Dwarf_Die *cudie, Dwarf_Die *subroutine, Dwarf_Addr bias, qint32 binaryId,
- qint32 binaryPathId, bool isKernel)
+qint32 PerfSymbolTable::parseDwarf(CuDieRangeMapping *cudie, SubProgramDie *subprogram, const QVector<Dwarf_Die> &inlined,
+ Dwarf_Addr bias, quint64 offset, quint64 size, quint64 relAddr, qint32 binaryId, qint32 binaryPathId, qint32 actualPathId, bool isKernel)
{
- Dwarf_Die *scopes = nullptr;
- const auto nscopes = dwarf_getscopes_die(subroutine, &scopes);
-
Dwarf_Files *files = nullptr;
- dwarf_getsrcfiles(cudie, &files, nullptr);
+ dwarf_getsrcfiles(cudie->cudie(), &files, nullptr);
qint32 parentLocationId = -1;
- for (int i = nscopes - 1; i >= 0; --i) {
- const auto scope = &scopes[i];
+ auto handleDie = [&](Dwarf_Die scope) {
Dwarf_Addr scopeAddr = bias;
Dwarf_Addr entry = 0;
- if (dwarf_entrypc(scope, &entry) == 0 && entry != 0)
+ if (dwarf_entrypc(&scope, &entry) == 0 && entry != 0)
scopeAddr += entry;
- auto locationId = parseDie(scope, binaryId, binaryPathId, isKernel, files, scopeAddr, parentLocationId);
+ auto locationId = parseDie(cudie, &scope, offset, size, relAddr, binaryId, binaryPathId, actualPathId, isKernel, files, scopeAddr, parentLocationId);
if (locationId != -1)
parentLocationId = locationId;
- }
+ };
- eu_compat_free(scopes);
+ handleDie(*subprogram->die());
+ std::for_each(inlined.begin(), inlined.end(), handleDie);
return parentLocationId;
}
@@ -484,16 +436,15 @@ 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;
}
Dwfl_Module *mod = dwfl_addrmodule(m_dwfl, addr);
- if (!mod) {
+ if (!mod && elf.isValid()) {
// check whether we queried for an address outside the elf range parsed
// by dwfl. If that is the case, then we would invalidate the cache and
// re-report the library again - essentially recreating the current state
@@ -599,156 +550,6 @@ PerfElfMap::ElfInfo PerfSymbolTable::findElf(quint64 ip) const
return m_elfs.findElf(ip);
}
-struct AddrRange
-{
- Dwarf_Addr low = 0;
- Dwarf_Addr high = 0;
-
- void setMinMax(const AddrRange range)
- {
- if (range.low && (low == 0 || low > range.low))
- low = range.low;
- if (range.high && (high == 0 || high < range.high))
- high = range.high;
- }
-
- bool contains(Dwarf_Addr addr) const
- {
- return low <= addr && addr < high;
- }
-
- bool operator<(const AddrRange &rhs) const
- {
- return std::tie(low, high) < std::tie(rhs.low, rhs.high);
- }
-};
-QT_BEGIN_NAMESPACE
-Q_DECLARE_TYPEINFO(AddrRange, Q_MOVABLE_TYPE);
-QT_END_NAMESPACE
-
-struct DieRangeMap
-{
- DieRangeMap(Dwarf_Die *die = nullptr, Dwarf_Addr bias = 0)
- : die(die)
- , bias(bias)
- {
- if (die)
- gatherRanges(die, bias);
- }
-
- bool contains(Dwarf_Addr addr) const
- {
- if (!range.contains(addr))
- return false;
- return std::any_of(ranges.begin(), ranges.end(),
- [addr](AddrRange range) {
- return range.contains(addr);
- });
- }
-
- bool operator<(const DieRangeMap &rhs) const
- {
- return range < rhs.range;
- }
-
- Dwarf_Die *die = nullptr;
- AddrRange range; // may be non-continuous, but allows quick checks and sorting
- QVector<AddrRange> ranges;
- Dwarf_Addr bias;
-
-private:
- void gatherRanges(Dwarf_Die *parent_die, Dwarf_Addr bias)
- {
- Dwarf_Die die;
- if (dwarf_child(parent_die, &die) != 0)
- return;
-
- do {
- switch (dwarf_tag(&die)) {
- case DW_TAG_subprogram:
- case DW_TAG_inlined_subroutine:
- addRanges(&die, bias);
- break;
- };
- bool declaration = false;
- Dwarf_Attribute attr_mem;
- dwarf_formflag(dwarf_attr(&die, DW_AT_declaration, &attr_mem), &declaration);
- if (!declaration) {
- // let's be curious and look deeper in the tree,
- // function are not necessarily at the first level, but
- // might be nested inside a namespace, structure etc.
- gatherRanges(&die, bias);
- }
- } while (dwarf_siblingof(&die, &die) == 0);
- }
-
- void addRanges(Dwarf_Die *die, Dwarf_Addr bias)
- {
- Dwarf_Addr low = 0, high = 0;
- Dwarf_Addr base = 0;
- ptrdiff_t offset = 0;
- while ((offset = dwarf_ranges(die, offset, &base, &low, &high)) > 0) {
- addRange(low, high, bias);
- }
- }
-
- void addRange(Dwarf_Addr low, Dwarf_Addr high, Dwarf_Addr bias)
- {
- AddrRange ret;
- ret.low = low + bias;
- ret.high = high + bias;
- range.setMinMax(ret);
- ranges.push_back(ret);
- }
-};
-QT_BEGIN_NAMESPACE
-Q_DECLARE_TYPEINFO(DieRangeMap, Q_MOVABLE_TYPE);
-QT_END_NAMESPACE
-
-class DieRangeMaps
-{
-public:
- DieRangeMaps(Dwfl_Module *mod = nullptr)
- {
- if (!mod)
- return;
-
- Dwarf_Die *die = nullptr;
- Dwarf_Addr bias = 0;
- while ((die = dwfl_module_nextcu(mod, die, &bias))) {
- DieRangeMap map(die, bias);
- if (map.range.low == 0 && map.range.high == 0) {
- // no range entries, skip
- continue;
- }
- range.setMinMax(map.range);
- maps.push_back(std::move(map));
- }
- }
-
- Dwarf_Die *findDie(Dwarf_Addr addr, Dwarf_Addr *bias) const
- {
- if (!range.contains(addr))
- return nullptr;
-
- auto it = std::find_if(maps.begin(), maps.end(),
- [addr](const DieRangeMap &map) {
- return map.contains(addr);
- });
- if (it == maps.end())
- return nullptr;
-
- *bias = it->bias;
- return it->die;
- }
-public:
- AddrRange range; // may be non-continuous, but allows quick checks
- QVector<DieRangeMap> maps;
-};
-QT_BEGIN_NAMESPACE
-Q_DECLARE_TYPEINFO(DieRangeMaps, Q_MOVABLE_TYPE);
-QT_END_NAMESPACE
-
int symbolIndex(const Elf64_Rel &rel)
{
return ELF64_R_SYM(rel.r_info);
@@ -922,11 +723,42 @@ static QByteArray fakeSymbolFromSection(Dwfl_Module *mod, Dwarf_Addr addr)
return sym;
}
+static quint64 symbolAddress(quint64 addr, bool isArmArch)
+{
+ // For dwfl API call we need the raw pointer into symtab, so we need to adjust ip.
+ return (!isArmArch || (addr & 1)) ? addr : addr + 1;
+}
+
+static quint64 alignedAddress(quint64 addr, bool isArmArch)
+{
+ // Adjust addr back. The symtab entries are 1 off for all practical purposes.
+ return (isArmArch && (addr & 1)) ? addr - 1 : addr;
+}
+
+static PerfAddressCache::SymbolCache cacheSymbols(Dwfl_Module *module, quint64 elfStart, bool isArmArch)
+{
+ PerfAddressCache::SymbolCache cache;
+
+ const auto numSymbols = dwfl_module_getsymtab(module);
+ for (int i = 0; i < numSymbols; ++i) {
+ GElf_Sym sym;
+ GElf_Addr symAddr;
+ const auto symbol = dwfl_module_getsym_info(module, i, &sym, &symAddr, nullptr, nullptr, nullptr);
+ if (symbol) {
+ const quint64 start = alignedAddress(sym.st_value, isArmArch);
+ cache.append({symAddr - elfStart, start, sym.st_size, symbol});
+ }
+ }
+ return cache;
+}
+
int PerfSymbolTable::lookupFrame(Dwarf_Addr ip, bool isKernel,
bool *isInterworking)
{
+ auto addressCache = m_unwind->addressCache();
+
const auto& elf = findElf(ip);
- auto cached = m_addressCache.find(elf, ip);
+ auto cached = addressCache->find(elf, ip, &m_invalidAddressCache);
if (cached.isValid()) {
*isInterworking = cached.isInterworking;
return cached.locationId;
@@ -934,50 +766,54 @@ int PerfSymbolTable::lookupFrame(Dwarf_Addr ip, bool isKernel,
qint32 binaryId = -1;
qint32 binaryPathId = -1;
+ qint32 actualPathId = -1;
quint64 elfStart = 0;
if (elf.isValid()) {
binaryId = m_unwind->resolveString(elf.originalFileName);
binaryPathId = m_unwind->resolveString(elf.originalPath);
- elfStart = elf.addr;
+ actualPathId = m_unwind->resolveString(elf.localFile.absoluteFilePath().toUtf8());
+ elfStart = elf.hasBaseAddr() ? elf.baseAddr : elf.addr;
}
Dwfl_Module *mod = module(ip, elf);
- PerfUnwind::Location addressLocation(
- (m_unwind->architecture() != PerfRegisterInfo::ARCH_ARM || (ip & 1))
- ? ip : ip + 1, -1, m_pid);
+ const bool isArmArch = (m_unwind->architecture() == PerfRegisterInfo::ARCH_ARM);
+ PerfUnwind::Location addressLocation(symbolAddress(ip, isArmArch), 0, -1, m_pid);
PerfUnwind::Location functionLocation(addressLocation);
QByteArray symname;
- GElf_Sym sym;
GElf_Off off = 0;
+ quint64 start = 0;
+ quint64 size = 0;
+ quint64 relAddr = 0;
if (mod) {
- // For addrinfo we need the raw pointer into symtab, so we need to adjust ourselves.
- symname = dwfl_module_addrinfo(mod, addressLocation.address, &off, &sym, nullptr, nullptr,
- nullptr);
+ if (!addressCache->hasSymbolCache(elf.originalPath)) {
+ // cache all symbols in a sorted lookup table and demangle them on-demand
+ // note that the symbols within the symtab aren't necessarily sorted,
+ // which makes searching repeatedly via dwfl_module_addrinfo potentially very slow
+ addressCache->setSymbolCache(elf.originalPath, cacheSymbols(mod, elfStart, isArmArch));
+ }
+
+ auto cachedAddrInfo = addressCache->findSymbol(elf.originalPath, addressLocation.address - elfStart);
+ if (cachedAddrInfo.isValid()) {
+ off = addressLocation.address - elfStart - cachedAddrInfo.offset;
+ symname = cachedAddrInfo.symname;
+ start = cachedAddrInfo.value;
+ size = cachedAddrInfo.size;
+ relAddr = alignedAddress(start + off, isArmArch);
- if (off == addressLocation.address) {// no symbol found
- symname = fakeSymbolFromSection(mod, addressLocation.address);
- addressLocation.parentLocationId = m_unwind->resolveLocation(functionLocation);
- } else {
Dwarf_Addr bias = 0;
functionLocation.address -= off; // in case we don't find anything better
- auto die = dwfl_module_addrdie(mod, addressLocation.address, &bias);
- if (!die) {
- // broken DWARF emitter by clang, e.g. no aranges
- // cf.: https://sourceware.org/ml/elfutils-devel/2017-q2/msg00180.html
- // build a custom lookup table and query that one
- if (!m_dieRangeMaps.contains(mod)) {
- m_dieRangeMaps[mod] = DieRangeMaps(mod);
- }
- const auto& maps = m_dieRangeMaps[mod];
- die = maps.findDie(addressLocation.address, &bias);
- }
+ if (!m_cuDieRanges.contains(mod))
+ m_cuDieRanges[mod] = PerfDwarfDieCache(mod);
- if (die) {
- auto srcloc = dwarf_getsrc_die(die, addressLocation.address - bias);
+ auto *cudie = m_cuDieRanges[mod].findCuDie(addressLocation.address);
+ if (cudie) {
+ bias = cudie->bias();
+ const auto offset = addressLocation.address - bias;
+ auto srcloc = dwarf_getsrc_die(cudie->cudie(), offset);
if (srcloc) {
const char* srcfile = dwarf_linesrc(srcloc, nullptr, nullptr);
if (srcfile) {
@@ -987,44 +823,46 @@ int PerfSymbolTable::lookupFrame(Dwarf_Addr ip, bool isKernel,
dwarf_linecol(srcloc, &addressLocation.column);
}
}
- }
- Dwarf_Die *subroutine = nullptr;
- Dwarf_Die *scopes = nullptr;
- int nscopes = dwarf_getscopes(die, addressLocation.address - bias, &scopes);
- for (int i = 0; i < nscopes; ++i) {
- Dwarf_Die *scope = &scopes[i];
- const int tag = dwarf_tag(scope);
- if (tag == DW_TAG_subprogram || tag == DW_TAG_inlined_subroutine) {
- Dwarf_Addr entry = 0;
- dwarf_entrypc(scope, &entry);
- symname = dieName(scope); // use name of inlined function as symbol
- functionLocation.address = entry + bias;
- functionLocation.file = m_unwind->resolveString(dwarf_decl_file(scope));
- dwarf_decl_line(scope, &functionLocation.line);
- dwarf_decl_column(scope, &functionLocation.column);
-
- subroutine = scope;
- break;
+ auto *subprogram = cudie->findSubprogramDie(offset);
+ if (subprogram) {
+ const auto scopes = findInlineScopes(subprogram->die(), offset);
+
+ // setup function location, i.e. entry point of the (inlined) frame
+ [&](Dwarf_Die die) {
+ Dwarf_Addr entry = 0;
+ dwarf_entrypc(&die, &entry);
+ symname = cudie->dieName(&die); // use name of inlined function as symbol
+ functionLocation.address = entry + bias;
+ functionLocation.file = m_unwind->resolveString(dwarf_decl_file(&die));
+ dwarf_decl_line(&die, &functionLocation.line);
+ dwarf_decl_column(&die, &functionLocation.column);
+ }(scopes.isEmpty() ? *subprogram->die() : scopes.last());
+
+ // check if the inline chain was cached already
+ addressLocation.parentLocationId = m_unwind->lookupLocation(functionLocation);
+ // otherwise resolve the inline chain if possible
+ if (!scopes.isEmpty() && !m_unwind->hasSymbol(addressLocation.parentLocationId)) {
+ functionLocation.parentLocationId = parseDwarf(cudie, subprogram, scopes, bias, start, size, relAddr,
+ binaryId, binaryPathId, actualPathId, isKernel);
+ }
}
}
- // check if the inline chain was cached already
- addressLocation.parentLocationId = m_unwind->lookupLocation(functionLocation);
- // otherwise resolve the inline chain if possible
- if (subroutine && !m_unwind->hasSymbol(addressLocation.parentLocationId))
- functionLocation.parentLocationId = parseDwarf(die, subroutine, bias, binaryId, binaryPathId, isKernel);
- // then resolve and cache the inline chain
+ // resolve and cache the inline chain
if (addressLocation.parentLocationId == -1)
addressLocation.parentLocationId = m_unwind->resolveLocation(functionLocation);
-
- eu_compat_free(scopes);
+ } else {
+ // no symbol found
+ symname = fakeSymbolFromSection(mod, addressLocation.address);
+ addressLocation.parentLocationId = m_unwind->resolveLocation(functionLocation);
}
+
if (!m_unwind->hasSymbol(addressLocation.parentLocationId)) {
// no sufficient debug information. Use what we already know
- qint32 symId = m_unwind->resolveString(demangle(symname));
+ qint32 symId = m_unwind->resolveString(symname);
m_unwind->resolveSymbol(addressLocation.parentLocationId,
- PerfUnwind::Symbol(symId, binaryId, binaryPathId, isKernel));
+ PerfUnwind::Symbol(symId, start, size, binaryId, binaryPathId, actualPathId, isKernel));
}
} else {
if (isKernel) {
@@ -1045,16 +883,17 @@ int PerfSymbolTable::lookupFrame(Dwarf_Addr ip, bool isKernel,
if (!m_unwind->hasSymbol(addressLocation.parentLocationId)) {
qint32 symId = m_unwind->resolveString(symname);
m_unwind->resolveSymbol(addressLocation.parentLocationId,
- PerfUnwind::Symbol(symId, binaryId, binaryPathId, isKernel));
+ PerfUnwind::Symbol(symId, start, size, binaryId, binaryPathId, actualPathId, isKernel));
}
}
-
+ // relAddr - relative address of the function start added with offset from the function start
+ addressLocation.relAddr = relAddr;
Q_ASSERT(addressLocation.parentLocationId != -1);
Q_ASSERT(m_unwind->hasSymbol(addressLocation.parentLocationId));
int locationId = m_unwind->resolveLocation(addressLocation);
*isInterworking = (symname == "$a" || symname == "$t");
- m_addressCache.cache(elf, ip, {locationId, *isInterworking});
+ addressCache->cache(elf, ip, {locationId, *isInterworking}, &m_invalidAddressCache);
return locationId;
}
@@ -1082,6 +921,9 @@ QByteArray PerfSymbolTable::symbolFromPerfMap(quint64 ip, GElf_Off *offset) cons
void PerfSymbolTable::updatePerfMap()
{
+ if (!m_perfMapFile.exists())
+ return;
+
if (!m_perfMapFile.isOpen())
m_perfMapFile.open(QIODevice::ReadOnly);
@@ -1116,6 +958,16 @@ Dwfl *PerfSymbolTable::attachDwfl(void *arg)
if (static_cast<pid_t>(m_pid) == dwfl_pid(m_dwfl))
return m_dwfl; // Already attached, nothing to do
+ // only attach state when we have the required information for stack unwinding
+ // for normal symbol resolution and inline frame resolution this is not needed
+ // most notably, this isn't needed for frame pointer callchains
+ PerfUnwind::UnwindInfo *unwindInfo = static_cast<PerfUnwind::UnwindInfo *>(arg);
+ const auto sampleType = unwindInfo->sample->type();
+ const auto hasSampleRegsUser = (sampleType & PerfEventAttributes::SAMPLE_REGS_USER);
+ const auto hasSampleStackUser = (sampleType & PerfEventAttributes::SAMPLE_STACK_USER);
+ if (!hasSampleRegsUser || !hasSampleStackUser)
+ return nullptr;
+
if (!dwfl_attach_state(m_dwfl, m_firstElf.elf(), m_pid, &threadCallbacks, arg)) {
qWarning() << m_pid << "failed to attach state" << dwfl_errmsg(dwfl_errno());
return nullptr;
@@ -1126,8 +978,8 @@ Dwfl *PerfSymbolTable::attachDwfl(void *arg)
void PerfSymbolTable::clearCache()
{
- m_addressCache.clearInvalid();
- m_dieRangeMaps.clear();
+ m_invalidAddressCache.clear();
+ m_cuDieRanges.clear();
m_perfMap.clear();
if (m_perfMapFile.isOpen())
m_perfMapFile.reset();
@@ -1147,6 +999,7 @@ PerfSymbolTable::ElfAndFile &PerfSymbolTable::ElfAndFile::operator=(
clear();
m_elf = other.m_elf;
m_file = other.m_file;
+ m_fullPath = std::move(other.m_fullPath);
other.m_elf = nullptr;
other.m_file = -1;
}
@@ -1168,6 +1021,7 @@ void PerfSymbolTable::ElfAndFile::clear()
}
PerfSymbolTable::ElfAndFile::ElfAndFile(const QFileInfo &fullPath)
+ : m_fullPath(fullPath)
{
m_file = eu_compat_open(fullPath.absoluteFilePath().toLocal8Bit().constData(),
O_RDONLY | O_BINARY);
@@ -1182,8 +1036,14 @@ PerfSymbolTable::ElfAndFile::ElfAndFile(const QFileInfo &fullPath)
}
PerfSymbolTable::ElfAndFile::ElfAndFile(PerfSymbolTable::ElfAndFile &&other)
- : m_elf(other.m_elf), m_file(other.m_file)
+ : m_elf(other.m_elf), m_file(other.m_file), m_fullPath(std::move(other.m_fullPath))
{
other.m_elf = nullptr;
other.m_file = -1;
}
+
+void PerfSymbolTable::initAfterFork(const PerfSymbolTable* parent)
+{
+ m_elfs.copyDataFrom(&parent->m_elfs);
+ m_firstElf = ElfAndFile(parent->m_firstElf.fullPath());
+}