This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
PATCH: MIPS/linux unwind through signal handlers.
- From: David Daney <ddaney at avtrex dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 10 Sep 2003 14:30:09 -0700
- Subject: 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;
}