Mercurial > hg > CbC > CbC_gcc
comparison libmpx/mpxrt/mpxrt-utils.c @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
68:561a7518be6b | 111:04ced10e8804 |
---|---|
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 * | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
347 check_yes (const char *val) | |
348 { | |
349 return val && (!strcmp (val, "yes") || !strcmp (val, "1")); | |
350 } | |
351 | |
352 void | |
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 | |
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 | |
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 | |
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 | |
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 | |
515 __mpxrt_mode (void) | |
516 { | |
517 return mode; | |
518 } | |
519 | |
520 mpx_rt_mode_t | |
521 __mpxrt_stop_handler (void) | |
522 { | |
523 return stop_handler; | |
524 } | |
525 | |
526 void __attribute__ ((noreturn)) | |
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 | |
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 } |