On Thu, Mar 24, 2011 at 12:15 AM, H.J. Lu <hjl.to...@gmail.com> wrote: > On Wed, Mar 23, 2011 at 12:22 PM, Ulrich Weigand <uweig...@de.ibm.com> wrote: >> Richard Henderson wrote: >>> Because, really, if we consider the structure truly public, we can't even >>> change the number of registers for a given port to support new features of >>> the cpu. >> >> Indeed, and I remember we got bitten by that a long time ago, which is why >> s390.h now has this comment: >> >> /* Number of hardware registers that go into the DWARF-2 unwind info. >> To avoid ABI incompatibility, this number must not change even as >> 'fake' hard registers are added or removed. */ >> #define DWARF_FRAME_REGISTERS 34 >> >>> I don't suppose there's any way that we can declare these old >>> programs Just Broken, and drop this compatibility stuff? >> >> I wouldn't like that ... we did run into this problem in the wild, and >> some s390 users really run very old programs for some reason. >> >> However, I'm wondering: this bug that leaked the implementation of >> _Unwind_Context only ever affected the *original* version of the >> structure -- it was fixed before the extended context was ever >> added, right? >> >> If this is true, we'd still need to keep the original context format >> unchanged, but we'd be free to modify the *extended* format at any >> time, without ABI considerations and need for further versioning ... >> > > From what I can tell, the issues are: > > 1. _Unwind_Context is supposed to be opaque and we are free to > change it. We should be able to extend DWARF_FRAME_REGISTERS > to support the new hard registers if needed, without breaking binary > compatibility. > 2. _Unwind_Context was leaked and wasn't really opaque. To > provide backward binary compatibility, we are stuck with what we > had. > > Is that possible to implement something along the line: > > 1. Add some bits to _Unwind_Context so that we can detect > the leaked _Unwind_Context. > 2. When a leaked _Unwind_Context is detected at run-time, > as a compile time option, a target can either provide binary > compatibility or issue a run-time error.
This is the attempt to implement it. Any comments? Thanks. -- H.J. -- 2011-04-09 H.J. Lu <hongjiu...@intel.com> PR other/48007 * unwind-dw2.c (UNIQUE_UNWIND_CONTEXT): New. (_Unwind_Context): If UNIQUE_UNWIND_CONTEXT is defined, add dwarf_reg_size_table and value, remove version and by_value. (EXTENDED_CONTEXT_BIT): Don't define if UNIQUE_UNWIND_CONTEXT is defined. (_Unwind_IsExtendedContext): Likewise. (_Unwind_GetGR): Support UNIQUE_UNWIND_CONTEXT. (_Unwind_SetGR): Likewise. (_Unwind_GetGRPtr): Likewise. (_Unwind_SetGRPtr): Likewise. (_Unwind_SetGRValue): Likewise. (_Unwind_GRByValue): Likewise. (__frame_state_for): Initialize dwarf_reg_size_table field if UNIQUE_UNWIND_CONTEXT is defined. (uw_install_context_1): Likewise. Support UNIQUE_UNWIND_CONTEXT.
2011-04-09 H.J. Lu <hongjiu...@intel.com> PR other/48007 * unwind-dw2.c (UNIQUE_UNWIND_CONTEXT): New. (_Unwind_Context): If UNIQUE_UNWIND_CONTEXT is defined, add dwarf_reg_size_table and value, remove version and by_value. (EXTENDED_CONTEXT_BIT): Don't define if UNIQUE_UNWIND_CONTEXT is defined. (_Unwind_IsExtendedContext): Likewise. (_Unwind_GetGR): Support UNIQUE_UNWIND_CONTEXT. (_Unwind_SetGR): Likewise. (_Unwind_GetGRPtr): Likewise. (_Unwind_SetGRPtr): Likewise. (_Unwind_SetGRValue): Likewise. (_Unwind_GRByValue): Likewise. (__frame_state_for): Initialize dwarf_reg_size_table field if UNIQUE_UNWIND_CONTEXT is defined. (uw_install_context_1): Likewise. Support UNIQUE_UNWIND_CONTEXT. diff --git a/gcc/unwind-dw2.c b/gcc/unwind-dw2.c index 25990b4..5fa2723 100644 --- a/gcc/unwind-dw2.c +++ b/gcc/unwind-dw2.c @@ -59,6 +59,12 @@ #define DWARF_REG_TO_UNWIND_COLUMN(REGNO) (REGNO) #endif +#ifndef UNIQUE_UNWIND_CONTEXT +#if defined __x86_64 && !defined __LP64__ +# define UNIQUE_UNWIND_CONTEXT +#endif +#endif + /* This is the register and unwind state for a particular frame. This provides the information necessary to unwind up past a frame and return to its caller. */ @@ -69,6 +75,15 @@ struct _Unwind_Context void *ra; void *lsda; struct dwarf_eh_bases bases; +#ifdef UNIQUE_UNWIND_CONTEXT + /* Used to check for unique _Unwind_Context. */ + void *dwarf_reg_size_table; + /* Signal frame context. */ +#define SIGNAL_FRAME_BIT ((_Unwind_Word) 1 >> 0) + _Unwind_Word flags; + _Unwind_Word args_size; + _Unwind_Word value[DWARF_FRAME_REGISTERS+1]; +#else /* Signal frame context. */ #define SIGNAL_FRAME_BIT ((~(_Unwind_Word) 0 >> 1) + 1) /* Context which has version/args_size/by_value fields. */ @@ -79,6 +94,7 @@ struct _Unwind_Context _Unwind_Word version; _Unwind_Word args_size; char by_value[DWARF_FRAME_REGISTERS+1]; +#endif }; /* Byte size of every register managed by these routines. */ @@ -144,11 +160,13 @@ _Unwind_SetSignalFrame (struct _Unwind_Context *context, int val) context->flags &= ~SIGNAL_FRAME_BIT; } +#ifndef UNIQUE_UNWIND_CONTEXT static inline _Unwind_Word _Unwind_IsExtendedContext (struct _Unwind_Context *context) { return context->flags & EXTENDED_CONTEXT_BIT; } +#endif /* Get the value of register INDEX as saved in CONTEXT. */ @@ -168,8 +186,14 @@ _Unwind_GetGR (struct _Unwind_Context *context, int index) size = dwarf_reg_size_table[index]; ptr = context->reg[index]; +#ifdef UNIQUE_UNWIND_CONTEXT + gcc_assert (context->dwarf_reg_size_table == &dwarf_reg_size_table); + if (context->reg[index] == &context->value[index]) + return context->value[index]; +#else if (_Unwind_IsExtendedContext (context) && context->by_value[index]) return (_Unwind_Word) (_Unwind_Internal_Ptr) ptr; +#endif /* This will segfault if the register hasn't been saved. */ if (size == sizeof(_Unwind_Ptr)) @@ -207,11 +231,20 @@ _Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val) gcc_assert (index < (int) sizeof(dwarf_reg_size_table)); size = dwarf_reg_size_table[index]; +#ifdef UNIQUE_UNWIND_CONTEXT + gcc_assert (context->dwarf_reg_size_table == &dwarf_reg_size_table); + if (context->reg[index] == &context->value[index]) + { + context->value[index] = val; + return; + } +#else if (_Unwind_IsExtendedContext (context) && context->by_value[index]) { context->reg[index] = (void *) (_Unwind_Internal_Ptr) val; return; } +#endif ptr = context->reg[index]; @@ -230,8 +263,10 @@ static inline void * _Unwind_GetGRPtr (struct _Unwind_Context *context, int index) { index = DWARF_REG_TO_UNWIND_COLUMN (index); +#ifndef UNIQUE_UNWIND_CONTEXT if (_Unwind_IsExtendedContext (context) && context->by_value[index]) return &context->reg[index]; +#endif return context->reg[index]; } @@ -241,8 +276,10 @@ static inline void _Unwind_SetGRPtr (struct _Unwind_Context *context, int index, void *p) { index = DWARF_REG_TO_UNWIND_COLUMN (index); +#ifndef UNIQUE_UNWIND_CONTEXT if (_Unwind_IsExtendedContext (context)) context->by_value[index] = 0; +#endif context->reg[index] = p; } @@ -254,10 +291,15 @@ _Unwind_SetGRValue (struct _Unwind_Context *context, int index, { index = DWARF_REG_TO_UNWIND_COLUMN (index); gcc_assert (index < (int) sizeof(dwarf_reg_size_table)); +#ifdef UNIQUE_UNWIND_CONTEXT + gcc_assert (dwarf_reg_size_table[index] == sizeof (_Unwind_Word)); + context->value[index] = val; + context->reg[index] = &context->value[index]; +#else gcc_assert (dwarf_reg_size_table[index] == sizeof (_Unwind_Ptr)); - context->by_value[index] = 1; context->reg[index] = (void *) (_Unwind_Internal_Ptr) val; +#endif } /* Return nonzero if register INDEX is stored by value rather than @@ -267,7 +309,11 @@ static inline int _Unwind_GRByValue (struct _Unwind_Context *context, int index) { index = DWARF_REG_TO_UNWIND_COLUMN (index); +#ifdef UNIQUE_UNWIND_CONTEXT + return context->reg[index] == &context->value[index]; +#else return context->by_value[index]; +#endif } /* Retrieve the return address for CONTEXT. */ @@ -1217,7 +1263,11 @@ __frame_state_for (void *pc_target, struct frame_state *state_in) int reg; memset (&context, 0, sizeof (struct _Unwind_Context)); +#ifdef UNIQUE_UNWIND_CONTEXT + context.dwarf_reg_size_table = &dwarf_reg_size_table; +#else context.flags = EXTENDED_CONTEXT_BIT; +#endif context.ra = pc_target + 1; if (uw_frame_state_for (&context, &fs) != _URC_NO_REASON) @@ -1455,7 +1505,11 @@ uw_init_context_1 (struct _Unwind_Context *context, memset (context, 0, sizeof (struct _Unwind_Context)); context->ra = ra; +#ifdef UNIQUE_UNWIND_CONTEXT + context->dwarf_reg_size_table = &dwarf_reg_size_table; +#else context->flags = EXTENDED_CONTEXT_BIT; +#endif code = uw_frame_state_for (context, &fs); gcc_assert (code == _URC_NO_REASON); @@ -1537,8 +1591,13 @@ uw_install_context_1 (struct _Unwind_Context *current, void *c = current->reg[i]; void *t = target->reg[i]; +#ifdef UNIQUE_UNWIND_CONTEXT + gcc_assert (current->reg[i] != ¤t->value[i]); + if (target->reg[i] == &target->value[i] && c) +#else gcc_assert (current->by_value[i] == 0); if (target->by_value[i] && c) +#endif { _Unwind_Word w; _Unwind_Ptr p;