Re: faultive address reported on SIGSEGV was simply junk
"Tom 'spot' Callaway" <[email protected]> Sat, 05 Jun 2004 10:54:44 -0500
| Newsgroups | gmane.linux.aurora.devel |
|---|---|
| Organization | Red Hat |
| Message-ID | <[email protected]> |
On Sat, 2004-06-05 at 15:04 +0200, Stefan van der Eijk wrote: > (lots of signal handler discussion snipped) Stefan, Signal handling on SPARC/Linux is special. You have to jump through a few flaming hoops to get the expected results. I've attached a fixed version of your test code, with the requisite hoops added. Feel free to pass this on to the MDK glibc maintainer. (Most relevant functions munged from sbcl, all relevant copyrights reserved). [root@fry root]# uname -a Linux fry 2.6.6-1.411sp1smp #1 SMP Thu Jun 3 14:43:58 EDT 2004 sparc64 sparc64 sparc64 GNU/Linux [root@fry root]# ./test-sparc-fixed p = 0x70024000 Caught SIGSEGV to 70024000 ~spot --- Tom "spot" Callaway <tcallawa(a)redhat*com> LCA, RHCE Red Hat Sales Engineer || Aurora SPARC Linux Project Leader "If you are going through hell, keep going." - Sir Winston Churchill _______________________________________________ Aurora-sparc-devel mailing list [email protected] http://lists.auroralinux.org/mailman/listinfo/aurora-sparc-devel Aurora FAQ: http://www.ecs.soton.ac.uk/~mas01r/aurorafaq.html
test-sparc-fixed.c
(text/x-csrc, 2.8 KB)
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdlib.h>
static volatile char *page;
static inline struct sigcontext *arch_os_get_context(struct sigcontext **void_context) {
asm volatile ("ta 0x03"); /* ta ST_FLUSH_WINDOWS */
return (struct sigcontext *) (void_context + 37);
}
unsigned long *os_context_register_addr(struct sigcontext *context, int offset)
{
if (offset == 0) {
static int zero;
zero = 0;
return (unsigned long)&zero;
} else if (offset < 16) {
return (unsigned long)&context->si_regs.u_regs[offset];
} else if (offset < 32) {
int *sp = (int*) context->si_regs.u_regs[14]; /* Stack Pointer */
return (unsigned long)&(sp[offset-16]);
} else
return 0;
}
unsigned long *os_context_pc_addr(struct sigcontext *context)
{
return (unsigned long)&(context->si_regs.pc);
}
caddr_t arch_get_bad_addr(int sig, siginfo_t *code, struct sigcontext *context)
{
unsigned long badinst;
unsigned long *pc;
int rs1;
pc = (unsigned long *)(*os_context_pc_addr(context));
/* On the sparc, we have to decode the instruction. */
if ((unsigned long) pc & 3) {
/* Unaligned */
return NULL;
}
badinst = *pc;
if ((badinst >> 30) != 3)
/* All load/store instructions have op = 11 (binary) */
return 0;
rs1 = (badinst>>14)&0x1f;
if (badinst & (1<<13)) {
/* r[rs1] + simm(13) */
int simm13 = badinst & 0x1fff;
if (simm13 & (1<<12))
simm13 |= -1<<13;
return (caddr_t)
(*os_context_register_addr(context, rs1)+simm13);
}
else {
/* r[rs1] + r[rs2] */
int rs2 = badinst & 0x1f;
return (caddr_t)
(*os_context_register_addr(context, rs1) +
*os_context_register_addr(context, rs2));
}
}
static void sigsegv_handler(int sig, siginfo_t *sip, void *scp)
{
struct sigcontext *context = arch_os_get_context(&scp);
caddr_t addr;
addr = arch_get_bad_addr(sig,sip,context);
printf("Caught SIGSEGV to %08x\n", addr);
if (addr != page)
abort();
exit(0);
}
int main(void)
{
struct sigaction sigsegv_sa;
sigemptyset(&sigsegv_sa.sa_mask);
sigsegv_sa.sa_sigaction = sigsegv_handler;
sigsegv_sa.sa_flags = SA_SIGINFO;
if (sigaction(SIGSEGV, &sigsegv_sa, 0) < 0) {
perror("sigaction");
return 1;
}
{
int page_size = getpagesize();
volatile unsigned char *p = (volatile unsigned char *)mmap(0,
page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
if (p == MAP_FAILED) {
perror("mmap");
return 2;
}
if (mprotect(p, page_size, PROT_READ) < 0) {
perror("mprotect");
return 3;
}
printf("p = %p\n", p);
page = p;
*p = 0;
munmap(p, page_size);
}
return 0;
}