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_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"
71 
72 #define MAX_FILE_NAME PATH_MAX
73 
74 typedef struct env_var_s {
75   char *env_name;
76   char *env_val;
77   struct env_var_s *next;
78 } env_var_t;
79 
80 typedef struct {
81   env_var_t *first;
82   env_var_t *last;
83 } env_var_list_t;
84 
85 /* Following vars are initialized at process startup only
86    and thus are considered to be thread safe.  */
87 static int summary;
88 static int add_pid;
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;
93 static FILE *out;
94 static FILE *err;
95 static char out_name[MAX_FILE_NAME];
96 static char err_name[MAX_FILE_NAME];
97 
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;
104 
105 /* Mutex used to sync output.  */
106 static pthread_mutex_t lock;
107 
108 static void *
malloc_check(size_t size)109 malloc_check (size_t size)
110 {
111   void *res = malloc (size);
112   if (!res)
113     __mpxrt_print (VERB_ERROR, "Couldn't allocate %zu bytes.", size);
114   else
115     memset (res, 0, size);
116   return res;
117 }
118 
119 static void
env_var_list_add(const char * env,const char * val)120 env_var_list_add (const char* env, const char* val)
121 {
122   env_var_t* n;
123 
124   if (val == 0)
125     return;
126 
127   n = (env_var_t *)malloc_check (sizeof (env_var_t));
128   if (!n)
129     return;
130 
131   if (env_var_list.first == 0)
132     env_var_list.first = n;
133 
134   if (env_var_list.last)
135     env_var_list.last->next = n;
136 
137   env_var_list.last = n;
138 
139   n->env_name = (char *)malloc_check (strlen (env) + 1);
140   n->env_val = (char *)malloc_check (strlen (val) + 1);
141 
142   if (!n->env_name || !n->env_val)
143     return;
144 
145   strcpy (n->env_name, env);
146   strcpy (n->env_val, val);
147 }
148 
149 static void
set_file_stream(FILE ** file,char * file_name,const char * env,FILE * deflt)150 set_file_stream (FILE** file, char* file_name,
151 		 const char* env, FILE* deflt)
152 {
153   int pid;
154   if (env != 0)
155     {
156       if (add_pid)
157 	{
158 	  pid = getpid ();
159 	  snprintf (file_name, MAX_FILE_NAME, "%s.%d", env, pid);
160 	}
161       else
162 	snprintf (file_name, MAX_FILE_NAME, "%s", env);
163 
164       *file = fopen (file_name, "we");
165       if (*file != 0)
166 	return;
167     }
168   *file = deflt;
169 }
170 
171 /*
172  * this function will be called after fork in the child
173  * open new files with pid of the process
174  */
175 static void
open_child_files()176 open_child_files ()
177 {
178   char *out_env;
179   char *err_env;
180 
181   out_env = secure_getenv (MPX_RT_OUT);
182   err_env = secure_getenv (MPX_RT_ERR);
183 
184   if (add_pid == 0 && (out_env != 0 || err_env != 0))
185     {
186       __mpxrt_print (VERB_ERROR, "MPX RUNTIME WARNING: out/err files are "
187 		     "overwritten in new processes since %s was not set.\n",
188 		     MPX_RT_ADDPID);
189       files_overwritten = 1;
190     }
191 
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);
195   else
196     /* in case we get the same file name for err and out */
197     err = out;
198 }
199 
200 /*
201  * this function is called after fork in the parent
202  */
203 static void
at_fork_check(void)204 at_fork_check (void)
205 {
206   char *out_env;
207   char *err_env;
208 
209   out_env = secure_getenv (MPX_RT_OUT);
210   err_env = secure_getenv (MPX_RT_ERR);
211 
212   if (add_pid == 0 && (out_env != 0 || err_env != 0))
213     files_overwritten = 1;
214 }
215 
216 static mpx_rt_mode_t
set_mpx_rt_mode(const char * env)217 set_mpx_rt_mode (const char *env)
218 {
219   if (env == 0)
220     return MPX_RT_MODE_DEFAULT;
221   else if (strcmp (env, "stop") == 0)
222     return MPX_RT_STOP;
223   else if (strcmp (env,"count") == 0)
224     return MPX_RT_COUNT;
225   {
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;
230   }
231 }
232 
233 static mpx_rt_stop_mode_handler_t
set_mpx_rt_stop_handler(const char * env)234 set_mpx_rt_stop_handler (const char *env)
235 {
236   if (env == 0)
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;
242   {
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;
247   }
248 }
249 
250 static void
print_help(void)251 print_help (void)
252 {
253   fprintf (out, "MPX Runtime environment variables help.\n");
254 
255   fprintf (out, "%s \t set output file for info & debug [default: stdout]\n",
256 	   MPX_RT_OUT);
257   fprintf (out, "%s \t set output file for error [default: stderr]\n",
258 	   MPX_RT_ERR);
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."
266 	   " [stop | count]\n"
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\'."
270 	   " [abort | exit]\n"
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);
283 
284   fprintf (out, "%s \t\t print this help and exit.\n"
285 	   "\t\t\t [default: no]\n", MPX_RT_HELP);
286 
287   exit (0);
288 }
289 
290 static void
validate_bndpreserve(const char * env,int * bndpreserve)291 validate_bndpreserve (const char *env, int *bndpreserve)
292 {
293   if (env == 0)
294     bndpreserve = MPX_RT_BNDPRESERVE_DEFAULT;
295   else if (strcmp (env, "0") == 0)
296     *bndpreserve = 0;
297   else if (strcmp (env, "1") == 0)
298     *bndpreserve = 1;
299   else
300     {
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;
305     }
306 }
307 
308 static verbose_type
init_verbose_val(const char * env)309 init_verbose_val (const char *env)
310 {
311   if (env == 0)
312     return MPX_RT_VERBOSE_DEFAULT;
313   else if (strcmp(env, "0") == 0)
314     return VERB_ERROR;
315   else if (strcmp(env, "1") == 0)
316     return VERB_INFO;
317   else if (strcmp(env, "2") == 0)
318     return VERB_BR;
319   else if (strcmp(env, "3") == 0)
320     return VERB_DEBUG;
321 
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);
325 
326   return MPX_RT_VERBOSE_DEFAULT;
327 }
328 
329 static void
env_var_print_summary(void)330 env_var_print_summary (void)
331 {
332   env_var_t* node;
333 
334   __mpxrt_print (VERB_DEBUG, "Used environment variables:\n");
335 
336   node = env_var_list.first;
337   while (node != 0)
338     {
339       __mpxrt_print (VERB_DEBUG, "  %s = %s\n", node->env_name, node->env_val);
340       node = node->next;
341     }
342 }
343 
344 /* Return 1 if passes env var value should enable feature.  */
345 
346 static int
check_yes(const char * val)347 check_yes (const char *val)
348 {
349   return val && (!strcmp (val, "yes") || !strcmp (val, "1"));
350 }
351 
352 void
__mpxrt_init_env_vars(int * bndpreserve)353 __mpxrt_init_env_vars (int* bndpreserve)
354 {
355   char *out_env;
356   char *err_env;
357   char *env;
358 
359   pthread_mutex_init (&lock, NULL);
360 
361   out_env = secure_getenv (MPX_RT_OUT);
362   env_var_list_add (MPX_RT_OUT, out_env);
363 
364   err_env = secure_getenv (MPX_RT_ERR);
365   env_var_list_add (MPX_RT_ERR, err_env);
366 
367   env = secure_getenv (MPX_RT_ADDPID);
368   env_var_list_add (MPX_RT_ADDPID, env);
369   add_pid = check_yes (env);
370 
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);
374   else
375     /* in case we get the same file name for err and out */
376     err = out;
377 
378   env = secure_getenv (MPX_RT_VERBOSE);
379   env_var_list_add (MPX_RT_VERBOSE, env);
380   verbose_val = init_verbose_val (env);
381 
382   env = secure_getenv (MPX_RT_MODE);
383   env_var_list_add (MPX_RT_MODE, env);
384   mode = set_mpx_rt_mode (env);
385 
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);
389 
390   env = secure_getenv (MPX_RT_BNDPRESERVE);
391   env_var_list_add (MPX_RT_BNDPRESERVE, env);
392   validate_bndpreserve (env, bndpreserve);
393 
394   env = secure_getenv (MPX_RT_PRINT_SUMMARY);
395   env_var_list_add (MPX_RT_PRINT_SUMMARY, env);
396   summary = check_yes (env);
397 
398   env = secure_getenv (MPX_RT_HELP);
399   if (check_yes (env))
400     print_help ();
401 
402   /*
403    * at fork - create new files for output and err according
404    * to the env vars.
405    */
406   pthread_atfork (NULL, at_fork_check, open_child_files);
407 
408   env_var_print_summary ();
409 }
410 
411 void
__mpxrt_utils_free(void)412 __mpxrt_utils_free (void)
413 {
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",
417 		   MPX_RT_ADDPID);
418 
419   if (out != stdout)
420     {
421       fclose (out);
422       if (out_file_dirty != 1)
423 	remove (out_name);
424     }
425 
426   if (err != stderr)
427     {
428       fclose (err);
429       if (err_file_dirty != 1)
430 	remove (err_name);
431     }
432 
433   pthread_mutex_destroy (&lock);
434 }
435 
436 void
__mpxrt_write_uint(verbose_type vt,uint64_t val,unsigned base)437 __mpxrt_write_uint (verbose_type vt, uint64_t val, unsigned base)
438 {
439   static const char digits[] = {
440     '0', '1', '2', '3', '4', '5', '6', '7',
441     '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
442   char str[65];
443   int pos = 64;;
444 
445   str[pos--] = 0;
446 
447   if (vt > verbose_val || base <= 1 || base > sizeof (digits))
448     return;
449 
450   if (val < base)
451     str[pos--] = digits[val];
452   else
453     while (val)
454       {
455 	str[pos--] = digits[val % base];
456 	val = val / base;
457       }
458 
459   __mpxrt_write (vt, str + pos + 1);
460 }
461 
462 void
__mpxrt_write(verbose_type vt,const char * str)463 __mpxrt_write (verbose_type vt, const char* str)
464 {
465   va_list argp;
466   FILE *print_to;
467 
468   if (vt > verbose_val)
469     return;
470 
471   if (vt == VERB_ERROR)
472     {
473       print_to = err;
474       err_file_dirty = 1;
475     }
476   else
477     {
478       print_to = out;
479       out_file_dirty = 1;
480     }
481   pthread_mutex_lock (&lock);
482   write (fileno (print_to), str, strlen (str));
483   pthread_mutex_unlock (&lock);
484   va_end (argp);
485 }
486 
487 void
__mpxrt_print(verbose_type vt,const char * frmt,...)488 __mpxrt_print (verbose_type vt, const char* frmt, ...)
489 {
490   va_list argp;
491   FILE *print_to;
492 
493   if (vt > verbose_val)
494     return;
495 
496   va_start (argp, frmt);
497   if (vt == VERB_ERROR)
498     {
499       print_to = err;
500       err_file_dirty = 1;
501     }
502   else
503     {
504       print_to = out;
505       out_file_dirty = 1;
506     }
507   pthread_mutex_lock (&lock);
508   vfprintf (print_to, frmt, argp);
509   fflush (print_to);
510   pthread_mutex_unlock (&lock);
511   va_end (argp);
512 }
513 
514 mpx_rt_mode_t
__mpxrt_mode(void)515 __mpxrt_mode (void)
516 {
517   return mode;
518 }
519 
520 mpx_rt_mode_t
__mpxrt_stop_handler(void)521 __mpxrt_stop_handler (void)
522 {
523   return stop_handler;
524 }
525 
526 void __attribute__ ((noreturn))
__mpxrt_stop(void)527 __mpxrt_stop (void)
528 {
529   if (__mpxrt_stop_handler () == MPX_RT_STOP_HANDLER_ABORT)
530     abort ();
531   else if (__mpxrt_stop_handler () == MPX_RT_STOP_HANDLER_EXIT)
532     exit (255);
533   __builtin_unreachable ();
534 }
535 
536 void
__mpxrt_print_summary(uint64_t num_brs,uint64_t l1_size)537 __mpxrt_print_summary (uint64_t num_brs, uint64_t l1_size)
538 {
539 
540   if (summary == 0)
541     return;
542 
543   out_file_dirty = 1;
544 
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);
549   fflush (out);
550   pthread_mutex_unlock (&lock);
551 }
552