This is the mail archive of the gcc-patches@gcc.gnu.org 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]

PATCH: MIPS/linux unwind through signal handlers.


Greetings patch evaluators,

The attached patch defines MD_FALLBACK_FRAME_STATE_FOR for mips/linux. It is needed for my upcomming patch (soon to be posted to java-patches) to libgcj to allow catching NullPointerExceptions via SIGSEGV handling.

The catcher.cc program (also attached) was used to test the patch.

Are there testcases for this sort of thing?

David Daney.
2003-09-10  David Daney <ddaney@avtrex.com>

	* gcc/config/mips/linux.h (MD_FALLBACK_FRAME_STATE_FOR): New macro,
	needed for mips/libgcj signal handling.


diff -u --recursive --ignore-space-change --new-file --exclude=*~ --exclude=Makefile.in --exclude=configure --exclude=semantic.cache* gcc-3.3.1/gcc/config/mips/linux.h gcc-3.3.1.dave/gcc/config/mips/linux.h
--- gcc-3.3.1/gcc/config/mips/linux.h	Thu May  8 10:31:34 2003
+++ gcc-3.3.1.dave/gcc/config/mips/linux.h	Wed Sep 10 10:07:54 2003
@@ -252,3 +252,80 @@
 /* The current Linux binutils uses MIPS_STABS_ELF and doesn't support
    COFF.  */
 #undef SDB_DEBUGGING_INFO
+
+/* Do code reading to identify a signal frame, and set the frame
+   state data appropriately.  See unwind-dw2.c for the structs.  */
+
+#ifdef IN_LIBGCC2
+#include <signal.h>
+
+/* The third parameter to the signal handler points to something with
+ * this structure defined in asm/ucontext.h, but the name clashes with
+ * struct ucontext from sys/ucontext.h so this private copy is used. */
+typedef struct _sig_ucontext {
+    unsigned long	  uc_flags;
+    struct _sig_ucontext  *uc_link;
+    stack_t		  uc_stack;
+    struct sigcontext uc_mcontext;
+    sigset_t	  uc_sigmask;
+} sig_ucontext_t;
+
+#endif /* IN_LIBGCC2  */
+
+#define MD_FALLBACK_FRAME_STATE_FOR(CONTEXT, FS, SUCCESS)		\
+  do {									\
+    unsigned char *pc_ = (CONTEXT)->ra;					\
+    struct sigcontext *sc_;						\
+    long new_cfa_;							\
+    int i_;								\
+									\
+    /* 24021061 li v0, 0x1061 (rt_sigreturn)*/                          \
+    /* 0000000c syscall    */                                           \
+    /*    or */                                                         \
+    /* 24021017 li v0, 0x1017 (sigreturn) */                            \
+    /* 0000000c syscall  */			                        \
+    if (*(unsigned int *) (pc_+4) != 0x0000000c)			\
+      break;								\
+    if (*(unsigned int *) (pc_+0) == 0x24021017)			\
+      {									\
+	struct sigframe {						\
+	  unsigned int trampoline[2];					\
+	  struct sigcontext sigctx;					\
+	} *rt_ = (CONTEXT)->ra;				        	\
+	sc_ = &rt_->sigctx;						\
+      }									\
+    else if (*(unsigned int *) (pc_+0) == 0x24021061)			\
+      {									\
+	struct rt_sigframe {						\
+	  unsigned int trampoline[2];					\
+	  struct siginfo info;						\
+	  sig_ucontext_t uc;			                	\
+	} *rt_ = (CONTEXT)->ra;				        	\
+	sc_ = &rt_->uc.uc_mcontext;					\
+      }									\
+    else								\
+      break;								\
+    									\
+    new_cfa_ = sc_->sc_regs[STACK_POINTER_REGNUM];			\
+    (FS)->cfa_how = CFA_REG_OFFSET;					\
+    (FS)->cfa_reg = STACK_POINTER_REGNUM;				\
+    (FS)->cfa_offset = new_cfa_ - (long) (CONTEXT)->cfa;		\
+    									\
+    for (i_ = 0; i_ < 32; i_++)						\
+      if (i_ != STACK_POINTER_REGNUM)					\
+	{	    							\
+	  (FS)->regs.reg[i_].how = REG_SAVED_OFFSET;			\
+	  (FS)->regs.reg[i_].loc.offset 				\
+	    = (long)&(sc_->sc_regs[i_]) - new_cfa_;			\
+	}								\
+    /* Overload RAP_REG_NUM to be signal handler return address. */     \
+    /* Is this correct?  It seems to work.  We don't have to define */  \
+    /* more pseudo registers. RAP should be unused in a signal frame. */\
+    (FS)->regs.reg[RAP_REG_NUM].how = REG_SAVED_OFFSET;                 \
+    (FS)->regs.reg[RAP_REG_NUM].loc.offset                              \
+        = (long)&(sc_->sc_pc) - new_cfa_;                               \
+    (FS)->retaddr_column = RAP_REG_NUM;                                 \
+									\
+    goto SUCCESS;							\
+  } while (0)
+
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

class CThrown
{
public:
    int reason;

    CThrown() {reason = 0;};
};

static CThrown *exception;

typedef struct _sig_ucontext {
    unsigned long	  uc_flags;
    struct _sig_ucontext  *uc_link;
    stack_t		  uc_stack;
    struct sigcontext uc_mcontext;
    sigset_t	  uc_sigmask;
} sig_ucontext_t;

static void
catch_segv (int fa, siginfo_t *psi, void *ta)
{
  struct sigcontext *_regs = &((sig_ucontext_t *)ta)->uc_mcontext;
  _regs->sc_pc += 4;

  printf("cought a segv\n");
  throw exception;
  
}


static void
f3(char *arg)
{
    char c = *arg;
    printf("c was %c\n", c);
}

static void
f2(char *arg)
{
    f3(arg);
}


static void
f1()
{
    try {
        f2(NULL);
    }
    catch (CThrown *ex) {
        printf("cought it!\n");
    }
}


int
main(int argc, char *argv[])
{
    printf("Starting\n");

    exception = new CThrown();

    struct sigaction sa;

    sa.sa_sigaction = catch_segv;
    sa.sa_flags = SA_NODEFER | SA_SIGINFO;
    sigemptyset (&sa.sa_mask);
    sigaction(SIGSEGV, &sa, NULL);
    

    f1();

    return 0;
}


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