"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-opcode.c" (15 Mar 2019, 9677 Bytes) of package /linux/privat/stress-ng-0.09.56.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "stress-opcode.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 0.09.52_vs_0.09.54.

    1 /*
    2  * Copyright (C) 2013-2019 Canonical, Ltd.
    3  *
    4  * This program is free software; you can redistribute it and/or
    5  * modify it under the terms of the GNU General Public License
    6  * as published by the Free Software Foundation; either version 2
    7  * of the License, or (at your option) any later version.
    8  *
    9  * This program is distributed in the hope that it will be useful,
   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12  * GNU General Public License for more details.
   13  *
   14  * You should have received a copy of the GNU General Public License
   15  * along with this program; if not, write to the Free Software
   16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
   17  *
   18  * This code is a complete clean re-write of the stress tool by
   19  * Colin Ian King <colin.king@canonical.com> and attempts to be
   20  * backwardly compatible with the stress tool by Amos Waterland
   21  * <apw@rossby.metr.ou.edu> but has more stress tests and more
   22  * functionality.
   23  *
   24  */
   25 #include "stress-ng.h"
   26 
   27 #if defined(HAVE_LINUX_SECCOMP_H) &&    \
   28     defined(HAVE_LINUX_AUDIT_H) &&  \
   29     defined(HAVE_LINUX_FILTER_H) && \
   30     defined(HAVE_MPROTECT) &&       \
   31     defined(HAVE_SYS_PRCTL_H)
   32 
   33 #define SYSCALL_NR  (offsetof(struct seccomp_data, nr))
   34 
   35 #define ALLOW_SYSCALL(syscall)                  \
   36     BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_##syscall, 0, 1),  \
   37     BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
   38 
   39 #define PAGES       (16)
   40 #define TRACK_SIGCOUNT  (0)
   41 #define EXIT_TRAPPED    (255)
   42 
   43 typedef void(*stress_opcode_func)(uint8_t *ops_begin, uint8_t *ops_end, uint32_t *op);
   44 
   45 typedef struct {
   46         const char *name;
   47         const stress_opcode_func func;
   48 } stress_opcode_method_info_t;
   49 
   50 static const int sigs[] = {
   51 #if defined(SIGILL)
   52     SIGILL,
   53 #endif
   54 #if defined(SIGTRAP)
   55     SIGTRAP,
   56 #endif
   57 #if defined(SIGFPE)
   58     SIGFPE,
   59 #endif
   60 #if defined(SIGBUS)
   61     SIGBUS,
   62 #endif
   63 #if defined(SIGSEGV)
   64     SIGSEGV,
   65 #endif
   66 #if defined(SIGIOT)
   67     SIGIOT,
   68 #endif
   69 #if defined(SIGEMT)
   70     SIGEMT,
   71 #endif
   72 #if defined(SIGALRM)
   73     SIGALRM,
   74 #endif
   75 #if defined(SIGINT)
   76     SIGINT,
   77 #endif
   78 #if defined(SIGHUP)
   79     SIGHUP,
   80 #endif
   81 #if defined(SIGSYS)
   82     SIGSYS
   83 #endif
   84 };
   85 
   86 #if defined(HAVE_LINUX_SECCOMP_H) && defined(SECCOMP_SET_MODE_FILTER)
   87 static struct sock_filter filter[] = {
   88     BPF_STMT(BPF_LD+BPF_W+BPF_ABS, SYSCALL_NR),
   89 #if defined(__NR_exit_group)
   90     ALLOW_SYSCALL(exit_group),
   91 #endif
   92     BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_TRAP)
   93 };
   94 
   95 static struct sock_fprog prog = {
   96         .len = (unsigned short)SIZEOF_ARRAY(filter),
   97         .filter = filter
   98 };
   99 
  100 #endif
  101 
  102 #if defined(NSIG)
  103 #define MAX_SIGS    (NSIG)
  104 #elif defined(_NSIG)
  105 #define MAX_SIGS    (_NSIG)
  106 #else
  107 #define MAX_SIGS    (256)
  108 #endif
  109 
  110 #if TRACK_SIGCOUNT
  111 static uint64_t *sig_count;
  112 #endif
  113 
  114 static void MLOCKED_TEXT stress_badhandler(int signum)
  115 {
  116 #if TRACK_SIGCOUNT
  117     if (signum < MAX_SIGS)
  118         sig_count[signum]++;
  119 #else
  120     (void)signum;
  121 #endif
  122     _exit(1);
  123 }
  124 
  125 static inline uint32_t reverse32(register uint64_t x)
  126 {
  127     x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
  128     x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
  129     x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
  130     x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));
  131     return((x >> 16) | (x << 16));
  132 }
  133 
  134 static void stress_opcode_random(
  135     uint8_t *ops_begin,
  136     uint8_t *ops_end,
  137     uint32_t *op)
  138 {
  139     register uint8_t *ops = (uint8_t *)ops_begin;
  140     (void)op;
  141 
  142     while (ops < ops_end)
  143         *(ops++) = mwc8();
  144 }
  145 
  146 static void stress_opcode_inc(
  147     uint8_t *ops_begin,
  148     uint8_t *ops_end,
  149     uint32_t *op)
  150 {
  151     register uint32_t tmp = *op;
  152     register uint32_t *ops = (uint32_t *)ops_begin;
  153 
  154     while (ops < (uint32_t *)ops_end)
  155         *(ops++) = tmp++;
  156 
  157     *op = tmp;
  158 }
  159 
  160 static void stress_opcode_mixed(
  161     uint8_t *ops_begin,
  162     uint8_t *ops_end,
  163     uint32_t *op)
  164 {
  165     register uint32_t tmp = *op;
  166     register uint32_t *ops = (uint32_t *)ops_begin;
  167 
  168     while (ops < (uint32_t *)ops_end) {
  169         register uint32_t rnd = mwc32();
  170 
  171         *(ops++) = tmp;
  172         *(ops++) = tmp ^ 0xffffffff;    /* Inverted */
  173         *(ops++) = ((tmp >> 1) ^ tmp);  /* Gray */
  174         *(ops++) = reverse32(tmp);
  175 
  176         *(ops++) = rnd;
  177         *(ops++) = rnd ^ 0xffffffff;
  178         *(ops++) = ((rnd >> 1) ^ rnd);
  179         *(ops++) = reverse32(rnd);
  180     }
  181     *op = tmp;
  182 }
  183 
  184 static void stress_opcode_text(
  185     uint8_t *ops_begin,
  186     uint8_t *ops_end,
  187     uint32_t *op)
  188 {
  189     char *text_start, *text_end;
  190     const size_t ops_len = ops_end - ops_begin;
  191     const size_t text_len = stress_text_addr(&text_start, &text_end) - 8;
  192     uint8_t *ops;
  193     size_t offset;
  194 
  195     if (text_len < ops_len) {
  196         stress_opcode_random(ops_begin, ops_end, op);
  197         return;
  198     }
  199 
  200     offset = mwc64() % (text_len - ops_len);
  201     offset &= ~(0x7ULL);
  202 
  203     (void)memcpy(ops_begin, text_start + offset, ops_len);
  204     for (ops = ops_begin; ops < ops_end; ops++) {
  205         uint8_t rnd = mwc8();
  206 
  207         /* 1 in 8 chance of random bit corruption */
  208         if (rnd < 32) {
  209             uint8_t bit = 1 << (rnd & 7);
  210             *ops ^= bit;
  211         }
  212     }
  213 }
  214 
  215 static const stress_opcode_method_info_t stress_opcode_methods[] = {
  216     { "random", stress_opcode_random },
  217     { "text",   stress_opcode_text },
  218     { "inc",    stress_opcode_inc },
  219     { "mixed",  stress_opcode_mixed },
  220     { NULL,     NULL }
  221 };
  222 
  223 /*
  224  *  stress_set_opcode_method()
  225  *      set default opcode stress method
  226  */
  227 int stress_set_opcode_method(const char *name)
  228 {
  229     stress_opcode_method_info_t const *info;
  230 
  231     for (info = stress_opcode_methods; info->func; info++) {
  232         if (!strcmp(info->name, name)) {
  233             set_setting("opcode-method", TYPE_ID_UINTPTR_T, &info);
  234             return 0;
  235         }
  236     }
  237 
  238     (void)fprintf(stderr, "opcode-method must be one of:");
  239     for (info = stress_opcode_methods; info->func; info++) {
  240         (void)fprintf(stderr, " %s", info->name);
  241     }
  242     (void)fprintf(stderr, "\n");
  243 
  244     return -1;
  245 }
  246 
  247 
  248 /*
  249  *  stress_opcode
  250  *  stress with random opcodes
  251  */
  252 static int stress_opcode(const args_t *args)
  253 {
  254     const size_t page_size = args->page_size;
  255     int rc = EXIT_FAILURE;
  256     uint32_t op = 0;
  257     size_t i;
  258     const stress_opcode_method_info_t *opcode_method = &stress_opcode_methods[0];
  259 #if TRACK_SIGCOUNT
  260     const size_t sig_count_size = MAX_SIGS * sizeof(*sig_count);
  261 #endif
  262 
  263 #if TRACK_SIGCOUNT
  264     sig_count = (uint64_t *)mmap(NULL, sig_count_size, PROT_READ | PROT_WRITE,
  265         MAP_ANONYMOUS | MAP_SHARED, -1, 0);
  266     if (sig_count == MAP_FAILED) {
  267         pr_fail_dbg("mmap");
  268         return EXIT_NO_RESOURCE;
  269     }
  270 #endif
  271 
  272     (void)get_setting("opcode-method", &opcode_method);
  273 
  274     do {
  275         pid_t pid;
  276 
  277         /*
  278          *  Force a new random value so that child always
  279          *  gets a different random value on each fork
  280          */
  281         (void)mwc32();
  282         op += 1024;
  283 again:
  284         if (!g_keep_stressing_flag)
  285             break;
  286         pid = fork();
  287         if (pid < 0) {
  288             if (errno == EAGAIN)
  289                 goto again;
  290 
  291             pr_fail_dbg("fork");
  292             rc = EXIT_NO_RESOURCE;
  293             goto err;
  294         }
  295         if (pid == 0) {
  296             struct itimerval it;
  297             uint8_t *opcodes, *ops_begin, *ops_end;
  298 
  299             /* We don't want bad ops clobbering this region */
  300             stress_unmap_shared();
  301 
  302             /* We don't want core dumps either */
  303             stress_process_dumpable(false);
  304 
  305             /* Drop all capabilities */
  306             if (stress_drop_capabilities(args->name) < 0) {
  307                 _exit(EXIT_NO_RESOURCE);
  308             }
  309             for (i = 0; i < SIZEOF_ARRAY(sigs); i++) {
  310                 if (stress_sighandler(args->name, sigs[i], stress_badhandler, NULL) < 0)
  311                     _exit(EXIT_FAILURE);
  312             }
  313 
  314             opcodes = mmap(NULL, page_size * PAGES, PROT_READ | PROT_WRITE,
  315                 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  316             if (opcodes == MAP_FAILED) {
  317                 pr_fail_dbg("mmap");
  318                 _exit(EXIT_NO_RESOURCE);
  319             }
  320             /* Force pages resident */
  321             (void)memset(opcodes, 0x00, page_size * PAGES);
  322 
  323             ops_begin = opcodes + page_size;
  324             ops_end = opcodes + (page_size * (PAGES - 1));
  325 
  326             (void)mprotect(opcodes, page_size, PROT_NONE);
  327             (void)mprotect(ops_end, page_size, PROT_NONE);
  328             (void)mprotect(ops_begin, page_size, PROT_WRITE);
  329 
  330             opcode_method->func(ops_begin, ops_end, &op);
  331 
  332             (void)mprotect(ops_begin, page_size, PROT_READ | PROT_EXEC);
  333             shim_clear_cache((char *)ops_begin, (char *)ops_end);
  334             (void)setpgid(0, g_pgrp);
  335             stress_parent_died_alarm();
  336 
  337             /*
  338              * Force abort if the opcodes magically
  339              * do an infinite loop
  340              */
  341             it.it_interval.tv_sec = 0;
  342             it.it_interval.tv_usec = 50000;
  343             it.it_value.tv_sec = 0;
  344             it.it_value.tv_usec = 50000;
  345             if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
  346                 pr_fail_dbg("setitimer");
  347                 _exit(EXIT_NO_RESOURCE);
  348             }
  349 
  350             for (i = 0; i < 1024; i++) {
  351 #if defined(HAVE_LINUX_SECCOMP_H) && defined(SECCOMP_SET_MODE_FILTER)
  352                 /*
  353                  * Limit syscall using seccomp
  354                  */
  355                 (void)shim_seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog);
  356 #endif
  357                 ((void (*)(void))(ops_begin + i))();
  358             }
  359 
  360             //(void)munmap(opcodes, page_size * PAGES);
  361             _exit(0);
  362         }
  363         if (pid > 0) {
  364             int ret, status;
  365 
  366             ret = waitpid(pid, &status, 0);
  367             if (ret < 0) {
  368                 if (errno != EINTR)
  369                     pr_dbg("%s: waitpid(): errno=%d (%s)\n",
  370                         args->name, errno, strerror(errno));
  371                 (void)kill(pid, SIGTERM);
  372                 (void)kill(pid, SIGKILL);
  373                 (void)waitpid(pid, &status, 0);
  374             }
  375             inc_counter(args);
  376         }
  377     } while (keep_stressing());
  378 
  379     rc = EXIT_SUCCESS;
  380 
  381 #if TRACK_SIGCOUNT
  382     for (i = 0; i < MAX_SIGS; i++) {
  383         if (sig_count[i]) {
  384             pr_dbg("%s: %-25.25s: %" PRIu64 "\n",
  385                 args->name, strsignal(i), sig_count[i]);
  386         }
  387     }
  388 #endif
  389 err:
  390 #if TRACK_SIGCOUNT
  391     (void)munmap(sig_count, sig_count_size);
  392 #endif
  393     return rc;
  394 }
  395 
  396 static void stress_opcode_set_default(void)
  397 {
  398         stress_set_opcode_method("random");
  399 }
  400 
  401 stressor_info_t stress_opcode_info = {
  402     .stressor = stress_opcode,
  403         .set_default = stress_opcode_set_default,
  404     .class = CLASS_CPU | CLASS_OS
  405 };
  406 #else
  407 
  408 int stress_set_opcode_method(const char *name)
  409 {
  410     (void)name;
  411 
  412     (void)fprintf(stderr, "opcode-method not implemented");
  413 
  414     return -1;
  415 }
  416 
  417 stressor_info_t stress_opcode_info = {
  418     .stressor = stress_not_implemented,
  419     .class = CLASS_CPU | CLASS_OS
  420 };
  421 #endif