blob: ab44bac49bf1af50cf8744b71eecca5d8ef01f10 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/app/kasko_client.h"
#if BUILDFLAG(ENABLE_KASKO)
#include <windows.h>
#include <stddef.h>
#include <string>
#include <vector>
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/process/process_handle.h"
#include "chrome/app/chrome_watcher_client_win.h"
#include "chrome/chrome_watcher/chrome_watcher_main_api.h"
#include "chrome/common/chrome_constants.h"
#include "components/crash/content/app/crashpad.h"
#include "syzygy/kasko/api/client.h"
namespace {
ChromeWatcherClient* g_chrome_watcher_client = nullptr;
kasko::api::MinidumpType g_minidump_type = kasko::api::SMALL_DUMP_TYPE;
base::LazyInstance<std::vector<kasko::api::CrashKey>>::Leaky
g_kasko_crash_keys = LAZY_INSTANCE_INITIALIZER;
void GetKaskoCrashKeys(const kasko::api::CrashKey** crash_keys,
size_t* crash_key_count) {
crash_reporter::GetCrashKeysForKasko(g_kasko_crash_keys.Pointer());
*crash_key_count = g_kasko_crash_keys.Pointer()->size();
*crash_keys = g_kasko_crash_keys.Pointer()->data();
}
} // namespace
KaskoClient::KaskoClient(ChromeWatcherClient* chrome_watcher_client,
kasko::api::MinidumpType minidump_type) {
DCHECK(!g_chrome_watcher_client);
g_minidump_type = minidump_type;
g_chrome_watcher_client = chrome_watcher_client;
kasko::api::InitializeClient(
GetKaskoEndpoint(base::GetCurrentProcId()).c_str());
// Register the crash keys so that they will be available whether a crash
// report is triggered directly by the browser process or requested by the
// Chrome Watcher process.
size_t crash_key_count = 0;
const kasko::api::CrashKey* crash_keys = nullptr;
GetKaskoCrashKeys(&crash_keys, &crash_key_count);
kasko::api::RegisterCrashKeys(crash_keys, crash_key_count);
}
KaskoClient::~KaskoClient() {
DCHECK(g_chrome_watcher_client);
g_chrome_watcher_client = nullptr;
kasko::api::ShutdownClient();
}
// Sends a diagnostic report for the current process, then terminates it.
// |info| is an optional exception record describing an exception on the current
// thread.
// |protobuf| is an optional buffer of length |protobuf_length|.
// |base_addresses| and |lengths| are optional null-terminated arrays of the
// same length. For each entry in |base_addresses|, a memory range starting at
// the specified address and having the length specified in the corresponding
// entry in |lengths| will be explicitly included in the report.
extern "C" void __declspec(dllexport)
ReportCrashWithProtobufAndMemoryRanges(EXCEPTION_POINTERS* info,
const char* protobuf,
size_t protobuf_length,
const void* const* base_addresses,
const size_t* lengths) {
if (g_chrome_watcher_client && g_chrome_watcher_client->EnsureInitialized()) {
size_t crash_key_count = 0;
const kasko::api::CrashKey* crash_keys = nullptr;
GetKaskoCrashKeys(&crash_keys, &crash_key_count);
std::vector<kasko::api::MemoryRange> memory_ranges;
if (base_addresses && lengths) {
for (int i = 0; base_addresses[i] != nullptr && lengths[i] != 0; ++i) {
kasko::api::MemoryRange memory_range = {base_addresses[i], lengths[i]};
memory_ranges.push_back(memory_range);
}
}
kasko::api::SendReport(info, g_minidump_type, protobuf, protobuf_length,
crash_keys, crash_key_count,
memory_ranges.size() ? &memory_ranges[0] : nullptr,
memory_ranges.size());
}
// The Breakpad integration hooks TerminateProcess. Sidestep it to avoid a
// secondary report. Crashpad, on the other hand, does not hook
// TerminateProcess so it can be safely invoked.
// TODO(chrisha): When Breakpad is completely ripped out make this Crashpad
// specific.
using TerminateProcessWithoutDumpProc = void(__cdecl*)();
TerminateProcessWithoutDumpProc terminate_process_without_dump =
reinterpret_cast<TerminateProcessWithoutDumpProc>(::GetProcAddress(
::GetModuleHandle(chrome::kBrowserProcessExecutableName),
"TerminateProcessWithoutDump"));
if (terminate_process_without_dump)
terminate_process_without_dump();
else
::TerminateProcess(::GetCurrentProcess(), 0);
}
extern "C" void __declspec(dllexport) ReportCrashWithProtobuf(
EXCEPTION_POINTERS* info, const char* protobuf, size_t protobuf_length) {
ReportCrashWithProtobufAndMemoryRanges(info, protobuf, protobuf_length,
nullptr, nullptr);
}
#endif // BUILDFLAG(ENABLE_KASKO)