brintos

brintos / llvm-project-archived public Read only

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