Skip to content

Commit

Permalink
[libunwind][AIX] Remove weak declaration "__xlcxx_personality_v0" (ll…
Browse files Browse the repository at this point in the history
…vm#112436)

`__xlcxx_personality_v0` is the personality routine in `libc++abi` for
the EH of applications generated by the legacy IBM C++ compiler. Since
the EH info generated by the legacy compiler does not provide the
location of the personality routine, this routine is hard-coded as the
handler for legacy EH in the unwinder. The symbol is resolved
dynamically using `dlopen()` to avoid a hard dependency of `libunwind`
on `libc++abi` for cases such as non-C++ applications. The weak
declaration of `__xlcxx_personality_v0` was originally intended to
bypass `dlopen()` if the C++ application generated by the legacy
compiler is statically linked with the new LLVM C++ compiler.
Unfortunately, this causes problems with runtime linking for
Clang-compiled code using the unwinder that does not link with
`libc++abi`.

On the other hand, the C++ runtime libraries shipped for AIX are
actually stripped and statically linking is not supported. So, we can
fix the problem by removing the `__xlcxx_personality_v0` weak
declaration. Besides, `dlopen()` would work as long as the libc++abi
shared library is available.
  • Loading branch information
xingxue-ibm authored and EricWF committed Oct 22, 2024
1 parent a6b940a commit 9d66361
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 30 deletions.
52 changes: 22 additions & 30 deletions libunwind/src/UnwindCursor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2033,7 +2033,6 @@ typedef _Unwind_Reason_Code __xlcxx_personality_v0_t(int, _Unwind_Action,
uint64_t,
_Unwind_Exception *,
struct _Unwind_Context *);
__attribute__((__weak__)) __xlcxx_personality_v0_t __xlcxx_personality_v0;
}

static __xlcxx_personality_v0_t *xlcPersonalityV0;
Expand Down Expand Up @@ -2126,42 +2125,35 @@ bool UnwindCursor<A, R>::getInfoFromTBTable(pint_t pc, R &registers) {
// function __xlcxx_personality_v0(), which is the personality for the state
// table and is exported from libc++abi, is directly assigned as the
// handler here. When a legacy XLC++ frame is encountered, the symbol
// is resolved dynamically using dlopen() to avoid hard dependency from
// libunwind on libc++abi.
// is resolved dynamically using dlopen() to avoid a hard dependency of
// libunwind on libc++abi in cases such as non-C++ applications.

// Resolve the function pointer to the state table personality if it has
// not already.
// not already been done.
if (xlcPersonalityV0 == NULL) {
xlcPersonalityV0InitLock.lock();
if (xlcPersonalityV0 == NULL) {
// If libc++abi is statically linked in, symbol __xlcxx_personality_v0
// has been resolved at the link time.
xlcPersonalityV0 = &__xlcxx_personality_v0;
// Resolve __xlcxx_personality_v0 using dlopen().
const char *libcxxabi = "libc++abi.a(libc++abi.so.1)";
void *libHandle;
// The AIX dlopen() sets errno to 0 when it is successful, which
// clobbers the value of errno from the user code. This is an AIX
// bug because according to POSIX it should not set errno to 0. To
// workaround before AIX fixes the bug, errno is saved and restored.
int saveErrno = errno;
libHandle = dlopen(libcxxabi, RTLD_MEMBER | RTLD_NOW);
if (libHandle == NULL) {
_LIBUNWIND_TRACE_UNWINDING("dlopen() failed with errno=%d\n", errno);
assert(0 && "dlopen() failed");
}
xlcPersonalityV0 = reinterpret_cast<__xlcxx_personality_v0_t *>(
dlsym(libHandle, "__xlcxx_personality_v0"));
if (xlcPersonalityV0 == NULL) {
// libc++abi is dynamically linked. Resolve __xlcxx_personality_v0
// using dlopen().
const char libcxxabi[] = "libc++abi.a(libc++abi.so.1)";
void *libHandle;
// The AIX dlopen() sets errno to 0 when it is successful, which
// clobbers the value of errno from the user code. This is an AIX
// bug because according to POSIX it should not set errno to 0. To
// workaround before AIX fixes the bug, errno is saved and restored.
int saveErrno = errno;
libHandle = dlopen(libcxxabi, RTLD_MEMBER | RTLD_NOW);
if (libHandle == NULL) {
_LIBUNWIND_TRACE_UNWINDING("dlopen() failed with errno=%d\n",
errno);
assert(0 && "dlopen() failed");
}
xlcPersonalityV0 = reinterpret_cast<__xlcxx_personality_v0_t *>(
dlsym(libHandle, "__xlcxx_personality_v0"));
if (xlcPersonalityV0 == NULL) {
_LIBUNWIND_TRACE_UNWINDING("dlsym() failed with errno=%d\n", errno);
assert(0 && "dlsym() failed");
}
dlclose(libHandle);
errno = saveErrno;
_LIBUNWIND_TRACE_UNWINDING("dlsym() failed with errno=%d\n", errno);
assert(0 && "dlsym() failed");
}
dlclose(libHandle);
errno = saveErrno;
}
xlcPersonalityV0InitLock.unlock();
}
Expand Down
20 changes: 20 additions & 0 deletions libunwind/test/aix_runtime_link.pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

// Test that libunwind loads successfully independently of libc++abi with
// runtime linking on AIX.

// REQUIRES: target={{.+}}-aix{{.*}}
// ADDITIONAL_COMPILE_FLAGS: -Wl,-brtl

#include <unwind.h>
extern "C" int printf(const char *, ...);
int main(void) {
void *fp = (void *)&_Unwind_Backtrace;
printf("%p\n", fp);
}

0 comments on commit 9d66361

Please sign in to comment.