summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@theqtcompany.com>2015-02-04 17:13:02 +0100
committerUlf Hermann <ulf.hermann@theqtcompany.com>2015-02-16 18:04:42 +0200
commit43913f2aa5f2a2320fa92ee7fbd7ddd4d906781e (patch)
treea83b8cbdf6efb84af6c35b3b1076d4e184b81ee6
parentbe7d6f47f4309270cf7d288db47580c7037eafb9 (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.cpp41
-rw-r--r--perfunwind.h20
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;