diff options
author | Ulf Hermann <ulf.hermann@theqtcompany.com> | 2015-02-04 17:13:02 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@theqtcompany.com> | 2015-02-16 18:04:42 +0200 |
commit | 43913f2aa5f2a2320fa92ee7fbd7ddd4d906781e (patch) | |
tree | a83b8cbdf6efb84af6c35b3b1076d4e184b81ee6 | |
parent | be7d6f47f4309270cf7d288db47580c7037eafb9 (diff) |
Use the CPU mode frames to report if symbols are in the kernel
Change-Id: I0b59c7cdcbfe050fd02a14ada52f22ee5d01d164
Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
-rw-r--r-- | perfunwind.cpp | 41 | ||||
-rw-r--r-- | perfunwind.h | 20 |
2 files changed, 44 insertions, 17 deletions
diff --git a/perfunwind.cpp b/perfunwind.cpp index 3b6d09b..58ff60a 100644 --- a/perfunwind.cpp +++ b/perfunwind.cpp @@ -78,7 +78,7 @@ void PerfUnwind::registerElf(const PerfRecordMmap &mmap) QString fileName = QFileInfo(mmap.filename()).fileName(); QFileInfo path; - if (mmap.pid() != std::numeric_limits<quint32>::max()) { + if (mmap.pid() != s_kernelPid) { path.setFile(appPath + "/" + fileName); if (!path.isFile()) { path.setFile(extraLibsPath); @@ -136,8 +136,6 @@ Dwfl_Module *PerfUnwind::reportElf(quint64 ip, quint32 pid) const << QString("0x%1").arg(i.key(), 0, 16).toLocal8Bit().constData() << ":" << dwfl_errmsg(dwfl_errno()); return ret; - } else if (pid != std::numeric_limits<quint32>::max()) { - return reportElf(ip, std::numeric_limits<quint32>::max()); } else { qWarning() << "no elf found for IP" << QString("0x%1").arg(ip, 0, 16).toLocal8Bit().constData(); @@ -147,7 +145,7 @@ Dwfl_Module *PerfUnwind::reportElf(quint64 ip, quint32 pid) const QDataStream &operator<<(QDataStream &stream, const PerfUnwind::Frame &frame) { - return stream << frame.frame << frame.symbol << frame.file; + return stream << frame.frame << frame.isKernel << frame.symbol << frame.file; } static pid_t nextThread(Dwfl *dwfl, void *arg, void **threadArg) @@ -207,13 +205,14 @@ static const Dwfl_Thread_Callbacks callbacks = { nextThread, NULL, memoryRead, setInitialRegisters, NULL, NULL }; -static PerfUnwind::Frame lookupSymbol(const PerfUnwind *unwind, Dwfl *dwfl, Dwarf_Addr ip) +static PerfUnwind::Frame lookupSymbol(const PerfUnwind *unwind, Dwfl *dwfl, Dwarf_Addr ip, + bool isKernel) { Dwfl_Module *mod = dwfl_addrmodule (dwfl, ip); const char *symname = NULL; const char *demangled = NULL; if (!mod) - mod = unwind->reportElf(ip, unwind->pid()); + mod = unwind->reportElf(ip, isKernel ? PerfUnwind::s_kernelPid : unwind->pid()); const char *filename = NULL; GElf_Sym sym; @@ -232,13 +231,11 @@ static PerfUnwind::Frame lookupSymbol(const PerfUnwind *unwind, Dwfl *dwfl, Dwar // Adjust it back. The symtab entries are 1 off for all practical purposes. return PerfUnwind::Frame((do_adjust && (sym.st_value & 1)) ? sym.st_value - 1 : sym.st_value, - demangled ? demangled : symname, filename); + isKernel, demangled ? demangled : symname, filename); } else { qWarning() << "no symbol found for" << ip << "in" << filename; - return PerfUnwind::Frame(ip, symname, filename); + return PerfUnwind::Frame(ip, isKernel, symname, filename); } - - } static int frameCallback(Dwfl_Frame *state, void *arg) @@ -257,7 +254,9 @@ static int frameCallback(Dwfl_Frame *state, void *arg) Dwfl_Thread *thread = dwfl_frame_thread (state); Dwfl *dwfl = dwfl_thread_dwfl (thread); PerfUnwind::UnwindInfo *ui = static_cast<PerfUnwind::UnwindInfo *>(arg); - ui->frames->append(lookupSymbol(ui->unwind, dwfl, pc_adjusted)); + + // isKernel = false as unwinding generally only works on user code + ui->frames->append(lookupSymbol(ui->unwind, dwfl, pc_adjusted, false)); return DWARF_CB_OK; } @@ -272,11 +271,25 @@ void PerfUnwind::unwindStack(QVector<Frame> *frames, const PerfRecordSample &sam void PerfUnwind::resolveCallchain(QVector<Frame> *frames, const PerfRecordSample &sample) { + bool isKernel = false; for (int i = 0; i < sample.callchain().length(); ++i) { quint64 ip = sample.callchain()[i]; - if (ip > s_callchainMax) - continue; // ignore cpu mode - frames->append(lookupSymbol(this, dwfl, ip)); + if (ip > PERF_CONTEXT_MAX) { + switch (ip) { + case PERF_CONTEXT_HV: // hypervisor + case PERF_CONTEXT_KERNEL: + isKernel = true; + break; + case PERF_CONTEXT_USER: + isKernel = false; + break; + default: + qWarning() << "invalid callchain context" << ip; + return; + } + } else { + frames->append(lookupSymbol(this, dwfl, ip, isKernel)); + } } } diff --git a/perfunwind.h b/perfunwind.h index 5b2e224..f1ef4ca 100644 --- a/perfunwind.h +++ b/perfunwind.h @@ -32,10 +32,11 @@ class PerfUnwind { public: struct Frame { - Frame(quint64 frame = 0, const QByteArray &symbol = QByteArray(), + Frame(quint64 frame = 0, bool isKernel = false, const QByteArray &symbol = QByteArray(), const QByteArray &file = QByteArray()) : - frame(frame), symbol(symbol), file(file) {} + frame(frame), isKernel(isKernel), symbol(symbol), file(file) {} quint64 frame; + bool isKernel; QByteArray symbol; QByteArray file; }; @@ -47,6 +48,8 @@ public: const PerfRecordSample *sample; }; + static const quint32 s_kernelPid = std::numeric_limits<quint32>::max(); + PerfUnwind(QIODevice *output, const QString &systemRoot, const QString &debugInfo, const QString &extraLibs, const QString &appPath); ~PerfUnwind(); @@ -66,7 +69,18 @@ public: void analyze(const PerfRecordSample &sample); private: - static const quint64 s_callchainMax = (quint64)-4095; + + enum CallchainContext { + PERF_CONTEXT_HV = (quint64)-32, + PERF_CONTEXT_KERNEL = (quint64)-128, + PERF_CONTEXT_USER = (quint64)-512, + + PERF_CONTEXT_GUEST = (quint64)-2048, + PERF_CONTEXT_GUEST_KERNEL = (quint64)-2176, + PERF_CONTEXT_GUEST_USER = (quint64)-2560, + + PERF_CONTEXT_MAX = (quint64)-4095, + }; UnwindInfo currentUnwind; QIODevice *output; |