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;
}