summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMilian Wolff <milian.wolff@kdab.com>2017-06-02 16:52:55 +0200
committerMilian Wolff <milian.wolff@kdab.com>2017-09-04 15:51:52 +0000
commit9917e10ade3cb0c4fd3404c41541b43efe97c3fe (patch)
tree6c399263ca4b240da8a0a45fbfabbb33f36e4af1
parent1e07e1e70df76e433d2d24e46291b4a93335b303 (diff)
Report module for PC before querying for isactivation flag
The call to dwfl_frame_pc potentially advances the internal unwinder state when we query for the isactivation flag. This can then lead to breakage when the about-to-be-returned PC lies in a not-yet-reported module. To fix this, we now ask first for the PC, which is cheap as it just forwards a data member of the Dwfl_Frame state. Then we ensure the module that contains this PC is properly reported to dwfl. Only then do we ask for the isactivation flag by calling dwfl_frame_pc a second time. This fixes many broken backtraces. In perf upstream I have submitted a similar fix. There, we can more easily compare the libdw unwinder with libunwind. Here is the corresponding output of the two: Working libunwind and libdw with this patch applied: ~~~~~ heaptrack_gui 2228 135073.400474: 613969 cycles: 108c8e [unknown] (/usr/lib/libQt5Core.so.5.8.0) 1093bc [unknown] (/usr/lib/libQt5Core.so.5.8.0) 109e7b QLocale::QLocale (/usr/lib/libQt5Core.so.5.8.0) 1470ff [unknown] (/usr/lib/libQt5Core.so.5.8.0) 147f67 QSystemLocale::query (/usr/lib/libQt5Core.so.5.8.0) 109fbf QLocalePrivate::updateSystemPrivate (/usr/lib/libQt5Core.so.5.8.0) 10aa27 QLocale::QLocale (/usr/lib/libQt5Core.so.5.8.0) 1e02c3 [unknown] (/usr/lib/libQt5Core.so.5.8.0) 2113bb [unknown] (/usr/lib/libQt5Core.so.5.8.0) 211505 [unknown] (/usr/lib/libQt5Core.so.5.8.0) 1b5df0 QFileInfo::exists (/usr/lib/libQt5Core.so.5.8.0) 92eb2 [unknown] (/usr/lib/libQt5Core.so.5.8.0) 93423 [unknown] (/usr/lib/libQt5Core.so.5.8.0) 93d2a QLibraryInfo::location (/usr/lib/libQt5Core.so.5.8.0) 2170af [unknown] (/usr/lib/libQt5Core.so.5.8.0) 297c53 QCoreApplicationPrivate::init (/usr/lib/libQt5Core.so.5.8.0) f7cde QGuiApplicationPrivate::init (/usr/lib/libQt5Gui.so.5.8.0) 1589e8 QApplicationPrivate::init (/usr/lib/libQt5Widgets.so.5.8.0) 78622 main (/home/milian/projects/compiled/other/bin/heaptrack_gui) 20439 __libc_start_main (/usr/lib/libc-2.25.so) 78299 _start (/home/milian/projects/compiled/other/bin/heaptrack_gui) heaptrack_gui 2228 135073.401156: 569521 cycles: 131633 QString::endsWith (/usr/lib/libQt5Core.so.5.8.0) 1a0701 QDir::cleanPath (/usr/lib/libQt5Core.so.5.8.0) 21b82d [unknown] (/usr/lib/libQt5Core.so.5.8.0) 1b3727 QFileInfo::canonicalFilePath (/usr/lib/libQt5Core.so.5.8.0) 2780c7 QFactoryLoader::update (/usr/lib/libQt5Core.so.5.8.0) 279525 QFactoryLoader::QFactoryLoader (/usr/lib/libQt5Core.so.5.8.0) e5bd0 QPlatformIntegrationFactory::create (/usr/lib/libQt5Gui.so.5.8.0) f5a1c QGuiApplicationPrivate::createPlatformIntegration (/usr/lib/libQt5Gui.so.5.8.0) f650c QGuiApplicationPrivate::createEventDispatcher (/usr/lib/libQt5Gui.so.5.8.0) 298524 QCoreApplicationPrivate::init (/usr/lib/libQt5Core.so.5.8.0) f7cde QGuiApplicationPrivate::init (/usr/lib/libQt5Gui.so.5.8.0) 1589e8 QApplicationPrivate::init (/usr/lib/libQt5Widgets.so.5.8.0) 78622 main (/home/milian/projects/compiled/other/bin/heaptrack_gui) 20439 __libc_start_main (/usr/lib/libc-2.25.so) 78299 _start (/home/milian/projects/compiled/other/bin/heaptrack_gui) ~~~~~ Broken libdw, i.e. status quo without this patch. Note how the first sample is randomly missing two frames close to the end. The second stack breaks completely. ~~~~~ heaptrack_gui 2228 135073.400474: 613969 cycles: 108c8e [unknown] (/usr/lib/libQt5Core.so.5.8.0) 1093bc [unknown] (/usr/lib/libQt5Core.so.5.8.0) 109e7b QLocale::QLocale (/usr/lib/libQt5Core.so.5.8.0) 1470ff [unknown] (/usr/lib/libQt5Core.so.5.8.0) 147f67 QSystemLocale::query (/usr/lib/libQt5Core.so.5.8.0) 109fbf QLocalePrivate::updateSystemPrivate (/usr/lib/libQt5Core.so.5.8.0) 10aa27 QLocale::QLocale (/usr/lib/libQt5Core.so.5.8.0) 1e02c3 [unknown] (/usr/lib/libQt5Core.so.5.8.0) 2113bb [unknown] (/usr/lib/libQt5Core.so.5.8.0) 211505 [unknown] (/usr/lib/libQt5Core.so.5.8.0) 1b5df0 QFileInfo::exists (/usr/lib/libQt5Core.so.5.8.0) 92eb2 [unknown] (/usr/lib/libQt5Core.so.5.8.0) 93423 [unknown] (/usr/lib/libQt5Core.so.5.8.0) 93d2a QLibraryInfo::location (/usr/lib/libQt5Core.so.5.8.0) 2170af [unknown] (/usr/lib/libQt5Core.so.5.8.0) 297c53 QCoreApplicationPrivate::init (/usr/lib/libQt5Core.so.5.8.0) f7cde QGuiApplicationPrivate::init (/usr/lib/libQt5Gui.so.5.8.0) 20439 __libc_start_main (/usr/lib/libc-2.25.so) 78299 _start (/home/milian/projects/compiled/other/bin/heaptrack_gui) heaptrack_gui 2228 135073.401156: 569521 cycles: 131633 QString::endsWith (/usr/lib/libQt5Core.so.5.8.0) 1a0701 QDir::cleanPath (/usr/lib/libQt5Core.so.5.8.0) 21b82d [unknown] (/usr/lib/libQt5Core.so.5.8.0) 1b3727 QFileInfo::canonicalFilePath (/usr/lib/libQt5Core.so.5.8.0) 2780c7 QFactoryLoader::update (/usr/lib/libQt5Core.so.5.8.0) 279525 QFactoryLoader::QFactoryLoader (/usr/lib/libQt5Core.so.5.8.0) e5bd0 QPlatformIntegrationFactory::create (/usr/lib/libQt5Gui.so.5.8.0) 723dbf [unknown] ([unknown]) ~~~~~ Both issues are fixed with this patch applied. Change-Id: Ib2a9394ab2a01a5e65860540a675c277ff15dc8c Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r--app/perfunwind.cpp16
1 files changed, 13 insertions, 3 deletions
diff --git a/app/perfunwind.cpp b/app/perfunwind.cpp
index 09d17ce..5839322 100644
--- a/app/perfunwind.cpp
+++ b/app/perfunwind.cpp
@@ -300,8 +300,10 @@ static int frameCallback(Dwfl_Frame *state, void *arg)
Dwarf_Addr pc = 0;
PerfUnwind::UnwindInfo *ui = static_cast<PerfUnwind::UnwindInfo *>(arg);
- bool isactivation;
- if (!dwfl_frame_pc(state, &pc, &isactivation)
+ // do not query for activation directly, as this could potentially advance
+ // the unwinder internally - we must first ensure the module for the pc
+ // is reported
+ if (!dwfl_frame_pc(state, &pc, NULL)
|| (ui->maxFrames != -1 && ui->frames.length() > ui->maxFrames)
|| pc == 0) {
ui->firstGuessedFrame = ui->frames.length();
@@ -309,9 +311,17 @@ static int frameCallback(Dwfl_Frame *state, void *arg)
return DWARF_CB_ABORT;
}
+ auto* symbolTable = ui->unwind->symbolTable(ui->sample->pid());
+
+ // ensure the module is reported
+ // if that fails, we will still try to unwind based on frame pointer
+ symbolTable->module(pc);
+
+ // now we can query for the activation flag
+ bool isactivation = false;
+ dwfl_frame_pc(state, &pc, &isactivation);
Dwarf_Addr pc_adjusted = pc - (isactivation ? 0 : 1);
- auto* symbolTable = ui->unwind->symbolTable(ui->sample->pid());
// isKernel = false as unwinding generally only works on user code
bool isInterworking = false;
const auto frame = symbolTable->lookupFrame(pc_adjusted, false, &isInterworking);