summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2018-01-25 14:56:45 +0100
committerUlf Hermann <ulf.hermann@qt.io>2018-01-25 14:26:21 +0000
commitd13a5eeded0f80ed88060e6a2e5b31ede849d572 (patch)
tree9db3e08d2243bcd4d0794ba76b49fd31143b956b
parent70cd96d631e2a63381cde248f6b68e0b7c9289f0 (diff)
Try to unwind the user stack even if IP is in kernel space
Quite often we get both a kernel call chain in sample.callchain() and a user stack and user registers. We should analyze both then, each with the right symbol table. Also, when resolving a call chain we need to make sure that every time we resolve a frame the dwfl is attached. This is important as context switches force us to change the symbol table. Change-Id: I9e5849eefef6780f822166e8c6a798749d18fce2 Reviewed-by: Milian Wolff <milian.wolff@kdab.com>
-rw-r--r--app/perfunwind.cpp40
-rw-r--r--app/perfunwind.h2
2 files changed, 26 insertions, 16 deletions
diff --git a/app/perfunwind.cpp b/app/perfunwind.cpp
index fab3e15..9680683 100644
--- a/app/perfunwind.cpp
+++ b/app/perfunwind.cpp
@@ -365,8 +365,9 @@ static int frameCallback(Dwfl_Frame *state, void *arg)
return DWARF_CB_OK;
}
-void PerfUnwind::unwindStack(Dwfl *dwfl)
+void PerfUnwind::unwindStack()
{
+ Dwfl *dwfl = symbolTable(m_currentUnwind.sample->pid())->attachDwfl(&m_currentUnwind);
dwfl_getthread_frames(dwfl, m_currentUnwind.sample->pid(), frameCallback, &m_currentUnwind);
if (m_currentUnwind.isInterworking) {
QVector<qint32> savedFrames = m_currentUnwind.frames;
@@ -417,12 +418,14 @@ void PerfUnwind::resolveCallchain()
// sometimes it skips the first user frame.
if (i == 0 && !isKernel && ip != m_currentUnwind.sample->ip()) {
+ symbols->attachDwfl(&m_currentUnwind);
m_currentUnwind.frames.append(symbols->lookupFrame(
m_currentUnwind.sample->ip(), false,
&m_currentUnwind.isInterworking));
}
if (ip <= PERF_CONTEXT_MAX) {
+ symbols->attachDwfl(&m_currentUnwind);
m_currentUnwind.frames.append(symbols->lookupFrame(
ip, isKernel,
&m_currentUnwind.isInterworking));
@@ -508,8 +511,8 @@ void PerfUnwind::analyze(const PerfRecordSample &sample)
if (m_stats.enabled) // don't do any time intensive work in stats mode
return;
- const bool isKernel = ipIsInKernelSpace(sample.ip());
- PerfSymbolTable *symbols = symbolTable(isKernel ? s_kernelPid : sample.pid());
+ PerfSymbolTable *kernelSymbols = symbolTable(s_kernelPid);
+ PerfSymbolTable *userSymbols = symbolTable(sample.pid());
for (int unwindingAttempt = 0; unwindingAttempt < 2; ++unwindingAttempt) {
m_currentUnwind.isInterworking = false;
@@ -517,32 +520,39 @@ void PerfUnwind::analyze(const PerfRecordSample &sample)
m_currentUnwind.sample = &sample;
m_currentUnwind.frames.clear();
- symbols->updatePerfMap();
-
- Dwfl *dwfl = symbols->attachDwfl(&m_currentUnwind);
+ userSymbols->updatePerfMap();
if (sample.callchain().length() > 0)
resolveCallchain();
+ bool userDirty = userSymbols->cacheIsDirty();
+ bool kernelDirty = kernelSymbols->cacheIsDirty();
+
// only try to unwind when resolveCallchain did not dirty the cache
- if (!symbols->cacheIsDirty()) {
- if (dwfl && sample.registerAbi() != 0 && sample.userStack().length() > 0)
- unwindStack(dwfl);
- else
+ if (!userDirty && !kernelDirty) {
+ if (sample.registerAbi() != 0 && sample.userStack().length() > 0) {
+ unwindStack();
+ userDirty = userSymbols->cacheIsDirty();
+ } else {
break;
+ }
}
// when the cache is dirty, we clean it up and try again, otherwise we can
// stop as unwinding should have succeeded
- if (symbols->cacheIsDirty())
- symbols->clearCache(); // fail, try again
- else
+ if (userDirty)
+ userSymbols->clearCache(); // fail, try again
+ if (kernelDirty)
+ kernelSymbols->clearCache();
+ if (!userDirty && !kernelDirty)
break; // success
}
// If nothing was found, at least look up the IP
if (m_currentUnwind.frames.isEmpty()) {
- m_currentUnwind.frames.append(symbols->lookupFrame(sample.ip(), isKernel,
- &m_currentUnwind.isInterworking));
+ const bool isKernel = ipIsInKernelSpace(sample.ip());
+ PerfSymbolTable *ipSymbols = isKernel ? kernelSymbols : userSymbols;
+ m_currentUnwind.frames.append(ipSymbols->lookupFrame(sample.ip(), isKernel,
+ &m_currentUnwind.isInterworking));
}
diff --git a/app/perfunwind.h b/app/perfunwind.h
index a18d6a0..82713a3 100644
--- a/app/perfunwind.h
+++ b/app/perfunwind.h
@@ -284,7 +284,7 @@ private:
Stats m_stats;
- void unwindStack(Dwfl *dwfl);
+ void unwindStack();
void resolveCallchain();
void analyze(const PerfRecordSample &sample);
void sendBuffer(const QByteArray &buffer);