1//===-- sanitizer_flags.cc ------------------------------------------------===//
2//
3// This file is distributed under the University of Illinois Open Source
4// License. See LICENSE.TXT for details.
5//
6//===----------------------------------------------------------------------===//
7//
8// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
9//
10//===----------------------------------------------------------------------===//
11
12#include "sanitizer_flags.h"
13
14#include "sanitizer_common.h"
15#include "sanitizer_libc.h"
16#include "sanitizer_list.h"
17#include "sanitizer_flag_parser.h"
18
19namespace __sanitizer {
20
21CommonFlags common_flags_dont_use;
22
23void CommonFlags::SetDefaults() {
24#define COMMON_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
25#include "sanitizer_flags.inc"
26#undef COMMON_FLAG
27}
28
29void CommonFlags::CopyFrom(const CommonFlags &other) {
30  internal_memcpy(this, &other, sizeof(*this));
31}
32
33// Copy the string from "s" to "out", making the following substitutions:
34// %b = binary basename
35// %p = pid
36void SubstituteForFlagValue(const char *s, char *out, uptr out_size) {
37  char *out_end = out + out_size;
38  while (*s && out < out_end - 1) {
39    if (s[0] != '%') {
40      *out++ = *s++;
41      continue;
42    }
43    switch (s[1]) {
44      case 'b': {
45        const char *base = GetProcessName();
46        CHECK(base);
47        while (*base && out < out_end - 1)
48          *out++ = *base++;
49        s += 2; // skip "%b"
50        break;
51      }
52      case 'p': {
53        int pid = internal_getpid();
54        char buf[32];
55        char *buf_pos = buf + 32;
56        do {
57          *--buf_pos = (pid % 10) + '0';
58          pid /= 10;
59        } while (pid);
60        while (buf_pos < buf + 32 && out < out_end - 1)
61          *out++ = *buf_pos++;
62        s += 2; // skip "%p"
63        break;
64      }
65      default:
66        *out++ = *s++;
67        break;
68    }
69  }
70  CHECK(out < out_end - 1);
71  *out = '\0';
72}
73
74class FlagHandlerInclude : public FlagHandlerBase {
75  FlagParser *parser_;
76  bool ignore_missing_;
77
78 public:
79  explicit FlagHandlerInclude(FlagParser *parser, bool ignore_missing)
80      : parser_(parser), ignore_missing_(ignore_missing) {}
81  bool Parse(const char *value) final {
82    if (internal_strchr(value, '%')) {
83      char *buf = (char *)MmapOrDie(kMaxPathLength, "FlagHandlerInclude");
84      SubstituteForFlagValue(value, buf, kMaxPathLength);
85      bool res = parser_->ParseFile(buf, ignore_missing_);
86      UnmapOrDie(buf, kMaxPathLength);
87      return res;
88    }
89    return parser_->ParseFile(value, ignore_missing_);
90  }
91};
92
93void RegisterIncludeFlags(FlagParser *parser, CommonFlags *cf) {
94  FlagHandlerInclude *fh_include = new (FlagParser::Alloc) // NOLINT
95      FlagHandlerInclude(parser, /*ignore_missing*/ false);
96  parser->RegisterHandler("include", fh_include,
97                          "read more options from the given file");
98  FlagHandlerInclude *fh_include_if_exists = new (FlagParser::Alloc) // NOLINT
99      FlagHandlerInclude(parser, /*ignore_missing*/ true);
100  parser->RegisterHandler(
101      "include_if_exists", fh_include_if_exists,
102      "read more options from the given file (if it exists)");
103}
104
105void RegisterCommonFlags(FlagParser *parser, CommonFlags *cf) {
106#define COMMON_FLAG(Type, Name, DefaultValue, Description) \
107  RegisterFlag(parser, #Name, Description, &cf->Name);
108#include "sanitizer_flags.inc"
109#undef COMMON_FLAG
110
111  RegisterIncludeFlags(parser, cf);
112}
113
114void InitializeCommonFlags(CommonFlags *cf) {
115  // need to record coverage to generate coverage report.
116  cf->coverage |= cf->html_cov_report;
117  SetVerbosity(cf->verbosity);
118}
119
120}  // namespace __sanitizer
121