(Note I am also applying this to main and stable/13, to restore the old libcxxrt ABI and to avoid having to maintain a compat library.) After the recent cherry-picking of libcxxrt commits0ee0dbfb0d
andd2b3fadf2d
, users reported that editors/libreoffice packages from the official package builders did not start anymore. It turns out that the combination of these commits subtly changes the ABI, requiring all applications that depend on internal details of struct _Unwind_Exception (available via unwind-arm.h and unwind-itanium.h) to be recompiled. However, the FreeBSD package builders always use -RELEASE jails, so these still use the old declaration of struct _Unwind_Exception, which is not entirely compatible. In particular, LibreOffice uses this struct in its internal "uno bridge" component, where it attempts to setup its own exception handling mechanism. To fix this incompatibility, go back to the old declarations of struct _Unwind_Exception, and restore the __LP64__ specific workaround we had in place before (which was to cope with yet another, older ABI bug). Effectively, this reverts upstream libcxxrt commits 88bdf6b290da ("Specify double-word alignment for ARM unwind") and b96169641f79 ("Updated Itanium unwind"), and reapplies our commit3c4fd2463b
("libcxxrt: add padding in __cxa_allocate_* to fix alignment"). PR: 253840
232 lines
7.4 KiB
C
232 lines
7.4 KiB
C
/*
|
|
* Copyright 2012 David Chisnall. All rights reserved.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to
|
|
* deal in the Software without restriction, including without limitation the
|
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
* sell copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
/* For uint32_t and uint64_t */
|
|
#include <stdint.h>
|
|
|
|
/**
|
|
* ARM-specific unwind definitions. These are taken from the ARM EHABI
|
|
* specification.
|
|
*/
|
|
typedef enum
|
|
{
|
|
_URC_NO_REASON = 0,
|
|
_URC_OK = 0, /* operation completed successfully */
|
|
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
|
|
_URC_END_OF_STACK = 5,
|
|
_URC_HANDLER_FOUND = 6,
|
|
_URC_INSTALL_CONTEXT = 7,
|
|
_URC_CONTINUE_UNWIND = 8,
|
|
_URC_FAILURE = 9, /* unspecified failure of some kind */
|
|
_URC_FATAL_PHASE1_ERROR = _URC_FAILURE
|
|
} _Unwind_Reason_Code;
|
|
|
|
typedef int _Unwind_Action;
|
|
|
|
typedef uint32_t _Unwind_State;
|
|
#ifdef __clang__
|
|
static const _Unwind_State _US_VIRTUAL_UNWIND_FRAME = 0;
|
|
static const _Unwind_State _US_UNWIND_FRAME_STARTING = 1;
|
|
static const _Unwind_State _US_UNWIND_FRAME_RESUME = 2;
|
|
static const _Unwind_State _US_ACTION_MASK = 3;
|
|
#else // GCC fails at knowing what a constant expression is
|
|
# define _US_VIRTUAL_UNWIND_FRAME 0
|
|
# define _US_UNWIND_FRAME_STARTING 1
|
|
# define _US_UNWIND_FRAME_RESUME 2
|
|
# define _US_ACTION_MASK 3
|
|
#endif
|
|
|
|
typedef struct _Unwind_Context _Unwind_Context;
|
|
|
|
typedef uint32_t _Unwind_EHT_Header;
|
|
|
|
struct _Unwind_Exception
|
|
{
|
|
uint64_t exception_class;
|
|
void (*exception_cleanup)(_Unwind_Reason_Code, struct _Unwind_Exception *);
|
|
/* Unwinder cache, private fields for the unwinder's use */
|
|
struct
|
|
{
|
|
uint32_t reserved1;
|
|
uint32_t reserved2;
|
|
uint32_t reserved3;
|
|
uint32_t reserved4;
|
|
uint32_t reserved5;
|
|
/* init reserved1 to 0, then don't touch */
|
|
} unwinder_cache;
|
|
/* Propagation barrier cache (valid after phase 1): */
|
|
struct
|
|
{
|
|
uint32_t sp;
|
|
uint32_t bitpattern[5];
|
|
} barrier_cache;
|
|
/* Cleanup cache (preserved over cleanup): */
|
|
struct
|
|
{
|
|
uint32_t bitpattern[4];
|
|
} cleanup_cache;
|
|
/* Pr cache (for pr's benefit): */
|
|
struct
|
|
{
|
|
/** function start address */
|
|
uint32_t fnstart;
|
|
/** pointer to EHT entry header word */
|
|
_Unwind_EHT_Header *ehtp;
|
|
/** additional data */
|
|
uint32_t additional;
|
|
uint32_t reserved1;
|
|
} pr_cache;
|
|
/** Force alignment of next item to 8-byte boundary */
|
|
long long int :0;
|
|
};
|
|
|
|
/* Unwinding functions */
|
|
_Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception *ucbp);
|
|
void _Unwind_Resume(struct _Unwind_Exception *ucbp);
|
|
void _Unwind_Complete(struct _Unwind_Exception *ucbp);
|
|
void _Unwind_DeleteException(struct _Unwind_Exception *ucbp);
|
|
void *_Unwind_GetLanguageSpecificData(struct _Unwind_Context*);
|
|
|
|
typedef enum
|
|
{
|
|
_UVRSR_OK = 0,
|
|
_UVRSR_NOT_IMPLEMENTED = 1,
|
|
_UVRSR_FAILED = 2
|
|
} _Unwind_VRS_Result;
|
|
typedef enum
|
|
{
|
|
_UVRSC_CORE = 0,
|
|
_UVRSC_VFP = 1,
|
|
_UVRSC_WMMXD = 3,
|
|
_UVRSC_WMMXC = 4
|
|
} _Unwind_VRS_RegClass;
|
|
typedef enum
|
|
{
|
|
_UVRSD_UINT32 = 0,
|
|
_UVRSD_VFPX = 1,
|
|
_UVRSD_UINT64 = 3,
|
|
_UVRSD_FLOAT = 4,
|
|
_UVRSD_DOUBLE = 5
|
|
} _Unwind_VRS_DataRepresentation;
|
|
|
|
_Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context *context,
|
|
_Unwind_VRS_RegClass regclass,
|
|
uint32_t regno,
|
|
_Unwind_VRS_DataRepresentation representation,
|
|
void *valuep);
|
|
_Unwind_VRS_Result _Unwind_VRS_Set(_Unwind_Context *context,
|
|
_Unwind_VRS_RegClass regclass,
|
|
uint32_t regno,
|
|
_Unwind_VRS_DataRepresentation representation,
|
|
void *valuep);
|
|
|
|
/* Return the base-address for data references. */
|
|
extern unsigned long _Unwind_GetDataRelBase(struct _Unwind_Context *);
|
|
|
|
/* Return the base-address for text references. */
|
|
extern unsigned long _Unwind_GetTextRelBase(struct _Unwind_Context *);
|
|
extern unsigned long _Unwind_GetRegionStart(struct _Unwind_Context *);
|
|
|
|
typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn) (struct _Unwind_Context *,
|
|
void *);
|
|
extern _Unwind_Reason_Code _Unwind_Backtrace (_Unwind_Trace_Fn, void *);
|
|
extern _Unwind_Reason_Code
|
|
_Unwind_Resume_or_Rethrow (struct _Unwind_Exception *);
|
|
|
|
/**
|
|
* The next set of functions are compatibility extensions, implementing Itanium
|
|
* ABI functions on top of ARM ones.
|
|
*/
|
|
|
|
#define _UA_SEARCH_PHASE 1
|
|
#define _UA_CLEANUP_PHASE 2
|
|
#define _UA_HANDLER_FRAME 4
|
|
#define _UA_FORCE_UNWIND 8
|
|
|
|
static inline unsigned long _Unwind_GetGR(struct _Unwind_Context *context, int reg)
|
|
{
|
|
unsigned long val;
|
|
_Unwind_VRS_Get(context, _UVRSC_CORE, reg, _UVRSD_UINT32, &val);
|
|
return val;
|
|
}
|
|
static inline void _Unwind_SetGR(struct _Unwind_Context *context, int reg, unsigned long val)
|
|
{
|
|
_Unwind_VRS_Set(context, _UVRSC_CORE, reg, _UVRSD_UINT32, &val);
|
|
}
|
|
static inline unsigned long _Unwind_GetIP(_Unwind_Context *context)
|
|
{
|
|
// Low bit store the thumb state - discard it
|
|
return _Unwind_GetGR(context, 15) & ~1;
|
|
}
|
|
static inline void _Unwind_SetIP(_Unwind_Context *context, unsigned long val)
|
|
{
|
|
// The lowest bit of the instruction pointer indicates whether we're in
|
|
// thumb or ARM mode. This is assumed to be fixed throughout a function,
|
|
// so must be propagated when setting the program counter.
|
|
unsigned long thumbState = _Unwind_GetGR(context, 15) & 1;
|
|
_Unwind_SetGR(context, 15, (val | thumbState));
|
|
}
|
|
|
|
/** GNU API function that unwinds the frame */
|
|
_Unwind_Reason_Code __gnu_unwind_frame(struct _Unwind_Exception*, struct _Unwind_Context*);
|
|
|
|
|
|
#define DECLARE_PERSONALITY_FUNCTION(name) \
|
|
_Unwind_Reason_Code name(_Unwind_State state,\
|
|
struct _Unwind_Exception *exceptionObject,\
|
|
struct _Unwind_Context *context);
|
|
|
|
#define BEGIN_PERSONALITY_FUNCTION(name) \
|
|
_Unwind_Reason_Code name(_Unwind_State state,\
|
|
struct _Unwind_Exception *exceptionObject,\
|
|
struct _Unwind_Context *context)\
|
|
{\
|
|
int version = 1;\
|
|
uint64_t exceptionClass = exceptionObject->exception_class;\
|
|
int actions;\
|
|
switch (state)\
|
|
{\
|
|
default: return _URC_FAILURE;\
|
|
case _US_VIRTUAL_UNWIND_FRAME:\
|
|
{\
|
|
actions = _UA_SEARCH_PHASE;\
|
|
break;\
|
|
}\
|
|
case _US_UNWIND_FRAME_STARTING:\
|
|
{\
|
|
actions = _UA_CLEANUP_PHASE;\
|
|
if (exceptionObject->barrier_cache.sp == _Unwind_GetGR(context, 13))\
|
|
{\
|
|
actions |= _UA_HANDLER_FRAME;\
|
|
}\
|
|
break;\
|
|
}\
|
|
case _US_UNWIND_FRAME_RESUME:\
|
|
{\
|
|
return continueUnwinding(exceptionObject, context);\
|
|
break;\
|
|
}\
|
|
}\
|
|
_Unwind_SetGR (context, 12, reinterpret_cast<unsigned long>(exceptionObject));\
|
|
|
|
#define CALL_PERSONALITY_FUNCTION(name) name(state,exceptionObject,context)
|