186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines//===-- sanitizer_flag_parser.cc ------------------------------------------===// 286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines// 386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines// The LLVM Compiler Infrastructure 486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines// 586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines// This file is distributed under the University of Illinois Open Source 686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines// License. See LICENSE.TXT for details. 786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines// 886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines//===----------------------------------------------------------------------===// 986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines// 1086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines// This file is a part of ThreadSanitizer/AddressSanitizer runtime. 1186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines// 1286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines//===----------------------------------------------------------------------===// 1386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines 1486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#include "sanitizer_flag_parser.h" 1586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines 1686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#include "sanitizer_common.h" 1786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#include "sanitizer_libc.h" 1886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#include "sanitizer_flags.h" 1986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#include "sanitizer_flag_parser.h" 2086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines 2186277eb844c4983c81de62d7c050e92fe7155788Stephen Hinesnamespace __sanitizer { 2286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines 2386277eb844c4983c81de62d7c050e92fe7155788Stephen HinesLowLevelAllocator FlagParser::Alloc; 2486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines 2586277eb844c4983c81de62d7c050e92fe7155788Stephen Hinesclass UnknownFlags { 2686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines static const int kMaxUnknownFlags = 20; 2786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines const char *unknown_flags_[kMaxUnknownFlags]; 2886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines int n_unknown_flags_; 2986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines 3086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines public: 3186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines void Add(const char *name) { 3286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines CHECK_LT(n_unknown_flags_, kMaxUnknownFlags); 3386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines unknown_flags_[n_unknown_flags_++] = name; 3486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines } 3586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines 3686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines void Report() { 3786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines if (!n_unknown_flags_) return; 3886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines Printf("WARNING: found %d unrecognized flag(s):\n", n_unknown_flags_); 3986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines for (int i = 0; i < n_unknown_flags_; ++i) 4086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines Printf(" %s\n", unknown_flags_[i]); 4186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines n_unknown_flags_ = 0; 4286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines } 4386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines}; 4486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines 4586277eb844c4983c81de62d7c050e92fe7155788Stephen HinesUnknownFlags unknown_flags; 4686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines 4786277eb844c4983c81de62d7c050e92fe7155788Stephen Hinesvoid ReportUnrecognizedFlags() { 4886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines unknown_flags.Report(); 4986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines} 5086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines 5186277eb844c4983c81de62d7c050e92fe7155788Stephen Hineschar *FlagParser::ll_strndup(const char *s, uptr n) { 5286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines uptr len = internal_strnlen(s, n); 5386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines char *s2 = (char*)Alloc.Allocate(len + 1); 5486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines internal_memcpy(s2, s, len); 5586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines s2[len] = 0; 5686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines return s2; 5786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines} 5886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines 5986277eb844c4983c81de62d7c050e92fe7155788Stephen Hinesvoid FlagParser::PrintFlagDescriptions() { 6086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines Printf("Available flags for %s:\n", SanitizerToolName); 6186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines for (int i = 0; i < n_flags_; ++i) 6286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines Printf("\t%s\n\t\t- %s\n", flags_[i].name, flags_[i].desc); 6386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines} 6486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines 6586277eb844c4983c81de62d7c050e92fe7155788Stephen Hinesvoid FlagParser::fatal_error(const char *err) { 6686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines Printf("ERROR: %s\n", err); 6786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines Die(); 6886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines} 6986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines 7086277eb844c4983c81de62d7c050e92fe7155788Stephen Hinesbool FlagParser::is_space(char c) { 7186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines return c == ' ' || c == ',' || c == ':' || c == '\n' || c == '\t' || 7286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines c == '\r'; 7386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines} 7486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines 7586277eb844c4983c81de62d7c050e92fe7155788Stephen Hinesvoid FlagParser::skip_whitespace() { 7686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines while (is_space(buf_[pos_])) ++pos_; 7786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines} 7886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines 7986277eb844c4983c81de62d7c050e92fe7155788Stephen Hinesvoid FlagParser::parse_flag() { 8086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines uptr name_start = pos_; 8186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines while (buf_[pos_] != 0 && buf_[pos_] != '=' && !is_space(buf_[pos_])) ++pos_; 8286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines if (buf_[pos_] != '=') fatal_error("expected '='"); 8386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines char *name = ll_strndup(buf_ + name_start, pos_ - name_start); 8486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines 8586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines uptr value_start = ++pos_; 8686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines char *value; 8786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines if (buf_[pos_] == '\'' || buf_[pos_] == '"') { 8886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines char quote = buf_[pos_++]; 8986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines while (buf_[pos_] != 0 && buf_[pos_] != quote) ++pos_; 9086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines if (buf_[pos_] == 0) fatal_error("unterminated string"); 9186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines value = ll_strndup(buf_ + value_start + 1, pos_ - value_start - 1); 9286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines ++pos_; // consume the closing quote 9386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines } else { 9486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines while (buf_[pos_] != 0 && !is_space(buf_[pos_])) ++pos_; 9586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines if (buf_[pos_] != 0 && !is_space(buf_[pos_])) 9686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines fatal_error("expected separator or eol"); 9786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines value = ll_strndup(buf_ + value_start, pos_ - value_start); 9886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines } 9986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines 10086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines bool res = run_handler(name, value); 10186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines if (!res) fatal_error("Flag parsing failed."); 10286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines} 10386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines 10486277eb844c4983c81de62d7c050e92fe7155788Stephen Hinesvoid FlagParser::parse_flags() { 10586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines while (true) { 10686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines skip_whitespace(); 10786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines if (buf_[pos_] == 0) break; 10886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines parse_flag(); 10986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines } 11086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines 11186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines // Do a sanity check for certain flags. 11286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines if (common_flags_dont_use.malloc_context_size < 1) 11386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines common_flags_dont_use.malloc_context_size = 1; 11486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines} 11586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines 11686277eb844c4983c81de62d7c050e92fe7155788Stephen Hinesvoid FlagParser::ParseString(const char *s) { 11786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines if (!s) return; 11886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines // Backup current parser state to allow nested ParseString() calls. 11986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines const char *old_buf_ = buf_; 12086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines uptr old_pos_ = pos_; 12186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines buf_ = s; 12286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines pos_ = 0; 12386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines 12486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines parse_flags(); 12586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines 12686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines buf_ = old_buf_; 12786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines pos_ = old_pos_; 12886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines} 12986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines 130799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainarbool FlagParser::ParseFile(const char *path, bool ignore_missing) { 131799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar static const uptr kMaxIncludeSize = 1 << 15; 132799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar char *data; 133799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar uptr data_mapped_size; 134799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar error_t err; 135799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar uptr len; 136799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar if (!ReadFileToBuffer(path, &data, &data_mapped_size, &len, 137799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar Max(kMaxIncludeSize, GetPageSizeCached()), &err)) { 138799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar if (ignore_missing) 139799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar return true; 140799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar Printf("Failed to read options from '%s': error %d\n", path, err); 141799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar return false; 142799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar } 143799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar ParseString(data); 144799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar UnmapOrDie(data, data_mapped_size); 145799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar return true; 146799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar} 147799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar 14886277eb844c4983c81de62d7c050e92fe7155788Stephen Hinesbool FlagParser::run_handler(const char *name, const char *value) { 14986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines for (int i = 0; i < n_flags_; ++i) { 15086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines if (internal_strcmp(name, flags_[i].name) == 0) 15186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines return flags_[i].handler->Parse(value); 15286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines } 15386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines // Unrecognized flag. This is not a fatal error, we may print a warning later. 15486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines unknown_flags.Add(name); 15586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines return true; 15686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines} 15786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines 15886277eb844c4983c81de62d7c050e92fe7155788Stephen Hinesvoid FlagParser::RegisterHandler(const char *name, FlagHandlerBase *handler, 15986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines const char *desc) { 16086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines CHECK_LT(n_flags_, kMaxFlags); 16186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines flags_[n_flags_].name = name; 16286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines flags_[n_flags_].desc = desc; 16386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines flags_[n_flags_].handler = handler; 16486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines ++n_flags_; 16586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines} 16686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines 16786277eb844c4983c81de62d7c050e92fe7155788Stephen HinesFlagParser::FlagParser() : n_flags_(0), buf_(nullptr), pos_(0) { 16886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines flags_ = (Flag *)Alloc.Allocate(sizeof(Flag) * kMaxFlags); 16986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines} 17086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines 17186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines} // namespace __sanitizer 172