Mercurial > hg > CbC > CbC_gcc
diff libmpx/mpxrt/mpxrt-utils.c @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmpx/mpxrt/mpxrt-utils.c Fri Oct 27 22:46:09 2017 +0900 @@ -0,0 +1,551 @@ +/* mpxrt-utils.c -*-C++-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2014, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ + +#define __STDC_FORMAT_MACROS +#include "config.h" +#include <inttypes.h> +#include <unistd.h> +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <pthread.h> +#include "mpxrt-utils.h" + +#ifndef HAVE_SECURE_GETENV +#define secure_getenv __secure_getenv +#endif + +#define MPX_RT_OUT "CHKP_RT_OUT_FILE" +#define MPX_RT_ERR "CHKP_RT_ERR_FILE" +#define MPX_RT_VERBOSE "CHKP_RT_VERBOSE" +#define MPX_RT_VERBOSE_DEFAULT VERB_BR +#define MPX_RT_MODE "CHKP_RT_MODE" +#define MPX_RT_MODE_DEFAULT MPX_RT_COUNT +#define MPX_RT_MODE_DEFAULT_STR "count" +#define MPX_RT_STOP_HANDLER "CHKP_RT_STOP_HANDLER" +#define MPX_RT_STOP_HANDLER_DEFAULT MPX_RT_STOP_HANDLER_ABORT +#define MPX_RT_STOP_HANDLER_DEFAULT_STR "abort" +#define MPX_RT_HELP "CHKP_RT_HELP" +#define MPX_RT_ADDPID "CHKP_RT_ADDPID" +#define MPX_RT_BNDPRESERVE "CHKP_RT_BNDPRESERVE" +#define MPX_RT_BNDPRESERVE_DEFAULT 0 +#define MPX_RT_PRINT_SUMMARY "CHKP_RT_PRINT_SUMMARY" + +#define MAX_FILE_NAME PATH_MAX + +typedef struct env_var_s { + char *env_name; + char *env_val; + struct env_var_s *next; +} env_var_t; + +typedef struct { + env_var_t *first; + env_var_t *last; +} env_var_list_t; + +/* Following vars are initialized at process startup only + and thus are considered to be thread safe. */ +static int summary; +static int add_pid; +static mpx_rt_mode_t mode; +static mpx_rt_stop_mode_handler_t stop_handler; +static env_var_list_t env_var_list; +static verbose_type verbose_val; +static FILE *out; +static FILE *err; +static char out_name[MAX_FILE_NAME]; +static char err_name[MAX_FILE_NAME]; + +/* Following vars are read at process finalization only. + All write accesses use the same value and thus are + considered to be thread safe. */ +static int out_file_dirty; +static int err_file_dirty; +static int files_overwritten; + +/* Mutex used to sync output. */ +static pthread_mutex_t lock; + +static void * +malloc_check (size_t size) +{ + void *res = malloc (size); + if (!res) + __mpxrt_print (VERB_ERROR, "Couldn't allocate %zu bytes.", size); + else + memset (res, 0, size); + return res; +} + +static void +env_var_list_add (const char* env, const char* val) +{ + env_var_t* n; + + if (val == 0) + return; + + n = (env_var_t *)malloc_check (sizeof (env_var_t)); + if (!n) + return; + + if (env_var_list.first == 0) + env_var_list.first = n; + + if (env_var_list.last) + env_var_list.last->next = n; + + env_var_list.last = n; + + n->env_name = (char *)malloc_check (strlen (env) + 1); + n->env_val = (char *)malloc_check (strlen (val) + 1); + + if (!n->env_name || !n->env_val) + return; + + strcpy (n->env_name, env); + strcpy (n->env_val, val); +} + +static void +set_file_stream (FILE** file, char* file_name, + const char* env, FILE* deflt) +{ + int pid; + if (env != 0) + { + if (add_pid) + { + pid = getpid (); + snprintf (file_name, MAX_FILE_NAME, "%s.%d", env, pid); + } + else + snprintf (file_name, MAX_FILE_NAME, "%s", env); + + *file = fopen (file_name, "we"); + if (*file != 0) + return; + } + *file = deflt; +} + +/* + * this function will be called after fork in the child + * open new files with pid of the process + */ +static void +open_child_files () +{ + char *out_env; + char *err_env; + + out_env = secure_getenv (MPX_RT_OUT); + err_env = secure_getenv (MPX_RT_ERR); + + if (add_pid == 0 && (out_env != 0 || err_env != 0)) + { + __mpxrt_print (VERB_ERROR, "MPX RUNTIME WARNING: out/err files are " + "overwritten in new processes since %s was not set.\n", + MPX_RT_ADDPID); + files_overwritten = 1; + } + + set_file_stream (&out, out_name, out_env, stdout); + if (out_env == 0 || err_env == 0 || (strcmp (out_env, err_env) != 0)) + set_file_stream (&err, err_name, err_env, stderr); + else + /* in case we get the same file name for err and out */ + err = out; +} + +/* + * this function is called after fork in the parent + */ +static void +at_fork_check (void) +{ + char *out_env; + char *err_env; + + out_env = secure_getenv (MPX_RT_OUT); + err_env = secure_getenv (MPX_RT_ERR); + + if (add_pid == 0 && (out_env != 0 || err_env != 0)) + files_overwritten = 1; +} + +static mpx_rt_mode_t +set_mpx_rt_mode (const char *env) +{ + if (env == 0) + return MPX_RT_MODE_DEFAULT; + else if (strcmp (env, "stop") == 0) + return MPX_RT_STOP; + else if (strcmp (env,"count") == 0) + return MPX_RT_COUNT; + { + __mpxrt_print (VERB_ERROR, "Illegal value '%s' for %s. Legal values are" + "[stop | count]\nUsing default value %s\n", + env, MPX_RT_MODE, MPX_RT_MODE_DEFAULT_STR); + return MPX_RT_MODE_DEFAULT; + } +} + +static mpx_rt_stop_mode_handler_t +set_mpx_rt_stop_handler (const char *env) +{ + if (env == 0) + return MPX_RT_STOP_HANDLER_DEFAULT; + else if (strcmp (env, "abort") == 0) + return MPX_RT_STOP_HANDLER_ABORT; + else if (strcmp (env, "exit") == 0) + return MPX_RT_STOP_HANDLER_EXIT; + { + __mpxrt_print (VERB_ERROR, "Illegal value '%s' for %s. Legal values are" + "[abort | exit]\nUsing default value %s\n", + env, MPX_RT_STOP_HANDLER, MPX_RT_STOP_HANDLER_DEFAULT); + return MPX_RT_STOP_HANDLER_DEFAULT; + } +} + +static void +print_help (void) +{ + fprintf (out, "MPX Runtime environment variables help.\n"); + + fprintf (out, "%s \t set output file for info & debug [default: stdout]\n", + MPX_RT_OUT); + fprintf (out, "%s \t set output file for error [default: stderr]\n", + MPX_RT_ERR); + fprintf (out, "%s \t set verbosity type [default: %d]\n" + "\t\t\t 0 - print only internal run time errors\n" + "\t\t\t 1 - just print summary\n" + "\t\t\t 2 - print summary and bound violation information\n " + "\t\t\t 3 - print debug information\n", + MPX_RT_VERBOSE, MPX_RT_VERBOSE_DEFAULT); + fprintf (out, "%s \t\t set MPX runtime behavior on #BR exception." + " [stop | count]\n" + "\t\t\t [default: %s]\n", MPX_RT_MODE, MPX_RT_MODE_DEFAULT_STR); + fprintf (out, "%s \t set the handler function MPX runtime will call\n" + "\t\t\t on #BR exception when %s is set to \'stop\'." + " [abort | exit]\n" + "\t\t\t [default: %s]\n", MPX_RT_STOP_HANDLER, MPX_RT_MODE, + MPX_RT_STOP_HANDLER_DEFAULT_STR); + fprintf (out, "%s \t\t generate out,err file for each process.\n" + "\t\t\t generated file will be MPX_RT_{OUT,ERR}_FILE.pid\n" + "\t\t\t [default: no]\n", MPX_RT_ADDPID); + fprintf (out, "%s \t set value for BNDPRESERVE bit.\n" + "\t\t\t BNDPRESERVE = 0 flush bounds on unprefixed call/ret/jmp\n" + "\t\t\t BNDPRESERVE = 1 do NOT flush bounds\n" + "\t\t\t [default: %d]\n", MPX_RT_BNDPRESERVE, + MPX_RT_BNDPRESERVE_DEFAULT); + fprintf (out, "%s \t print summary at the end of the run\n" + "\t\t\t [default: no]\n", MPX_RT_PRINT_SUMMARY); + + fprintf (out, "%s \t\t print this help and exit.\n" + "\t\t\t [default: no]\n", MPX_RT_HELP); + + exit (0); +} + +static void +validate_bndpreserve (const char *env, int *bndpreserve) +{ + if (env == 0) + bndpreserve = MPX_RT_BNDPRESERVE_DEFAULT; + else if (strcmp (env, "0") == 0) + *bndpreserve = 0; + else if (strcmp (env, "1") == 0) + *bndpreserve = 1; + else + { + __mpxrt_print (VERB_ERROR, "Illegal value '%s' for %s. Legal values " + "are [0 | 1]\nUsing default value %d\n", + env, MPX_RT_BNDPRESERVE, MPX_RT_BNDPRESERVE_DEFAULT); + *bndpreserve = MPX_RT_BNDPRESERVE_DEFAULT; + } +} + +static verbose_type +init_verbose_val (const char *env) +{ + if (env == 0) + return MPX_RT_VERBOSE_DEFAULT; + else if (strcmp(env, "0") == 0) + return VERB_ERROR; + else if (strcmp(env, "1") == 0) + return VERB_INFO; + else if (strcmp(env, "2") == 0) + return VERB_BR; + else if (strcmp(env, "3") == 0) + return VERB_DEBUG; + + __mpxrt_print (VERB_ERROR, "Illegal value '%s' for %s. Legal values " + "are [0..3]\nUsing default value %d\n", + env, MPX_RT_VERBOSE, (int)MPX_RT_VERBOSE_DEFAULT); + + return MPX_RT_VERBOSE_DEFAULT; +} + +static void +env_var_print_summary (void) +{ + env_var_t* node; + + __mpxrt_print (VERB_DEBUG, "Used environment variables:\n"); + + node = env_var_list.first; + while (node != 0) + { + __mpxrt_print (VERB_DEBUG, " %s = %s\n", node->env_name, node->env_val); + node = node->next; + } +} + +/* Return 1 if passes env var value should enable feature. */ + +static int +check_yes (const char *val) +{ + return val && (!strcmp (val, "yes") || !strcmp (val, "1")); +} + +void +__mpxrt_init_env_vars (int* bndpreserve) +{ + char *out_env; + char *err_env; + char *env; + + pthread_mutex_init (&lock, NULL); + + out_env = secure_getenv (MPX_RT_OUT); + env_var_list_add (MPX_RT_OUT, out_env); + + err_env = secure_getenv (MPX_RT_ERR); + env_var_list_add (MPX_RT_ERR, err_env); + + env = secure_getenv (MPX_RT_ADDPID); + env_var_list_add (MPX_RT_ADDPID, env); + add_pid = check_yes (env); + + set_file_stream (&out, out_name, out_env, stdout); + if (out_env == 0 || err_env == 0 || (strcmp (out_env, err_env) != 0)) + set_file_stream (&err, err_name, err_env, stderr); + else + /* in case we get the same file name for err and out */ + err = out; + + env = secure_getenv (MPX_RT_VERBOSE); + env_var_list_add (MPX_RT_VERBOSE, env); + verbose_val = init_verbose_val (env); + + env = secure_getenv (MPX_RT_MODE); + env_var_list_add (MPX_RT_MODE, env); + mode = set_mpx_rt_mode (env); + + env = secure_getenv (MPX_RT_STOP_HANDLER); + env_var_list_add (MPX_RT_STOP_HANDLER, env); + stop_handler = set_mpx_rt_stop_handler (env); + + env = secure_getenv (MPX_RT_BNDPRESERVE); + env_var_list_add (MPX_RT_BNDPRESERVE, env); + validate_bndpreserve (env, bndpreserve); + + env = secure_getenv (MPX_RT_PRINT_SUMMARY); + env_var_list_add (MPX_RT_PRINT_SUMMARY, env); + summary = check_yes (env); + + env = secure_getenv (MPX_RT_HELP); + if (check_yes (env)) + print_help (); + + /* + * at fork - create new files for output and err according + * to the env vars. + */ + pthread_atfork (NULL, at_fork_check, open_child_files); + + env_var_print_summary (); +} + +void +__mpxrt_utils_free (void) +{ + if (files_overwritten) + __mpxrt_print (VERB_INFO, "\nMPX RUNTIME WARNING: out/err files are" + " overwritten in new processes since %s was not set.\n", + MPX_RT_ADDPID); + + if (out != stdout) + { + fclose (out); + if (out_file_dirty != 1) + remove (out_name); + } + + if (err != stderr) + { + fclose (err); + if (err_file_dirty != 1) + remove (err_name); + } + + pthread_mutex_destroy (&lock); +} + +void +__mpxrt_write_uint (verbose_type vt, uint64_t val, unsigned base) +{ + static const char digits[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + char str[65]; + int pos = 64;; + + str[pos--] = 0; + + if (vt > verbose_val || base <= 1 || base > sizeof (digits)) + return; + + if (val < base) + str[pos--] = digits[val]; + else + while (val) + { + str[pos--] = digits[val % base]; + val = val / base; + } + + __mpxrt_write (vt, str + pos + 1); +} + +void +__mpxrt_write (verbose_type vt, const char* str) +{ + va_list argp; + FILE *print_to; + + if (vt > verbose_val) + return; + + if (vt == VERB_ERROR) + { + print_to = err; + err_file_dirty = 1; + } + else + { + print_to = out; + out_file_dirty = 1; + } + pthread_mutex_lock (&lock); + write (fileno (print_to), str, strlen (str)); + pthread_mutex_unlock (&lock); + va_end (argp); +} + +void +__mpxrt_print (verbose_type vt, const char* frmt, ...) +{ + va_list argp; + FILE *print_to; + + if (vt > verbose_val) + return; + + va_start (argp, frmt); + if (vt == VERB_ERROR) + { + print_to = err; + err_file_dirty = 1; + } + else + { + print_to = out; + out_file_dirty = 1; + } + pthread_mutex_lock (&lock); + vfprintf (print_to, frmt, argp); + fflush (print_to); + pthread_mutex_unlock (&lock); + va_end (argp); +} + +mpx_rt_mode_t +__mpxrt_mode (void) +{ + return mode; +} + +mpx_rt_mode_t +__mpxrt_stop_handler (void) +{ + return stop_handler; +} + +void __attribute__ ((noreturn)) +__mpxrt_stop (void) +{ + if (__mpxrt_stop_handler () == MPX_RT_STOP_HANDLER_ABORT) + abort (); + else if (__mpxrt_stop_handler () == MPX_RT_STOP_HANDLER_EXIT) + exit (255); + __builtin_unreachable (); +} + +void +__mpxrt_print_summary (uint64_t num_brs, uint64_t l1_size) +{ + + if (summary == 0) + return; + + out_file_dirty = 1; + + pthread_mutex_lock (&lock); + fprintf (out, "MPX runtime summary:\n"); + fprintf (out, " Number of bounds violations: %" PRIu64 ".\n", num_brs); + fprintf (out, " Size of allocated L1: %" PRIu64 "B\n", l1_size); + fflush (out); + pthread_mutex_unlock (&lock); +}