Debrand for AlmaLinux
This commit is contained in:
commit
a9efcc8941
63
SOURCES/gcc-RHEL-105072-1.patch
Normal file
63
SOURCES/gcc-RHEL-105072-1.patch
Normal file
@ -0,0 +1,63 @@
|
||||
commit 90986c5f0aa61cd22a9132486304ba5d12aae6c4
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Mon Nov 22 13:30:23 2021 +0100
|
||||
|
||||
libgcc: Remove tbase member from struct unw_eh_callback_data
|
||||
|
||||
It is always a null pointer.
|
||||
|
||||
libgcc/ChangeLog
|
||||
|
||||
* unwind-dw2-fde-dip.c (struct unw_eh_callback_data): Remove
|
||||
tbase member.
|
||||
(base_from_cb_data): Adjust.
|
||||
(_Unwind_IteratePhdrCallback): Likewise.
|
||||
(_Unwind_Find_FDE): Likewise.
|
||||
|
||||
diff --git a/libgcc/unwind-dw2-fde-dip.c b/libgcc/unwind-dw2-fde-dip.c
|
||||
index 5095b6830bf79e2e..4a4d990f455e5c11 100644
|
||||
--- a/libgcc/unwind-dw2-fde-dip.c
|
||||
+++ b/libgcc/unwind-dw2-fde-dip.c
|
||||
@@ -104,7 +104,6 @@ static const fde * _Unwind_Find_registered_FDE (void *pc, struct dwarf_eh_bases
|
||||
struct unw_eh_callback_data
|
||||
{
|
||||
_Unwind_Ptr pc;
|
||||
- void *tbase;
|
||||
void *dbase;
|
||||
void *func;
|
||||
const fde *ret;
|
||||
@@ -154,7 +153,7 @@ base_from_cb_data (unsigned char encoding, struct unw_eh_callback_data *data)
|
||||
return 0;
|
||||
|
||||
case DW_EH_PE_textrel:
|
||||
- return (_Unwind_Ptr) data->tbase;
|
||||
+ return 0;
|
||||
case DW_EH_PE_datarel:
|
||||
return (_Unwind_Ptr) data->dbase;
|
||||
default:
|
||||
@@ -431,7 +430,7 @@ _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
|
||||
As soon as GLIBC will provide API so to notify that a library has been
|
||||
removed, we could cache this (and thus use search_object). */
|
||||
ob.pc_begin = NULL;
|
||||
- ob.tbase = data->tbase;
|
||||
+ ob.tbase = NULL;
|
||||
ob.dbase = data->dbase;
|
||||
ob.u.single = (fde *) eh_frame;
|
||||
ob.s.i = 0;
|
||||
@@ -461,7 +460,6 @@ _Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases)
|
||||
return ret;
|
||||
|
||||
data.pc = (_Unwind_Ptr) pc;
|
||||
- data.tbase = NULL;
|
||||
data.dbase = NULL;
|
||||
data.func = NULL;
|
||||
data.ret = NULL;
|
||||
@@ -472,7 +470,7 @@ _Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases)
|
||||
|
||||
if (data.ret)
|
||||
{
|
||||
- bases->tbase = data.tbase;
|
||||
+ bases->tbase = NULL;
|
||||
bases->dbase = data.dbase;
|
||||
bases->func = data.func;
|
||||
}
|
||||
51
SOURCES/gcc-RHEL-105072-10.patch
Normal file
51
SOURCES/gcc-RHEL-105072-10.patch
Normal file
@ -0,0 +1,51 @@
|
||||
commit 94ccaf62c378c3737f7e4b6a80e1160157119171
|
||||
Author: Thomas Neumann <tneumann@users.sourceforge.net>
|
||||
Date: Mon Sep 19 18:10:02 2022 +0200
|
||||
|
||||
Avoid depending on destructor order
|
||||
|
||||
In some scenarios (e.g., when mixing gcc and clang code), it can
|
||||
happen that frames are deregistered after the lookup structure
|
||||
has already been destroyed. That in itself would be fine, but
|
||||
it triggers an assert in __deregister_frame_info_bases that
|
||||
expects to find the frame.
|
||||
|
||||
To avoid that, we now remember that the btree as already been
|
||||
destroyed and disable the assert in that case.
|
||||
|
||||
libgcc/ChangeLog:
|
||||
|
||||
* unwind-dw2-fde.c: (release_register_frames) Remember
|
||||
when the btree has been destroyed.
|
||||
(__deregister_frame_info_bases) Disable the assert when
|
||||
shutting down.
|
||||
|
||||
diff --git a/libgcc/unwind-dw2-fde.c b/libgcc/unwind-dw2-fde.c
|
||||
index f38efd3c09efc3e9..b0d07ccd53b30f4c 100644
|
||||
--- a/libgcc/unwind-dw2-fde.c
|
||||
+++ b/libgcc/unwind-dw2-fde.c
|
||||
@@ -48,6 +48,7 @@ typedef __UINTPTR_TYPE__ uintptr_type;
|
||||
#include "unwind-dw2-btree.h"
|
||||
|
||||
static struct btree registered_frames;
|
||||
+static bool in_shutdown;
|
||||
|
||||
static void
|
||||
release_registered_frames (void) __attribute__ ((destructor (110)));
|
||||
@@ -57,6 +58,7 @@ release_registered_frames (void)
|
||||
/* Release the b-tree and all frames. Frame releases that happen later are
|
||||
* silently ignored */
|
||||
btree_destroy (®istered_frames);
|
||||
+ in_shutdown = true;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -282,7 +284,7 @@ __deregister_frame_info_bases (const void *begin)
|
||||
__gthread_mutex_unlock (&object_mutex);
|
||||
#endif
|
||||
|
||||
- gcc_assert (ob);
|
||||
+ gcc_assert (in_shutdown || ob);
|
||||
return (void *) ob;
|
||||
}
|
||||
|
||||
42
SOURCES/gcc-RHEL-105072-11.patch
Normal file
42
SOURCES/gcc-RHEL-105072-11.patch
Normal file
@ -0,0 +1,42 @@
|
||||
commit 386ebf75f4c0342b1f823f4e4aba07abda3288d1
|
||||
Author: Thomas Neumann <tneumann@users.sourceforge.net>
|
||||
Date: Fri Sep 23 15:57:13 2022 +0200
|
||||
|
||||
fix assert in __deregister_frame_info_bases
|
||||
|
||||
When using the atomic fast path deregistering can fail during
|
||||
program shutdown if the lookup structures are already destroyed.
|
||||
The assert in __deregister_frame_info_bases takes that into
|
||||
account. In the non-fast-path case however is not aware of
|
||||
program shutdown, which caused a compiler error on such platforms.
|
||||
We fix that by introducing a constant for in_shutdown in
|
||||
non-fast-path builds.
|
||||
We also drop the destructor priority, as it is not supported on
|
||||
all platforms and we no longer rely upon the priority anyway.
|
||||
|
||||
libgcc/ChangeLog:
|
||||
* unwind-dw2-fde.c: Introduce a constant for in_shutdown
|
||||
for the non-fast-path case. Drop destructor priority.
|
||||
|
||||
diff --git a/libgcc/unwind-dw2-fde.c b/libgcc/unwind-dw2-fde.c
|
||||
index b0d07ccd53b30f4c..27fea89dc314ccd0 100644
|
||||
--- a/libgcc/unwind-dw2-fde.c
|
||||
+++ b/libgcc/unwind-dw2-fde.c
|
||||
@@ -51,7 +51,7 @@ static struct btree registered_frames;
|
||||
static bool in_shutdown;
|
||||
|
||||
static void
|
||||
-release_registered_frames (void) __attribute__ ((destructor (110)));
|
||||
+release_registered_frames (void) __attribute__ ((destructor));
|
||||
static void
|
||||
release_registered_frames (void)
|
||||
{
|
||||
@@ -67,6 +67,8 @@ static void
|
||||
init_object (struct object *ob);
|
||||
|
||||
#else
|
||||
+/* Without fast path frame deregistration must always succeed. */
|
||||
+static const int in_shutdown = 0;
|
||||
|
||||
/* The unseen_objects list contains objects that have been registered
|
||||
but not yet categorized in any way. The seen_objects list has had
|
||||
1811
SOURCES/gcc-RHEL-105072-12.patch
Normal file
1811
SOURCES/gcc-RHEL-105072-12.patch
Normal file
File diff suppressed because it is too large
Load Diff
48
SOURCES/gcc-RHEL-105072-13.patch
Normal file
48
SOURCES/gcc-RHEL-105072-13.patch
Normal file
@ -0,0 +1,48 @@
|
||||
commit acdb24166d13d87c374e578d2ad5d58249171930
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Mon Oct 17 11:09:17 2022 +0200
|
||||
|
||||
libgcc: Move cfa_how into potential padding in struct frame_state_reg_info
|
||||
|
||||
On many architectures, there is a padding gap after the how array
|
||||
member, and cfa_how can be moved there. This reduces the size of the
|
||||
struct and the amount of memory that uw_frame_state_for has to clear.
|
||||
|
||||
There is no measurable performance benefit from this on x86-64 (even
|
||||
though the memset goes from 120 to 112 bytes), but it seems to be a
|
||||
good idea to do anyway.
|
||||
|
||||
libgcc/
|
||||
|
||||
* unwind-dw2.h (struct frame_state_reg_info): Move cfa_how member
|
||||
and reduce its size.
|
||||
|
||||
diff --git a/libgcc/unwind-dw2.h b/libgcc/unwind-dw2.h
|
||||
index 22241b1f0d14cffc..437c785efa4f297d 100644
|
||||
--- a/libgcc/unwind-dw2.h
|
||||
+++ b/libgcc/unwind-dw2.h
|
||||
@@ -50,6 +50,12 @@ typedef struct
|
||||
} reg[__LIBGCC_DWARF_FRAME_REGISTERS__+1];
|
||||
unsigned char how[__LIBGCC_DWARF_FRAME_REGISTERS__+1];
|
||||
|
||||
+ enum {
|
||||
+ CFA_UNSET,
|
||||
+ CFA_REG_OFFSET,
|
||||
+ CFA_EXP
|
||||
+ } cfa_how : 8;
|
||||
+
|
||||
/* Used to implement DW_CFA_remember_state. */
|
||||
struct frame_state_reg_info *prev;
|
||||
|
||||
@@ -58,11 +64,6 @@ typedef struct
|
||||
_Unwind_Sword cfa_offset;
|
||||
_Unwind_Word cfa_reg;
|
||||
const unsigned char *cfa_exp;
|
||||
- enum {
|
||||
- CFA_UNSET,
|
||||
- CFA_REG_OFFSET,
|
||||
- CFA_EXP
|
||||
- } cfa_how;
|
||||
} regs;
|
||||
|
||||
/* The PC described by the current frame state. */
|
||||
99
SOURCES/gcc-RHEL-105072-14.patch
Normal file
99
SOURCES/gcc-RHEL-105072-14.patch
Normal file
@ -0,0 +1,99 @@
|
||||
commit e724b0480bfa5ec04f39be8c7290330b495c59de
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Nov 4 10:18:03 2022 +0100
|
||||
|
||||
libgcc: Special-case BFD ld unwind table encodings in find_fde_tail
|
||||
|
||||
BFD ld (and the other linkers) only produce one encoding of these
|
||||
values. It is not necessary to use the general
|
||||
read_encoded_value_with_base decoding routine. This avoids the
|
||||
data-dependent branches in its implementation.
|
||||
|
||||
libgcc/
|
||||
|
||||
* unwind-dw2-fde-dip.c (find_fde_tail): Special-case encoding
|
||||
values actually used by BFD ld.
|
||||
|
||||
diff --git a/libgcc/unwind-dw2-fde-dip.c b/libgcc/unwind-dw2-fde-dip.c
|
||||
index 25f2e44c5823cf64..d4821d7d19950f15 100644
|
||||
--- a/libgcc/unwind-dw2-fde-dip.c
|
||||
+++ b/libgcc/unwind-dw2-fde-dip.c
|
||||
@@ -396,10 +396,21 @@ find_fde_tail (_Unwind_Ptr pc,
|
||||
if (hdr->version != 1)
|
||||
return NULL;
|
||||
|
||||
- p = read_encoded_value_with_base (hdr->eh_frame_ptr_enc,
|
||||
- base_from_cb_data (hdr->eh_frame_ptr_enc,
|
||||
- dbase),
|
||||
- p, &eh_frame);
|
||||
+ if (__builtin_expect (hdr->eh_frame_ptr_enc == (DW_EH_PE_sdata4
|
||||
+ | DW_EH_PE_pcrel), 1))
|
||||
+ {
|
||||
+ /* Specialized version of read_encoded_value_with_base, based on what
|
||||
+ BFD ld generates. */
|
||||
+ signed value __attribute__ ((mode (SI)));
|
||||
+ memcpy (&value, p, sizeof (value));
|
||||
+ p += sizeof (value);
|
||||
+ dbase = value; /* No adjustment because pcrel has base 0. */
|
||||
+ }
|
||||
+ else
|
||||
+ p = read_encoded_value_with_base (hdr->eh_frame_ptr_enc,
|
||||
+ base_from_cb_data (hdr->eh_frame_ptr_enc,
|
||||
+ dbase),
|
||||
+ p, &eh_frame);
|
||||
|
||||
/* We require here specific table encoding to speed things up.
|
||||
Also, DW_EH_PE_datarel here means using PT_GNU_EH_FRAME start
|
||||
@@ -409,10 +420,20 @@ find_fde_tail (_Unwind_Ptr pc,
|
||||
{
|
||||
_Unwind_Ptr fde_count;
|
||||
|
||||
- p = read_encoded_value_with_base (hdr->fde_count_enc,
|
||||
- base_from_cb_data (hdr->fde_count_enc,
|
||||
- dbase),
|
||||
- p, &fde_count);
|
||||
+ if (__builtin_expect (hdr->fde_count_enc == DW_EH_PE_udata4, 1))
|
||||
+ {
|
||||
+ /* Specialized version of read_encoded_value_with_base, based on
|
||||
+ what BFD ld generates. */
|
||||
+ unsigned value __attribute__ ((mode (SI)));
|
||||
+ memcpy (&value, p, sizeof (value));
|
||||
+ p += sizeof (value);
|
||||
+ fde_count = value;
|
||||
+ }
|
||||
+ else
|
||||
+ p = read_encoded_value_with_base (hdr->fde_count_enc,
|
||||
+ base_from_cb_data (hdr->fde_count_enc,
|
||||
+ dbase),
|
||||
+ p, &fde_count);
|
||||
/* Shouldn't happen. */
|
||||
if (fde_count == 0)
|
||||
return NULL;
|
||||
@@ -454,8 +475,25 @@ find_fde_tail (_Unwind_Ptr pc,
|
||||
f = (fde *) (table[mid].fde + data_base);
|
||||
f_enc = get_fde_encoding (f);
|
||||
f_enc_size = size_of_encoded_value (f_enc);
|
||||
- read_encoded_value_with_base (f_enc & 0x0f, 0,
|
||||
- &f->pc_begin[f_enc_size], &range);
|
||||
+
|
||||
+ /* BFD ld uses DW_EH_PE_sdata4 | DW_EH_PE_pcrel on non-FDPIC targets,
|
||||
+ so optimize for that.
|
||||
+
|
||||
+ This optimization is not valid for FDPIC targets. f_enc & 0x0f as
|
||||
+ passed to read_encoded_value_with_base masks away the base flags,
|
||||
+ but they are implicit for FDPIC. */
|
||||
+#ifndef __FDPIC__
|
||||
+ if (__builtin_expect (f_enc == (DW_EH_PE_sdata4 | DW_EH_PE_pcrel),
|
||||
+ 1))
|
||||
+ {
|
||||
+ signed value __attribute__ ((mode (SI)));
|
||||
+ memcpy (&value, &f->pc_begin[f_enc_size], sizeof (value));
|
||||
+ range = value;
|
||||
+ }
|
||||
+ else
|
||||
+#endif
|
||||
+ read_encoded_value_with_base (f_enc & 0x0f, 0,
|
||||
+ &f->pc_begin[f_enc_size], &range);
|
||||
_Unwind_Ptr func = table[mid].initial_loc + data_base;
|
||||
if (pc < table[mid].initial_loc + data_base + range)
|
||||
{
|
||||
337
SOURCES/gcc-RHEL-105072-15.patch
Normal file
337
SOURCES/gcc-RHEL-105072-15.patch
Normal file
@ -0,0 +1,337 @@
|
||||
commit 1c118c9970600117700cc12284587e0238de6bbe
|
||||
Author: Thomas Neumann <tneumann@users.sourceforge.net>
|
||||
Date: Tue Nov 22 08:41:54 2022 +0100
|
||||
|
||||
speed up end_fde_sort using radix sort
|
||||
|
||||
When registering a dynamic unwinding frame the fde list is sorted.
|
||||
Previously, we split the list into a sorted and an unsorted part,
|
||||
sorted the later using heap sort, and merged both. That can be
|
||||
quite slow due to the large number of (expensive) comparisons.
|
||||
|
||||
This patch replaces that logic with a radix sort instead. The
|
||||
radix sort uses the same amount of memory as the old logic,
|
||||
using the second list as auxiliary space, and it includes two
|
||||
techniques to speed up sorting: First, it computes the pointer
|
||||
addresses for blocks of values, reducing the decoding overhead.
|
||||
And it recognizes when the data has reached a sorted state,
|
||||
allowing for early termination. When running out of memory
|
||||
we fall back to pure heap sort, as before.
|
||||
|
||||
For this test program
|
||||
|
||||
\#include <cstdio>
|
||||
int main(int argc, char** argv) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
compiled with g++ -O -o hello -static hello.c we get with
|
||||
perf stat -r 200 on a 5950X the following performance numbers:
|
||||
|
||||
old logic:
|
||||
|
||||
0,20 msec task-clock
|
||||
930.834 cycles
|
||||
3.079.765 instructions
|
||||
0,00030478 +- 0,00000237 seconds time elapsed
|
||||
|
||||
new logic:
|
||||
|
||||
0,10 msec task-clock
|
||||
473.269 cycles
|
||||
1.239.077 instructions
|
||||
0,00021119 +- 0,00000168 seconds time elapsed
|
||||
|
||||
libgcc/ChangeLog:
|
||||
* unwind-dw2-fde.c: Use radix sort instead of split+sort+merge.
|
||||
|
||||
diff --git a/libgcc/unwind-dw2-fde.c b/libgcc/unwind-dw2-fde.c
|
||||
index 27fea89dc314ccd0..a0d9bfb9f7d34ec1 100644
|
||||
--- a/libgcc/unwind-dw2-fde.c
|
||||
+++ b/libgcc/unwind-dw2-fde.c
|
||||
@@ -456,22 +456,52 @@ fde_mixed_encoding_compare (struct object *ob, const fde *x, const fde *y)
|
||||
|
||||
typedef int (*fde_compare_t) (struct object *, const fde *, const fde *);
|
||||
|
||||
+// The extractor functions compute the pointer values for a block of
|
||||
+// fdes. The block processing hides the call overhead.
|
||||
|
||||
-/* This is a special mix of insertion sort and heap sort, optimized for
|
||||
- the data sets that actually occur. They look like
|
||||
- 101 102 103 127 128 105 108 110 190 111 115 119 125 160 126 129 130.
|
||||
- I.e. a linearly increasing sequence (coming from functions in the text
|
||||
- section), with additionally a few unordered elements (coming from functions
|
||||
- in gnu_linkonce sections) whose values are higher than the values in the
|
||||
- surrounding linear sequence (but not necessarily higher than the values
|
||||
- at the end of the linear sequence!).
|
||||
- The worst-case total run time is O(N) + O(n log (n)), where N is the
|
||||
- total number of FDEs and n is the number of erratic ones. */
|
||||
+static void
|
||||
+fde_unencoded_extract (struct object *ob __attribute__ ((unused)),
|
||||
+ _Unwind_Ptr *target, const fde **x, int count)
|
||||
+{
|
||||
+ for (int index = 0; index < count; ++index)
|
||||
+ memcpy (target + index, x[index]->pc_begin, sizeof (_Unwind_Ptr));
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+fde_single_encoding_extract (struct object *ob, _Unwind_Ptr *target,
|
||||
+ const fde **x, int count)
|
||||
+{
|
||||
+ _Unwind_Ptr base;
|
||||
+
|
||||
+ base = base_from_object (ob->s.b.encoding, ob);
|
||||
+ for (int index = 0; index < count; ++index)
|
||||
+ read_encoded_value_with_base (ob->s.b.encoding, base, x[index]->pc_begin,
|
||||
+ target + index);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+fde_mixed_encoding_extract (struct object *ob, _Unwind_Ptr *target,
|
||||
+ const fde **x, int count)
|
||||
+{
|
||||
+ for (int index = 0; index < count; ++index)
|
||||
+ {
|
||||
+ int encoding = get_fde_encoding (x[index]);
|
||||
+ read_encoded_value_with_base (encoding, base_from_object (encoding, ob),
|
||||
+ x[index]->pc_begin, target + index);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+typedef void (*fde_extractor_t) (struct object *, _Unwind_Ptr *, const fde **,
|
||||
+ int);
|
||||
+
|
||||
+// Data is is sorted using radix sort if possible, using an temporary
|
||||
+// auxiliary data structure of the same size as the input. When running
|
||||
+// out of memory do in-place heap sort.
|
||||
|
||||
struct fde_accumulator
|
||||
{
|
||||
struct fde_vector *linear;
|
||||
- struct fde_vector *erratic;
|
||||
+ struct fde_vector *aux;
|
||||
};
|
||||
|
||||
static inline int
|
||||
@@ -485,8 +515,8 @@ start_fde_sort (struct fde_accumulator *accu, size_t count)
|
||||
if ((accu->linear = malloc (size)))
|
||||
{
|
||||
accu->linear->count = 0;
|
||||
- if ((accu->erratic = malloc (size)))
|
||||
- accu->erratic->count = 0;
|
||||
+ if ((accu->aux = malloc (size)))
|
||||
+ accu->aux->count = 0;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
@@ -500,59 +530,6 @@ fde_insert (struct fde_accumulator *accu, const fde *this_fde)
|
||||
accu->linear->array[accu->linear->count++] = this_fde;
|
||||
}
|
||||
|
||||
-/* Split LINEAR into a linear sequence with low values and an erratic
|
||||
- sequence with high values, put the linear one (of longest possible
|
||||
- length) into LINEAR and the erratic one into ERRATIC. This is O(N).
|
||||
-
|
||||
- Because the longest linear sequence we are trying to locate within the
|
||||
- incoming LINEAR array can be interspersed with (high valued) erratic
|
||||
- entries. We construct a chain indicating the sequenced entries.
|
||||
- To avoid having to allocate this chain, we overlay it onto the space of
|
||||
- the ERRATIC array during construction. A final pass iterates over the
|
||||
- chain to determine what should be placed in the ERRATIC array, and
|
||||
- what is the linear sequence. This overlay is safe from aliasing. */
|
||||
-
|
||||
-static inline void
|
||||
-fde_split (struct object *ob, fde_compare_t fde_compare,
|
||||
- struct fde_vector *linear, struct fde_vector *erratic)
|
||||
-{
|
||||
- static const fde *marker;
|
||||
- size_t count = linear->count;
|
||||
- const fde *const *chain_end = ▮
|
||||
- size_t i, j, k;
|
||||
-
|
||||
- /* This should optimize out, but it is wise to make sure this assumption
|
||||
- is correct. Should these have different sizes, we cannot cast between
|
||||
- them and the overlaying onto ERRATIC will not work. */
|
||||
- gcc_assert (sizeof (const fde *) == sizeof (const fde **));
|
||||
-
|
||||
- for (i = 0; i < count; i++)
|
||||
- {
|
||||
- const fde *const *probe;
|
||||
-
|
||||
- for (probe = chain_end;
|
||||
- probe != &marker && fde_compare (ob, linear->array[i], *probe) < 0;
|
||||
- probe = chain_end)
|
||||
- {
|
||||
- chain_end = (const fde *const*) erratic->array[probe - linear->array];
|
||||
- erratic->array[probe - linear->array] = NULL;
|
||||
- }
|
||||
- erratic->array[i] = (const fde *) chain_end;
|
||||
- chain_end = &linear->array[i];
|
||||
- }
|
||||
-
|
||||
- /* Each entry in LINEAR which is part of the linear sequence we have
|
||||
- discovered will correspond to a non-NULL entry in the chain we built in
|
||||
- the ERRATIC array. */
|
||||
- for (i = j = k = 0; i < count; i++)
|
||||
- if (erratic->array[i])
|
||||
- linear->array[j++] = linear->array[i];
|
||||
- else
|
||||
- erratic->array[k++] = linear->array[i];
|
||||
- linear->count = j;
|
||||
- erratic->count = k;
|
||||
-}
|
||||
-
|
||||
#define SWAP(x,y) do { const fde * tmp = x; x = y; y = tmp; } while (0)
|
||||
|
||||
/* Convert a semi-heap to a heap. A semi-heap is a heap except possibly
|
||||
@@ -615,59 +592,116 @@ frame_heapsort (struct object *ob, fde_compare_t fde_compare,
|
||||
#undef SWAP
|
||||
}
|
||||
|
||||
-/* Merge V1 and V2, both sorted, and put the result into V1. */
|
||||
+// Radix sort data in V1 using V2 as aux memory. Runtime O(n).
|
||||
static inline void
|
||||
-fde_merge (struct object *ob, fde_compare_t fde_compare,
|
||||
- struct fde_vector *v1, struct fde_vector *v2)
|
||||
+fde_radixsort (struct object *ob, fde_extractor_t fde_extractor,
|
||||
+ struct fde_vector *v1, struct fde_vector *v2)
|
||||
{
|
||||
- size_t i1, i2;
|
||||
- const fde * fde2;
|
||||
-
|
||||
- i2 = v2->count;
|
||||
- if (i2 > 0)
|
||||
+#define FANOUTBITS 8
|
||||
+#define FANOUT (1 << FANOUTBITS)
|
||||
+#define BLOCKSIZE 128
|
||||
+ const unsigned rounds
|
||||
+ = (__CHAR_BIT__ * sizeof (_Unwind_Ptr) + FANOUTBITS - 1) / FANOUTBITS;
|
||||
+ const fde **a1 = v1->array, **a2 = v2->array;
|
||||
+ _Unwind_Ptr ptrs[BLOCKSIZE + 1];
|
||||
+ unsigned n = v1->count;
|
||||
+ for (unsigned round = 0; round != rounds; ++round)
|
||||
{
|
||||
- i1 = v1->count;
|
||||
- do
|
||||
+ unsigned counts[FANOUT] = {0};
|
||||
+ unsigned violations = 0;
|
||||
+
|
||||
+ // Count the number of elements per bucket and check if we are already
|
||||
+ // sorted.
|
||||
+ _Unwind_Ptr last = 0;
|
||||
+ for (unsigned i = 0; i < n;)
|
||||
+ {
|
||||
+ unsigned chunk = ((n - i) <= BLOCKSIZE) ? (n - i) : BLOCKSIZE;
|
||||
+ fde_extractor (ob, ptrs + 1, a1 + i, chunk);
|
||||
+ ptrs[0] = last;
|
||||
+ for (unsigned j = 0; j < chunk; ++j)
|
||||
+ {
|
||||
+ unsigned b = (ptrs[j + 1] >> (round * FANOUTBITS)) & (FANOUT - 1);
|
||||
+ counts[b]++;
|
||||
+ // Use summation instead of an if to eliminate branches.
|
||||
+ violations += ptrs[j + 1] < ptrs[j];
|
||||
+ }
|
||||
+ i += chunk;
|
||||
+ last = ptrs[chunk];
|
||||
+ }
|
||||
+
|
||||
+ // Stop if we are already sorted.
|
||||
+ if (!violations)
|
||||
+ {
|
||||
+ // The sorted data is in a1 now.
|
||||
+ a2 = a1;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ // Compute the prefix sum.
|
||||
+ unsigned sum = 0;
|
||||
+ for (unsigned i = 0; i != FANOUT; ++i)
|
||||
+ {
|
||||
+ unsigned s = sum;
|
||||
+ sum += counts[i];
|
||||
+ counts[i] = s;
|
||||
+ }
|
||||
+
|
||||
+ // Place all elements.
|
||||
+ for (unsigned i = 0; i < n;)
|
||||
{
|
||||
- i2--;
|
||||
- fde2 = v2->array[i2];
|
||||
- while (i1 > 0 && fde_compare (ob, v1->array[i1-1], fde2) > 0)
|
||||
+ unsigned chunk = ((n - i) <= BLOCKSIZE) ? (n - i) : BLOCKSIZE;
|
||||
+ fde_extractor (ob, ptrs, a1 + i, chunk);
|
||||
+ for (unsigned j = 0; j < chunk; ++j)
|
||||
{
|
||||
- v1->array[i1+i2] = v1->array[i1-1];
|
||||
- i1--;
|
||||
+ unsigned b = (ptrs[j] >> (round * FANOUTBITS)) & (FANOUT - 1);
|
||||
+ a2[counts[b]++] = a1[i + j];
|
||||
}
|
||||
- v1->array[i1+i2] = fde2;
|
||||
+ i += chunk;
|
||||
}
|
||||
- while (i2 > 0);
|
||||
- v1->count += v2->count;
|
||||
+
|
||||
+ // Swap a1 and a2.
|
||||
+ const fde **tmp = a1;
|
||||
+ a1 = a2;
|
||||
+ a2 = tmp;
|
||||
}
|
||||
+#undef BLOCKSIZE
|
||||
+#undef FANOUT
|
||||
+#undef FANOUTBITS
|
||||
+
|
||||
+ // The data is in a2 now, move in place if needed.
|
||||
+ if (a2 != v1->array)
|
||||
+ memcpy (v1->array, a2, sizeof (const fde *) * n);
|
||||
}
|
||||
|
||||
static inline void
|
||||
end_fde_sort (struct object *ob, struct fde_accumulator *accu, size_t count)
|
||||
{
|
||||
- fde_compare_t fde_compare;
|
||||
-
|
||||
gcc_assert (!accu->linear || accu->linear->count == count);
|
||||
|
||||
- if (ob->s.b.mixed_encoding)
|
||||
- fde_compare = fde_mixed_encoding_compare;
|
||||
- else if (ob->s.b.encoding == DW_EH_PE_absptr)
|
||||
- fde_compare = fde_unencoded_compare;
|
||||
- else
|
||||
- fde_compare = fde_single_encoding_compare;
|
||||
-
|
||||
- if (accu->erratic)
|
||||
+ if (accu->aux)
|
||||
{
|
||||
- fde_split (ob, fde_compare, accu->linear, accu->erratic);
|
||||
- gcc_assert (accu->linear->count + accu->erratic->count == count);
|
||||
- frame_heapsort (ob, fde_compare, accu->erratic);
|
||||
- fde_merge (ob, fde_compare, accu->linear, accu->erratic);
|
||||
- free (accu->erratic);
|
||||
+ fde_extractor_t fde_extractor;
|
||||
+ if (ob->s.b.mixed_encoding)
|
||||
+ fde_extractor = fde_mixed_encoding_extract;
|
||||
+ else if (ob->s.b.encoding == DW_EH_PE_absptr)
|
||||
+ fde_extractor = fde_unencoded_extract;
|
||||
+ else
|
||||
+ fde_extractor = fde_single_encoding_extract;
|
||||
+
|
||||
+ fde_radixsort (ob, fde_extractor, accu->linear, accu->aux);
|
||||
+ free (accu->aux);
|
||||
}
|
||||
else
|
||||
{
|
||||
- /* We've not managed to malloc an erratic array,
|
||||
+ fde_compare_t fde_compare;
|
||||
+ if (ob->s.b.mixed_encoding)
|
||||
+ fde_compare = fde_mixed_encoding_compare;
|
||||
+ else if (ob->s.b.encoding == DW_EH_PE_absptr)
|
||||
+ fde_compare = fde_unencoded_compare;
|
||||
+ else
|
||||
+ fde_compare = fde_single_encoding_compare;
|
||||
+
|
||||
+ /* We've not managed to malloc an aux array,
|
||||
so heap sort in the linear one. */
|
||||
frame_heapsort (ob, fde_compare, accu->linear);
|
||||
}
|
||||
143
SOURCES/gcc-RHEL-105072-16.patch
Normal file
143
SOURCES/gcc-RHEL-105072-16.patch
Normal file
@ -0,0 +1,143 @@
|
||||
commit 6e56633daae79f514b0e71f4d9849bcd8d9ce71f
|
||||
Author: Thomas Neumann <tneumann@users.sourceforge.net>
|
||||
Date: Fri Dec 9 18:23:44 2022 +0100
|
||||
|
||||
initialize fde objects lazily
|
||||
|
||||
When registering an unwind frame with __register_frame_info_bases
|
||||
we currently initialize that fde object eagerly. This has the
|
||||
advantage that it is immutable afterwards and we can safely
|
||||
access it from multiple threads, but it has the disadvantage
|
||||
that we pay the initialization cost even if the application
|
||||
never throws an exception.
|
||||
|
||||
This commit changes the logic to initialize the objects lazily.
|
||||
The objects themselves are inserted into the b-tree when
|
||||
registering the frame, but the sorted fde_vector is
|
||||
not constructed yet. Only on the first time that an
|
||||
exception tries to pass through the registered code the
|
||||
object is initialized. We notice that with a double checking,
|
||||
first doing a relaxed load of the sorted bit and then re-checking
|
||||
under a mutex when the object was not initialized yet.
|
||||
|
||||
Note that the check must implicitly be safe concering a concurrent
|
||||
frame deregistration, as trying the deregister a frame that is
|
||||
on the unwinding path of a concurrent exception is inherently racy.
|
||||
|
||||
libgcc/ChangeLog:
|
||||
* unwind-dw2-fde.c: Initialize fde object lazily when
|
||||
the first exception tries to pass through.
|
||||
|
||||
diff --git a/libgcc/unwind-dw2-fde.c b/libgcc/unwind-dw2-fde.c
|
||||
index a0d9bfb9f7d34ec1..efcf9490469ad1a0 100644
|
||||
--- a/libgcc/unwind-dw2-fde.c
|
||||
+++ b/libgcc/unwind-dw2-fde.c
|
||||
@@ -63,8 +63,6 @@ release_registered_frames (void)
|
||||
|
||||
static void
|
||||
get_pc_range (const struct object *ob, uintptr_type *range);
|
||||
-static void
|
||||
-init_object (struct object *ob);
|
||||
|
||||
#else
|
||||
/* Without fast path frame deregistration must always succeed. */
|
||||
@@ -76,6 +74,7 @@ static const int in_shutdown = 0;
|
||||
by decreasing value of pc_begin. */
|
||||
static struct object *unseen_objects;
|
||||
static struct object *seen_objects;
|
||||
+#endif
|
||||
|
||||
#ifdef __GTHREAD_MUTEX_INIT
|
||||
static __gthread_mutex_t object_mutex = __GTHREAD_MUTEX_INIT;
|
||||
@@ -103,7 +102,6 @@ init_object_mutex_once (void)
|
||||
static __gthread_mutex_t object_mutex;
|
||||
#endif
|
||||
#endif
|
||||
-#endif
|
||||
|
||||
/* Called from crtbegin.o to register the unwind info for an object. */
|
||||
|
||||
@@ -126,10 +124,7 @@ __register_frame_info_bases (const void *begin, struct object *ob,
|
||||
#endif
|
||||
|
||||
#ifdef ATOMIC_FDE_FAST_PATH
|
||||
- // Initialize eagerly to avoid locking later
|
||||
- init_object (ob);
|
||||
-
|
||||
- // And register the frame
|
||||
+ // Register the frame in the b-tree
|
||||
uintptr_type range[2];
|
||||
get_pc_range (ob, range);
|
||||
btree_insert (®istered_frames, range[0], range[1] - range[0], ob);
|
||||
@@ -180,10 +175,7 @@ __register_frame_info_table_bases (void *begin, struct object *ob,
|
||||
ob->s.b.encoding = DW_EH_PE_omit;
|
||||
|
||||
#ifdef ATOMIC_FDE_FAST_PATH
|
||||
- // Initialize eagerly to avoid locking later
|
||||
- init_object (ob);
|
||||
-
|
||||
- // And register the frame
|
||||
+ // Register the frame in the b-tree
|
||||
uintptr_type range[2];
|
||||
get_pc_range (ob, range);
|
||||
btree_insert (®istered_frames, range[0], range[1] - range[0], ob);
|
||||
@@ -926,7 +918,15 @@ init_object (struct object* ob)
|
||||
accu.linear->orig_data = ob->u.single;
|
||||
ob->u.sort = accu.linear;
|
||||
|
||||
+#ifdef ATOMIC_FDE_FAST_PATH
|
||||
+ // We must update the sorted bit with an atomic operation
|
||||
+ struct object tmp;
|
||||
+ tmp.s.b = ob->s.b;
|
||||
+ tmp.s.b.sorted = 1;
|
||||
+ __atomic_store (&(ob->s.b), &(tmp.s.b), __ATOMIC_RELEASE);
|
||||
+#else
|
||||
ob->s.b.sorted = 1;
|
||||
+#endif
|
||||
}
|
||||
|
||||
#ifdef ATOMIC_FDE_FAST_PATH
|
||||
@@ -1164,6 +1164,21 @@ search_object (struct object* ob, void *pc)
|
||||
}
|
||||
}
|
||||
|
||||
+#ifdef ATOMIC_FDE_FAST_PATH
|
||||
+
|
||||
+// Check if the object was already initialized
|
||||
+static inline bool
|
||||
+is_object_initialized (struct object *ob)
|
||||
+{
|
||||
+ // We have to use acquire atomics for the read, which
|
||||
+ // is a bit involved as we read from a bitfield
|
||||
+ struct object tmp;
|
||||
+ __atomic_load (&(ob->s.b), &(tmp.s.b), __ATOMIC_ACQUIRE);
|
||||
+ return tmp.s.b.sorted;
|
||||
+}
|
||||
+
|
||||
+#endif
|
||||
+
|
||||
const fde *
|
||||
_Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases)
|
||||
{
|
||||
@@ -1175,6 +1190,21 @@ _Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases)
|
||||
if (!ob)
|
||||
return NULL;
|
||||
|
||||
+ // Initialize the object lazily
|
||||
+ if (!is_object_initialized (ob))
|
||||
+ {
|
||||
+ // Check again under mutex
|
||||
+ init_object_mutex_once ();
|
||||
+ __gthread_mutex_lock (&object_mutex);
|
||||
+
|
||||
+ if (!ob->s.b.sorted)
|
||||
+ {
|
||||
+ init_object (ob);
|
||||
+ }
|
||||
+
|
||||
+ __gthread_mutex_unlock (&object_mutex);
|
||||
+ }
|
||||
+
|
||||
f = search_object (ob, pc);
|
||||
#else
|
||||
|
||||
703
SOURCES/gcc-RHEL-105072-17.patch
Normal file
703
SOURCES/gcc-RHEL-105072-17.patch
Normal file
@ -0,0 +1,703 @@
|
||||
commit 8fdef16cd5d1b89359db3cd9a9768ab2d1b5081f
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Tue Jan 3 16:47:32 2023 +0100
|
||||
|
||||
libgcc: Specialize execute_cfa_program in DWARF unwinder for alignments [redo]
|
||||
|
||||
The parameters fs->data_align and fs->code_align always have fixed
|
||||
values for a particular target in GCC-generated code. Specialize
|
||||
execute_cfa_program for these values, to avoid multiplications.
|
||||
|
||||
gcc/c-family/
|
||||
|
||||
* c-cppbuiltin.cc (c_cpp_builtins): Define
|
||||
__LIBGCC_DWARF_CIE_DATA_ALIGNMENT__.
|
||||
|
||||
libgcc/
|
||||
|
||||
* unwind-dw2-execute_cfa.h: New file. Extracted from
|
||||
the execute_cfa_program function in unwind-dw2.c.
|
||||
* unwind-dw2.c (execute_cfa_program_generic): New function.
|
||||
(execute_cfa_program_specialized): Likewise.
|
||||
(execute_cfa_program): Call execute_cfa_program_specialized
|
||||
or execute_cfa_program_generic, as appropriate.
|
||||
|
||||
diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c
|
||||
index 11e015bdb87b0f9b..a5369eb51b07f0ab 100644
|
||||
--- a/gcc/c-family/c-cppbuiltin.c
|
||||
+++ b/gcc/c-family/c-cppbuiltin.c
|
||||
@@ -1408,6 +1408,9 @@ c_cpp_builtins (cpp_reader *pfile)
|
||||
#endif
|
||||
builtin_define_with_int_value ("__LIBGCC_DWARF_FRAME_REGISTERS__",
|
||||
DWARF_FRAME_REGISTERS);
|
||||
+ builtin_define_with_int_value ("__LIBGCC_DWARF_CIE_DATA_ALIGNMENT__",
|
||||
+ DWARF_CIE_DATA_ALIGNMENT);
|
||||
+
|
||||
#ifdef EH_RETURN_STACKADJ_RTX
|
||||
cpp_define (pfile, "__LIBGCC_EH_RETURN_STACKADJ_RTX__");
|
||||
#endif
|
||||
diff --git a/libgcc/unwind-dw2-execute_cfa.h b/libgcc/unwind-dw2-execute_cfa.h
|
||||
new file mode 100644
|
||||
index 0000000000000000..dd97b7866686a361
|
||||
--- /dev/null
|
||||
+++ b/libgcc/unwind-dw2-execute_cfa.h
|
||||
@@ -0,0 +1,322 @@
|
||||
+/* DWARF2 exception handling CFA execution engine.
|
||||
+ Copyright (C) 1997-2022 Free Software Foundation, Inc.
|
||||
+
|
||||
+ This file is part of GCC.
|
||||
+
|
||||
+ GCC is free software; you can redistribute it and/or modify it
|
||||
+ under the terms of the GNU General Public License as published by
|
||||
+ the Free Software Foundation; either version 3, or (at your option)
|
||||
+ any later version.
|
||||
+
|
||||
+ GCC is distributed in the hope that it will be useful, but WITHOUT
|
||||
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
+ License for more details.
|
||||
+
|
||||
+ Under Section 7 of GPL version 3, you are granted additional
|
||||
+ permissions described in the GCC Runtime Library Exception, version
|
||||
+ 3.1, as published by the Free Software Foundation.
|
||||
+
|
||||
+ You should have received a copy of the GNU General Public License and
|
||||
+ a copy of the GCC Runtime Library Exception along with this program;
|
||||
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
+ <http://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+/* This file is included from unwind-dw2.c to specialize the code for certain
|
||||
+ values of DATA_ALIGN and CODE_ALIGN. These macros must be defined prior to
|
||||
+ including this file. */
|
||||
+
|
||||
+{
|
||||
+ struct frame_state_reg_info *unused_rs = NULL;
|
||||
+
|
||||
+ /* Don't allow remember/restore between CIE and FDE programs. */
|
||||
+ fs->regs.prev = NULL;
|
||||
+
|
||||
+ /* The comparison with the return address uses < rather than <= because
|
||||
+ we are only interested in the effects of code before the call; for a
|
||||
+ noreturn function, the return address may point to unrelated code with
|
||||
+ a different stack configuration that we are not interested in. We
|
||||
+ assume that the call itself is unwind info-neutral; if not, or if
|
||||
+ there are delay instructions that adjust the stack, these must be
|
||||
+ reflected at the point immediately before the call insn.
|
||||
+ In signal frames, return address is after last completed instruction,
|
||||
+ so we add 1 to return address to make the comparison <=. */
|
||||
+ while (insn_ptr < insn_end
|
||||
+ && fs->pc < context->ra + _Unwind_IsSignalFrame (context))
|
||||
+ {
|
||||
+ unsigned char insn = *insn_ptr++;
|
||||
+ _uleb128_t reg, utmp;
|
||||
+ _sleb128_t offset, stmp;
|
||||
+
|
||||
+ if ((insn & 0xc0) == DW_CFA_advance_loc)
|
||||
+ fs->pc += (insn & 0x3f) * CODE_ALIGN;
|
||||
+ else if ((insn & 0xc0) == DW_CFA_offset)
|
||||
+ {
|
||||
+ reg = insn & 0x3f;
|
||||
+ insn_ptr = read_uleb128 (insn_ptr, &utmp);
|
||||
+ offset = (_Unwind_Sword) utmp * DATA_ALIGN;
|
||||
+ reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
|
||||
+ if (UNWIND_COLUMN_IN_RANGE (reg))
|
||||
+ {
|
||||
+ fs->regs.how[reg] = REG_SAVED_OFFSET;
|
||||
+ fs->regs.reg[reg].loc.offset = offset;
|
||||
+ }
|
||||
+ }
|
||||
+ else if ((insn & 0xc0) == DW_CFA_restore)
|
||||
+ {
|
||||
+ reg = insn & 0x3f;
|
||||
+ reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
|
||||
+ if (UNWIND_COLUMN_IN_RANGE (reg))
|
||||
+ fs->regs.how[reg] = REG_UNSAVED;
|
||||
+ }
|
||||
+ else switch (insn)
|
||||
+ {
|
||||
+ case DW_CFA_set_loc:
|
||||
+ {
|
||||
+ _Unwind_Ptr pc;
|
||||
+
|
||||
+ insn_ptr = read_encoded_value (context, fs->fde_encoding,
|
||||
+ insn_ptr, &pc);
|
||||
+ fs->pc = (void *) pc;
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
+ case DW_CFA_advance_loc1:
|
||||
+ fs->pc += read_1u (insn_ptr) * CODE_ALIGN;
|
||||
+ insn_ptr += 1;
|
||||
+ break;
|
||||
+ case DW_CFA_advance_loc2:
|
||||
+ fs->pc += read_2u (insn_ptr) * CODE_ALIGN;
|
||||
+ insn_ptr += 2;
|
||||
+ break;
|
||||
+ case DW_CFA_advance_loc4:
|
||||
+ fs->pc += read_4u (insn_ptr) * CODE_ALIGN;
|
||||
+ insn_ptr += 4;
|
||||
+ break;
|
||||
+
|
||||
+ case DW_CFA_offset_extended:
|
||||
+ insn_ptr = read_uleb128 (insn_ptr, ®);
|
||||
+ insn_ptr = read_uleb128 (insn_ptr, &utmp);
|
||||
+ offset = (_Unwind_Sword) utmp * DATA_ALIGN;
|
||||
+ reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
|
||||
+ if (UNWIND_COLUMN_IN_RANGE (reg))
|
||||
+ {
|
||||
+ fs->regs.how[reg] = REG_SAVED_OFFSET;
|
||||
+ fs->regs.reg[reg].loc.offset = offset;
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
+ case DW_CFA_restore_extended:
|
||||
+ insn_ptr = read_uleb128 (insn_ptr, ®);
|
||||
+ /* FIXME, this is wrong; the CIE might have said that the
|
||||
+ register was saved somewhere. */
|
||||
+ reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
|
||||
+ if (UNWIND_COLUMN_IN_RANGE (reg))
|
||||
+ fs->regs.how[reg] = REG_UNSAVED;
|
||||
+ break;
|
||||
+
|
||||
+ case DW_CFA_same_value:
|
||||
+ insn_ptr = read_uleb128 (insn_ptr, ®);
|
||||
+ reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
|
||||
+ if (UNWIND_COLUMN_IN_RANGE (reg))
|
||||
+ fs->regs.how[reg] = REG_UNSAVED;
|
||||
+ break;
|
||||
+
|
||||
+ case DW_CFA_undefined:
|
||||
+ insn_ptr = read_uleb128 (insn_ptr, ®);
|
||||
+ reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
|
||||
+ if (UNWIND_COLUMN_IN_RANGE (reg))
|
||||
+ fs->regs.how[reg] = REG_UNDEFINED;
|
||||
+ break;
|
||||
+
|
||||
+ case DW_CFA_nop:
|
||||
+ break;
|
||||
+
|
||||
+ case DW_CFA_register:
|
||||
+ {
|
||||
+ _uleb128_t reg2;
|
||||
+ insn_ptr = read_uleb128 (insn_ptr, ®);
|
||||
+ insn_ptr = read_uleb128 (insn_ptr, ®2);
|
||||
+ reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
|
||||
+ if (UNWIND_COLUMN_IN_RANGE (reg))
|
||||
+ {
|
||||
+ fs->regs.how[reg] = REG_SAVED_REG;
|
||||
+ fs->regs.reg[reg].loc.reg = (_Unwind_Word)reg2;
|
||||
+ }
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
+ case DW_CFA_remember_state:
|
||||
+ {
|
||||
+ struct frame_state_reg_info *new_rs;
|
||||
+ if (unused_rs)
|
||||
+ {
|
||||
+ new_rs = unused_rs;
|
||||
+ unused_rs = unused_rs->prev;
|
||||
+ }
|
||||
+ else
|
||||
+ new_rs = alloca (sizeof (struct frame_state_reg_info));
|
||||
+
|
||||
+ *new_rs = fs->regs;
|
||||
+ fs->regs.prev = new_rs;
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
+ case DW_CFA_restore_state:
|
||||
+ {
|
||||
+ struct frame_state_reg_info *old_rs = fs->regs.prev;
|
||||
+ fs->regs = *old_rs;
|
||||
+ old_rs->prev = unused_rs;
|
||||
+ unused_rs = old_rs;
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
+ case DW_CFA_def_cfa:
|
||||
+ insn_ptr = read_uleb128 (insn_ptr, &utmp);
|
||||
+ fs->regs.cfa_reg = (_Unwind_Word)utmp;
|
||||
+ insn_ptr = read_uleb128 (insn_ptr, &utmp);
|
||||
+ fs->regs.cfa_offset = (_Unwind_Word)utmp;
|
||||
+ fs->regs.cfa_how = CFA_REG_OFFSET;
|
||||
+ break;
|
||||
+
|
||||
+ case DW_CFA_def_cfa_register:
|
||||
+ insn_ptr = read_uleb128 (insn_ptr, &utmp);
|
||||
+ fs->regs.cfa_reg = (_Unwind_Word)utmp;
|
||||
+ fs->regs.cfa_how = CFA_REG_OFFSET;
|
||||
+ break;
|
||||
+
|
||||
+ case DW_CFA_def_cfa_offset:
|
||||
+ insn_ptr = read_uleb128 (insn_ptr, &utmp);
|
||||
+ fs->regs.cfa_offset = utmp;
|
||||
+ /* cfa_how deliberately not set. */
|
||||
+ break;
|
||||
+
|
||||
+ case DW_CFA_def_cfa_expression:
|
||||
+ fs->regs.cfa_exp = insn_ptr;
|
||||
+ fs->regs.cfa_how = CFA_EXP;
|
||||
+ insn_ptr = read_uleb128 (insn_ptr, &utmp);
|
||||
+ insn_ptr += utmp;
|
||||
+ break;
|
||||
+
|
||||
+ case DW_CFA_expression:
|
||||
+ insn_ptr = read_uleb128 (insn_ptr, ®);
|
||||
+ reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
|
||||
+ if (UNWIND_COLUMN_IN_RANGE (reg))
|
||||
+ {
|
||||
+ fs->regs.how[reg] = REG_SAVED_EXP;
|
||||
+ fs->regs.reg[reg].loc.exp = insn_ptr;
|
||||
+ }
|
||||
+ insn_ptr = read_uleb128 (insn_ptr, &utmp);
|
||||
+ insn_ptr += utmp;
|
||||
+ break;
|
||||
+
|
||||
+ /* Dwarf3. */
|
||||
+ case DW_CFA_offset_extended_sf:
|
||||
+ insn_ptr = read_uleb128 (insn_ptr, ®);
|
||||
+ insn_ptr = read_sleb128 (insn_ptr, &stmp);
|
||||
+ offset = stmp * DATA_ALIGN;
|
||||
+ reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
|
||||
+ if (UNWIND_COLUMN_IN_RANGE (reg))
|
||||
+ {
|
||||
+ fs->regs.how[reg] = REG_SAVED_OFFSET;
|
||||
+ fs->regs.reg[reg].loc.offset = offset;
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
+ case DW_CFA_def_cfa_sf:
|
||||
+ insn_ptr = read_uleb128 (insn_ptr, &utmp);
|
||||
+ fs->regs.cfa_reg = (_Unwind_Word)utmp;
|
||||
+ insn_ptr = read_sleb128 (insn_ptr, &stmp);
|
||||
+ fs->regs.cfa_offset = (_Unwind_Sword)stmp;
|
||||
+ fs->regs.cfa_how = CFA_REG_OFFSET;
|
||||
+ fs->regs.cfa_offset *= DATA_ALIGN;
|
||||
+ break;
|
||||
+
|
||||
+ case DW_CFA_def_cfa_offset_sf:
|
||||
+ insn_ptr = read_sleb128 (insn_ptr, &stmp);
|
||||
+ fs->regs.cfa_offset = (_Unwind_Sword)stmp;
|
||||
+ fs->regs.cfa_offset *= DATA_ALIGN;
|
||||
+ /* cfa_how deliberately not set. */
|
||||
+ break;
|
||||
+
|
||||
+ case DW_CFA_val_offset:
|
||||
+ insn_ptr = read_uleb128 (insn_ptr, ®);
|
||||
+ insn_ptr = read_uleb128 (insn_ptr, &utmp);
|
||||
+ offset = (_Unwind_Sword) utmp * DATA_ALIGN;
|
||||
+ reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
|
||||
+ if (UNWIND_COLUMN_IN_RANGE (reg))
|
||||
+ {
|
||||
+ fs->regs.how[reg] = REG_SAVED_VAL_OFFSET;
|
||||
+ fs->regs.reg[reg].loc.offset = offset;
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
+ case DW_CFA_val_offset_sf:
|
||||
+ insn_ptr = read_uleb128 (insn_ptr, ®);
|
||||
+ insn_ptr = read_sleb128 (insn_ptr, &stmp);
|
||||
+ offset = stmp * DATA_ALIGN;
|
||||
+ reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
|
||||
+ if (UNWIND_COLUMN_IN_RANGE (reg))
|
||||
+ {
|
||||
+ fs->regs.how[reg] = REG_SAVED_VAL_OFFSET;
|
||||
+ fs->regs.reg[reg].loc.offset = offset;
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
+ case DW_CFA_val_expression:
|
||||
+ insn_ptr = read_uleb128 (insn_ptr, ®);
|
||||
+ reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
|
||||
+ if (UNWIND_COLUMN_IN_RANGE (reg))
|
||||
+ {
|
||||
+ fs->regs.how[reg] = REG_SAVED_VAL_EXP;
|
||||
+ fs->regs.reg[reg].loc.exp = insn_ptr;
|
||||
+ }
|
||||
+ insn_ptr = read_uleb128 (insn_ptr, &utmp);
|
||||
+ insn_ptr += utmp;
|
||||
+ break;
|
||||
+
|
||||
+ case DW_CFA_GNU_window_save:
|
||||
+#if defined (__aarch64__) && !defined (__ILP32__)
|
||||
+ /* This CFA is multiplexed with Sparc. On AArch64 it's used to toggle
|
||||
+ return address signing status. */
|
||||
+ reg = DWARF_REGNUM_AARCH64_RA_STATE;
|
||||
+ gcc_assert (fs->regs.how[reg] == REG_UNSAVED);
|
||||
+ fs->regs.reg[reg].loc.offset ^= 1;
|
||||
+#else
|
||||
+ /* ??? Hardcoded for SPARC register window configuration. */
|
||||
+ if (__LIBGCC_DWARF_FRAME_REGISTERS__ >= 32)
|
||||
+ for (reg = 16; reg < 32; ++reg)
|
||||
+ {
|
||||
+ fs->regs.how[reg] = REG_SAVED_OFFSET;
|
||||
+ fs->regs.reg[reg].loc.offset = (reg - 16) * sizeof (void *);
|
||||
+ }
|
||||
+#endif
|
||||
+ break;
|
||||
+
|
||||
+ case DW_CFA_GNU_args_size:
|
||||
+ insn_ptr = read_uleb128 (insn_ptr, &utmp);
|
||||
+ context->args_size = (_Unwind_Word)utmp;
|
||||
+ break;
|
||||
+
|
||||
+ case DW_CFA_GNU_negative_offset_extended:
|
||||
+ /* Obsoleted by DW_CFA_offset_extended_sf, but used by
|
||||
+ older PowerPC code. */
|
||||
+ insn_ptr = read_uleb128 (insn_ptr, ®);
|
||||
+ insn_ptr = read_uleb128 (insn_ptr, &utmp);
|
||||
+ offset = (_Unwind_Word) utmp * DATA_ALIGN;
|
||||
+ reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
|
||||
+ if (UNWIND_COLUMN_IN_RANGE (reg))
|
||||
+ {
|
||||
+ fs->regs.how[reg] = REG_SAVED_OFFSET;
|
||||
+ fs->regs.reg[reg].loc.offset = -offset;
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
+ default:
|
||||
+ gcc_unreachable ();
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+#undef DATA_ALIGN
|
||||
+#undef CODE_ALIGN
|
||||
diff --git a/libgcc/unwind-dw2.c b/libgcc/unwind-dw2.c
|
||||
index daebcb8bf7d215fe..701552634c6e87c5 100644
|
||||
--- a/libgcc/unwind-dw2.c
|
||||
+++ b/libgcc/unwind-dw2.c
|
||||
@@ -947,302 +947,43 @@ execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end,
|
||||
instruction sequence to decode, current register information and
|
||||
CIE info, and the PC range to evaluate. */
|
||||
|
||||
+static void __attribute__ ((__noinline__))
|
||||
+execute_cfa_program_generic (const unsigned char *insn_ptr,
|
||||
+ const unsigned char *insn_end,
|
||||
+ struct _Unwind_Context *context,
|
||||
+ _Unwind_FrameState *fs)
|
||||
+{
|
||||
+#define DATA_ALIGN fs->data_align
|
||||
+#define CODE_ALIGN fs->code_align
|
||||
+#include "unwind-dw2-execute_cfa.h"
|
||||
+}
|
||||
+
|
||||
+static inline void
|
||||
+execute_cfa_program_specialized (const unsigned char *insn_ptr,
|
||||
+ const unsigned char *insn_end,
|
||||
+ struct _Unwind_Context *context,
|
||||
+ _Unwind_FrameState *fs)
|
||||
+{
|
||||
+#define DATA_ALIGN __LIBGCC_DWARF_CIE_DATA_ALIGNMENT__
|
||||
+ /* GCC always uses 1 even on architectures with a fixed instruction
|
||||
+ width. */
|
||||
+#define CODE_ALIGN 1
|
||||
+#include "unwind-dw2-execute_cfa.h"
|
||||
+}
|
||||
+
|
||||
static void
|
||||
execute_cfa_program (const unsigned char *insn_ptr,
|
||||
const unsigned char *insn_end,
|
||||
struct _Unwind_Context *context,
|
||||
_Unwind_FrameState *fs)
|
||||
{
|
||||
- struct frame_state_reg_info *unused_rs = NULL;
|
||||
-
|
||||
- /* Don't allow remember/restore between CIE and FDE programs. */
|
||||
- fs->regs.prev = NULL;
|
||||
-
|
||||
- /* The comparison with the return address uses < rather than <= because
|
||||
- we are only interested in the effects of code before the call; for a
|
||||
- noreturn function, the return address may point to unrelated code with
|
||||
- a different stack configuration that we are not interested in. We
|
||||
- assume that the call itself is unwind info-neutral; if not, or if
|
||||
- there are delay instructions that adjust the stack, these must be
|
||||
- reflected at the point immediately before the call insn.
|
||||
- In signal frames, return address is after last completed instruction,
|
||||
- so we add 1 to return address to make the comparison <=. */
|
||||
- while (insn_ptr < insn_end
|
||||
- && fs->pc < context->ra + _Unwind_IsSignalFrame (context))
|
||||
- {
|
||||
- unsigned char insn = *insn_ptr++;
|
||||
- _uleb128_t reg, utmp;
|
||||
- _sleb128_t offset, stmp;
|
||||
-
|
||||
- if ((insn & 0xc0) == DW_CFA_advance_loc)
|
||||
- fs->pc += (insn & 0x3f) * fs->code_align;
|
||||
- else if ((insn & 0xc0) == DW_CFA_offset)
|
||||
- {
|
||||
- reg = insn & 0x3f;
|
||||
- insn_ptr = read_uleb128 (insn_ptr, &utmp);
|
||||
- offset = (_Unwind_Sword) utmp * fs->data_align;
|
||||
- reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
|
||||
- if (UNWIND_COLUMN_IN_RANGE (reg))
|
||||
- {
|
||||
- fs->regs.how[reg] = REG_SAVED_OFFSET;
|
||||
- fs->regs.reg[reg].loc.offset = offset;
|
||||
- }
|
||||
- }
|
||||
- else if ((insn & 0xc0) == DW_CFA_restore)
|
||||
- {
|
||||
- reg = insn & 0x3f;
|
||||
- reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
|
||||
- if (UNWIND_COLUMN_IN_RANGE (reg))
|
||||
- fs->regs.how[reg] = REG_UNSAVED;
|
||||
- }
|
||||
- else switch (insn)
|
||||
- {
|
||||
- case DW_CFA_set_loc:
|
||||
- {
|
||||
- _Unwind_Ptr pc;
|
||||
-
|
||||
- insn_ptr = read_encoded_value (context, fs->fde_encoding,
|
||||
- insn_ptr, &pc);
|
||||
- fs->pc = (void *) pc;
|
||||
- }
|
||||
- break;
|
||||
-
|
||||
- case DW_CFA_advance_loc1:
|
||||
- fs->pc += read_1u (insn_ptr) * fs->code_align;
|
||||
- insn_ptr += 1;
|
||||
- break;
|
||||
- case DW_CFA_advance_loc2:
|
||||
- fs->pc += read_2u (insn_ptr) * fs->code_align;
|
||||
- insn_ptr += 2;
|
||||
- break;
|
||||
- case DW_CFA_advance_loc4:
|
||||
- fs->pc += read_4u (insn_ptr) * fs->code_align;
|
||||
- insn_ptr += 4;
|
||||
- break;
|
||||
-
|
||||
- case DW_CFA_offset_extended:
|
||||
- insn_ptr = read_uleb128 (insn_ptr, ®);
|
||||
- insn_ptr = read_uleb128 (insn_ptr, &utmp);
|
||||
- offset = (_Unwind_Sword) utmp * fs->data_align;
|
||||
- reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
|
||||
- if (UNWIND_COLUMN_IN_RANGE (reg))
|
||||
- {
|
||||
- fs->regs.how[reg] = REG_SAVED_OFFSET;
|
||||
- fs->regs.reg[reg].loc.offset = offset;
|
||||
- }
|
||||
- break;
|
||||
-
|
||||
- case DW_CFA_restore_extended:
|
||||
- insn_ptr = read_uleb128 (insn_ptr, ®);
|
||||
- /* FIXME, this is wrong; the CIE might have said that the
|
||||
- register was saved somewhere. */
|
||||
- reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
|
||||
- if (UNWIND_COLUMN_IN_RANGE (reg))
|
||||
- fs->regs.how[reg] = REG_UNSAVED;
|
||||
- break;
|
||||
-
|
||||
- case DW_CFA_same_value:
|
||||
- insn_ptr = read_uleb128 (insn_ptr, ®);
|
||||
- reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
|
||||
- if (UNWIND_COLUMN_IN_RANGE (reg))
|
||||
- fs->regs.how[reg] = REG_UNSAVED;
|
||||
- break;
|
||||
-
|
||||
- case DW_CFA_undefined:
|
||||
- insn_ptr = read_uleb128 (insn_ptr, ®);
|
||||
- reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
|
||||
- if (UNWIND_COLUMN_IN_RANGE (reg))
|
||||
- fs->regs.how[reg] = REG_UNDEFINED;
|
||||
- break;
|
||||
-
|
||||
- case DW_CFA_nop:
|
||||
- break;
|
||||
-
|
||||
- case DW_CFA_register:
|
||||
- {
|
||||
- _uleb128_t reg2;
|
||||
- insn_ptr = read_uleb128 (insn_ptr, ®);
|
||||
- insn_ptr = read_uleb128 (insn_ptr, ®2);
|
||||
- reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
|
||||
- if (UNWIND_COLUMN_IN_RANGE (reg))
|
||||
- {
|
||||
- fs->regs.how[reg] = REG_SAVED_REG;
|
||||
- fs->regs.reg[reg].loc.reg = (_Unwind_Word)reg2;
|
||||
- }
|
||||
- }
|
||||
- break;
|
||||
-
|
||||
- case DW_CFA_remember_state:
|
||||
- {
|
||||
- struct frame_state_reg_info *new_rs;
|
||||
- if (unused_rs)
|
||||
- {
|
||||
- new_rs = unused_rs;
|
||||
- unused_rs = unused_rs->prev;
|
||||
- }
|
||||
- else
|
||||
- new_rs = alloca (sizeof (struct frame_state_reg_info));
|
||||
-
|
||||
- *new_rs = fs->regs;
|
||||
- fs->regs.prev = new_rs;
|
||||
- }
|
||||
- break;
|
||||
-
|
||||
- case DW_CFA_restore_state:
|
||||
- {
|
||||
- struct frame_state_reg_info *old_rs = fs->regs.prev;
|
||||
- fs->regs = *old_rs;
|
||||
- old_rs->prev = unused_rs;
|
||||
- unused_rs = old_rs;
|
||||
- }
|
||||
- break;
|
||||
-
|
||||
- case DW_CFA_def_cfa:
|
||||
- insn_ptr = read_uleb128 (insn_ptr, &utmp);
|
||||
- fs->regs.cfa_reg = (_Unwind_Word)utmp;
|
||||
- insn_ptr = read_uleb128 (insn_ptr, &utmp);
|
||||
- fs->regs.cfa_offset = (_Unwind_Word)utmp;
|
||||
- fs->regs.cfa_how = CFA_REG_OFFSET;
|
||||
- break;
|
||||
-
|
||||
- case DW_CFA_def_cfa_register:
|
||||
- insn_ptr = read_uleb128 (insn_ptr, &utmp);
|
||||
- fs->regs.cfa_reg = (_Unwind_Word)utmp;
|
||||
- fs->regs.cfa_how = CFA_REG_OFFSET;
|
||||
- break;
|
||||
-
|
||||
- case DW_CFA_def_cfa_offset:
|
||||
- insn_ptr = read_uleb128 (insn_ptr, &utmp);
|
||||
- fs->regs.cfa_offset = utmp;
|
||||
- /* cfa_how deliberately not set. */
|
||||
- break;
|
||||
-
|
||||
- case DW_CFA_def_cfa_expression:
|
||||
- fs->regs.cfa_exp = insn_ptr;
|
||||
- fs->regs.cfa_how = CFA_EXP;
|
||||
- insn_ptr = read_uleb128 (insn_ptr, &utmp);
|
||||
- insn_ptr += utmp;
|
||||
- break;
|
||||
-
|
||||
- case DW_CFA_expression:
|
||||
- insn_ptr = read_uleb128 (insn_ptr, ®);
|
||||
- reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
|
||||
- if (UNWIND_COLUMN_IN_RANGE (reg))
|
||||
- {
|
||||
- fs->regs.how[reg] = REG_SAVED_EXP;
|
||||
- fs->regs.reg[reg].loc.exp = insn_ptr;
|
||||
- }
|
||||
- insn_ptr = read_uleb128 (insn_ptr, &utmp);
|
||||
- insn_ptr += utmp;
|
||||
- break;
|
||||
-
|
||||
- /* Dwarf3. */
|
||||
- case DW_CFA_offset_extended_sf:
|
||||
- insn_ptr = read_uleb128 (insn_ptr, ®);
|
||||
- insn_ptr = read_sleb128 (insn_ptr, &stmp);
|
||||
- offset = stmp * fs->data_align;
|
||||
- reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
|
||||
- if (UNWIND_COLUMN_IN_RANGE (reg))
|
||||
- {
|
||||
- fs->regs.how[reg] = REG_SAVED_OFFSET;
|
||||
- fs->regs.reg[reg].loc.offset = offset;
|
||||
- }
|
||||
- break;
|
||||
-
|
||||
- case DW_CFA_def_cfa_sf:
|
||||
- insn_ptr = read_uleb128 (insn_ptr, &utmp);
|
||||
- fs->regs.cfa_reg = (_Unwind_Word)utmp;
|
||||
- insn_ptr = read_sleb128 (insn_ptr, &stmp);
|
||||
- fs->regs.cfa_offset = (_Unwind_Sword)stmp;
|
||||
- fs->regs.cfa_how = CFA_REG_OFFSET;
|
||||
- fs->regs.cfa_offset *= fs->data_align;
|
||||
- break;
|
||||
-
|
||||
- case DW_CFA_def_cfa_offset_sf:
|
||||
- insn_ptr = read_sleb128 (insn_ptr, &stmp);
|
||||
- fs->regs.cfa_offset = (_Unwind_Sword)stmp;
|
||||
- fs->regs.cfa_offset *= fs->data_align;
|
||||
- /* cfa_how deliberately not set. */
|
||||
- break;
|
||||
-
|
||||
- case DW_CFA_val_offset:
|
||||
- insn_ptr = read_uleb128 (insn_ptr, ®);
|
||||
- insn_ptr = read_uleb128 (insn_ptr, &utmp);
|
||||
- offset = (_Unwind_Sword) utmp * fs->data_align;
|
||||
- reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
|
||||
- if (UNWIND_COLUMN_IN_RANGE (reg))
|
||||
- {
|
||||
- fs->regs.how[reg] = REG_SAVED_VAL_OFFSET;
|
||||
- fs->regs.reg[reg].loc.offset = offset;
|
||||
- }
|
||||
- break;
|
||||
-
|
||||
- case DW_CFA_val_offset_sf:
|
||||
- insn_ptr = read_uleb128 (insn_ptr, ®);
|
||||
- insn_ptr = read_sleb128 (insn_ptr, &stmp);
|
||||
- offset = stmp * fs->data_align;
|
||||
- reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
|
||||
- if (UNWIND_COLUMN_IN_RANGE (reg))
|
||||
- {
|
||||
- fs->regs.how[reg] = REG_SAVED_VAL_OFFSET;
|
||||
- fs->regs.reg[reg].loc.offset = offset;
|
||||
- }
|
||||
- break;
|
||||
-
|
||||
- case DW_CFA_val_expression:
|
||||
- insn_ptr = read_uleb128 (insn_ptr, ®);
|
||||
- reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
|
||||
- if (UNWIND_COLUMN_IN_RANGE (reg))
|
||||
- {
|
||||
- fs->regs.how[reg] = REG_SAVED_VAL_EXP;
|
||||
- fs->regs.reg[reg].loc.exp = insn_ptr;
|
||||
- }
|
||||
- insn_ptr = read_uleb128 (insn_ptr, &utmp);
|
||||
- insn_ptr += utmp;
|
||||
- break;
|
||||
-
|
||||
- case DW_CFA_GNU_window_save:
|
||||
-#if defined (__aarch64__) && !defined (__ILP32__)
|
||||
- /* This CFA is multiplexed with Sparc. On AArch64 it's used to toggle
|
||||
- return address signing status. */
|
||||
- reg = DWARF_REGNUM_AARCH64_RA_STATE;
|
||||
- gcc_assert (fs->regs.how[reg] == REG_UNSAVED);
|
||||
- fs->regs.reg[reg].loc.offset ^= 1;
|
||||
-#else
|
||||
- /* ??? Hardcoded for SPARC register window configuration. */
|
||||
- if (__LIBGCC_DWARF_FRAME_REGISTERS__ >= 32)
|
||||
- for (reg = 16; reg < 32; ++reg)
|
||||
- {
|
||||
- fs->regs.how[reg] = REG_SAVED_OFFSET;
|
||||
- fs->regs.reg[reg].loc.offset = (reg - 16) * sizeof (void *);
|
||||
- }
|
||||
-#endif
|
||||
- break;
|
||||
-
|
||||
- case DW_CFA_GNU_args_size:
|
||||
- insn_ptr = read_uleb128 (insn_ptr, &utmp);
|
||||
- context->args_size = (_Unwind_Word)utmp;
|
||||
- break;
|
||||
-
|
||||
- case DW_CFA_GNU_negative_offset_extended:
|
||||
- /* Obsoleted by DW_CFA_offset_extended_sf, but used by
|
||||
- older PowerPC code. */
|
||||
- insn_ptr = read_uleb128 (insn_ptr, ®);
|
||||
- insn_ptr = read_uleb128 (insn_ptr, &utmp);
|
||||
- offset = (_Unwind_Word) utmp * fs->data_align;
|
||||
- reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
|
||||
- if (UNWIND_COLUMN_IN_RANGE (reg))
|
||||
- {
|
||||
- fs->regs.how[reg] = REG_SAVED_OFFSET;
|
||||
- fs->regs.reg[reg].loc.offset = -offset;
|
||||
- }
|
||||
- break;
|
||||
-
|
||||
- default:
|
||||
- gcc_unreachable ();
|
||||
- }
|
||||
- }
|
||||
+ if (fs->data_align == __LIBGCC_DWARF_CIE_DATA_ALIGNMENT__
|
||||
+ && fs->code_align == 1)
|
||||
+ execute_cfa_program_specialized (insn_ptr, insn_end, context, fs);
|
||||
+ else
|
||||
+ execute_cfa_program_generic (insn_ptr, insn_end, context, fs);
|
||||
}
|
||||
+
|
||||
|
||||
/* Given the _Unwind_Context CONTEXT for a stack frame, look up the FDE for
|
||||
its caller and decode it into FS. This function also sets the
|
||||
146
SOURCES/gcc-RHEL-105072-18.patch
Normal file
146
SOURCES/gcc-RHEL-105072-18.patch
Normal file
@ -0,0 +1,146 @@
|
||||
commit c98cd1df22fbe0829149e346a1ba9bf1f0be8a40
|
||||
Author: Wilco Dijkstra <wilco.dijkstra@arm.com>
|
||||
Date: Tue Jan 3 15:57:46 2023 +0000
|
||||
|
||||
libgcc: Fix uninitialized RA signing on AArch64 [PR107678]
|
||||
|
||||
A recent change only initializes the regs.how[] during Dwarf unwinding
|
||||
which resulted in an uninitialized offset used in return address signing
|
||||
and random failures during unwinding. The fix is to encode the return
|
||||
address signing state in REG_UNSAVED and a new state REG_UNSAVED_ARCHEXT.
|
||||
|
||||
libgcc/
|
||||
PR target/107678
|
||||
* unwind-dw2.h (REG_UNSAVED_ARCHEXT): Add new enum.
|
||||
* unwind-dw2.c (uw_update_context_1): Add REG_UNSAVED_ARCHEXT case.
|
||||
* unwind-dw2-execute_cfa.h: Use REG_UNSAVED_ARCHEXT/REG_UNSAVED to
|
||||
encode the return address signing state.
|
||||
* config/aarch64/aarch64-unwind.h (aarch64_demangle_return_addr)
|
||||
Check current return address signing state.
|
||||
(aarch64_frob_update_contex): Remove.
|
||||
|
||||
diff --git a/libgcc/config/aarch64/aarch64-unwind.h b/libgcc/config/aarch64/aarch64-unwind.h
|
||||
index 466e4235991485ea..2fddadc57564348f 100644
|
||||
--- a/libgcc/config/aarch64/aarch64-unwind.h
|
||||
+++ b/libgcc/config/aarch64/aarch64-unwind.h
|
||||
@@ -29,8 +29,6 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
|
||||
#define MD_DEMANGLE_RETURN_ADDR(context, fs, addr) \
|
||||
aarch64_demangle_return_addr (context, fs, addr)
|
||||
-#define MD_FROB_UPDATE_CONTEXT(context, fs) \
|
||||
- aarch64_frob_update_context (context, fs)
|
||||
|
||||
static inline int
|
||||
aarch64_cie_signed_with_b_key (struct _Unwind_Context *context)
|
||||
@@ -55,42 +53,28 @@ aarch64_cie_signed_with_b_key (struct _Unwind_Context *context)
|
||||
|
||||
static inline void *
|
||||
aarch64_demangle_return_addr (struct _Unwind_Context *context,
|
||||
- _Unwind_FrameState *fs ATTRIBUTE_UNUSED,
|
||||
+ _Unwind_FrameState *fs,
|
||||
_Unwind_Word addr_word)
|
||||
{
|
||||
void *addr = (void *)addr_word;
|
||||
- if (context->flags & RA_SIGNED_BIT)
|
||||
+ const int reg = DWARF_REGNUM_AARCH64_RA_STATE;
|
||||
+
|
||||
+ if (fs->regs.how[reg] == REG_UNSAVED)
|
||||
+ return addr;
|
||||
+
|
||||
+ /* Return-address signing state is toggled by DW_CFA_GNU_window_save (where
|
||||
+ REG_UNSAVED/REG_UNSAVED_ARCHEXT means RA signing is disabled/enabled),
|
||||
+ or set by a DW_CFA_expression. */
|
||||
+ if (fs->regs.how[reg] == REG_UNSAVED_ARCHEXT
|
||||
+ || (_Unwind_GetGR (context, reg) & 0x1) != 0)
|
||||
{
|
||||
_Unwind_Word salt = (_Unwind_Word) context->cfa;
|
||||
if (aarch64_cie_signed_with_b_key (context) != 0)
|
||||
return __builtin_aarch64_autib1716 (addr, salt);
|
||||
return __builtin_aarch64_autia1716 (addr, salt);
|
||||
}
|
||||
- else
|
||||
- return addr;
|
||||
-}
|
||||
-
|
||||
-/* Do AArch64 private initialization on CONTEXT based on frame info FS. Mark
|
||||
- CONTEXT as return address signed if bit 0 of DWARF_REGNUM_AARCH64_RA_STATE is
|
||||
- set. */
|
||||
-
|
||||
-static inline void
|
||||
-aarch64_frob_update_context (struct _Unwind_Context *context,
|
||||
- _Unwind_FrameState *fs)
|
||||
-{
|
||||
- const int reg = DWARF_REGNUM_AARCH64_RA_STATE;
|
||||
- int ra_signed;
|
||||
- if (fs->regs.how[reg] == REG_UNSAVED)
|
||||
- ra_signed = fs->regs.reg[reg].loc.offset & 0x1;
|
||||
- else
|
||||
- ra_signed = _Unwind_GetGR (context, reg) & 0x1;
|
||||
- if (ra_signed)
|
||||
- /* The flag is used for re-authenticating EH handler's address. */
|
||||
- context->flags |= RA_SIGNED_BIT;
|
||||
- else
|
||||
- context->flags &= ~RA_SIGNED_BIT;
|
||||
|
||||
- return;
|
||||
+ return addr;
|
||||
}
|
||||
|
||||
#endif /* defined AARCH64_UNWIND_H && defined __ILP32__ */
|
||||
diff --git a/libgcc/unwind-dw2-execute_cfa.h b/libgcc/unwind-dw2-execute_cfa.h
|
||||
index dd97b7866686a361..0166f85965d4a5ee 100644
|
||||
--- a/libgcc/unwind-dw2-execute_cfa.h
|
||||
+++ b/libgcc/unwind-dw2-execute_cfa.h
|
||||
@@ -278,10 +278,15 @@
|
||||
case DW_CFA_GNU_window_save:
|
||||
#if defined (__aarch64__) && !defined (__ILP32__)
|
||||
/* This CFA is multiplexed with Sparc. On AArch64 it's used to toggle
|
||||
- return address signing status. */
|
||||
+ return address signing status. REG_UNSAVED/REG_UNSAVED_ARCHEXT
|
||||
+ mean RA signing is disabled/enabled. */
|
||||
reg = DWARF_REGNUM_AARCH64_RA_STATE;
|
||||
- gcc_assert (fs->regs.how[reg] == REG_UNSAVED);
|
||||
- fs->regs.reg[reg].loc.offset ^= 1;
|
||||
+ gcc_assert (fs->regs.how[reg] == REG_UNSAVED
|
||||
+ || fs->regs.how[reg] == REG_UNSAVED_ARCHEXT);
|
||||
+ if (fs->regs.how[reg] == REG_UNSAVED)
|
||||
+ fs->regs.how[reg] = REG_UNSAVED_ARCHEXT;
|
||||
+ else
|
||||
+ fs->regs.how[reg] = REG_UNSAVED;
|
||||
#else
|
||||
/* ??? Hardcoded for SPARC register window configuration. */
|
||||
if (__LIBGCC_DWARF_FRAME_REGISTERS__ >= 32)
|
||||
diff --git a/libgcc/unwind-dw2.c b/libgcc/unwind-dw2.c
|
||||
index 701552634c6e87c5..280ec2eb4df3d2a2 100644
|
||||
--- a/libgcc/unwind-dw2.c
|
||||
+++ b/libgcc/unwind-dw2.c
|
||||
@@ -137,9 +137,6 @@ struct _Unwind_Context
|
||||
#define SIGNAL_FRAME_BIT ((~(_Unwind_Word) 0 >> 1) + 1)
|
||||
/* Context which has version/args_size/by_value fields. */
|
||||
#define EXTENDED_CONTEXT_BIT ((~(_Unwind_Word) 0 >> 2) + 1)
|
||||
- /* Bit reserved on AArch64, return address has been signed with A or B
|
||||
- key. */
|
||||
-#define RA_SIGNED_BIT ((~(_Unwind_Word) 0 >> 3) + 1)
|
||||
_Unwind_Word flags;
|
||||
/* 0 for now, can be increased when further fields are added to
|
||||
struct _Unwind_Context. */
|
||||
@@ -1200,6 +1197,7 @@ uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
|
||||
{
|
||||
case REG_UNSAVED:
|
||||
case REG_UNDEFINED:
|
||||
+ case REG_UNSAVED_ARCHEXT:
|
||||
break;
|
||||
|
||||
case REG_SAVED_OFFSET:
|
||||
diff --git a/libgcc/unwind-dw2.h b/libgcc/unwind-dw2.h
|
||||
index 437c785efa4f297d..44f63e2eb31298d8 100644
|
||||
--- a/libgcc/unwind-dw2.h
|
||||
+++ b/libgcc/unwind-dw2.h
|
||||
@@ -29,6 +29,7 @@ enum {
|
||||
REG_SAVED_EXP,
|
||||
REG_SAVED_VAL_OFFSET,
|
||||
REG_SAVED_VAL_EXP,
|
||||
+ REG_UNSAVED_ARCHEXT, /* Target specific extension. */
|
||||
REG_UNDEFINED
|
||||
};
|
||||
|
||||
34
SOURCES/gcc-RHEL-105072-19.patch
Normal file
34
SOURCES/gcc-RHEL-105072-19.patch
Normal file
@ -0,0 +1,34 @@
|
||||
commit 9be9be828dc9020735bc7eacddd1ceae1aeedb1b
|
||||
Author: Sören Tempel <soeren+git@soeren-tempel.net>
|
||||
Date: Sun May 14 19:30:21 2023 +0200
|
||||
|
||||
fix assert in __deregister_frame_info_bases
|
||||
|
||||
The assertion in __deregister_frame_info_bases assumes that for every
|
||||
frame something was inserted into the lookup data structure by
|
||||
__register_frame_info_bases. Unfortunately, this does not necessarily
|
||||
hold true as the btree_insert call in __register_frame_info_bases will
|
||||
not insert anything for empty ranges. Therefore, we need to explicitly
|
||||
account for such empty ranges in the assertion as `ob` will be a null
|
||||
pointer for such ranges, hence causing the assertion to fail.
|
||||
|
||||
Signed-off-by: Sören Tempel <soeren@soeren-tempel.net>
|
||||
|
||||
libgcc/ChangeLog:
|
||||
* unwind-dw2-fde.c: Accept empty ranges when deregistering frames.
|
||||
|
||||
diff --git a/libgcc/unwind-dw2-fde.c b/libgcc/unwind-dw2-fde.c
|
||||
index efcf9490469ad1a0..fdf52396e8576b79 100644
|
||||
--- a/libgcc/unwind-dw2-fde.c
|
||||
+++ b/libgcc/unwind-dw2-fde.c
|
||||
@@ -278,7 +278,9 @@ __deregister_frame_info_bases (const void *begin)
|
||||
__gthread_mutex_unlock (&object_mutex);
|
||||
#endif
|
||||
|
||||
- gcc_assert (in_shutdown || ob);
|
||||
+ // If we didn't find anything in the lookup data structures then they
|
||||
+ // were either already destroyed or we tried to remove an empty range.
|
||||
+ gcc_assert (in_shutdown || ((range[1] - range[0]) == 0 || ob));
|
||||
return (void *) ob;
|
||||
}
|
||||
|
||||
147
SOURCES/gcc-RHEL-105072-2.patch
Normal file
147
SOURCES/gcc-RHEL-105072-2.patch
Normal file
@ -0,0 +1,147 @@
|
||||
commit f58bf16f672cda3ac55f92f12e258c817ece6e3c
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Mon Nov 22 13:30:23 2021 +0100
|
||||
|
||||
libgcc: Remove dbase member from struct unw_eh_callback_data if NULL
|
||||
|
||||
Only bfin, frv, i386 and nios2 need this member at present.
|
||||
|
||||
libgcc/ChangeLog
|
||||
|
||||
* unwind-dw2-fde-dip.c (NEED_DBASE_MEMBER): Define.
|
||||
(struct unw_eh_callback_data): Make dbase member conditional.
|
||||
(unw_eh_callback_data_dbase): New function.
|
||||
(base_from_cb_data): Simplify for the non-dbase case.
|
||||
(_Unwind_IteratePhdrCallback): Adjust.
|
||||
(_Unwind_Find_FDE): Likewise.
|
||||
|
||||
diff --git a/libgcc/unwind-dw2-fde-dip.c b/libgcc/unwind-dw2-fde-dip.c
|
||||
index 4a4d990f455e5c11..3f302826d2d49074 100644
|
||||
--- a/libgcc/unwind-dw2-fde-dip.c
|
||||
+++ b/libgcc/unwind-dw2-fde-dip.c
|
||||
@@ -101,15 +101,35 @@ static const fde * _Unwind_Find_registered_FDE (void *pc, struct dwarf_eh_bases
|
||||
#define PT_GNU_EH_FRAME (PT_LOOS + 0x474e550)
|
||||
#endif
|
||||
|
||||
+#ifdef CRT_GET_RFIB_DATA
|
||||
+#define NEED_DBASE_MEMBER 1
|
||||
+#else
|
||||
+#define NEED_DBASE_MEMBER 0
|
||||
+#endif
|
||||
+
|
||||
struct unw_eh_callback_data
|
||||
{
|
||||
_Unwind_Ptr pc;
|
||||
+#if NEED_DBASE_MEMBER
|
||||
void *dbase;
|
||||
+#endif
|
||||
void *func;
|
||||
const fde *ret;
|
||||
int check_cache;
|
||||
};
|
||||
|
||||
+/* Returns DATA->dbase if available, else NULL. */
|
||||
+static inline _Unwind_Ptr
|
||||
+unw_eh_callback_data_dbase (const struct unw_eh_callback_data *data
|
||||
+ __attribute__ ((unused)))
|
||||
+{
|
||||
+#if NEED_DBASE_MEMBER
|
||||
+ return (_Unwind_Ptr) data->dbase;
|
||||
+#else
|
||||
+ return 0;
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
struct unw_eh_frame_hdr
|
||||
{
|
||||
unsigned char version;
|
||||
@@ -139,9 +159,11 @@ static struct frame_hdr_cache_element *frame_hdr_cache_head;
|
||||
/* Like base_of_encoded_value, but take the base from a struct
|
||||
unw_eh_callback_data instead of an _Unwind_Context. */
|
||||
|
||||
-static _Unwind_Ptr
|
||||
-base_from_cb_data (unsigned char encoding, struct unw_eh_callback_data *data)
|
||||
+static inline _Unwind_Ptr
|
||||
+base_from_cb_data (unsigned char encoding __attribute__ ((unused)),
|
||||
+ _Unwind_Ptr dbase __attribute__ ((unused)))
|
||||
{
|
||||
+#if NEED_DBASE_MEMBER
|
||||
if (encoding == DW_EH_PE_omit)
|
||||
return 0;
|
||||
|
||||
@@ -155,10 +177,13 @@ base_from_cb_data (unsigned char encoding, struct unw_eh_callback_data *data)
|
||||
case DW_EH_PE_textrel:
|
||||
return 0;
|
||||
case DW_EH_PE_datarel:
|
||||
- return (_Unwind_Ptr) data->dbase;
|
||||
+ return dbase;
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
+#else /* !NEED_DBASE_MEMBER */
|
||||
+ return 0;
|
||||
+#endif
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -358,9 +383,10 @@ _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
+ _Unwind_Ptr dbase = unw_eh_callback_data_dbase (data);
|
||||
p = read_encoded_value_with_base (hdr->eh_frame_ptr_enc,
|
||||
base_from_cb_data (hdr->eh_frame_ptr_enc,
|
||||
- data),
|
||||
+ dbase),
|
||||
(const unsigned char *) (hdr + 1),
|
||||
&eh_frame);
|
||||
|
||||
@@ -374,7 +400,7 @@ _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
|
||||
|
||||
p = read_encoded_value_with_base (hdr->fde_count_enc,
|
||||
base_from_cb_data (hdr->fde_count_enc,
|
||||
- data),
|
||||
+ dbase),
|
||||
p, &fde_count);
|
||||
/* Shouldn't happen. */
|
||||
if (fde_count == 0)
|
||||
@@ -431,7 +457,7 @@ _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
|
||||
removed, we could cache this (and thus use search_object). */
|
||||
ob.pc_begin = NULL;
|
||||
ob.tbase = NULL;
|
||||
- ob.dbase = data->dbase;
|
||||
+ ob.dbase = (void *) dbase;
|
||||
ob.u.single = (fde *) eh_frame;
|
||||
ob.s.i = 0;
|
||||
ob.s.b.mixed_encoding = 1; /* Need to assume worst case. */
|
||||
@@ -442,7 +468,7 @@ _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
|
||||
unsigned int encoding = get_fde_encoding (data->ret);
|
||||
|
||||
read_encoded_value_with_base (encoding,
|
||||
- base_from_cb_data (encoding, data),
|
||||
+ base_from_cb_data (encoding, dbase),
|
||||
data->ret->pc_begin, &func);
|
||||
data->func = (void *) func;
|
||||
}
|
||||
@@ -460,7 +486,9 @@ _Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases)
|
||||
return ret;
|
||||
|
||||
data.pc = (_Unwind_Ptr) pc;
|
||||
+#if NEED_DBASE_MEMBER
|
||||
data.dbase = NULL;
|
||||
+#endif
|
||||
data.func = NULL;
|
||||
data.ret = NULL;
|
||||
data.check_cache = 1;
|
||||
@@ -471,7 +499,11 @@ _Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases)
|
||||
if (data.ret)
|
||||
{
|
||||
bases->tbase = NULL;
|
||||
+#if NEED_DBASE_MEMBER
|
||||
bases->dbase = data.dbase;
|
||||
+#else
|
||||
+ bases->dbase = NULL;
|
||||
+#endif
|
||||
bases->func = data.func;
|
||||
}
|
||||
return data.ret;
|
||||
38
SOURCES/gcc-RHEL-105072-20.patch
Normal file
38
SOURCES/gcc-RHEL-105072-20.patch
Normal file
@ -0,0 +1,38 @@
|
||||
commit 30adfb85ff994c0faa0cc556ba46838b218263f5
|
||||
Author: Thomas Neumann <tneumann@users.sourceforge.net>
|
||||
Date: Mon May 15 14:59:22 2023 +0200
|
||||
|
||||
fix assert in non-atomic path
|
||||
|
||||
The non-atomic path does not have range information,
|
||||
we have to adjust the assert handle that case, too.
|
||||
|
||||
libgcc/ChangeLog:
|
||||
* unwind-dw2-fde.c: Fix assert in non-atomic path.
|
||||
|
||||
diff --git a/libgcc/unwind-dw2-fde.c b/libgcc/unwind-dw2-fde.c
|
||||
index fdf52396e8576b79..9b0c229efa5427a9 100644
|
||||
--- a/libgcc/unwind-dw2-fde.c
|
||||
+++ b/libgcc/unwind-dw2-fde.c
|
||||
@@ -240,6 +240,7 @@ __deregister_frame_info_bases (const void *begin)
|
||||
|
||||
// And remove
|
||||
ob = btree_remove (®istered_frames, range[0]);
|
||||
+ bool empty_table = (range[1] - range[0]) == 0;
|
||||
#else
|
||||
init_object_mutex_once ();
|
||||
__gthread_mutex_lock (&object_mutex);
|
||||
@@ -276,11 +277,12 @@ __deregister_frame_info_bases (const void *begin)
|
||||
|
||||
out:
|
||||
__gthread_mutex_unlock (&object_mutex);
|
||||
+ const int empty_table = 0; // The non-atomic path stores all tables.
|
||||
#endif
|
||||
|
||||
// If we didn't find anything in the lookup data structures then they
|
||||
// were either already destroyed or we tried to remove an empty range.
|
||||
- gcc_assert (in_shutdown || ((range[1] - range[0]) == 0 || ob));
|
||||
+ gcc_assert (in_shutdown || (empty_table || ob));
|
||||
return (void *) ob;
|
||||
}
|
||||
|
||||
31
SOURCES/gcc-RHEL-105072-21.patch
Normal file
31
SOURCES/gcc-RHEL-105072-21.patch
Normal file
@ -0,0 +1,31 @@
|
||||
commit 5cf60b6ba111f4169305c7832b063b000e9ec36a
|
||||
Author: Thomas Neumann <tneumann@users.sourceforge.net>
|
||||
Date: Tue May 2 16:21:09 2023 +0200
|
||||
|
||||
release the sorted FDE array when deregistering a frame [PR109685]
|
||||
|
||||
The atomic fastpath bypasses the code that releases the sort
|
||||
array which was lazily allocated during unwinding. We now
|
||||
check after deregistering if there is an array to free.
|
||||
|
||||
libgcc/ChangeLog:
|
||||
PR libgcc/109685
|
||||
* unwind-dw2-fde.c: Free sort array in atomic fast path.
|
||||
|
||||
diff --git a/libgcc/unwind-dw2-fde.c b/libgcc/unwind-dw2-fde.c
|
||||
index 9b0c229efa5427a9..0fd2fc54aa651350 100644
|
||||
--- a/libgcc/unwind-dw2-fde.c
|
||||
+++ b/libgcc/unwind-dw2-fde.c
|
||||
@@ -241,6 +241,12 @@ __deregister_frame_info_bases (const void *begin)
|
||||
// And remove
|
||||
ob = btree_remove (®istered_frames, range[0]);
|
||||
bool empty_table = (range[1] - range[0]) == 0;
|
||||
+
|
||||
+ // Deallocate the sort array if any.
|
||||
+ if (ob && ob->s.b.sorted)
|
||||
+ {
|
||||
+ free (ob->u.sort);
|
||||
+ }
|
||||
#else
|
||||
init_object_mutex_once ();
|
||||
__gthread_mutex_lock (&object_mutex);
|
||||
51
SOURCES/gcc-RHEL-105072-22.patch
Normal file
51
SOURCES/gcc-RHEL-105072-22.patch
Normal file
@ -0,0 +1,51 @@
|
||||
commit 38e88d41f50d844f1404172657ef7e8372014ef6
|
||||
Author: Thomas Neumann <tneumann@users.sourceforge.net>
|
||||
Date: Wed May 10 12:33:49 2023 +0200
|
||||
|
||||
fix radix sort on 32bit platforms [PR109670]
|
||||
|
||||
The radix sort uses two buffers, a1 for input and a2 for output.
|
||||
After every digit the role of the two buffers is swapped.
|
||||
When terminating the sort early the code made sure the output
|
||||
was in a2. However, when we run out of bits, as can happen on
|
||||
32bit platforms, the sorted result was in a1, as we had just
|
||||
swapped a1 and a2.
|
||||
This patch fixes the problem by unconditionally having a1 as
|
||||
output after every loop iteration.
|
||||
|
||||
This bug manifested itself only on 32bit platforms and even then
|
||||
only in some circumstances, as it needs frames where a swap
|
||||
is required due to differences in the top-most byte, which is
|
||||
affected by ASLR. The new logic was validated by exhaustive
|
||||
search over 32bit input values.
|
||||
|
||||
libgcc/ChangeLog:
|
||||
PR libgcc/109670
|
||||
* unwind-dw2-fde.c: Fix radix sort buffer management.
|
||||
|
||||
diff --git a/libgcc/unwind-dw2-fde.c b/libgcc/unwind-dw2-fde.c
|
||||
index 0fd2fc54aa651350..41b8c2e9380bc45b 100644
|
||||
--- a/libgcc/unwind-dw2-fde.c
|
||||
+++ b/libgcc/unwind-dw2-fde.c
|
||||
@@ -634,8 +634,6 @@ fde_radixsort (struct object *ob, fde_extractor_t fde_extractor,
|
||||
// Stop if we are already sorted.
|
||||
if (!violations)
|
||||
{
|
||||
- // The sorted data is in a1 now.
|
||||
- a2 = a1;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -670,9 +668,9 @@ fde_radixsort (struct object *ob, fde_extractor_t fde_extractor,
|
||||
#undef FANOUT
|
||||
#undef FANOUTBITS
|
||||
|
||||
- // The data is in a2 now, move in place if needed.
|
||||
- if (a2 != v1->array)
|
||||
- memcpy (v1->array, a2, sizeof (const fde *) * n);
|
||||
+ // The data is in a1 now, move in place if needed.
|
||||
+ if (a1 != v1->array)
|
||||
+ memcpy (v1->array, a1, sizeof (const fde *) * n);
|
||||
}
|
||||
|
||||
static inline void
|
||||
33
SOURCES/gcc-RHEL-105072-23.patch
Normal file
33
SOURCES/gcc-RHEL-105072-23.patch
Normal file
@ -0,0 +1,33 @@
|
||||
commit 49310a993308492348119f4033e4db0bda4fe46a
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Tue Jun 6 11:01:07 2023 +0200
|
||||
|
||||
libgcc: Fix eh_frame fast path in find_fde_tail
|
||||
|
||||
The eh_frame value is only used by linear_search_fdes, not the binary
|
||||
search directly in find_fde_tail, so the bug is not immediately
|
||||
apparent with most programs.
|
||||
|
||||
Fixes commit e724b0480bfa5ec04f39be8c7290330b495c59de ("libgcc:
|
||||
Special-case BFD ld unwind table encodings in find_fde_tail").
|
||||
|
||||
libgcc/
|
||||
|
||||
PR libgcc/109712
|
||||
* unwind-dw2-fde-dip.c (find_fde_tail): Correct fast path for
|
||||
parsing eh_frame.
|
||||
|
||||
diff --git a/libgcc/unwind-dw2-fde-dip.c b/libgcc/unwind-dw2-fde-dip.c
|
||||
index d4821d7d19950f15..b46e95dc8f88ac5c 100644
|
||||
--- a/libgcc/unwind-dw2-fde-dip.c
|
||||
+++ b/libgcc/unwind-dw2-fde-dip.c
|
||||
@@ -403,8 +403,8 @@ find_fde_tail (_Unwind_Ptr pc,
|
||||
BFD ld generates. */
|
||||
signed value __attribute__ ((mode (SI)));
|
||||
memcpy (&value, p, sizeof (value));
|
||||
+ eh_frame = p + value;
|
||||
p += sizeof (value);
|
||||
- dbase = value; /* No adjustment because pcrel has base 0. */
|
||||
}
|
||||
else
|
||||
p = read_encoded_value_with_base (hdr->eh_frame_ptr_enc,
|
||||
28
SOURCES/gcc-RHEL-105072-24.patch
Normal file
28
SOURCES/gcc-RHEL-105072-24.patch
Normal file
@ -0,0 +1,28 @@
|
||||
commit 104b09005229ef48a79a33511ea192bb3ec3c415
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Tue Jul 11 06:19:39 2023 +0200
|
||||
|
||||
libgcc: Fix -Wint-conversion warning in find_fde_tail
|
||||
|
||||
Fixes commit r14-1614-g49310a99330849 ("libgcc: Fix eh_frame fast path
|
||||
in find_fde_tail").
|
||||
|
||||
libgcc/
|
||||
|
||||
PR libgcc/110179
|
||||
* unwind-dw2-fde-dip.c (find_fde_tail): Add cast to avoid
|
||||
implicit conversion of pointer value to integer.
|
||||
|
||||
diff --git a/libgcc/unwind-dw2-fde-dip.c b/libgcc/unwind-dw2-fde-dip.c
|
||||
index b46e95dc8f88ac5c..e08154c1442d748f 100644
|
||||
--- a/libgcc/unwind-dw2-fde-dip.c
|
||||
+++ b/libgcc/unwind-dw2-fde-dip.c
|
||||
@@ -403,7 +403,7 @@ find_fde_tail (_Unwind_Ptr pc,
|
||||
BFD ld generates. */
|
||||
signed value __attribute__ ((mode (SI)));
|
||||
memcpy (&value, p, sizeof (value));
|
||||
- eh_frame = p + value;
|
||||
+ eh_frame = (_Unwind_Ptr) (p + value);
|
||||
p += sizeof (value);
|
||||
}
|
||||
else
|
||||
97
SOURCES/gcc-RHEL-105072-25.patch
Normal file
97
SOURCES/gcc-RHEL-105072-25.patch
Normal file
@ -0,0 +1,97 @@
|
||||
commit c46bded78f3733ad1312d141ebf1ae541032a48b
|
||||
Author: Thomas Neumann <thomas.neumann@in.tum.de>
|
||||
Date: Fri Aug 11 09:20:27 2023 -0600
|
||||
|
||||
preserve base pointer for __deregister_frame [PR110956]
|
||||
|
||||
Original bug report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110956
|
||||
Rainer Orth successfully tested the patch on Solaris with a full bootstrap.
|
||||
|
||||
Some uncommon unwinding table encodings need to access the base pointer
|
||||
for address computations. We do not have that information in calls to
|
||||
__deregister_frame_info_bases, and previously simply used nullptr as
|
||||
base pointer. That is usually fine, but for some Solaris i386 shared
|
||||
libraries that results in wrong address computations.
|
||||
|
||||
To fix this problem we now associate the unwinding object with
|
||||
the table pointer itself, which is always known, in addition to
|
||||
the PC range. When deregistering a frame, we first locate the object
|
||||
using the table pointer, and then use the base pointer stored within
|
||||
the object to compute the PC range.
|
||||
|
||||
libgcc/ChangeLog:
|
||||
PR libgcc/110956
|
||||
* unwind-dw2-fde.c: Associate object with address of unwinding
|
||||
table.
|
||||
|
||||
diff --git a/libgcc/unwind-dw2-fde.c b/libgcc/unwind-dw2-fde.c
|
||||
index 41b8c2e9380bc45b..5d6fb29acd440563 100644
|
||||
--- a/libgcc/unwind-dw2-fde.c
|
||||
+++ b/libgcc/unwind-dw2-fde.c
|
||||
@@ -124,6 +124,9 @@ __register_frame_info_bases (const void *begin, struct object *ob,
|
||||
#endif
|
||||
|
||||
#ifdef ATOMIC_FDE_FAST_PATH
|
||||
+ // Register the object itself to know the base pointer on deregistration.
|
||||
+ btree_insert (®istered_frames, (uintptr_type) begin, 1, ob);
|
||||
+
|
||||
// Register the frame in the b-tree
|
||||
uintptr_type range[2];
|
||||
get_pc_range (ob, range);
|
||||
@@ -175,6 +178,9 @@ __register_frame_info_table_bases (void *begin, struct object *ob,
|
||||
ob->s.b.encoding = DW_EH_PE_omit;
|
||||
|
||||
#ifdef ATOMIC_FDE_FAST_PATH
|
||||
+ // Register the object itself to know the base pointer on deregistration.
|
||||
+ btree_insert (®istered_frames, (uintptr_type) begin, 1, ob);
|
||||
+
|
||||
// Register the frame in the b-tree
|
||||
uintptr_type range[2];
|
||||
get_pc_range (ob, range);
|
||||
@@ -225,22 +231,17 @@ __deregister_frame_info_bases (const void *begin)
|
||||
return ob;
|
||||
|
||||
#ifdef ATOMIC_FDE_FAST_PATH
|
||||
- // Find the corresponding PC range
|
||||
- struct object lookupob;
|
||||
- lookupob.tbase = 0;
|
||||
- lookupob.dbase = 0;
|
||||
- lookupob.u.single = begin;
|
||||
- lookupob.s.i = 0;
|
||||
- lookupob.s.b.encoding = DW_EH_PE_omit;
|
||||
-#ifdef DWARF2_OBJECT_END_PTR_EXTENSION
|
||||
- lookupob.fde_end = NULL;
|
||||
-#endif
|
||||
- uintptr_type range[2];
|
||||
- get_pc_range (&lookupob, range);
|
||||
+ // Find the originally registered object to get the base pointer.
|
||||
+ ob = btree_remove (®istered_frames, (uintptr_type) begin);
|
||||
|
||||
- // And remove
|
||||
- ob = btree_remove (®istered_frames, range[0]);
|
||||
- bool empty_table = (range[1] - range[0]) == 0;
|
||||
+ // Remove the corresponding PC range.
|
||||
+ if (ob)
|
||||
+ {
|
||||
+ uintptr_type range[2];
|
||||
+ get_pc_range (ob, range);
|
||||
+ if (range[0] != range[1])
|
||||
+ btree_remove (®istered_frames, range[0]);
|
||||
+ }
|
||||
|
||||
// Deallocate the sort array if any.
|
||||
if (ob && ob->s.b.sorted)
|
||||
@@ -283,12 +284,11 @@ __deregister_frame_info_bases (const void *begin)
|
||||
|
||||
out:
|
||||
__gthread_mutex_unlock (&object_mutex);
|
||||
- const int empty_table = 0; // The non-atomic path stores all tables.
|
||||
#endif
|
||||
|
||||
// If we didn't find anything in the lookup data structures then they
|
||||
// were either already destroyed or we tried to remove an empty range.
|
||||
- gcc_assert (in_shutdown || (empty_table || ob));
|
||||
+ gcc_assert (in_shutdown || ob);
|
||||
return (void *) ob;
|
||||
}
|
||||
|
||||
112
SOURCES/gcc-RHEL-105072-26.patch
Normal file
112
SOURCES/gcc-RHEL-105072-26.patch
Normal file
@ -0,0 +1,112 @@
|
||||
commit a364148530c28645ce87adbc58a66c9f32a325ab
|
||||
Author: Thomas Neumann <tneumann@users.sourceforge.net>
|
||||
Date: Mon Mar 11 14:35:20 2024 +0100
|
||||
|
||||
handle unwind tables that are embedded within unwinding code [PR111731]
|
||||
|
||||
Original bug report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111731
|
||||
|
||||
The unwinding mechanism registers both the code range and the unwind
|
||||
table itself within a b-tree lookup structure. That data structure
|
||||
assumes that is consists of non-overlappping intervals. This
|
||||
becomes a problem if the unwinding table is embedded within the
|
||||
code itself, as now the intervals do overlap.
|
||||
|
||||
To fix this problem we now keep the unwind tables in a separate
|
||||
b-tree, which prevents the overlap.
|
||||
|
||||
libgcc/ChangeLog:
|
||||
PR libgcc/111731
|
||||
* unwind-dw2-fde.c: Split unwind ranges if they contain the
|
||||
unwind table.
|
||||
|
||||
diff --git a/libgcc/unwind-dw2-fde.c b/libgcc/unwind-dw2-fde.c
|
||||
index 5d6fb29acd440563..421068b538abc66d 100644
|
||||
--- a/libgcc/unwind-dw2-fde.c
|
||||
+++ b/libgcc/unwind-dw2-fde.c
|
||||
@@ -48,6 +48,7 @@ typedef __UINTPTR_TYPE__ uintptr_type;
|
||||
#include "unwind-dw2-btree.h"
|
||||
|
||||
static struct btree registered_frames;
|
||||
+static struct btree registered_objects;
|
||||
static bool in_shutdown;
|
||||
|
||||
static void
|
||||
@@ -58,6 +59,7 @@ release_registered_frames (void)
|
||||
/* Release the b-tree and all frames. Frame releases that happen later are
|
||||
* silently ignored */
|
||||
btree_destroy (®istered_frames);
|
||||
+ btree_destroy (®istered_objects);
|
||||
in_shutdown = true;
|
||||
}
|
||||
|
||||
@@ -103,6 +105,21 @@ static __gthread_mutex_t object_mutex;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+#ifdef ATOMIC_FDE_FAST_PATH
|
||||
+// Register the pc range for a given object in the lookup structure.
|
||||
+static void
|
||||
+register_pc_range_for_object (uintptr_type begin, struct object *ob)
|
||||
+{
|
||||
+ // Register the object itself to know the base pointer on deregistration.
|
||||
+ btree_insert (®istered_objects, begin, 1, ob);
|
||||
+
|
||||
+ // Register the frame in the b-tree
|
||||
+ uintptr_type range[2];
|
||||
+ get_pc_range (ob, range);
|
||||
+ btree_insert (®istered_frames, range[0], range[1] - range[0], ob);
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
/* Called from crtbegin.o to register the unwind info for an object. */
|
||||
|
||||
void
|
||||
@@ -124,13 +141,7 @@ __register_frame_info_bases (const void *begin, struct object *ob,
|
||||
#endif
|
||||
|
||||
#ifdef ATOMIC_FDE_FAST_PATH
|
||||
- // Register the object itself to know the base pointer on deregistration.
|
||||
- btree_insert (®istered_frames, (uintptr_type) begin, 1, ob);
|
||||
-
|
||||
- // Register the frame in the b-tree
|
||||
- uintptr_type range[2];
|
||||
- get_pc_range (ob, range);
|
||||
- btree_insert (®istered_frames, range[0], range[1] - range[0], ob);
|
||||
+ register_pc_range_for_object ((uintptr_type) begin, ob);
|
||||
#else
|
||||
init_object_mutex_once ();
|
||||
__gthread_mutex_lock (&object_mutex);
|
||||
@@ -178,13 +189,7 @@ __register_frame_info_table_bases (void *begin, struct object *ob,
|
||||
ob->s.b.encoding = DW_EH_PE_omit;
|
||||
|
||||
#ifdef ATOMIC_FDE_FAST_PATH
|
||||
- // Register the object itself to know the base pointer on deregistration.
|
||||
- btree_insert (®istered_frames, (uintptr_type) begin, 1, ob);
|
||||
-
|
||||
- // Register the frame in the b-tree
|
||||
- uintptr_type range[2];
|
||||
- get_pc_range (ob, range);
|
||||
- btree_insert (®istered_frames, range[0], range[1] - range[0], ob);
|
||||
+ register_pc_range_for_object ((uintptr_type) begin, ob);
|
||||
#else
|
||||
init_object_mutex_once ();
|
||||
__gthread_mutex_lock (&object_mutex);
|
||||
@@ -232,7 +237,7 @@ __deregister_frame_info_bases (const void *begin)
|
||||
|
||||
#ifdef ATOMIC_FDE_FAST_PATH
|
||||
// Find the originally registered object to get the base pointer.
|
||||
- ob = btree_remove (®istered_frames, (uintptr_type) begin);
|
||||
+ ob = btree_remove (®istered_objects, (uintptr_type) begin);
|
||||
|
||||
// Remove the corresponding PC range.
|
||||
if (ob)
|
||||
@@ -240,7 +245,7 @@ __deregister_frame_info_bases (const void *begin)
|
||||
uintptr_type range[2];
|
||||
get_pc_range (ob, range);
|
||||
if (range[0] != range[1])
|
||||
- btree_remove (®istered_frames, range[0]);
|
||||
+ btree_remove (®istered_frames, range[0]);
|
||||
}
|
||||
|
||||
// Deallocate the sort array if any.
|
||||
299
SOURCES/gcc-RHEL-105072-27.patch
Normal file
299
SOURCES/gcc-RHEL-105072-27.patch
Normal file
@ -0,0 +1,299 @@
|
||||
commit 21109b37e8585a7a1b27650fcbf1749380016108
|
||||
Author: Jakub Jelinek <jakub@redhat.com>
|
||||
Date: Mon Mar 10 10:34:00 2025 +0100
|
||||
|
||||
libgcc: Fix up unwind-dw2-btree.h [PR119151]
|
||||
|
||||
The following testcase shows a bug in unwind-dw2-btree.h.
|
||||
In short, the header provides lock-free btree data structure (so no parent
|
||||
link on nodes, both insertion and deletion are done in top-down walks
|
||||
with some locking of just a few nodes at a time so that lookups can notice
|
||||
concurrent modifications and retry, non-leaf (inner) nodes contain keys
|
||||
which are initially the base address of the left-most leaf entry of the
|
||||
following child (or all ones if there is none) minus one, insertion ensures
|
||||
balancing of the tree to ensure [d/2, d] entries filled through aggressive
|
||||
splitting if it sees a full tree while walking, deletion performs various
|
||||
operations like merging neighbour trees, merging into parent or moving some
|
||||
nodes from neighbour to the current one).
|
||||
What differs from the textbook implementations is mostly that the leaf nodes
|
||||
don't include just address as a key, but address range, address + size
|
||||
(where we don't insert any ranges with zero size) and the lookups can be
|
||||
performed for any address in the [address, address + size) range. The keys
|
||||
on inner nodes are still just address-1, so the child covers all nodes
|
||||
where addr <= key unless it is covered already in children to the left.
|
||||
The user (static executables or JIT) should always ensure there is no
|
||||
overlap in between any of the ranges.
|
||||
|
||||
In the testcase a bunch of insertions are done, always followed by one
|
||||
removal, followed by one insertion of a range slightly different from the
|
||||
removed one. E.g. in the first case [&code[0x50], &code[0x59]] range
|
||||
is removed and then we insert [&code[0x4c], &code[0x53]] range instead.
|
||||
This is valid, it doesn't overlap anything. But the problem is that some
|
||||
non-leaf (inner) one used the &code[0x4f] key (after the 11 insertions
|
||||
completely correctly). On removal, nothing adjusts the keys on the parent
|
||||
nodes (it really can't in the top-down only walk, the keys could be many nodes
|
||||
above it and unlike insertion, removal only knows the start address, doesn't
|
||||
know the removed size and so will discover it only when reaching the leaf
|
||||
node which contains it; plus even if it knew the address and size, it still
|
||||
doesn't know what the second left-most leaf node will be (i.e. the one after
|
||||
removal)). And on insertion, if nodes aren't split at a level, nothing
|
||||
adjusts the inner keys either. If a range is inserted and is either fully
|
||||
bellow key (keys are - 1, so having address + size - 1 being equal to key is
|
||||
fine) or fully after key (i.e. address > key), it works just fine, but if
|
||||
the key is in a middle of the range like in this case, &code[0x4f] is in the
|
||||
middle of the [&code[0x4c], &code[0x53]] range, then insertion works fine
|
||||
(we only use size on the leaf nodes), and lookup of the addresses below
|
||||
the key work fine too (i.e. [&code[0x4c], &code[0x4f]] will succeed).
|
||||
The problem is with lookups after the key (i.e. [&code[0x50, &code[0x53]]),
|
||||
the lookup looks for them in different children of the btree and doesn't
|
||||
find an entry and returns NULL.
|
||||
|
||||
As users need to ensure non-overlapping entries at any time, the following
|
||||
patch fixes it by adjusting keys during insertion where we know not just
|
||||
the address but also size; if we find during the top-down walk a key
|
||||
which is in the middle of the range being inserted, we simply increase the
|
||||
key to be equal to address + size - 1 of the range being inserted.
|
||||
There can't be any existing leaf nodes overlapping the range in correct
|
||||
programs and the btree rebalancing done on deletion ensures we don't have
|
||||
any empty nodes which would also cause problems.
|
||||
|
||||
The patch adjusts the keys in two spots, once for the current node being
|
||||
walked (the last hunk in the header, with large comment trying to explain
|
||||
it) and once during inner node splitting in a parent node if we'd otherwise
|
||||
try to add that key in the middle of the range being inserted into the
|
||||
parent node (in that case it would be missed in the last hunk).
|
||||
The testcase covers both of those spots, so succeeds with GCC 12 (which
|
||||
didn't have btrees) and fails with vanilla GCC trunk and also fails if
|
||||
either the
|
||||
if (fence < base + size - 1)
|
||||
fence = iter->content.children[slot].separator = base + size - 1;
|
||||
or
|
||||
if (left_fence >= target && left_fence < target + size - 1)
|
||||
left_fence = target + size - 1;
|
||||
hunk is removed (of course, only with the current node sizes, i.e. up to
|
||||
15 children of inner nodes and up to 10 entries in leaf nodes).
|
||||
|
||||
2025-03-10 Jakub Jelinek <jakub@redhat.com>
|
||||
Michael Leuchtenburg <michael@slashhome.org>
|
||||
|
||||
PR libgcc/119151
|
||||
* unwind-dw2-btree.h (btree_split_inner): Add size argument. If
|
||||
left_fence is in the middle of [target,target + size - 1] range,
|
||||
increase it to target + size - 1.
|
||||
(btree_insert): Adjust btree_split_inner caller. If fence is smaller
|
||||
than base + size - 1, increase it and separator of the slot to
|
||||
base + size - 1.
|
||||
|
||||
* gcc.dg/pr119151.c: New test.
|
||||
|
||||
diff --git a/gcc/testsuite/gcc.dg/pr119151.c b/gcc/testsuite/gcc.dg/pr119151.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..6ef0f12ce9ae6c06
|
||||
--- /dev/null
|
||||
+++ b/gcc/testsuite/gcc.dg/pr119151.c
|
||||
@@ -0,0 +1,151 @@
|
||||
+/* PR libgcc/119151 */
|
||||
+/* Should be run just on targets which don't have _Unwind_Find_FDE in libc.so. */
|
||||
+/* { dg-do run { target { { x86_64-*-linux* aarch64*-*-linux* powerpc64*-*-linux* riscv*-*-linux* } && lp64 } } } */
|
||||
+/* { dg-options "-O2" } */
|
||||
+
|
||||
+struct object
|
||||
+{
|
||||
+ void *pc_begin, *tbase, *dbase, *single;
|
||||
+ __SIZE_TYPE__ i;
|
||||
+ void *fde_end, *next;
|
||||
+};
|
||||
+struct dwarf_eh_bases
|
||||
+{
|
||||
+ void *tbase, *dbase, *func;
|
||||
+};
|
||||
+extern void __register_frame_info (const void *, struct object *);
|
||||
+extern void *__deregister_frame_info (const void *);
|
||||
+extern const void *_Unwind_Find_FDE (void *, struct dwarf_eh_bases *);
|
||||
+#define DW_EH_PE_sdata8 0x0c
|
||||
+#define DW_EH_PE_pcrel 0x10
|
||||
+#define DW_CFA_def_cfa 0x0c
|
||||
+#define DW_CFA_offset 0x80
|
||||
+
|
||||
+struct __attribute__((aligned (8))) eh_frame_cie {
|
||||
+ unsigned len;
|
||||
+ unsigned tag;
|
||||
+ unsigned char version;
|
||||
+ unsigned char augmentation[3];
|
||||
+ unsigned char code_align_factor;
|
||||
+ unsigned char data_align_factor;
|
||||
+ unsigned char ra_column;
|
||||
+ unsigned char augmentation_size;
|
||||
+ unsigned char encoding;
|
||||
+ unsigned char def_cfa;
|
||||
+ unsigned char def_cfa_op1, def_cfa_op2;
|
||||
+ unsigned char offset;
|
||||
+ unsigned char offset_op;
|
||||
+};
|
||||
+struct __attribute__((aligned (8))) eh_frame_fde {
|
||||
+ unsigned len;
|
||||
+ unsigned cie_offset;
|
||||
+ unsigned long long begin, size;
|
||||
+ unsigned char augmentation;
|
||||
+};
|
||||
+struct eh_frame_cie_fde {
|
||||
+ struct eh_frame_cie cie;
|
||||
+ struct eh_frame_fde fde;
|
||||
+ unsigned int zero;
|
||||
+ struct object obj;
|
||||
+} eh_frame[256];
|
||||
+unsigned ehidx;
|
||||
+unsigned char code[0x800] __attribute__((aligned (8)));
|
||||
+
|
||||
+void *
|
||||
+register_range (void *addr, unsigned size)
|
||||
+{
|
||||
+ /* Fills in empty-ish CIE and FDE with pcrel sdata8 encoding so that
|
||||
+ we don't need to worry about lp64 large code models.
|
||||
+ We don't actually execute anything in code and only _Unwind_Find_FDE,
|
||||
+ don't actually try to unwind anything. */
|
||||
+ eh_frame[ehidx].cie.len
|
||||
+ = (unsigned) ((char *) &eh_frame[ehidx].fde
|
||||
+ - (char *) &eh_frame[ehidx].cie.tag);
|
||||
+ eh_frame[ehidx].cie.tag = 0;
|
||||
+ eh_frame[ehidx].cie.version = 3;
|
||||
+ __builtin_memcpy (eh_frame[ehidx].cie.augmentation, "zR", 3);
|
||||
+ eh_frame[ehidx].cie.code_align_factor = 1;
|
||||
+ eh_frame[ehidx].cie.data_align_factor = 0x78; /* sleb128 -8 */
|
||||
+ eh_frame[ehidx].cie.ra_column = 0x10;
|
||||
+ eh_frame[ehidx].cie.augmentation_size = 1;
|
||||
+ eh_frame[ehidx].cie.encoding = DW_EH_PE_pcrel | DW_EH_PE_sdata8;
|
||||
+ eh_frame[ehidx].cie.def_cfa = DW_CFA_def_cfa;
|
||||
+ eh_frame[ehidx].cie.def_cfa_op1 = 7;
|
||||
+ eh_frame[ehidx].cie.def_cfa_op2 = 8;
|
||||
+ eh_frame[ehidx].cie.offset = DW_CFA_offset + 0x10;
|
||||
+ eh_frame[ehidx].cie.offset_op = 1;
|
||||
+ eh_frame[ehidx].fde.len
|
||||
+ = (unsigned) ((char *) &eh_frame[ehidx].zero
|
||||
+ - (char *) &eh_frame[ehidx].fde.cie_offset);
|
||||
+ eh_frame[ehidx].fde.cie_offset
|
||||
+ = (unsigned) ((char *) &eh_frame[ehidx].fde.cie_offset
|
||||
+ - (char *) &eh_frame[ehidx].cie);
|
||||
+ eh_frame[ehidx].fde.begin
|
||||
+ = (__INTPTR_TYPE__) ((__UINTPTR_TYPE__) addr
|
||||
+ - (__UINTPTR_TYPE__) &eh_frame[ehidx].fde.begin);
|
||||
+ eh_frame[ehidx].fde.size = size;
|
||||
+ eh_frame[ehidx].fde.augmentation = 0;
|
||||
+ eh_frame[ehidx].zero = 0;
|
||||
+ __register_frame_info (&eh_frame[ehidx].cie, &eh_frame[ehidx].obj);
|
||||
+ ++ehidx;
|
||||
+ return &eh_frame[ehidx - 1].cie;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+unregister (void *eh_frame)
|
||||
+{
|
||||
+ __deregister_frame_info (eh_frame);
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+main ()
|
||||
+{
|
||||
+ for (int i = 0; i < 0x50; i += 0x10)
|
||||
+ register_range (&code[i], 10);
|
||||
+ void *p = register_range (&code[0x50], 10);
|
||||
+ for (int i = 0x60; i < 0xb0; i += 0x10)
|
||||
+ register_range (&code[i], 10);
|
||||
+ unregister (p);
|
||||
+ register_range (&code[0x4c], 8);
|
||||
+ struct dwarf_eh_bases bases;
|
||||
+ const void *q = _Unwind_Find_FDE (&code[0x4c], &bases);
|
||||
+ const void *r = _Unwind_Find_FDE (&code[0x51], &bases);
|
||||
+ if (!q || q != r)
|
||||
+ __builtin_abort ();
|
||||
+ for (int i = 0; i <= 0xa0; i += 0x10)
|
||||
+ if (i != 0x50)
|
||||
+ {
|
||||
+ q = _Unwind_Find_FDE (&code[i], &bases);
|
||||
+ r = _Unwind_Find_FDE (&code[i + 9], &bases);
|
||||
+ if (!q || q != r)
|
||||
+ __builtin_abort ();
|
||||
+ }
|
||||
+ for (int i = 0xb0; i < 0x240; i += 0x10)
|
||||
+ register_range (&code[i], 10);
|
||||
+ p = register_range (&code[0x240], 10);
|
||||
+ for (int i = 0x250; i < 0x470; i += 0x10)
|
||||
+ register_range (&code[i], 10);
|
||||
+ void *s = register_range (&code[0x470], 10);
|
||||
+ for (int i = 0x480; i < 0x700; i += 0x10)
|
||||
+ register_range (&code[i], 10);
|
||||
+ unregister (p);
|
||||
+ register_range (&code[0x23c], 16);
|
||||
+ q = _Unwind_Find_FDE (&code[0x23d], &bases);
|
||||
+ r = _Unwind_Find_FDE (&code[0x24b], &bases);
|
||||
+ if (!q || q != r)
|
||||
+ __builtin_abort ();
|
||||
+ unregister (s);
|
||||
+ register_range (&code[0x46c], 16);
|
||||
+ q = _Unwind_Find_FDE (&code[0x46d], &bases);
|
||||
+ r = _Unwind_Find_FDE (&code[0x47b], &bases);
|
||||
+ if (!q || q != r)
|
||||
+ __builtin_abort ();
|
||||
+ for (int i = 0; i < 0x700; i += 0x10)
|
||||
+ if (i != 0x50 && i != 0x240 && i != 0x470)
|
||||
+ {
|
||||
+ q = _Unwind_Find_FDE (&code[i], &bases);
|
||||
+ r = _Unwind_Find_FDE (&code[i + 9], &bases);
|
||||
+ if (!q || q != r)
|
||||
+ __builtin_abort ();
|
||||
+ }
|
||||
+}
|
||||
diff --git a/libgcc/unwind-dw2-btree.h b/libgcc/unwind-dw2-btree.h
|
||||
index ace507d9ffbdffb7..e3f3a11a7b5443d6 100644
|
||||
--- a/libgcc/unwind-dw2-btree.h
|
||||
+++ b/libgcc/unwind-dw2-btree.h
|
||||
@@ -474,7 +474,8 @@ btree_handle_root_split (struct btree *t, struct btree_node **node,
|
||||
// Split an inner node.
|
||||
static void
|
||||
btree_split_inner (struct btree *t, struct btree_node **inner,
|
||||
- struct btree_node **parent, uintptr_type target)
|
||||
+ struct btree_node **parent, uintptr_type target,
|
||||
+ uintptr_type size)
|
||||
{
|
||||
// Check for the root.
|
||||
btree_handle_root_split (t, inner, parent);
|
||||
@@ -490,6 +491,9 @@ btree_split_inner (struct btree *t, struct btree_node **inner,
|
||||
= left_inner->content.children[split + index];
|
||||
left_inner->entry_count = split;
|
||||
uintptr_type left_fence = btree_node_get_fence_key (left_inner);
|
||||
+ if (left_fence >= target && left_fence < target + size - 1)
|
||||
+ // See the PR119151 comment in btree_insert.
|
||||
+ left_fence = target + size - 1;
|
||||
btree_node_update_separator_after_split (*parent, right_fence, left_fence,
|
||||
right_inner);
|
||||
if (target <= left_fence)
|
||||
@@ -753,13 +757,28 @@ btree_insert (struct btree *t, uintptr_type base, uintptr_type size,
|
||||
{
|
||||
// Use eager splits to avoid lock coupling up.
|
||||
if (iter->entry_count == max_fanout_inner)
|
||||
- btree_split_inner (t, &iter, &parent, base);
|
||||
+ btree_split_inner (t, &iter, &parent, base, size);
|
||||
|
||||
unsigned slot = btree_node_find_inner_slot (iter, base);
|
||||
if (parent)
|
||||
btree_node_unlock_exclusive (parent);
|
||||
parent = iter;
|
||||
fence = iter->content.children[slot].separator;
|
||||
+ if (fence < base + size - 1)
|
||||
+ // The separator was set to the base - 1 of the leftmost leaf child
|
||||
+ // at some point but such an entry could have been removed afterwards.
|
||||
+ // As both insertion and removal are just walking down the tree with
|
||||
+ // only a few current nodes locked at a time, updating the separator
|
||||
+ // on removal is not possible, especially because btree_remove does
|
||||
+ // not know the size until it reaches leaf node. We must ensure that
|
||||
+ // the separator is not in a middle of some entry though, as
|
||||
+ // btree_lookup can look up any address in the entry's range and if
|
||||
+ // the separator is in the middle, addresses below it or equal to it
|
||||
+ // would be found while addresses above it would result in failed
|
||||
+ // lookup. Update the separator now. Assumption that users
|
||||
+ // ensure no overlapping registered ranges, there should be no
|
||||
+ // current entry for any address in the range. See PR119151.
|
||||
+ fence = iter->content.children[slot].separator = base + size - 1;
|
||||
iter = iter->content.children[slot].child;
|
||||
btree_node_lock_exclusive (iter);
|
||||
}
|
||||
204
SOURCES/gcc-RHEL-105072-3.patch
Normal file
204
SOURCES/gcc-RHEL-105072-3.patch
Normal file
@ -0,0 +1,204 @@
|
||||
commit 9488d24206687be80443dafdb2cdfc4ff3aca28c
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Thu Nov 25 18:40:51 2021 +0100
|
||||
|
||||
libgcc: Split FDE search code from PT_GNU_EH_FRAME lookup
|
||||
|
||||
This allows switching to a different implementation for
|
||||
PT_GNU_EH_FRAME lookup in a subsequent commit.
|
||||
|
||||
This moves some of the PT_GNU_EH_FRAME parsing out of the glibc loader
|
||||
lock that is implied by dl_iterate_phdr. However, the FDE is already
|
||||
parsed outside the lock before this change, so this does not introduce
|
||||
additional crashes in case of a concurrent dlclose.
|
||||
|
||||
libgcc/ChangeLog:
|
||||
|
||||
* unwind-dw2-fde-dip.c (struct unw_eh_callback_data): Add hdr.
|
||||
Remove func, ret.
|
||||
(find_fde_tail): New function. Split from
|
||||
_Unwind_IteratePhdrCallback. Move the result initialization
|
||||
from _Unwind_Find_FDE.
|
||||
(_Unwind_Find_FDE): Updated to call find_fde_tail.
|
||||
|
||||
diff --git a/libgcc/unwind-dw2-fde-dip.c b/libgcc/unwind-dw2-fde-dip.c
|
||||
index 3f302826d2d49074..fbb0fbdebb92d484 100644
|
||||
--- a/libgcc/unwind-dw2-fde-dip.c
|
||||
+++ b/libgcc/unwind-dw2-fde-dip.c
|
||||
@@ -113,8 +113,7 @@ struct unw_eh_callback_data
|
||||
#if NEED_DBASE_MEMBER
|
||||
void *dbase;
|
||||
#endif
|
||||
- void *func;
|
||||
- const fde *ret;
|
||||
+ const struct unw_eh_frame_hdr *hdr;
|
||||
int check_cache;
|
||||
};
|
||||
|
||||
@@ -197,10 +196,6 @@ _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
|
||||
#else
|
||||
_Unwind_Ptr load_base;
|
||||
#endif
|
||||
- const unsigned char *p;
|
||||
- const struct unw_eh_frame_hdr *hdr;
|
||||
- _Unwind_Ptr eh_frame;
|
||||
- struct object ob;
|
||||
_Unwind_Ptr pc_low = 0, pc_high = 0;
|
||||
|
||||
struct ext_dl_phdr_info
|
||||
@@ -348,10 +343,8 @@ _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
|
||||
return 0;
|
||||
|
||||
/* Read .eh_frame_hdr header. */
|
||||
- hdr = (const struct unw_eh_frame_hdr *)
|
||||
+ data->hdr = (const struct unw_eh_frame_hdr *)
|
||||
__RELOC_POINTER (p_eh_frame_hdr->p_vaddr, load_base);
|
||||
- if (hdr->version != 1)
|
||||
- return 1;
|
||||
|
||||
#ifdef CRT_GET_RFIB_DATA
|
||||
# if defined __i386__ || defined __nios2__
|
||||
@@ -383,12 +376,30 @@ _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
- _Unwind_Ptr dbase = unw_eh_callback_data_dbase (data);
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+/* Find the FDE for the program counter PC, in a previously located
|
||||
+ PT_GNU_EH_FRAME data region. *BASES is updated if an FDE to return is
|
||||
+ found. */
|
||||
+
|
||||
+static const fde *
|
||||
+find_fde_tail (_Unwind_Ptr pc,
|
||||
+ const struct unw_eh_frame_hdr *hdr,
|
||||
+ _Unwind_Ptr dbase,
|
||||
+ struct dwarf_eh_bases *bases)
|
||||
+{
|
||||
+ const unsigned char *p = (const unsigned char *) (hdr + 1);
|
||||
+ _Unwind_Ptr eh_frame;
|
||||
+ struct object ob;
|
||||
+
|
||||
+ if (hdr->version != 1)
|
||||
+ return NULL;
|
||||
+
|
||||
p = read_encoded_value_with_base (hdr->eh_frame_ptr_enc,
|
||||
base_from_cb_data (hdr->eh_frame_ptr_enc,
|
||||
dbase),
|
||||
- (const unsigned char *) (hdr + 1),
|
||||
- &eh_frame);
|
||||
+ p, &eh_frame);
|
||||
|
||||
/* We require here specific table encoding to speed things up.
|
||||
Also, DW_EH_PE_datarel here means using PT_GNU_EH_FRAME start
|
||||
@@ -404,7 +415,7 @@ _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
|
||||
p, &fde_count);
|
||||
/* Shouldn't happen. */
|
||||
if (fde_count == 0)
|
||||
- return 1;
|
||||
+ return NULL;
|
||||
if ((((_Unwind_Ptr) p) & 3) == 0)
|
||||
{
|
||||
struct fde_table {
|
||||
@@ -419,9 +430,9 @@ _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
|
||||
_Unwind_Ptr range;
|
||||
|
||||
mid = fde_count - 1;
|
||||
- if (data->pc < table[0].initial_loc + data_base)
|
||||
- return 1;
|
||||
- else if (data->pc < table[mid].initial_loc + data_base)
|
||||
+ if (pc < table[0].initial_loc + data_base)
|
||||
+ return NULL;
|
||||
+ else if (pc < table[mid].initial_loc + data_base)
|
||||
{
|
||||
lo = 0;
|
||||
hi = mid;
|
||||
@@ -429,9 +440,9 @@ _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
|
||||
while (lo < hi)
|
||||
{
|
||||
mid = (lo + hi) / 2;
|
||||
- if (data->pc < table[mid].initial_loc + data_base)
|
||||
+ if (pc < table[mid].initial_loc + data_base)
|
||||
hi = mid;
|
||||
- else if (data->pc >= table[mid + 1].initial_loc + data_base)
|
||||
+ else if (pc >= table[mid + 1].initial_loc + data_base)
|
||||
lo = mid + 1;
|
||||
else
|
||||
break;
|
||||
@@ -445,10 +456,16 @@ _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
|
||||
f_enc_size = size_of_encoded_value (f_enc);
|
||||
read_encoded_value_with_base (f_enc & 0x0f, 0,
|
||||
&f->pc_begin[f_enc_size], &range);
|
||||
- if (data->pc < table[mid].initial_loc + data_base + range)
|
||||
- data->ret = f;
|
||||
- data->func = (void *) (table[mid].initial_loc + data_base);
|
||||
- return 1;
|
||||
+ _Unwind_Ptr func = table[mid].initial_loc + data_base;
|
||||
+ if (pc < table[mid].initial_loc + data_base + range)
|
||||
+ {
|
||||
+ bases->tbase = NULL;
|
||||
+ bases->dbase = (void *) dbase;
|
||||
+ bases->func = (void *) func;
|
||||
+ return f;
|
||||
+ }
|
||||
+ else
|
||||
+ return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -461,18 +478,20 @@ _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
|
||||
ob.u.single = (fde *) eh_frame;
|
||||
ob.s.i = 0;
|
||||
ob.s.b.mixed_encoding = 1; /* Need to assume worst case. */
|
||||
- data->ret = linear_search_fdes (&ob, (fde *) eh_frame, (void *) data->pc);
|
||||
- if (data->ret != NULL)
|
||||
+ const fde *entry = linear_search_fdes (&ob, (fde *) eh_frame, (void *) pc);
|
||||
+ if (entry != NULL)
|
||||
{
|
||||
_Unwind_Ptr func;
|
||||
- unsigned int encoding = get_fde_encoding (data->ret);
|
||||
+ unsigned int encoding = get_fde_encoding (entry);
|
||||
|
||||
read_encoded_value_with_base (encoding,
|
||||
base_from_cb_data (encoding, dbase),
|
||||
- data->ret->pc_begin, &func);
|
||||
- data->func = (void *) func;
|
||||
+ entry->pc_begin, &func);
|
||||
+ bases->tbase = NULL;
|
||||
+ bases->dbase = (void *) dbase;
|
||||
+ bases->func = (void *) func;
|
||||
}
|
||||
- return 1;
|
||||
+ return entry;
|
||||
}
|
||||
|
||||
const fde *
|
||||
@@ -489,24 +508,13 @@ _Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases)
|
||||
#if NEED_DBASE_MEMBER
|
||||
data.dbase = NULL;
|
||||
#endif
|
||||
- data.func = NULL;
|
||||
- data.ret = NULL;
|
||||
data.check_cache = 1;
|
||||
|
||||
- if (dl_iterate_phdr (_Unwind_IteratePhdrCallback, &data) < 0)
|
||||
+ if (dl_iterate_phdr (_Unwind_IteratePhdrCallback, &data) <= 0)
|
||||
return NULL;
|
||||
|
||||
- if (data.ret)
|
||||
- {
|
||||
- bases->tbase = NULL;
|
||||
-#if NEED_DBASE_MEMBER
|
||||
- bases->dbase = data.dbase;
|
||||
-#else
|
||||
- bases->dbase = NULL;
|
||||
-#endif
|
||||
- bases->func = data.func;
|
||||
- }
|
||||
- return data.ret;
|
||||
+ _Unwind_Ptr dbase = unw_eh_callback_data_dbase (&data);
|
||||
+ return find_fde_tail ((_Unwind_Ptr) pc, data.hdr, dbase, bases);
|
||||
}
|
||||
|
||||
#else
|
||||
40
SOURCES/gcc-RHEL-105072-4.patch
Normal file
40
SOURCES/gcc-RHEL-105072-4.patch
Normal file
@ -0,0 +1,40 @@
|
||||
commit 790854ea7670f11c14d431c102a49181d2915965
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Tue Jan 4 15:47:30 2022 +0100
|
||||
|
||||
libgcc: Use _dl_find_object in _Unwind_Find_FDE
|
||||
|
||||
libgcc/ChangeLog:
|
||||
|
||||
* unwind-dw2-fde-dip.c (_Unwind_Find_FDE): Call _dl_find_object
|
||||
if available.
|
||||
|
||||
diff --git a/libgcc/unwind-dw2-fde-dip.c b/libgcc/unwind-dw2-fde-dip.c
|
||||
index fbb0fbdebb92d484..b837d8e490425652 100644
|
||||
--- a/libgcc/unwind-dw2-fde-dip.c
|
||||
+++ b/libgcc/unwind-dw2-fde-dip.c
|
||||
@@ -504,6 +504,24 @@ _Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases)
|
||||
if (ret != NULL)
|
||||
return ret;
|
||||
|
||||
+ /* Use DLFO_STRUCT_HAS_EH_DBASE as a proxy for the existence of a glibc-style
|
||||
+ _dl_find_object function. */
|
||||
+#ifdef DLFO_STRUCT_HAS_EH_DBASE
|
||||
+ {
|
||||
+ struct dl_find_object dlfo;
|
||||
+ if (_dl_find_object (pc, &dlfo) == 0)
|
||||
+ return find_fde_tail ((_Unwind_Ptr) pc, dlfo.dlfo_eh_frame,
|
||||
+# if DLFO_STRUCT_HAS_EH_DBASE
|
||||
+ (_Unwind_Ptr) dlfo.dlfo_eh_dbase,
|
||||
+# else
|
||||
+ NULL,
|
||||
+# endif
|
||||
+ bases);
|
||||
+ else
|
||||
+ return NULL;
|
||||
+ }
|
||||
+#endif /* DLFO_STRUCT_HAS_EH_DBASE */
|
||||
+
|
||||
data.pc = (_Unwind_Ptr) pc;
|
||||
#if NEED_DBASE_MEMBER
|
||||
data.dbase = NULL;
|
||||
27
SOURCES/gcc-RHEL-105072-5.patch
Normal file
27
SOURCES/gcc-RHEL-105072-5.patch
Normal file
@ -0,0 +1,27 @@
|
||||
commit ab2a2457780d224343ce05e7d8e2964c6a47fd83
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Tue Jan 25 12:09:56 2022 +0100
|
||||
|
||||
libgcc: Fix _Unwind_Find_FDE for missing unwind data with glibc 2.35
|
||||
|
||||
_dl_find_object returns success even if no unwind information has been
|
||||
found, and dlfo_eh_frame is NULL.
|
||||
|
||||
libgcc/ChangeLog:
|
||||
|
||||
PR libgcc/104207
|
||||
* unwind-dw2-fde-dip.c (_Unwind_Find_FDE): Add NULL check.
|
||||
|
||||
diff --git a/libgcc/unwind-dw2-fde-dip.c b/libgcc/unwind-dw2-fde-dip.c
|
||||
index b837d8e490425652..1744c91958013ebb 100644
|
||||
--- a/libgcc/unwind-dw2-fde-dip.c
|
||||
+++ b/libgcc/unwind-dw2-fde-dip.c
|
||||
@@ -509,7 +509,7 @@ _Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases)
|
||||
#ifdef DLFO_STRUCT_HAS_EH_DBASE
|
||||
{
|
||||
struct dl_find_object dlfo;
|
||||
- if (_dl_find_object (pc, &dlfo) == 0)
|
||||
+ if (_dl_find_object (pc, &dlfo) == 0 && dlfo.dlfo_eh_frame != NULL)
|
||||
return find_fde_tail ((_Unwind_Ptr) pc, dlfo.dlfo_eh_frame,
|
||||
# if DLFO_STRUCT_HAS_EH_DBASE
|
||||
(_Unwind_Ptr) dlfo.dlfo_eh_dbase,
|
||||
28
SOURCES/gcc-RHEL-105072-6.patch
Normal file
28
SOURCES/gcc-RHEL-105072-6.patch
Normal file
@ -0,0 +1,28 @@
|
||||
commit 157cc4e0117756503c7c63df97cf31de7570b088
|
||||
Author: Xi Ruoyao <xry111@mengyan1223.wang>
|
||||
Date: Fri Feb 25 01:45:57 2022 +0800
|
||||
|
||||
libgcc: fix a warning calling find_fde_tail
|
||||
|
||||
The third parameter of find_fde_tail is an _Unwind_Ptr (which is an
|
||||
integer type instead of a pointer), but we are passing NULL to it. This
|
||||
causes a -Wint-conversion warning.
|
||||
|
||||
libgcc/
|
||||
|
||||
* unwind-dw2-fde-dip.c (_Unwind_Find_FDE): Call find_fde_tail
|
||||
with 0 instead of NULL.
|
||||
|
||||
diff --git a/libgcc/unwind-dw2-fde-dip.c b/libgcc/unwind-dw2-fde-dip.c
|
||||
index 1744c91958013ebb..25f2e44c5823cf64 100644
|
||||
--- a/libgcc/unwind-dw2-fde-dip.c
|
||||
+++ b/libgcc/unwind-dw2-fde-dip.c
|
||||
@@ -514,7 +514,7 @@ _Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases)
|
||||
# if DLFO_STRUCT_HAS_EH_DBASE
|
||||
(_Unwind_Ptr) dlfo.dlfo_eh_dbase,
|
||||
# else
|
||||
- NULL,
|
||||
+ 0,
|
||||
# endif
|
||||
bases);
|
||||
else
|
||||
222
SOURCES/gcc-RHEL-105072-7.patch
Normal file
222
SOURCES/gcc-RHEL-105072-7.patch
Normal file
@ -0,0 +1,222 @@
|
||||
commit 0d344b557604e966dc7f91739881f03e1f221efd
|
||||
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
|
||||
Date: Thu Feb 10 17:42:56 2022 +0000
|
||||
|
||||
aarch64: Fix pac-ret with unusual dwarf in libgcc unwinder [PR104689]
|
||||
|
||||
The RA_SIGN_STATE dwarf pseudo-register is normally only set using the
|
||||
DW_CFA_AARCH64_negate_ra_state (== DW_CFA_window_save) operation which
|
||||
toggles the return address signedness state (the default state is 0).
|
||||
(It may be set by remember/restore_state CFI too, those save/restore
|
||||
the state of all registers.)
|
||||
|
||||
However RA_SIGN_STATE can be set directly via DW_CFA_val_expression too.
|
||||
GCC does not generate such CFI but some other compilers reportedly do.
|
||||
|
||||
Note: the toggle operation must not be mixed with other dwarf register
|
||||
rule CFI within the same CIE and FDE.
|
||||
|
||||
In libgcc we assume REG_UNSAVED means the RA_STATE is set using toggle
|
||||
operations, otherwise we assume its value is set by other CFI.
|
||||
|
||||
libgcc/ChangeLog:
|
||||
|
||||
PR target/104689
|
||||
* config/aarch64/aarch64-unwind.h (aarch64_frob_update_context):
|
||||
Handle the !REG_UNSAVED case.
|
||||
* unwind-dw2.c (execute_cfa_program): Fail toggle if !REG_UNSAVED.
|
||||
|
||||
gcc/testsuite/ChangeLog:
|
||||
|
||||
PR target/104689
|
||||
* gcc.target/aarch64/pr104689.c: New test.
|
||||
|
||||
diff --git a/gcc/testsuite/gcc.target/aarch64/pr104689.c b/gcc/testsuite/gcc.target/aarch64/pr104689.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..3b7adbdfe7d6f969
|
||||
--- /dev/null
|
||||
+++ b/gcc/testsuite/gcc.target/aarch64/pr104689.c
|
||||
@@ -0,0 +1,149 @@
|
||||
+/* PR target/104689. Unwind across pac-ret frames with unusual dwarf. */
|
||||
+/* { dg-do run } */
|
||||
+/* { dg-require-effective-target lp64 } */
|
||||
+/* { dg-options "-fexceptions -O2" } */
|
||||
+
|
||||
+#include <unwind.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <stdio.h>
|
||||
+
|
||||
+#define die() \
|
||||
+ do { \
|
||||
+ printf ("%s:%d: reached unexpectedly.\n", __FILE__, __LINE__); \
|
||||
+ fflush (stdout); \
|
||||
+ abort (); \
|
||||
+ } while (0)
|
||||
+
|
||||
+
|
||||
+/* Code to invoke unwinding with a logging callback. */
|
||||
+
|
||||
+static struct _Unwind_Exception exc;
|
||||
+
|
||||
+static _Unwind_Reason_Code
|
||||
+force_unwind_stop (int version, _Unwind_Action actions,
|
||||
+ _Unwind_Exception_Class exc_class,
|
||||
+ struct _Unwind_Exception *exc_obj,
|
||||
+ struct _Unwind_Context *context,
|
||||
+ void *stop_parameter)
|
||||
+{
|
||||
+ printf ("%s: CFA: %p PC: %p actions: %d\n",
|
||||
+ __func__,
|
||||
+ (void *)_Unwind_GetCFA (context),
|
||||
+ (void *)_Unwind_GetIP (context),
|
||||
+ (int)actions);
|
||||
+ if (actions & _UA_END_OF_STACK)
|
||||
+ die ();
|
||||
+ return _URC_NO_REASON;
|
||||
+}
|
||||
+
|
||||
+static void force_unwind (void)
|
||||
+{
|
||||
+#ifndef __USING_SJLJ_EXCEPTIONS__
|
||||
+ _Unwind_ForcedUnwind (&exc, force_unwind_stop, 0);
|
||||
+#else
|
||||
+ _Unwind_SjLj_ForcedUnwind (&exc, force_unwind_stop, 0);
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+
|
||||
+/* Define functions with unusual pac-ret dwarf via top level asm. */
|
||||
+
|
||||
+#define STR(x) #x
|
||||
+#define DW_CFA_val_expression 0x16
|
||||
+#define RA_SIGN_STATE 34
|
||||
+#define DW_OP_lit0 0x30
|
||||
+#define DW_OP_lit1 0x31
|
||||
+
|
||||
+#define cfi_escape(a1, a2, a3, a4) \
|
||||
+ ".cfi_escape " STR(a1) ", " STR(a2) ", " STR(a3) ", " STR(a4)
|
||||
+
|
||||
+/* Bytes: 0x16 0x22 0x01 0x30 */
|
||||
+#define SET_RA_STATE_0 \
|
||||
+ cfi_escape (DW_CFA_val_expression, RA_SIGN_STATE, 1, DW_OP_lit0)
|
||||
+
|
||||
+/* Bytes: 0x16 0x22 0x01 0x31 */
|
||||
+#define SET_RA_STATE_1 \
|
||||
+ cfi_escape (DW_CFA_val_expression, RA_SIGN_STATE, 1, DW_OP_lit1)
|
||||
+
|
||||
+/* These function call their argument. */
|
||||
+void unusual_pac_ret (void *);
|
||||
+void unusual_no_pac_ret (void *);
|
||||
+
|
||||
+asm(""
|
||||
+".global unusual_pac_ret\n"
|
||||
+".type unusual_pac_ret, %function\n"
|
||||
+"unusual_pac_ret:\n"
|
||||
+" .cfi_startproc\n"
|
||||
+" " SET_RA_STATE_0 "\n"
|
||||
+" hint 25 // paciasp\n"
|
||||
+" " SET_RA_STATE_1 "\n"
|
||||
+" stp x29, x30, [sp, -16]!\n"
|
||||
+" .cfi_def_cfa_offset 16\n"
|
||||
+" .cfi_offset 29, -16\n"
|
||||
+" .cfi_offset 30, -8\n"
|
||||
+" mov x29, sp\n"
|
||||
+" blr x0\n"
|
||||
+" ldp x29, x30, [sp], 16\n"
|
||||
+" .cfi_restore 30\n"
|
||||
+" .cfi_restore 29\n"
|
||||
+" .cfi_def_cfa_offset 0\n"
|
||||
+" hint 29 // autiasp\n"
|
||||
+" " SET_RA_STATE_0 "\n"
|
||||
+" ret\n"
|
||||
+" .cfi_endproc\n");
|
||||
+
|
||||
+asm(""
|
||||
+".global unusual_no_pac_ret\n"
|
||||
+".type unusual_no_pac_ret, %function\n"
|
||||
+"unusual_no_pac_ret:\n"
|
||||
+" .cfi_startproc\n"
|
||||
+" " SET_RA_STATE_0 "\n"
|
||||
+" stp x29, x30, [sp, -16]!\n"
|
||||
+" .cfi_def_cfa_offset 16\n"
|
||||
+" .cfi_offset 29, -16\n"
|
||||
+" .cfi_offset 30, -8\n"
|
||||
+" mov x29, sp\n"
|
||||
+" blr x0\n"
|
||||
+" ldp x29, x30, [sp], 16\n"
|
||||
+" .cfi_restore 30\n"
|
||||
+" .cfi_restore 29\n"
|
||||
+" .cfi_def_cfa_offset 0\n"
|
||||
+" ret\n"
|
||||
+" .cfi_endproc\n");
|
||||
+
|
||||
+
|
||||
+/* Functions to create a call chain with mixed pac-ret dwarf. */
|
||||
+
|
||||
+__attribute__((target("branch-protection=pac-ret")))
|
||||
+static void f2_pac_ret (void)
|
||||
+{
|
||||
+ force_unwind ();
|
||||
+ die ();
|
||||
+}
|
||||
+
|
||||
+__attribute__((target("branch-protection=none")))
|
||||
+static void f1_no_pac_ret (void)
|
||||
+{
|
||||
+ unusual_pac_ret (f2_pac_ret);
|
||||
+ die ();
|
||||
+}
|
||||
+
|
||||
+__attribute__((noinline, target("branch-protection=pac-ret")))
|
||||
+static void f0_pac_ret (void)
|
||||
+{
|
||||
+ unusual_no_pac_ret (f1_no_pac_ret);
|
||||
+ die ();
|
||||
+}
|
||||
+
|
||||
+static void cleanup_handler (void *p)
|
||||
+{
|
||||
+ printf ("%s: Success.\n", __func__);
|
||||
+ exit (0);
|
||||
+}
|
||||
+
|
||||
+int main ()
|
||||
+{
|
||||
+ char dummy __attribute__((cleanup (cleanup_handler)));
|
||||
+ f0_pac_ret ();
|
||||
+ die ();
|
||||
+}
|
||||
diff --git a/libgcc/config/aarch64/aarch64-unwind.h b/libgcc/config/aarch64/aarch64-unwind.h
|
||||
index b6faa9b495094d8e..3158af4c8c371fac 100644
|
||||
--- a/libgcc/config/aarch64/aarch64-unwind.h
|
||||
+++ b/libgcc/config/aarch64/aarch64-unwind.h
|
||||
@@ -78,7 +78,13 @@ static inline void
|
||||
aarch64_frob_update_context (struct _Unwind_Context *context,
|
||||
_Unwind_FrameState *fs)
|
||||
{
|
||||
- if (fs->regs.reg[DWARF_REGNUM_AARCH64_RA_STATE].loc.offset & 0x1)
|
||||
+ const int reg = DWARF_REGNUM_AARCH64_RA_STATE;
|
||||
+ int ra_signed;
|
||||
+ if (fs->regs.reg[reg].how == REG_UNSAVED)
|
||||
+ ra_signed = fs->regs.reg[reg].loc.offset & 0x1;
|
||||
+ else
|
||||
+ ra_signed = _Unwind_GetGR (context, reg) & 0x1;
|
||||
+ if (ra_signed)
|
||||
/* The flag is used for re-authenticating EH handler's address. */
|
||||
context->flags |= RA_SIGNED_BIT;
|
||||
else
|
||||
diff --git a/libgcc/unwind-dw2.c b/libgcc/unwind-dw2.c
|
||||
index 41af7e23f47602ec..43d06531fce9bed1 100644
|
||||
--- a/libgcc/unwind-dw2.c
|
||||
+++ b/libgcc/unwind-dw2.c
|
||||
@@ -1204,7 +1204,9 @@ execute_cfa_program (const unsigned char *insn_ptr,
|
||||
#if defined (__aarch64__) && !defined (__ILP32__)
|
||||
/* This CFA is multiplexed with Sparc. On AArch64 it's used to toggle
|
||||
return address signing status. */
|
||||
- fs->regs.reg[DWARF_REGNUM_AARCH64_RA_STATE].loc.offset ^= 1;
|
||||
+ reg = DWARF_REGNUM_AARCH64_RA_STATE;
|
||||
+ gcc_assert (fs->regs.reg[reg].how == REG_UNSAVED);
|
||||
+ fs->regs.reg[reg].loc.offset ^= 1;
|
||||
#else
|
||||
/* ??? Hardcoded for SPARC register window configuration. */
|
||||
if (__LIBGCC_DWARF_FRAME_REGISTERS__ >= 32)
|
||||
1354
SOURCES/gcc-RHEL-105072-8.patch
Normal file
1354
SOURCES/gcc-RHEL-105072-8.patch
Normal file
File diff suppressed because it is too large
Load Diff
377
SOURCES/gcc-RHEL-105072-9.patch
Normal file
377
SOURCES/gcc-RHEL-105072-9.patch
Normal file
@ -0,0 +1,377 @@
|
||||
commit d458f806afe07d1e06bdf275e94d05a716f41bf6
|
||||
Author: Thomas Neumann <tneumann@users.sourceforge.net>
|
||||
Date: Sun Sep 18 11:31:01 2022 +0200
|
||||
|
||||
Remove dependency on uintptr_t in libgcc
|
||||
|
||||
uintptr_t is no available for all targets, use __UINTPTR_TYPE__
|
||||
instead.
|
||||
|
||||
libgcc/ChangeLog:
|
||||
|
||||
* unwind-dw2-fde.c: Replace uintptr_t with typedef
|
||||
for __UINTPTR_TYPE__.
|
||||
* unwind-dw2-btree.h: Likewise.
|
||||
|
||||
diff --git a/libgcc/unwind-dw2-btree.h b/libgcc/unwind-dw2-btree.h
|
||||
index 8853f0eab486b847..ace507d9ffbdffb7 100644
|
||||
--- a/libgcc/unwind-dw2-btree.h
|
||||
+++ b/libgcc/unwind-dw2-btree.h
|
||||
@@ -39,7 +39,7 @@ struct version_lock
|
||||
// range. Even on 32 bit platforms that would require 1 billion
|
||||
// frame registrations within the time span of a few assembler
|
||||
// instructions.
|
||||
- uintptr_t version_lock;
|
||||
+ uintptr_type version_lock;
|
||||
};
|
||||
|
||||
#ifdef __GTHREAD_HAS_COND
|
||||
@@ -60,7 +60,7 @@ version_lock_initialize_locked_exclusive (struct version_lock *vl)
|
||||
static inline bool
|
||||
version_lock_try_lock_exclusive (struct version_lock *vl)
|
||||
{
|
||||
- uintptr_t state = __atomic_load_n (&(vl->version_lock), __ATOMIC_SEQ_CST);
|
||||
+ uintptr_type state = __atomic_load_n (&(vl->version_lock), __ATOMIC_SEQ_CST);
|
||||
if (state & 1)
|
||||
return false;
|
||||
return __atomic_compare_exchange_n (&(vl->version_lock), &state, state | 1,
|
||||
@@ -78,7 +78,7 @@ restart:
|
||||
|
||||
// We should virtually never get contention here, as frame
|
||||
// changes are rare.
|
||||
- uintptr_t state = __atomic_load_n (&(vl->version_lock), __ATOMIC_SEQ_CST);
|
||||
+ uintptr_type state = __atomic_load_n (&(vl->version_lock), __ATOMIC_SEQ_CST);
|
||||
if (!(state & 1))
|
||||
{
|
||||
if (__atomic_compare_exchange_n (&(vl->version_lock), &state, state | 1,
|
||||
@@ -134,8 +134,8 @@ static void
|
||||
version_lock_unlock_exclusive (struct version_lock *vl)
|
||||
{
|
||||
// increase version, reset exclusive lock bits
|
||||
- uintptr_t state = __atomic_load_n (&(vl->version_lock), __ATOMIC_SEQ_CST);
|
||||
- uintptr_t ns = (state + 4) & (~((uintptr_t) 3));
|
||||
+ uintptr_type state = __atomic_load_n (&(vl->version_lock), __ATOMIC_SEQ_CST);
|
||||
+ uintptr_type ns = (state + 4) & (~((uintptr_type) 3));
|
||||
state = __atomic_exchange_n (&(vl->version_lock), ns, __ATOMIC_SEQ_CST);
|
||||
|
||||
#ifdef __GTHREAD_HAS_COND
|
||||
@@ -152,9 +152,9 @@ version_lock_unlock_exclusive (struct version_lock *vl)
|
||||
// Acquire an optimistic "lock". Note that this does not lock at all, it
|
||||
// only allows for validation later.
|
||||
static inline bool
|
||||
-version_lock_lock_optimistic (const struct version_lock *vl, uintptr_t *lock)
|
||||
+version_lock_lock_optimistic (const struct version_lock *vl, uintptr_type *lock)
|
||||
{
|
||||
- uintptr_t state = __atomic_load_n (&(vl->version_lock), __ATOMIC_SEQ_CST);
|
||||
+ uintptr_type state = __atomic_load_n (&(vl->version_lock), __ATOMIC_SEQ_CST);
|
||||
*lock = state;
|
||||
|
||||
// Acquiring the lock fails when there is currently an exclusive lock.
|
||||
@@ -163,7 +163,7 @@ version_lock_lock_optimistic (const struct version_lock *vl, uintptr_t *lock)
|
||||
|
||||
// Validate a previously acquired "lock".
|
||||
static inline bool
|
||||
-version_lock_validate (const struct version_lock *vl, uintptr_t lock)
|
||||
+version_lock_validate (const struct version_lock *vl, uintptr_type lock)
|
||||
{
|
||||
// Prevent the reordering of non-atomic loads behind the atomic load.
|
||||
// Hans Boehm, Can Seqlocks Get Along with Programming Language Memory
|
||||
@@ -171,26 +171,26 @@ version_lock_validate (const struct version_lock *vl, uintptr_t lock)
|
||||
__atomic_thread_fence (__ATOMIC_ACQUIRE);
|
||||
|
||||
// Check that the node is still in the same state.
|
||||
- uintptr_t state = __atomic_load_n (&(vl->version_lock), __ATOMIC_SEQ_CST);
|
||||
+ uintptr_type state = __atomic_load_n (&(vl->version_lock), __ATOMIC_SEQ_CST);
|
||||
return (state == lock);
|
||||
}
|
||||
|
||||
// The largest possible separator value.
|
||||
-static const uintptr_t max_separator = ~((uintptr_t) (0));
|
||||
+static const uintptr_type max_separator = ~((uintptr_type) (0));
|
||||
|
||||
struct btree_node;
|
||||
|
||||
// Inner entry. The child tree contains all entries <= separator.
|
||||
struct inner_entry
|
||||
{
|
||||
- uintptr_t separator;
|
||||
+ uintptr_type separator;
|
||||
struct btree_node *child;
|
||||
};
|
||||
|
||||
// Leaf entry. Stores an object entry.
|
||||
struct leaf_entry
|
||||
{
|
||||
- uintptr_t base, size;
|
||||
+ uintptr_type base, size;
|
||||
struct object *ob;
|
||||
};
|
||||
|
||||
@@ -248,7 +248,7 @@ btree_node_needs_merge (const struct btree_node *n)
|
||||
}
|
||||
|
||||
// Get the fence key for inner nodes.
|
||||
-static inline uintptr_t
|
||||
+static inline uintptr_type
|
||||
btree_node_get_fence_key (const struct btree_node *n)
|
||||
{
|
||||
// For inner nodes we just return our right-most entry.
|
||||
@@ -257,7 +257,7 @@ btree_node_get_fence_key (const struct btree_node *n)
|
||||
|
||||
// Find the position for a slot in an inner node.
|
||||
static unsigned
|
||||
-btree_node_find_inner_slot (const struct btree_node *n, uintptr_t value)
|
||||
+btree_node_find_inner_slot (const struct btree_node *n, uintptr_type value)
|
||||
{
|
||||
for (unsigned index = 0, ec = n->entry_count; index != ec; ++index)
|
||||
if (n->content.children[index].separator >= value)
|
||||
@@ -267,7 +267,7 @@ btree_node_find_inner_slot (const struct btree_node *n, uintptr_t value)
|
||||
|
||||
// Find the position for a slot in a leaf node.
|
||||
static unsigned
|
||||
-btree_node_find_leaf_slot (const struct btree_node *n, uintptr_t value)
|
||||
+btree_node_find_leaf_slot (const struct btree_node *n, uintptr_type value)
|
||||
{
|
||||
for (unsigned index = 0, ec = n->entry_count; index != ec; ++index)
|
||||
if (n->content.entries[index].base + n->content.entries[index].size > value)
|
||||
@@ -299,14 +299,14 @@ btree_node_unlock_exclusive (struct btree_node *n)
|
||||
// Acquire an optimistic "lock". Note that this does not lock at all, it
|
||||
// only allows for validation later.
|
||||
static inline bool
|
||||
-btree_node_lock_optimistic (const struct btree_node *n, uintptr_t *lock)
|
||||
+btree_node_lock_optimistic (const struct btree_node *n, uintptr_type *lock)
|
||||
{
|
||||
return version_lock_lock_optimistic (&(n->version_lock), lock);
|
||||
}
|
||||
|
||||
// Validate a previously acquire lock.
|
||||
static inline bool
|
||||
-btree_node_validate (const struct btree_node *n, uintptr_t lock)
|
||||
+btree_node_validate (const struct btree_node *n, uintptr_type lock)
|
||||
{
|
||||
return version_lock_validate (&(n->version_lock), lock);
|
||||
}
|
||||
@@ -314,8 +314,8 @@ btree_node_validate (const struct btree_node *n, uintptr_t lock)
|
||||
// Insert a new separator after splitting.
|
||||
static void
|
||||
btree_node_update_separator_after_split (struct btree_node *n,
|
||||
- uintptr_t old_separator,
|
||||
- uintptr_t new_separator,
|
||||
+ uintptr_type old_separator,
|
||||
+ uintptr_type new_separator,
|
||||
struct btree_node *new_right)
|
||||
{
|
||||
unsigned slot = btree_node_find_inner_slot (n, old_separator);
|
||||
@@ -474,13 +474,13 @@ btree_handle_root_split (struct btree *t, struct btree_node **node,
|
||||
// Split an inner node.
|
||||
static void
|
||||
btree_split_inner (struct btree *t, struct btree_node **inner,
|
||||
- struct btree_node **parent, uintptr_t target)
|
||||
+ struct btree_node **parent, uintptr_type target)
|
||||
{
|
||||
// Check for the root.
|
||||
btree_handle_root_split (t, inner, parent);
|
||||
|
||||
// Create two inner node.
|
||||
- uintptr_t right_fence = btree_node_get_fence_key (*inner);
|
||||
+ uintptr_type right_fence = btree_node_get_fence_key (*inner);
|
||||
struct btree_node *left_inner = *inner;
|
||||
struct btree_node *right_inner = btree_allocate_node (t, true);
|
||||
unsigned split = left_inner->entry_count / 2;
|
||||
@@ -489,7 +489,7 @@ btree_split_inner (struct btree *t, struct btree_node **inner,
|
||||
right_inner->content.children[index]
|
||||
= left_inner->content.children[split + index];
|
||||
left_inner->entry_count = split;
|
||||
- uintptr_t left_fence = btree_node_get_fence_key (left_inner);
|
||||
+ uintptr_type left_fence = btree_node_get_fence_key (left_inner);
|
||||
btree_node_update_separator_after_split (*parent, right_fence, left_fence,
|
||||
right_inner);
|
||||
if (target <= left_fence)
|
||||
@@ -507,13 +507,14 @@ btree_split_inner (struct btree *t, struct btree_node **inner,
|
||||
// Split a leaf node.
|
||||
static void
|
||||
btree_split_leaf (struct btree *t, struct btree_node **leaf,
|
||||
- struct btree_node **parent, uintptr_t fence, uintptr_t target)
|
||||
+ struct btree_node **parent, uintptr_type fence,
|
||||
+ uintptr_type target)
|
||||
{
|
||||
// Check for the root.
|
||||
btree_handle_root_split (t, leaf, parent);
|
||||
|
||||
// Create two leaf nodes.
|
||||
- uintptr_t right_fence = fence;
|
||||
+ uintptr_type right_fence = fence;
|
||||
struct btree_node *left_leaf = *leaf;
|
||||
struct btree_node *right_leaf = btree_allocate_node (t, false);
|
||||
unsigned split = left_leaf->entry_count / 2;
|
||||
@@ -522,7 +523,7 @@ btree_split_leaf (struct btree *t, struct btree_node **leaf,
|
||||
right_leaf->content.entries[index]
|
||||
= left_leaf->content.entries[split + index];
|
||||
left_leaf->entry_count = split;
|
||||
- uintptr_t left_fence = right_leaf->content.entries[0].base - 1;
|
||||
+ uintptr_type left_fence = right_leaf->content.entries[0].base - 1;
|
||||
btree_node_update_separator_after_split (*parent, right_fence, left_fence,
|
||||
right_leaf);
|
||||
if (target <= left_fence)
|
||||
@@ -540,7 +541,7 @@ btree_split_leaf (struct btree *t, struct btree_node **leaf,
|
||||
// Merge (or balance) child nodes.
|
||||
static struct btree_node *
|
||||
btree_merge_node (struct btree *t, unsigned child_slot,
|
||||
- struct btree_node *parent, uintptr_t target)
|
||||
+ struct btree_node *parent, uintptr_type target)
|
||||
{
|
||||
// Choose the emptiest neighbor and lock both. The target child is already
|
||||
// locked.
|
||||
@@ -693,7 +694,7 @@ btree_merge_node (struct btree *t, unsigned child_slot,
|
||||
left_node->entry_count += to_shift;
|
||||
right_node->entry_count -= to_shift;
|
||||
}
|
||||
- uintptr_t left_fence;
|
||||
+ uintptr_type left_fence;
|
||||
if (btree_node_is_leaf (left_node))
|
||||
{
|
||||
left_fence = right_node->content.entries[0].base - 1;
|
||||
@@ -718,7 +719,7 @@ btree_merge_node (struct btree *t, unsigned child_slot,
|
||||
|
||||
// Insert an entry.
|
||||
static bool
|
||||
-btree_insert (struct btree *t, uintptr_t base, uintptr_t size,
|
||||
+btree_insert (struct btree *t, uintptr_type base, uintptr_type size,
|
||||
struct object *ob)
|
||||
{
|
||||
// Sanity check.
|
||||
@@ -747,7 +748,7 @@ btree_insert (struct btree *t, uintptr_t base, uintptr_t size,
|
||||
// But that is more difficult to implement and frame registration is
|
||||
// rare anyway, we use simple locking for now.
|
||||
|
||||
- uintptr_t fence = max_separator;
|
||||
+ uintptr_type fence = max_separator;
|
||||
while (btree_node_is_inner (iter))
|
||||
{
|
||||
// Use eager splits to avoid lock coupling up.
|
||||
@@ -790,7 +791,7 @@ btree_insert (struct btree *t, uintptr_t base, uintptr_t size,
|
||||
|
||||
// Remove an entry.
|
||||
static struct object *
|
||||
-btree_remove (struct btree *t, uintptr_t base)
|
||||
+btree_remove (struct btree *t, uintptr_type base)
|
||||
{
|
||||
// Access the root.
|
||||
version_lock_lock_exclusive (&(t->root_lock));
|
||||
@@ -838,7 +839,7 @@ btree_remove (struct btree *t, uintptr_t base)
|
||||
|
||||
// Find the corresponding entry for the given address.
|
||||
static struct object *
|
||||
-btree_lookup (const struct btree *t, uintptr_t target_addr)
|
||||
+btree_lookup (const struct btree *t, uintptr_type target_addr)
|
||||
{
|
||||
// Within this function many loads are relaxed atomic loads.
|
||||
// Use a macro to keep the code reasonable.
|
||||
@@ -867,7 +868,7 @@ btree_lookup (const struct btree *t, uintptr_t target_addr)
|
||||
|
||||
restart:
|
||||
struct btree_node *iter;
|
||||
- uintptr_t lock;
|
||||
+ uintptr_type lock;
|
||||
{
|
||||
// Accessing the root node requires defending against concurrent pointer
|
||||
// changes Thus we couple rootLock -> lock on root node -> validate rootLock
|
||||
@@ -878,7 +879,7 @@ restart:
|
||||
goto restart;
|
||||
if (!iter)
|
||||
return NULL;
|
||||
- uintptr_t child_lock;
|
||||
+ uintptr_type child_lock;
|
||||
if ((!btree_node_lock_optimistic (iter, &child_lock))
|
||||
|| (!version_lock_validate (&(t->root_lock), lock)))
|
||||
goto restart;
|
||||
@@ -910,7 +911,7 @@ restart:
|
||||
|
||||
// The node content can change at any point in time, thus we must
|
||||
// interleave parent and child checks.
|
||||
- uintptr_t child_lock;
|
||||
+ uintptr_type child_lock;
|
||||
if (!btree_node_lock_optimistic (child, &child_lock))
|
||||
goto restart;
|
||||
if (!btree_node_validate (iter, lock))
|
||||
diff --git a/libgcc/unwind-dw2-fde.c b/libgcc/unwind-dw2-fde.c
|
||||
index a591faaa579b5883..f38efd3c09efc3e9 100644
|
||||
--- a/libgcc/unwind-dw2-fde.c
|
||||
+++ b/libgcc/unwind-dw2-fde.c
|
||||
@@ -42,6 +42,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+typedef __UINTPTR_TYPE__ uintptr_type;
|
||||
+
|
||||
#ifdef ATOMIC_FDE_FAST_PATH
|
||||
#include "unwind-dw2-btree.h"
|
||||
|
||||
@@ -58,7 +60,7 @@ release_registered_frames (void)
|
||||
}
|
||||
|
||||
static void
|
||||
-get_pc_range (const struct object *ob, uintptr_t *range);
|
||||
+get_pc_range (const struct object *ob, uintptr_type *range);
|
||||
static void
|
||||
init_object (struct object *ob);
|
||||
|
||||
@@ -124,7 +126,7 @@ __register_frame_info_bases (const void *begin, struct object *ob,
|
||||
init_object (ob);
|
||||
|
||||
// And register the frame
|
||||
- uintptr_t range[2];
|
||||
+ uintptr_type range[2];
|
||||
get_pc_range (ob, range);
|
||||
btree_insert (®istered_frames, range[0], range[1] - range[0], ob);
|
||||
#else
|
||||
@@ -178,7 +180,7 @@ __register_frame_info_table_bases (void *begin, struct object *ob,
|
||||
init_object (ob);
|
||||
|
||||
// And register the frame
|
||||
- uintptr_t range[2];
|
||||
+ uintptr_type range[2];
|
||||
get_pc_range (ob, range);
|
||||
btree_insert (®istered_frames, range[0], range[1] - range[0], ob);
|
||||
#else
|
||||
@@ -237,7 +239,7 @@ __deregister_frame_info_bases (const void *begin)
|
||||
#ifdef DWARF2_OBJECT_END_PTR_EXTENSION
|
||||
lookupob.fde_end = NULL;
|
||||
#endif
|
||||
- uintptr_t range[2];
|
||||
+ uintptr_type range[2];
|
||||
get_pc_range (&lookupob, range);
|
||||
|
||||
// And remove
|
||||
@@ -677,7 +679,7 @@ end_fde_sort (struct object *ob, struct fde_accumulator *accu, size_t count)
|
||||
|
||||
static size_t
|
||||
classify_object_over_fdes (struct object *ob, const fde *this_fde,
|
||||
- uintptr_t *range)
|
||||
+ uintptr_type *range)
|
||||
{
|
||||
const struct dwarf_cie *last_cie = 0;
|
||||
size_t count = 0;
|
||||
@@ -892,11 +894,11 @@ init_object (struct object* ob)
|
||||
#ifdef ATOMIC_FDE_FAST_PATH
|
||||
/* Get the PC range for lookup */
|
||||
static void
|
||||
-get_pc_range (const struct object *ob, uintptr_t *range)
|
||||
+get_pc_range (const struct object *ob, uintptr_type *range)
|
||||
{
|
||||
// It is safe to cast to non-const object* here as
|
||||
// classify_object_over_fdes does not modify ob in query mode.
|
||||
- struct object *ncob = (struct object *) (uintptr_t) ob;
|
||||
+ struct object *ncob = (struct object *) (uintptr_type) ob;
|
||||
range[0] = range[1] = 0;
|
||||
if (ob->s.b.sorted)
|
||||
{
|
||||
@@ -1131,7 +1133,7 @@ _Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases)
|
||||
const fde *f = NULL;
|
||||
|
||||
#ifdef ATOMIC_FDE_FAST_PATH
|
||||
- ob = btree_lookup (®istered_frames, (uintptr_t) pc);
|
||||
+ ob = btree_lookup (®istered_frames, (uintptr_type) pc);
|
||||
if (!ob)
|
||||
return NULL;
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
commit 190c644c06369766aa2537851ddbf83b1231b65b
|
||||
Author: Philipp Fent <fent@in.tum.de>
|
||||
Date: Sun Sep 4 20:47:34 2022 +0200
|
||||
|
||||
libstdc++: Fix pretty printer tests of tuple indexes
|
||||
|
||||
Signed-off-by: Philipp Fent <fent@in.tum.de>
|
||||
|
||||
libstdc++-v3/ChangeLog:
|
||||
|
||||
* testsuite/libstdc++-prettyprinters/48362.cc: Fix expected
|
||||
tuple indices.
|
||||
* testsuite/libstdc++-prettyprinters/cxx11.cc: Likewise.
|
||||
|
||||
diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/48362.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/48362.cc
|
||||
index cc91803e247..af335d0d3c7 100644
|
||||
--- a/libstdc++-v3/testsuite/libstdc++-prettyprinters/48362.cc
|
||||
+++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/48362.cc
|
||||
@@ -29,7 +29,7 @@ main()
|
||||
// { dg-final { note-test t1 {empty std::tuple} } }
|
||||
|
||||
std::tuple<std::string, int, std::tuple<>> t2{ "Johnny", 5, {} };
|
||||
-// { dg-final { regexp-test t2 {std::tuple containing = {\[1\] = "Johnny", \[2\] = 5, \[3\] = empty std::tuple}} } }
|
||||
+// { dg-final { regexp-test t2 {std::tuple containing = {\[0\] = "Johnny", \[1\] = 5, \[2\] = empty std::tuple}} } }
|
||||
|
||||
std::cout << "\n";
|
||||
return 0; // Mark SPOT
|
||||
270
SOURCES/gcc11-libstdc++-prettyprinter-update-15-tests.patch
Normal file
270
SOURCES/gcc11-libstdc++-prettyprinter-update-15-tests.patch
Normal file
@ -0,0 +1,270 @@
|
||||
.../testsuite/libstdc++-prettyprinters/compat.cc | 10 +++----
|
||||
.../testsuite/libstdc++-prettyprinters/cxx11.cc | 33 +++++++++++++++++-----
|
||||
.../testsuite/libstdc++-prettyprinters/cxx17.cc | 27 ++++++++----------
|
||||
.../libstdc++-prettyprinters/filesystem-ts.cc | 2 +-
|
||||
.../libstdc++-prettyprinters/libfundts.cc | 25 ++++++++--------
|
||||
5 files changed, 58 insertions(+), 39 deletions(-)
|
||||
|
||||
diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/compat.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/compat.cc
|
||||
index 35243e5f892..2ef5979834f 100644
|
||||
--- a/libstdc++-v3/testsuite/libstdc++-prettyprinters/compat.cc
|
||||
+++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/compat.cc
|
||||
@@ -1,7 +1,7 @@
|
||||
// { dg-options "-g -O0" }
|
||||
// { dg-do run { target c++11 } }
|
||||
|
||||
-// Copyright (C) 2014-2021 Free Software Foundation, Inc.
|
||||
+// Copyright (C) 2014-2025 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
@@ -102,13 +102,13 @@ main()
|
||||
using std::optional;
|
||||
|
||||
optional<int> o;
|
||||
-// { dg-final { note-test o {std::optional<int> [no contained value]} } }
|
||||
+// { dg-final { note-test o {std::optional [no contained value]} } }
|
||||
optional<bool> ob{false};
|
||||
-// { dg-final { note-test ob {std::optional<bool> = {[contained value] = false}} } }
|
||||
+// { dg-final { note-test ob {std::optional = {[contained value] = false}} } }
|
||||
optional<int> oi{5};
|
||||
-// { dg-final { note-test oi {std::optional<int> = {[contained value] = 5}} } }
|
||||
+// { dg-final { note-test oi {std::optional = {[contained value] = 5}} } }
|
||||
optional<void*> op{nullptr};
|
||||
-// { dg-final { note-test op {std::optional<void *> = {[contained value] = 0x0}} } }
|
||||
+// { dg-final { note-test op {std::optional = {[contained value] = 0x0}} } }
|
||||
|
||||
__builtin_puts("");
|
||||
return 0; // Mark SPOT
|
||||
diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/cxx11.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/cxx11.cc
|
||||
index 0545076fb6f..23f6d97ddd4 100644
|
||||
--- a/libstdc++-v3/testsuite/libstdc++-prettyprinters/cxx11.cc
|
||||
+++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/cxx11.cc
|
||||
@@ -1,7 +1,7 @@
|
||||
// { dg-do run { target c++11 } }
|
||||
// { dg-options "-g -O0" }
|
||||
|
||||
-// Copyright (C) 2011-2021 Free Software Foundation, Inc.
|
||||
+// Copyright (C) 2011-2025 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <iostream>
|
||||
#include <future>
|
||||
#include <initializer_list>
|
||||
+#include <atomic>
|
||||
#include "../util/testsuite_allocator.h" // NullablePointer
|
||||
|
||||
typedef std::tuple<int, int> ExTuple;
|
||||
@@ -62,6 +63,11 @@ struct datum
|
||||
|
||||
std::unique_ptr<datum> global;
|
||||
|
||||
+struct custom_cat : std::error_category {
|
||||
+ const char* name() const noexcept { return "miaow"; }
|
||||
+ std::string message(int) const { return ""; }
|
||||
+};
|
||||
+
|
||||
int
|
||||
main()
|
||||
{
|
||||
@@ -165,9 +171,9 @@ main()
|
||||
// { dg-final { note-test runiq_ptr {std::unique_ptr<int> = {get() = 0x0}} } }
|
||||
|
||||
ExTuple tpl(6,7);
|
||||
-// { dg-final { note-test tpl {std::tuple containing = {[1] = 6, [2] = 7}} } }
|
||||
+// { dg-final { note-test tpl {std::tuple containing = {[0] = 6, [1] = 7}} } }
|
||||
ExTuple &rtpl = tpl;
|
||||
-// { dg-final { note-test rtpl {std::tuple containing = {[1] = 6, [2] = 7}} } }
|
||||
+// { dg-final { note-test rtpl {std::tuple containing = {[0] = 6, [1] = 7}} } }
|
||||
|
||||
std::error_code e0;
|
||||
// { dg-final { note-test e0 {std::error_code = { }} } }
|
||||
@@ -178,10 +184,7 @@ main()
|
||||
std::error_condition ecinval = std::make_error_condition(std::errc::invalid_argument);
|
||||
// { dg-final { note-test ecinval {std::error_condition = {"generic": EINVAL}} } }
|
||||
|
||||
- struct custom_cat : std::error_category {
|
||||
- const char* name() const noexcept { return "miaow"; }
|
||||
- std::string message(int) const { return ""; }
|
||||
- } cat;
|
||||
+ custom_cat cat;
|
||||
std::error_code emiaow(42, cat);
|
||||
// { dg-final { note-test emiaow {std::error_code = {custom_cat: 42}} } }
|
||||
std::error_condition ecmiaow(42, cat);
|
||||
@@ -197,6 +200,22 @@ main()
|
||||
std::initializer_list<int> il = {3, 4};
|
||||
// { dg-final { note-test il {std::initializer_list of length 2 = {3, 4}} } }
|
||||
|
||||
+ std::atomic<int> ai{100};
|
||||
+ // { dg-final { note-test ai {std::atomic<int> = { 100 }} } }
|
||||
+ long l{};
|
||||
+ std::atomic<long*> ap{&l};
|
||||
+ // { dg-final { regexp-test ap {std::atomic.long \*. = { 0x.* }} } }
|
||||
+ struct Value { int i, j; };
|
||||
+ std::atomic<Value> av{{8, 9}};
|
||||
+ // { dg-final { note-test av {std::atomic<Value> = { {i = 8, j = 9} }} } }
|
||||
+
|
||||
+ std::integral_constant<int, 1> one;
|
||||
+ // { dg-final { note-test one {std::integral_constant<int, 1>} } }
|
||||
+ std::integral_constant<bool, true> truth;
|
||||
+ // { dg-final { note-test truth {std::true_type} } }
|
||||
+ std::integral_constant<bool, 0> lies;
|
||||
+ // { dg-final { note-test lies {std::false_type} } }
|
||||
+
|
||||
placeholder(""); // Mark SPOT
|
||||
use(efl);
|
||||
use(fl);
|
||||
diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/cxx17.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/cxx17.cc
|
||||
index 72c66d3b785..6dd2b60c0a5 100644
|
||||
--- a/libstdc++-v3/testsuite/libstdc++-prettyprinters/cxx17.cc
|
||||
+++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/cxx17.cc
|
||||
@@ -1,7 +1,7 @@
|
||||
// { dg-options "-g -O0" }
|
||||
// { dg-do run { target c++17 } }
|
||||
|
||||
-// Copyright (C) 2014-2021 Free Software Foundation, Inc.
|
||||
+// Copyright (C) 2014-2025 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
@@ -18,9 +18,6 @@
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
-// Type printers only recognize the old std::string for now.
|
||||
-#define _GLIBCXX_USE_CXX11_ABI 0
|
||||
-
|
||||
#include <filesystem>
|
||||
#include <any>
|
||||
#include <optional>
|
||||
@@ -53,18 +50,18 @@ main()
|
||||
// { dg-final { note-test str "\"string\"" } }
|
||||
|
||||
optional<int> o;
|
||||
-// { dg-final { note-test o {std::optional<int> [no contained value]} } }
|
||||
+// { dg-final { note-test o {std::optional [no contained value]} } }
|
||||
optional<bool> ob{false};
|
||||
-// { dg-final { note-test ob {std::optional<bool> = {[contained value] = false}} } }
|
||||
+// { dg-final { note-test ob {std::optional = {[contained value] = false}} } }
|
||||
optional<int> oi{5};
|
||||
-// { dg-final { note-test oi {std::optional<int> = {[contained value] = 5}} } }
|
||||
+// { dg-final { note-test oi {std::optional = {[contained value] = 5}} } }
|
||||
optional<void*> op{nullptr};
|
||||
-// { dg-final { note-test op {std::optional<void *> = {[contained value] = 0x0}} } }
|
||||
+// { dg-final { note-test op {std::optional = {[contained value] = 0x0}} } }
|
||||
optional<std::map<int, double>> om;
|
||||
om = std::map<int, double>{ {1, 2.}, {3, 4.}, {5, 6.} };
|
||||
-// { dg-final { regexp-test om {std::optional<std::(__debug::)?map<int, double>> containing std::(__debug::)?map with 3 elements = {\[1\] = 2, \[3\] = 4, \[5\] = 6}} } }
|
||||
+// { dg-final { regexp-test om {std::optional containing std::(__debug::)?map with 3 elements = {\[1\] = 2, \[3\] = 4, \[5\] = 6}} } }
|
||||
optional<std::string> os{ "stringy" };
|
||||
-// { dg-final { note-test os {std::optional<std::string> = {[contained value] = "stringy"}} } }
|
||||
+// { dg-final { note-test os {std::optional = {[contained value] = "stringy"}} } }
|
||||
|
||||
any a;
|
||||
// { dg-final { note-test a {std::any [no contained value]} } }
|
||||
@@ -86,18 +83,18 @@ main()
|
||||
|
||||
struct S { operator int() { throw 42; }};
|
||||
variant<float, int, string_view> v0;
|
||||
-// { dg-final { note-test v0 {std::variant<float, int, std::string_view> [index 0] = {0}} } }
|
||||
+// { dg-final { note-test v0 {std::variant [index 0] = {0}} } }
|
||||
variant<float, int, string_view> v1{ 0.5f };
|
||||
-// { dg-final { note-test v1 {std::variant<float, int, std::string_view> [index 0] = {0.5}} } }
|
||||
+// { dg-final { note-test v1 {std::variant [index 0] = {0.5}} } }
|
||||
variant<float, X, string_view> v2;
|
||||
try {
|
||||
v2.emplace<1>(S());
|
||||
} catch (int) { }
|
||||
-// { dg-final { note-test v2 {std::variant<float, X, std::string_view> [no contained value]} } }
|
||||
+// { dg-final { note-test v2 {std::variant [no contained value]} } }
|
||||
variant<float, int, string_view> v3{ 3 };
|
||||
-// { dg-final { note-test v3 {std::variant<float, int, std::string_view> [index 1] = {3}} } }
|
||||
+// { dg-final { note-test v3 {std::variant [index 1] = {3}} } }
|
||||
variant<float, int, string_view> v4{ str };
|
||||
-// { dg-final { note-test v4 {std::variant<float, int, std::string_view> [index 2] = {"string"}} } }
|
||||
+// { dg-final { note-test v4 {std::variant [index 2] = {"string"}} } }
|
||||
|
||||
map<int, string_view> m{ {1, "one"} };
|
||||
map<int, string_view>::node_type n0;
|
||||
diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/filesystem-ts.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/filesystem-ts.cc
|
||||
index 00d100bd066..3221f2df90d 100644
|
||||
--- a/libstdc++-v3/testsuite/libstdc++-prettyprinters/filesystem-ts.cc
|
||||
+++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/filesystem-ts.cc
|
||||
@@ -2,7 +2,7 @@
|
||||
// { dg-do run { target c++11 } }
|
||||
// { dg-require-filesystem-ts "" }
|
||||
|
||||
-// Copyright (C) 2020-2021 Free Software Foundation, Inc.
|
||||
+// Copyright (C) 2020-2025 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/libfundts.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/libfundts.cc
|
||||
index 85005c0617f..bfb86885457 100644
|
||||
--- a/libstdc++-v3/testsuite/libstdc++-prettyprinters/libfundts.cc
|
||||
+++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/libfundts.cc
|
||||
@@ -1,7 +1,7 @@
|
||||
// { dg-do run { target c++14 } }
|
||||
// { dg-options "-g -O0" }
|
||||
|
||||
-// Copyright (C) 2014-2021 Free Software Foundation, Inc.
|
||||
+// Copyright (C) 2014-2025 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
@@ -18,9 +18,6 @@
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
-// Type printers only recognize the old std::string for now.
|
||||
-#define _GLIBCXX_USE_CXX11_ABI 0
|
||||
-
|
||||
#include <experimental/any>
|
||||
#include <experimental/optional>
|
||||
#include <experimental/string_view>
|
||||
@@ -35,22 +32,28 @@ using std::experimental::string_view;
|
||||
int
|
||||
main()
|
||||
{
|
||||
+ // Ensure debug info for std::string is issued in the local
|
||||
+ // translation unit, so that GDB won't pick up any alternate
|
||||
+ // std::string notion that might be present in libstdc++.so.
|
||||
+ std::string bah = "hi";
|
||||
+ (void)bah;
|
||||
+
|
||||
string_view str = "string";
|
||||
// { dg-final { note-test str "\"string\"" } }
|
||||
|
||||
optional<int> o;
|
||||
-// { dg-final { note-test o {std::experimental::optional<int> [no contained value]} } }
|
||||
+// { dg-final { note-test o {std::experimental::optional [no contained value]} } }
|
||||
optional<bool> ob{false};
|
||||
-// { dg-final { note-test ob {std::experimental::optional<bool> = {[contained value] = false}} } }
|
||||
+// { dg-final { note-test ob {std::experimental::optional = {[contained value] = false}} } }
|
||||
optional<int> oi{5};
|
||||
-// { dg-final { note-test oi {std::experimental::optional<int> = {[contained value] = 5}} } }
|
||||
+// { dg-final { note-test oi {std::experimental::optional = {[contained value] = 5}} } }
|
||||
optional<void*> op{nullptr};
|
||||
-// { dg-final { note-test op {std::experimental::optional<void *> = {[contained value] = 0x0}} } }
|
||||
+// { dg-final { note-test op {std::experimental::optional = {[contained value] = 0x0}} } }
|
||||
optional<std::map<int, double>> om;
|
||||
om = std::map<int, double>{ {1, 2.}, {3, 4.}, {5, 6.} };
|
||||
-// { dg-final { regexp-test om {std::experimental::optional<std::(__debug::)?map<int, double>> containing std::(__debug::)?map with 3 elements = {\[1\] = 2, \[3\] = 4, \[5\] = 6}} } }
|
||||
+// { dg-final { regexp-test om {std::experimental::optional containing std::(__debug::)?map with 3 elements = {\[1\] = 2, \[3\] = 4, \[5\] = 6}} } }
|
||||
optional<std::string> os{ "stringy" };
|
||||
-// { dg-final { note-test os {std::experimental::optional<std::string> = {[contained value] = "stringy"}} { xfail { c++20 || debug_mode } } } }
|
||||
+// { dg-final { note-test os {std::experimental::optional = {[contained value] = "stringy"}} } }
|
||||
|
||||
any a;
|
||||
// { dg-final { note-test a {std::experimental::any [no contained value]} } }
|
||||
@@ -61,7 +64,7 @@ main()
|
||||
any ap = (void*)nullptr;
|
||||
// { dg-final { note-test ap {std::experimental::any containing void * = {[contained value] = 0x0}} } }
|
||||
any as = *os;
|
||||
-// { dg-final { note-test as {std::experimental::any containing std::string = {[contained value] = "stringy"}} { xfail { c++20 || debug_mode } } } }
|
||||
+// { dg-final { note-test as {std::experimental::any containing std::string = {[contained value] = "stringy"}} } }
|
||||
any as2("stringiest");
|
||||
// { dg-final { regexp-test as2 {std::experimental::any containing const char \* = {\[contained value\] = 0x[[:xdigit:]]+ "stringiest"}} } }
|
||||
any am = *om;
|
||||
4066
SOURCES/gcc11-libstdc++-prettyprinter-update-15.patch
Normal file
4066
SOURCES/gcc11-libstdc++-prettyprinter-update-15.patch
Normal file
File diff suppressed because it is too large
Load Diff
64
SOURCES/gcc11-pr118976.patch
Normal file
64
SOURCES/gcc11-pr118976.patch
Normal file
@ -0,0 +1,64 @@
|
||||
Original patch (taken from GCC 12 branch version) edited for GCC 11 to
|
||||
use .c rather than .cc filenames.
|
||||
|
||||
commit 587b370c8492aadaab14c57e242c66778cc78891
|
||||
Author: Richard Sandiford <richard.sandiford@arm.com>
|
||||
Date: Tue Mar 11 15:51:55 2025 +0000
|
||||
|
||||
Fix folding of BIT_NOT_EXPR for POLY_INT_CST [PR118976]
|
||||
|
||||
There was an embarrassing typo in the folding of BIT_NOT_EXPR for
|
||||
POLY_INT_CSTs: it used - rather than ~ on the poly_int. Not sure
|
||||
how that happened, but it might have been due to the way that
|
||||
~x is implemented as -1 - x internally.
|
||||
|
||||
gcc/
|
||||
PR tree-optimization/118976
|
||||
* fold-const.cc (const_unop): Use ~ rather than - for BIT_NOT_EXPR.
|
||||
* config/aarch64/aarch64.cc (aarch64_test_sve_folding): New function.
|
||||
(aarch64_run_selftests): Run it.
|
||||
|
||||
(cherry picked from commit 78380fd7f743e23dfdf013d68a2f0347e1511550)
|
||||
|
||||
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
|
||||
index be0d958dcf6b..72d737d62228 100644
|
||||
--- a/gcc/config/aarch64/aarch64.c
|
||||
+++ b/gcc/config/aarch64/aarch64.c
|
||||
@@ -27541,6 +27541,16 @@ aarch64_test_fractional_cost ()
|
||||
ASSERT_EQ (cf (1, 2).as_double (), 0.5);
|
||||
}
|
||||
|
||||
+/* Test SVE arithmetic folding. */
|
||||
+
|
||||
+static void
|
||||
+aarch64_test_sve_folding ()
|
||||
+{
|
||||
+ tree res = fold_unary (BIT_NOT_EXPR, ssizetype,
|
||||
+ ssize_int (poly_int64 (1, 1)));
|
||||
+ ASSERT_TRUE (operand_equal_p (res, ssize_int (poly_int64 (-2, -1))));
|
||||
+}
|
||||
+
|
||||
/* Run all target-specific selftests. */
|
||||
|
||||
static void
|
||||
@@ -27548,6 +27558,7 @@ aarch64_run_selftests (void)
|
||||
{
|
||||
aarch64_test_loading_full_dump ();
|
||||
aarch64_test_fractional_cost ();
|
||||
+ aarch64_test_sve_folding ();
|
||||
}
|
||||
|
||||
} // namespace selftest
|
||||
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
|
||||
index d81a71c41a17..391f11095408 100644
|
||||
--- a/gcc/fold-const.c
|
||||
+++ b/gcc/fold-const.c
|
||||
@@ -1802,7 +1802,7 @@ const_unop (enum tree_code code, tree type, tree arg0)
|
||||
if (TREE_CODE (arg0) == INTEGER_CST)
|
||||
return fold_not_const (arg0, type);
|
||||
else if (POLY_INT_CST_P (arg0))
|
||||
- return wide_int_to_tree (type, -poly_int_cst_value (arg0));
|
||||
+ return wide_int_to_tree (type, ~poly_int_cst_value (arg0));
|
||||
/* Perform BIT_NOT_EXPR on each element individually. */
|
||||
else if (TREE_CODE (arg0) == VECTOR_CST)
|
||||
{
|
||||
403
SOURCES/gcc11-pr99888.patch
Normal file
403
SOURCES/gcc11-pr99888.patch
Normal file
@ -0,0 +1,403 @@
|
||||
From c23b5006d3ffeda1a9edf5fd817765a6da3696ca Mon Sep 17 00:00:00 2001
|
||||
From: Kewen Lin <linkw@linux.ibm.com>
|
||||
Date: Fri, 30 Sep 2022 07:16:49 -0500
|
||||
Subject: [PATCH] rs6000: Rework ELFv2 support for -fpatchable-function-entry*
|
||||
[PR99888]
|
||||
|
||||
As PR99888 and its related show, the current support for
|
||||
-fpatchable-function-entry on powerpc ELFv2 doesn't work
|
||||
well with global entry existence. For example, with one
|
||||
command line option -fpatchable-function-entry=3,2, it got
|
||||
below w/o this patch:
|
||||
|
||||
.LPFE1:
|
||||
nop
|
||||
nop
|
||||
.type foo, @function
|
||||
foo:
|
||||
nop
|
||||
.LFB0:
|
||||
.cfi_startproc
|
||||
.LCF0:
|
||||
0: addis 2,12,.TOC.-.LCF0@ha
|
||||
addi 2,2,.TOC.-.LCF0@l
|
||||
.localentry foo,.-foo
|
||||
|
||||
, the assembly is unexpected since the patched nops have
|
||||
no effects when being entered from local entry.
|
||||
|
||||
This patch is to update the nops patched before and after
|
||||
local entry, it looks like:
|
||||
|
||||
.type foo, @function
|
||||
foo:
|
||||
.LFB0:
|
||||
.cfi_startproc
|
||||
.LCF0:
|
||||
0: addis 2,12,.TOC.-.LCF0@ha
|
||||
addi 2,2,.TOC.-.LCF0@l
|
||||
nop
|
||||
nop
|
||||
.localentry foo,.-foo
|
||||
nop
|
||||
|
||||
PR target/99888
|
||||
PR target/105649
|
||||
|
||||
Backported to GCC 11: renamed source files from .cc back to .c
|
||||
|
||||
gcc/ChangeLog:
|
||||
|
||||
* doc/invoke.texi (option -fpatchable-function-entry): Adjust the
|
||||
documentation for PowerPC ELFv2 ABI dual entry points.
|
||||
* config/rs6000/rs6000-internal.h
|
||||
(rs6000_print_patchable_function_entry): New function declaration.
|
||||
* config/rs6000/rs6000-logue.c (rs6000_output_function_prologue):
|
||||
Support patchable-function-entry by emitting nops before and after
|
||||
local entry for the function that needs global entry.
|
||||
* config/rs6000/rs6000.c (rs6000_print_patchable_function_entry): Skip
|
||||
the function that needs global entry till global entry has been
|
||||
emitted.
|
||||
* config/rs6000/rs6000.h (struct machine_function): New bool member
|
||||
global_entry_emitted.
|
||||
|
||||
gcc/testsuite/ChangeLog:
|
||||
|
||||
* gcc.target/powerpc/pr99888-1.c: New test.
|
||||
* gcc.target/powerpc/pr99888-2.c: New test.
|
||||
* gcc.target/powerpc/pr99888-3.c: New test.
|
||||
* gcc.target/powerpc/pr99888-4.c: New test.
|
||||
* gcc.target/powerpc/pr99888-5.c: New test.
|
||||
* gcc.target/powerpc/pr99888-6.c: New test.
|
||||
* c-c++-common/patchable_function_entry-default.c: Adjust for
|
||||
powerpc_elfv2 to avoid compilation error.
|
||||
---
|
||||
gcc/config/rs6000/rs6000-internal.h | 4 ++
|
||||
gcc/config/rs6000/rs6000-logue.c | 32 ++++++++++++++
|
||||
gcc/config/rs6000/rs6000.c | 10 ++++-
|
||||
gcc/config/rs6000/rs6000.h | 4 ++
|
||||
gcc/doc/invoke.texi | 8 +++-
|
||||
.../patchable_function_entry-default.c | 3 ++
|
||||
gcc/testsuite/gcc.target/powerpc/pr99888-1.c | 43 +++++++++++++++++++
|
||||
gcc/testsuite/gcc.target/powerpc/pr99888-2.c | 43 +++++++++++++++++++
|
||||
gcc/testsuite/gcc.target/powerpc/pr99888-3.c | 11 +++++
|
||||
gcc/testsuite/gcc.target/powerpc/pr99888-4.c | 13 ++++++
|
||||
gcc/testsuite/gcc.target/powerpc/pr99888-5.c | 13 ++++++
|
||||
gcc/testsuite/gcc.target/powerpc/pr99888-6.c | 14 ++++++
|
||||
12 files changed, 194 insertions(+), 4 deletions(-)
|
||||
create mode 100644 gcc/testsuite/gcc.target/powerpc/pr99888-1.c
|
||||
create mode 100644 gcc/testsuite/gcc.target/powerpc/pr99888-2.c
|
||||
create mode 100644 gcc/testsuite/gcc.target/powerpc/pr99888-3.c
|
||||
create mode 100644 gcc/testsuite/gcc.target/powerpc/pr99888-4.c
|
||||
create mode 100644 gcc/testsuite/gcc.target/powerpc/pr99888-5.c
|
||||
create mode 100644 gcc/testsuite/gcc.target/powerpc/pr99888-6.c
|
||||
|
||||
diff --git a/gcc/config/rs6000/rs6000-internal.h b/gcc/config/rs6000/rs6000-internal.h
|
||||
index b9e82c0468d0..e75b8d5c7e88 100644
|
||||
--- a/gcc/config/rs6000/rs6000-internal.h
|
||||
+++ b/gcc/config/rs6000/rs6000-internal.h
|
||||
@@ -182,6 +182,10 @@ extern tree rs6000_fold_builtin (tree fndecl ATTRIBUTE_UNUSED,
|
||||
tree *args ATTRIBUTE_UNUSED,
|
||||
bool ignore ATTRIBUTE_UNUSED);
|
||||
|
||||
+extern void rs6000_print_patchable_function_entry (FILE *,
|
||||
+ unsigned HOST_WIDE_INT,
|
||||
+ bool);
|
||||
+
|
||||
extern bool rs6000_passes_float;
|
||||
extern bool rs6000_passes_long_double;
|
||||
extern bool rs6000_passes_vector;
|
||||
diff --git a/gcc/config/rs6000/rs6000-logue.c b/gcc/config/rs6000/rs6000-logue.c
|
||||
index a11d020ccd0c..3621cb501c70 100644
|
||||
--- a/gcc/config/rs6000/rs6000-logue.c
|
||||
+++ b/gcc/config/rs6000/rs6000-logue.c
|
||||
@@ -4009,11 +4009,43 @@ rs6000_output_function_prologue (FILE *file)
|
||||
fprintf (file, "\tadd 2,2,12\n");
|
||||
}
|
||||
|
||||
+ unsigned short patch_area_size = crtl->patch_area_size;
|
||||
+ unsigned short patch_area_entry = crtl->patch_area_entry;
|
||||
+ /* Need to emit the patching area. */
|
||||
+ if (patch_area_size > 0)
|
||||
+ {
|
||||
+ cfun->machine->global_entry_emitted = true;
|
||||
+ /* As ELFv2 ABI shows, the allowable bytes between the global
|
||||
+ and local entry points are 0, 4, 8, 16, 32 and 64 when
|
||||
+ there is a local entry point. Considering there are two
|
||||
+ non-prefixed instructions for global entry point prologue
|
||||
+ (8 bytes), the count for patchable nops before local entry
|
||||
+ point would be 2, 6 and 14. It's possible to support those
|
||||
+ other counts of nops by not making a local entry point, but
|
||||
+ we don't have clear use cases for them, so leave them
|
||||
+ unsupported for now. */
|
||||
+ if (patch_area_entry > 0)
|
||||
+ {
|
||||
+ if (patch_area_entry != 2
|
||||
+ && patch_area_entry != 6
|
||||
+ && patch_area_entry != 14)
|
||||
+ error ("unsupported number of nops before function entry (%u)",
|
||||
+ patch_area_entry);
|
||||
+ rs6000_print_patchable_function_entry (file, patch_area_entry,
|
||||
+ true);
|
||||
+ patch_area_size -= patch_area_entry;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
fputs ("\t.localentry\t", file);
|
||||
assemble_name (file, name);
|
||||
fputs (",.-", file);
|
||||
assemble_name (file, name);
|
||||
fputs ("\n", file);
|
||||
+ /* Emit the nops after local entry. */
|
||||
+ if (patch_area_size > 0)
|
||||
+ rs6000_print_patchable_function_entry (file, patch_area_size,
|
||||
+ patch_area_entry == 0);
|
||||
}
|
||||
|
||||
else if (rs6000_pcrel_p ())
|
||||
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
|
||||
index bbe21eacc6b9..b9496d7f2680 100644
|
||||
--- a/gcc/config/rs6000/rs6000.c
|
||||
+++ b/gcc/config/rs6000/rs6000.c
|
||||
@@ -14930,8 +14930,14 @@ rs6000_print_patchable_function_entry (FILE *file,
|
||||
if (!(TARGET_64BIT && DEFAULT_ABI != ABI_ELFv2)
|
||||
&& HAVE_GAS_SECTION_LINK_ORDER)
|
||||
flags |= SECTION_LINK_ORDER;
|
||||
- default_print_patchable_function_entry_1 (file, patch_area_size, record_p,
|
||||
- flags);
|
||||
+ bool global_entry_needed_p = rs6000_global_entry_point_prologue_needed_p ();
|
||||
+ /* For a function which needs global entry point, we will emit the
|
||||
+ patchable area before and after local entry point under the control of
|
||||
+ cfun->machine->global_entry_emitted, see the handling in function
|
||||
+ rs6000_output_function_prologue. */
|
||||
+ if (!global_entry_needed_p || cfun->machine->global_entry_emitted)
|
||||
+ default_print_patchable_function_entry_1 (file, patch_area_size, record_p,
|
||||
+ flags);
|
||||
}
|
||||
|
||||
enum rtx_code
|
||||
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
|
||||
index eb7b21584970..b4df22b60303 100644
|
||||
--- a/gcc/config/rs6000/rs6000.h
|
||||
+++ b/gcc/config/rs6000/rs6000.h
|
||||
@@ -2435,6 +2435,10 @@ typedef struct GTY(()) machine_function
|
||||
bool lr_is_wrapped_separately;
|
||||
bool toc_is_wrapped_separately;
|
||||
bool mma_return_type_error;
|
||||
+ /* Indicate global entry is emitted, only useful when the function requires
|
||||
+ global entry. It helps to control the patchable area before and after
|
||||
+ local entry. */
|
||||
+ bool global_entry_emitted;
|
||||
} machine_function;
|
||||
#endif
|
||||
|
||||
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
|
||||
index 2ac9cfc35f92..518bfdf0867d 100644
|
||||
--- a/gcc/doc/invoke.texi
|
||||
+++ b/gcc/doc/invoke.texi
|
||||
@@ -16884,9 +16884,13 @@ the area size or to remove it completely on a single function.
|
||||
If @code{N=0}, no pad location is recorded.
|
||||
|
||||
The NOP instructions are inserted at---and maybe before, depending on
|
||||
-@var{M}---the function entry address, even before the prologue.
|
||||
+@var{M}---the function entry address, even before the prologue. On
|
||||
+PowerPC with the ELFv2 ABI, for a function with dual entry points,
|
||||
+the local entry point is this function entry address.
|
||||
|
||||
-The maximum value of @var{N} and @var{M} is 65535.
|
||||
+The maximum value of @var{N} and @var{M} is 65535. On PowerPC with the
|
||||
+ELFv2 ABI, for a function with dual entry points, the supported values
|
||||
+for @var{M} are 0, 2, 6 and 14.
|
||||
@end table
|
||||
|
||||
|
||||
diff --git a/gcc/testsuite/c-c++-common/patchable_function_entry-default.c b/gcc/testsuite/c-c++-common/patchable_function_entry-default.c
|
||||
index 7036f7bfbea4..a501efccb194 100644
|
||||
--- a/gcc/testsuite/c-c++-common/patchable_function_entry-default.c
|
||||
+++ b/gcc/testsuite/c-c++-common/patchable_function_entry-default.c
|
||||
@@ -1,6 +1,9 @@
|
||||
/* { dg-do compile { target { ! { nvptx*-*-* visium-*-* } } } } */
|
||||
/* { dg-options "-O2 -fpatchable-function-entry=3,1" } */
|
||||
/* { dg-additional-options "-fno-pie" { target sparc*-*-* } } */
|
||||
+/* See PR99888, one single preceding nop isn't allowed on powerpc_elfv2,
|
||||
+ so overriding with two preceding nops to make it pass there. */
|
||||
+/* { dg-additional-options "-fpatchable-function-entry=3,2" { target powerpc_elfv2 } } */
|
||||
/* { dg-final { scan-assembler-times "nop|NOP|SWYM" 3 { target { ! { alpha*-*-* } } } } } */
|
||||
/* { dg-final { scan-assembler-times "bis" 3 { target alpha*-*-* } } } */
|
||||
|
||||
diff --git a/gcc/testsuite/gcc.target/powerpc/pr99888-1.c b/gcc/testsuite/gcc.target/powerpc/pr99888-1.c
|
||||
new file mode 100644
|
||||
index 000000000000..9370b4e74388
|
||||
--- /dev/null
|
||||
+++ b/gcc/testsuite/gcc.target/powerpc/pr99888-1.c
|
||||
@@ -0,0 +1,43 @@
|
||||
+/* Verify no errors for different nops after local entry on ELFv2. */
|
||||
+
|
||||
+extern int a;
|
||||
+
|
||||
+__attribute__ ((noipa, patchable_function_entry (1, 0)))
|
||||
+int test1 (int b) {
|
||||
+ return a + b;
|
||||
+}
|
||||
+
|
||||
+__attribute__ ((noipa, patchable_function_entry (2, 0)))
|
||||
+int test2 (int b) {
|
||||
+ return a + b;
|
||||
+}
|
||||
+
|
||||
+__attribute__ ((noipa, patchable_function_entry (3, 0)))
|
||||
+int test3 (int b) {
|
||||
+ return a + b;
|
||||
+}
|
||||
+
|
||||
+__attribute__ ((noipa, patchable_function_entry (4, 0)))
|
||||
+int test4 (int b) {
|
||||
+ return a + b;
|
||||
+}
|
||||
+
|
||||
+__attribute__ ((noipa, patchable_function_entry (5, 0)))
|
||||
+int test5 (int b) {
|
||||
+ return a + b;
|
||||
+}
|
||||
+
|
||||
+__attribute__ ((noipa, patchable_function_entry (6, 0)))
|
||||
+int test6 (int b) {
|
||||
+ return a + b;
|
||||
+}
|
||||
+
|
||||
+__attribute__ ((noipa, patchable_function_entry (7, 0)))
|
||||
+int test7 (int b) {
|
||||
+ return a + b;
|
||||
+}
|
||||
+
|
||||
+__attribute__ ((noipa, patchable_function_entry (8, 0)))
|
||||
+int test8 (int b) {
|
||||
+ return a + b;
|
||||
+}
|
||||
diff --git a/gcc/testsuite/gcc.target/powerpc/pr99888-2.c b/gcc/testsuite/gcc.target/powerpc/pr99888-2.c
|
||||
new file mode 100644
|
||||
index 000000000000..450617126023
|
||||
--- /dev/null
|
||||
+++ b/gcc/testsuite/gcc.target/powerpc/pr99888-2.c
|
||||
@@ -0,0 +1,43 @@
|
||||
+/* Verify no errors for 2, 6 and 14 nops before local entry on ELFv2. */
|
||||
+
|
||||
+extern int a;
|
||||
+
|
||||
+__attribute__ ((noipa, patchable_function_entry (2, 2)))
|
||||
+int test1 (int b) {
|
||||
+ return a + b;
|
||||
+}
|
||||
+
|
||||
+__attribute__ ((noipa, patchable_function_entry (4, 2)))
|
||||
+int test2 (int b) {
|
||||
+ return a + b;
|
||||
+}
|
||||
+
|
||||
+__attribute__ ((noipa, patchable_function_entry (6, 6)))
|
||||
+int test3 (int b) {
|
||||
+ return a + b;
|
||||
+}
|
||||
+
|
||||
+__attribute__ ((noipa, patchable_function_entry (8, 6)))
|
||||
+int test4 (int b) {
|
||||
+ return a + b;
|
||||
+}
|
||||
+
|
||||
+__attribute__ ((noipa, patchable_function_entry (16, 6)))
|
||||
+int test5 (int b) {
|
||||
+ return a + b;
|
||||
+}
|
||||
+
|
||||
+__attribute__ ((noipa, patchable_function_entry (14, 14)))
|
||||
+int test6 (int b) {
|
||||
+ return a + b;
|
||||
+}
|
||||
+
|
||||
+__attribute__ ((noipa, patchable_function_entry (28, 14)))
|
||||
+int test7 (int b) {
|
||||
+ return a + b;
|
||||
+}
|
||||
+
|
||||
+__attribute__ ((noipa, patchable_function_entry (64, 14)))
|
||||
+int test8 (int b) {
|
||||
+ return a + b;
|
||||
+}
|
||||
diff --git a/gcc/testsuite/gcc.target/powerpc/pr99888-3.c b/gcc/testsuite/gcc.target/powerpc/pr99888-3.c
|
||||
new file mode 100644
|
||||
index 000000000000..4531ae32036d
|
||||
--- /dev/null
|
||||
+++ b/gcc/testsuite/gcc.target/powerpc/pr99888-3.c
|
||||
@@ -0,0 +1,11 @@
|
||||
+/* { dg-options "-fpatchable-function-entry=1" } */
|
||||
+
|
||||
+/* Verify no errors on ELFv2, using command line option instead of
|
||||
+ function attribute. */
|
||||
+
|
||||
+extern int a;
|
||||
+
|
||||
+int test (int b) {
|
||||
+ return a + b;
|
||||
+}
|
||||
+
|
||||
diff --git a/gcc/testsuite/gcc.target/powerpc/pr99888-4.c b/gcc/testsuite/gcc.target/powerpc/pr99888-4.c
|
||||
new file mode 100644
|
||||
index 000000000000..00a8d4d316e0
|
||||
--- /dev/null
|
||||
+++ b/gcc/testsuite/gcc.target/powerpc/pr99888-4.c
|
||||
@@ -0,0 +1,13 @@
|
||||
+/* { dg-require-effective-target powerpc_elfv2 } */
|
||||
+/* There is no global entry point prologue with pcrel. */
|
||||
+/* { dg-options "-mno-pcrel -fpatchable-function-entry=1,1" } */
|
||||
+
|
||||
+/* Verify one error emitted for unexpected 1 nop before local
|
||||
+ entry. */
|
||||
+
|
||||
+extern int a;
|
||||
+
|
||||
+int test (int b) {
|
||||
+ return a + b;
|
||||
+}
|
||||
+/* { dg-error "unsupported number of nops before function entry \\(1\\)" "" { target *-*-* } .-1 } */
|
||||
diff --git a/gcc/testsuite/gcc.target/powerpc/pr99888-5.c b/gcc/testsuite/gcc.target/powerpc/pr99888-5.c
|
||||
new file mode 100644
|
||||
index 000000000000..39d3b4465f11
|
||||
--- /dev/null
|
||||
+++ b/gcc/testsuite/gcc.target/powerpc/pr99888-5.c
|
||||
@@ -0,0 +1,13 @@
|
||||
+/* { dg-require-effective-target powerpc_elfv2 } */
|
||||
+/* There is no global entry point prologue with pcrel. */
|
||||
+/* { dg-options "-mno-pcrel -fpatchable-function-entry=7,3" } */
|
||||
+
|
||||
+/* Verify one error emitted for unexpected 3 nops before local
|
||||
+ entry. */
|
||||
+
|
||||
+extern int a;
|
||||
+
|
||||
+int test (int b) {
|
||||
+ return a + b;
|
||||
+}
|
||||
+/* { dg-error "unsupported number of nops before function entry \\(3\\)" "" { target *-*-* } .-1 } */
|
||||
diff --git a/gcc/testsuite/gcc.target/powerpc/pr99888-6.c b/gcc/testsuite/gcc.target/powerpc/pr99888-6.c
|
||||
new file mode 100644
|
||||
index 000000000000..c6c18dcc7ac0
|
||||
--- /dev/null
|
||||
+++ b/gcc/testsuite/gcc.target/powerpc/pr99888-6.c
|
||||
@@ -0,0 +1,14 @@
|
||||
+/* { dg-require-effective-target powerpc_elfv2 } */
|
||||
+/* There is no global entry point prologue with pcrel. */
|
||||
+/* { dg-options "-mno-pcrel" } */
|
||||
+
|
||||
+/* Verify one error emitted for unexpected 4 nops before local
|
||||
+ entry. */
|
||||
+
|
||||
+extern int a;
|
||||
+
|
||||
+__attribute__ ((patchable_function_entry (20, 4)))
|
||||
+int test (int b) {
|
||||
+ return a + b;
|
||||
+}
|
||||
+/* { dg-error "unsupported number of nops before function entry \\(4\\)" "" { target *-*-* } .-1 } */
|
||||
--
|
||||
2.43.5
|
||||
|
||||
38
SOURCES/gcc11-testsuite-fixes-4.patch
Normal file
38
SOURCES/gcc11-testsuite-fixes-4.patch
Normal file
@ -0,0 +1,38 @@
|
||||
commit 181f40f5cf8510a16191e4768dadbe2cb7a5c095
|
||||
Author: Jakub Jelinek <jakub@redhat.com>
|
||||
Date: Wed Jul 24 18:00:05 2024 +0200
|
||||
|
||||
testsuite: Fix up pr116034.c test for big/pdp endian [PR116061]
|
||||
|
||||
Didn't notice the memmove is into an int variable, so the test
|
||||
was still failing on big endian.
|
||||
|
||||
2024-07-24 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR tree-optimization/116034
|
||||
PR testsuite/116061
|
||||
* gcc.dg/pr116034.c (g): Change type from int to unsigned short.
|
||||
(foo): Guard memmove call on __SIZEOF_SHORT__ == 2.
|
||||
|
||||
(cherry picked from commit 69e69847e21a8d951ab5f09fd3421449564dba31)
|
||||
|
||||
diff --git a/gcc/testsuite/gcc.dg/pr116034.c b/gcc/testsuite/gcc.dg/pr116034.c
|
||||
index 9a31de03424..955b4c9e86b 100644
|
||||
--- a/gcc/testsuite/gcc.dg/pr116034.c
|
||||
+++ b/gcc/testsuite/gcc.dg/pr116034.c
|
||||
@@ -2,12 +2,13 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O1 -fno-strict-aliasing" } */
|
||||
|
||||
-int g;
|
||||
+unsigned short int g;
|
||||
|
||||
static inline int
|
||||
foo (_Complex unsigned short c)
|
||||
{
|
||||
- __builtin_memmove (&g, 1 + (char *) &c, 2);
|
||||
+ if (__SIZEOF_SHORT__ == 2)
|
||||
+ __builtin_memmove (&g, 1 + (char *) &c, 2);
|
||||
return g;
|
||||
}
|
||||
|
||||
120
SPECS/gcc.spec
120
SPECS/gcc.spec
@ -1,10 +1,11 @@
|
||||
%global source_date_epoch_from_changelog 1
|
||||
%global DATE 20240719
|
||||
%global gitrev a985e3068a6f8045f8a6f2d2d5ae75f5eb0a8767
|
||||
%global gcc_version 11.5.0
|
||||
%global gcc_major 11
|
||||
# Note, gcc_release must be integer, if you want to add suffixes to
|
||||
# %%{release}, append them after %%{gcc_release} on Release: line.
|
||||
%global gcc_release 2
|
||||
%global gcc_release 11
|
||||
%global nvptx_tools_gitrev 5f6f343a302d620b0868edab376c00b15741e39e
|
||||
%global newlib_cygwin_gitrev 50e2a63b04bdd018484605fbb954fd1bd5147fa0
|
||||
%global _unpackaged_files_terminate_build 0
|
||||
@ -150,7 +151,7 @@ Source0: gcc-%{version}-%{DATE}.tar.xz
|
||||
Source1: nvptx-tools-%{nvptx_tools_gitrev}.tar.xz
|
||||
# The source for nvptx-newlib package was pulled from upstream's vcs. Use the
|
||||
# following commands to generate the tarball:
|
||||
# git clone git://sourceware.org/git/newlib-cygwin.git newlib-cygwin-dir.tmp
|
||||
# git clone https://sourceware.org/git/newlib-cygwin.git newlib-cygwin-dir.tmp
|
||||
# git --git-dir=newlib-cygwin-dir.tmp/.git archive --prefix=newlib-cygwin-%%{newlib_cygwin_gitrev}/ %%{newlib_cygwin_gitrev} ":(exclude)newlib/libc/sys/linux/include/rpc/*.[hx]" | xz -9e > newlib-cygwin-%%{newlib_cygwin_gitrev}.tar.xz
|
||||
# rm -rf newlib-cygwin-dir.tmp
|
||||
Source2: newlib-cygwin-%{newlib_cygwin_gitrev}.tar.xz
|
||||
@ -202,7 +203,10 @@ BuildRequires: glibc >= 2.3.90-35
|
||||
%endif
|
||||
%ifarch %{multilib_64_archs} sparcv9 ppc
|
||||
# Ensure glibc{,-devel} is installed for both multilib arches
|
||||
BuildRequires: /lib/libc.so.6 /usr/lib/libc.so /lib64/libc.so.6 /usr/lib64/libc.so
|
||||
BuildRequires: (glibc32 or glibc-devel(%{__isa_name}-32))
|
||||
%endif
|
||||
%ifarch sparcv9 ppc
|
||||
BuildRequires: (glibc64 or glibc-devel(%{__isa_name}-64))
|
||||
%endif
|
||||
%if %{build_ada}
|
||||
# Ada requires Ada to build
|
||||
@ -298,6 +302,36 @@ Patch35: gcc11-testsuite-aarch64-add-fno-stack-protector.patch
|
||||
Patch36: gcc11-libgfortran-flush.patch
|
||||
Patch37: gcc11-pr113960.patch
|
||||
Patch38: gcc11-pr105157.patch
|
||||
Patch39: gcc11-testsuite-fixes-4.patch
|
||||
Patch40: gcc11-pr99888.patch
|
||||
Patch41: gcc11-pr118976.patch
|
||||
Patch42: gcc-RHEL-105072-1.patch
|
||||
Patch43: gcc-RHEL-105072-2.patch
|
||||
Patch44: gcc-RHEL-105072-3.patch
|
||||
Patch45: gcc-RHEL-105072-4.patch
|
||||
Patch46: gcc-RHEL-105072-5.patch
|
||||
Patch47: gcc-RHEL-105072-6.patch
|
||||
Patch48: gcc-RHEL-105072-7.patch
|
||||
Patch49: gcc-RHEL-105072-8.patch
|
||||
Patch50: gcc-RHEL-105072-9.patch
|
||||
Patch51: gcc-RHEL-105072-10.patch
|
||||
Patch52: gcc-RHEL-105072-11.patch
|
||||
Patch53: gcc-RHEL-105072-12.patch
|
||||
Patch54: gcc-RHEL-105072-13.patch
|
||||
Patch55: gcc-RHEL-105072-14.patch
|
||||
Patch56: gcc-RHEL-105072-15.patch
|
||||
Patch57: gcc-RHEL-105072-16.patch
|
||||
Patch58: gcc-RHEL-105072-17.patch
|
||||
Patch59: gcc-RHEL-105072-18.patch
|
||||
Patch60: gcc-RHEL-105072-19.patch
|
||||
Patch61: gcc-RHEL-105072-20.patch
|
||||
Patch62: gcc-RHEL-105072-21.patch
|
||||
Patch63: gcc-RHEL-105072-22.patch
|
||||
Patch64: gcc-RHEL-105072-23.patch
|
||||
Patch65: gcc-RHEL-105072-24.patch
|
||||
Patch66: gcc-RHEL-105072-25.patch
|
||||
Patch67: gcc-RHEL-105072-26.patch
|
||||
Patch68: gcc-RHEL-105072-27.patch
|
||||
|
||||
Patch100: gcc11-fortran-fdec-duplicates.patch
|
||||
Patch101: gcc11-fortran-flogical-as-integer.patch
|
||||
@ -310,6 +344,11 @@ Patch107: gcc11-fortran-fdec-promotion.patch
|
||||
Patch108: gcc11-fortran-fdec-sequence.patch
|
||||
Patch109: gcc11-fortran-fdec-add-missing-indexes.patch
|
||||
|
||||
# Pretty printer update.
|
||||
Patch1000: gcc11-libstdc++-prettyprinter-update-15.patch
|
||||
Patch1001: gcc11-libstdc++-prettyprinter-update-15-tests.patch
|
||||
Patch1002: gcc11-libstdc++-prettyprinter-update-15-tests-48362.patch
|
||||
|
||||
# On ARM EABI systems, we do want -gnueabi to be part of the
|
||||
# target triple.
|
||||
%ifnarch %{arm}
|
||||
@ -355,6 +394,8 @@ You'll need this package in order to compile C code.
|
||||
%package -n libgcc
|
||||
Summary: GCC version 11 shared support library
|
||||
Autoreq: false
|
||||
# This expresses the dependency on _dl_find_object.
|
||||
Requires: libc.so.6(GLIBC_2.35)%[0%{?__isa_bits} == 64 ? "(64bit)" : ""]
|
||||
%if !%{build_ada}
|
||||
Obsoletes: libgnat < %{version}-%{release}
|
||||
%endif
|
||||
@ -901,6 +942,36 @@ mark them as cross compiled.
|
||||
%patch36 -p1 -b .libgfortran-flush~
|
||||
%patch37 -p1 -b .pr113960~
|
||||
%patch38 -p1 -b .pr105157~
|
||||
%patch39 -p1 -b .testsuite4~
|
||||
%patch40 -p1 -b .pr99888~
|
||||
%patch41 -p1 -b .pr118976~
|
||||
%patch42 -p1 -b .rhel-105072-1~
|
||||
%patch43 -p1 -b .rhel-105072-2~
|
||||
%patch44 -p1 -b .rhel-105072-3~
|
||||
%patch45 -p1 -b .rhel-105072-4~
|
||||
%patch46 -p1 -b .rhel-105072-5~
|
||||
%patch47 -p1 -b .rhel-105072-6~
|
||||
%patch48 -p1 -b .rhel-105072-7~
|
||||
%patch49 -p1 -b .rhel-105072-8~
|
||||
%patch50 -p1 -b .rhel-105072-9~
|
||||
%patch51 -p1 -b .rhel-105072-10~
|
||||
%patch52 -p1 -b .rhel-105072-11~
|
||||
%patch53 -p1 -b .rhel-105072-12~
|
||||
%patch54 -p1 -b .rhel-105072-13~
|
||||
%patch55 -p1 -b .rhel-105072-14~
|
||||
%patch56 -p1 -b .rhel-105072-15~
|
||||
%patch57 -p1 -b .rhel-105072-16~
|
||||
%patch58 -p1 -b .rhel-105072-17~
|
||||
%patch59 -p1 -b .rhel-105072-18~
|
||||
%patch60 -p1 -b .rhel-105072-19~
|
||||
%patch61 -p1 -b .rhel-105072-20~
|
||||
%patch62 -p1 -b .rhel-105072-21~
|
||||
%patch63 -p1 -b .rhel-105072-22~
|
||||
%patch64 -p1 -b .rhel-105072-23~
|
||||
%patch65 -p1 -b .rhel-105072-24~
|
||||
%patch66 -p1 -b .rhel-105072-25~
|
||||
%patch67 -p1 -b .rhel-105072-26~
|
||||
%patch68 -p1 -b .rhel-105072-27~
|
||||
|
||||
%if 0%{?rhel} >= 9
|
||||
%patch100 -p1 -b .fortran-fdec-duplicates~
|
||||
@ -915,6 +986,10 @@ mark them as cross compiled.
|
||||
%patch109 -p1 -b .fortran-fdec-add-missing-indexes~
|
||||
%endif
|
||||
|
||||
%patch1000 -p1 -b .libstdc++-prettyprinter-update-15
|
||||
%patch1001 -p1 -b .libstdc++-prettyprinter-update-15-tests
|
||||
%patch1002 -p1 -b .libstdc++-prettyprinter-update-15-tests-48362
|
||||
|
||||
%ifarch %{arm}
|
||||
rm -f gcc/testsuite/go.test/test/fixedbugs/issue19182.go
|
||||
%endif
|
||||
@ -1422,6 +1497,9 @@ then
|
||||
CONFIG_ARGS="$CONFIG_ARGS --without-annocheck"
|
||||
CONFIG_ARGS="$CONFIG_ARGS --without-tests"
|
||||
CONFIG_ARGS="$CONFIG_ARGS --disable-rpath"
|
||||
CONFIG_ARGS="$CONFIG_ARGS --without-debuginfod"
|
||||
CONFIG_ARGS="$CONFIG_ARGS --without-clang-plugin"
|
||||
CONFIG_ARGS="$CONFIG_ARGS --without-llvm-plugin"
|
||||
|
||||
comp_dir="%{_builddir}/gcc-%{version}-%{DATE}/obj-%{gcc_target_platform}/gcc/"
|
||||
ccompiler="%{_builddir}/gcc-%{version}-%{DATE}/obj-%{gcc_target_platform}/gcc/xgcc -B $comp_dir"
|
||||
@ -1813,9 +1891,9 @@ mv -f %{buildroot}%{_prefix}/%{_lib}/libstdc++*gdb.py* \
|
||||
%{buildroot}%{_datadir}/gdb/auto-load/%{_prefix}/%{_lib}/
|
||||
pushd ../libstdc++-v3/python
|
||||
for i in `find . -name \*.py`; do
|
||||
touch -r $i %{buildroot}%{_prefix}/share/gcc-%{gcc_major}/python/$i
|
||||
touch -d @$SOURCE_DATE_EPOCH %{buildroot}%{_prefix}/share/gcc-%{gcc_major}/python/$i
|
||||
done
|
||||
touch -r hook.in %{buildroot}%{_datadir}/gdb/auto-load/%{_prefix}/%{_lib}/libstdc++*gdb.py
|
||||
touch -d @$SOURCE_DATE_EPOCH %{buildroot}%{_datadir}/gdb/auto-load/%{_prefix}/%{_lib}/libstdc++*gdb.py
|
||||
popd
|
||||
for f in `find %{buildroot}%{_prefix}/share/gcc-%{gcc_major}/python/ \
|
||||
%{buildroot}%{_datadir}/gdb/auto-load/%{_prefix}/%{_lib}/ -name \*.py`; do
|
||||
@ -3594,9 +3672,39 @@ end
|
||||
%endif
|
||||
|
||||
%changelog
|
||||
* Mon Sep 30 2024 Eduard Abdullin - 11.5.0-2.alma.1
|
||||
* Mon Sep 15 2025 Eduard Abdullin <eabdullin@almalinux.org> - 11.5.0-11.alma.1
|
||||
- Debrand for AlmaLinux
|
||||
|
||||
* Thu Jul 31 2025 Florian Weimer <fweimer@redhat.com> - 11.5.0-11
|
||||
- Adjust glibc32 build dependency (RHEL-105072)
|
||||
|
||||
* Tue Jul 29 2025 Florian Weimer <fweimer@redhat.com> - 11.5.0-10
|
||||
- Exception handling performance improvements (RHEL-105072)
|
||||
- libgcc: Use _dl_find_object to find DWARF data in unwinder
|
||||
- libgcc: Use lock-free data structures for run-time unwinder registration
|
||||
|
||||
* Fri Jun 27 2025 Siddhesh Poyarekar <siddhesh@redhat.com> 11.5.0-9
|
||||
- Pin modification time for python files to SOURCE_DATE_EPOCH (RHEL-100148).
|
||||
|
||||
* Mon Jun 23 2025 Siddhesh Poyarekar <siddhesh@redhat.com> - 11.5.0-8
|
||||
- Sync libstdc++ pretty printers to latest GTS (RHEL-81975)
|
||||
|
||||
* Thu May 29 2025 Joseph Myers <josmyers@redhat.com> - 11.5.0-7
|
||||
- Fix folding of BIT_NOT_EXPR for POLY_INT_CST (PR 118976, RHEL-90239)
|
||||
|
||||
* Wed May 21 2025 David Malcolm <dmalcolm@redhat.com> - 11.5.0-6
|
||||
- rs6000: Rework ELFv2 support for -fpatchable-function-entry (PR target/99888,
|
||||
RHEL-75806)
|
||||
|
||||
* Fri Feb 7 2025 Marek Polacek <polacek@redhat.com> 11.5.0-5
|
||||
- rebuild for CVE-2020-11023 (RHEL-78377)
|
||||
|
||||
* Mon Jan 27 2025 Marek Polacek <polacek@redhat.com> 11.5.0-4
|
||||
- revert the PR middle-end/57245 patch (RHEL-76359)
|
||||
|
||||
* Tue Jan 21 2025 Marek Polacek <polacek@redhat.com> 11.5.0-3
|
||||
- honor -frounding-math in real truncation (PR middle-end/57245, RHEL-73749)
|
||||
|
||||
* Mon Jul 22 2024 Marek Polacek <polacek@redhat.com> 11.5.0-2
|
||||
- fix TARGET_CPU_DEFAULT (PR target/105157, RHEL-50037)
|
||||
- libstdc++: Workaround kernel-headers on s390x-linux (RHEL-50054)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user