master
  1//===-- sanitizer_flag_parser.h ---------------------------------*- C++ -*-===//
  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-exception
  6//
  7//===----------------------------------------------------------------------===//
  8//
  9// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
 10//
 11//===----------------------------------------------------------------------===//
 12
 13#ifndef SANITIZER_FLAG_REGISTRY_H
 14#define SANITIZER_FLAG_REGISTRY_H
 15
 16#include "sanitizer_common.h"
 17#include "sanitizer_internal_defs.h"
 18#include "sanitizer_libc.h"
 19
 20namespace __sanitizer {
 21
 22class FlagHandlerBase {
 23 public:
 24  virtual bool Parse(const char *value) { return false; }
 25  // Write the C string representation of the current value (truncated to fit)
 26  // into the buffer of size `size`. Returns false if truncation occurred and
 27  // returns true otherwise.
 28  virtual bool Format(char *buffer, uptr size) {
 29    if (size > 0)
 30      buffer[0] = '\0';
 31    return false;
 32  }
 33
 34 protected:
 35  ~FlagHandlerBase() {}
 36
 37  inline bool FormatString(char *buffer, uptr size, const char *str_to_use) {
 38    uptr num_symbols_should_write =
 39        internal_snprintf(buffer, size, "%s", str_to_use);
 40    return num_symbols_should_write < size;
 41  }
 42};
 43
 44template <typename T>
 45class FlagHandler final : public FlagHandlerBase {
 46  T *t_;
 47
 48 public:
 49  explicit FlagHandler(T *t) : t_(t) {}
 50  bool Parse(const char *value) final;
 51  bool Format(char *buffer, uptr size) final;
 52};
 53
 54inline bool ParseBool(const char *value, bool *b) {
 55  if (internal_strcmp(value, "0") == 0 ||
 56      internal_strcmp(value, "no") == 0 ||
 57      internal_strcmp(value, "false") == 0) {
 58    *b = false;
 59    return true;
 60  }
 61  if (internal_strcmp(value, "1") == 0 ||
 62      internal_strcmp(value, "yes") == 0 ||
 63      internal_strcmp(value, "true") == 0) {
 64    *b = true;
 65    return true;
 66  }
 67  return false;
 68}
 69
 70template <>
 71inline bool FlagHandler<bool>::Parse(const char *value) {
 72  if (ParseBool(value, t_)) return true;
 73  Printf("ERROR: Invalid value for bool option: '%s'\n", value);
 74  return false;
 75}
 76
 77template <>
 78inline bool FlagHandler<bool>::Format(char *buffer, uptr size) {
 79  return FormatString(buffer, size, *t_ ? "true" : "false");
 80}
 81
 82template <>
 83inline bool FlagHandler<HandleSignalMode>::Parse(const char *value) {
 84  bool b;
 85  if (ParseBool(value, &b)) {
 86    *t_ = b ? kHandleSignalYes : kHandleSignalNo;
 87    return true;
 88  }
 89  if (internal_strcmp(value, "2") == 0 ||
 90      internal_strcmp(value, "exclusive") == 0) {
 91    *t_ = kHandleSignalExclusive;
 92    return true;
 93  }
 94  Printf("ERROR: Invalid value for signal handler option: '%s'\n", value);
 95  return false;
 96}
 97
 98template <>
 99inline bool FlagHandler<HandleSignalMode>::Format(char *buffer, uptr size) {
100  uptr num_symbols_should_write = internal_snprintf(buffer, size, "%d", *t_);
101  return num_symbols_should_write < size;
102}
103
104template <>
105inline bool FlagHandler<const char *>::Parse(const char *value) {
106  *t_ = value;
107  return true;
108}
109
110template <>
111inline bool FlagHandler<const char *>::Format(char *buffer, uptr size) {
112  return FormatString(buffer, size, *t_);
113}
114
115template <>
116inline bool FlagHandler<int>::Parse(const char *value) {
117  const char *value_end;
118  *t_ = internal_simple_strtoll(value, &value_end, 10);
119  bool ok = *value_end == 0;
120  if (!ok) Printf("ERROR: Invalid value for int option: '%s'\n", value);
121  return ok;
122}
123
124template <>
125inline bool FlagHandler<int>::Format(char *buffer, uptr size) {
126  uptr num_symbols_should_write = internal_snprintf(buffer, size, "%d", *t_);
127  return num_symbols_should_write < size;
128}
129
130template <>
131inline bool FlagHandler<uptr>::Parse(const char *value) {
132  const char *value_end;
133  *t_ = internal_simple_strtoll(value, &value_end, 10);
134  bool ok = *value_end == 0;
135  if (!ok) Printf("ERROR: Invalid value for uptr option: '%s'\n", value);
136  return ok;
137}
138
139template <>
140inline bool FlagHandler<uptr>::Format(char *buffer, uptr size) {
141  uptr num_symbols_should_write = internal_snprintf(buffer, size, "0x%zx", *t_);
142  return num_symbols_should_write < size;
143}
144
145template <>
146inline bool FlagHandler<s64>::Parse(const char *value) {
147  const char *value_end;
148  *t_ = internal_simple_strtoll(value, &value_end, 10);
149  bool ok = *value_end == 0;
150  if (!ok) Printf("ERROR: Invalid value for s64 option: '%s'\n", value);
151  return ok;
152}
153
154template <>
155inline bool FlagHandler<s64>::Format(char *buffer, uptr size) {
156  uptr num_symbols_should_write = internal_snprintf(buffer, size, "%lld", *t_);
157  return num_symbols_should_write < size;
158}
159
160class FlagParser {
161  static const int kMaxFlags = 200;
162  struct Flag {
163    const char *name;
164    const char *desc;
165    FlagHandlerBase *handler;
166  } *flags_;
167  int n_flags_;
168
169  const char *buf_;
170  uptr pos_;
171
172 public:
173  FlagParser();
174  void RegisterHandler(const char *name, FlagHandlerBase *handler,
175                       const char *desc);
176  void ParseString(const char *s, const char *env_name = 0);
177  void ParseStringFromEnv(const char *env_name);
178  bool ParseFile(const char *path, bool ignore_missing);
179  void PrintFlagDescriptions();
180
181 private:
182  void fatal_error(const char *err);
183  bool is_space(char c);
184  void skip_whitespace();
185  void parse_flags(const char *env_option_name);
186  void parse_flag(const char *env_option_name);
187  bool run_handler(const char *name, const char *value);
188  char *ll_strndup(const char *s, uptr n);
189};
190
191template <typename T>
192static void RegisterFlag(FlagParser *parser, const char *name, const char *desc,
193                         T *var) {
194  FlagHandler<T> *fh = new (GetGlobalLowLevelAllocator()) FlagHandler<T>(var);
195  parser->RegisterHandler(name, fh, desc);
196}
197
198void ReportUnrecognizedFlags();
199
200}  // namespace __sanitizer
201
202#endif  // SANITIZER_FLAG_REGISTRY_H