1 /* mpxrt-utils.c -*-C++-*-
3 *************************************************************************
6 * Copyright (C) 2014, Intel Corporation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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
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.
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
50 #include "mpxrt-utils.h"
52 #ifndef HAVE_SECURE_GETENV
53 #define secure_getenv __secure_getenv
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_STOP_HANDLER "CHKP_RT_STOP_HANDLER"
64 #define MPX_RT_STOP_HANDLER_DEFAULT MPX_RT_STOP_HANDLER_ABORT
65 #define MPX_RT_STOP_HANDLER_DEFAULT_STR "abort"
66 #define MPX_RT_HELP "CHKP_RT_HELP"
67 #define MPX_RT_ADDPID "CHKP_RT_ADDPID"
68 #define MPX_RT_BNDPRESERVE "CHKP_RT_BNDPRESERVE"
69 #define MPX_RT_BNDPRESERVE_DEFAULT 0
70 #define MPX_RT_PRINT_SUMMARY "CHKP_RT_PRINT_SUMMARY"
72 #define MAX_FILE_NAME PATH_MAX
74 typedef struct env_var_s
{
77 struct env_var_s
*next
;
85 /* Following vars are initialized at process startup only
86 and thus are considered to be thread safe. */
89 static mpx_rt_mode_t mode
;
90 static mpx_rt_stop_mode_handler_t stop_handler
;
91 static env_var_list_t env_var_list
;
92 static verbose_type verbose_val
;
95 static char out_name
[MAX_FILE_NAME
];
96 static char err_name
[MAX_FILE_NAME
];
98 /* Following vars are read at process finalization only.
99 All write accesses use the same value and thus are
100 considered to be thread safe. */
101 static int out_file_dirty
;
102 static int err_file_dirty
;
103 static int files_overwritten
;
105 /* Mutex used to sync output. */
106 static pthread_mutex_t lock
;
109 malloc_check (size_t size
)
111 void *res
= malloc (size
);
113 __mpxrt_print (VERB_ERROR
, "Couldn't allocate %zu bytes.", size
);
115 memset (res
, 0, size
);
120 env_var_list_add (const char* env
, const char* val
)
127 n
= (env_var_t
*)malloc_check (sizeof (env_var_t
));
131 if (env_var_list
.first
== 0)
132 env_var_list
.first
= n
;
134 if (env_var_list
.last
)
135 env_var_list
.last
->next
= n
;
137 env_var_list
.last
= n
;
139 n
->env_name
= (char *)malloc_check (strlen (env
) + 1);
140 n
->env_val
= (char *)malloc_check (strlen (val
) + 1);
142 if (!n
->env_name
|| !n
->env_val
)
145 strcpy (n
->env_name
, env
);
146 strcpy (n
->env_val
, val
);
150 set_file_stream (FILE** file
, char* file_name
,
151 const char* env
, FILE* deflt
)
159 snprintf (file_name
, MAX_FILE_NAME
, "%s.%d", env
, pid
);
162 snprintf (file_name
, MAX_FILE_NAME
, "%s", env
);
164 *file
= fopen (file_name
, "we");
172 * this function will be called after fork in the child
173 * open new files with pid of the process
181 out_env
= secure_getenv (MPX_RT_OUT
);
182 err_env
= secure_getenv (MPX_RT_ERR
);
184 if (add_pid
== 0 && (out_env
!= 0 || err_env
!= 0))
186 __mpxrt_print (VERB_ERROR
, "MPX RUNTIME WARNING: out/err files are "
187 "overwritten in new processes since %s was not set.\n",
189 files_overwritten
= 1;
192 set_file_stream (&out
, out_name
, out_env
, stdout
);
193 if (out_env
== 0 || err_env
== 0 || (strcmp (out_env
, err_env
) != 0))
194 set_file_stream (&err
, err_name
, err_env
, stderr
);
196 /* in case we get the same file name for err and out */
201 * this function is called after fork in the parent
209 out_env
= secure_getenv (MPX_RT_OUT
);
210 err_env
= secure_getenv (MPX_RT_ERR
);
212 if (add_pid
== 0 && (out_env
!= 0 || err_env
!= 0))
213 files_overwritten
= 1;
217 set_mpx_rt_mode (const char *env
)
220 return MPX_RT_MODE_DEFAULT
;
221 else if (strcmp (env
, "stop") == 0)
223 else if (strcmp (env
,"count") == 0)
226 __mpxrt_print (VERB_ERROR
, "Illegal value '%s' for %s. Legal values are"
227 "[stop | count]\nUsing default value %s\n",
228 env
, MPX_RT_MODE
, MPX_RT_MODE_DEFAULT_STR
);
229 return MPX_RT_MODE_DEFAULT
;
233 static mpx_rt_stop_mode_handler_t
234 set_mpx_rt_stop_handler (const char *env
)
237 return MPX_RT_STOP_HANDLER_DEFAULT
;
238 else if (strcmp (env
, "abort") == 0)
239 return MPX_RT_STOP_HANDLER_ABORT
;
240 else if (strcmp (env
, "exit") == 0)
241 return MPX_RT_STOP_HANDLER_EXIT
;
243 __mpxrt_print (VERB_ERROR
, "Illegal value '%s' for %s. Legal values are"
244 "[abort | exit]\nUsing default value %s\n",
245 env
, MPX_RT_STOP_HANDLER
, MPX_RT_STOP_HANDLER_DEFAULT
);
246 return MPX_RT_STOP_HANDLER_DEFAULT
;
253 fprintf (out
, "MPX Runtime environment variables help.\n");
255 fprintf (out
, "%s \t set output file for info & debug [default: stdout]\n",
257 fprintf (out
, "%s \t set output file for error [default: stderr]\n",
259 fprintf (out
, "%s \t set verbosity type [default: %d]\n"
260 "\t\t\t 0 - print only internal run time errors\n"
261 "\t\t\t 1 - just print summary\n"
262 "\t\t\t 2 - print summary and bound violation information\n "
263 "\t\t\t 3 - print debug information\n",
264 MPX_RT_VERBOSE
, MPX_RT_VERBOSE_DEFAULT
);
265 fprintf (out
, "%s \t\t set MPX runtime behavior on #BR exception."
267 "\t\t\t [default: %s]\n", MPX_RT_MODE
, MPX_RT_MODE_DEFAULT_STR
);
268 fprintf (out
, "%s \t set the handler function MPX runtime will call\n"
269 "\t\t\t on #BR exception when %s is set to \'stop\'."
271 "\t\t\t [default: %s]\n", MPX_RT_STOP_HANDLER
, MPX_RT_MODE
,
272 MPX_RT_STOP_HANDLER_DEFAULT_STR
);
273 fprintf (out
, "%s \t\t generate out,err file for each process.\n"
274 "\t\t\t generated file will be MPX_RT_{OUT,ERR}_FILE.pid\n"
275 "\t\t\t [default: no]\n", MPX_RT_ADDPID
);
276 fprintf (out
, "%s \t set value for BNDPRESERVE bit.\n"
277 "\t\t\t BNDPRESERVE = 0 flush bounds on unprefixed call/ret/jmp\n"
278 "\t\t\t BNDPRESERVE = 1 do NOT flush bounds\n"
279 "\t\t\t [default: %d]\n", MPX_RT_BNDPRESERVE
,
280 MPX_RT_BNDPRESERVE_DEFAULT
);
281 fprintf (out
, "%s \t print summary at the end of the run\n"
282 "\t\t\t [default: no]\n", MPX_RT_PRINT_SUMMARY
);
284 fprintf (out
, "%s \t\t print this help and exit.\n"
285 "\t\t\t [default: no]\n", MPX_RT_HELP
);
291 validate_bndpreserve (const char *env
, int *bndpreserve
)
294 bndpreserve
= MPX_RT_BNDPRESERVE_DEFAULT
;
295 else if (strcmp (env
, "0") == 0)
297 else if (strcmp (env
, "1") == 0)
301 __mpxrt_print (VERB_ERROR
, "Illegal value '%s' for %s. Legal values "
302 "are [0 | 1]\nUsing default value %d\n",
303 env
, MPX_RT_BNDPRESERVE
, MPX_RT_BNDPRESERVE_DEFAULT
);
304 *bndpreserve
= MPX_RT_BNDPRESERVE_DEFAULT
;
309 init_verbose_val (const char *env
)
312 return MPX_RT_VERBOSE_DEFAULT
;
313 else if (strcmp(env
, "0") == 0)
315 else if (strcmp(env
, "1") == 0)
317 else if (strcmp(env
, "2") == 0)
319 else if (strcmp(env
, "3") == 0)
322 __mpxrt_print (VERB_ERROR
, "Illegal value '%s' for %s. Legal values "
323 "are [0..3]\nUsing default value %d\n",
324 env
, MPX_RT_VERBOSE
, (int)MPX_RT_VERBOSE_DEFAULT
);
326 return MPX_RT_VERBOSE_DEFAULT
;
330 env_var_print_summary (void)
334 __mpxrt_print (VERB_DEBUG
, "Used environment variables:\n");
336 node
= env_var_list
.first
;
339 __mpxrt_print (VERB_DEBUG
, " %s = %s\n", node
->env_name
, node
->env_val
);
344 /* Return 1 if passes env var value should enable feature. */
347 check_yes (const char *val
)
349 return val
&& (!strcmp (val
, "yes") || !strcmp (val
, "1"));
353 __mpxrt_init_env_vars (int* bndpreserve
)
359 pthread_mutex_init (&lock
, NULL
);
361 out_env
= secure_getenv (MPX_RT_OUT
);
362 env_var_list_add (MPX_RT_OUT
, out_env
);
364 err_env
= secure_getenv (MPX_RT_ERR
);
365 env_var_list_add (MPX_RT_ERR
, err_env
);
367 env
= secure_getenv (MPX_RT_ADDPID
);
368 env_var_list_add (MPX_RT_ADDPID
, env
);
369 add_pid
= check_yes (env
);
371 set_file_stream (&out
, out_name
, out_env
, stdout
);
372 if (out_env
== 0 || err_env
== 0 || (strcmp (out_env
, err_env
) != 0))
373 set_file_stream (&err
, err_name
, err_env
, stderr
);
375 /* in case we get the same file name for err and out */
378 env
= secure_getenv (MPX_RT_VERBOSE
);
379 env_var_list_add (MPX_RT_VERBOSE
, env
);
380 verbose_val
= init_verbose_val (env
);
382 env
= secure_getenv (MPX_RT_MODE
);
383 env_var_list_add (MPX_RT_MODE
, env
);
384 mode
= set_mpx_rt_mode (env
);
386 env
= secure_getenv (MPX_RT_STOP_HANDLER
);
387 env_var_list_add (MPX_RT_STOP_HANDLER
, env
);
388 stop_handler
= set_mpx_rt_stop_handler (env
);
390 env
= secure_getenv (MPX_RT_BNDPRESERVE
);
391 env_var_list_add (MPX_RT_BNDPRESERVE
, env
);
392 validate_bndpreserve (env
, bndpreserve
);
394 env
= secure_getenv (MPX_RT_PRINT_SUMMARY
);
395 env_var_list_add (MPX_RT_PRINT_SUMMARY
, env
);
396 summary
= check_yes (env
);
398 env
= secure_getenv (MPX_RT_HELP
);
403 * at fork - create new files for output and err according
406 pthread_atfork (NULL
, at_fork_check
, open_child_files
);
408 env_var_print_summary ();
412 __mpxrt_utils_free (void)
414 if (files_overwritten
)
415 __mpxrt_print (VERB_INFO
, "\nMPX RUNTIME WARNING: out/err files are"
416 " overwritten in new processes since %s was not set.\n",
422 if (out_file_dirty
!= 1)
429 if (err_file_dirty
!= 1)
433 pthread_mutex_destroy (&lock
);
437 __mpxrt_write_uint (verbose_type vt
, uint64_t val
, unsigned base
)
439 static const char digits
[] = {
440 '0', '1', '2', '3', '4', '5', '6', '7',
441 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
447 if (vt
> verbose_val
|| base
<= 1 || base
> sizeof (digits
))
451 str
[pos
--] = digits
[val
];
455 str
[pos
--] = digits
[val
% base
];
459 __mpxrt_write (vt
, str
+ pos
+ 1);
463 __mpxrt_write (verbose_type vt
, const char* str
)
468 if (vt
> verbose_val
)
471 if (vt
== VERB_ERROR
)
481 pthread_mutex_lock (&lock
);
482 write (fileno (print_to
), str
, strlen (str
));
483 pthread_mutex_unlock (&lock
);
488 __mpxrt_print (verbose_type vt
, const char* frmt
, ...)
493 if (vt
> verbose_val
)
496 va_start (argp
, frmt
);
497 if (vt
== VERB_ERROR
)
507 pthread_mutex_lock (&lock
);
508 vfprintf (print_to
, frmt
, argp
);
510 pthread_mutex_unlock (&lock
);
521 __mpxrt_stop_handler (void)
526 void __attribute__ ((noreturn
))
529 if (__mpxrt_stop_handler () == MPX_RT_STOP_HANDLER_ABORT
)
531 else if (__mpxrt_stop_handler () == MPX_RT_STOP_HANDLER_EXIT
)
533 __builtin_unreachable ();
537 __mpxrt_print_summary (uint64_t num_brs
, uint64_t l1_size
)
545 pthread_mutex_lock (&lock
);
546 fprintf (out
, "MPX runtime summary:\n");
547 fprintf (out
, " Number of bounds violations: %" PRIu64
".\n", num_brs
);
548 fprintf (out
, " Size of allocated L1: %" PRIu64
"B\n", l1_size
);
550 pthread_mutex_unlock (&lock
);