1278497Sdim//===-- sanitizer_flag_parser.h ---------------------------------*- C++ -*-===//
2278497Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6278497Sdim//
7278497Sdim//===----------------------------------------------------------------------===//
8278497Sdim//
9278497Sdim// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
10278497Sdim//
11278497Sdim//===----------------------------------------------------------------------===//
12278497Sdim
13278497Sdim#ifndef SANITIZER_FLAG_REGISTRY_H
14278497Sdim#define SANITIZER_FLAG_REGISTRY_H
15278497Sdim
16278497Sdim#include "sanitizer_internal_defs.h"
17278497Sdim#include "sanitizer_libc.h"
18278497Sdim#include "sanitizer_common.h"
19278497Sdim
20278497Sdimnamespace __sanitizer {
21278497Sdim
22278497Sdimclass FlagHandlerBase {
23278497Sdim public:
24278497Sdim  virtual bool Parse(const char *value) { return false; }
25360784Sdim  // Write the C string representation of the current value (truncated to fit)
26360784Sdim  // into the buffer of size `size`. Returns false if truncation occurred and
27360784Sdim  // returns true otherwise.
28360784Sdim  virtual bool Format(char *buffer, uptr size) {
29360784Sdim    if (size > 0)
30360784Sdim      buffer[0] = '\0';
31360784Sdim    return false;
32360784Sdim  }
33353358Sdim
34353358Sdim protected:
35360784Sdim  ~FlagHandlerBase() {}
36360784Sdim
37360784Sdim  inline bool FormatString(char *buffer, uptr size, const char *str_to_use) {
38360784Sdim    uptr num_symbols_should_write =
39360784Sdim        internal_snprintf(buffer, size, "%s", str_to_use);
40360784Sdim    return num_symbols_should_write < size;
41360784Sdim  }
42278497Sdim};
43278497Sdim
44278497Sdimtemplate <typename T>
45278497Sdimclass FlagHandler : public FlagHandlerBase {
46278497Sdim  T *t_;
47278497Sdim
48278497Sdim public:
49278497Sdim  explicit FlagHandler(T *t) : t_(t) {}
50279194Sdim  bool Parse(const char *value) final;
51360784Sdim  bool Format(char *buffer, uptr size) final;
52278497Sdim};
53278497Sdim
54321369Sdiminline bool ParseBool(const char *value, bool *b) {
55278497Sdim  if (internal_strcmp(value, "0") == 0 ||
56278497Sdim      internal_strcmp(value, "no") == 0 ||
57278497Sdim      internal_strcmp(value, "false") == 0) {
58321369Sdim    *b = false;
59278497Sdim    return true;
60278497Sdim  }
61278497Sdim  if (internal_strcmp(value, "1") == 0 ||
62278497Sdim      internal_strcmp(value, "yes") == 0 ||
63278497Sdim      internal_strcmp(value, "true") == 0) {
64321369Sdim    *b = true;
65278497Sdim    return true;
66278497Sdim  }
67321369Sdim  return false;
68321369Sdim}
69321369Sdim
70321369Sdimtemplate <>
71321369Sdiminline bool FlagHandler<bool>::Parse(const char *value) {
72321369Sdim  if (ParseBool(value, t_)) return true;
73278497Sdim  Printf("ERROR: Invalid value for bool option: '%s'\n", value);
74278497Sdim  return false;
75278497Sdim}
76278497Sdim
77278497Sdimtemplate <>
78360784Sdiminline bool FlagHandler<bool>::Format(char *buffer, uptr size) {
79360784Sdim  return FormatString(buffer, size, *t_ ? "true" : "false");
80360784Sdim}
81360784Sdim
82360784Sdimtemplate <>
83321369Sdiminline bool FlagHandler<HandleSignalMode>::Parse(const char *value) {
84321369Sdim  bool b;
85321369Sdim  if (ParseBool(value, &b)) {
86321369Sdim    *t_ = b ? kHandleSignalYes : kHandleSignalNo;
87321369Sdim    return true;
88321369Sdim  }
89321369Sdim  if (internal_strcmp(value, "2") == 0 ||
90321369Sdim      internal_strcmp(value, "exclusive") == 0) {
91321369Sdim    *t_ = kHandleSignalExclusive;
92321369Sdim    return true;
93321369Sdim  }
94321369Sdim  Printf("ERROR: Invalid value for signal handler option: '%s'\n", value);
95321369Sdim  return false;
96321369Sdim}
97321369Sdim
98321369Sdimtemplate <>
99360784Sdiminline bool FlagHandler<HandleSignalMode>::Format(char *buffer, uptr size) {
100360784Sdim  uptr num_symbols_should_write = internal_snprintf(buffer, size, "%d", *t_);
101360784Sdim  return num_symbols_should_write < size;
102360784Sdim}
103360784Sdim
104360784Sdimtemplate <>
105278497Sdiminline bool FlagHandler<const char *>::Parse(const char *value) {
106327952Sdim  *t_ = value;
107278497Sdim  return true;
108278497Sdim}
109278497Sdim
110278497Sdimtemplate <>
111360784Sdiminline bool FlagHandler<const char *>::Format(char *buffer, uptr size) {
112360784Sdim  return FormatString(buffer, size, *t_);
113360784Sdim}
114360784Sdim
115360784Sdimtemplate <>
116278497Sdiminline bool FlagHandler<int>::Parse(const char *value) {
117341825Sdim  const char *value_end;
118278497Sdim  *t_ = internal_simple_strtoll(value, &value_end, 10);
119278497Sdim  bool ok = *value_end == 0;
120278497Sdim  if (!ok) Printf("ERROR: Invalid value for int option: '%s'\n", value);
121278497Sdim  return ok;
122278497Sdim}
123278497Sdim
124278497Sdimtemplate <>
125360784Sdiminline bool FlagHandler<int>::Format(char *buffer, uptr size) {
126360784Sdim  uptr num_symbols_should_write = internal_snprintf(buffer, size, "%d", *t_);
127360784Sdim  return num_symbols_should_write < size;
128360784Sdim}
129360784Sdim
130360784Sdimtemplate <>
131278497Sdiminline bool FlagHandler<uptr>::Parse(const char *value) {
132341825Sdim  const char *value_end;
133278497Sdim  *t_ = internal_simple_strtoll(value, &value_end, 10);
134278497Sdim  bool ok = *value_end == 0;
135278497Sdim  if (!ok) Printf("ERROR: Invalid value for uptr option: '%s'\n", value);
136278497Sdim  return ok;
137278497Sdim}
138278497Sdim
139353358Sdimtemplate <>
140360784Sdiminline bool FlagHandler<uptr>::Format(char *buffer, uptr size) {
141360784Sdim  uptr num_symbols_should_write = internal_snprintf(buffer, size, "%p", *t_);
142360784Sdim  return num_symbols_should_write < size;
143360784Sdim}
144360784Sdim
145360784Sdimtemplate <>
146353358Sdiminline bool FlagHandler<s64>::Parse(const char *value) {
147353358Sdim  const char *value_end;
148353358Sdim  *t_ = internal_simple_strtoll(value, &value_end, 10);
149353358Sdim  bool ok = *value_end == 0;
150353358Sdim  if (!ok) Printf("ERROR: Invalid value for s64 option: '%s'\n", value);
151353358Sdim  return ok;
152353358Sdim}
153353358Sdim
154360784Sdimtemplate <>
155360784Sdiminline bool FlagHandler<s64>::Format(char *buffer, uptr size) {
156360784Sdim  uptr num_symbols_should_write = internal_snprintf(buffer, size, "%lld", *t_);
157360784Sdim  return num_symbols_should_write < size;
158360784Sdim}
159360784Sdim
160278497Sdimclass FlagParser {
161278497Sdim  static const int kMaxFlags = 200;
162278497Sdim  struct Flag {
163278497Sdim    const char *name;
164278497Sdim    const char *desc;
165278497Sdim    FlagHandlerBase *handler;
166278497Sdim  } *flags_;
167278497Sdim  int n_flags_;
168278497Sdim
169278497Sdim  const char *buf_;
170278497Sdim  uptr pos_;
171278497Sdim
172278497Sdim public:
173278497Sdim  FlagParser();
174278497Sdim  void RegisterHandler(const char *name, FlagHandlerBase *handler,
175278497Sdim                       const char *desc);
176353358Sdim  void ParseString(const char *s, const char *env_name = 0);
177353358Sdim  void ParseStringFromEnv(const char *env_name);
178296417Sdim  bool ParseFile(const char *path, bool ignore_missing);
179278497Sdim  void PrintFlagDescriptions();
180278497Sdim
181278497Sdim  static LowLevelAllocator Alloc;
182278497Sdim
183278497Sdim private:
184278497Sdim  void fatal_error(const char *err);
185278497Sdim  bool is_space(char c);
186278497Sdim  void skip_whitespace();
187353358Sdim  void parse_flags(const char *env_option_name);
188353358Sdim  void parse_flag(const char *env_option_name);
189278497Sdim  bool run_handler(const char *name, const char *value);
190278497Sdim  char *ll_strndup(const char *s, uptr n);
191278497Sdim};
192278497Sdim
193278497Sdimtemplate <typename T>
194278497Sdimstatic void RegisterFlag(FlagParser *parser, const char *name, const char *desc,
195278497Sdim                         T *var) {
196360784Sdim  FlagHandler<T> *fh = new (FlagParser::Alloc) FlagHandler<T>(var);
197278497Sdim  parser->RegisterHandler(name, fh, desc);
198278497Sdim}
199278497Sdim
200278497Sdimvoid ReportUnrecognizedFlags();
201278497Sdim
202278497Sdim}  // namespace __sanitizer
203278497Sdim
204278497Sdim#endif  // SANITIZER_FLAG_REGISTRY_H
205