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