xref: /freebsd/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_flag_parser.h (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===-- sanitizer_flag_parser.h ---------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file is a part of ThreadSanitizer/AddressSanitizer runtime.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #ifndef SANITIZER_FLAG_REGISTRY_H
140b57cec5SDimitry Andric #define SANITIZER_FLAG_REGISTRY_H
150b57cec5SDimitry Andric 
1606c3fb27SDimitry Andric #include "sanitizer_common.h"
170b57cec5SDimitry Andric #include "sanitizer_internal_defs.h"
180b57cec5SDimitry Andric #include "sanitizer_libc.h"
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric namespace __sanitizer {
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric class FlagHandlerBase {
230b57cec5SDimitry Andric  public:
240b57cec5SDimitry Andric   virtual bool Parse(const char *value) { return false; }
25480093f4SDimitry Andric   // Write the C string representation of the current value (truncated to fit)
26480093f4SDimitry Andric   // into the buffer of size `size`. Returns false if truncation occurred and
27480093f4SDimitry Andric   // returns true otherwise.
28480093f4SDimitry Andric   virtual bool Format(char *buffer, uptr size) {
29480093f4SDimitry Andric     if (size > 0)
30480093f4SDimitry Andric       buffer[0] = '\0';
31480093f4SDimitry Andric     return false;
32480093f4SDimitry Andric   }
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric  protected:
3568d75effSDimitry Andric   ~FlagHandlerBase() {}
36480093f4SDimitry Andric 
37480093f4SDimitry Andric   inline bool FormatString(char *buffer, uptr size, const char *str_to_use) {
38480093f4SDimitry Andric     uptr num_symbols_should_write =
39480093f4SDimitry Andric         internal_snprintf(buffer, size, "%s", str_to_use);
40480093f4SDimitry Andric     return num_symbols_should_write < size;
41480093f4SDimitry Andric   }
420b57cec5SDimitry Andric };
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric template <typename T>
45e8d8bef9SDimitry Andric class FlagHandler final : public FlagHandlerBase {
460b57cec5SDimitry Andric   T *t_;
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric  public:
490b57cec5SDimitry Andric   explicit FlagHandler(T *t) : t_(t) {}
500b57cec5SDimitry Andric   bool Parse(const char *value) final;
51480093f4SDimitry Andric   bool Format(char *buffer, uptr size) final;
520b57cec5SDimitry Andric };
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric inline bool ParseBool(const char *value, bool *b) {
550b57cec5SDimitry Andric   if (internal_strcmp(value, "0") == 0 ||
560b57cec5SDimitry Andric       internal_strcmp(value, "no") == 0 ||
570b57cec5SDimitry Andric       internal_strcmp(value, "false") == 0) {
580b57cec5SDimitry Andric     *b = false;
590b57cec5SDimitry Andric     return true;
600b57cec5SDimitry Andric   }
610b57cec5SDimitry Andric   if (internal_strcmp(value, "1") == 0 ||
620b57cec5SDimitry Andric       internal_strcmp(value, "yes") == 0 ||
630b57cec5SDimitry Andric       internal_strcmp(value, "true") == 0) {
640b57cec5SDimitry Andric     *b = true;
650b57cec5SDimitry Andric     return true;
660b57cec5SDimitry Andric   }
670b57cec5SDimitry Andric   return false;
680b57cec5SDimitry Andric }
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric template <>
710b57cec5SDimitry Andric inline bool FlagHandler<bool>::Parse(const char *value) {
720b57cec5SDimitry Andric   if (ParseBool(value, t_)) return true;
730b57cec5SDimitry Andric   Printf("ERROR: Invalid value for bool option: '%s'\n", value);
740b57cec5SDimitry Andric   return false;
750b57cec5SDimitry Andric }
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric template <>
78480093f4SDimitry Andric inline bool FlagHandler<bool>::Format(char *buffer, uptr size) {
79480093f4SDimitry Andric   return FormatString(buffer, size, *t_ ? "true" : "false");
80480093f4SDimitry Andric }
81480093f4SDimitry Andric 
82480093f4SDimitry Andric template <>
830b57cec5SDimitry Andric inline bool FlagHandler<HandleSignalMode>::Parse(const char *value) {
840b57cec5SDimitry Andric   bool b;
850b57cec5SDimitry Andric   if (ParseBool(value, &b)) {
860b57cec5SDimitry Andric     *t_ = b ? kHandleSignalYes : kHandleSignalNo;
870b57cec5SDimitry Andric     return true;
880b57cec5SDimitry Andric   }
890b57cec5SDimitry Andric   if (internal_strcmp(value, "2") == 0 ||
900b57cec5SDimitry Andric       internal_strcmp(value, "exclusive") == 0) {
910b57cec5SDimitry Andric     *t_ = kHandleSignalExclusive;
920b57cec5SDimitry Andric     return true;
930b57cec5SDimitry Andric   }
940b57cec5SDimitry Andric   Printf("ERROR: Invalid value for signal handler option: '%s'\n", value);
950b57cec5SDimitry Andric   return false;
960b57cec5SDimitry Andric }
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric template <>
99480093f4SDimitry Andric inline bool FlagHandler<HandleSignalMode>::Format(char *buffer, uptr size) {
100480093f4SDimitry Andric   uptr num_symbols_should_write = internal_snprintf(buffer, size, "%d", *t_);
101480093f4SDimitry Andric   return num_symbols_should_write < size;
102480093f4SDimitry Andric }
103480093f4SDimitry Andric 
104480093f4SDimitry Andric template <>
1050b57cec5SDimitry Andric inline bool FlagHandler<const char *>::Parse(const char *value) {
1060b57cec5SDimitry Andric   *t_ = value;
1070b57cec5SDimitry Andric   return true;
1080b57cec5SDimitry Andric }
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric template <>
111480093f4SDimitry Andric inline bool FlagHandler<const char *>::Format(char *buffer, uptr size) {
112480093f4SDimitry Andric   return FormatString(buffer, size, *t_);
113480093f4SDimitry Andric }
114480093f4SDimitry Andric 
115480093f4SDimitry Andric template <>
1160b57cec5SDimitry Andric inline bool FlagHandler<int>::Parse(const char *value) {
1170b57cec5SDimitry Andric   const char *value_end;
1180b57cec5SDimitry Andric   *t_ = internal_simple_strtoll(value, &value_end, 10);
1190b57cec5SDimitry Andric   bool ok = *value_end == 0;
1200b57cec5SDimitry Andric   if (!ok) Printf("ERROR: Invalid value for int option: '%s'\n", value);
1210b57cec5SDimitry Andric   return ok;
1220b57cec5SDimitry Andric }
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric template <>
125480093f4SDimitry Andric inline bool FlagHandler<int>::Format(char *buffer, uptr size) {
126480093f4SDimitry Andric   uptr num_symbols_should_write = internal_snprintf(buffer, size, "%d", *t_);
127480093f4SDimitry Andric   return num_symbols_should_write < size;
128480093f4SDimitry Andric }
129480093f4SDimitry Andric 
130480093f4SDimitry Andric template <>
1310b57cec5SDimitry Andric inline bool FlagHandler<uptr>::Parse(const char *value) {
1320b57cec5SDimitry Andric   const char *value_end;
1330b57cec5SDimitry Andric   *t_ = internal_simple_strtoll(value, &value_end, 10);
1340b57cec5SDimitry Andric   bool ok = *value_end == 0;
1350b57cec5SDimitry Andric   if (!ok) Printf("ERROR: Invalid value for uptr option: '%s'\n", value);
1360b57cec5SDimitry Andric   return ok;
1370b57cec5SDimitry Andric }
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric template <>
140480093f4SDimitry Andric inline bool FlagHandler<uptr>::Format(char *buffer, uptr size) {
141349cc55cSDimitry Andric   uptr num_symbols_should_write = internal_snprintf(buffer, size, "0x%zx", *t_);
142480093f4SDimitry Andric   return num_symbols_should_write < size;
143480093f4SDimitry Andric }
144480093f4SDimitry Andric 
145480093f4SDimitry Andric template <>
1460b57cec5SDimitry Andric inline bool FlagHandler<s64>::Parse(const char *value) {
1470b57cec5SDimitry Andric   const char *value_end;
1480b57cec5SDimitry Andric   *t_ = internal_simple_strtoll(value, &value_end, 10);
1490b57cec5SDimitry Andric   bool ok = *value_end == 0;
1500b57cec5SDimitry Andric   if (!ok) Printf("ERROR: Invalid value for s64 option: '%s'\n", value);
1510b57cec5SDimitry Andric   return ok;
1520b57cec5SDimitry Andric }
1530b57cec5SDimitry Andric 
154480093f4SDimitry Andric template <>
155480093f4SDimitry Andric inline bool FlagHandler<s64>::Format(char *buffer, uptr size) {
156480093f4SDimitry Andric   uptr num_symbols_should_write = internal_snprintf(buffer, size, "%lld", *t_);
157480093f4SDimitry Andric   return num_symbols_should_write < size;
158480093f4SDimitry Andric }
159480093f4SDimitry Andric 
1600b57cec5SDimitry Andric class FlagParser {
1610b57cec5SDimitry Andric   static const int kMaxFlags = 200;
1620b57cec5SDimitry Andric   struct Flag {
1630b57cec5SDimitry Andric     const char *name;
1640b57cec5SDimitry Andric     const char *desc;
1650b57cec5SDimitry Andric     FlagHandlerBase *handler;
1660b57cec5SDimitry Andric   } *flags_;
1670b57cec5SDimitry Andric   int n_flags_;
1680b57cec5SDimitry Andric 
1690b57cec5SDimitry Andric   const char *buf_;
1700b57cec5SDimitry Andric   uptr pos_;
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric  public:
1730b57cec5SDimitry Andric   FlagParser();
1740b57cec5SDimitry Andric   void RegisterHandler(const char *name, FlagHandlerBase *handler,
1750b57cec5SDimitry Andric                        const char *desc);
1760b57cec5SDimitry Andric   void ParseString(const char *s, const char *env_name = 0);
1770b57cec5SDimitry Andric   void ParseStringFromEnv(const char *env_name);
1780b57cec5SDimitry Andric   bool ParseFile(const char *path, bool ignore_missing);
1790b57cec5SDimitry Andric   void PrintFlagDescriptions();
1800b57cec5SDimitry Andric 
1810b57cec5SDimitry Andric  private:
1820b57cec5SDimitry Andric   void fatal_error(const char *err);
1830b57cec5SDimitry Andric   bool is_space(char c);
1840b57cec5SDimitry Andric   void skip_whitespace();
1850b57cec5SDimitry Andric   void parse_flags(const char *env_option_name);
1860b57cec5SDimitry Andric   void parse_flag(const char *env_option_name);
1870b57cec5SDimitry Andric   bool run_handler(const char *name, const char *value);
1880b57cec5SDimitry Andric   char *ll_strndup(const char *s, uptr n);
1890b57cec5SDimitry Andric };
1900b57cec5SDimitry Andric 
1910b57cec5SDimitry Andric template <typename T>
1920b57cec5SDimitry Andric static void RegisterFlag(FlagParser *parser, const char *name, const char *desc,
1930b57cec5SDimitry Andric                          T *var) {
194*5f757f3fSDimitry Andric   FlagHandler<T> *fh = new (GetGlobalLowLevelAllocator()) FlagHandler<T>(var);
1950b57cec5SDimitry Andric   parser->RegisterHandler(name, fh, desc);
1960b57cec5SDimitry Andric }
1970b57cec5SDimitry Andric 
1980b57cec5SDimitry Andric void ReportUnrecognizedFlags();
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric }  // namespace __sanitizer
2010b57cec5SDimitry Andric 
2020b57cec5SDimitry Andric #endif  // SANITIZER_FLAG_REGISTRY_H
203