| //===--- EnvironmentVariables.h - Debug variables. --------------*- C++ -*-===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Debug behavior conditionally enabled using environment variables. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "swift/Runtime/Debug.h" |
| #include "swift/Runtime/EnvironmentVariables.h" |
| |
| #include <string.h> |
| |
| using namespace swift; |
| |
| namespace { |
| |
| // Require all environment variable names to start with SWIFT_ |
| static constexpr bool hasSwiftPrefix(const char *str) { |
| const char prefix[] = "SWIFT_"; |
| for (unsigned i = 0; i < sizeof(prefix) - 1; i++) |
| if (str[i] != prefix[i]) |
| return false; |
| return true; |
| } |
| #define VARIABLE(name, type, defaultValue, help) \ |
| static_assert(hasSwiftPrefix(#name), "Names must start with SWIFT"); |
| #include "EnvironmentVariables.def" |
| |
| // Value parsers. Add new functions named parse_<type> to accommodate more |
| // debug variable types. |
| static bool parse_bool(const char *name, const char *value, bool defaultValue) { |
| if (!value) |
| return defaultValue; |
| switch (value[0]) { |
| case 'Y': |
| case 'y': |
| case 'T': |
| case 't': |
| case '1': |
| return true; |
| case 'N': |
| case 'n': |
| case 'F': |
| case 'f': |
| case '0': |
| return false; |
| default: |
| swift::warning(RuntimeErrorFlagNone, |
| "Warning: cannot parse value %s=%s, defaulting to %s.\n", |
| name, value, defaultValue ? "true" : "false"); |
| return defaultValue; |
| } |
| } |
| |
| static uint8_t parse_uint8_t(const char *name, |
| const char *value, |
| uint8_t defaultValue) { |
| if (!value) |
| return defaultValue; |
| char *end; |
| long n = strtol(value, &end, 0); |
| if (*end != '\0') { |
| swift::warning(RuntimeErrorFlagNone, |
| "Warning: cannot parse value %s=%s, defaulting to %u.\n", |
| name, value, defaultValue); |
| return defaultValue; |
| } |
| |
| if (n < 0) { |
| swift::warning(RuntimeErrorFlagNone, |
| "Warning: %s=%s out of bounds, clamping to 0.\n", |
| name, value); |
| return 0; |
| } |
| if (n > UINT8_MAX) { |
| swift::warning(RuntimeErrorFlagNone, |
| "Warning: %s=%s out of bounds, clamping to %d.\n", |
| name, value, UINT8_MAX); |
| return UINT8_MAX; |
| } |
| |
| return n; |
| } |
| |
| // Print a list of all the environment variables. Lazy initialization makes |
| // this a bit odd, but the use of these variables in the metadata system means |
| // it's almost certain to run early. |
| // |
| // The "extra" parameter is printed after the header and before the list of |
| // variables. |
| void printHelp(const char *extra) { |
| swift::warning(RuntimeErrorFlagNone, "Swift runtime debugging:\n"); |
| if (extra) |
| swift::warning(RuntimeErrorFlagNone, "%s\n", extra); |
| #define VARIABLE(name, type, defaultValue, help) \ |
| swift::warning(RuntimeErrorFlagNone, "%7s %s [default: %s] - %s\n", \ |
| #type, #name, #defaultValue, help); |
| #include "EnvironmentVariables.def" |
| swift::warning(RuntimeErrorFlagNone, "SWIFT_DEBUG_HELP=YES - Print this help."); |
| } |
| |
| } // end anonymous namespace |
| |
| // Define backing variables. |
| #define VARIABLE(name, type, defaultValue, help) \ |
| type swift::runtime::environment::name ## _variable = defaultValue; |
| #include "EnvironmentVariables.def" |
| |
| // Initialization code. |
| OnceToken_t swift::runtime::environment::initializeToken; |
| |
| #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__linux__) |
| extern "C" char **environ; |
| #define ENVIRON environ |
| #elif defined(_WIN32) |
| extern "C" char **_environ; |
| #define ENVIRON _environ |
| #endif |
| |
| #ifdef ENVIRON |
| void swift::runtime::environment::initialize(void *context) { |
| // On platforms where we have an environment variable array available, scan it |
| // directly. This optimizes for the common case where no variables are set, |
| // since we only need to perform one scan to set all variables. It also allows |
| // us to detect some spelling mistakes by warning on unknown SWIFT_ variables. |
| |
| bool SWIFT_DEBUG_HELP_variable = false; |
| for (char **var = ENVIRON; *var; var++) { |
| // Immediately skip anything without a SWIFT_ prefix. |
| if (strncmp(*var, "SWIFT_", 6) != 0) |
| continue; |
| |
| bool foundVariable = false; |
| // Check each defined variable in turn, plus SWIFT_DEBUG_HELP. Variables are |
| // parsed by functions named parse_<type> above. An unknown type will |
| // produce an error that parse_<unknown-type> doesn't exist. Add new parsers |
| // above. |
| #define VARIABLE(name, type, defaultValue, help) \ |
| if (strncmp(*var, #name "=", strlen(#name "=")) == 0) { \ |
| name ## _variable = \ |
| parse_ ## type(#name, *var + strlen(#name "="), defaultValue); \ |
| foundVariable = true; \ |
| } |
| // SWIFT_DEBUG_HELP is not in the variables list. Parse it like the other |
| // variables. |
| VARIABLE(SWIFT_DEBUG_HELP, bool, false, ) |
| #include "EnvironmentVariables.def" |
| |
| // Flag unknown SWIFT_DEBUG_ variables to catch misspellings. We don't flag |
| // all unknown SWIFT_ variables, because there are a bunch of other SWIFT_ |
| // variables used for other purposes, such as SWIFT_SOURCE_ROOT and |
| // SWIFT_INSTALL_DIR, and we don't want to warn for all of those. |
| const char *swiftDebugPrefix = "SWIFT_DEBUG_"; |
| if (!foundVariable && |
| strncmp(*var, swiftDebugPrefix, strlen(swiftDebugPrefix)) == 0) { |
| const char *equals = strchr(*var, '='); |
| if (!equals) |
| equals = *var + strlen(*var); |
| swift::warning(RuntimeErrorFlagNone, |
| "Warning: unknown environment variable %.*s\n", |
| (int)(equals - *var), *var); |
| } |
| } |
| |
| if (SWIFT_DEBUG_HELP_variable) |
| printHelp(nullptr); |
| } |
| #else |
| void swift::runtime::environment::initialize(void *context) { |
| // Emit a getenv call for each variable. This is less efficient but works |
| // everywhere. |
| #define VARIABLE(name, type, defaultValue, help) \ |
| name ## _variable = parse_ ## type(#name, getenv(#name), defaultValue); |
| #include "EnvironmentVariables.def" |
| |
| // Print help if requested. |
| if (parse_bool("SWIFT_DEBUG_HELP", getenv("SWIFT_DEBUG_HELP"), false)) |
| printHelp("Using getenv to read variables. Unknown SWIFT_DEBUG_ variables " |
| "will not be flagged."); |
| } |
| #endif |
| |
| SWIFT_RUNTIME_EXPORT |
| bool swift_COWChecksEnabled() { |
| return runtime::environment::SWIFT_DEBUG_ENABLE_COW_CHECKS(); |
| } |
| |