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_internal_defs.h" 17 #include "sanitizer_libc.h" 18 #include "sanitizer_common.h" 19 20 namespace __sanitizer { 21 22 class FlagHandlerBase { 23 public: 24 virtual bool Parse(const char *value) { return false; } 25 26 protected: 27 ~FlagHandlerBase() {}; 28 }; 29 30 template <typename T> 31 class FlagHandler : public FlagHandlerBase { 32 T *t_; 33 34 public: 35 explicit FlagHandler(T *t) : t_(t) {} 36 bool Parse(const char *value) final; 37 }; 38 39 inline bool ParseBool(const char *value, bool *b) { 40 if (internal_strcmp(value, "0") == 0 || 41 internal_strcmp(value, "no") == 0 || 42 internal_strcmp(value, "false") == 0) { 43 *b = false; 44 return true; 45 } 46 if (internal_strcmp(value, "1") == 0 || 47 internal_strcmp(value, "yes") == 0 || 48 internal_strcmp(value, "true") == 0) { 49 *b = true; 50 return true; 51 } 52 return false; 53 } 54 55 template <> 56 inline bool FlagHandler<bool>::Parse(const char *value) { 57 if (ParseBool(value, t_)) return true; 58 Printf("ERROR: Invalid value for bool option: '%s'\n", value); 59 return false; 60 } 61 62 template <> 63 inline bool FlagHandler<HandleSignalMode>::Parse(const char *value) { 64 bool b; 65 if (ParseBool(value, &b)) { 66 *t_ = b ? kHandleSignalYes : kHandleSignalNo; 67 return true; 68 } 69 if (internal_strcmp(value, "2") == 0 || 70 internal_strcmp(value, "exclusive") == 0) { 71 *t_ = kHandleSignalExclusive; 72 return true; 73 } 74 Printf("ERROR: Invalid value for signal handler option: '%s'\n", value); 75 return false; 76 } 77 78 template <> 79 inline bool FlagHandler<const char *>::Parse(const char *value) { 80 *t_ = value; 81 return true; 82 } 83 84 template <> 85 inline bool FlagHandler<int>::Parse(const char *value) { 86 const char *value_end; 87 *t_ = internal_simple_strtoll(value, &value_end, 10); 88 bool ok = *value_end == 0; 89 if (!ok) Printf("ERROR: Invalid value for int option: '%s'\n", value); 90 return ok; 91 } 92 93 template <> 94 inline bool FlagHandler<uptr>::Parse(const char *value) { 95 const char *value_end; 96 *t_ = internal_simple_strtoll(value, &value_end, 10); 97 bool ok = *value_end == 0; 98 if (!ok) Printf("ERROR: Invalid value for uptr option: '%s'\n", value); 99 return ok; 100 } 101 102 template <> 103 inline bool FlagHandler<s64>::Parse(const char *value) { 104 const char *value_end; 105 *t_ = internal_simple_strtoll(value, &value_end, 10); 106 bool ok = *value_end == 0; 107 if (!ok) Printf("ERROR: Invalid value for s64 option: '%s'\n", value); 108 return ok; 109 } 110 111 class FlagParser { 112 static const int kMaxFlags = 200; 113 struct Flag { 114 const char *name; 115 const char *desc; 116 FlagHandlerBase *handler; 117 } *flags_; 118 int n_flags_; 119 120 const char *buf_; 121 uptr pos_; 122 123 public: 124 FlagParser(); 125 void RegisterHandler(const char *name, FlagHandlerBase *handler, 126 const char *desc); 127 void ParseString(const char *s, const char *env_name = 0); 128 void ParseStringFromEnv(const char *env_name); 129 bool ParseFile(const char *path, bool ignore_missing); 130 void PrintFlagDescriptions(); 131 132 static LowLevelAllocator Alloc; 133 134 private: 135 void fatal_error(const char *err); 136 bool is_space(char c); 137 void skip_whitespace(); 138 void parse_flags(const char *env_option_name); 139 void parse_flag(const char *env_option_name); 140 bool run_handler(const char *name, const char *value); 141 char *ll_strndup(const char *s, uptr n); 142 }; 143 144 template <typename T> 145 static void RegisterFlag(FlagParser *parser, const char *name, const char *desc, 146 T *var) { 147 FlagHandler<T> *fh = new (FlagParser::Alloc) FlagHandler<T>(var); // NOLINT 148 parser->RegisterHandler(name, fh, desc); 149 } 150 151 void ReportUnrecognizedFlags(); 152 153 } // namespace __sanitizer 154 155 #endif // SANITIZER_FLAG_REGISTRY_H 156