mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-08 21:26:04 +00:00
linux: add CRASHPAD_SIMULATE_CRASH()
Bug: crashpad:30 Change-Id: I135864a0e31119de3a814ee5ab5729336f6284a3 Reviewed-on: https://chromium-review.googlesource.com/927116 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
parent
38540eaf71
commit
01105719d7
@ -44,7 +44,10 @@ static_library("client") {
|
||||
}
|
||||
|
||||
if (crashpad_is_linux || crashpad_is_android) {
|
||||
sources += [ "crashpad_client_linux.cc" ]
|
||||
sources += [
|
||||
"crashpad_client_linux.cc",
|
||||
"simulate_crash_linux.h",
|
||||
]
|
||||
}
|
||||
|
||||
if (crashpad_is_linux || crashpad_is_android || crashpad_is_fuchsia) {
|
||||
|
@ -50,6 +50,7 @@
|
||||
'simple_string_dictionary.h',
|
||||
'simple_address_range_bag.h',
|
||||
'simulate_crash.h',
|
||||
'simulate_crash_linux.h',
|
||||
'simulate_crash_mac.cc',
|
||||
'simulate_crash_mac.h',
|
||||
'simulate_crash_win.h',
|
||||
@ -73,6 +74,7 @@
|
||||
['OS=="android"', {
|
||||
'sources/': [
|
||||
['include', '^crashpad_client_linux\\.cc$'],
|
||||
['include', '^simulate_crash_linux\\.h$'],
|
||||
],
|
||||
}],
|
||||
],
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/macros.h"
|
||||
#include "build/build_config.h"
|
||||
#include "util/misc/capture_context.h"
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
#include "base/mac/scoped_mach_port.h"
|
||||
@ -168,6 +169,17 @@ class CrashpadClient {
|
||||
const std::map<std::string, std::string>& annotations,
|
||||
const std::vector<std::string>& arguments,
|
||||
int socket);
|
||||
|
||||
//! \brief Requests that the handler capture a dump even though there hasn't
|
||||
//! been a crash.
|
||||
//!
|
||||
//! TODO(jperaza): Floating point information in the context is zeroed out
|
||||
//! until CaptureContext() supports collecting that information.
|
||||
//!
|
||||
//! \param[in] context A NativeCPUContext, generally captured by
|
||||
//! CaptureContext() or similar.
|
||||
static void DumpWithoutCrash(NativeCPUContext* context);
|
||||
|
||||
#endif // OS_LINUX || OS_ANDROID || DOXYGEN
|
||||
|
||||
#if defined(OS_MACOSX) || DOXYGEN
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "util/file/file_io.h"
|
||||
#include "util/linux/exception_handler_client.h"
|
||||
#include "util/linux/exception_information.h"
|
||||
#include "util/linux/scoped_pr_set_ptracer.h"
|
||||
#include "util/misc/from_pointer_cast.h"
|
||||
#include "util/posix/double_fork_and_exec.h"
|
||||
#include "util/posix/signals.h"
|
||||
@ -82,7 +83,7 @@ void BuildHandlerArgvStrings(
|
||||
}
|
||||
}
|
||||
|
||||
void ConvertArgvStrings(const std::vector<std::string> argv_strings,
|
||||
void ConvertArgvStrings(const std::vector<std::string>& argv_strings,
|
||||
std::vector<const char*>* argv) {
|
||||
argv->clear();
|
||||
argv->reserve(argv_strings.size() + 1);
|
||||
@ -92,8 +93,22 @@ void ConvertArgvStrings(const std::vector<std::string> argv_strings,
|
||||
argv->push_back(nullptr);
|
||||
}
|
||||
|
||||
class SignalHandler {
|
||||
public:
|
||||
virtual void HandleCrashFatal(int signo,
|
||||
siginfo_t* siginfo,
|
||||
void* context) = 0;
|
||||
virtual void HandleCrashNonFatal(int signo,
|
||||
siginfo_t* siginfo,
|
||||
void* context) = 0;
|
||||
|
||||
protected:
|
||||
SignalHandler() = default;
|
||||
~SignalHandler() = default;
|
||||
};
|
||||
|
||||
// Launches a single use handler to snapshot this process.
|
||||
class LaunchAtCrashHandler {
|
||||
class LaunchAtCrashHandler : public SignalHandler {
|
||||
public:
|
||||
static LaunchAtCrashHandler* Get() {
|
||||
static LaunchAtCrashHandler* instance = new LaunchAtCrashHandler();
|
||||
@ -110,6 +125,37 @@ class LaunchAtCrashHandler {
|
||||
return Signals::InstallCrashHandlers(HandleCrash, 0, nullptr);
|
||||
}
|
||||
|
||||
void HandleCrashNonFatal(int signo,
|
||||
siginfo_t* siginfo,
|
||||
void* context) override {
|
||||
exception_information_.siginfo_address =
|
||||
FromPointerCast<decltype(exception_information_.siginfo_address)>(
|
||||
siginfo);
|
||||
exception_information_.context_address =
|
||||
FromPointerCast<decltype(exception_information_.context_address)>(
|
||||
context);
|
||||
exception_information_.thread_id = syscall(SYS_gettid);
|
||||
|
||||
ScopedPrSetPtracer set_ptracer(getpid(), /* may_log= */ false);
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
return;
|
||||
}
|
||||
if (pid == 0) {
|
||||
execv(argv_[0], const_cast<char* const*>(argv_.data()));
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int status;
|
||||
waitpid(pid, &status, 0);
|
||||
}
|
||||
|
||||
void HandleCrashFatal(int signo, siginfo_t* siginfo, void* context) override {
|
||||
HandleCrashNonFatal(signo, siginfo, context);
|
||||
Signals::RestoreHandlerAndReraiseSignalOnReturn(siginfo, nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
LaunchAtCrashHandler() = default;
|
||||
|
||||
@ -117,27 +163,7 @@ class LaunchAtCrashHandler {
|
||||
|
||||
static void HandleCrash(int signo, siginfo_t* siginfo, void* context) {
|
||||
auto state = Get();
|
||||
auto exception_information = &state->exception_information_;
|
||||
|
||||
exception_information->siginfo_address =
|
||||
FromPointerCast<decltype(exception_information->siginfo_address)>(
|
||||
siginfo);
|
||||
exception_information->context_address =
|
||||
FromPointerCast<decltype(exception_information->context_address)>(
|
||||
context);
|
||||
exception_information->thread_id = syscall(SYS_gettid);
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
return;
|
||||
}
|
||||
if (pid == 0) {
|
||||
execv(state->argv_[0], const_cast<char* const*>(state->argv_.data()));
|
||||
return;
|
||||
}
|
||||
|
||||
int status;
|
||||
waitpid(pid, &status, 0);
|
||||
state->HandleCrashFatal(signo, siginfo, context);
|
||||
}
|
||||
|
||||
std::vector<std::string> argv_strings_;
|
||||
@ -147,6 +173,11 @@ class LaunchAtCrashHandler {
|
||||
DISALLOW_COPY_AND_ASSIGN(LaunchAtCrashHandler);
|
||||
};
|
||||
|
||||
// A pointer to the currently installed crash signal handler. This allows
|
||||
// the static method CrashpadClient::DumpWithoutCrashing to simulate a crash
|
||||
// using the currently configured crash handling strategy.
|
||||
static SignalHandler* g_crash_handler;
|
||||
|
||||
} // namespace
|
||||
|
||||
CrashpadClient::CrashpadClient() {}
|
||||
@ -181,7 +212,12 @@ bool CrashpadClient::StartHandlerAtCrash(
|
||||
handler, database, metrics_dir, url, annotations, arguments, &argv);
|
||||
|
||||
auto signal_handler = LaunchAtCrashHandler::Get();
|
||||
return signal_handler->Initialize(&argv);
|
||||
if (signal_handler->Initialize(&argv)) {
|
||||
DCHECK(!g_crash_handler);
|
||||
g_crash_handler = signal_handler;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CrashpadClient::StartHandlerForClient(
|
||||
@ -201,4 +237,34 @@ bool CrashpadClient::StartHandlerForClient(
|
||||
return DoubleForkAndExec(argv, socket, true, nullptr);
|
||||
}
|
||||
|
||||
// static
|
||||
void CrashpadClient::DumpWithoutCrash(NativeCPUContext* context) {
|
||||
if (!g_crash_handler) {
|
||||
LOG(WARNING) << "No crash handler installed";
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(ARCH_CPU_X86)
|
||||
memset(&context->__fpregs_mem, 0, sizeof(context->__fpregs_mem));
|
||||
context->__fpregs_mem.status = 0xffff0000;
|
||||
#elif defined(ARCH_CPU_X86_64)
|
||||
memset(&context->__fpregs_mem, 0, sizeof(context->__fpregs_mem));
|
||||
#elif defined(ARCH_CPU_ARMEL)
|
||||
memset(context->uc_regspace, 0, sizeof(context->uc_regspace));
|
||||
#elif defined(ARCH_CPU_ARM64)
|
||||
memset(context->uc_mcontext.__reserved,
|
||||
0,
|
||||
sizeof(context->uc_mcontext.__reserved));
|
||||
#else
|
||||
#error Port.
|
||||
#endif
|
||||
|
||||
siginfo_t siginfo;
|
||||
siginfo.si_signo = Signals::kSimulatedSigno;
|
||||
siginfo.si_errno = 0;
|
||||
siginfo.si_code = 0;
|
||||
g_crash_handler->HandleCrashNonFatal(
|
||||
siginfo.si_signo, &siginfo, reinterpret_cast<void*>(context));
|
||||
}
|
||||
|
||||
} // namespace crashpad
|
||||
|
@ -21,6 +21,8 @@
|
||||
#include "client/simulate_crash_mac.h"
|
||||
#elif defined(OS_WIN)
|
||||
#include "client/simulate_crash_win.h"
|
||||
#elif defined(OS_LINUX) || defined(OS_ANDROID)
|
||||
#include "client/simulate_crash_linux.h"
|
||||
#endif
|
||||
|
||||
#endif // CRASHPAD_CLIENT_SIMULATE_CRASH_H_
|
||||
|
31
client/simulate_crash_linux.h
Normal file
31
client/simulate_crash_linux.h
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright 2018 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#ifndef CRASHPAD_CLIENT_SIMULATE_CRASH_LINUX_H_
|
||||
#define CRASHPAD_CLIENT_SIMULATE_CRASH_LINUX_H_
|
||||
|
||||
#include "client/crashpad_client.h"
|
||||
#include "util/misc/capture_context.h"
|
||||
|
||||
//! \file
|
||||
|
||||
//! \brief Captures the CPU context and simulates an exception without crashing.
|
||||
#define CRASHPAD_SIMULATE_CRASH() \
|
||||
do { \
|
||||
crashpad::NativeCPUContext simulate_crash_cpu_context; \
|
||||
crashpad::CaptureContext(&simulate_crash_cpu_context); \
|
||||
crashpad::CrashpadClient::DumpWithoutCrash(&simulate_crash_cpu_context); \
|
||||
} while (false)
|
||||
|
||||
#endif // CRASHPAD_CLIENT_SIMULATE_CRASH_LINUX_H_
|
@ -37,6 +37,10 @@ using NativeCPUContext = CONTEXT;
|
||||
using NativeCPUContext = ucontext_t;
|
||||
#endif // OS_MACOSX
|
||||
|
||||
// No NativeCPUContext defined for Fuchsia yet.
|
||||
// https://crashpad.chromium.org/bug/196.
|
||||
#if !defined(OS_FUCHSIA)
|
||||
|
||||
//! \brief Saves the CPU context.
|
||||
//!
|
||||
//! The CPU context will be captured as accurately and completely as possible,
|
||||
@ -76,6 +80,8 @@ using NativeCPUContext = ucontext_t;
|
||||
//! \endcode
|
||||
void CaptureContext(NativeCPUContext* cpu_context);
|
||||
|
||||
#endif // !OS_FUCHSIA
|
||||
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_UTIL_MISC_CAPTURE_CONTEXT_H_
|
||||
|
@ -24,6 +24,9 @@ namespace crashpad {
|
||||
//! \brief Utilities for handling POSIX signals.
|
||||
class Signals {
|
||||
public:
|
||||
//! \brief A signal number used by Crashpad to simulate signals.
|
||||
static constexpr int kSimulatedSigno = -1;
|
||||
|
||||
//! \brief The type used for `struct sigaction::sa_sigaction`.
|
||||
using Handler = void (*)(int, siginfo_t*, void*);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user