diff options
Diffstat (limited to 'app/perfsymboltable.cpp')
-rw-r--r-- | app/perfsymboltable.cpp | 436 |
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()); +} |