168d75effSDimitry Andric //===-- sanitizer_flags.cpp -----------------------------------------------===// 268d75effSDimitry Andric // 368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 668d75effSDimitry Andric // 768d75effSDimitry Andric //===----------------------------------------------------------------------===// 868d75effSDimitry Andric // 968d75effSDimitry Andric // This file is a part of ThreadSanitizer/AddressSanitizer runtime. 1068d75effSDimitry Andric // 1168d75effSDimitry Andric //===----------------------------------------------------------------------===// 1268d75effSDimitry Andric 1368d75effSDimitry Andric #include "sanitizer_flags.h" 1468d75effSDimitry Andric 1568d75effSDimitry Andric #include "sanitizer_common.h" 1668d75effSDimitry Andric #include "sanitizer_flag_parser.h" 17e8d8bef9SDimitry Andric #include "sanitizer_libc.h" 18e8d8bef9SDimitry Andric #include "sanitizer_linux.h" 19e8d8bef9SDimitry Andric #include "sanitizer_list.h" 2068d75effSDimitry Andric 2168d75effSDimitry Andric namespace __sanitizer { 2268d75effSDimitry Andric 2368d75effSDimitry Andric CommonFlags common_flags_dont_use; 2468d75effSDimitry Andric 2568d75effSDimitry Andric void CommonFlags::SetDefaults() { 2668d75effSDimitry Andric #define COMMON_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue; 2768d75effSDimitry Andric #include "sanitizer_flags.inc" 2868d75effSDimitry Andric #undef COMMON_FLAG 2968d75effSDimitry Andric } 3068d75effSDimitry Andric 3168d75effSDimitry Andric void CommonFlags::CopyFrom(const CommonFlags &other) { 3268d75effSDimitry Andric internal_memcpy(this, &other, sizeof(*this)); 3368d75effSDimitry Andric } 3468d75effSDimitry Andric 3568d75effSDimitry Andric // Copy the string from "s" to "out", making the following substitutions: 3668d75effSDimitry Andric // %b = binary basename 3768d75effSDimitry Andric // %p = pid 38fe6060f1SDimitry Andric // %d = binary directory 3968d75effSDimitry Andric void SubstituteForFlagValue(const char *s, char *out, uptr out_size) { 4068d75effSDimitry Andric char *out_end = out + out_size; 4168d75effSDimitry Andric while (*s && out < out_end - 1) { 4268d75effSDimitry Andric if (s[0] != '%') { 4368d75effSDimitry Andric *out++ = *s++; 4468d75effSDimitry Andric continue; 4568d75effSDimitry Andric } 4668d75effSDimitry Andric switch (s[1]) { 4768d75effSDimitry Andric case 'b': { 4868d75effSDimitry Andric const char *base = GetProcessName(); 4968d75effSDimitry Andric CHECK(base); 5068d75effSDimitry Andric while (*base && out < out_end - 1) 5168d75effSDimitry Andric *out++ = *base++; 5268d75effSDimitry Andric s += 2; // skip "%b" 5368d75effSDimitry Andric break; 5468d75effSDimitry Andric } 5568d75effSDimitry Andric case 'p': { 5668d75effSDimitry Andric int pid = internal_getpid(); 5768d75effSDimitry Andric char buf[32]; 5868d75effSDimitry Andric char *buf_pos = buf + 32; 5968d75effSDimitry Andric do { 6068d75effSDimitry Andric *--buf_pos = (pid % 10) + '0'; 6168d75effSDimitry Andric pid /= 10; 6268d75effSDimitry Andric } while (pid); 6368d75effSDimitry Andric while (buf_pos < buf + 32 && out < out_end - 1) 6468d75effSDimitry Andric *out++ = *buf_pos++; 6568d75effSDimitry Andric s += 2; // skip "%p" 6668d75effSDimitry Andric break; 6768d75effSDimitry Andric } 68fe6060f1SDimitry Andric case 'd': { 69fe6060f1SDimitry Andric uptr len = ReadBinaryDir(out, out_end - out); 70fe6060f1SDimitry Andric out += len; 71fe6060f1SDimitry Andric s += 2; // skip "%d" 72fe6060f1SDimitry Andric break; 73fe6060f1SDimitry Andric } 7468d75effSDimitry Andric default: 7568d75effSDimitry Andric *out++ = *s++; 7668d75effSDimitry Andric break; 7768d75effSDimitry Andric } 7868d75effSDimitry Andric } 7968d75effSDimitry Andric CHECK(out < out_end - 1); 8068d75effSDimitry Andric *out = '\0'; 8168d75effSDimitry Andric } 8268d75effSDimitry Andric 83e8d8bef9SDimitry Andric class FlagHandlerInclude final : public FlagHandlerBase { 8468d75effSDimitry Andric FlagParser *parser_; 8568d75effSDimitry Andric bool ignore_missing_; 86480093f4SDimitry Andric const char *original_path_; 8768d75effSDimitry Andric 8868d75effSDimitry Andric public: 8968d75effSDimitry Andric explicit FlagHandlerInclude(FlagParser *parser, bool ignore_missing) 90480093f4SDimitry Andric : parser_(parser), ignore_missing_(ignore_missing), original_path_("") {} 9168d75effSDimitry Andric bool Parse(const char *value) final { 92480093f4SDimitry Andric original_path_ = value; 9368d75effSDimitry Andric if (internal_strchr(value, '%')) { 9468d75effSDimitry Andric char *buf = (char *)MmapOrDie(kMaxPathLength, "FlagHandlerInclude"); 9568d75effSDimitry Andric SubstituteForFlagValue(value, buf, kMaxPathLength); 9668d75effSDimitry Andric bool res = parser_->ParseFile(buf, ignore_missing_); 9768d75effSDimitry Andric UnmapOrDie(buf, kMaxPathLength); 9868d75effSDimitry Andric return res; 9968d75effSDimitry Andric } 10068d75effSDimitry Andric return parser_->ParseFile(value, ignore_missing_); 10168d75effSDimitry Andric } 102e8d8bef9SDimitry Andric bool Format(char *buffer, uptr size) override { 103480093f4SDimitry Andric // Note `original_path_` isn't actually what's parsed due to `%` 104480093f4SDimitry Andric // substitutions. Printing the substituted path would require holding onto 105480093f4SDimitry Andric // mmap'ed memory. 106480093f4SDimitry Andric return FormatString(buffer, size, original_path_); 107480093f4SDimitry Andric } 10868d75effSDimitry Andric }; 10968d75effSDimitry Andric 11068d75effSDimitry Andric void RegisterIncludeFlags(FlagParser *parser, CommonFlags *cf) { 111*5f757f3fSDimitry Andric FlagHandlerInclude *fh_include = new (GetGlobalLowLevelAllocator()) 11268d75effSDimitry Andric FlagHandlerInclude(parser, /*ignore_missing*/ false); 11368d75effSDimitry Andric parser->RegisterHandler("include", fh_include, 11468d75effSDimitry Andric "read more options from the given file"); 115*5f757f3fSDimitry Andric FlagHandlerInclude *fh_include_if_exists = new (GetGlobalLowLevelAllocator()) 11668d75effSDimitry Andric FlagHandlerInclude(parser, /*ignore_missing*/ true); 11768d75effSDimitry Andric parser->RegisterHandler( 11868d75effSDimitry Andric "include_if_exists", fh_include_if_exists, 11968d75effSDimitry Andric "read more options from the given file (if it exists)"); 12068d75effSDimitry Andric } 12168d75effSDimitry Andric 12268d75effSDimitry Andric void RegisterCommonFlags(FlagParser *parser, CommonFlags *cf) { 12368d75effSDimitry Andric #define COMMON_FLAG(Type, Name, DefaultValue, Description) \ 12468d75effSDimitry Andric RegisterFlag(parser, #Name, Description, &cf->Name); 12568d75effSDimitry Andric #include "sanitizer_flags.inc" 12668d75effSDimitry Andric #undef COMMON_FLAG 12768d75effSDimitry Andric 12868d75effSDimitry Andric RegisterIncludeFlags(parser, cf); 12968d75effSDimitry Andric } 13068d75effSDimitry Andric 13168d75effSDimitry Andric void InitializeCommonFlags(CommonFlags *cf) { 13268d75effSDimitry Andric // need to record coverage to generate coverage report. 13368d75effSDimitry Andric cf->coverage |= cf->html_cov_report; 13468d75effSDimitry Andric SetVerbosity(cf->verbosity); 135e8d8bef9SDimitry Andric 136e8d8bef9SDimitry Andric InitializePlatformCommonFlags(cf); 13768d75effSDimitry Andric } 13868d75effSDimitry Andric 13968d75effSDimitry Andric } // namespace __sanitizer 140