#include "libcef/common/crash_reporting.h"
#include "include/cef_crash_util.h"
#include "libcef/common/cef_switches.h"
#include "libcef/features/runtime.h"
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/debug/crash_logging.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "chrome/common/crash_keys.h"
#include "components/crash/core/common/crash_key.h"
#include "components/crash/core/common/crash_keys.h"
#include "content/public/common/content_switches.h"
#if BUILDFLAG(IS_MAC)
#include "base/mac/foundation_util.h"
#include "components/crash/core/app/crashpad.h"
#include "components/crash/core/common/crash_keys.h"
#include "content/public/common/content_paths.h"
#endif
#if BUILDFLAG(IS_POSIX)
#include "base/lazy_instance.h"
#include "libcef/common/crash_reporter_client.h"
#endif
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
#include "components/crash/core/app/breakpad_linux.h"
#include "v8/include/v8-wasm-trap-handler-posix.h"
#endif
namespace crash_reporting {
namespace {
#if BUILDFLAG(IS_WIN)
const base::FilePath::CharType kChromeElfDllName[] =
FILE_PATH_LITERAL("chrome_elf.dll");
typedef int(__cdecl* SetCrashKeyValue)(const char*,
size_t,
const char*,
size_t);
typedef int(__cdecl* IsCrashReportingEnabled)();
bool SetCrashKeyValueTrampoline(const base::StringPiece& key,
const base::StringPiece& value) {
static SetCrashKeyValue set_crash_key = []() {
HMODULE elf_module = GetModuleHandle(kChromeElfDllName);
return reinterpret_cast<SetCrashKeyValue>(
elf_module ? GetProcAddress(elf_module, "SetCrashKeyValueImpl")
: nullptr);
}();
if (set_crash_key) {
return !!(set_crash_key)(key.data(), key.size(), value.data(),
value.size());
}
return false;
}
bool IsCrashReportingEnabledTrampoline() {
static IsCrashReportingEnabled is_crash_reporting_enabled = []() {
HMODULE elf_module = GetModuleHandle(kChromeElfDllName);
return reinterpret_cast<IsCrashReportingEnabled>(
elf_module ? GetProcAddress(elf_module, "IsCrashReportingEnabledImpl")
: nullptr);
}();
if (is_crash_reporting_enabled) {
return !!(is_crash_reporting_enabled)();
}
return false;
}
#endif
bool g_crash_reporting_enabled = false;
#if BUILDFLAG(IS_POSIX)
base::LazyInstance<CefCrashReporterClient>::Leaky g_crash_reporter_client =
LAZY_INSTANCE_INITIALIZER;
void InitCrashReporter(const base::CommandLine& command_line,
const std::string& process_type) {
CefCrashReporterClient* crash_client = g_crash_reporter_client.Pointer();
if (!crash_client->HasCrashConfigFile())
return;
crash_reporter::SetCrashReporterClient(crash_client);
#if BUILDFLAG(IS_MAC)
crash_reporter::InitializeCrashpad(process_type.empty(), process_type);
if (base::mac::AmIBundled()) {
if (base::mac::IsBackgroundOnlyProcess()) {
CHECK(command_line.HasSwitch(switches::kProcessType) &&
!process_type.empty())
<< "Helper application requires --type.";
} else {
CHECK(!command_line.HasSwitch(switches::kProcessType) &&
process_type.empty())
<< "Main application forbids --type, saw " << process_type;
}
}
g_crash_reporting_enabled = true;
#else
if (process_type != switches::kZygoteProcess) {
breakpad::InitCrashReporter(process_type);
g_crash_reporting_enabled = true;
}
#endif
}
#endif
bool IsBoringCEFSwitch(const std::string& flag) {
if (crash_keys::IsBoringChromeSwitch(flag))
return true;
static const char* const kIgnoreSwitches[] = {
switches::kLogFile,
"content-image-texture-target",
"mojo-platform-channel-handle",
"primordial-pipe-token",
"service-pipe-token",
"service-request-channel-token",
};
if (!base::StartsWith(flag, "--", base::CompareCase::SENSITIVE))
return false;
size_t end = flag.find("=");
size_t len = (end == std::string::npos) ? flag.length() - 2 : end - 2;
for (size_t i = 0; i < base::size(kIgnoreSwitches); ++i) {
if (flag.compare(2, len, kIgnoreSwitches[i]) == 0)
return true;
}
return false;
}
}
bool Enabled() {
return g_crash_reporting_enabled;
}
bool SetCrashKeyValue(const base::StringPiece& key,
const base::StringPiece& value) {
if (!g_crash_reporting_enabled)
return false;
#if BUILDFLAG(IS_WIN)
return SetCrashKeyValueTrampoline(key, value);
#else
return g_crash_reporter_client.Pointer()->SetCrashKeyValue(key, value);
#endif
}
#if BUILDFLAG(IS_POSIX)
void BasicStartupComplete(base::CommandLine* command_line) {
CefCrashReporterClient* crash_client = g_crash_reporter_client.Pointer();
if (crash_client->ReadCrashConfigFile()) {
#if !BUILDFLAG(IS_MAC)
command_line->AppendSwitch(switches::kEnableCrashReporter);
breakpad::SetFirstChanceExceptionHandler(v8::TryHandleWebAssemblyTrapPosix);
#endif
}
}
#endif
void PreSandboxStartup(const base::CommandLine& command_line,
const std::string& process_type) {
#if BUILDFLAG(IS_POSIX)
InitCrashReporter(command_line, process_type);
#elif BUILDFLAG(IS_WIN)
g_crash_reporting_enabled = IsCrashReportingEnabledTrampoline();
#endif
if (g_crash_reporting_enabled) {
LOG(INFO) << "Crash reporting enabled for process: "
<< (process_type.empty() ? "browser" : process_type.c_str());
}
crash_reporter::InitializeCrashKeys();
crash_keys::SetSwitchesFromCommandLine(command_line, &IsBoringCEFSwitch);
}
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_MAC)
void ZygoteForked(base::CommandLine* command_line,
const std::string& process_type) {
CefCrashReporterClient* crash_client = g_crash_reporter_client.Pointer();
if (crash_client->HasCrashConfigFile()) {
command_line->AppendSwitch(switches::kEnableCrashReporter);
}
InitCrashReporter(*command_line, process_type);
if (g_crash_reporting_enabled) {
LOG(INFO) << "Crash reporting enabled for process: " << process_type;
}
crash_keys::SetSwitchesFromCommandLine(*command_line, &IsBoringCEFSwitch);
}
#endif
}
bool CefCrashReportingEnabled() {
return crash_reporting::Enabled();
}
void CefSetCrashKeyValue(const CefString& key, const CefString& value) {
if (!crash_reporting::SetCrashKeyValue(key.ToString(), value.ToString())) {
LOG(WARNING) << "Failed to set crash key: " << key.ToString()
<< " with value: " << value.ToString();
}
}
namespace cef {
bool IsCrashReportingEnabled() {
return crash_reporting::Enabled();
}
}