1 //===-- sanitizer_flag_parser.cc ------------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file is a part of ThreadSanitizer/AddressSanitizer runtime. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "sanitizer_flag_parser.h" 15 16 #include "sanitizer_common.h" 17 #include "sanitizer_libc.h" 18 #include "sanitizer_flags.h" 19 #include "sanitizer_flag_parser.h" 20 21 namespace __sanitizer { 22 23 LowLevelAllocator FlagParser::Alloc; 24 25 class UnknownFlags { 26 static const int kMaxUnknownFlags = 20; 27 const char *unknown_flags_[kMaxUnknownFlags]; 28 int n_unknown_flags_; 29 30 public: 31 void Add(const char *name) { 32 CHECK_LT(n_unknown_flags_, kMaxUnknownFlags); 33 unknown_flags_[n_unknown_flags_++] = name; 34 } 35 36 void Report() { 37 if (!n_unknown_flags_) return; 38 Printf("WARNING: found %d unrecognized flag(s):\n", n_unknown_flags_); 39 for (int i = 0; i < n_unknown_flags_; ++i) 40 Printf(" %s\n", unknown_flags_[i]); 41 n_unknown_flags_ = 0; 42 } 43 }; 44 45 UnknownFlags unknown_flags; 46 47 void ReportUnrecognizedFlags() { 48 unknown_flags.Report(); 49 } 50 51 char *FlagParser::ll_strndup(const char *s, uptr n) { 52 uptr len = internal_strnlen(s, n); 53 char *s2 = (char*)Alloc.Allocate(len + 1); 54 internal_memcpy(s2, s, len); 55 s2[len] = 0; 56 return s2; 57 } 58 59 void FlagParser::PrintFlagDescriptions() { 60 Printf("Available flags for %s:\n", SanitizerToolName); 61 for (int i = 0; i < n_flags_; ++i) 62 Printf("\t%s\n\t\t- %s\n", flags_[i].name, flags_[i].desc); 63 } 64 65 void FlagParser::fatal_error(const char *err) { 66 Printf("ERROR: %s\n", err); 67 Die(); 68 } 69 70 bool FlagParser::is_space(char c) { 71 return c == ' ' || c == ',' || c == ':' || c == '\n' || c == '\t' || 72 c == '\r'; 73 } 74 75 void FlagParser::skip_whitespace() { 76 while (is_space(buf_[pos_])) ++pos_; 77 } 78 79 void FlagParser::parse_flag() { 80 uptr name_start = pos_; 81 while (buf_[pos_] != 0 && buf_[pos_] != '=' && !is_space(buf_[pos_])) ++pos_; 82 if (buf_[pos_] != '=') fatal_error("expected '='"); 83 char *name = ll_strndup(buf_ + name_start, pos_ - name_start); 84 85 uptr value_start = ++pos_; 86 char *value; 87 if (buf_[pos_] == '\'' || buf_[pos_] == '"') { 88 char quote = buf_[pos_++]; 89 while (buf_[pos_] != 0 && buf_[pos_] != quote) ++pos_; 90 if (buf_[pos_] == 0) fatal_error("unterminated string"); 91 value = ll_strndup(buf_ + value_start + 1, pos_ - value_start - 1); 92 ++pos_; // consume the closing quote 93 } else { 94 while (buf_[pos_] != 0 && !is_space(buf_[pos_])) ++pos_; 95 if (buf_[pos_] != 0 && !is_space(buf_[pos_])) 96 fatal_error("expected separator or eol"); 97 value = ll_strndup(buf_ + value_start, pos_ - value_start); 98 } 99 100 bool res = run_handler(name, value); 101 if (!res) fatal_error("Flag parsing failed."); 102 } 103 104 void FlagParser::parse_flags() { 105 while (true) { 106 skip_whitespace(); 107 if (buf_[pos_] == 0) break; 108 parse_flag(); 109 } 110 111 // Do a sanity check for certain flags. 112 if (common_flags_dont_use.malloc_context_size < 1) 113 common_flags_dont_use.malloc_context_size = 1; 114 } 115 116 void FlagParser::ParseString(const char *s) { 117 if (!s) return; 118 // Backup current parser state to allow nested ParseString() calls. 119 const char *old_buf_ = buf_; 120 uptr old_pos_ = pos_; 121 buf_ = s; 122 pos_ = 0; 123 124 parse_flags(); 125 126 buf_ = old_buf_; 127 pos_ = old_pos_; 128 } 129 130 bool FlagParser::ParseFile(const char *path, bool ignore_missing) { 131 static const uptr kMaxIncludeSize = 1 << 15; 132 char *data; 133 uptr data_mapped_size; 134 error_t err; 135 uptr len; 136 if (!ReadFileToBuffer(path, &data, &data_mapped_size, &len, 137 Max(kMaxIncludeSize, GetPageSizeCached()), &err)) { 138 if (ignore_missing) 139 return true; 140 Printf("Failed to read options from '%s': error %d\n", path, err); 141 return false; 142 } 143 ParseString(data); 144 UnmapOrDie(data, data_mapped_size); 145 return true; 146 } 147 148 bool FlagParser::run_handler(const char *name, const char *value) { 149 for (int i = 0; i < n_flags_; ++i) { 150 if (internal_strcmp(name, flags_[i].name) == 0) 151 return flags_[i].handler->Parse(value); 152 } 153 // Unrecognized flag. This is not a fatal error, we may print a warning later. 154 unknown_flags.Add(name); 155 return true; 156 } 157 158 void FlagParser::RegisterHandler(const char *name, FlagHandlerBase *handler, 159 const char *desc) { 160 CHECK_LT(n_flags_, kMaxFlags); 161 flags_[n_flags_].name = name; 162 flags_[n_flags_].desc = desc; 163 flags_[n_flags_].handler = handler; 164 ++n_flags_; 165 } 166 167 FlagParser::FlagParser() : n_flags_(0), buf_(nullptr), pos_(0) { 168 flags_ = (Flag *)Alloc.Allocate(sizeof(Flag) * kMaxFlags); 169 } 170 171 } // namespace __sanitizer 172