blob: b32deca145c19dacc7abf3b394ff894d28ddce4d [file] [log] [blame]
Evgeniy Stepanovf294d5b2015-01-15 15:13:43 +00001//===-- sanitizer_flag_parser.cc ------------------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
11//
12//===----------------------------------------------------------------------===//
13
14#include "sanitizer_flag_parser.h"
15
16#include "sanitizer_common.h"
17#include "sanitizer_libc.h"
18#include "sanitizer_flags.h"
19#include "sanitizer_flag_parser.h"
20#include "sanitizer_allocator_internal.h"
21
22namespace __sanitizer {
23
24void FlagParser::PrintFlagDescriptions() {
25 Printf("Available flags for %s:\n", SanitizerToolName);
26 for (int i = 0; i < n_flags_; ++i)
27 Printf("\t%s\n\t\t- %s\n", flags_[i].name, flags_[i].desc);
28}
29
30void FlagParser::fatal_error(const char *err) {
31 Printf("ERROR: %s\n", err);
32 Die();
33}
34
35bool FlagParser::is_space(char c) {
36 return c == ' ' || c == ',' || c == ':' || c == '\n' || c == '\t' ||
37 c == '\r';
38}
39
40void FlagParser::skip_whitespace() {
41 while (is_space(buf_[pos_])) ++pos_;
42}
43
44void FlagParser::parse_flag() {
45 uptr name_start = pos_;
46 while (buf_[pos_] != 0 && buf_[pos_] != '=' && !is_space(buf_[pos_])) ++pos_;
47 if (buf_[pos_] != '=') fatal_error("expected '='");
Evgeniy Stepanovdb205392015-01-16 09:32:31 +000048 char *name = internal_strndup(buf_ + name_start, pos_ - name_start);
Evgeniy Stepanovf294d5b2015-01-15 15:13:43 +000049
50 uptr value_start = ++pos_;
Evgeniy Stepanovdb205392015-01-16 09:32:31 +000051 char *value;
Evgeniy Stepanovf294d5b2015-01-15 15:13:43 +000052 if (buf_[pos_] == '\'' || buf_[pos_] == '"') {
53 char quote = buf_[pos_++];
54 while (buf_[pos_] != 0 && buf_[pos_] != quote) ++pos_;
55 if (buf_[pos_] == 0) fatal_error("unterminated string");
56 value = internal_strndup(buf_ + value_start + 1, pos_ - value_start - 1);
57 ++pos_; // consume the closing quote
58 } else {
59 while (buf_[pos_] != 0 && !is_space(buf_[pos_])) ++pos_;
60 if (buf_[pos_] != 0 && !is_space(buf_[pos_]))
61 fatal_error("expected separator or eol");
62 value = internal_strndup(buf_ + value_start, pos_ - value_start);
63 }
64
65 bool res = run_handler(name, value);
66 if (!res) {
67 Printf("Flag parsing failed.");
68 Die();
69 }
Evgeniy Stepanovdb205392015-01-16 09:32:31 +000070 InternalFree(name);
71 InternalFree(value);
Evgeniy Stepanovf294d5b2015-01-15 15:13:43 +000072}
73
Evgeniy Stepanovbc14dd42015-01-15 16:26:59 +000074void FlagParser::parse_flags() {
Evgeniy Stepanovf294d5b2015-01-15 15:13:43 +000075 while (true) {
76 skip_whitespace();
77 if (buf_[pos_] == 0) break;
78 parse_flag();
79 }
80
81 // Do a sanity check for certain flags.
82 if (common_flags_dont_use.malloc_context_size < 1)
83 common_flags_dont_use.malloc_context_size = 1;
84}
85
Evgeniy Stepanovbc14dd42015-01-15 16:26:59 +000086void FlagParser::ParseString(const char *s) {
87 if (!s) return;
88 // Backup current parser state to allow nested ParseString() calls.
89 const char *old_buf_ = buf_;
90 uptr old_pos_ = pos_;
91 buf_ = s;
92 pos_ = 0;
93
94 parse_flags();
95
96 buf_ = old_buf_;
97 pos_ = old_pos_;
98}
99
Evgeniy Stepanovf294d5b2015-01-15 15:13:43 +0000100bool FlagParser::run_handler(const char *name, const char *value) {
101 for (int i = 0; i < n_flags_; ++i) {
102 if (internal_strcmp(name, flags_[i].name) == 0)
103 return flags_[i].handler->Parse(value);
104 }
105 Printf("ERROR: Unknown flag: '%s'\n", name);
106 return false;
107}
108
109void FlagParser::RegisterHandler(const char *name, FlagHandlerBase *handler,
110 const char *desc) {
111 CHECK(n_flags_ < kMaxFlags);
112 flags_[n_flags_].name = name;
113 flags_[n_flags_].desc = desc;
114 flags_[n_flags_].handler = handler;
115 ++n_flags_;
116}
117
118FlagParser::FlagParser() : n_flags_(0), buf_(nullptr), pos_(0) {
119 flags_ = (Flag *)InternalAlloc(sizeof(Flag) * kMaxFlags);
120}
121
122FlagParser::~FlagParser() {
123 for (int i = 0; i < n_flags_; ++i)
124 InternalFree(flags_[i].handler);
125 InternalFree(flags_);
126}
127
128} // namespace __sanitizer