| /* |
| * Copyright (C) 2003-2025 Apple Inc. All rights reserved. |
| * Copyright (C) 2007-2009 Torch Mobile, Inc. |
| * Copyright (C) 2011 University of Szeged. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include <wtf/Assertions.h> |
| |
| #include <stdio.h> |
| #include <string.h> |
| #include <wtf/Compiler.h> |
| #include <wtf/Lock.h> |
| #include <wtf/Locker.h> |
| #include <wtf/LoggingAccumulator.h> |
| #include <wtf/NeverDestroyed.h> |
| #include <wtf/PrintStream.h> |
| #include <wtf/StackTrace.h> |
| #include <wtf/StdLibExtras.h> |
| #include <wtf/WTFConfig.h> |
| #include <wtf/text/CString.h> |
| #include <wtf/text/MakeString.h> |
| #include <wtf/text/StringBuilder.h> |
| #include <wtf/text/StringCommon.h> |
| #include <wtf/text/WTFString.h> |
| |
| #if USE(CF) |
| #include <CoreFoundation/CFString.h> |
| #endif // USE(CF) |
| |
| #if OS(WINDOWS) |
| #include <crtdbg.h> |
| #include <windows.h> |
| #endif |
| |
| #if OS(DARWIN) |
| #include <array> |
| #include <sys/sysctl.h> |
| #include <unistd.h> |
| #include <wtf/OSObjectPtr.h> |
| #endif |
| |
| #if ENABLE(JOURNALD_LOG) |
| #include <stdlib.h> |
| #include <unistd.h> |
| #endif |
| |
| #if !RELEASE_LOG_DISABLED && !USE(OS_LOG) |
| #include <wtf/StringPrintStream.h> |
| #endif |
| |
| #if PLATFORM(COCOA) |
| #import <wtf/spi/cocoa/OSLogSPI.h> |
| #endif |
| |
| WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN |
| |
| namespace WTF { |
| |
| WTF_ATTRIBUTE_NSSTRING(1, 0) |
| static String createWithFormatAndArguments(const char* format, va_list args) |
| { |
| va_list argsCopy; |
| va_copy(argsCopy, args); |
| |
| auto formatSpan = unsafeSpan(format); |
| |
| ALLOW_NONLITERAL_FORMAT_BEGIN |
| |
| #if USE(CF) |
| if (contains(formatSpan, "%@"_span)) { |
| auto cfFormat = adoptCF(CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, format, kCFStringEncodingUTF8, kCFAllocatorNull)); |
| auto result = adoptCF(CFStringCreateWithFormatAndArguments(kCFAllocatorDefault, nullptr, cfFormat.get(), args)); |
| va_end(argsCopy); |
| return result.get(); |
| } |
| #endif |
| |
| // Do the format once to get the length. |
| #if OS(WINDOWS) |
| int result = _vscprintf(formatSpan.data(), args); |
| #else |
| char ch; |
| int result = vsnprintf(&ch, 1, formatSpan.data(), args); |
| #endif |
| |
| if (!result) { |
| va_end(argsCopy); |
| return emptyString(); |
| } |
| if (result < 0) { |
| va_end(argsCopy); |
| return { }; |
| } |
| |
| Vector<char, 256> buffer; |
| buffer.grow(result + 1); |
| |
| // Now do the formatting again, guaranteed to fit. |
| vsnprintf(buffer.mutableSpan().data(), buffer.size(), formatSpan.data(), argsCopy); |
| va_end(argsCopy); |
| |
| ALLOW_NONLITERAL_FORMAT_END |
| |
| return StringImpl::create(buffer.subspan(0, buffer.size() - 1)); |
| } |
| |
| #if PLATFORM(COCOA) || OS(ANDROID) |
| void disableForwardingVPrintfStdErrToOSLog() |
| { |
| g_wtfConfig.disableForwardingVPrintfStdErrToOSLog = true; |
| } |
| #endif |
| |
| } // namespace WTF |
| |
| extern "C" { |
| |
| #if PLATFORM(COCOA) |
| static os_log_t webkitSubsystemForGenericOSLog() |
| { |
| SUPPRESS_RETAINPTR_CTOR_ADOPT static NeverDestroyed<OSObjectPtr<os_log_t>> subsystem = adoptOSObject(os_log_create(LOG_CHANNEL_WEBKIT_SUBSYSTEM, "Generic")); |
| return subsystem.get().get(); |
| } |
| #endif |
| |
| static void logToStderr([[maybe_unused]] WTFLogChannel* channel, const char* buffer) |
| { |
| #if PLATFORM(COCOA) |
| os_log(channel ? channel->osLogChannel : webkitSubsystemForGenericOSLog(), "%s", buffer); |
| #elif OS(ANDROID) |
| __android_log_write(ANDROID_LOG_VERBOSE, LOG_CHANNEL_WEBKIT_SUBSYSTEM, buffer); |
| #endif |
| fputs(buffer, stderr); |
| } |
| |
| WTF_ATTRIBUTE_NSSTRING(2, 0) |
| static void vprintf_stderr_common([[maybe_unused]] WTFLogChannel* channel, const char* format, va_list args) |
| { |
| auto formatSpan = unsafeSpan(format); |
| |
| ALLOW_NONLITERAL_FORMAT_BEGIN |
| |
| #if USE(CF) |
| if (contains(formatSpan, "%@"_span)) { |
| auto cfFormat = adoptCF(CFStringCreateWithCStringNoCopy(nullptr, format, kCFStringEncodingUTF8, kCFAllocatorNull)); |
| |
| auto str = adoptCF(CFStringCreateWithFormatAndArguments(nullptr, nullptr, cfFormat.get(), args)); |
| CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str.get()), kCFStringEncodingUTF8); |
| constexpr unsigned InitialBufferSize { 256 }; |
| Vector<char, InitialBufferSize> buffer(length + 1); |
| |
| CFStringGetCString(str.get(), buffer.mutableSpan().data(), length, kCFStringEncodingUTF8); |
| |
| logToStderr(channel, buffer.span().data()); |
| return; |
| } |
| |
| #if PLATFORM(COCOA) |
| if (!g_wtfConfig.disableForwardingVPrintfStdErrToOSLog) { |
| os_log_t osLogChannel = channel ? channel->osLogChannel : webkitSubsystemForGenericOSLog(); |
| va_list copyOfArgs; |
| va_copy(copyOfArgs, args); |
| os_log_with_args(osLogChannel, OS_LOG_TYPE_DEFAULT, formatSpan.data(), copyOfArgs, __builtin_return_address(0)); |
| va_end(copyOfArgs); |
| } |
| #endif |
| |
| #if OS(ANDROID) |
| if (!g_wtfConfig.disableForwardingVPrintfStdErrToOSLog) { |
| va_list copyOfArgs; |
| va_copy(copyOfArgs, args); |
| __android_log_vprint(ANDROID_LOG_ERROR, LOG_CHANNEL_WEBKIT_SUBSYSTEM, formatSpan.data(), copyOfArgs); |
| va_end(copyOfArgs); |
| } |
| #endif |
| |
| // Fall through to write to stderr in the same manner as other platforms. |
| |
| #elif HAVE(ISDEBUGGERPRESENT) |
| if (IsDebuggerPresent()) { |
| size_t size = 1024; |
| Vector<char> buffer(size); |
| do { |
| buffer.grow(size); |
| if (vsnprintf(buffer.mutableSpan().data(), size, formatSpan.data(), args) != -1) { |
| OutputDebugStringA(buffer.span().data()); |
| break; |
| } |
| size *= 2; |
| } while (size > 1024); |
| } |
| #endif |
| vfprintf(stderr, formatSpan.data(), args); |
| ALLOW_NONLITERAL_FORMAT_END |
| } |
| |
| WTF_ATTRIBUTE_NSSTRING(2, 0) |
| static void vprintf_stderr_with_prefix(const char* rawPrefix, const char* rawFormat, va_list args) |
| { |
| auto prefix = unsafeSpan(rawPrefix); |
| auto format = unsafeSpan(rawFormat); |
| Vector<char> formatWithPrefix(prefix.size() + format.size() + 1); |
| memcpySpan(formatWithPrefix.mutableSpan(), prefix); |
| memcpySpan(formatWithPrefix.mutableSpan().subspan(prefix.size()), format); |
| formatWithPrefix[prefix.size() + format.size()] = 0; |
| |
| ALLOW_NONLITERAL_FORMAT_BEGIN |
| vprintf_stderr_common(nullptr, formatWithPrefix.span().data(), args); |
| ALLOW_NONLITERAL_FORMAT_END |
| } |
| |
| WTF_ATTRIBUTE_NSSTRING(2, 0) |
| static void vprintf_stderr_with_trailing_newline(WTFLogChannel* channel, const char* rawFormat, va_list args) |
| { |
| auto format = unsafeSpan(rawFormat); |
| if (!format.empty() && format.back() == '\n') { |
| vprintf_stderr_common(channel, rawFormat, args); |
| return; |
| } |
| |
| Vector<char> formatWithNewline(format.size() + 2); |
| memcpySpan(formatWithNewline.mutableSpan(), format); |
| formatWithNewline[format.size()] = '\n'; |
| formatWithNewline[format.size() + 1] = 0; |
| |
| ALLOW_NONLITERAL_FORMAT_BEGIN |
| vprintf_stderr_common(channel, formatWithNewline.span().data(), args); |
| ALLOW_NONLITERAL_FORMAT_END |
| } |
| |
| WTF_ATTRIBUTE_NSSTRING(1, 2) |
| static void printf_stderr_common(const char* format, ...) |
| { |
| va_list args; |
| va_start(args, format); |
| vprintf_stderr_common(nullptr, format, args); |
| va_end(args); |
| } |
| |
| static void printCallSite(const char* file, int line, const char* function) |
| { |
| #if OS(WINDOWS) && defined(_DEBUG) |
| _CrtDbgReport(_CRT_WARN, file, line, NULL, "%s\n", function); |
| #else |
| // By using this format, which matches the format used by MSVC for compiler errors, developers |
| // using Visual Studio can double-click the file/line number in the Output Window to have the |
| // editor navigate to that line of code. It seems fine for other developers, too. |
| printf_stderr_common("%s(%d) : %s\n", file, line, function); |
| #endif |
| } |
| |
| void WTFReportNotImplementedYet(const char* file, int line, const char* function) |
| { |
| printf_stderr_common("NOT IMPLEMENTED YET\n"); |
| printCallSite(file, line, function); |
| } |
| |
| void WTFReportAssertionFailure(const char* file, int line, const char* function, const char* assertion) |
| { |
| if (assertion) |
| printf_stderr_common("ASSERTION FAILED: %s\n", assertion); |
| else |
| printf_stderr_common("SHOULD NEVER BE REACHED\n"); |
| printCallSite(file, line, function); |
| } |
| |
| void WTFReportAssertionFailureWithMessage(const char* file, int line, const char* function, const char* assertion, const char* format, ...) |
| { |
| va_list args; |
| va_start(args, format); |
| vprintf_stderr_with_prefix("ASSERTION FAILED: ", format, args); |
| va_end(args); |
| printf_stderr_common("\n%s\n", assertion); |
| printCallSite(file, line, function); |
| } |
| |
| void WTFReportArgumentAssertionFailure(const char* file, int line, const char* function, const char* argName, const char* assertion) |
| { |
| printf_stderr_common("ARGUMENT BAD: %s, %s\n", argName, assertion); |
| printCallSite(file, line, function); |
| } |
| |
| class CrashLogPrintStream final : public PrintStream { |
| public: |
| WTF_ATTRIBUTE_NSSTRING(2, 0) |
| void vprintf(const char* format, va_list argList) final |
| { |
| vprintf_stderr_common(nullptr, format, argList); |
| } |
| }; |
| |
| void WTFReportBacktraceWithPrefix(const char* prefix) |
| { |
| CrashLogPrintStream out; |
| WTFReportBacktraceWithPrefixAndPrintStream(out, prefix); |
| } |
| |
| static constexpr int kDefaultFramesToShow = 31; |
| static constexpr int kDefaultFramesToSkip = 2; |
| |
| void WTFReportBacktraceWithStackDepth(int framesToShow) |
| { |
| WTFReportBacktraceWithPrefixAndStackDepth("", framesToShow); |
| } |
| |
| void WTFReportBacktraceWithPrefixAndStackDepth(const char* prefix, int framesToShow) |
| { |
| int frames = framesToShow + kDefaultFramesToSkip; |
| Vector<void*> samples(frames); |
| |
| WTFGetBacktrace(samples.mutableSpan().data(), &frames); |
| CrashLogPrintStream out; |
| if (frames > kDefaultFramesToSkip) |
| WTFPrintBacktraceWithPrefixAndPrintStream(out, samples.subspan(kDefaultFramesToSkip, frames - kDefaultFramesToSkip), prefix); |
| else |
| out.print("%sno stacktrace available", prefix); |
| } |
| |
| void WTFReportBacktraceWithPrefixAndPrintStream(PrintStream& out, const char* prefix) |
| { |
| std::array<void*, kDefaultFramesToShow + kDefaultFramesToSkip> samples; |
| int frames = samples.size(); |
| |
| WTFGetBacktrace(samples.data(), &frames); |
| if (frames > kDefaultFramesToSkip) |
| WTFPrintBacktraceWithPrefixAndPrintStream(out, std::span { samples }.subspan(kDefaultFramesToSkip, frames - kDefaultFramesToSkip), prefix); |
| else |
| out.print("%sno stacktrace available", prefix); |
| } |
| |
| void WTFReportBacktrace() |
| { |
| std::array<void*, kDefaultFramesToShow + kDefaultFramesToSkip> samples; |
| int frames = kDefaultFramesToShow + kDefaultFramesToSkip; |
| |
| WTFGetBacktrace(samples.data(), &frames); |
| if (frames > kDefaultFramesToSkip) |
| WTFPrintBacktrace(std::span { samples }.subspan(kDefaultFramesToSkip, frames - kDefaultFramesToSkip)); |
| else |
| CrashLogPrintStream { }.print("no stacktrace available"); |
| } |
| |
| void WTFPrintBacktraceWithPrefixAndPrintStream(PrintStream& out, std::span<void* const> stack, const char* prefix) |
| { |
| out.print(StackTracePrinter { stack, prefix }); |
| } |
| |
| void WTFPrintBacktrace(std::span<void* const> stack) |
| { |
| CrashLogPrintStream out; |
| WTFPrintBacktraceWithPrefixAndPrintStream(out, stack, ""); |
| } |
| |
| #if !defined(NDEBUG) || !(OS(DARWIN) || PLATFORM(PLAYSTATION)) |
| void WTFCrash() |
| { |
| #if ASAN_ENABLED |
| __builtin_trap(); |
| #elif OS(DARWIN) && CPU(ARM64) |
| WTFBreakpointTrap(); |
| __builtin_trap(); // Suppress NO_RETURN_DUE_TO_CRASH warning. |
| #else |
| *(int *)(uintptr_t)0xbbadbeef = 0; |
| // More reliable, but doesn't say BBADBEEF. |
| __builtin_trap(); |
| #endif // ASAN_ENABLED |
| } |
| #else |
| // We need to keep WTFCrash() around (even on non-debug OS(DARWIN) builds) as a workaround |
| // for presently shipping (circa early 2016) SafariForWebKitDevelopment binaries which still |
| // expects to link to it. |
| void WTFCrash() |
| { |
| CRASH(); |
| } |
| #endif // !defined(NDEBUG) || !(OS(DARWIN) || PLATFORM(PLAYSTATION)) |
| |
| #if ENABLE(CONJECTURE_ASSERT) |
| int wtfConjectureAssertIsEnabled = 0; |
| |
| void WTFCrashDueToConjectureAssert(const char* file, int line, const char* function, const char* assertion) |
| { |
| printf_stderr_common("CONJECTURE ASSERTION FAILED: %s\n", assertion); |
| printCallSite(file, line, function); |
| WTFReportBacktrace(); |
| CRASH(); |
| } |
| #endif |
| |
| void WTFCrashWithSecurityImplication() |
| { |
| CRASH(); |
| } |
| |
| bool WTFIsDebuggerAttached() |
| { |
| #if OS(DARWIN) |
| struct kinfo_proc info; |
| std::array mib { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid() }; |
| size_t size = sizeof(info); |
| if (sysctl(mib.data(), mib.size(), &info, &size, nullptr, 0) == -1) |
| return false; |
| return info.kp_proc.p_flag & P_TRACED; |
| #else |
| return false; |
| #endif |
| } |
| |
| void WTFReportFatalError(const char* file, int line, const char* function, const char* format, ...) |
| { |
| va_list args; |
| va_start(args, format); |
| vprintf_stderr_with_prefix("FATAL ERROR: ", format, args); |
| va_end(args); |
| printf_stderr_common("\n"); |
| printCallSite(file, line, function); |
| } |
| |
| void WTFReportError(const char* file, int line, const char* function, const char* format, ...) |
| { |
| va_list args; |
| va_start(args, format); |
| vprintf_stderr_with_prefix("ERROR: ", format, args); |
| va_end(args); |
| printf_stderr_common("\n"); |
| printCallSite(file, line, function); |
| } |
| |
| class WTFLoggingAccumulator { |
| WTF_DEPRECATED_MAKE_FAST_ALLOCATED(WTFLoggingAccumulator); |
| public: |
| void accumulate(const String&); |
| void resetAccumulatedLogs(); |
| String getAndResetAccumulatedLogs(); |
| |
| private: |
| Lock accumulatorLock; |
| StringBuilder loggingAccumulator WTF_GUARDED_BY_LOCK(accumulatorLock); |
| }; |
| |
| void WTFLoggingAccumulator::accumulate(const String& log) |
| { |
| Locker locker { accumulatorLock }; |
| loggingAccumulator.append(log); |
| } |
| |
| void WTFLoggingAccumulator::resetAccumulatedLogs() |
| { |
| Locker locker { accumulatorLock }; |
| loggingAccumulator.clear(); |
| } |
| |
| String WTFLoggingAccumulator::getAndResetAccumulatedLogs() |
| { |
| Locker locker { accumulatorLock }; |
| String result = loggingAccumulator.toString(); |
| loggingAccumulator.clear(); |
| return result; |
| } |
| |
| static WTFLoggingAccumulator& loggingAccumulator() |
| { |
| static NeverDestroyed<UniqueRef<WTFLoggingAccumulator>> accumulator = makeUniqueRef<WTFLoggingAccumulator>(); |
| return accumulator.get(); |
| } |
| |
| void WTFSetLogChannelLevel(WTFLogChannel* channel, WTFLogLevel level) |
| { |
| channel->level = level; |
| } |
| |
| bool WTFWillLogWithLevel(WTFLogChannel* channel, WTFLogLevel level) |
| { |
| return channel->level >= level && channel->state != WTFLogChannelState::Off; |
| } |
| |
| #if ENABLE(JOURNALD_LOG) |
| bool WTFShouldLogToJournal() |
| { |
| static const bool shouldLogToJournal = [] { |
| if (const char* output = getenv("WEBKIT_DEBUG_OUTPUT")) { |
| auto outputSpan = unsafeSpan(output); |
| if (equalSpans(outputSpan, "stderr"_span)) |
| return false; |
| if (equalSpans(outputSpan, "journal"_span)) |
| return true; |
| WTFLogAlways("Unknown WEBKIT_DEBUG_OUTPUT value '%s', expected 'journal' or 'stderr'.", output); |
| } |
| |
| // sd_journal_send() returns success even when journald is not running: |
| // https://man.archlinux.org/man/sd_journal_send_with_location.3.en#RETURN_VALUE |
| return !access("/run/systemd/journal/socket", F_OK); |
| }(); |
| |
| return shouldLogToJournal; |
| } |
| #endif // ENABLE(JOURNALD_LOG) |
| |
| void WTFLogWithLevel(WTFLogChannel* channel, WTFLogLevel level, const char* format, ...) |
| { |
| if (level != WTFLogLevel::Always && level > channel->level) |
| return; |
| |
| if (channel->level != WTFLogLevel::Always && channel->state == WTFLogChannelState::Off) |
| return; |
| |
| va_list args; |
| va_start(args, format); |
| |
| ALLOW_NONLITERAL_FORMAT_BEGIN |
| WTFLog(channel, format, args); |
| ALLOW_NONLITERAL_FORMAT_END |
| |
| va_end(args); |
| } |
| |
| WTF_ATTRIBUTE_NSSTRING(2, 0) |
| static void WTFLogVaList(WTFLogChannel* channel, const char* format, va_list args) |
| { |
| if (channel->state == WTFLogChannelState::Off) |
| return; |
| |
| if (channel->state == WTFLogChannelState::On) { |
| vprintf_stderr_with_trailing_newline(channel, format, args); |
| return; |
| } |
| |
| ASSERT(channel->state == WTFLogChannelState::OnWithAccumulation); |
| |
| ALLOW_NONLITERAL_FORMAT_BEGIN |
| String loggingString = WTF::createWithFormatAndArguments(format, args); |
| ALLOW_NONLITERAL_FORMAT_END |
| |
| if (!loggingString.endsWith('\n')) |
| loggingString = makeString(loggingString, '\n'); |
| |
| loggingAccumulator().accumulate(loggingString); |
| |
| logToStderr(channel, loggingString.utf8().data()); |
| } |
| |
| void WTFLog(WTFLogChannel* channel, const char* format, ...) |
| { |
| va_list args; |
| va_start(args, format); |
| |
| WTFLogVaList(channel, format, args); |
| |
| va_end(args); |
| } |
| |
| void WTFLogVerbose(const char* file, int line, const char* function, WTFLogChannel* channel, const char* format, ...) |
| { |
| if (channel->state != WTFLogChannelState::On) |
| return; |
| |
| va_list args; |
| va_start(args, format); |
| |
| ALLOW_NONLITERAL_FORMAT_BEGIN |
| WTFLogVaList(channel, format, args); |
| ALLOW_NONLITERAL_FORMAT_END |
| |
| va_end(args); |
| |
| printCallSite(file, line, function); |
| } |
| |
| void WTFLogAlwaysV(const char* format, va_list args) |
| { |
| vprintf_stderr_with_trailing_newline(nullptr, format, args); |
| } |
| |
| void WTFLogAlways(const char* format, ...) |
| { |
| va_list args; |
| va_start(args, format); |
| WTFLogAlwaysV(format, args); |
| va_end(args); |
| } |
| |
| void WTFLogAlwaysAndCrash(const char* format, ...) |
| { |
| va_list args; |
| va_start(args, format); |
| WTFLogAlwaysV(format, args); |
| va_end(args); |
| CRASH(); |
| } |
| |
| WTFLogChannel* WTFLogChannelByName(WTFLogChannel* channels[], size_t count, const char* name) |
| { |
| for (size_t i = 0; i < count; ++i) { |
| WTFLogChannel* channel = channels[i]; |
| if (equalIgnoringASCIICase(name, channel->name)) |
| return channel; |
| } |
| |
| return nullptr; |
| } |
| |
| static void NODELETE setStateOfAllChannels(WTFLogChannel* channels[], size_t channelCount, WTFLogChannelState state) |
| { |
| for (size_t i = 0; i < channelCount; ++i) |
| channels[i]->state = state; |
| } |
| |
| void WTFInitializeLogChannelStatesFromString(WTFLogChannel* channels[], size_t count, const char* logLevel) |
| { |
| #if USE(OS_LOG) && !RELEASE_LOG_DISABLED |
| for (size_t i = 0; i < count; ++i) { |
| WTFLogChannel* channel = channels[i]; |
| channel->osLogChannel = os_log_create(LOG_CHANNEL_WEBKIT_SUBSYSTEM, channel->name); |
| } |
| #endif |
| |
| for (auto logLevelComponent : StringView::fromLatin1(logLevel).split(',')) { |
| auto componentInfo = logLevelComponent.split('='); |
| auto it = componentInfo.begin(); |
| if (it == componentInfo.end()) |
| continue; |
| |
| auto component = (*it).trim(isUnicodeCompatibleASCIIWhitespace<char16_t>); |
| |
| WTFLogChannelState logChannelState = WTFLogChannelState::On; |
| if (component.startsWith('-')) { |
| logChannelState = WTFLogChannelState::Off; |
| component = component.substring(1); |
| } |
| |
| if (equalLettersIgnoringASCIICase(component, "all"_s)) { |
| setStateOfAllChannels(channels, count, logChannelState); |
| continue; |
| } |
| |
| WTFLogLevel logChannelLevel = WTFLogLevel::Error; |
| if (++it != componentInfo.end()) { |
| auto level = (*it).trim(isUnicodeCompatibleASCIIWhitespace<char16_t>); |
| if (equalLettersIgnoringASCIICase(level, "error"_s)) |
| logChannelLevel = WTFLogLevel::Error; |
| else if (equalLettersIgnoringASCIICase(level, "warning"_s)) |
| logChannelLevel = WTFLogLevel::Warning; |
| else if (equalLettersIgnoringASCIICase(level, "info"_s)) |
| logChannelLevel = WTFLogLevel::Info; |
| else if (equalLettersIgnoringASCIICase(level, "debug"_s)) |
| logChannelLevel = WTFLogLevel::Debug; |
| else |
| WTFLogAlways("Unknown logging level: %s", level.utf8().data()); |
| } |
| |
| if (WTFLogChannel* channel = WTFLogChannelByName(channels, count, component.utf8().data())) { |
| channel->state = logChannelState; |
| channel->level = logChannelLevel; |
| } else |
| WTFLogAlways("Unknown logging channel: %s", component.utf8().data()); |
| } |
| } |
| |
| } // extern "C" |
| |
| #if !ASAN_ENABLED && (OS(DARWIN) || PLATFORM(PLAYSTATION)) && (CPU(X86_64) || CPU(ARM64)) |
| |
| void WTFCrashWithInfoImpl(int, const char*, const char*, UCPURegister reason, UCPURegister misc1, UCPURegister misc2, UCPURegister misc3, UCPURegister misc4, UCPURegister misc5, UCPURegister misc6) |
| { |
| register UCPURegister reasonGPR __asm__(CRASH_GPR0) = reason; |
| register UCPURegister misc1GPR __asm__(CRASH_GPR1) = misc1; |
| register UCPURegister misc2GPR __asm__(CRASH_GPR2) = misc2; |
| register UCPURegister misc3GPR __asm__(CRASH_GPR3) = misc3; |
| register UCPURegister misc4GPR __asm__(CRASH_GPR4) = misc4; |
| register UCPURegister misc5GPR __asm__(CRASH_GPR5) = misc5; |
| register UCPURegister misc6GPR __asm__(CRASH_GPR6) = misc6; |
| __asm__ volatile (WTF_FATAL_CRASH_INST : : "r"(reasonGPR), "r"(misc1GPR), "r"(misc2GPR), "r"(misc3GPR), "r"(misc4GPR), "r"(misc5GPR), "r"(misc6GPR)); |
| __builtin_unreachable(); |
| } |
| |
| void WTFCrashWithInfoImpl(int, const char*, const char*, UCPURegister reason, UCPURegister misc1, UCPURegister misc2, UCPURegister misc3, UCPURegister misc4, UCPURegister misc5) |
| { |
| register UCPURegister reasonGPR __asm__(CRASH_GPR0) = reason; |
| register UCPURegister misc1GPR __asm__(CRASH_GPR1) = misc1; |
| register UCPURegister misc2GPR __asm__(CRASH_GPR2) = misc2; |
| register UCPURegister misc3GPR __asm__(CRASH_GPR3) = misc3; |
| register UCPURegister misc4GPR __asm__(CRASH_GPR4) = misc4; |
| register UCPURegister misc5GPR __asm__(CRASH_GPR5) = misc5; |
| __asm__ volatile (WTF_FATAL_CRASH_INST : : "r"(reasonGPR), "r"(misc1GPR), "r"(misc2GPR), "r"(misc3GPR), "r"(misc4GPR), "r"(misc5GPR)); |
| __builtin_unreachable(); |
| } |
| |
| void WTFCrashWithInfoImpl(int, const char*, const char*, UCPURegister reason, UCPURegister misc1, UCPURegister misc2, UCPURegister misc3, UCPURegister misc4) |
| { |
| register UCPURegister reasonGPR __asm__(CRASH_GPR0) = reason; |
| register UCPURegister misc1GPR __asm__(CRASH_GPR1) = misc1; |
| register UCPURegister misc2GPR __asm__(CRASH_GPR2) = misc2; |
| register UCPURegister misc3GPR __asm__(CRASH_GPR3) = misc3; |
| register UCPURegister misc4GPR __asm__(CRASH_GPR4) = misc4; |
| __asm__ volatile (WTF_FATAL_CRASH_INST : : "r"(reasonGPR), "r"(misc1GPR), "r"(misc2GPR), "r"(misc3GPR), "r"(misc4GPR)); |
| __builtin_unreachable(); |
| } |
| |
| void WTFCrashWithInfoImpl(int, const char*, const char*, UCPURegister reason, UCPURegister misc1, UCPURegister misc2, UCPURegister misc3) |
| { |
| register UCPURegister reasonGPR __asm__(CRASH_GPR0) = reason; |
| register UCPURegister misc1GPR __asm__(CRASH_GPR1) = misc1; |
| register UCPURegister misc2GPR __asm__(CRASH_GPR2) = misc2; |
| register UCPURegister misc3GPR __asm__(CRASH_GPR3) = misc3; |
| __asm__ volatile (WTF_FATAL_CRASH_INST : : "r"(reasonGPR), "r"(misc1GPR), "r"(misc2GPR), "r"(misc3GPR)); |
| __builtin_unreachable(); |
| } |
| |
| void WTFCrashWithInfoImpl(int, const char*, const char*, UCPURegister reason, UCPURegister misc1, UCPURegister misc2) |
| { |
| register UCPURegister reasonGPR __asm__(CRASH_GPR0) = reason; |
| register UCPURegister misc1GPR __asm__(CRASH_GPR1) = misc1; |
| register UCPURegister misc2GPR __asm__(CRASH_GPR2) = misc2; |
| __asm__ volatile (WTF_FATAL_CRASH_INST : : "r"(reasonGPR), "r"(misc1GPR), "r"(misc2GPR)); |
| __builtin_unreachable(); |
| } |
| |
| void WTFCrashWithInfoImpl(int, const char*, const char*, UCPURegister reason, UCPURegister misc1) |
| { |
| register UCPURegister reasonGPR __asm__(CRASH_GPR0) = reason; |
| register UCPURegister misc1GPR __asm__(CRASH_GPR1) = misc1; |
| __asm__ volatile (WTF_FATAL_CRASH_INST : : "r"(reasonGPR), "r"(misc1GPR)); |
| __builtin_unreachable(); |
| } |
| |
| void WTFCrashWithInfoImpl(int, const char*, const char*, UCPURegister reason) |
| { |
| register UCPURegister reasonGPR __asm__(CRASH_GPR0) = reason; |
| __asm__ volatile (WTF_FATAL_CRASH_INST : : "r"(reasonGPR)); |
| __builtin_unreachable(); |
| } |
| |
| #else |
| |
| void WTFCrashWithInfoImpl(int, const char*, const char*, UCPURegister, UCPURegister, UCPURegister, UCPURegister, UCPURegister, UCPURegister, UCPURegister) { CRASH(); } |
| void WTFCrashWithInfoImpl(int, const char*, const char*, UCPURegister, UCPURegister, UCPURegister, UCPURegister, UCPURegister, UCPURegister) { CRASH(); } |
| void WTFCrashWithInfoImpl(int, const char*, const char*, UCPURegister, UCPURegister, UCPURegister, UCPURegister, UCPURegister) { CRASH(); } |
| void WTFCrashWithInfoImpl(int, const char*, const char*, UCPURegister, UCPURegister, UCPURegister, UCPURegister) { CRASH(); } |
| void WTFCrashWithInfoImpl(int, const char*, const char*, UCPURegister, UCPURegister, UCPURegister) { CRASH(); } |
| void WTFCrashWithInfoImpl(int, const char*, const char*, UCPURegister, UCPURegister) { CRASH(); } |
| void WTFCrashWithInfoImpl(int, const char*, const char*, UCPURegister) { CRASH(); } |
| |
| #endif // (OS(DARWIN) || PLATFORM(PLAYSTATION)) && (CPU(X64_64) || CPU(ARM64)) |
| |
| namespace WTF { |
| |
| void resetAccumulatedLogs() |
| { |
| loggingAccumulator().resetAccumulatedLogs(); |
| } |
| |
| String getAndResetAccumulatedLogs() |
| { |
| return loggingAccumulator().getAndResetAccumulatedLogs(); |
| } |
| |
| } // namespace WTF |
| |
| WTF_ALLOW_UNSAFE_BUFFER_USAGE_END |