mirror of
git://sourceware.org/git/glibc.git
synced 2026-09-08 23:58:31 +08:00
Support loading libunwind instead of libgcc_s
The 'unwind-link' facility allows glibc to support thread cancellation
and exit (pthread_cancel, pthread_exiti, backtrace) by dynamically
loading the unwind library at runtime, preventing a hard dependency on
libgcc_s within libc.so.
When building with libunwind (for clang/LLVM toolchains [1]), two
assumptions in the existing code break:
1. The runtime library is libunwind.so instead of libgcc_s.so.
2. libgcc relies on __gcc_personality_v0 to handle unwinding mechanics.
libunwind exposes the standard '_Unwind_*' accessors directly.
This patch adapts `unwind-link` to handle both environments based on
the HAVE_CC_WITH_LIBUNWIND configuration:
* The UNWIND_SONAME macro now selects between LIBGCC_S_SO and
LIBUNWIND_SO.
* For libgcc, it continues to resolve `__gcc_personality_v0`.
* For libunwind, it instead resolves the standard
_Unwind_GetLanguageSpecificData, _Unwind_SetGR, _Unwind_SetIP,
and _Unwind_GetRegionStart helpers.
* unwind-resume.c is updated to implement wrappers for these
accessors that forward calls to the dynamically loaded function
pointers, effectively shimming the unwinder.
Tests and Makefiles are updated to link against `$(libunwind)` where
appropriate.
Reviewed-by: Sam James <sam@gentoo.org>
[1] https://github.com/libunwind/libunwind
This commit is contained in:
@@ -2765,6 +2765,8 @@ $(objpfx)tst-big-note-lib.so: $(objpfx)tst-big-note-lib.o
|
||||
$(LINK.o) -shared -o $@ $(LDFLAGS.so) $(dt-relr-ldflag) $<
|
||||
|
||||
$(objpfx)tst-unwind-ctor: $(objpfx)tst-unwind-ctor-lib.so
|
||||
LDLIBS-tst-unwind-ctor += $(libunwind)
|
||||
LDFLAGS-tst-unwind-ctor-lib.so = -Wl,--unresolved-symbols=ignore-all
|
||||
|
||||
CFLAGS-tst-unwind-main.c += -funwind-tables -DUSE_PTHREADS=0
|
||||
|
||||
|
||||
+33
-1
@@ -37,6 +37,12 @@ static void *global_libgcc_handle;
|
||||
may depend on unwinding. */
|
||||
__libc_lock_define (static, lock);
|
||||
|
||||
#ifndef HAVE_CC_WITH_LIBUNWIND
|
||||
# define UNWIND_SONAME LIBGCC_S_SO
|
||||
#else
|
||||
# define UNWIND_SONAME LIBUNWIND_SO
|
||||
#endif
|
||||
|
||||
struct unwind_link *
|
||||
__libc_unwind_link_get (void)
|
||||
{
|
||||
@@ -48,7 +54,7 @@ __libc_unwind_link_get (void)
|
||||
/* Initialize a copy of the data, so that we do not need about
|
||||
unlocking in case the dynamic loader somehow triggers
|
||||
unwinding. */
|
||||
void *local_libgcc_handle = __libc_dlopen (LIBGCC_S_SO);
|
||||
void *local_libgcc_handle = __libc_dlopen (UNWIND_SONAME);
|
||||
if (local_libgcc_handle == NULL)
|
||||
{
|
||||
__libc_lock_unlock (lock);
|
||||
@@ -72,8 +78,19 @@ __libc_unwind_link_get (void)
|
||||
local.ptr___frame_state_for
|
||||
= __libc_dlsym (local_libgcc_handle, "__frame_state_for");
|
||||
#endif
|
||||
#ifndef HAVE_CC_WITH_LIBUNWIND
|
||||
local.ptr_personality
|
||||
= __libc_dlsym (local_libgcc_handle, "__gcc_personality_v0");
|
||||
#else
|
||||
local.ptr__Unwind_GetLanguageSpecificData
|
||||
= __libc_dlsym (local_libgcc_handle, "_Unwind_GetLanguageSpecificData");
|
||||
local.ptr__Unwind_SetGR
|
||||
= __libc_dlsym (local_libgcc_handle, "_Unwind_SetGR");
|
||||
local.ptr__Unwind_SetIP
|
||||
= __libc_dlsym (local_libgcc_handle, "_Unwind_SetIP");
|
||||
local.ptr__Unwind_GetRegionStart
|
||||
= __libc_dlsym (local_libgcc_handle, "_Unwind_GetRegionStart");
|
||||
#endif
|
||||
UNWIND_LINK_EXTRA_INIT
|
||||
|
||||
/* If a symbol is missing, libgcc_s has somehow been corrupted. */
|
||||
@@ -84,7 +101,15 @@ __libc_unwind_link_get (void)
|
||||
assert (local.ptr__Unwind_GetIP != NULL);
|
||||
#endif
|
||||
assert (local.ptr__Unwind_Resume != NULL);
|
||||
#ifndef HAVE_CC_WITH_LIBUNWIND
|
||||
assert (local.ptr_personality != NULL);
|
||||
#else
|
||||
assert (local.ptr__Unwind_GetLanguageSpecificData != NULL);
|
||||
assert (local.ptr__Unwind_SetGR != NULL);
|
||||
assert (local.ptr__Unwind_GetIP != NULL);
|
||||
assert (local.ptr__Unwind_SetIP != NULL);
|
||||
assert (local.ptr__Unwind_GetRegionStart != NULL);
|
||||
#endif
|
||||
|
||||
PTR_MANGLE (local.ptr__Unwind_Backtrace);
|
||||
PTR_MANGLE (local.ptr__Unwind_ForcedUnwind);
|
||||
@@ -96,7 +121,14 @@ __libc_unwind_link_get (void)
|
||||
#if UNWIND_LINK_FRAME_STATE_FOR
|
||||
PTR_MANGLE (local.ptr___frame_state_for);
|
||||
#endif
|
||||
#ifndef HAVE_CC_WITH_LIBUNWIND
|
||||
PTR_MANGLE (local.ptr_personality);
|
||||
#else
|
||||
PTR_MANGLE (local.ptr__Unwind_GetLanguageSpecificData);
|
||||
PTR_MANGLE (local.ptr__Unwind_SetGR);
|
||||
PTR_MANGLE (local.ptr__Unwind_SetIP);
|
||||
PTR_MANGLE (local.ptr__Unwind_GetRegionStart);
|
||||
#endif
|
||||
|
||||
__libc_lock_lock (lock);
|
||||
if (atomic_load_relaxed (&global_libgcc_handle) != NULL)
|
||||
|
||||
@@ -87,7 +87,7 @@ __pthread_cancel (pthread_t th)
|
||||
{
|
||||
struct unwind_link *unwind_link = __libc_unwind_link_get ();
|
||||
if (unwind_link == NULL)
|
||||
__libc_fatal (LIBGCC_S_SO
|
||||
__libc_fatal (UNWIND_SONAME
|
||||
" must be installed for pthread_cancel to work\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ __pthread_exit (void *value)
|
||||
{
|
||||
struct unwind_link *unwind_link = __libc_unwind_link_get ();
|
||||
if (unwind_link == NULL)
|
||||
__libc_fatal (LIBGCC_S_SO
|
||||
__libc_fatal (UNWIND_SONAME
|
||||
" must be installed for pthread_exit to work\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -68,3 +68,5 @@ libmvec=1
|
||||
|
||||
# The malloc debug library
|
||||
libc_malloc_debug=0
|
||||
|
||||
libunwind=1
|
||||
|
||||
@@ -34,6 +34,12 @@ unwind_arch_adjustment (void *prev, void *addr)
|
||||
# include <pointer_guard.h>
|
||||
# include <unwind-resume.h>
|
||||
|
||||
# ifndef HAVE_CC_WITH_LIBUNWIND
|
||||
# define UNWIND_SONAME LIBGCC_S_SO
|
||||
# else
|
||||
# define UNWIND_SONAME LIBUNWIND_SO
|
||||
# endif
|
||||
|
||||
# if UNWIND_LINK_FRAME_STATE_FOR
|
||||
struct frame_state;
|
||||
# endif
|
||||
@@ -50,7 +56,14 @@ struct unwind_link
|
||||
#if UNWIND_LINK_FRAME_STATE_FOR
|
||||
struct frame_state *(*ptr___frame_state_for) (void *, struct frame_state *);
|
||||
#endif
|
||||
#ifndef HAVE_CC_WITH_LIBUNWIND
|
||||
_Unwind_Reason_Code (*ptr_personality) PERSONALITY_PROTO;
|
||||
#else
|
||||
__typeof (_Unwind_GetLanguageSpecificData) *ptr__Unwind_GetLanguageSpecificData;
|
||||
__typeof (_Unwind_SetGR) *ptr__Unwind_SetGR;
|
||||
__typeof (_Unwind_SetIP) *ptr__Unwind_SetIP;
|
||||
__typeof (_Unwind_GetRegionStart) *ptr__Unwind_GetRegionStart;
|
||||
#endif
|
||||
UNWIND_LINK_EXTRA_FIELDS
|
||||
};
|
||||
|
||||
|
||||
@@ -38,11 +38,43 @@ _Unwind_Resume (struct _Unwind_Exception *exc)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_CC_WITH_LIBUNWIND
|
||||
_Unwind_Reason_Code
|
||||
__gcc_personality_v0 PERSONALITY_PROTO
|
||||
{
|
||||
return UNWIND_LINK_PTR (link (), personality) PERSONALITY_ARGS;
|
||||
}
|
||||
#else
|
||||
void *
|
||||
_Unwind_GetLanguageSpecificData (struct _Unwind_Context *context)
|
||||
{
|
||||
return UNWIND_LINK_PTR (link (), _Unwind_GetLanguageSpecificData) (context);
|
||||
}
|
||||
|
||||
void
|
||||
_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val)
|
||||
{
|
||||
UNWIND_LINK_PTR (link (), _Unwind_SetGR) (context, index, val);
|
||||
}
|
||||
|
||||
_Unwind_Ptr
|
||||
_Unwind_GetIP (struct _Unwind_Context *context)
|
||||
{
|
||||
return UNWIND_LINK_PTR (link (), _Unwind_GetIP) (context);
|
||||
}
|
||||
|
||||
void
|
||||
_Unwind_SetIP (struct _Unwind_Context *context, _Unwind_Ptr val)
|
||||
{
|
||||
UNWIND_LINK_PTR (link (), _Unwind_SetIP) (context, val);
|
||||
}
|
||||
|
||||
_Unwind_Ptr
|
||||
_Unwind_GetRegionStart (struct _Unwind_Context *context)
|
||||
{
|
||||
return UNWIND_LINK_PTR (link (), _Unwind_GetRegionStart) (context);
|
||||
}
|
||||
#endif
|
||||
|
||||
_Unwind_Reason_Code
|
||||
_Unwind_ForcedUnwind (struct _Unwind_Exception *exc, _Unwind_Stop_Fn stop,
|
||||
|
||||
Reference in New Issue
Block a user