This is the mail archive of the mailing list for the GCC project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[committed] Make config/mips/linux-unwind.h MIPS16-safe

config/mips/linux-unwind.h adds 4 to the address of the faulting
instruction, as an alternative to setting fs->signal_frame to 1.
But adding 4 is too much for MIPS16 code, where unextended instructions
are only 2 bytes long.  This patch changes the 4 to a 2.

That isn't the full justification.  The full justification is more
subtle, and I've tried to explain it in the new comments.

Tested on mips64-linux-gnu (-mips16/-mabi=32, -mabi=32, -mabi=n32
and -mabi=64).  Applied.


	* config/mips/mips.h (MASK_RETURN_ADDR): Expand commentary.
	* config/mips/linux-unwind.h (mips_fallback_frame_state): Add 2
	rather than 4 to PC.

Index: gcc/config/mips/mips.h
--- gcc/config/mips/mips.h	2008-08-09 17:03:59.000000000 +0100
+++ gcc/config/mips/mips.h	2008-08-09 17:27:33.000000000 +0100
@@ -1958,10 +1958,32 @@ #define STARTING_FRAME_OFFSET						\
 #define RETURN_ADDR_RTX mips_return_addr
-/* Since the mips16 ISA mode is encoded in the least-significant bit
-   of the address, mask it off return addresses for purposes of
-   finding exception handling regions.  */
+/* Mask off the MIPS16 ISA bit in unwind addresses.
+   The reason for this is a little subtle.  When unwinding a call,
+   we are given the call's return address, which on most targets
+   is the address of the following instruction.  However, what we
+   actually want to find is the EH region for the call itself.
+   The target-independent unwind code therefore searches for "RA - 1".
+   In the MIPS16 case, RA is always an odd-valued (ISA-encoded) address.
+   RA - 1 is therefore the real (even-valued) start of the return
+   instruction.  EH region labels are usually odd-valued MIPS16 symbols
+   too, so a search for an even address within a MIPS16 region would
+   usually work.
+   However, there is an exception.  If the end of an EH region is also
+   the end of a function, the end label is allowed to be even.  This is
+   necessary because a following non-MIPS16 function may also need EH
+   information for its first instruction.
+   Thus a MIPS16 region may be terminated by an ISA-encoded or a
+   non-ISA-encoded address.  This probably isn't ideal, but it is
+   the traditional (legacy) behavior.  It is therefore only safe
+   to search MIPS EH regions for an _odd-valued_ address.
+   Masking off the ISA bit means that the target-independent code
+   will search for "(RA & -2) - 1", which is guaranteed to be odd.  */
Index: gcc/config/mips/linux-unwind.h
--- gcc/config/mips/linux-unwind.h	2008-08-09 10:08:59.000000000 +0100
+++ gcc/config/mips/linux-unwind.h	2008-08-09 17:35:19.000000000 +0100
@@ -106,12 +106,17 @@ mips_fallback_frame_state (struct _Unwin
       = (_Unwind_Ptr)&(sc->sc_regs[i]) + reg_offset - new_cfa;
-  /* The PC points to the faulting instruction, but the unwind tables
-     expect it point to the following instruction.  We compensate by
-     reporting a return address at the next instruction. */
+  /* "PC & -2" points to the faulting instruction, but the unwind code
+     searches for "(ADDR & -2) - 1".  (See MASK_RETURN_ADDR for the source
+     of the -2 mask.)  Adding 2 here ensures that "(ADDR & -2) - 1" is the
+     address of the second byte of the faulting instruction.
+     Note that setting fs->signal_frame would not work.  As the comment
+     above MASK_RETURN_ADDR explains, MIPS unwinders must earch for an
+     odd-valued address.  */
-    = (_Unwind_Ptr)(sc->sc_pc) + 4 - new_cfa;
+    = (_Unwind_Ptr)(sc->sc_pc) + 2 - new_cfa;
   fs->retaddr_column = DWARF_ALT_FRAME_RETURN_COLUMN;
   return _URC_NO_REASON;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]