Home | History | Annotate | Download | only in sanitizer_common
      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