3131 */
3232void __register_frame (const void * );
3333void __deregister_frame (const void * );
34+
35+ # if defined(__linux__ ) && defined(__clang__ ) && \
36+ (__clang_major__ >= 22 ) && (__clang_major__ <= 23 )
37+ # define PY_JIT_GNU_BACKTRACE_REGISTER_FDE
38+ # endif
39+
40+ # if defined(PY_JIT_GNU_BACKTRACE_REGISTER_FDE )
41+ typedef struct JitGnuBacktraceRegistration {
42+ uint8_t * eh_frame ;
43+ const void * registered_frame ;
44+ } JitGnuBacktraceRegistration ;
45+ # endif
3446#endif
3547#include <stdio.h>
3648#include <string.h>
@@ -1008,6 +1020,50 @@ _PyJitUnwind_GdbUnregisterCode(void *handle)
10081020}
10091021
10101022#if defined(PY_HAVE_JIT_GNU_BACKTRACE_UNWIND )
1023+ #if defined(PY_JIT_GNU_BACKTRACE_REGISTER_FDE )
1024+ static const void *
1025+ gnu_backtrace_registration_frame (const uint8_t * eh_frame , size_t eh_frame_size )
1026+ {
1027+ /*
1028+ * LLVM libunwind 22 and 23 implement __register_frame as a single-FDE
1029+ * registration API. The compiler-version check above is intentionally a
1030+ * narrow toolchain guard requested for those releases; it is not a
1031+ * general runtime unwinder capability probe.
1032+ */
1033+ uint32_t cie_length ;
1034+ if (eh_frame == NULL || eh_frame_size < 2 * sizeof (uint32_t )) {
1035+ return NULL ;
1036+ }
1037+ memcpy (& cie_length , eh_frame , sizeof (cie_length ));
1038+ if (cie_length == 0 || cie_length == UINT32_MAX ) {
1039+ return NULL ;
1040+ }
1041+
1042+ size_t fde_offset = sizeof (uint32_t ) + (size_t )cie_length ;
1043+ if (fde_offset > eh_frame_size - 2 * sizeof (uint32_t )) {
1044+ return NULL ;
1045+ }
1046+
1047+ uint32_t fde_length ;
1048+ memcpy (& fde_length , eh_frame + fde_offset , sizeof (fde_length ));
1049+ if (fde_length == 0 || fde_length == UINT32_MAX ) {
1050+ return NULL ;
1051+ }
1052+ if ((size_t )fde_length > eh_frame_size - fde_offset - sizeof (uint32_t )) {
1053+ return NULL ;
1054+ }
1055+
1056+ uint32_t cie_pointer ;
1057+ memcpy (& cie_pointer , eh_frame + fde_offset + sizeof (fde_length ),
1058+ sizeof (cie_pointer ));
1059+ if (cie_pointer == 0 ) {
1060+ return NULL ;
1061+ }
1062+
1063+ return eh_frame + fde_offset ;
1064+ }
1065+ #endif
1066+
10111067void *
10121068_PyJitUnwind_GnuBacktraceRegisterCode (const void * code_addr , size_t code_size )
10131069{
@@ -1044,8 +1100,29 @@ _PyJitUnwind_GnuBacktraceRegisterCode(const void *code_addr, size_t code_size)
10441100 return NULL ;
10451101 }
10461102
1103+ #if defined(PY_JIT_GNU_BACKTRACE_REGISTER_FDE )
1104+ const void * registered_frame = gnu_backtrace_registration_frame (
1105+ eh_frame , eh_frame_size );
1106+ if (registered_frame == NULL ) {
1107+ PyMem_RawFree (eh_frame );
1108+ return NULL ;
1109+ }
1110+
1111+ JitGnuBacktraceRegistration * registration =
1112+ PyMem_RawMalloc (sizeof (* registration ));
1113+ if (registration == NULL ) {
1114+ PyMem_RawFree (eh_frame );
1115+ return NULL ;
1116+ }
1117+ registration -> eh_frame = eh_frame ;
1118+ registration -> registered_frame = registered_frame ;
1119+
1120+ __register_frame (registered_frame );
1121+ return registration ;
1122+ #else
10471123 __register_frame (eh_frame );
10481124 return eh_frame ;
1125+ #endif
10491126}
10501127
10511128void
@@ -1054,8 +1131,16 @@ _PyJitUnwind_GnuBacktraceUnregisterCode(void *handle)
10541131 if (handle == NULL ) {
10551132 return ;
10561133 }
1134+ #if defined(PY_JIT_GNU_BACKTRACE_REGISTER_FDE )
1135+ JitGnuBacktraceRegistration * registration =
1136+ (JitGnuBacktraceRegistration * )handle ;
1137+ __deregister_frame (registration -> registered_frame );
1138+ PyMem_RawFree (registration -> eh_frame );
1139+ PyMem_RawFree (registration );
1140+ #else
10571141 __deregister_frame (handle );
10581142 PyMem_RawFree (handle );
1143+ #endif
10591144}
10601145#endif // defined(PY_HAVE_JIT_GNU_BACKTRACE_UNWIND)
10611146
0 commit comments