linux/tools/testing/selftests/powerpc/mm/segv_errors.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2
   3/*
   4 * Copyright 2017 John Sperbeck
   5 *
   6 * Test that an access to a mapped but inaccessible area causes a SEGV and
   7 * reports si_code == SEGV_ACCERR.
   8 */
   9
  10#include <stdbool.h>
  11#include <stdio.h>
  12#include <stdlib.h>
  13#include <string.h>
  14#include <unistd.h>
  15#include <signal.h>
  16#include <sys/mman.h>
  17#include <assert.h>
  18#include <ucontext.h>
  19
  20#include "utils.h"
  21
  22static bool faulted;
  23static int si_code;
  24
  25static void segv_handler(int n, siginfo_t *info, void *ctxt_v)
  26{
  27        ucontext_t *ctxt = (ucontext_t *)ctxt_v;
  28        struct pt_regs *regs = ctxt->uc_mcontext.regs;
  29
  30        faulted = true;
  31        si_code = info->si_code;
  32        regs->nip += 4;
  33}
  34
  35int test_segv_errors(void)
  36{
  37        struct sigaction act = {
  38                .sa_sigaction = segv_handler,
  39                .sa_flags = SA_SIGINFO,
  40        };
  41        char c, *p = NULL;
  42
  43        p = mmap(NULL, getpagesize(), 0, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
  44        FAIL_IF(p == MAP_FAILED);
  45
  46        FAIL_IF(sigaction(SIGSEGV, &act, NULL) != 0);
  47
  48        faulted = false;
  49        si_code = 0;
  50
  51        /*
  52         * We just need a compiler barrier, but mb() works and has the nice
  53         * property of being easy to spot in the disassembly.
  54         */
  55        mb();
  56        c = *p;
  57        mb();
  58
  59        FAIL_IF(!faulted);
  60        FAIL_IF(si_code != SEGV_ACCERR);
  61
  62        faulted = false;
  63        si_code = 0;
  64
  65        mb();
  66        *p = c;
  67        mb();
  68
  69        FAIL_IF(!faulted);
  70        FAIL_IF(si_code != SEGV_ACCERR);
  71
  72        return 0;
  73}
  74
  75int main(void)
  76{
  77        return test_harness(test_segv_errors, "segv_errors");
  78}
  79