[gcc(refs/vendors/ARM/heads/morello)] Update types in the unwinder
Matthew Malcomson
matmal01@gcc.gnu.org
Fri Dec 10 16:49:43 GMT 2021
https://gcc.gnu.org/g:bd3017caf6c4a9ab8bb63a49f173380592bae453
commit bd3017caf6c4a9ab8bb63a49f173380592bae453
Author: Matthew Malcomson <matthew.malcomson@arm.com>
Date: Fri Dec 10 16:31:17 2021 +0000
Update types in the unwinder
First thing to mention here is that these updates are *only* for the
language-independent part. I.e. we do not handle the LSDA data and
personality functions here. That is left for when we're implementing
C++.
Some parts of the unwinder need a capability type to preserve
provenance, some parts just need an address. This commit is starting to
make that distinction clear by changing the types accordingly.
So far we have:
- Allowed the return of a capability from _Unwind_GetGR, and _Unwind_GetCFA.
- Allowed a capability argument to _Unwind_SetGR, and
_Unwind_SetGRValue.
- Managed an ambiguous provenance problem creating a pointer to
dereference in `read_encoded_value_with_base`.
- Ensured that `execute_stack_op` uses a stack of capabilities and
takes a capability as its first argument. This means that in those
cases where a capability is generated the permissions and validity
tag will not be lost.
- Use capabilities for the private data in the _Unwind_Exception
structure. This data records pointers to a function and a buffer.
- Pass a capability to `aarch64_demangle_return_addr`.
(N.b. the pointer authentication builtins in this function happen to
use DImode in the unspec that implements them. However, since
the Morello boards do not implement pointer authentication, the
unwind information will not indicate the return address is signed,
and the builtins will not be used).
- Align DWARF FDE's to an address boundary (and not a capability
boundary). They are specified to be aligned to an "addressing unit
boundary", which in Morello is taken to be the alignment of an
address rather than a capability.
It happens to be that in GCC we have already made a mode attribute
for an address sized integer, and this is already used in the same
header as the dwarf_fde and dwarf_cie structures are defined. Hence
we use this type to specify the alignment that the FDE and CIE
structures will have rather than using `void *` as was done before.
- Account for the "C" character in a DWARF augmentation string.
We don't actually need to do anything about this, so we just
recognise that it exists and skip over it.
N.b. the assembler appears to insert this augmentation string
character based on whether it is assembling morello+c64 code or not
rather than based on whether it sees the `.cfi_startproc purecap`
directive or just a `.cfi_startproc` directive.
This is convenient for testing, but we will still want to emit the
correct directive from GCC in a later patch.
- Make _Unwind_FrameState->pc an address rather than a pointer.
This matches its use throughout the unwinder as something to indicate
which FDE to choose or which instructions to execute.
This is quite unlikely to be fully correct, a plain audit is prooving to
be quite error-prone. That said it appears to work for basic testing,
and unwinding without personality functions and landing pads does not
appear to have very many edge-cases, so we do expect this to work for
most C-only code.
Diff:
---
libgcc/config/aarch64/aarch64-unwind.h | 3 +-
libgcc/unwind-dw2-fde.c | 15 ++++----
libgcc/unwind-dw2-fde.h | 4 +--
libgcc/unwind-dw2.c | 63 ++++++++++++++++++----------------
libgcc/unwind-dw2.h | 7 ++--
libgcc/unwind-generic.h | 14 ++++----
libgcc/unwind-pe.h | 4 +--
7 files changed, 61 insertions(+), 49 deletions(-)
diff --git a/libgcc/config/aarch64/aarch64-unwind.h b/libgcc/config/aarch64/aarch64-unwind.h
index 3c5f85b43c8..81379bc8129 100644
--- a/libgcc/config/aarch64/aarch64-unwind.h
+++ b/libgcc/config/aarch64/aarch64-unwind.h
@@ -55,7 +55,8 @@ aarch64_cie_signed_with_b_key (struct _Unwind_Context *context)
static inline void *
aarch64_demangle_return_addr (struct _Unwind_Context *context,
- _Unwind_FrameState *fs, _Unwind_Word addr_word)
+ _Unwind_FrameState *fs,
+ _Unwind_CapWord addr_word)
{
void *addr = (void *)addr_word;
if (context->flags & RA_SIGNED_BIT)
diff --git a/libgcc/unwind-dw2-fde.c b/libgcc/unwind-dw2-fde.c
index 73a27653f20..d1bad1c6315 100644
--- a/libgcc/unwind-dw2-fde.c
+++ b/libgcc/unwind-dw2-fde.c
@@ -683,8 +683,8 @@ classify_object_over_fdes (struct object *ob, const fde *this_fde)
continue;
count += 1;
- if ((void *) pc_begin < ob->pc_begin)
- ob->pc_begin = (void *) pc_begin;
+ if (pc_begin < ob->pc_begin)
+ ob->pc_begin = pc_begin;
}
return count;
@@ -727,7 +727,8 @@ add_fdes (struct object *ob, struct fde_accumulator *accu, const fde *this_fde)
}
else
{
- _Unwind_Ptr pc_begin, mask;
+ _Unwind_Ptr pc_begin;
+ _Unwind_Address mask;
read_encoded_value_with_base (encoding, base, this_fde->pc_begin,
&pc_begin);
@@ -835,7 +836,7 @@ linear_search_fdes (struct object *ob, const fde *this_fde, void *pc)
for (; ! last_fde (ob, this_fde); this_fde = next_fde (this_fde))
{
const struct dwarf_cie *this_cie;
- _Unwind_Address pc_begin, pc_range;
+ _Unwind_Ptr pc_begin, pc_range;
/* Skip CIEs. */
if (this_fde->CIE_delta == 0)
@@ -933,7 +934,7 @@ binary_search_single_encoding_fdes (struct object *ob, void *pc)
{
size_t i = (lo + hi) / 2;
const fde *f = vec->array[i];
- _Unwind_Address pc_begin, pc_range;
+ _Unwind_Ptr pc_begin, pc_range;
const unsigned char *p;
p = read_encoded_value_with_base (encoding, base, f->pc_begin,
@@ -961,7 +962,7 @@ binary_search_mixed_encoding_fdes (struct object *ob, void *pc)
{
size_t i = (lo + hi) / 2;
const fde *f = vec->array[i];
- _Unwind_Address pc_begin, pc_range;
+ _Unwind_Ptr pc_begin, pc_range;
const unsigned char *p;
int encoding;
@@ -1095,7 +1096,7 @@ _Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases)
encoding = get_fde_encoding (f);
read_encoded_value_with_base (encoding, base_from_object (encoding, ob),
f->pc_begin, &func);
- bases->func = (void *) func;
+ bases->func = func;
}
return f;
diff --git a/libgcc/unwind-dw2-fde.h b/libgcc/unwind-dw2-fde.h
index 117cbd9ac45..4bf7716e37f 100644
--- a/libgcc/unwind-dw2-fde.h
+++ b/libgcc/unwind-dw2-fde.h
@@ -137,7 +137,7 @@ struct dwarf_cie
sword CIE_id;
ubyte version;
unsigned char augmentation[];
-} __attribute__ ((packed, aligned (__alignof__ (void *))));
+} __attribute__ ((packed, aligned (__alignof__ (uaddr))));
/* The first few fields of an FDE. */
struct dwarf_fde
@@ -145,7 +145,7 @@ struct dwarf_fde
uword length;
sword CIE_delta;
unsigned char pc_begin[];
-} __attribute__ ((packed, aligned (__alignof__ (void *))));
+} __attribute__ ((packed, aligned (__alignof__ (uaddr))));
typedef struct dwarf_fde fde;
diff --git a/libgcc/unwind-dw2.c b/libgcc/unwind-dw2.c
index fe896565d2e..d88b99e8f96 100644
--- a/libgcc/unwind-dw2.c
+++ b/libgcc/unwind-dw2.c
@@ -85,34 +85,34 @@
__builtin_expect((x) <= __LIBGCC_DWARF_FRAME_REGISTERS__, 1)
#ifdef REG_VALUE_IN_UNWIND_CONTEXT
-typedef _Unwind_Word _Unwind_Context_Reg_Val;
+typedef _Unwind_CapWord _Unwind_Context_Reg_Val;
#ifndef ASSUME_EXTENDED_UNWIND_CONTEXT
#define ASSUME_EXTENDED_UNWIND_CONTEXT 1
#endif
-static inline _Unwind_Word
+static inline _Unwind_CapWord
_Unwind_Get_Unwind_Word (_Unwind_Context_Reg_Val val)
{
return val;
}
static inline _Unwind_Context_Reg_Val
-_Unwind_Get_Unwind_Context_Reg_Val (_Unwind_Word val)
+_Unwind_Get_Unwind_Context_Reg_Val (_Unwind_CapWord val)
{
return val;
}
#else
typedef void *_Unwind_Context_Reg_Val;
-static inline _Unwind_Word
+static inline _Unwind_CapWord
_Unwind_Get_Unwind_Word (_Unwind_Context_Reg_Val val)
{
- return (_Unwind_Word) (_Unwind_Internal_Ptr) val;
+ return (_Unwind_CapWord) (_Unwind_Internal_Ptr) val;
}
static inline _Unwind_Context_Reg_Val
-_Unwind_Get_Unwind_Context_Reg_Val (_Unwind_Word val)
+_Unwind_Get_Unwind_Context_Reg_Val (_Unwind_CapWord val)
{
return (_Unwind_Context_Reg_Val) (_Unwind_Internal_Ptr) val;
}
@@ -219,7 +219,7 @@ _Unwind_IsExtendedContext (struct _Unwind_Context *context)
/* Get the value of register REGNO as saved in CONTEXT. */
-inline _Unwind_Word
+inline _Unwind_CapWord
_Unwind_GetGR (struct _Unwind_Context *context, int regno)
{
int size, index;
@@ -240,7 +240,7 @@ _Unwind_GetGR (struct _Unwind_Context *context, int regno)
#ifdef DWARF_LAZY_REGISTER_VALUE
{
- _Unwind_Word value;
+ _Unwind_CapWord value;
if (DWARF_LAZY_REGISTER_VALUE (regno, &value))
return value;
}
@@ -264,7 +264,7 @@ _Unwind_GetPtr (struct _Unwind_Context *context, int index)
/* Get the value of the CFA as saved in CONTEXT. */
-_Unwind_Word
+_Unwind_CapWord
_Unwind_GetCFA (struct _Unwind_Context *context)
{
return (_Unwind_Ptr) context->cfa;
@@ -273,7 +273,7 @@ _Unwind_GetCFA (struct _Unwind_Context *context)
/* Overwrite the saved value for register INDEX in CONTEXT with VAL. */
inline void
-_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val)
+_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_CapWord val)
{
int size;
void *ptr;
@@ -294,8 +294,8 @@ _Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val)
* (_Unwind_Ptr *) ptr = val;
else
{
- gcc_assert (size == sizeof(_Unwind_Word));
- * (_Unwind_Word *) ptr = val;
+ gcc_assert (size == sizeof(_Unwind_CapWord));
+ * (_Unwind_CapWord *) ptr = val;
}
}
@@ -325,7 +325,7 @@ _Unwind_SetGRPtr (struct _Unwind_Context *context, int index, void *p)
static inline void
_Unwind_SetGRValue (struct _Unwind_Context *context, int index,
- _Unwind_Word val)
+ _Unwind_CapWord val)
{
index = DWARF_REG_TO_UNWIND_COLUMN (index);
gcc_assert (index < (int) sizeof(dwarf_reg_size_table));
@@ -507,7 +507,12 @@ extract_cie_info (const struct dwarf_cie *cie, struct _Unwind_Context *context,
else if (aug[0] == 'B')
{
aug += 1;
- }
+ }
+ /* aarch64 pure capability function. */
+ else if (aug[0] == 'C')
+ {
+ aug += 1;
+ }
/* Otherwise we have an unknown augmentation string.
Bail unless we saw a 'z' prefix. */
@@ -522,11 +527,11 @@ extract_cie_info (const struct dwarf_cie *cie, struct _Unwind_Context *context,
/* Decode a DW_OP stack program. Return the top of stack. Push INITIAL
onto the stack to start. */
-static _Unwind_Word
+static _Unwind_CapWord
execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end,
- struct _Unwind_Context *context, _Unwind_Word initial)
+ struct _Unwind_Context *context, _Unwind_CapWord initial)
{
- _Unwind_Word stack[64]; /* ??? Assume this is enough. */
+ _Unwind_CapWord stack[64]; /* ??? Assume this is enough. */
int stack_elt;
stack[0] = initial;
@@ -535,7 +540,7 @@ execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end,
while (op_ptr < op_end)
{
enum dwarf_location_atom op = *op_ptr++;
- _Unwind_Word result;
+ _Unwind_CapWord result;
_uleb128_t reg, utmp;
_sleb128_t offset, stmp;
@@ -577,7 +582,7 @@ execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end,
break;
case DW_OP_addr:
- result = (_Unwind_Word) (_Unwind_Ptr) read_pointer (op_ptr);
+ result = (_Unwind_CapWord) (_Unwind_Ptr) read_pointer (op_ptr);
op_ptr += sizeof (void *);
break;
@@ -623,11 +628,11 @@ execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end,
break;
case DW_OP_constu:
op_ptr = read_uleb128 (op_ptr, &utmp);
- result = (_Unwind_Word)utmp;
+ result = (_Unwind_CapWord)utmp;
break;
case DW_OP_consts:
op_ptr = read_sleb128 (op_ptr, &stmp);
- result = (_Unwind_Sword)stmp;
+ result = (_Unwind_CapSword)stmp;
break;
case DW_OP_reg0:
@@ -733,7 +738,7 @@ execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end,
case DW_OP_swap:
{
- _Unwind_Word t;
+ _Unwind_CapWord t;
gcc_assert (stack_elt >= 2);
t = stack[stack_elt - 1];
stack[stack_elt - 1] = stack[stack_elt - 2];
@@ -743,7 +748,7 @@ execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end,
case DW_OP_rot:
{
- _Unwind_Word t1, t2, t3;
+ _Unwind_CapWord t1, t2, t3;
gcc_assert (stack_elt >= 3);
t1 = stack[stack_elt - 1];
@@ -838,7 +843,7 @@ execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end,
case DW_OP_ne:
{
/* Binary operations. */
- _Unwind_Word first, second;
+ _Unwind_CapWord first, second;
gcc_assert (stack_elt >= 2);
stack_elt -= 2;
@@ -851,7 +856,7 @@ execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end,
result = second & first;
break;
case DW_OP_div:
- result = (_Unwind_Sword) second / (_Unwind_Sword) first;
+ result = (_Unwind_CapSword) second / (_Unwind_CapSword) first;
break;
case DW_OP_minus:
result = second - first;
@@ -875,7 +880,7 @@ execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end,
result = second >> first;
break;
case DW_OP_shra:
- result = (_Unwind_Sword) second >> first;
+ result = (_Unwind_CapSword) second >> first;
break;
case DW_OP_xor:
result = second ^ first;
@@ -998,11 +1003,11 @@ execute_cfa_program (const unsigned char *insn_ptr,
{
case DW_CFA_set_loc:
{
- _Unwind_Ptr pc;
+ _Unwind_Address pc;
insn_ptr = read_encoded_value (context, fs->fde_encoding,
insn_ptr, &pc);
- fs->pc = (void *) pc;
+ fs->pc = pc;
}
break;
@@ -1540,7 +1545,7 @@ uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
can change from frame to frame. */
void *ret_addr;
#ifdef MD_DEMANGLE_RETURN_ADDR
- _Unwind_Word ra = _Unwind_GetGR (context, fs->retaddr_column);
+ _Unwind_CapWord ra = _Unwind_GetGR (context, fs->retaddr_column);
ret_addr = MD_DEMANGLE_RETURN_ADDR (context, fs, ra);
#else
ret_addr = _Unwind_GetPtr (context, fs->retaddr_column);
diff --git a/libgcc/unwind-dw2.h b/libgcc/unwind-dw2.h
index 2b8c1fd49db..1c4977d97e2 100644
--- a/libgcc/unwind-dw2.h
+++ b/libgcc/unwind-dw2.h
@@ -63,8 +63,11 @@ typedef struct
} cfa_how;
} regs;
- /* The PC described by the current frame state. */
- void *pc;
+ /* The PC described by the current frame state.
+ This is read from the CFA data or FDE pc range. Hence on capability
+ architectures it is an address rather than a pointer. For non-capability
+ architectures _Unwind_Address is the same as a pointer. */
+ _Unwind_Address pc;
/* The information we care about from the CIE/FDE. */
_Unwind_Personality_Fn personality;
diff --git a/libgcc/unwind-generic.h b/libgcc/unwind-generic.h
index bbdfbc75f55..57e3fe8bcf9 100644
--- a/libgcc/unwind-generic.h
+++ b/libgcc/unwind-generic.h
@@ -46,7 +46,9 @@ extern "C" {
/* @@@ The IA-64 ABI uses uint64 throughout. Most places this is
inefficient for 32-bit and smaller machines. */
typedef unsigned _Unwind_Word __attribute__((__mode__(__unwind_word__)));
+typedef __UINTPTR_TYPE__ _Unwind_CapWord;
typedef signed _Unwind_Sword __attribute__((__mode__(__unwind_word__)));
+typedef __INTPTR_TYPE__ _Unwind_CapSword;
#if defined(__ia64__) && defined(__hpux__)
typedef unsigned _Unwind_Ptr __attribute__((__mode__(__word__)));
typedef unsigned _Unwind_Address __attribute__((__mode__(__word__)));
@@ -95,10 +97,10 @@ struct _Unwind_Exception
_Unwind_Exception_Cleanup_Fn exception_cleanup;
#if !defined (__USING_SJLJ_EXCEPTIONS__) && defined (__SEH__)
- _Unwind_Word private_[6];
+ _Unwind_CapWord private_[6];
#else
- _Unwind_Word private_1;
- _Unwind_Word private_2;
+ _Unwind_CapWord private_1;
+ _Unwind_CapWord private_2;
#endif
/* @@@ The IA-64 ABI says that this structure must be double-word aligned.
@@ -169,15 +171,15 @@ _Unwind_Backtrace (_Unwind_Trace_Fn, void *);
the unwind library and the personality routine and landing pad. Only
selected registers may be manipulated. */
-extern _Unwind_Word _Unwind_GetGR (struct _Unwind_Context *, int);
-extern void _Unwind_SetGR (struct _Unwind_Context *, int, _Unwind_Word);
+extern _Unwind_CapWord _Unwind_GetGR (struct _Unwind_Context *, int);
+extern void _Unwind_SetGR (struct _Unwind_Context *, int, _Unwind_CapWord);
extern _Unwind_Ptr _Unwind_GetIP (struct _Unwind_Context *);
extern _Unwind_Ptr _Unwind_GetIPInfo (struct _Unwind_Context *, int *);
extern void _Unwind_SetIP (struct _Unwind_Context *, _Unwind_Ptr);
/* @@@ Retrieve the CFA of the given context. */
-extern _Unwind_Word _Unwind_GetCFA (struct _Unwind_Context *);
+extern _Unwind_CapWord _Unwind_GetCFA (struct _Unwind_Context *);
extern void *_Unwind_GetLanguageSpecificData (struct _Unwind_Context *);
diff --git a/libgcc/unwind-pe.h b/libgcc/unwind-pe.h
index a6b4bffa944..1b0496527b8 100644
--- a/libgcc/unwind-pe.h
+++ b/libgcc/unwind-pe.h
@@ -278,8 +278,8 @@ read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base,
result = *(_Unwind_Internal_Ptr *) result;
}
#else
- result += ((encoding & 0x70) == DW_EH_PE_pcrel
- ? (_Unwind_Internal_Ptr) u : base);
+ result = ((encoding & 0x70) == DW_EH_PE_pcrel
+ ? (_Unwind_Internal_Ptr) u : base) + (_Unwind_Word)result;
if (encoding & DW_EH_PE_indirect)
result = *(_Unwind_Internal_Ptr *) result;
#endif
More information about the Gcc-cvs
mailing list