2016-12-24 François Dumont <fdumont@gcc.gnu.org>
[official-gcc.git] / libmpx / mpxrt / mpxrt-utils.c
blob057a3553cb5b1f03eaeca64d42c5e72164b50922
1 /* mpxrt-utils.c -*-C++-*-
3 *************************************************************************
5 * @copyright
6 * Copyright (C) 2014, Intel Corporation
7 * All rights reserved.
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:
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.
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.
38 **************************************************************************/
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"
52 #ifndef HAVE_SECURE_GETENV
53 #define secure_getenv __secure_getenv
54 #endif
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"
69 #define MAX_FILE_NAME PATH_MAX
71 typedef struct env_var_s {
72 char *env_name;
73 char *env_val;
74 struct env_var_s *next;
75 } env_var_t;
77 typedef struct {
78 env_var_t *first;
79 env_var_t *last;
80 } env_var_list_t;
82 /* Following vars are initialized at process startup only
83 and thus are considered to be thread safe. */
84 static int summary;
85 static int add_pid;
86 static mpx_rt_mode_t mode;
87 static env_var_list_t env_var_list;
88 static verbose_type verbose_val;
89 static FILE *out;
90 static FILE *err;
91 static char out_name[MAX_FILE_NAME];
92 static char err_name[MAX_FILE_NAME];
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. */
97 static int out_file_dirty;
98 static int err_file_dirty;
99 static int files_overwritten;
101 /* Mutex used to sync output. */
102 static pthread_mutex_t lock;
104 static void *
105 malloc_check (size_t size)
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;
115 static void
116 env_var_list_add (const char* env, const char* val)
118 env_var_t* n;
120 if (val == 0)
121 return;
123 n = (env_var_t *)malloc_check (sizeof (env_var_t));
124 if (!n)
125 return;
127 if (env_var_list.first == 0)
128 env_var_list.first = n;
130 if (env_var_list.last)
131 env_var_list.last->next = n;
133 env_var_list.last = n;
135 n->env_name = (char *)malloc_check (strlen (env) + 1);
136 n->env_val = (char *)malloc_check (strlen (val) + 1);
138 if (!n->env_name || !n->env_val)
139 return;
141 strcpy (n->env_name, env);
142 strcpy (n->env_val, val);
145 static void
146 set_file_stream (FILE** file, char* file_name,
147 const char* env, FILE* deflt)
149 int pid;
150 if (env != 0)
152 if (add_pid)
154 pid = getpid ();
155 snprintf (file_name, MAX_FILE_NAME, "%s.%d", env, pid);
157 else
158 snprintf (file_name, MAX_FILE_NAME, "%s", env);
160 *file = fopen (file_name, "we");
161 if (*file != 0)
162 return;
164 *file = deflt;
168 * this function will be called after fork in the child
169 * open new files with pid of the process
171 static void
172 open_child_files ()
174 char *out_env;
175 char *err_env;
177 out_env = secure_getenv (MPX_RT_OUT);
178 err_env = secure_getenv (MPX_RT_ERR);
180 if (add_pid == 0 && (out_env != 0 || err_env != 0))
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;
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;
197 * this function is called after fork in the parent
199 static void
200 at_fork_check (void)
202 char *out_env;
203 char *err_env;
205 out_env = secure_getenv (MPX_RT_OUT);
206 err_env = secure_getenv (MPX_RT_ERR);
208 if (add_pid == 0 && (out_env != 0 || err_env != 0))
209 files_overwritten = 1;
212 static mpx_rt_mode_t
213 set_mpx_rt_mode (const char *env)
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;
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;
229 static void
230 print_help (void)
232 fprintf (out, "MPX Runtime environment variables help.\n");
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);
258 fprintf (out, "%s \t\t print this help and exit.\n"
259 "\t\t\t [default: no]\n", MPX_RT_HELP);
261 exit (0);
264 static void
265 validate_bndpreserve (const char *env, int *bndpreserve)
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
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;
282 static verbose_type
283 init_verbose_val (const char *env)
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;
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);
300 return MPX_RT_VERBOSE_DEFAULT;
303 static void
304 env_var_print_summary (void)
306 env_var_t* node;
308 __mpxrt_print (VERB_DEBUG, "Used environment variables:\n");
310 node = env_var_list.first;
311 while (node != 0)
313 __mpxrt_print (VERB_DEBUG, " %s = %s\n", node->env_name, node->env_val);
314 node = node->next;
318 /* Return 1 if passes env var value should enable feature. */
320 static int
321 check_yes (const char *val)
323 return val && (!strcmp (val, "yes") || !strcmp (val, "1"));
326 void
327 __mpxrt_init_env_vars (int* bndpreserve)
329 char *out_env;
330 char *err_env;
331 char *env;
333 pthread_mutex_init (&lock, NULL);
335 out_env = secure_getenv (MPX_RT_OUT);
336 env_var_list_add (MPX_RT_OUT, out_env);
338 err_env = secure_getenv (MPX_RT_ERR);
339 env_var_list_add (MPX_RT_ERR, err_env);
341 env = secure_getenv (MPX_RT_ADDPID);
342 env_var_list_add (MPX_RT_ADDPID, env);
343 add_pid = check_yes (env);
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;
352 env = secure_getenv (MPX_RT_VERBOSE);
353 env_var_list_add (MPX_RT_VERBOSE, env);
354 verbose_val = init_verbose_val (env);
356 env = secure_getenv (MPX_RT_MODE);
357 env_var_list_add (MPX_RT_MODE, env);
358 mode = set_mpx_rt_mode (env);
360 env = secure_getenv (MPX_RT_BNDPRESERVE);
361 env_var_list_add (MPX_RT_BNDPRESERVE, env);
362 validate_bndpreserve (env, bndpreserve);
364 env = secure_getenv (MPX_RT_PRINT_SUMMARY);
365 env_var_list_add (MPX_RT_PRINT_SUMMARY, env);
366 summary = check_yes (env);
368 env = secure_getenv (MPX_RT_HELP);
369 if (check_yes (env))
370 print_help ();
373 * at fork - create new files for output and err according
374 * to the env vars.
376 pthread_atfork (NULL, at_fork_check, open_child_files);
378 env_var_print_summary ();
381 void
382 __mpxrt_utils_free (void)
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);
389 if (out != stdout)
391 fclose (out);
392 if (out_file_dirty != 1)
393 remove (out_name);
396 if (err != stderr)
398 fclose (err);
399 if (err_file_dirty != 1)
400 remove (err_name);
403 pthread_mutex_destroy (&lock);
406 void
407 __mpxrt_write_uint (verbose_type vt, uint64_t val, unsigned base)
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;;
415 str[pos--] = 0;
417 if (vt > verbose_val || base <= 1 || base > sizeof (digits))
418 return;
420 if (val < base)
421 str[pos--] = digits[val];
422 else
423 while (val)
425 str[pos--] = digits[val % base];
426 val = val / base;
429 __mpxrt_write (vt, str + pos + 1);
432 void
433 __mpxrt_write (verbose_type vt, const char* str)
435 va_list argp;
436 FILE *print_to;
438 if (vt > verbose_val)
439 return;
441 if (vt == VERB_ERROR)
443 print_to = err;
444 err_file_dirty = 1;
446 else
448 print_to = out;
449 out_file_dirty = 1;
451 pthread_mutex_lock (&lock);
452 write (fileno (print_to), str, strlen (str));
453 pthread_mutex_unlock (&lock);
454 va_end (argp);
457 void
458 __mpxrt_print (verbose_type vt, const char* frmt, ...)
460 va_list argp;
461 FILE *print_to;
463 if (vt > verbose_val)
464 return;
466 va_start (argp, frmt);
467 if (vt == VERB_ERROR)
469 print_to = err;
470 err_file_dirty = 1;
472 else
474 print_to = out;
475 out_file_dirty = 1;
477 pthread_mutex_lock (&lock);
478 vfprintf (print_to, frmt, argp);
479 fflush (print_to);
480 pthread_mutex_unlock (&lock);
481 va_end (argp);
484 mpx_rt_mode_t
485 __mpxrt_mode (void)
487 return mode;
490 void
491 __mpxrt_print_summary (uint64_t num_brs, uint64_t l1_size)
494 if (summary == 0)
495 return;
497 out_file_dirty = 1;
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);