1 //===-- sanitizer_flag_parser.cc ------------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file is a part of ThreadSanitizer/AddressSanitizer runtime.
12 //===----------------------------------------------------------------------===//
14 #include "sanitizer_flag_parser.h"
16 #include "sanitizer_common.h"
17 #include "sanitizer_libc.h"
18 #include "sanitizer_flags.h"
19 #include "sanitizer_flag_parser.h"
21 namespace __sanitizer
{
23 LowLevelAllocator
FlagParser::Alloc
;
26 static const int kMaxUnknownFlags
= 20;
27 const char *unknown_flags_
[kMaxUnknownFlags
];
31 void Add(const char *name
) {
32 CHECK_LT(n_unknown_flags_
, kMaxUnknownFlags
);
33 unknown_flags_
[n_unknown_flags_
++] = name
;
37 if (!n_unknown_flags_
) return;
38 Printf("WARNING: found %d unrecognized flag(s):\n", n_unknown_flags_
);
39 for (int i
= 0; i
< n_unknown_flags_
; ++i
)
40 Printf(" %s\n", unknown_flags_
[i
]);
45 UnknownFlags unknown_flags
;
47 void ReportUnrecognizedFlags() {
48 unknown_flags
.Report();
51 char *FlagParser::ll_strndup(const char *s
, uptr n
) {
52 uptr len
= internal_strnlen(s
, n
);
53 char *s2
= (char*)Alloc
.Allocate(len
+ 1);
54 internal_memcpy(s2
, s
, len
);
59 void FlagParser::PrintFlagDescriptions() {
60 Printf("Available flags for %s:\n", SanitizerToolName
);
61 for (int i
= 0; i
< n_flags_
; ++i
)
62 Printf("\t%s\n\t\t- %s\n", flags_
[i
].name
, flags_
[i
].desc
);
65 void FlagParser::fatal_error(const char *err
) {
66 Printf("ERROR: %s\n", err
);
70 bool FlagParser::is_space(char c
) {
71 return c
== ' ' || c
== ',' || c
== ':' || c
== '\n' || c
== '\t' ||
75 void FlagParser::skip_whitespace() {
76 while (is_space(buf_
[pos_
])) ++pos_
;
79 void FlagParser::parse_flag() {
80 uptr name_start
= pos_
;
81 while (buf_
[pos_
] != 0 && buf_
[pos_
] != '=' && !is_space(buf_
[pos_
])) ++pos_
;
82 if (buf_
[pos_
] != '=') fatal_error("expected '='");
83 char *name
= ll_strndup(buf_
+ name_start
, pos_
- name_start
);
85 uptr value_start
= ++pos_
;
87 if (buf_
[pos_
] == '\'' || buf_
[pos_
] == '"') {
88 char quote
= buf_
[pos_
++];
89 while (buf_
[pos_
] != 0 && buf_
[pos_
] != quote
) ++pos_
;
90 if (buf_
[pos_
] == 0) fatal_error("unterminated string");
91 value
= ll_strndup(buf_
+ value_start
+ 1, pos_
- value_start
- 1);
92 ++pos_
; // consume the closing quote
94 while (buf_
[pos_
] != 0 && !is_space(buf_
[pos_
])) ++pos_
;
95 if (buf_
[pos_
] != 0 && !is_space(buf_
[pos_
]))
96 fatal_error("expected separator or eol");
97 value
= ll_strndup(buf_
+ value_start
, pos_
- value_start
);
100 bool res
= run_handler(name
, value
);
101 if (!res
) fatal_error("Flag parsing failed.");
104 void FlagParser::parse_flags() {
107 if (buf_
[pos_
] == 0) break;
111 // Do a sanity check for certain flags.
112 if (common_flags_dont_use
.malloc_context_size
< 1)
113 common_flags_dont_use
.malloc_context_size
= 1;
116 void FlagParser::ParseString(const char *s
) {
118 // Backup current parser state to allow nested ParseString() calls.
119 const char *old_buf_
= buf_
;
120 uptr old_pos_
= pos_
;
130 bool FlagParser::ParseFile(const char *path
, bool ignore_missing
) {
131 static const uptr kMaxIncludeSize
= 1 << 15;
133 uptr data_mapped_size
;
136 if (!ReadFileToBuffer(path
, &data
, &data_mapped_size
, &len
,
137 Max(kMaxIncludeSize
, GetPageSizeCached()), &err
)) {
140 Printf("Failed to read options from '%s': error %d\n", path
, err
);
144 UnmapOrDie(data
, data_mapped_size
);
148 bool FlagParser::run_handler(const char *name
, const char *value
) {
149 for (int i
= 0; i
< n_flags_
; ++i
) {
150 if (internal_strcmp(name
, flags_
[i
].name
) == 0)
151 return flags_
[i
].handler
->Parse(value
);
153 // Unrecognized flag. This is not a fatal error, we may print a warning later.
154 unknown_flags
.Add(name
);
158 void FlagParser::RegisterHandler(const char *name
, FlagHandlerBase
*handler
,
160 CHECK_LT(n_flags_
, kMaxFlags
);
161 flags_
[n_flags_
].name
= name
;
162 flags_
[n_flags_
].desc
= desc
;
163 flags_
[n_flags_
].handler
= handler
;
167 FlagParser::FlagParser() : n_flags_(0), buf_(nullptr), pos_(0) {
168 flags_
= (Flag
*)Alloc
.Allocate(sizeof(Flag
) * kMaxFlags
);
171 } // namespace __sanitizer