13cab2bb3Spatrick //===-- sanitizer_flags.cpp -----------------------------------------------===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // This file is a part of ThreadSanitizer/AddressSanitizer runtime.
103cab2bb3Spatrick //
113cab2bb3Spatrick //===----------------------------------------------------------------------===//
123cab2bb3Spatrick
133cab2bb3Spatrick #include "sanitizer_flags.h"
143cab2bb3Spatrick
153cab2bb3Spatrick #include "sanitizer_common.h"
163cab2bb3Spatrick #include "sanitizer_flag_parser.h"
17*d89ec533Spatrick #include "sanitizer_libc.h"
18*d89ec533Spatrick #include "sanitizer_linux.h"
19*d89ec533Spatrick #include "sanitizer_list.h"
203cab2bb3Spatrick
213cab2bb3Spatrick namespace __sanitizer {
223cab2bb3Spatrick
233cab2bb3Spatrick CommonFlags common_flags_dont_use;
243cab2bb3Spatrick
SetDefaults()253cab2bb3Spatrick void CommonFlags::SetDefaults() {
263cab2bb3Spatrick #define COMMON_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
273cab2bb3Spatrick #include "sanitizer_flags.inc"
283cab2bb3Spatrick #undef COMMON_FLAG
293cab2bb3Spatrick }
303cab2bb3Spatrick
CopyFrom(const CommonFlags & other)313cab2bb3Spatrick void CommonFlags::CopyFrom(const CommonFlags &other) {
323cab2bb3Spatrick internal_memcpy(this, &other, sizeof(*this));
333cab2bb3Spatrick }
343cab2bb3Spatrick
353cab2bb3Spatrick // Copy the string from "s" to "out", making the following substitutions:
363cab2bb3Spatrick // %b = binary basename
373cab2bb3Spatrick // %p = pid
38*d89ec533Spatrick // %d = binary directory
SubstituteForFlagValue(const char * s,char * out,uptr out_size)393cab2bb3Spatrick void SubstituteForFlagValue(const char *s, char *out, uptr out_size) {
403cab2bb3Spatrick char *out_end = out + out_size;
413cab2bb3Spatrick while (*s && out < out_end - 1) {
423cab2bb3Spatrick if (s[0] != '%') {
433cab2bb3Spatrick *out++ = *s++;
443cab2bb3Spatrick continue;
453cab2bb3Spatrick }
463cab2bb3Spatrick switch (s[1]) {
473cab2bb3Spatrick case 'b': {
483cab2bb3Spatrick const char *base = GetProcessName();
493cab2bb3Spatrick CHECK(base);
503cab2bb3Spatrick while (*base && out < out_end - 1)
513cab2bb3Spatrick *out++ = *base++;
523cab2bb3Spatrick s += 2; // skip "%b"
533cab2bb3Spatrick break;
543cab2bb3Spatrick }
553cab2bb3Spatrick case 'p': {
563cab2bb3Spatrick int pid = internal_getpid();
573cab2bb3Spatrick char buf[32];
583cab2bb3Spatrick char *buf_pos = buf + 32;
593cab2bb3Spatrick do {
603cab2bb3Spatrick *--buf_pos = (pid % 10) + '0';
613cab2bb3Spatrick pid /= 10;
623cab2bb3Spatrick } while (pid);
633cab2bb3Spatrick while (buf_pos < buf + 32 && out < out_end - 1)
643cab2bb3Spatrick *out++ = *buf_pos++;
653cab2bb3Spatrick s += 2; // skip "%p"
663cab2bb3Spatrick break;
673cab2bb3Spatrick }
68*d89ec533Spatrick case 'd': {
69*d89ec533Spatrick uptr len = ReadBinaryDir(out, out_end - out);
70*d89ec533Spatrick out += len;
71*d89ec533Spatrick s += 2; // skip "%d"
72*d89ec533Spatrick break;
73*d89ec533Spatrick }
743cab2bb3Spatrick default:
753cab2bb3Spatrick *out++ = *s++;
763cab2bb3Spatrick break;
773cab2bb3Spatrick }
783cab2bb3Spatrick }
793cab2bb3Spatrick CHECK(out < out_end - 1);
803cab2bb3Spatrick *out = '\0';
813cab2bb3Spatrick }
823cab2bb3Spatrick
83*d89ec533Spatrick class FlagHandlerInclude final : public FlagHandlerBase {
843cab2bb3Spatrick FlagParser *parser_;
853cab2bb3Spatrick bool ignore_missing_;
863cab2bb3Spatrick const char *original_path_;
873cab2bb3Spatrick
883cab2bb3Spatrick public:
FlagHandlerInclude(FlagParser * parser,bool ignore_missing)893cab2bb3Spatrick explicit FlagHandlerInclude(FlagParser *parser, bool ignore_missing)
903cab2bb3Spatrick : parser_(parser), ignore_missing_(ignore_missing), original_path_("") {}
Parse(const char * value)913cab2bb3Spatrick bool Parse(const char *value) final {
923cab2bb3Spatrick original_path_ = value;
933cab2bb3Spatrick if (internal_strchr(value, '%')) {
943cab2bb3Spatrick char *buf = (char *)MmapOrDie(kMaxPathLength, "FlagHandlerInclude");
953cab2bb3Spatrick SubstituteForFlagValue(value, buf, kMaxPathLength);
963cab2bb3Spatrick bool res = parser_->ParseFile(buf, ignore_missing_);
973cab2bb3Spatrick UnmapOrDie(buf, kMaxPathLength);
983cab2bb3Spatrick return res;
993cab2bb3Spatrick }
1003cab2bb3Spatrick return parser_->ParseFile(value, ignore_missing_);
1013cab2bb3Spatrick }
Format(char * buffer,uptr size)102*d89ec533Spatrick bool Format(char *buffer, uptr size) override {
1033cab2bb3Spatrick // Note `original_path_` isn't actually what's parsed due to `%`
1043cab2bb3Spatrick // substitutions. Printing the substituted path would require holding onto
1053cab2bb3Spatrick // mmap'ed memory.
1063cab2bb3Spatrick return FormatString(buffer, size, original_path_);
1073cab2bb3Spatrick }
1083cab2bb3Spatrick };
1093cab2bb3Spatrick
RegisterIncludeFlags(FlagParser * parser,CommonFlags * cf)1103cab2bb3Spatrick void RegisterIncludeFlags(FlagParser *parser, CommonFlags *cf) {
1113cab2bb3Spatrick FlagHandlerInclude *fh_include = new (FlagParser::Alloc)
1123cab2bb3Spatrick FlagHandlerInclude(parser, /*ignore_missing*/ false);
1133cab2bb3Spatrick parser->RegisterHandler("include", fh_include,
1143cab2bb3Spatrick "read more options from the given file");
1153cab2bb3Spatrick FlagHandlerInclude *fh_include_if_exists = new (FlagParser::Alloc)
1163cab2bb3Spatrick FlagHandlerInclude(parser, /*ignore_missing*/ true);
1173cab2bb3Spatrick parser->RegisterHandler(
1183cab2bb3Spatrick "include_if_exists", fh_include_if_exists,
1193cab2bb3Spatrick "read more options from the given file (if it exists)");
1203cab2bb3Spatrick }
1213cab2bb3Spatrick
RegisterCommonFlags(FlagParser * parser,CommonFlags * cf)1223cab2bb3Spatrick void RegisterCommonFlags(FlagParser *parser, CommonFlags *cf) {
1233cab2bb3Spatrick #define COMMON_FLAG(Type, Name, DefaultValue, Description) \
1243cab2bb3Spatrick RegisterFlag(parser, #Name, Description, &cf->Name);
1253cab2bb3Spatrick #include "sanitizer_flags.inc"
1263cab2bb3Spatrick #undef COMMON_FLAG
1273cab2bb3Spatrick
1283cab2bb3Spatrick RegisterIncludeFlags(parser, cf);
1293cab2bb3Spatrick }
1303cab2bb3Spatrick
InitializeCommonFlags(CommonFlags * cf)1313cab2bb3Spatrick void InitializeCommonFlags(CommonFlags *cf) {
1323cab2bb3Spatrick // need to record coverage to generate coverage report.
1333cab2bb3Spatrick cf->coverage |= cf->html_cov_report;
1343cab2bb3Spatrick SetVerbosity(cf->verbosity);
135*d89ec533Spatrick
136*d89ec533Spatrick InitializePlatformCommonFlags(cf);
1373cab2bb3Spatrick }
1383cab2bb3Spatrick
1393cab2bb3Spatrick } // namespace __sanitizer
140