[KDE/Mac] Review Request 121213: [OS X] correctly parse backtrace for demangling symbols
René J.V. Bertin
rjvbertin at gmail.com
Thu Nov 27 20:52:22 UTC 2014
> On Nov. 23, 2014, 12:20 a.m., Thomas Lübking wrote:
> > kdecore/io/kdebug.cpp, line 717
> > <https://git.reviewboard.kde.org/r/121213/diff/1/?file=329504#file329504line717>
> >
> > Why do you need to sharpen the match?
>
> René J.V. Bertin wrote:
> Because otherwise the symbol to be demangled is left with a trailing space, which causes the demangle to fail. Wanna know how I know?
>
> Thomas Lübking wrote:
> Don't know about the GCC behavior on trailing spaces, but one should probably have some "while (in.at(mangledNameEnd) == ' ') --mangledNameEnd;" loop?
>
> René J.V. Bertin wrote:
> One could, but why? The start is found with a string, I don't see why the end wouldn't be, given that that loop of yours will always loop just once ...
>
> Thomas Lübking wrote:
> ... or not at all or thrice - depending on how the mangler feels today.
>
> What I mean is that if untrimmed strings are a problem for demangling, one should seek to get rid of all the whitespace generically - i don't care about whether seeking for a string or char, this context is hardly performance critical.
>
> René J.V. Bertin wrote:
> this particular bit of whitespace has nothing to do with the mangler or how it feels today. It's formatting done by the backtrace function, which clearly always puts a space-padded `+` rather than one without padding as under Linux.
> Frankly, in general I'd agree with you, but here I don't see any reason to make the code more complex than it is.
>
> Thomas Lübking wrote:
> backtrace() is provided by glibc resp. the apple (darwin) libc (i hope).
> -> What provides /usr/include/execinfo.h on OSX?
> That's what is needed to be detected (I assume this would affect *all* BSD variants?)
>
> > I don't see any reason to make the code more complex than it is.
>
> If we're dealing w/ unspecified output and need to sanitize it, we may have to do this generically if we must consider random toolchains aside gcc+glibc.
> I know that you only care about OSX, but actually OSX is just a good testcase to see whether the code is "correct" or just happens to work.
>
> - Do you compile with gcc or clang?
> - Did you check whether the glibc backtrace() output is actually stripped?
> - What if we compile glibc w/ llvm and glibc backtrace() fires padded " + " which llvm __cxa_demangle() cannot handle? (ok, rethorical question ;-)
>
> René J.V. Bertin wrote:
> > backtrace() is provided by glibc resp. the apple (darwin) libc (i hope).
>
> Not that we have something called libc on OS X, but I think that just underlines my point. The C Library is more part of the system than it is of the C "package", so the only check on compiler that would make sense IMHO is on the system compiler, as far as that's possible (like the Apple-provided __APPLE_CC__).
>
> > What provides /usr/include/execinfo.h on OSX?
>
> If you're talking about packages: either the standard install, or Xcode and/or "Command Line Tools".
> One shouldn't take OS X as a guideline for any BSD variant, it might even have diverged too much to use BSD as a guideline for what ought to work on OS X.
>
> I agree about the sanitising/generalising, which is why I pulled the suppression of trailing whitespace out of the end token search (and you'll notice I don't just suppress spaces). I just don't think it'd make any sense to have a os/toolchain-specific constant and then the actual search one-liner. Just put that search statement in the conditional block and be done with it.
>
> This patch has currently been tested only on 10.9(.4), which means I can basically only test with clang. I can affirm though that the existing code doesn't demangle on 10.6 either, whether I use clang or gcc.
>
> > Did you check whether the glibc backtrace() output is actually stripped?
>
> I don't understand the question?
>
> This is what unparsed output from backtrace_symbols looks like (even adding the counter: isn't required):
>
> ```
> 0: "0 libkdecore.5.dylib 0x0000000106656f71 _Z14kRealBacktracei + 81"
> 1: "1 kwindowtest 0x0000000105e322e1 _ZN10TestWindow8slotOpenEv + 2753"
> 2: "2 kwindowtest 0x0000000105e33d68 _ZN10TestWindow18qt_static_metacallEP7QObjectN11QMetaObject4CallEiPPv + 184"
> 3: "3 QtCore 0x0000000106c8d3fd _ZN11QMetaObject8activateEP7QObjectPKS_iPPv + 1693"
> 4: "4 QtGui 0x0000000106faf419 _ZN7QAction8activateENS_11ActionEventE + 233"
> 5: "5 QtGui 0x00000001073141e4 _ZN22QAbstractButtonPrivate5clickEv + 84"
> 6: "6 QtGui 0x0000000107314fc8 _ZN15QAbstractButton17mouseReleaseEventEP11QMouseEvent + 88"
> 7: "7 QtGui 0x00000001073db67f _ZN11QToolButton17mouseReleaseEventEP11QMouseEvent + 15"
> 8: "8 QtGui 0x00000001070069bd _ZN7QWidget5eventEP6QEvent + 717"
> 9: "9 QtGui 0x0000000107314ed4 _ZN15QAbstractButton5eventEP6QEvent + 180"
> 10: "10 QtGui 0x00000001073dbb2a _ZN11QToolButton5eventEP6QEvent + 170"
> 11: "11 QtGui 0x0000000106fb840c _ZN19QApplicationPrivate13notify_helperEP7QObjectP6QEvent + 252"
> 12: "12 QtGui 0x0000000106fba357 _ZN12QApplication6notifyEP7QObjectP6QEvent + 2919"
> 13: "13 QtCore 0x0000000106c75516 _ZN16QCoreApplication14notifyInternalEP7QObjectP6QEvent + 118"
> 14: "14 QtGui 0x0000000106fb8df6 _ZN19QApplicationPrivate14sendMouseEventEP7QWidgetP11QMouseEventS1_S1_PS1_R8QPointerIS0_Eb + 470"
> 15: "15 QtGui 0x0000000106f67a2a _Z23qt_mac_handleMouseEventP7NSEventN6QEvent4TypeEN2Qt11MouseButtonEP7QWidgetb + 922"
> 16: "16 AppKit 0x00007fff9491f145 -[NSWindow sendEvent:] + 781"
> 17: "17 QtGui 0x0000000106f5f2f1 -[QCocoaWindow sendEvent:] + 113"
> 18: "18 AppKit 0x00007fff948c05d4 -[NSApplication sendEvent:] + 2021"
> 19: "19 QtGui 0x0000000106f640fe -[QNSApplication sendEvent:] + 78"
> 20: "20 AppKit 0x00007fff947109f9 -[NSApplication run] + 646"
> 21: "21 QtGui 0x0000000106f6cba0 _ZN19QEventDispatcherMac13processEventsE6QFlagsIN10QEventLoop17ProcessEventsFlagEE + 528"
> 22: "22 QtCore 0x0000000106c728ad _ZN10QEventLoop4execE6QFlagsINS_17ProcessEventsFlagEE + 477"
> 23: "23 QtCore 0x0000000106c75ac7 _ZN16QCoreApplication4execEv + 199"
> 24: "24 kwindowtest 0x0000000105e33bdc main + 316"
> 25: "25 libdyld.dylib 0x00007fff93bb75fd start + 1"
> 26: "26 ??? 0x0000000000000002 0x0 + 2"
> ```
>
> which is converted to:
>
> ```
> 0: 0 libkdecore.5.dylib 0x0000000106656f71 kRealBacktrace(int) + 81
> 1: 1 kwindowtest 0x0000000105e322e1 TestWindow::slotOpen() + 2753
> 2: 2 kwindowtest 0x0000000105e33d68 TestWindow::qt_static_metacall(QObject*, QMetaObject::Call, int, void**) + 184
> 3: 3 QtCore 0x0000000106c8d3fd QMetaObject::activate(QObject*, QMetaObject const*, int, void**) + 1693
> 4: 4 QtGui 0x0000000106faf419 QAction::activate(QAction::ActionEvent) + 233
> 5: 5 QtGui 0x00000001073141e4 QAbstractButtonPrivate::click() + 84
> 6: 6 QtGui 0x0000000107314fc8 QAbstractButton::mouseReleaseEvent(QMouseEvent*) + 88
> 7: 7 QtGui 0x00000001073db67f QToolButton::mouseReleaseEvent(QMouseEvent*) + 15
> 8: 8 QtGui 0x00000001070069bd QWidget::event(QEvent*) + 717
> 9: 9 QtGui 0x0000000107314ed4 QAbstractButton::event(QEvent*) + 180
> 10: 10 QtGui 0x00000001073dbb2a QToolButton::event(QEvent*) + 170
> 11: 11 QtGui 0x0000000106fb840c QApplicationPrivate::notify_helper(QObject*, QEvent*) + 252
> 12: 12 QtGui 0x0000000106fba357 QApplication::notify(QObject*, QEvent*) + 2919
> 13: 13 QtCore 0x0000000106c75516 QCoreApplication::notifyInternal(QObject*, QEvent*) + 118
> 14: 14 QtGui 0x0000000106fb8df6 QApplicationPrivate::sendMouseEvent(QWidget*, QMouseEvent*, QWidget*, QWidget*, QWidget**, QPointer<QWidget>&, bool) + 470
> 15: 15 QtGui 0x0000000106f67a2a qt_mac_handleMouseEvent(NSEvent*, QEvent::Type, Qt::MouseButton, QWidget*, bool) + 922
> 16: 16 AppKit 0x00007fff9491f145 -[NSWindow sendEvent:] + 781
> 17: 17 QtGui 0x0000000106f5f2f1 -[QCocoaWindow sendEvent:] + 113
> 18: 18 AppKit 0x00007fff948c05d4 -[NSApplication sendEvent:] + 2021
> 19: 19 QtGui 0x0000000106f640fe -[QNSApplication sendEvent:] + 78
> 20: 20 AppKit 0x00007fff947109f9 -[NSApplication run] + 646
> 21: 21 QtGui 0x0000000106f6cba0 QEventDispatcherMac::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 528
> 22: 22 QtCore 0x0000000106c728ad QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) + 477
> 23: 23 QtCore 0x0000000106c75ac7 QCoreApplication::exec() + 199
> 24: 24 kwindowtest 0x0000000105e33bdc main + 316
> 25: 25 libdyld.dylib 0x00007fff93bb75fd start + 1
> 26: 26 ??? 0x0000000000000002 0x0 + 2
> ```
>
> René J.V. Bertin wrote:
> Using a very simple standalone test application I have compared the `backtrace_symbols` output under 10.9.4, using clang and gcc-4.8. Apparently this particular case is simple enough to avoid C++ runtime conflicts (there's main(), a `show_backtrace` function that mimicks `kRealBacktrace` and optionally a `maybeDemangledName` when building as C++).
>
> - In pure C, both compilers give
> ```
> 0 backtrace 0x0000000104d57d9c show_backtrace + 60
> ```
>
> so the current parser would fail (but it's called from C++ so that's a moot point, or so I hope).
>
> - In C++ mode, both compilers give
> ```
> 0 backtrace 0x000000010656dbed _Z14show_backtracev + 61
> ```
>
> I'll attach the code so that it can be tested on other platforms too.
>
> Thomas Lübking wrote:
> Very good - I already felt stupid.
> The demangled is always nullptr here and the backtrace strings do not end w/ " + *" at all. No matter whether gcc, g++, clang or clang++
>
> *shrug*
>
> René J.V. Bertin wrote:
> Yeah, on Linux I get
>
> ```
> 0: ./backtrace() [0x400fa5]
> 1: ./backtrace() [0x4011d2]
> 2: /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf5) [0x7fbc5e1f7ec5]
> 3: ./backtrace() [0x400c49]
> ```
>
> is that comparable to what you're getting? If so, it would seem that backtrace or backtrace_symbols already do their own demangling...
>
> Thomas Lübking wrote:
> Yupp.
> This is of course nasty, because we cannot check "other" requirements - the entire demangling should be omitted on linux/glibc > v?.?
> (I will argue that this is what I meant by "how the mangler feels today")
>
> Depending on your raw output, I'd btw. suggest to search for " _Z" - a simple " _" could (too) easily appear in the lib name?
> For " + " ./. "+" + trimming, it becomes a coin flip between "future proof" and simplicitly - as demangling is apparently only relevant on eXoticOS™, *me* would now leave that choice to you.
>
> René J.V. Bertin wrote:
> I'll see if I still have that OpenIndiana VM, and what a BSD VM might teach me (but which flavour ...)
>
> Anyway, it seems that the function is rather aptly named ... it may demangle, and it may not, and if so that might be because the input was already demangled :).
>
> René J.V. Bertin wrote:
> It's really getting weirder and weirder.
>
> When I copy the kdelib workhorse function into a KDE test application
>
> ```C++
> QString RealBacktrace(int levels)
> {
> QString s;
> void* trace[256];
> int n = backtrace(trace, 256);
> if (!n)
> return s;
> char** strings = backtrace_symbols (trace, n);
>
> if ( levels != -1 )
> n = qMin( n, levels );
> s = QLatin1String("[\n");
>
> for (int i = 0; i < n; ++i)
> s += QString::number(i) + QLatin1String(": ") +
> QLatin1String(strings[i]) + QLatin1Char('\n');
> s += QLatin1String("]\n");
> if (strings)
> free (strings);
> return s;
> }
> ```
>
> and call it, I get this on Linux:
>
> ```
> # qDebug() << RealBacktrace(-1);
> 0: kdelibs4-4.14.0/build/kdeui/tests/kwindowtest() [0x40c349]
> 1: kdelibs4-4.14.0/build/kdeui/tests/kwindowtest() [0x40c66a]
> 2: kdelibs4-4.14.0/build/kdeui/tests/kwindowtest() [0x40dd4e]
> 3: /usr/lib/x86_64-linux-gnu/libQtCore.so.4(_ZN11QMetaObject8activateEP7QObjectPKS_iPPv+0x2da) [0x7fc93ac8b95a]
> 4: /usr/lib/x86_64-linux-gnu/libQtGui.so.4(_ZN7QAction9triggeredEb+0x32) [0x7fc939d07312]
> 5: /usr/lib/x86_64-linux-gnu/libQtGui.so.4(_ZN7QAction8activateENS_11ActionEventE+0x5f) [0x7fc939d08f3f]
> 6: /usr/lib/x86_64-linux-gnu/libQtGui.so.4(+0x5f8202) [0x7fc93a13a202]
> 7: /usr/lib/x86_64-linux-gnu/libQtGui.so.4(_ZN15QAbstractButton17mouseReleaseEventEP11QMouseEvent+0x6c) [0x7fc93a13a32c]
> <snip>
> ```
>
> and when I call
>
> ```
> # qDebug() << kBacktrace();
> 0: kdelibs4-4.14.0/build/lib/libkdecore.so.5(kRealBacktrace(int)+0x3f) [0x7fc93b3924cf]
> 1: kdelibs4-4.14.0/build/kdeui/tests/kwindowtest() [0x40c72d]
> 2: kdelibs4-4.14.0/build/kdeui/tests/kwindowtest() [0x40dd4e]
> 3: /usr/lib/x86_64-linux-gnu/libQtCore.so.4(QMetaObject::activate(QObject*, QMetaObject const*, int, void**)+0x2da) [0x7fc93ac8b95a]
> 4: /usr/lib/x86_64-linux-gnu/libQtGui.so.4(QAction::triggered(bool)+0x32) [0x7fc939d07312]
> 5: /usr/lib/x86_64-linux-gnu/libQtGui.so.4(QAction::activate(QAction::ActionEvent)+0x5f) [0x7fc939d08f3f]
> 6: /usr/lib/x86_64-linux-gnu/libQtGui.so.4(+0x5f8202) [0x7fc93a13a202]
> 7: /usr/lib/x86_64-linux-gnu/libQtGui.so.4(QAbstractButton::mouseReleaseEvent(QMouseEvent*)+0x6c) [0x7fc93a13a32c]
> <snip>
> ```
>
> In other words, in this case we get mangled symbols out of `backtrace_symbols` and maybeDemangledName gets to do its job...
> It seems that backtrace/backtrace_symbols behave differently when called from a shared library than when called from a linked-in source module (which also contains main), but does that make any sense??
>
> Thomas Lübking wrote:
> http://www.gnu.org/software/libc/manual/html_node/Backtraces.html
>
> tl;dr: you must link -rdynamic
> g++ -rdynamic -o backtrace backtrace.c
> clang++ -rdynamic -o backtrace backtrace.c
> in order to get the symbols.
>
> I can also confirm the format for glibc (same for g++ and clang++), ie. "(_Z" and NO whitespace around the '+'
> The is also reflected by readelf -sw.
`-rdynamic` to get the *mangled* symbols you mean? Kinda would make sense there's no mangling in my test as it isn't really required here.
Let me see what I can learn on a PC-BSD VM I'm setting up "between acts" (I've already checked OpenIndiana) and then we'll figure out how to polish this whole thing up.
- René J.V.
-----------------------------------------------------------
This is an automatically generated e-mail. To reply, visit:
https://git.reviewboard.kde.org/r/121213/#review70796
-----------------------------------------------------------
On Nov. 25, 2014, 3:12 p.m., René J.V. Bertin wrote:
>
> -----------------------------------------------------------
> This is an automatically generated e-mail. To reply, visit:
> https://git.reviewboard.kde.org/r/121213/
> -----------------------------------------------------------
>
> (Updated Nov. 25, 2014, 3:12 p.m.)
>
>
> Review request for KDE Software on Mac OS X and kdelibs.
>
>
> Repository: kdelibs
>
>
> Description
> -------
>
> This patch adapts the parser in `maybeDemangledName` to the backtrace obtained in `kRealBacktrace` on OS X.
>
>
> Diffs
> -----
>
> kdecore/io/kdebug.cpp 872a05a
>
> Diff: https://git.reviewboard.kde.org/r/121213/diff/
>
>
> Testing
> -------
>
> Works as expected on OS X 10.9.4 .
>
>
> File Attachments
> ----------------
>
> minimal test for backtrace functionality and parsing; can be built as C and C++
> https://git.reviewboard.kde.org/media/uploaded/files/2014/11/25/e9d48fea-2506-493c-b068-26a8e7d12b6c__backtrace.c
>
>
> Thanks,
>
> René J.V. Bertin
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.kde.org/pipermail/kde-mac/attachments/20141127/c0a42e92/attachment-0001.html>
More information about the kde-mac
mailing list