Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 75 additions & 6 deletions compiler-rt/lib/builtins/gcc_personality_v0.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,54 @@ EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, void *, PCONTEXT,
_Unwind_Personality_Fn);
#endif

#if __has_feature(ptrauth_calls)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed previously, let's use the new macro LIBUNWIND_PTRAUTH_CALLS_AND_RETURNS defined as follows everywhere instead of __has_include(<ptrauth.h>), __has_feature(ptrauth_calls), __has_feature(ptrauth_returns), __has_extension(ptrauth_qualifier), etc:

#if __has_feature(ptrauth_calls) && __has_feature(ptrauth_returns)
#define LIBUNWIND_PTRAUTH_CALLS_AND_RETURNS
#elif __has_feature(ptrauth_calls) || __has_feature(ptrauth_returns)
#error "Either both or none of ptrauth_calls and ptrauth_returns is allowed to be enabled"
#endif

See proposed fix in commit 644405b in my branch https://github.com/kovdan01/llvm-project/commits/pointer-authenticated-unwinding-2025-09-22-with-fixes/.

I think this should be done in scope of this PR.

#include <ptrauth.h>

// `__ptrauth_restricted_intptr` is a feature of apple clang that predates
// support for direct application of `__ptrauth` to integer types. This
// guard is necessary to support compilation with those compiler.
#if __has_feature(ptrauth_restricted_intptr_qualifier)
#define __ptrauth_gcc_personality_intptr(key, addressDiscriminated, \
discriminator) \
__ptrauth_restricted_intptr(key, addressDiscriminated, discriminator)
#else
#define __ptrauth_gcc_personality_intptr(key, addressDiscriminated, \
discriminator) \
__ptrauth(key, addressDiscriminated, discriminator)
#endif
#else
#define __ptrauth_gcc_personality_intptr(...)
#endif

#define __ptrauth_gcc_personality_func_key ptrauth_key_function_pointer

// ptrauth_string_discriminator("__gcc_personality_v0'funcStart") == 0xDFEB
#define __ptrauth_gcc_personality_func_start \
__ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, \
0xDFEB)

// ptrauth_string_discriminator("__gcc_personality_v0'start") == 0x52DC
#define __ptrauth_gcc_personality_start \
__ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, \
0x52DC)

// ptrauth_string_discriminator("__gcc_personality_v0'length") == 0xFFF7
#define __ptrauth_gcc_personality_length \
__ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, \
0xFFF7)

// ptrauth_string_discriminator("__gcc_personality_v0'landingPadOffset") ==
// 0x6498
#define __ptrauth_gcc_personality_lpoffset \
__ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, \
0x6498)

// ptrauth_string_discriminator("__gcc_personality_v0'landingPad") == 0xA134
#define __ptrauth_gcc_personality_lpad_disc 0xA134
#define __ptrauth_gcc_personality_lpad \
__ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, \
__ptrauth_gcc_personality_lpad_disc)

// Pointer encodings documented at:
// http://refspecs.freestandards.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html

Expand Down Expand Up @@ -205,7 +253,8 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
return continueUnwind(exceptionObject, context);

uintptr_t pc = (uintptr_t)_Unwind_GetIP(context) - 1;
uintptr_t funcStart = (uintptr_t)_Unwind_GetRegionStart(context);
uintptr_t __ptrauth_gcc_personality_func_start funcStart =
(uintptr_t)_Unwind_GetRegionStart(context);
uintptr_t pcOffset = pc - funcStart;

// Parse LSDA header.
Expand All @@ -224,11 +273,14 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
const uint8_t *callSiteTableEnd = callSiteTableStart + callSiteTableLength;
const uint8_t *p = callSiteTableStart;
while (p < callSiteTableEnd) {
uintptr_t start = readEncodedPointer(&p, callSiteEncoding);
size_t length = readEncodedPointer(&p, callSiteEncoding);
size_t landingPad = readEncodedPointer(&p, callSiteEncoding);
uintptr_t __ptrauth_gcc_personality_start start =
readEncodedPointer(&p, callSiteEncoding);
size_t __ptrauth_gcc_personality_length length =
readEncodedPointer(&p, callSiteEncoding);
size_t __ptrauth_gcc_personality_lpoffset landingPadOffset =
readEncodedPointer(&p, callSiteEncoding);
readULEB128(&p); // action value not used for C code
if (landingPad == 0)
if (landingPadOffset == 0)
continue; // no landing pad for this entry
if ((start <= pcOffset) && (pcOffset < (start + length))) {
// Found landing pad for the PC.
Expand All @@ -238,7 +290,24 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
_Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
(uintptr_t)exceptionObject);
_Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0);
_Unwind_SetIP(context, (funcStart + landingPad));
size_t __ptrauth_gcc_personality_lpad landingPad =
funcStart + landingPadOffset;
#if __has_feature(ptrauth_calls)
uintptr_t stackPointer = _Unwind_GetGR(context, -2);
const uintptr_t existingDiscriminator = ptrauth_blend_discriminator(
&landingPad, __ptrauth_gcc_personality_lpad_disc);
// newIP is authenticated as if it were qualified with a pseudo qualifier
// along the lines of:
// __ptrauth(ptrauth_key_return_address, <stackPointer>, 0)
// where the stack pointer is used in place of the strict storage
// address.
uintptr_t newIP = (uintptr_t)ptrauth_auth_and_resign(
*(void **)&landingPad, __ptrauth_gcc_personality_func_key,
existingDiscriminator, ptrauth_key_return_address, stackPointer);
_Unwind_SetIP(context, newIP);
#else
_Unwind_SetIP(context, landingPad);
#endif
return _URC_INSTALL_CONTEXT;
}
}
Expand Down
41 changes: 41 additions & 0 deletions libcxxabi/include/__cxxabi_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,47 @@
#define _LIBCXXABI_DTOR_FUNC
#endif

#if __has_include(<ptrauth.h>)
# include <ptrauth.h>
#endif

#if __has_feature(ptrauth_calls)

// ptrauth_string_discriminator("__cxa_exception::actionRecord") == 0xFC91
# define __ptrauth_cxxabi_action_record __ptrauth(ptrauth_key_process_dependent_data, 1, 0xFC91)

// ptrauth_string_discriminator("__cxa_exception::languageSpecificData") == 0xE8EE
# define __ptrauth_cxxabi_lsd __ptrauth(ptrauth_key_process_dependent_data, 1, 0xE8EE)

// ptrauth_string_discriminator("__cxa_exception::catchTemp") == 0xFA58
# define __ptrauth_cxxabi_catch_temp_disc 0xFA58
# define __ptrauth_cxxabi_catch_temp_key ptrauth_key_process_dependent_data
# define __ptrauth_cxxabi_catch_temp __ptrauth(__ptrauth_cxxabi_catch_temp_key, 1, __ptrauth_cxxabi_catch_temp_disc)

// ptrauth_string_discriminator("__cxa_exception::adjustedPtr") == 0x99E4
# define __ptrauth_cxxabi_adjusted_ptr __ptrauth(ptrauth_key_process_dependent_data, 1, 0x99E4)

// ptrauth_string_discriminator("__cxa_exception::unexpectedHandler") == 0x99A9
# define __ptrauth_cxxabi_unexpected_handler __ptrauth(ptrauth_key_function_pointer, 1, 0x99A9)

// ptrauth_string_discriminator("__cxa_exception::terminateHandler") == 0x0886)
# define __ptrauth_cxxabi_terminate_handler __ptrauth(ptrauth_key_function_pointer, 1, 0x886)

// ptrauth_string_discriminator("__cxa_exception::exceptionDestructor") == 0xC088
# define __ptrauth_cxxabi_exception_destructor __ptrauth(ptrauth_key_function_pointer, 1, 0xC088)

#else

# define __ptrauth_cxxabi_action_record
# define __ptrauth_cxxabi_lsd
# define __ptrauth_cxxabi_catch_temp
# define __ptrauth_cxxabi_adjusted_ptr
# define __ptrauth_cxxabi_unexpected_handler
# define __ptrauth_cxxabi_terminate_handler
# define __ptrauth_cxxabi_exception_destructor

#endif

#if __cplusplus < 201103L
# define _LIBCXXABI_NOEXCEPT throw()
#else
Expand Down
4 changes: 3 additions & 1 deletion libcxxabi/src/cxa_exception.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,9 @@ void *__cxa_allocate_exception(size_t thrown_size) throw() {
std::terminate();
__cxa_exception *exception_header =
static_cast<__cxa_exception *>((void *)(raw_buffer + header_offset));
::memset(exception_header, 0, actual_size);
// We warn on memset to a non-trivially castable type. We might want to
// change that diagnostic to not fire on a trivially obvious zero fill.
::memset(static_cast<void*>(exception_header), 0, actual_size);
return thrown_object_from_cxa_exception(exception_header);
}

Expand Down
30 changes: 16 additions & 14 deletions libcxxabi/src/cxa_exception.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
// In Wasm, a destructor returns its argument
void *(_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
#else
void (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
void (_LIBCXXABI_DTOR_FUNC *__ptrauth_cxxabi_exception_destructor exceptionDestructor)(void *);
#endif
std::unexpected_handler unexpectedHandler;
std::terminate_handler terminateHandler;
std::unexpected_handler __ptrauth_cxxabi_unexpected_handler unexpectedHandler;
std::terminate_handler __ptrauth_cxxabi_terminate_handler terminateHandler;

__cxa_exception *nextException;

Expand All @@ -61,10 +61,10 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
int propagationCount;
#else
int handlerSwitchValue;
const unsigned char *actionRecord;
const unsigned char *languageSpecificData;
void *catchTemp;
void *adjustedPtr;
const unsigned char *__ptrauth_cxxabi_action_record actionRecord;
const unsigned char *__ptrauth_cxxabi_lsd languageSpecificData;
void *__ptrauth_cxxabi_catch_temp catchTemp;
void *__ptrauth_cxxabi_adjusted_ptr adjustedPtr;
#endif

#if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
Expand All @@ -79,16 +79,18 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
// http://sourcery.mentor.com/archives/cxx-abi-dev/msg01924.html
// The layout of this structure MUST match the layout of __cxa_exception, with
// primaryException instead of referenceCount.
// The pointer authentication schemas specified here must also match those of
// the corresponding members in __cxa_exception.
struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
#if defined(__LP64__) || defined(_WIN64) || defined(_LIBCXXABI_ARM_EHABI)
void* reserve; // padding.
void* primaryException;
#endif

std::type_info *exceptionType;
void (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
std::unexpected_handler unexpectedHandler;
std::terminate_handler terminateHandler;
void (_LIBCXXABI_DTOR_FUNC *__ptrauth_cxxabi_exception_destructor exceptionDestructor)(void *);
std::unexpected_handler __ptrauth_cxxabi_unexpected_handler unexpectedHandler;
std::terminate_handler __ptrauth_cxxabi_terminate_handler terminateHandler;

__cxa_exception *nextException;

Expand All @@ -99,10 +101,10 @@ struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
int propagationCount;
#else
int handlerSwitchValue;
const unsigned char *actionRecord;
const unsigned char *languageSpecificData;
void * catchTemp;
void *adjustedPtr;
const unsigned char *__ptrauth_cxxabi_action_record actionRecord;
const unsigned char *__ptrauth_cxxabi_lsd languageSpecificData;
void *__ptrauth_cxxabi_catch_temp catchTemp;
void *__ptrauth_cxxabi_adjusted_ptr adjustedPtr;
#endif

#if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
Expand Down
Loading
Loading