From 61be8779509a3c9c7d223cb072a57c16df83e344 Mon Sep 17 00:00:00 2001 From: dknysh Date: Mon, 21 Sep 2020 19:14:01 +0700 Subject: [PATCH] Added Disassembler functionality. Added mangled symbol name, start address and size into Symbol and their stream output. --- app/perfaddresscache.h | 5 ++- app/perfsymboltable.cpp | 32 ++++++++++++-------- app/perfsymboltable.h | 6 ++-- app/perfunwind.cpp | 2 +- app/perfunwind.h | 7 +++-- tests/auto/addresscache/tst_addresscache.cpp | 2 +- 6 files changed, 34 insertions(+), 20 deletions(-) diff --git a/app/perfaddresscache.h b/app/perfaddresscache.h index 6bc780d..7c974f9 100644 --- a/app/perfaddresscache.h +++ b/app/perfaddresscache.h @@ -42,8 +42,9 @@ class PerfAddressCache struct SymbolCacheEntry { - SymbolCacheEntry(quint64 offset = 0, quint64 size = 0, const QByteArray &symname = {}) + SymbolCacheEntry(quint64 offset = 0, quint64 value = 0, quint64 size = 0, const QByteArray &symname = {}) : offset(offset) + , value(value) , size(size) , symname(symname) {} @@ -51,6 +52,8 @@ class PerfAddressCache bool isValid() const { return !symname.isEmpty(); } quint64 offset; + // st_value in elf symbol table entry + quint64 value; quint64 size; QByteArray symname; bool demangled = false; diff --git a/app/perfsymboltable.cpp b/app/perfsymboltable.cpp index 7fed6d0..7a6ff8a 100644 --- a/app/perfsymboltable.cpp +++ b/app/perfsymboltable.cpp @@ -317,6 +317,7 @@ void PerfSymbolTable::registerElf(const PerfRecordMmap &mmap, const QByteArray & } int PerfSymbolTable::insertSubprogram(CuDieRangeMapping *cudie, Dwarf_Die *top, Dwarf_Addr entry, + quint64 offset, quint64 size, qint32 binaryId, qint32 binaryPathId, qint32 inlineCallLocationId, bool isKernel) { @@ -329,13 +330,15 @@ int PerfSymbolTable::insertSubprogram(CuDieRangeMapping *cudie, Dwarf_Die *top, qint32 fileId = m_unwind->resolveString(file); int locationId = m_unwind->resolveLocation(PerfUnwind::Location(entry, fileId, m_pid, line, column, inlineCallLocationId)); - qint32 symId = m_unwind->resolveString(cudie->dieName(top)); - m_unwind->resolveSymbol(locationId, PerfUnwind::Symbol(symId, binaryId, binaryPathId, isKernel)); + const auto mangled = cudie->dieName(top); + const auto mangledSymId = m_unwind->resolveString(mangled); + const auto symId = m_unwind->resolveString(demangle(mangled)); + m_unwind->resolveSymbol(locationId, PerfUnwind::Symbol(symId, mangledSymId, offset, size, binaryId, binaryPathId, isKernel)); return locationId; } -int PerfSymbolTable::parseDie(CuDieRangeMapping *cudie, Dwarf_Die *top, qint32 binaryId, qint32 binaryPathId, +int PerfSymbolTable::parseDie(CuDieRangeMapping *cudie, Dwarf_Die *top, quint64 offset, quint64 size, qint32 binaryId, qint32 binaryPathId, bool isKernel, Dwarf_Files *files, Dwarf_Addr entry, qint32 parentLocationId) { int tag = dwarf_tag(top); @@ -359,17 +362,17 @@ int PerfSymbolTable::parseDie(CuDieRangeMapping *cudie, Dwarf_Die *top, qint32 b location.parentLocationId = parentLocationId; int callLocationId = m_unwind->resolveLocation(location); - return insertSubprogram(cudie, top, entry, binaryId, binaryPathId, callLocationId, isKernel); + return insertSubprogram(cudie, top, entry, offset, size, binaryId, binaryPathId, callLocationId, isKernel); } case DW_TAG_subprogram: - return insertSubprogram(cudie, top, entry, binaryId, binaryPathId, -1, isKernel); + return insertSubprogram(cudie, top, entry, offset, size, binaryId, binaryPathId, -1, isKernel); default: return -1; } } qint32 PerfSymbolTable::parseDwarf(CuDieRangeMapping *cudie, SubProgramDie *subprogram, const QVector &inlined, - Dwarf_Addr bias, qint32 binaryId, qint32 binaryPathId, bool isKernel) + Dwarf_Addr bias, quint64 offset, quint64 size, qint32 binaryId, qint32 binaryPathId, bool isKernel) { Dwarf_Files *files = nullptr; dwarf_getsrcfiles(cudie->cudie(), &files, nullptr); @@ -381,7 +384,7 @@ qint32 PerfSymbolTable::parseDwarf(CuDieRangeMapping *cudie, SubProgramDie *subp if (dwarf_entrypc(&scope, &entry) == 0 && entry != 0) scopeAddr += entry; - auto locationId = parseDie(cudie, &scope, binaryId, binaryPathId, isKernel, files, scopeAddr, parentLocationId); + auto locationId = parseDie(cudie, &scope, offset, size, binaryId, binaryPathId, isKernel, files, scopeAddr, parentLocationId); if (locationId != -1) parentLocationId = locationId; }; @@ -732,7 +735,7 @@ static PerfAddressCache::SymbolCache cacheSymbols(Dwfl_Module *module, quint64 e GElf_Addr symAddr; const auto symbol = dwfl_module_getsym_info(module, i, &sym, &symAddr, nullptr, nullptr, nullptr); if (symbol) - cache.append({symAddr - elfStart, sym.st_size, symbol}); + cache.append({symAddr - elfStart, sym.st_value, sym.st_size, symbol}); } return cache; } @@ -768,6 +771,8 @@ int PerfSymbolTable::lookupFrame(Dwarf_Addr ip, bool isKernel, QByteArray symname; GElf_Off off = 0; + quint64 start = 0; + quint64 size = 0; if (mod) { if (!addressCache->hasSymbolCache(elf.originalPath)) { // cache all symbols in a sorted lookup table and demangle them on-demand @@ -780,6 +785,8 @@ int PerfSymbolTable::lookupFrame(Dwarf_Addr ip, bool isKernel, if (cachedAddrInfo.isValid()) { off = addressLocation.address - elfStart - cachedAddrInfo.offset; symname = cachedAddrInfo.symname; + start = cachedAddrInfo.value; + size = cachedAddrInfo.size; Dwarf_Addr bias = 0; functionLocation.address -= off; // in case we don't find anything better @@ -821,7 +828,7 @@ int PerfSymbolTable::lookupFrame(Dwarf_Addr ip, bool isKernel, 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, + functionLocation.parentLocationId = parseDwarf(cudie, subprogram, scopes, bias, start, size, binaryId, binaryPathId, isKernel); } } @@ -838,9 +845,10 @@ int PerfSymbolTable::lookupFrame(Dwarf_Addr ip, bool isKernel, if (!m_unwind->hasSymbol(addressLocation.parentLocationId)) { // no sufficient debug information. Use what we already know - qint32 symId = m_unwind->resolveString(symname); + qint32 symId = m_unwind->resolveString(demangle(symname)); + qint32 mangledSymId = m_unwind->resolveString(symname); m_unwind->resolveSymbol(addressLocation.parentLocationId, - PerfUnwind::Symbol(symId, binaryId, binaryPathId, isKernel)); + PerfUnwind::Symbol(symId, mangledSymId, start, size, binaryId, binaryPathId, isKernel)); } } else { if (isKernel) { @@ -861,7 +869,7 @@ 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, symId, start, size, binaryId, binaryPathId, isKernel)); } } diff --git a/app/perfsymboltable.h b/app/perfsymboltable.h index 526834b..fe2082e 100644 --- a/app/perfsymboltable.h +++ b/app/perfsymboltable.h @@ -122,12 +122,12 @@ class PerfSymbolTable qint32 m_pid; QByteArray symbolFromPerfMap(quint64 ip, GElf_Off *offset) const; - int parseDie(CuDieRangeMapping *cudie, Dwarf_Die *top, qint32 binaryId, qint32 binaryPathId, bool isKernel, + int parseDie(CuDieRangeMapping *cudie, Dwarf_Die *top, quint64 offset, quint64 size, qint32 binaryId, qint32 binaryPathId, bool isKernel, Dwarf_Files *files, Dwarf_Addr entry, qint32 parentLocationId); - int insertSubprogram(CuDieRangeMapping *cudie, Dwarf_Die *top, Dwarf_Addr entry, qint32 binaryId, qint32 binaryPathId, + int insertSubprogram(CuDieRangeMapping *cudie, Dwarf_Die *top, Dwarf_Addr entry, quint64 offset, quint64 size, qint32 binaryId, qint32 binaryPathId, qint32 inlineParent, bool isKernel); qint32 parseDwarf(CuDieRangeMapping *cudie, SubProgramDie *subprogram, const QVector &inlined, - Dwarf_Addr bias, qint32 binaryId, qint32 binaryPathId, bool isKernel); + Dwarf_Addr bias, quint64 offset, quint64 size, qint32 binaryId, qint32 binaryPathId, bool isKernel); }; QT_BEGIN_NAMESPACE diff --git a/app/perfunwind.cpp b/app/perfunwind.cpp index 5c241eb..bfe45e6 100644 --- a/app/perfunwind.cpp +++ b/app/perfunwind.cpp @@ -365,7 +365,7 @@ QDataStream &operator<<(QDataStream &stream, const PerfUnwind::Location &locatio QDataStream &operator<<(QDataStream &stream, const PerfUnwind::Symbol &symbol) { - return stream << symbol.name << symbol.binary << symbol.path << symbol.isKernel; + return stream << symbol.name << symbol.mangled << symbol.relAddr << symbol.size << symbol.binary << symbol.path << symbol.isKernel; } static int frameCallback(Dwfl_Frame *state, void *arg) diff --git a/app/perfunwind.h b/app/perfunwind.h index 5e5a0b1..a3be244 100644 --- a/app/perfunwind.h +++ b/app/perfunwind.h @@ -79,12 +79,15 @@ class PerfUnwind : public QObject }; struct Symbol { - explicit Symbol(qint32 name = -1, qint32 binary = -1, qint32 path = -1, + explicit Symbol(qint32 name = -1, qint32 mangled = -1, quint64 relAddr = 0, quint64 size = 0, qint32 binary = -1, qint32 path = -1, bool isKernel = false) : - name(name), binary(binary), path(path), isKernel(isKernel) + name(name), mangled(mangled), relAddr(relAddr), size(size), binary(binary), path(path), isKernel(isKernel) {} qint32 name; + qint32 mangled; + quint64 relAddr; + quint64 size; qint32 binary; qint32 path; bool isKernel; diff --git a/tests/auto/addresscache/tst_addresscache.cpp b/tests/auto/addresscache/tst_addresscache.cpp index 4ffb8ba..9b02a85 100644 --- a/tests/auto/addresscache/tst_addresscache.cpp +++ b/tests/auto/addresscache/tst_addresscache.cpp @@ -72,7 +72,7 @@ private slots: QVERIFY(!cache.findSymbol(libfoo_a, 0).isValid()); QVERIFY(!cache.findSymbol(libfoo_b, 0).isValid()); - cache.setSymbolCache(libfoo_a, {{0x100, 10, "Foo"}, {0x11a, 0, "FooZ"}, {0x12a, 10, "FooN"}}); + cache.setSymbolCache(libfoo_a, {{0x100, 0x100, 10, "Foo"}, {0x11a, 0x11a, 0, "FooZ"}, {0x12a, 0x12a, 10, "FooN"}}); for (auto addr : {0x100, 0x100 + 9}) { const auto cached = cache.findSymbol(libfoo_a, addr); QVERIFY(cached.isValid());