123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- //===-- sanitizer_flag_parser.cpp -----------------------------------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This file is a part of ThreadSanitizer/AddressSanitizer runtime.
- //
- //===----------------------------------------------------------------------===//
- #include "sanitizer_flag_parser.h"
- #include "sanitizer_common.h"
- #include "sanitizer_libc.h"
- #include "sanitizer_flags.h"
- #include "sanitizer_flag_parser.h"
- namespace __sanitizer {
- LowLevelAllocator FlagParser::Alloc;
- class UnknownFlags {
- static const int kMaxUnknownFlags = 20;
- const char *unknown_flags_[kMaxUnknownFlags];
- int n_unknown_flags_;
- public:
- void Add(const char *name) {
- CHECK_LT(n_unknown_flags_, kMaxUnknownFlags);
- unknown_flags_[n_unknown_flags_++] = name;
- }
- void Report() {
- if (!n_unknown_flags_) return;
- Printf("WARNING: found %d unrecognized flag(s):\n", n_unknown_flags_);
- for (int i = 0; i < n_unknown_flags_; ++i)
- Printf(" %s\n", unknown_flags_[i]);
- n_unknown_flags_ = 0;
- }
- };
- UnknownFlags unknown_flags;
- void ReportUnrecognizedFlags() {
- unknown_flags.Report();
- }
- char *FlagParser::ll_strndup(const char *s, uptr n) {
- uptr len = internal_strnlen(s, n);
- char *s2 = (char*)Alloc.Allocate(len + 1);
- internal_memcpy(s2, s, len);
- s2[len] = 0;
- return s2;
- }
- void FlagParser::PrintFlagDescriptions() {
- char buffer[128];
- buffer[sizeof(buffer) - 1] = '\0';
- Printf("Available flags for %s:\n", SanitizerToolName);
- for (int i = 0; i < n_flags_; ++i) {
- bool truncated = !(flags_[i].handler->Format(buffer, sizeof(buffer)));
- CHECK_EQ(buffer[sizeof(buffer) - 1], '\0');
- const char *truncation_str = truncated ? " Truncated" : "";
- Printf("\t%s\n\t\t- %s (Current Value%s: %s)\n", flags_[i].name,
- flags_[i].desc, truncation_str, buffer);
- }
- }
- void FlagParser::fatal_error(const char *err) {
- Printf("%s: ERROR: %s\n", SanitizerToolName, err);
- Die();
- }
- bool FlagParser::is_space(char c) {
- return c == ' ' || c == ',' || c == ':' || c == '\n' || c == '\t' ||
- c == '\r';
- }
- void FlagParser::skip_whitespace() {
- while (is_space(buf_[pos_])) ++pos_;
- }
- void FlagParser::parse_flag(const char *env_option_name) {
- uptr name_start = pos_;
- while (buf_[pos_] != 0 && buf_[pos_] != '=' && !is_space(buf_[pos_])) ++pos_;
- if (buf_[pos_] != '=') {
- if (env_option_name) {
- Printf("%s: ERROR: expected '=' in %s\n", SanitizerToolName,
- env_option_name);
- Die();
- } else {
- fatal_error("expected '='");
- }
- }
- char *name = ll_strndup(buf_ + name_start, pos_ - name_start);
- uptr value_start = ++pos_;
- char *value;
- if (buf_[pos_] == '\'' || buf_[pos_] == '"') {
- char quote = buf_[pos_++];
- while (buf_[pos_] != 0 && buf_[pos_] != quote) ++pos_;
- if (buf_[pos_] == 0) fatal_error("unterminated string");
- value = ll_strndup(buf_ + value_start + 1, pos_ - value_start - 1);
- ++pos_; // consume the closing quote
- } else {
- while (buf_[pos_] != 0 && !is_space(buf_[pos_])) ++pos_;
- if (buf_[pos_] != 0 && !is_space(buf_[pos_]))
- fatal_error("expected separator or eol");
- value = ll_strndup(buf_ + value_start, pos_ - value_start);
- }
- bool res = run_handler(name, value);
- if (!res) fatal_error("Flag parsing failed.");
- }
- void FlagParser::parse_flags(const char *env_option_name) {
- while (true) {
- skip_whitespace();
- if (buf_[pos_] == 0) break;
- parse_flag(env_option_name);
- }
- // Do a sanity check for certain flags.
- if (common_flags_dont_use.malloc_context_size < 1)
- common_flags_dont_use.malloc_context_size = 1;
- }
- void FlagParser::ParseStringFromEnv(const char *env_name) {
- const char *env = GetEnv(env_name);
- VPrintf(1, "%s: %s\n", env_name, env ? env : "<empty>");
- ParseString(env, env_name);
- }
- void FlagParser::ParseString(const char *s, const char *env_option_name) {
- if (!s) return;
- // Backup current parser state to allow nested ParseString() calls.
- const char *old_buf_ = buf_;
- uptr old_pos_ = pos_;
- buf_ = s;
- pos_ = 0;
- parse_flags(env_option_name);
- buf_ = old_buf_;
- pos_ = old_pos_;
- }
- bool FlagParser::ParseFile(const char *path, bool ignore_missing) {
- static const uptr kMaxIncludeSize = 1 << 15;
- char *data;
- uptr data_mapped_size;
- error_t err;
- uptr len;
- if (!ReadFileToBuffer(path, &data, &data_mapped_size, &len,
- Max(kMaxIncludeSize, GetPageSizeCached()), &err)) {
- if (ignore_missing)
- return true;
- Printf("Failed to read options from '%s': error %d\n", path, err);
- return false;
- }
- ParseString(data, path);
- UnmapOrDie(data, data_mapped_size);
- return true;
- }
- bool FlagParser::run_handler(const char *name, const char *value) {
- for (int i = 0; i < n_flags_; ++i) {
- if (internal_strcmp(name, flags_[i].name) == 0)
- return flags_[i].handler->Parse(value);
- }
- // Unrecognized flag. This is not a fatal error, we may print a warning later.
- unknown_flags.Add(name);
- return true;
- }
- void FlagParser::RegisterHandler(const char *name, FlagHandlerBase *handler,
- const char *desc) {
- CHECK_LT(n_flags_, kMaxFlags);
- flags_[n_flags_].name = name;
- flags_[n_flags_].desc = desc;
- flags_[n_flags_].handler = handler;
- ++n_flags_;
- }
- FlagParser::FlagParser() : n_flags_(0), buf_(nullptr), pos_(0) {
- flags_ = (Flag *)Alloc.Allocate(sizeof(Flag) * kMaxFlags);
- }
- } // namespace __sanitizer
|