1/* mpxrt-utils.c -*-C++-*- 2 * 3 ************************************************************************* 4 * 5 * @copyright 6 * Copyright (C) 2014, Intel Corporation 7 * All rights reserved. 8 * 9 * @copyright 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 14 * * Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * * Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * * Neither the name of Intel Corporation nor the names of its 21 * contributors may be used to endorse or promote products derived 22 * from this software without specific prior written permission. 23 * 24 * @copyright 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 30 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 31 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 32 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 33 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 35 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 * 38 **************************************************************************/ 39 40#define __STDC_FORMAT_MACROS 41#include "config.h" 42#include <inttypes.h> 43#include <unistd.h> 44#include <stdio.h> 45#include <stdarg.h> 46#include <stdlib.h> 47#include <string.h> 48#include <limits.h> 49#include <pthread.h> 50#include "mpxrt-utils.h" 51 52#ifndef HAVE_SECURE_GETENV 53#define secure_getenv __secure_getenv 54#endif 55 56#define MPX_RT_OUT "CHKP_RT_OUT_FILE" 57#define MPX_RT_ERR "CHKP_RT_ERR_FILE" 58#define MPX_RT_VERBOSE "CHKP_RT_VERBOSE" 59#define MPX_RT_VERBOSE_DEFAULT VERB_BR 60#define MPX_RT_MODE "CHKP_RT_MODE" 61#define MPX_RT_MODE_DEFAULT MPX_RT_COUNT 62#define MPX_RT_MODE_DEFAULT_STR "count" 63#define MPX_RT_HELP "CHKP_RT_HELP" 64#define MPX_RT_ADDPID "CHKP_RT_ADDPID" 65#define MPX_RT_BNDPRESERVE "CHKP_RT_BNDPRESERVE" 66#define MPX_RT_BNDPRESERVE_DEFAULT 0 67#define MPX_RT_PRINT_SUMMARY "CHKP_RT_PRINT_SUMMARY" 68 69#define MAX_FILE_NAME PATH_MAX 70 71typedef struct env_var_s { 72 char *env_name; 73 char *env_val; 74 struct env_var_s *next; 75} env_var_t; 76 77typedef struct { 78 env_var_t *first; 79 env_var_t *last; 80} env_var_list_t; 81 82/* Following vars are initialized at process startup only 83 and thus are considered to be thread safe. */ 84static int summary; 85static int add_pid; 86static mpx_rt_mode_t mode; 87static env_var_list_t env_var_list; 88static verbose_type verbose_val; 89static FILE *out; 90static FILE *err; 91static char out_name[MAX_FILE_NAME]; 92static char err_name[MAX_FILE_NAME]; 93 94/* Following vars are read at process finalization only. 95 All write accesses use the same value and thus are 96 considered to be thread safe. */ 97static int out_file_dirty; 98static int err_file_dirty; 99static int files_overwritten; 100 101/* Mutex used to sync output. */ 102static pthread_mutex_t lock; 103 104static void * 105malloc_check (size_t size) 106{ 107 void *res = malloc (size); 108 if (!res) 109 __mpxrt_print (VERB_ERROR, "Couldn't allocate %zu bytes.", size); 110 else 111 memset (res, 0, size); 112 return res; 113} 114 115static void 116env_var_list_add (const char* env, const char* val) 117{ 118 env_var_t* n; 119 120 if (val == 0) 121 return; 122 123 n = (env_var_t *)malloc_check (sizeof (env_var_t)); 124 if (!n) 125 return; 126 127 if (env_var_list.first == 0) 128 env_var_list.first = n; 129 130 if (env_var_list.last) 131 env_var_list.last->next = n; 132 133 env_var_list.last = n; 134 135 n->env_name = (char *)malloc_check (strlen (env) + 1); 136 n->env_val = (char *)malloc_check (strlen (val) + 1); 137 138 if (!n->env_name || !n->env_val) 139 return; 140 141 strcpy (n->env_name, env); 142 strcpy (n->env_val, val); 143} 144 145static void 146set_file_stream (FILE** file, char* file_name, 147 const char* env, FILE* deflt) 148{ 149 int pid; 150 if (env != 0) 151 { 152 if (add_pid) 153 { 154 pid = getpid (); 155 snprintf (file_name, MAX_FILE_NAME, "%s.%d", env, pid); 156 } 157 else 158 snprintf (file_name, MAX_FILE_NAME, "%s", env); 159 160 *file = fopen (file_name, "we"); 161 if (*file != 0) 162 return; 163 } 164 *file = deflt; 165} 166 167/* 168 * this function will be called after fork in the child 169 * open new files with pid of the process 170 */ 171static void 172open_child_files () 173{ 174 char *out_env; 175 char *err_env; 176 177 out_env = secure_getenv (MPX_RT_OUT); 178 err_env = secure_getenv (MPX_RT_ERR); 179 180 if (add_pid == 0 && (out_env != 0 || err_env != 0)) 181 { 182 __mpxrt_print (VERB_ERROR, "MPX RUNTIME WARNING: out/err files are " 183 "overwritten in new processes since %s was not set.\n", 184 MPX_RT_ADDPID); 185 files_overwritten = 1; 186 } 187 188 set_file_stream (&out, out_name, out_env, stdout); 189 if (out_env == 0 || err_env == 0 || (strcmp (out_env, err_env) != 0)) 190 set_file_stream (&err, err_name, err_env, stderr); 191 else 192 /* in case we get the same file name for err and out */ 193 err = out; 194} 195 196/* 197 * this function is called after fork in the parent 198 */ 199static void 200at_fork_check (void) 201{ 202 char *out_env; 203 char *err_env; 204 205 out_env = secure_getenv (MPX_RT_OUT); 206 err_env = secure_getenv (MPX_RT_ERR); 207 208 if (add_pid == 0 && (out_env != 0 || err_env != 0)) 209 files_overwritten = 1; 210} 211 212static mpx_rt_mode_t 213set_mpx_rt_mode (const char *env) 214{ 215 if (env == 0) 216 return MPX_RT_MODE_DEFAULT; 217 else if (strcmp (env, "stop") == 0) 218 return MPX_RT_STOP; 219 else if (strcmp (env,"count") == 0) 220 return MPX_RT_COUNT; 221 { 222 __mpxrt_print (VERB_ERROR, "Illegal value '%s' for %s. Legal values are" 223 "[stop | count]\nUsing default value %s\n", 224 env, MPX_RT_MODE, MPX_RT_MODE_DEFAULT_STR); 225 return MPX_RT_MODE_DEFAULT; 226 } 227} 228 229static void 230print_help (void) 231{ 232 fprintf (out, "MPX Runtime environment variables help.\n"); 233 234 fprintf (out, "%s \t set output file for info & debug [default: stdout]\n", 235 MPX_RT_OUT); 236 fprintf (out, "%s \t set output file for error [default: stderr]\n", 237 MPX_RT_ERR); 238 fprintf (out, "%s \t set verbosity type [default: %d]\n" 239 "\t\t\t 0 - print only internal run time errors\n" 240 "\t\t\t 1 - just print summary\n" 241 "\t\t\t 2 - print summary and bound violation information\n " 242 "\t\t\t 3 - print debug information\n", 243 MPX_RT_VERBOSE, MPX_RT_VERBOSE_DEFAULT); 244 fprintf (out, "%s \t\t set MPX runtime behavior on #BR exception." 245 " [stop | count]\n" 246 "\t\t\t [default: %s]\n", MPX_RT_MODE, MPX_RT_MODE_DEFAULT_STR); 247 fprintf (out, "%s \t\t generate out,err file for each process.\n" 248 "\t\t\t generated file will be MPX_RT_{OUT,ERR}_FILE.pid\n" 249 "\t\t\t [default: no]\n", MPX_RT_ADDPID); 250 fprintf (out, "%s \t set value for BNDPRESERVE bit.\n" 251 "\t\t\t BNDPRESERVE = 0 flush bounds on unprefixed call/ret/jmp\n" 252 "\t\t\t BNDPRESERVE = 1 do NOT flush bounds\n" 253 "\t\t\t [default: %d]\n", MPX_RT_BNDPRESERVE, 254 MPX_RT_BNDPRESERVE_DEFAULT); 255 fprintf (out, "%s \t print summary at the end of the run\n" 256 "\t\t\t [default: no]\n", MPX_RT_PRINT_SUMMARY); 257 258 fprintf (out, "%s \t\t print this help and exit.\n" 259 "\t\t\t [default: no]\n", MPX_RT_HELP); 260 261 exit (0); 262} 263 264static void 265validate_bndpreserve (const char *env, int *bndpreserve) 266{ 267 if (env == 0) 268 bndpreserve = MPX_RT_BNDPRESERVE_DEFAULT; 269 else if (strcmp (env, "0") == 0) 270 *bndpreserve = 0; 271 else if (strcmp (env, "1") == 0) 272 *bndpreserve = 1; 273 else 274 { 275 __mpxrt_print (VERB_ERROR, "Illegal value '%s' for %s. Legal values " 276 "are [0 | 1]\nUsing default value %d\n", 277 env, MPX_RT_BNDPRESERVE, MPX_RT_BNDPRESERVE_DEFAULT); 278 *bndpreserve = MPX_RT_BNDPRESERVE_DEFAULT; 279 } 280} 281 282static verbose_type 283init_verbose_val (const char *env) 284{ 285 if (env == 0) 286 return MPX_RT_VERBOSE_DEFAULT; 287 else if (strcmp(env, "0") == 0) 288 return VERB_ERROR; 289 else if (strcmp(env, "1") == 0) 290 return VERB_INFO; 291 else if (strcmp(env, "2") == 0) 292 return VERB_BR; 293 else if (strcmp(env, "3") == 0) 294 return VERB_DEBUG; 295 296 __mpxrt_print (VERB_ERROR, "Illegal value '%s' for %s. Legal values " 297 "are [0..3]\nUsing default value %d\n", 298 env, MPX_RT_VERBOSE, (int)MPX_RT_VERBOSE_DEFAULT); 299 300 return MPX_RT_VERBOSE_DEFAULT; 301} 302 303static void 304env_var_print_summary (void) 305{ 306 env_var_t* node; 307 308 __mpxrt_print (VERB_DEBUG, "Used environment variables:\n"); 309 310 node = env_var_list.first; 311 while (node != 0) 312 { 313 __mpxrt_print (VERB_DEBUG, " %s = %s\n", node->env_name, node->env_val); 314 node = node->next; 315 } 316} 317 318/* Return 1 if passes env var value should enable feature. */ 319 320static int 321check_yes (const char *val) 322{ 323 return val && (!strcmp (val, "yes") || !strcmp (val, "1")); 324} 325 326void 327__mpxrt_init_env_vars (int* bndpreserve) 328{ 329 char *out_env; 330 char *err_env; 331 char *env; 332 333 pthread_mutex_init (&lock, NULL); 334 335 out_env = secure_getenv (MPX_RT_OUT); 336 env_var_list_add (MPX_RT_OUT, out_env); 337 338 err_env = secure_getenv (MPX_RT_ERR); 339 env_var_list_add (MPX_RT_ERR, err_env); 340 341 env = secure_getenv (MPX_RT_ADDPID); 342 env_var_list_add (MPX_RT_ADDPID, env); 343 add_pid = check_yes (env); 344 345 set_file_stream (&out, out_name, out_env, stdout); 346 if (out_env == 0 || err_env == 0 || (strcmp (out_env, err_env) != 0)) 347 set_file_stream (&err, err_name, err_env, stderr); 348 else 349 /* in case we get the same file name for err and out */ 350 err = out; 351 352 env = secure_getenv (MPX_RT_VERBOSE); 353 env_var_list_add (MPX_RT_VERBOSE, env); 354 verbose_val = init_verbose_val (env); 355 356 env = secure_getenv (MPX_RT_MODE); 357 env_var_list_add (MPX_RT_MODE, env); 358 mode = set_mpx_rt_mode (env); 359 360 env = secure_getenv (MPX_RT_BNDPRESERVE); 361 env_var_list_add (MPX_RT_BNDPRESERVE, env); 362 validate_bndpreserve (env, bndpreserve); 363 364 env = secure_getenv (MPX_RT_PRINT_SUMMARY); 365 env_var_list_add (MPX_RT_PRINT_SUMMARY, env); 366 summary = check_yes (env); 367 368 env = secure_getenv (MPX_RT_HELP); 369 if (check_yes (env)) 370 print_help (); 371 372 /* 373 * at fork - create new files for output and err according 374 * to the env vars. 375 */ 376 pthread_atfork (NULL, at_fork_check, open_child_files); 377 378 env_var_print_summary (); 379} 380 381void 382__mpxrt_utils_free (void) 383{ 384 if (files_overwritten) 385 __mpxrt_print (VERB_INFO, "\nMPX RUNTIME WARNING: out/err files are" 386 " overwritten in new processes since %s was not set.\n", 387 MPX_RT_ADDPID); 388 389 if (out != stdout) 390 { 391 fclose (out); 392 if (out_file_dirty != 1) 393 remove (out_name); 394 } 395 396 if (err != stderr) 397 { 398 fclose (err); 399 if (err_file_dirty != 1) 400 remove (err_name); 401 } 402 403 pthread_mutex_destroy (&lock); 404} 405 406void 407__mpxrt_write_uint (verbose_type vt, uint64_t val, unsigned base) 408{ 409 static const char digits[] = { 410 '0', '1', '2', '3', '4', '5', '6', '7', 411 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; 412 char str[65]; 413 int pos = 64;; 414 415 str[pos--] = 0; 416 417 if (vt > verbose_val || base <= 1 || base > sizeof (digits)) 418 return; 419 420 if (val < base) 421 str[pos--] = digits[val]; 422 else 423 while (val) 424 { 425 str[pos--] = digits[val % base]; 426 val = val / base; 427 } 428 429 __mpxrt_write (vt, str + pos + 1); 430} 431 432void 433__mpxrt_write (verbose_type vt, const char* str) 434{ 435 va_list argp; 436 FILE *print_to; 437 438 if (vt > verbose_val) 439 return; 440 441 if (vt == VERB_ERROR) 442 { 443 print_to = err; 444 err_file_dirty = 1; 445 } 446 else 447 { 448 print_to = out; 449 out_file_dirty = 1; 450 } 451 pthread_mutex_lock (&lock); 452 write (fileno (print_to), str, strlen (str)); 453 pthread_mutex_unlock (&lock); 454 va_end (argp); 455} 456 457void 458__mpxrt_print (verbose_type vt, const char* frmt, ...) 459{ 460 va_list argp; 461 FILE *print_to; 462 463 if (vt > verbose_val) 464 return; 465 466 va_start (argp, frmt); 467 if (vt == VERB_ERROR) 468 { 469 print_to = err; 470 err_file_dirty = 1; 471 } 472 else 473 { 474 print_to = out; 475 out_file_dirty = 1; 476 } 477 pthread_mutex_lock (&lock); 478 vfprintf (print_to, frmt, argp); 479 fflush (print_to); 480 pthread_mutex_unlock (&lock); 481 va_end (argp); 482} 483 484mpx_rt_mode_t 485__mpxrt_mode (void) 486{ 487 return mode; 488} 489 490void 491__mpxrt_print_summary (uint64_t num_brs, uint64_t l1_size) 492{ 493 494 if (summary == 0) 495 return; 496 497 out_file_dirty = 1; 498 499 pthread_mutex_lock (&lock); 500 fprintf (out, "MPX runtime summary:\n"); 501 fprintf (out, " Number of bounds violations: %" PRIu64 ".\n", num_brs); 502 fprintf (out, " Size of allocated L1: %" PRIu64 "B\n", l1_size); 503 fflush (out); 504 pthread_mutex_unlock (&lock); 505} 506