This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug target/42159] unwinding issues on darwin
- From: "niklas.hauser at arm dot com" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: Tue, 03 Oct 2017 09:57:16 +0000
- Subject: [Bug target/42159] unwinding issues on darwin
- Auto-submitted: auto-generated
- References: <bug-42159-4@http.gcc.gnu.org/bugzilla/>
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=42159
Niklas Hauser <niklas.hauser at arm dot com> changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |niklas.hauser at arm dot com
--- Comment #35 from Niklas Hauser <niklas.hauser at arm dot com> ---
We can reproduce this issue on OS X 10.12, please see below for a detailed
analysis of the underlying problem.
This issue is fixed by the patch proposed by Pierre Ossman. Did this patch (or
maybe a similar solution) make it upstream already?
Summary of cause:
The libgcc unwinder implementation is broken for all 64-bit builds of OS X
(since 10.6) due to a non-backwards compatible change in the _keymgr API, which
does not provide a process-wide image list anymore.
Details of cause:
This is the minimal example to reproduce the issue on OS X (>10.6):
#include <iostream>
int main() {
try {
throw 20;
}
catch (int e) {
std::cout << "Exception No. " << e << "\n";
}
return 0;
}
Running this application will cause a SIGABRT:
g++ -static-libgcc -o failboat main.cpp && ./failboat
[1] 4047 abort ./failboat
Stack trace of this failure is:
...
#12 0x00007fff5fbff370 in ?? ()
#13 0x00000001000987c1 in uw_init_context_1 ()
#14 0x0000000100098e1e in _Unwind_RaiseException ()
#15 0x000000010000d81b in __cxa_throw ()
#16 0x0000000100000b30 in main () at main.cpp:4
We're failing an assert in uw_init_context_1 (gcc/libgcc/unwind-dw2.c:1578):
code = uw_frame_state_for (context, &fs);
gcc_assert (code == _URC_NO_REASON);
Specifically uw_frame_state_for returns code _URC_END_OF_STACK and this then
fails the gcc_assert, which then unwraps in a SIGABRT. uw_frame_state_for()
calls _Unwind_Find_FDE() in gcc/libgcc/unwind-dw2.c:1249, which returns NULL
however and the entire function therefore returns _URC_END_OF_STACK:
fde = _Unwind_Find_FDE (context->ra + _Unwind_IsSignalFrame (context) - 1,
&context->bases);
if (fde == NULL)
{
return _URC_END_OF_STACK;
}
_Unwind_Find_FDE() is defined in gcc/libgcc/unwind-dw2-fde.c:1027, EXCEPT on OS
X (aka. Darwin), where it is reimplemented in
gcc/libgcc/config/unwind-dw2-fde-darwin.c:244!
This implementation uses the _keymgr API to access Dwarf2 object lists and ELF
images (with the KEYMGR_GCC3_DW2_OBJ_LIST and KEYMGR_GCC3_LIVE_IMAGE_LIST keys,
respectively).
The function first checks the Dwarf2 object lists, then falls back to using the
original implementation (which has been renamed to
_Unwind_Find_registered_FDE()) before searching the ELF images in
examine_objects:
the_obj_info =
_keymgr_get_and_lock_processwide_ptr (KEYMGR_GCC3_DW2_OBJ_LIST);
if (! the_obj_info)
the_obj_info = calloc (1, sizeof (*the_obj_info));
if (the_obj_info != NULL)
{
/* code removed for brevity */
ret = _Unwind_Find_registered_FDE (pc, bases);
}
/* OK, didn't find it in the list of FDEs we've seen before,
so go through and look at the new ones. */
if (ret == NULL)
ret = examine_objects (pc, bases, the_obj_info == NULL);
Here the first call to KEYMGR_GCC3_DW2_OBJ_LIST returns NULL, thus an empty
object list is allocated. _Unwind_Find_registered_FDE() returns NULL too, since
it operates only on previously seen objects, of which there are none yet.
Finally, examine_objects is finally called, which contains:
image = _keymgr_get_and_lock_processwide_ptr (KEYMGR_GCC3_LIVE_IMAGE_LIST);
Note how the KEYMGR_GCC3_DW2_OBJ_LIST list is used as a "cache" of previously
seen Dwarf2 objects and is first populated by examine_objects() using the
KEYMGR_GCC3_LIVE_IMAGE_LIST.
However, on 64-bit builds of OS X, KEYMGR_GCC3_LIVE_IMAGE_LIST always returns
NULL and so the image information can never be retrieved. The reason for this
is found in the implementation of keymgr.c, which is published here:
https://opensource.apple.com/source/keymgr/keymgr-28/keymgr.c.auto.html.
At the very bottom, in __keymgr_initializer() it says:
#if __x86_64__
/* On Mac OS X 10.6, libunwind in libSystem.dylib implements all unwinding
functionality. */
/* libunwind does not use keymgr, so there is no need to maintain
KEYMGR_GCC3_LIVE_IMAGE_LIST */
/* in sync with dyld's list of images. But there might be some i386 or ppc
applications that */
/* carry around there own copy of the unwinder (from libgcc.a) and need
KEYMGR_GCC3_LIVE_IMAGE_LIST. */
#else
/* register with dyld so that we are notified about all loaded mach-o
images */
_dyld_register_func_for_add_image (dwarf2_unwind_dyld_add_image_hook);
_dyld_register_func_for_remove_image
(dwarf2_unwind_dyld_remove_image_hook);
#endif /* __x86_64__ */
On 64-bit builds of OS X these images are simply never added. The libgcc
unwinder code can therefore never work, since it relies on this information.