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_internal_defs.h"
17 #include "sanitizer_libc.h"
18 #include "sanitizer_common.h"
19 
20 namespace __sanitizer {
21 
22 class FlagHandlerBase {
23  public:
Parse(const char * value)24   virtual bool Parse(const char *value) { return false; }
25 
26  protected:
~FlagHandlerBase()27   ~FlagHandlerBase() {}
28 };
29 
30 template <typename T>
31 class FlagHandler : public FlagHandlerBase {
32   T *t_;
33 
34  public:
FlagHandler(T * t)35   explicit FlagHandler(T *t) : t_(t) {}
36   bool Parse(const char *value) final;
37 };
38 
ParseBool(const char * value,bool * b)39 inline bool ParseBool(const char *value, bool *b) {
40   if (internal_strcmp(value, "0") == 0 ||
41       internal_strcmp(value, "no") == 0 ||
42       internal_strcmp(value, "false") == 0) {
43     *b = false;
44     return true;
45   }
46   if (internal_strcmp(value, "1") == 0 ||
47       internal_strcmp(value, "yes") == 0 ||
48       internal_strcmp(value, "true") == 0) {
49     *b = true;
50     return true;
51   }
52   return false;
53 }
54 
55 template <>
Parse(const char * value)56 inline bool FlagHandler<bool>::Parse(const char *value) {
57   if (ParseBool(value, t_)) return true;
58   Printf("ERROR: Invalid value for bool option: '%s'\n", value);
59   return false;
60 }
61 
62 template <>
Parse(const char * value)63 inline bool FlagHandler<HandleSignalMode>::Parse(const char *value) {
64   bool b;
65   if (ParseBool(value, &b)) {
66     *t_ = b ? kHandleSignalYes : kHandleSignalNo;
67     return true;
68   }
69   if (internal_strcmp(value, "2") == 0 ||
70       internal_strcmp(value, "exclusive") == 0) {
71     *t_ = kHandleSignalExclusive;
72     return true;
73   }
74   Printf("ERROR: Invalid value for signal handler option: '%s'\n", value);
75   return false;
76 }
77 
78 template <>
Parse(const char * value)79 inline bool FlagHandler<const char *>::Parse(const char *value) {
80   *t_ = value;
81   return true;
82 }
83 
84 template <>
Parse(const char * value)85 inline bool FlagHandler<int>::Parse(const char *value) {
86   const char *value_end;
87   *t_ = internal_simple_strtoll(value, &value_end, 10);
88   bool ok = *value_end == 0;
89   if (!ok) Printf("ERROR: Invalid value for int option: '%s'\n", value);
90   return ok;
91 }
92 
93 template <>
Parse(const char * value)94 inline bool FlagHandler<uptr>::Parse(const char *value) {
95   const char *value_end;
96   *t_ = internal_simple_strtoll(value, &value_end, 10);
97   bool ok = *value_end == 0;
98   if (!ok) Printf("ERROR: Invalid value for uptr option: '%s'\n", value);
99   return ok;
100 }
101 
102 template <>
Parse(const char * value)103 inline bool FlagHandler<s64>::Parse(const char *value) {
104   const char *value_end;
105   *t_ = internal_simple_strtoll(value, &value_end, 10);
106   bool ok = *value_end == 0;
107   if (!ok) Printf("ERROR: Invalid value for s64 option: '%s'\n", value);
108   return ok;
109 }
110 
111 class FlagParser {
112   static const int kMaxFlags = 200;
113   struct Flag {
114     const char *name;
115     const char *desc;
116     FlagHandlerBase *handler;
117   } *flags_;
118   int n_flags_;
119 
120   const char *buf_;
121   uptr pos_;
122 
123  public:
124   FlagParser();
125   void RegisterHandler(const char *name, FlagHandlerBase *handler,
126                        const char *desc);
127   void ParseString(const char *s, const char *env_name = 0);
128   void ParseStringFromEnv(const char *env_name);
129   bool ParseFile(const char *path, bool ignore_missing);
130   void PrintFlagDescriptions();
131 
132   static LowLevelAllocator Alloc;
133 
134  private:
135   void fatal_error(const char *err);
136   bool is_space(char c);
137   void skip_whitespace();
138   void parse_flags(const char *env_option_name);
139   void parse_flag(const char *env_option_name);
140   bool run_handler(const char *name, const char *value);
141   char *ll_strndup(const char *s, uptr n);
142 };
143 
144 template <typename T>
RegisterFlag(FlagParser * parser,const char * name,const char * desc,T * var)145 static void RegisterFlag(FlagParser *parser, const char *name, const char *desc,
146                          T *var) {
147   FlagHandler<T> *fh = new (FlagParser::Alloc) FlagHandler<T>(var);
148   parser->RegisterHandler(name, fh, desc);
149 }
150 
151 void ReportUnrecognizedFlags();
152 
153 }  // namespace __sanitizer
154 
155 #endif  // SANITIZER_FLAG_REGISTRY_H
156