/* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "perfetto/base/logging.h" #include <stdarg.h> #include <stdio.h> #if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) #include <unistd.h> // For isatty() #endif #include <atomic> #include <memory> #include "perfetto/base/build_config.h" #include "perfetto/base/time.h" #include "perfetto/ext/base/crash_keys.h" #include "perfetto/ext/base/string_utils.h" #include "perfetto/ext/base/string_view.h" #include "src/base/log_ring_buffer.h" #if PERFETTO_ENABLE_LOG_RING_BUFFER() && PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) #include <android/set_abort_message.h> #endif namespace perfetto { namespace base { namespace { const char kReset[] = …; const char kDefault[] = …; const char kDim[] = …; const char kRed[] = …; const char kBoldGreen[] = …; const char kLightGray[] = …; std::atomic<LogMessageCallback> g_log_callback{ … }; #if PERFETTO_BUILDFLAG(PERFETTO_STDERR_CRASH_DUMP) // __attribute__((constructor)) causes a static initializer that automagically // early runs this function before the main(). void PERFETTO_EXPORT_COMPONENT __attribute__((constructor)) InitDebugCrashReporter() { // This function is defined in debug_crash_stack_trace.cc. // The dynamic initializer is in logging.cc because logging.cc is included // in virtually any target that depends on base. Having it in // debug_crash_stack_trace.cc would require figuring out -Wl,whole-archive // which is not worth it. EnableStacktraceOnCrashForDebug(); } #endif #if PERFETTO_ENABLE_LOG_RING_BUFFER() LogRingBuffer g_log_ring_buffer{}; // This is global to avoid allocating memory or growing too much the stack // in MaybeSerializeLastLogsForCrashReporting(), which is called from // arbitrary code paths hitting PERFETTO_CHECK()/FATAL(). char g_crash_buf[kLogRingBufEntries * kLogRingBufMsgLen]; #endif } // namespace void SetLogMessageCallback(LogMessageCallback callback) { … } void LogMessage(LogLev level, const char* fname, int line, const char* fmt, ...) { … } #if PERFETTO_ENABLE_LOG_RING_BUFFER() void MaybeSerializeLastLogsForCrashReporting() { // Keep this function minimal. This is called from the watchdog thread, often // when the system is thrashing. // This is racy because two threads could hit a CHECK/FATAL at the same time. // But if that happens we have bigger problems, not worth designing around it. // The behaviour is still defined in the race case (the string attached to // the crash report will contain a mixture of log strings). size_t wr = 0; wr += SerializeCrashKeys(&g_crash_buf[wr], sizeof(g_crash_buf) - wr); wr += g_log_ring_buffer.Read(&g_crash_buf[wr], sizeof(g_crash_buf) - wr); // Read() null-terminates the string properly. This is just to avoid UB when // two threads race on each other (T1 writes a shorter string, T2 // overwrites the \0 writing a longer string. T1 continues here before T2 // finishes writing the longer string with the \0 -> boom. g_crash_buf[sizeof(g_crash_buf) - 1] = '\0'; #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) // android_set_abort_message() will cause debuggerd to report the message // in the tombstone and in the crash log in logcat. // NOTE: android_set_abort_message() can be called only once. This should // be called only when we are sure we are about to crash. android_set_abort_message(g_crash_buf); #else // Print out the message on stderr on Linux/Mac/Win. fputs("\n-----BEGIN PERFETTO PRE-CRASH LOG-----\n", stderr); fputs(g_crash_buf, stderr); fputs("\n-----END PERFETTO PRE-CRASH LOG-----\n", stderr); #endif } #endif // PERFETTO_ENABLE_LOG_RING_BUFFER } // namespace base } // namespace perfetto