| //===-- sanitizer_flag_parser.h ---------------------------------*- C++ -*-===// |
| // |
| // 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. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef SANITIZER_FLAG_REGISTRY_H |
| #define SANITIZER_FLAG_REGISTRY_H |
| |
| #include "sanitizer_internal_defs.h" |
| #include "sanitizer_libc.h" |
| #include "sanitizer_common.h" |
| |
| namespace __sanitizer { |
| |
| class FlagHandlerBase { |
| public: |
| virtual bool Parse(const char *value) { return false; } |
| // Write the C string representation of the current value (truncated to fit) |
| // into the buffer of size `size`. Returns false if truncation occurred and |
| // returns true otherwise. |
| virtual bool Format(char *buffer, uptr size) { |
| if (size > 0) |
| buffer[0] = '\0'; |
| return false; |
| } |
| |
| protected: |
| ~FlagHandlerBase() {} |
| |
| inline bool FormatString(char *buffer, uptr size, const char *str_to_use) { |
| uptr num_symbols_should_write = |
| internal_snprintf(buffer, size, "%s", str_to_use); |
| return num_symbols_should_write < size; |
| } |
| }; |
| |
| template <typename T> |
| class FlagHandler final : public FlagHandlerBase { |
| T *t_; |
| |
| public: |
| explicit FlagHandler(T *t) : t_(t) {} |
| bool Parse(const char *value) final; |
| bool Format(char *buffer, uptr size) final; |
| }; |
| |
| inline bool ParseBool(const char *value, bool *b) { |
| if (internal_strcmp(value, "0") == 0 || |
| internal_strcmp(value, "no") == 0 || |
| internal_strcmp(value, "false") == 0) { |
| *b = false; |
| return true; |
| } |
| if (internal_strcmp(value, "1") == 0 || |
| internal_strcmp(value, "yes") == 0 || |
| internal_strcmp(value, "true") == 0) { |
| *b = true; |
| return true; |
| } |
| return false; |
| } |
| |
| template <> |
| inline bool FlagHandler<bool>::Parse(const char *value) { |
| if (ParseBool(value, t_)) return true; |
| Printf("ERROR: Invalid value for bool option: '%s'\n", value); |
| return false; |
| } |
| |
| template <> |
| inline bool FlagHandler<bool>::Format(char *buffer, uptr size) { |
| return FormatString(buffer, size, *t_ ? "true" : "false"); |
| } |
| |
| template <> |
| inline bool FlagHandler<HandleSignalMode>::Parse(const char *value) { |
| bool b; |
| if (ParseBool(value, &b)) { |
| *t_ = b ? kHandleSignalYes : kHandleSignalNo; |
| return true; |
| } |
| if (internal_strcmp(value, "2") == 0 || |
| internal_strcmp(value, "exclusive") == 0) { |
| *t_ = kHandleSignalExclusive; |
| return true; |
| } |
| Printf("ERROR: Invalid value for signal handler option: '%s'\n", value); |
| return false; |
| } |
| |
| template <> |
| inline bool FlagHandler<HandleSignalMode>::Format(char *buffer, uptr size) { |
| uptr num_symbols_should_write = internal_snprintf(buffer, size, "%d", *t_); |
| return num_symbols_should_write < size; |
| } |
| |
| template <> |
| inline bool FlagHandler<const char *>::Parse(const char *value) { |
| *t_ = value; |
| return true; |
| } |
| |
| template <> |
| inline bool FlagHandler<const char *>::Format(char *buffer, uptr size) { |
| return FormatString(buffer, size, *t_); |
| } |
| |
| template <> |
| inline bool FlagHandler<int>::Parse(const char *value) { |
| const char *value_end; |
| *t_ = internal_simple_strtoll(value, &value_end, 10); |
| bool ok = *value_end == 0; |
| if (!ok) Printf("ERROR: Invalid value for int option: '%s'\n", value); |
| return ok; |
| } |
| |
| template <> |
| inline bool FlagHandler<int>::Format(char *buffer, uptr size) { |
| uptr num_symbols_should_write = internal_snprintf(buffer, size, "%d", *t_); |
| return num_symbols_should_write < size; |
| } |
| |
| template <> |
| inline bool FlagHandler<uptr>::Parse(const char *value) { |
| const char *value_end; |
| *t_ = internal_simple_strtoll(value, &value_end, 10); |
| bool ok = *value_end == 0; |
| if (!ok) Printf("ERROR: Invalid value for uptr option: '%s'\n", value); |
| return ok; |
| } |
| |
| template <> |
| inline bool FlagHandler<uptr>::Format(char *buffer, uptr size) { |
| uptr num_symbols_should_write = internal_snprintf(buffer, size, "%p", *t_); |
| return num_symbols_should_write < size; |
| } |
| |
| template <> |
| inline bool FlagHandler<s64>::Parse(const char *value) { |
| const char *value_end; |
| *t_ = internal_simple_strtoll(value, &value_end, 10); |
| bool ok = *value_end == 0; |
| if (!ok) Printf("ERROR: Invalid value for s64 option: '%s'\n", value); |
| return ok; |
| } |
| |
| template <> |
| inline bool FlagHandler<s64>::Format(char *buffer, uptr size) { |
| uptr num_symbols_should_write = internal_snprintf(buffer, size, "%lld", *t_); |
| return num_symbols_should_write < size; |
| } |
| |
| class FlagParser { |
| static const int kMaxFlags = 200; |
| struct Flag { |
| const char *name; |
| const char *desc; |
| FlagHandlerBase *handler; |
| } *flags_; |
| int n_flags_; |
| |
| const char *buf_; |
| uptr pos_; |
| |
| public: |
| FlagParser(); |
| void RegisterHandler(const char *name, FlagHandlerBase *handler, |
| const char *desc); |
| void ParseString(const char *s, const char *env_name = 0); |
| void ParseStringFromEnv(const char *env_name); |
| bool ParseFile(const char *path, bool ignore_missing); |
| void PrintFlagDescriptions(); |
| |
| static LowLevelAllocator Alloc; |
| |
| private: |
| void fatal_error(const char *err); |
| bool is_space(char c); |
| void skip_whitespace(); |
| void parse_flags(const char *env_option_name); |
| void parse_flag(const char *env_option_name); |
| bool run_handler(const char *name, const char *value); |
| char *ll_strndup(const char *s, uptr n); |
| }; |
| |
| template <typename T> |
| static void RegisterFlag(FlagParser *parser, const char *name, const char *desc, |
| T *var) { |
| FlagHandler<T> *fh = new (FlagParser::Alloc) FlagHandler<T>(var); |
| parser->RegisterHandler(name, fh, desc); |
| } |
| |
| void ReportUnrecognizedFlags(); |
| |
| } // namespace __sanitizer |
| |
| #endif // SANITIZER_FLAG_REGISTRY_H |