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