Rebase.
[official-gcc.git] / libsanitizer / sanitizer_common / sanitizer_flags.cc
blobe90d79e436025c44dd22e2e9ff07954aa69bfa9a
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 //===----------------------------------------------------------------------===//
12 #include "sanitizer_flags.h"
14 #include "sanitizer_common.h"
15 #include "sanitizer_libc.h"
16 #include "sanitizer_list.h"
18 namespace __sanitizer {
20 CommonFlags common_flags_dont_use;
22 struct FlagDescription {
23 const char *name;
24 const char *description;
25 FlagDescription *next;
28 IntrusiveList<FlagDescription> flag_descriptions;
30 void SetCommonFlagsDefaults(CommonFlags *f) {
31 f->symbolize = true;
32 f->external_symbolizer_path = 0;
33 f->allow_addr2line = false;
34 f->strip_path_prefix = "";
35 f->fast_unwind_on_fatal = false;
36 f->fast_unwind_on_malloc = true;
37 f->handle_ioctl = false;
38 f->malloc_context_size = 1;
39 f->log_path = "stderr";
40 f->verbosity = 0;
41 f->detect_leaks = true;
42 f->leak_check_at_exit = true;
43 f->allocator_may_return_null = false;
44 f->print_summary = true;
45 f->check_printf = true;
46 // TODO(glider): tools may want to set different defaults for handle_segv.
47 f->handle_segv = SANITIZER_NEEDS_SEGV;
48 f->allow_user_segv_handler = false;
49 f->use_sigaltstack = true;
50 f->detect_deadlocks = false;
51 f->clear_shadow_mmap_threshold = 64 * 1024;
52 f->color = "auto";
53 f->legacy_pthread_cond = false;
54 f->intercept_tls_get_addr = false;
55 f->coverage = false;
56 f->full_address_space = false;
59 void ParseCommonFlagsFromString(CommonFlags *f, const char *str) {
60 ParseFlag(str, &f->symbolize, "symbolize",
61 "If set, use the online symbolizer from common sanitizer runtime to turn "
62 "virtual addresses to file/line locations.");
63 ParseFlag(str, &f->external_symbolizer_path, "external_symbolizer_path",
64 "Path to external symbolizer. If empty, the tool will search $PATH for "
65 "the symbolizer.");
66 ParseFlag(str, &f->allow_addr2line, "allow_addr2line",
67 "If set, allows online symbolizer to run addr2line binary to symbolize "
68 "stack traces (addr2line will only be used if llvm-symbolizer binary is "
69 "unavailable.");
70 ParseFlag(str, &f->strip_path_prefix, "strip_path_prefix",
71 "Strips this prefix from file paths in error reports.");
72 ParseFlag(str, &f->fast_unwind_on_fatal, "fast_unwind_on_fatal",
73 "If available, use the fast frame-pointer-based unwinder on fatal "
74 "errors.");
75 ParseFlag(str, &f->fast_unwind_on_malloc, "fast_unwind_on_malloc",
76 "If available, use the fast frame-pointer-based unwinder on "
77 "malloc/free.");
78 ParseFlag(str, &f->handle_ioctl, "handle_ioctl",
79 "Intercept and handle ioctl requests.");
80 ParseFlag(str, &f->malloc_context_size, "malloc_context_size",
81 "Max number of stack frames kept for each allocation/deallocation.");
82 ParseFlag(str, &f->log_path, "log_path",
83 "Write logs to \"log_path.pid\". The special values are \"stdout\" and "
84 "\"stderr\". The default is \"stderr\".");
85 ParseFlag(str, &f->verbosity, "verbosity",
86 "Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).");
87 ParseFlag(str, &f->detect_leaks, "detect_leaks",
88 "Enable memory leak detection.");
89 ParseFlag(str, &f->leak_check_at_exit, "leak_check_at_exit",
90 "Invoke leak checking in an atexit handler. Has no effect if "
91 "detect_leaks=false, or if __lsan_do_leak_check() is called before the "
92 "handler has a chance to run.");
93 ParseFlag(str, &f->allocator_may_return_null, "allocator_may_return_null",
94 "If false, the allocator will crash instead of returning 0 on "
95 "out-of-memory.");
96 ParseFlag(str, &f->print_summary, "print_summary",
97 "If false, disable printing error summaries in addition to error "
98 "reports.");
99 ParseFlag(str, &f->check_printf, "check_printf",
100 "Check printf arguments.");
101 ParseFlag(str, &f->handle_segv, "handle_segv",
102 "If set, registers the tool's custom SEGV handler (both SIGBUS and "
103 "SIGSEGV on OSX).");
104 ParseFlag(str, &f->allow_user_segv_handler, "allow_user_segv_handler",
105 "If set, allows user to register a SEGV handler even if the tool "
106 "registers one.");
107 ParseFlag(str, &f->use_sigaltstack, "use_sigaltstack",
108 "If set, uses alternate stack for signal handling.");
109 ParseFlag(str, &f->detect_deadlocks, "detect_deadlocks",
110 "If set, deadlock detection is enabled.");
111 ParseFlag(str, &f->clear_shadow_mmap_threshold,
112 "clear_shadow_mmap_threshold",
113 "Large shadow regions are zero-filled using mmap(NORESERVE) instead of "
114 "memset(). This is the threshold size in bytes.");
115 ParseFlag(str, &f->color, "color",
116 "Colorize reports: (always|never|auto).");
117 ParseFlag(str, &f->legacy_pthread_cond, "legacy_pthread_cond",
118 "Enables support for dynamic libraries linked with libpthread 2.2.5.");
119 ParseFlag(str, &f->intercept_tls_get_addr, "intercept_tls_get_addr",
120 "Intercept __tls_get_addr.");
121 ParseFlag(str, &f->help, "help", "Print the flag descriptions.");
122 ParseFlag(str, &f->mmap_limit_mb, "mmap_limit_mb",
123 "Limit the amount of mmap-ed memory (excluding shadow) in Mb; "
124 "not a user-facing flag, used mosly for testing the tools");
125 ParseFlag(str, &f->coverage, "coverage",
126 "If set, coverage information will be dumped at program shutdown (if the "
127 "coverage instrumentation was enabled at compile time).");
128 ParseFlag(str, &f->full_address_space, "full_address_space",
129 "Sanitize complete address space; "
130 "by default kernel area on 32-bit platforms will not be sanitized");
132 // Do a sanity check for certain flags.
133 if (f->malloc_context_size < 1)
134 f->malloc_context_size = 1;
137 static bool GetFlagValue(const char *env, const char *name,
138 const char **value, int *value_length) {
139 if (env == 0)
140 return false;
141 const char *pos = 0;
142 for (;;) {
143 pos = internal_strstr(env, name);
144 if (pos == 0)
145 return false;
146 if (pos != env && ((pos[-1] >= 'a' && pos[-1] <= 'z') || pos[-1] == '_')) {
147 // Seems to be middle of another flag name or value.
148 env = pos + 1;
149 continue;
151 break;
153 pos += internal_strlen(name);
154 const char *end;
155 if (pos[0] != '=') {
156 end = pos;
157 } else {
158 pos += 1;
159 if (pos[0] == '"') {
160 pos += 1;
161 end = internal_strchr(pos, '"');
162 } else if (pos[0] == '\'') {
163 pos += 1;
164 end = internal_strchr(pos, '\'');
165 } else {
166 // Read until the next space or colon.
167 end = pos + internal_strcspn(pos, " :");
169 if (end == 0)
170 end = pos + internal_strlen(pos);
172 *value = pos;
173 *value_length = end - pos;
174 return true;
177 static bool StartsWith(const char *flag, int flag_length, const char *value) {
178 if (!flag || !value)
179 return false;
180 int value_length = internal_strlen(value);
181 return (flag_length >= value_length) &&
182 (0 == internal_strncmp(flag, value, value_length));
185 static LowLevelAllocator allocator_for_flags;
187 // The linear scan is suboptimal, but the number of flags is relatively small.
188 bool FlagInDescriptionList(const char *name) {
189 IntrusiveList<FlagDescription>::Iterator it(&flag_descriptions);
190 while (it.hasNext()) {
191 if (!internal_strcmp(it.next()->name, name)) return true;
193 return false;
196 void AddFlagDescription(const char *name, const char *description) {
197 if (FlagInDescriptionList(name)) return;
198 FlagDescription *new_description = new(allocator_for_flags) FlagDescription;
199 new_description->name = name;
200 new_description->description = description;
201 flag_descriptions.push_back(new_description);
204 // TODO(glider): put the descriptions inside CommonFlags.
205 void PrintFlagDescriptions() {
206 IntrusiveList<FlagDescription>::Iterator it(&flag_descriptions);
207 Printf("Available flags for %s:\n", SanitizerToolName);
208 while (it.hasNext()) {
209 FlagDescription *descr = it.next();
210 Printf("\t%s\n\t\t- %s\n", descr->name, descr->description);
214 void ParseFlag(const char *env, bool *flag,
215 const char *name, const char *descr) {
216 const char *value;
217 int value_length;
218 AddFlagDescription(name, descr);
219 if (!GetFlagValue(env, name, &value, &value_length))
220 return;
221 if (StartsWith(value, value_length, "0") ||
222 StartsWith(value, value_length, "no") ||
223 StartsWith(value, value_length, "false"))
224 *flag = false;
225 if (StartsWith(value, value_length, "1") ||
226 StartsWith(value, value_length, "yes") ||
227 StartsWith(value, value_length, "true"))
228 *flag = true;
231 void ParseFlag(const char *env, int *flag,
232 const char *name, const char *descr) {
233 const char *value;
234 int value_length;
235 AddFlagDescription(name, descr);
236 if (!GetFlagValue(env, name, &value, &value_length))
237 return;
238 *flag = static_cast<int>(internal_atoll(value));
241 void ParseFlag(const char *env, uptr *flag,
242 const char *name, const char *descr) {
243 const char *value;
244 int value_length;
245 AddFlagDescription(name, descr);
246 if (!GetFlagValue(env, name, &value, &value_length))
247 return;
248 *flag = static_cast<uptr>(internal_atoll(value));
251 void ParseFlag(const char *env, const char **flag,
252 const char *name, const char *descr) {
253 const char *value;
254 int value_length;
255 AddFlagDescription(name, descr);
256 if (!GetFlagValue(env, name, &value, &value_length))
257 return;
258 // Copy the flag value. Don't use locks here, as flags are parsed at
259 // tool startup.
260 char *value_copy = (char*)(allocator_for_flags.Allocate(value_length + 1));
261 internal_memcpy(value_copy, value, value_length);
262 value_copy[value_length] = '\0';
263 *flag = value_copy;
266 } // namespace __sanitizer