1 //===-- sanitizer_flag_parser.h ---------------------------------*- C++ -*-===// 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 #ifndef SANITIZER_FLAG_REGISTRY_H 14 #define SANITIZER_FLAG_REGISTRY_H 15 16 #include "sanitizer_common.h" 17 #include "sanitizer_internal_defs.h" 18 #include "sanitizer_libc.h" 19 20 namespace __sanitizer { 21 22 class FlagHandlerBase { 23 public: 24 virtual bool Parse(const char *value) { return false; } 25 // Write the C string representation of the current value (truncated to fit) 26 // into the buffer of size `size`. Returns false if truncation occurred and 27 // returns true otherwise. 28 virtual bool Format(char *buffer, uptr size) { 29 if (size > 0) 30 buffer[0] = '\0'; 31 return false; 32 } 33 34 protected: 35 ~FlagHandlerBase() {} 36 37 inline bool FormatString(char *buffer, uptr size, const char *str_to_use) { 38 uptr num_symbols_should_write = 39 internal_snprintf(buffer, size, "%s", str_to_use); 40 return num_symbols_should_write < size; 41 } 42 }; 43 44 template <typename T> 45 class FlagHandler final : public FlagHandlerBase { 46 T *t_; 47 48 public: 49 explicit FlagHandler(T *t) : t_(t) {} 50 bool Parse(const char *value) final; 51 bool Format(char *buffer, uptr size) final; 52 }; 53 54 inline bool ParseBool(const char *value, bool *b) { 55 if (internal_strcmp(value, "0") == 0 || 56 internal_strcmp(value, "no") == 0 || 57 internal_strcmp(value, "false") == 0) { 58 *b = false; 59 return true; 60 } 61 if (internal_strcmp(value, "1") == 0 || 62 internal_strcmp(value, "yes") == 0 || 63 internal_strcmp(value, "true") == 0) { 64 *b = true; 65 return true; 66 } 67 return false; 68 } 69 70 template <> 71 inline bool FlagHandler<bool>::Parse(const char *value) { 72 if (ParseBool(value, t_)) return true; 73 Printf("ERROR: Invalid value for bool option: '%s'\n", value); 74 return false; 75 } 76 77 template <> 78 inline bool FlagHandler<bool>::Format(char *buffer, uptr size) { 79 return FormatString(buffer, size, *t_ ? "true" : "false"); 80 } 81 82 template <> 83 inline bool FlagHandler<HandleSignalMode>::Parse(const char *value) { 84 bool b; 85 if (ParseBool(value, &b)) { 86 *t_ = b ? kHandleSignalYes : kHandleSignalNo; 87 return true; 88 } 89 if (internal_strcmp(value, "2") == 0 || 90 internal_strcmp(value, "exclusive") == 0) { 91 *t_ = kHandleSignalExclusive; 92 return true; 93 } 94 Printf("ERROR: Invalid value for signal handler option: '%s'\n", value); 95 return false; 96 } 97 98 template <> 99 inline bool FlagHandler<HandleSignalMode>::Format(char *buffer, uptr size) { 100 uptr num_symbols_should_write = internal_snprintf(buffer, size, "%d", *t_); 101 return num_symbols_should_write < size; 102 } 103 104 template <> 105 inline bool FlagHandler<const char *>::Parse(const char *value) { 106 *t_ = value; 107 return true; 108 } 109 110 template <> 111 inline bool FlagHandler<const char *>::Format(char *buffer, uptr size) { 112 return FormatString(buffer, size, *t_); 113 } 114 115 template <> 116 inline bool FlagHandler<int>::Parse(const char *value) { 117 const char *value_end; 118 *t_ = internal_simple_strtoll(value, &value_end, 10); 119 bool ok = *value_end == 0; 120 if (!ok) Printf("ERROR: Invalid value for int option: '%s'\n", value); 121 return ok; 122 } 123 124 template <> 125 inline bool FlagHandler<int>::Format(char *buffer, uptr size) { 126 uptr num_symbols_should_write = internal_snprintf(buffer, size, "%d", *t_); 127 return num_symbols_should_write < size; 128 } 129 130 template <> 131 inline bool FlagHandler<uptr>::Parse(const char *value) { 132 const char *value_end; 133 *t_ = internal_simple_strtoll(value, &value_end, 10); 134 bool ok = *value_end == 0; 135 if (!ok) Printf("ERROR: Invalid value for uptr option: '%s'\n", value); 136 return ok; 137 } 138 139 template <> 140 inline bool FlagHandler<uptr>::Format(char *buffer, uptr size) { 141 uptr num_symbols_should_write = internal_snprintf(buffer, size, "0x%zx", *t_); 142 return num_symbols_should_write < size; 143 } 144 145 template <> 146 inline bool FlagHandler<s64>::Parse(const char *value) { 147 const char *value_end; 148 *t_ = internal_simple_strtoll(value, &value_end, 10); 149 bool ok = *value_end == 0; 150 if (!ok) Printf("ERROR: Invalid value for s64 option: '%s'\n", value); 151 return ok; 152 } 153 154 template <> 155 inline bool FlagHandler<s64>::Format(char *buffer, uptr size) { 156 uptr num_symbols_should_write = internal_snprintf(buffer, size, "%lld", *t_); 157 return num_symbols_should_write < size; 158 } 159 160 class FlagParser { 161 static const int kMaxFlags = 200; 162 struct Flag { 163 const char *name; 164 const char *desc; 165 FlagHandlerBase *handler; 166 } *flags_; 167 int n_flags_; 168 169 const char *buf_; 170 uptr pos_; 171 172 public: 173 FlagParser(); 174 void RegisterHandler(const char *name, FlagHandlerBase *handler, 175 const char *desc); 176 void ParseString(const char *s, const char *env_name = 0); 177 void ParseStringFromEnv(const char *env_name); 178 bool ParseFile(const char *path, bool ignore_missing); 179 void PrintFlagDescriptions(); 180 181 static LowLevelAllocator Alloc; 182 183 private: 184 void fatal_error(const char *err); 185 bool is_space(char c); 186 void skip_whitespace(); 187 void parse_flags(const char *env_option_name); 188 void parse_flag(const char *env_option_name); 189 bool run_handler(const char *name, const char *value); 190 char *ll_strndup(const char *s, uptr n); 191 }; 192 193 template <typename T> 194 static void RegisterFlag(FlagParser *parser, const char *name, const char *desc, 195 T *var) { 196 FlagHandler<T> *fh = new (FlagParser::Alloc) FlagHandler<T>(var); 197 parser->RegisterHandler(name, fh, desc); 198 } 199 200 void ReportUnrecognizedFlags(); 201 202 } // namespace __sanitizer 203 204 #endif // SANITIZER_FLAG_REGISTRY_H 205