mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 14:06:33 +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) {
|
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) {
|
if (crashpad_is_linux || crashpad_is_android || crashpad_is_fuchsia) {
|
||||||
|
@ -50,6 +50,7 @@
|
|||||||
'simple_string_dictionary.h',
|
'simple_string_dictionary.h',
|
||||||
'simple_address_range_bag.h',
|
'simple_address_range_bag.h',
|
||||||
'simulate_crash.h',
|
'simulate_crash.h',
|
||||||
|
'simulate_crash_linux.h',
|
||||||
'simulate_crash_mac.cc',
|
'simulate_crash_mac.cc',
|
||||||
'simulate_crash_mac.h',
|
'simulate_crash_mac.h',
|
||||||
'simulate_crash_win.h',
|
'simulate_crash_win.h',
|
||||||
@ -73,6 +74,7 @@
|
|||||||
['OS=="android"', {
|
['OS=="android"', {
|
||||||
'sources/': [
|
'sources/': [
|
||||||
['include', '^crashpad_client_linux\\.cc$'],
|
['include', '^crashpad_client_linux\\.cc$'],
|
||||||
|
['include', '^simulate_crash_linux\\.h$'],
|
||||||
],
|
],
|
||||||
}],
|
}],
|
||||||
],
|
],
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "base/files/file_path.h"
|
#include "base/files/file_path.h"
|
||||||
#include "base/macros.h"
|
#include "base/macros.h"
|
||||||
#include "build/build_config.h"
|
#include "build/build_config.h"
|
||||||
|
#include "util/misc/capture_context.h"
|
||||||
|
|
||||||
#if defined(OS_MACOSX)
|
#if defined(OS_MACOSX)
|
||||||
#include "base/mac/scoped_mach_port.h"
|
#include "base/mac/scoped_mach_port.h"
|
||||||
@ -168,6 +169,17 @@ class CrashpadClient {
|
|||||||
const std::map<std::string, std::string>& annotations,
|
const std::map<std::string, std::string>& annotations,
|
||||||
const std::vector<std::string>& arguments,
|
const std::vector<std::string>& arguments,
|
||||||
int socket);
|
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
|
#endif // OS_LINUX || OS_ANDROID || DOXYGEN
|
||||||
|
|
||||||
#if defined(OS_MACOSX) || DOXYGEN
|
#if defined(OS_MACOSX) || DOXYGEN
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "util/file/file_io.h"
|
#include "util/file/file_io.h"
|
||||||
#include "util/linux/exception_handler_client.h"
|
#include "util/linux/exception_handler_client.h"
|
||||||
#include "util/linux/exception_information.h"
|
#include "util/linux/exception_information.h"
|
||||||
|
#include "util/linux/scoped_pr_set_ptracer.h"
|
||||||
#include "util/misc/from_pointer_cast.h"
|
#include "util/misc/from_pointer_cast.h"
|
||||||
#include "util/posix/double_fork_and_exec.h"
|
#include "util/posix/double_fork_and_exec.h"
|
||||||
#include "util/posix/signals.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) {
|
std::vector<const char*>* argv) {
|
||||||
argv->clear();
|
argv->clear();
|
||||||
argv->reserve(argv_strings.size() + 1);
|
argv->reserve(argv_strings.size() + 1);
|
||||||
@ -92,8 +93,22 @@ void ConvertArgvStrings(const std::vector<std::string> argv_strings,
|
|||||||
argv->push_back(nullptr);
|
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.
|
// Launches a single use handler to snapshot this process.
|
||||||
class LaunchAtCrashHandler {
|
class LaunchAtCrashHandler : public SignalHandler {
|
||||||
public:
|
public:
|
||||||
static LaunchAtCrashHandler* Get() {
|
static LaunchAtCrashHandler* Get() {
|
||||||
static LaunchAtCrashHandler* instance = new LaunchAtCrashHandler();
|
static LaunchAtCrashHandler* instance = new LaunchAtCrashHandler();
|
||||||
@ -110,6 +125,37 @@ class LaunchAtCrashHandler {
|
|||||||
return Signals::InstallCrashHandlers(HandleCrash, 0, nullptr);
|
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:
|
private:
|
||||||
LaunchAtCrashHandler() = default;
|
LaunchAtCrashHandler() = default;
|
||||||
|
|
||||||
@ -117,27 +163,7 @@ class LaunchAtCrashHandler {
|
|||||||
|
|
||||||
static void HandleCrash(int signo, siginfo_t* siginfo, void* context) {
|
static void HandleCrash(int signo, siginfo_t* siginfo, void* context) {
|
||||||
auto state = Get();
|
auto state = Get();
|
||||||
auto exception_information = &state->exception_information_;
|
state->HandleCrashFatal(signo, siginfo, context);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> argv_strings_;
|
std::vector<std::string> argv_strings_;
|
||||||
@ -147,6 +173,11 @@ class LaunchAtCrashHandler {
|
|||||||
DISALLOW_COPY_AND_ASSIGN(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
|
} // namespace
|
||||||
|
|
||||||
CrashpadClient::CrashpadClient() {}
|
CrashpadClient::CrashpadClient() {}
|
||||||
@ -181,7 +212,12 @@ bool CrashpadClient::StartHandlerAtCrash(
|
|||||||
handler, database, metrics_dir, url, annotations, arguments, &argv);
|
handler, database, metrics_dir, url, annotations, arguments, &argv);
|
||||||
|
|
||||||
auto signal_handler = LaunchAtCrashHandler::Get();
|
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(
|
bool CrashpadClient::StartHandlerForClient(
|
||||||
@ -201,4 +237,34 @@ bool CrashpadClient::StartHandlerForClient(
|
|||||||
return DoubleForkAndExec(argv, socket, true, nullptr);
|
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
|
} // namespace crashpad
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
#include "client/simulate_crash_mac.h"
|
#include "client/simulate_crash_mac.h"
|
||||||
#elif defined(OS_WIN)
|
#elif defined(OS_WIN)
|
||||||
#include "client/simulate_crash_win.h"
|
#include "client/simulate_crash_win.h"
|
||||||
|
#elif defined(OS_LINUX) || defined(OS_ANDROID)
|
||||||
|
#include "client/simulate_crash_linux.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // CRASHPAD_CLIENT_SIMULATE_CRASH_H_
|
#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;
|
using NativeCPUContext = ucontext_t;
|
||||||
#endif // OS_MACOSX
|
#endif // OS_MACOSX
|
||||||
|
|
||||||
|
// No NativeCPUContext defined for Fuchsia yet.
|
||||||
|
// https://crashpad.chromium.org/bug/196.
|
||||||
|
#if !defined(OS_FUCHSIA)
|
||||||
|
|
||||||
//! \brief Saves the CPU context.
|
//! \brief Saves the CPU context.
|
||||||
//!
|
//!
|
||||||
//! The CPU context will be captured as accurately and completely as possible,
|
//! The CPU context will be captured as accurately and completely as possible,
|
||||||
@ -76,6 +80,8 @@ using NativeCPUContext = ucontext_t;
|
|||||||
//! \endcode
|
//! \endcode
|
||||||
void CaptureContext(NativeCPUContext* cpu_context);
|
void CaptureContext(NativeCPUContext* cpu_context);
|
||||||
|
|
||||||
|
#endif // !OS_FUCHSIA
|
||||||
|
|
||||||
} // namespace crashpad
|
} // namespace crashpad
|
||||||
|
|
||||||
#endif // CRASHPAD_UTIL_MISC_CAPTURE_CONTEXT_H_
|
#endif // CRASHPAD_UTIL_MISC_CAPTURE_CONTEXT_H_
|
||||||
|
@ -24,6 +24,9 @@ namespace crashpad {
|
|||||||
//! \brief Utilities for handling POSIX signals.
|
//! \brief Utilities for handling POSIX signals.
|
||||||
class Signals {
|
class Signals {
|
||||||
public:
|
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`.
|
//! \brief The type used for `struct sigaction::sa_sigaction`.
|
||||||
using Handler = void (*)(int, siginfo_t*, void*);
|
using Handler = void (*)(int, siginfo_t*, void*);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user