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