203 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file is a part of ThreadSanitizer/AddressSanitizer runtime.10//11//===----------------------------------------------------------------------===//12 13#ifndef SANITIZER_FLAG_REGISTRY_H14#define SANITIZER_FLAG_REGISTRY_H15 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 and27 // 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 __sanitizer201 202#endif // SANITIZER_FLAG_REGISTRY_H203