diff options
author | Milian Wolff <milian.wolff@kdab.com> | 2017-06-02 16:52:55 +0200 |
---|---|---|
committer | Milian Wolff <milian.wolff@kdab.com> | 2017-09-04 15:51:52 +0000 |
commit | 9917e10ade3cb0c4fd3404c41541b43efe97c3fe (patch) | |
tree | 6c399263ca4b240da8a0a45fbfabbb33f36e4af1 | |
parent | 1e07e1e70df76e433d2d24e46291b4a93335b303 (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.cpp | 16 |
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); |