1 //===-- sanitizer_flags.cpp -----------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file is a part of ThreadSanitizer/AddressSanitizer runtime. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "sanitizer_flags.h" 14 15 #include "sanitizer_common.h" 16 #include "sanitizer_libc.h" 17 #include "sanitizer_list.h" 18 #include "sanitizer_flag_parser.h" 19 20 namespace __sanitizer { 21 22 CommonFlags common_flags_dont_use; 23 24 void CommonFlags::SetDefaults() { 25 #define COMMON_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; 26 #include "sanitizer_flags.inc" 27 #undef COMMON_FLAG 28 } 29 30 void CommonFlags::CopyFrom(const CommonFlags &other) { 31 internal_memcpy(this, &other, sizeof(*this)); 32 } 33 34 // Copy the string from "s" to "out", making the following substitutions: 35 // %b = binary basename 36 // %p = pid 37 void SubstituteForFlagValue(const char *s, char *out, uptr out_size) { 38 char *out_end = out + out_size; 39 while (*s && out < out_end - 1) { 40 if (s[0] != '%') { 41 *out++ = *s++; 42 continue; 43 } 44 switch (s[1]) { 45 case 'b': { 46 const char *base = GetProcessName(); 47 CHECK(base); 48 while (*base && out < out_end - 1) 49 *out++ = *base++; 50 s += 2; // skip "%b" 51 break; 52 } 53 case 'p': { 54 int pid = internal_getpid(); 55 char buf[32]; 56 char *buf_pos = buf + 32; 57 do { 58 *--buf_pos = (pid % 10) + '0'; 59 pid /= 10; 60 } while (pid); 61 while (buf_pos < buf + 32 && out < out_end - 1) 62 *out++ = *buf_pos++; 63 s += 2; // skip "%p" 64 break; 65 } 66 default: 67 *out++ = *s++; 68 break; 69 } 70 } 71 CHECK(out < out_end - 1); 72 *out = '\0'; 73 } 74 75 class FlagHandlerInclude : public FlagHandlerBase { 76 FlagParser *parser_; 77 bool ignore_missing_; 78 const char *original_path_; 79 80 public: 81 explicit FlagHandlerInclude(FlagParser *parser, bool ignore_missing) 82 : parser_(parser), ignore_missing_(ignore_missing), original_path_("") {} 83 bool Parse(const char *value) final { 84 original_path_ = value; 85 if (internal_strchr(value, '%')) { 86 char *buf = (char *)MmapOrDie(kMaxPathLength, "FlagHandlerInclude"); 87 SubstituteForFlagValue(value, buf, kMaxPathLength); 88 bool res = parser_->ParseFile(buf, ignore_missing_); 89 UnmapOrDie(buf, kMaxPathLength); 90 return res; 91 } 92 return parser_->ParseFile(value, ignore_missing_); 93 } 94 bool Format(char *buffer, uptr size) { 95 // Note `original_path_` isn't actually what's parsed due to `%` 96 // substitutions. Printing the substituted path would require holding onto 97 // mmap'ed memory. 98 return FormatString(buffer, size, original_path_); 99 } 100 }; 101 102 void RegisterIncludeFlags(FlagParser *parser, CommonFlags *cf) { 103 FlagHandlerInclude *fh_include = new (FlagParser::Alloc) 104 FlagHandlerInclude(parser, /*ignore_missing*/ false); 105 parser->RegisterHandler("include", fh_include, 106 "read more options from the given file"); 107 FlagHandlerInclude *fh_include_if_exists = new (FlagParser::Alloc) 108 FlagHandlerInclude(parser, /*ignore_missing*/ true); 109 parser->RegisterHandler( 110 "include_if_exists", fh_include_if_exists, 111 "read more options from the given file (if it exists)"); 112 } 113 114 void RegisterCommonFlags(FlagParser *parser, CommonFlags *cf) { 115 #define COMMON_FLAG(Type, Name, DefaultValue, Description) \ 116 RegisterFlag(parser, #Name, Description, &cf->Name); 117 #include "sanitizer_flags.inc" 118 #undef COMMON_FLAG 119 120 RegisterIncludeFlags(parser, cf); 121 } 122 123 void InitializeCommonFlags(CommonFlags *cf) { 124 // need to record coverage to generate coverage report. 125 cf->coverage |= cf->html_cov_report; 126 SetVerbosity(cf->verbosity); 127 } 128 129 } // namespace __sanitizer 130