static void sigHandle(int sig, siginfo_t *info, void *context)
{
  int e;
  sigset_t sigset, oldset;
  struct sigaction sa;

  AVER(sig == SIGSEGV);
  AVER(info != NULL);

  if(info->si_code == SEGV_ACCERR) {
    AccessSet mode;
    Addr base, limit;

    /* We can't determine the access mode (read, write, etc.) */
    /* under Solaris without decoding the faulting instruction. */
    /* Don't bother, yet.  We can do this if necessary. */

    mode = AccessREAD | AccessWRITE;

    /* We assume that the access is for one word at the address. */

    base = (Addr)info->si_addr;
    limit = AddrAdd(base, (Size)sizeof(Addr));

    /* Offer each protection structure the opportunity to handle the */
    /* exception.  If it succeeds, then allow the mutator to continue. */

    /* MutatorFaultContext parameter is a dummy parameter in this */
    /* implementation */
    if(ArenaAccess(base, mode, NULL))
      return;
  }

  /* The exception was not handled by any known protection structure, */
  /* so throw it to the previously installed handler. */

  /* @@ This is really weak.
   * Need to implement rest of the contract of sigaction */
 
  e = sigaction(SIGSEGV, &sigNext, &sa);
  AVER(e == 0);
  sigemptyset(&sigset);
  sigaddset(&sigset, SIGSEGV);
  e = sigprocmask(SIG_UNBLOCK, &sigset, &oldset);
  AVER(e == 0);
  kill(getpid(), SIGSEGV);
  e = sigprocmask(SIG_SETMASK, &oldset, NULL);
  AVER(e == 0);
  e = sigaction(SIGSEGV, &sa, NULL);
  AVER(e == 0);
}
Beispiel #2
0
static void sigHandle(int sig, siginfo_t *info, void *context)  /* .sigh.args */
{
  int e;
  /* sigset renamed to asigset due to clash with global on Darwin. */
  sigset_t asigset, oldset;
  struct sigaction sa;

  AVER(sig == PROT_SIGNAL);

  if(info->si_code == SEGV_ACCERR) {  /* .sigh.context */
    AccessSet mode;
    Addr base;
    ucontext_t *ucontext;
    MutatorFaultContextStruct mfContext;

    ucontext = (ucontext_t *)context;
    mfContext.ucontext = ucontext;
    mfContext.info = info;

    /* on linux we used to be able to tell whether this was a read or a write */
    mode = AccessREAD | AccessWRITE;

    /* We assume that the access is for one word at the address. */
    base = (Addr)info->si_addr;   /* .sigh.addr */
    /* limit = AddrAdd(base, (Size)sizeof(Addr)); */

    /* Offer each protection structure the opportunity to handle the */
    /* exception.  If it succeeds, then allow the mutator to continue. */

    if(ArenaAccess(base, mode, &mfContext))
      return;
  }

  /* The exception was not handled by any known protection structure, */
  /* so throw it to the previously installed handler.  That handler won't */
  /* get an accurate context (the MPS would fail if it were the second in */
  /* line) but it's the best we can do. */

  e = sigaction(PROT_SIGNAL, &sigNext, &sa);
  AVER(e == 0);
  sigemptyset(&asigset);
  sigaddset(&asigset, PROT_SIGNAL);
  e = sigprocmask(SIG_UNBLOCK, &asigset, &oldset);
  AVER(e == 0);
  kill(getpid(), PROT_SIGNAL);
  e = sigprocmask(SIG_SETMASK, &oldset, NULL);
  AVER(e == 0);
  e = sigaction(PROT_SIGNAL, &sa, NULL);
  AVER(e == 0);
}
static void sigHandle(int sig, siginfo_t *info, void *contextArg)
{
  ucontext_t *ucontext;

  AVER(sig == SIGBUS);
  AVER(info != NULL);

  ucontext = contextArg;

  /* On OS X the si_code field does't appear to be useful.  Protection
   * faults appear as SIGBUS signals, and the only documented code for
   * SIGBUS is BUS_ADRALN (invalid address alignment) which is what
   * si_code is set to (it has value 1), even though the address is
   * in fact aligned.
   * On other platforms a test like info->si_code == SEGV_ACCERR appears
   * here. */
  if(1) {
    AccessSet mode;
    Addr base, limit;

    /* We dont't bother to determine the access mode (read, write, etc.)
     * under OS X.  It's possible that this information is available in
     * the context structures.  Needs more investigation.
     */

    mode = AccessREAD | AccessWRITE;

    /* We assume that the access is for one word at the address. */

    /* See [PPCUCH] */
    base = (Addr)ucontext->uc_mcontext->es.dar;
    limit = AddrAdd(base, (Size)sizeof(Addr));

    /* Offer each protection structure the opportunity to handle the */
    /* exception.  If it succeeds, then allow the mutator to continue. */

    /* MutatorFaultContext parameter is a dummy parameter for this */
    /* implementation */
    if(ArenaAccess(base, mode, NULL)) {
      return;
    }
  }

  /* The exception was not handled by any known protection structure, */
  /* so throw it to the previously installed handler. */

  /* @@ This is really weak.
   * Need to implement rest of the contract of sigaction */
  (*sigNext.sa_sigaction)(sig, info, contextArg);
}
static void sigHandle(int sig, siginfo_t *info, void *context)  /* .sigh.args */
{
  int e;
  /* sigset renamed to asigset due to clash with global on Darwin. */
  sigset_t asigset, oldset;
  struct sigaction sa;
  
  UNUSED(context);
  AVER(sig == PROT_SIGNAL);

  /* .sigh.context */
  if(PROT_SIGINFO_GOOD(info)) {
    AccessSet mode;
    Addr base;

    mode = AccessREAD | AccessWRITE; /* .sigh.mode */

    /* We assume that the access is for one word at the address. */
    base = (Addr)info->si_addr;   /* .sigh.context */

    /* Offer each protection structure the opportunity to handle the */
    /* exception.  If it succeeds, then allow the mutator to continue. */
    if(ArenaAccess(base, mode, NULL))
      return;
  }

  /* The exception was not handled by any known protection structure, */
  /* so throw it to the previously installed handler. */

  e = sigaction(PROT_SIGNAL, &sigNext, &sa);
  AVER(e == 0);
  sigemptyset(&asigset);
  sigaddset(&asigset, PROT_SIGNAL);
  e = sigprocmask(SIG_UNBLOCK, &asigset, &oldset);
  AVER(e == 0);
  kill(getpid(), PROT_SIGNAL);
  e = sigprocmask(SIG_SETMASK, &oldset, NULL);
  AVER(e == 0);
  e = sigaction(PROT_SIGNAL, &sa, NULL);
  AVER(e == 0);
}
Beispiel #5
0
static void protCatchOne(void)
{
  protRequestStruct request;
  mach_msg_return_t mr;
  protReplyStruct reply;

  AVER(MACH_PORT_VALID(protExcPort));
  mr = mach_msg(&request.Head,
                /* option */ MACH_RCV_MSG,
                /* send_size */ 0,
                /* receive_limit */ sizeof(request),
                /* receive_name */ protExcPort,
                /* timeout */ MACH_MSG_TIMEOUT_NONE,
                /* notify */ MACH_PORT_NULL);
  AVER(mr == MACH_MSG_SUCCESS);
  if (mr != MACH_MSG_SUCCESS)
    mach_error("ERROR: MPS mach_msg recv\n", mr);  /* .trans.must */

  /* 2407 is the id for the 64-bit exception requests we asked for in
     ProtThreadRegister, with state and identity
     information, determined by experimentation and confirmed by 
     running mig on /usr/include/mach/mach_exc.defs */
  AVER(request.Head.msgh_id == 2407);
  AVER(request.Head.msgh_local_port == protExcPort);
  AVER(request.task.name == mach_task_self());
  AVER(request.exception == EXC_BAD_ACCESS);
  AVER(request.codeCnt == 2);
  AVER(request.old_stateCnt == THREAD_STATE_COUNT);
  AVER(request.flavor == THREAD_STATE_FLAVOR);
  
  /* TODO: This could dispatch to separate worker threads, in order to
     spread scanning work across several cores once the MPS can be
     re-entered. */

  if (request.code[0] == KERN_PROTECTION_FAILURE) {
    MutatorFaultContextStruct mfcStruct;

    /* The cast via Word suppresses "cast to pointer from integer of
       different size" warnings in GCC, for the  XCI3GC build. */
    mfcStruct.address = (Addr)(Word)request.code[1];
    AVER(sizeof(*mfcStruct.threadState) == sizeof(THREAD_STATE_S));
    mfcStruct.threadState = (THREAD_STATE_S *)request.old_state;
  
    if (ArenaAccess(mfcStruct.address,
                    AccessREAD | AccessWRITE,
                    &mfcStruct)) {
      /* Send a reply that will cause the thread to continue.
         Note that ArenaAccess may have updated request.old_state
         via mfcStruct.thread_state, and that will get copied to the
         reply and affect the state the thread resumes in. */
      protBuildReply(&reply, &request, KERN_SUCCESS);
      protMustSend(&reply.Head);
      return;
    }
  }

  /* We didn't handle the exception -- it wasn't one of ours. */

  /* .assume.only-port: We assume that there was no previously installed
     exception port.  This is checked in ProtThreadRegister, and we don't
     check it again here to avoid the extra system call.  If there
     were, we must arrange to forward the exception message to the
     previous port.  This module used to do that because it installed a
     task-wide exception handler, but the code is pretty hairy and not
     necessary as long as the MPS is registering threads individually.
     If we ever need to reinstate that code, look at
     https://info.ravenbrook.com/project/mps/prototype/2013-06-24/machtest */
  
  protBuildReply(&reply, &request, KERN_FAILURE);
  protMustSend(&reply.Head);
}