mirror of
https://github.com/chromium/crashpad.git
synced 2025-01-14 09:17:57 +08:00
android/linux: add a client interface to control sanitization
Sanitization is controlled by a SanitizationInformation struct to be read from the client's memory. The address of this struct is either passed in a ClientInformation when the client requests a crash dump, or as a flag to the handler --sanitization_information. Bug: crashpad:30 Change-Id: I2744f8fb85b4fea7362b2b88faa4bef1da74e36b Reviewed-on: https://chromium-review.googlesource.com/1083143 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Scott Graham <scottmg@chromium.org>
This commit is contained in:
parent
a42b5269b4
commit
d1e6a2130d
@ -28,6 +28,7 @@
|
|||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "snapshot/annotation_snapshot.h"
|
#include "snapshot/annotation_snapshot.h"
|
||||||
#include "snapshot/minidump/process_snapshot_minidump.h"
|
#include "snapshot/minidump/process_snapshot_minidump.h"
|
||||||
|
#include "snapshot/sanitized/sanitization_information.h"
|
||||||
#include "test/multiprocess.h"
|
#include "test/multiprocess.h"
|
||||||
#include "test/multiprocess_exec.h"
|
#include "test/multiprocess_exec.h"
|
||||||
#include "test/scoped_temp_dir.h"
|
#include "test/scoped_temp_dir.h"
|
||||||
@ -210,7 +211,9 @@ class StartHandlerForClientTest {
|
|||||||
StartHandlerForClientTest() = default;
|
StartHandlerForClientTest() = default;
|
||||||
~StartHandlerForClientTest() = default;
|
~StartHandlerForClientTest() = default;
|
||||||
|
|
||||||
bool Initialize() {
|
bool Initialize(bool sanitize) {
|
||||||
|
sanitize_ = sanitize;
|
||||||
|
|
||||||
int socks[2];
|
int socks[2];
|
||||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks) != 0) {
|
if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks) != 0) {
|
||||||
PLOG(ERROR) << "socketpair";
|
PLOG(ERROR) << "socketpair";
|
||||||
@ -253,19 +256,23 @@ class StartHandlerForClientTest {
|
|||||||
ASSERT_TRUE(database);
|
ASSERT_TRUE(database);
|
||||||
|
|
||||||
std::vector<CrashReportDatabase::Report> reports;
|
std::vector<CrashReportDatabase::Report> reports;
|
||||||
ASSERT_EQ(database->GetPendingReports(&reports),
|
|
||||||
CrashReportDatabase::kNoError);
|
|
||||||
EXPECT_EQ(reports.size(), 1u);
|
|
||||||
|
|
||||||
reports.clear();
|
|
||||||
ASSERT_EQ(database->GetCompletedReports(&reports),
|
ASSERT_EQ(database->GetCompletedReports(&reports),
|
||||||
CrashReportDatabase::kNoError);
|
CrashReportDatabase::kNoError);
|
||||||
EXPECT_EQ(reports.size(), 0u);
|
EXPECT_EQ(reports.size(), 0u);
|
||||||
|
|
||||||
|
reports.clear();
|
||||||
|
ASSERT_EQ(database->GetPendingReports(&reports),
|
||||||
|
CrashReportDatabase::kNoError);
|
||||||
|
if (sanitize_) {
|
||||||
|
EXPECT_EQ(reports.size(), 0u);
|
||||||
|
} else {
|
||||||
|
EXPECT_EQ(reports.size(), 1u);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InstallHandler() {
|
bool InstallHandler() {
|
||||||
auto signal_handler = SandboxedHandler::Get();
|
auto signal_handler = SandboxedHandler::Get();
|
||||||
return signal_handler->Initialize(client_sock_.get());
|
return signal_handler->Initialize(client_sock_.get(), sanitize_);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -278,8 +285,9 @@ class StartHandlerForClientTest {
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Initialize(FileHandle client_sock) {
|
bool Initialize(FileHandle client_sock, bool sanitize) {
|
||||||
client_sock_ = client_sock;
|
client_sock_ = client_sock;
|
||||||
|
sanitize_ = sanitize;
|
||||||
return Signals::InstallCrashHandlers(HandleCrash, 0, nullptr);
|
return Signals::InstallCrashHandlers(HandleCrash, 0, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -302,11 +310,20 @@ class StartHandlerForClientTest {
|
|||||||
context);
|
context);
|
||||||
exception_information.thread_id = syscall(SYS_gettid);
|
exception_information.thread_id = syscall(SYS_gettid);
|
||||||
|
|
||||||
ClientInformation info = {};
|
ClientInformation info;
|
||||||
info.exception_information_address =
|
info.exception_information_address =
|
||||||
FromPointerCast<decltype(info.exception_information_address)>(
|
FromPointerCast<decltype(info.exception_information_address)>(
|
||||||
&exception_information);
|
&exception_information);
|
||||||
|
|
||||||
|
SanitizationInformation sanitization_info = {};
|
||||||
|
if (state->sanitize_) {
|
||||||
|
info.sanitization_information_address =
|
||||||
|
FromPointerCast<VMAddress>(&sanitization_info);
|
||||||
|
// Target a non-module address to prevent a crash dump.
|
||||||
|
sanitization_info.target_module_address =
|
||||||
|
FromPointerCast<VMAddress>(&sanitization_info);
|
||||||
|
}
|
||||||
|
|
||||||
ExceptionHandlerClient handler_client(state->client_sock_);
|
ExceptionHandlerClient handler_client(state->client_sock_);
|
||||||
CHECK_EQ(handler_client.RequestCrashDump(info), 0);
|
CHECK_EQ(handler_client.RequestCrashDump(info), 0);
|
||||||
|
|
||||||
@ -314,6 +331,7 @@ class StartHandlerForClientTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FileHandle client_sock_;
|
FileHandle client_sock_;
|
||||||
|
bool sanitize_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(SandboxedHandler);
|
DISALLOW_COPY_AND_ASSIGN(SandboxedHandler);
|
||||||
};
|
};
|
||||||
@ -321,6 +339,7 @@ class StartHandlerForClientTest {
|
|||||||
ScopedTempDir temp_dir_;
|
ScopedTempDir temp_dir_;
|
||||||
ScopedFileHandle client_sock_;
|
ScopedFileHandle client_sock_;
|
||||||
ScopedFileHandle server_sock_;
|
ScopedFileHandle server_sock_;
|
||||||
|
bool sanitize_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(StartHandlerForClientTest);
|
DISALLOW_COPY_AND_ASSIGN(StartHandlerForClientTest);
|
||||||
};
|
};
|
||||||
@ -331,9 +350,9 @@ class StartHandlerForChildTest : public Multiprocess {
|
|||||||
StartHandlerForChildTest() = default;
|
StartHandlerForChildTest() = default;
|
||||||
~StartHandlerForChildTest() = default;
|
~StartHandlerForChildTest() = default;
|
||||||
|
|
||||||
bool Initialize() {
|
bool Initialize(bool sanitize) {
|
||||||
SetExpectedChildTerminationBuiltinTrap();
|
SetExpectedChildTerminationBuiltinTrap();
|
||||||
return test_state_.Initialize();
|
return test_state_.Initialize(sanitize);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -361,7 +380,13 @@ class StartHandlerForChildTest : public Multiprocess {
|
|||||||
|
|
||||||
TEST(CrashpadClient, StartHandlerForChild) {
|
TEST(CrashpadClient, StartHandlerForChild) {
|
||||||
StartHandlerForChildTest test;
|
StartHandlerForChildTest test;
|
||||||
ASSERT_TRUE(test.Initialize());
|
ASSERT_TRUE(test.Initialize(/* sanitize= */ false));
|
||||||
|
test.Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CrashpadClient, SanitizedChild) {
|
||||||
|
StartHandlerForChildTest test;
|
||||||
|
ASSERT_TRUE(test.Initialize(/* sanitize= */ true));
|
||||||
test.Run();
|
test.Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,6 +144,8 @@ void Usage(const base::FilePath& me) {
|
|||||||
" --trace-parent-with-exception=EXCEPTION_INFORMATION_ADDRESS\n"
|
" --trace-parent-with-exception=EXCEPTION_INFORMATION_ADDRESS\n"
|
||||||
" request a dump for the handler's parent process\n"
|
" request a dump for the handler's parent process\n"
|
||||||
" --initial-client-fd=FD a socket connected to a client.\n"
|
" --initial-client-fd=FD a socket connected to a client.\n"
|
||||||
|
" --sanitization_information=SANITIZATION_INFORMATION_ADDRESS\n"
|
||||||
|
" the address of a SanitizationInformation struct.\n"
|
||||||
#endif // OS_LINUX || OS_ANDROID
|
#endif // OS_LINUX || OS_ANDROID
|
||||||
" --url=URL send crash reports to this Breakpad server URL,\n"
|
" --url=URL send crash reports to this Breakpad server URL,\n"
|
||||||
" only if uploads are enabled for the database\n"
|
" only if uploads are enabled for the database\n"
|
||||||
@ -167,6 +169,7 @@ struct Options {
|
|||||||
#elif defined(OS_LINUX) || defined(OS_ANDROID)
|
#elif defined(OS_LINUX) || defined(OS_ANDROID)
|
||||||
VMAddress exception_information_address;
|
VMAddress exception_information_address;
|
||||||
int initial_client_fd;
|
int initial_client_fd;
|
||||||
|
VMAddress sanitization_information_address;
|
||||||
#elif defined(OS_WIN)
|
#elif defined(OS_WIN)
|
||||||
std::string pipe_name;
|
std::string pipe_name;
|
||||||
InitialClientData initial_client_data;
|
InitialClientData initial_client_data;
|
||||||
@ -535,6 +538,7 @@ int HandlerMain(int argc,
|
|||||||
#if defined(OS_LINUX) || defined(OS_ANDROID)
|
#if defined(OS_LINUX) || defined(OS_ANDROID)
|
||||||
kOptionTraceParentWithException,
|
kOptionTraceParentWithException,
|
||||||
kOptionInitialClientFD,
|
kOptionInitialClientFD,
|
||||||
|
kOptionSanitizationInformation,
|
||||||
#endif
|
#endif
|
||||||
kOptionURL,
|
kOptionURL,
|
||||||
|
|
||||||
@ -590,6 +594,10 @@ int HandlerMain(int argc,
|
|||||||
nullptr,
|
nullptr,
|
||||||
kOptionTraceParentWithException},
|
kOptionTraceParentWithException},
|
||||||
{"initial-client-fd", required_argument, nullptr, kOptionInitialClientFD},
|
{"initial-client-fd", required_argument, nullptr, kOptionInitialClientFD},
|
||||||
|
{"sanitization-information",
|
||||||
|
required_argument,
|
||||||
|
nullptr,
|
||||||
|
kOptionSanitizationInformation},
|
||||||
#endif // OS_LINUX || OS_ANDROID
|
#endif // OS_LINUX || OS_ANDROID
|
||||||
{"url", required_argument, nullptr, kOptionURL},
|
{"url", required_argument, nullptr, kOptionURL},
|
||||||
{"help", no_argument, nullptr, kOptionHelp},
|
{"help", no_argument, nullptr, kOptionHelp},
|
||||||
@ -608,6 +616,7 @@ int HandlerMain(int argc,
|
|||||||
#if defined(OS_LINUX) || defined(OS_ANDROID)
|
#if defined(OS_LINUX) || defined(OS_ANDROID)
|
||||||
options.exception_information_address = 0;
|
options.exception_information_address = 0;
|
||||||
options.initial_client_fd = kInvalidFileHandle;
|
options.initial_client_fd = kInvalidFileHandle;
|
||||||
|
options.sanitization_information_address = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int opt;
|
int opt;
|
||||||
@ -714,6 +723,15 @@ int HandlerMain(int argc,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case kOptionSanitizationInformation: {
|
||||||
|
if (!StringToNumber(optarg,
|
||||||
|
&options.sanitization_information_address)) {
|
||||||
|
ToolSupport::UsageHint(me,
|
||||||
|
"failed to parse --sanitization-information");
|
||||||
|
return ExitFailure();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
#endif // OS_LINUX || OS_ANDROID
|
#endif // OS_LINUX || OS_ANDROID
|
||||||
case kOptionURL: {
|
case kOptionURL: {
|
||||||
options.url = optarg;
|
options.url = optarg;
|
||||||
@ -762,9 +780,15 @@ int HandlerMain(int argc,
|
|||||||
#elif defined(OS_LINUX) || defined(OS_ANDROID)
|
#elif defined(OS_LINUX) || defined(OS_ANDROID)
|
||||||
if (!options.exception_information_address &&
|
if (!options.exception_information_address &&
|
||||||
options.initial_client_fd == kInvalidFileHandle) {
|
options.initial_client_fd == kInvalidFileHandle) {
|
||||||
|
ToolSupport::UsageHint(
|
||||||
|
me, "--trace-parent-with-exception or --initial_client_fd is required");
|
||||||
|
return ExitFailure();
|
||||||
|
}
|
||||||
|
if (options.sanitization_information_address &&
|
||||||
|
!options.exception_information_address) {
|
||||||
ToolSupport::UsageHint(
|
ToolSupport::UsageHint(
|
||||||
me,
|
me,
|
||||||
"--exception_information_address or --initial_client_fd is required");
|
"--sanitization_information requires --trace-parent-with-exception");
|
||||||
return ExitFailure();
|
return ExitFailure();
|
||||||
}
|
}
|
||||||
#endif // OS_MACOSX
|
#endif // OS_MACOSX
|
||||||
@ -844,9 +868,12 @@ int HandlerMain(int argc,
|
|||||||
|
|
||||||
#if defined(OS_LINUX) || defined(OS_ANDROID)
|
#if defined(OS_LINUX) || defined(OS_ANDROID)
|
||||||
if (options.exception_information_address) {
|
if (options.exception_information_address) {
|
||||||
return exception_handler.HandleException(getppid(),
|
ClientInformation info;
|
||||||
options.exception_information_address) ?
|
info.exception_information_address = options.exception_information_address;
|
||||||
EXIT_SUCCESS : ExitFailure();
|
info.sanitization_information_address =
|
||||||
|
options.sanitization_information_address;
|
||||||
|
return exception_handler.HandleException(getppid(), info) ? EXIT_SUCCESS
|
||||||
|
: ExitFailure();
|
||||||
}
|
}
|
||||||
#endif // OS_LINUX || OS_ANDROID
|
#endif // OS_LINUX || OS_ANDROID
|
||||||
|
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
#include "minidump/minidump_file_writer.h"
|
#include "minidump/minidump_file_writer.h"
|
||||||
#include "snapshot/crashpad_info_client_options.h"
|
#include "snapshot/crashpad_info_client_options.h"
|
||||||
#include "snapshot/linux/process_snapshot_linux.h"
|
#include "snapshot/linux/process_snapshot_linux.h"
|
||||||
|
#include "snapshot/sanitized/process_snapshot_sanitized.h"
|
||||||
|
#include "snapshot/sanitized/sanitization_information.h"
|
||||||
#include "util/linux/direct_ptrace_connection.h"
|
#include "util/linux/direct_ptrace_connection.h"
|
||||||
#include "util/linux/ptrace_client.h"
|
#include "util/linux/ptrace_client.h"
|
||||||
#include "util/misc/metrics.h"
|
#include "util/misc/metrics.h"
|
||||||
@ -43,7 +45,7 @@ CrashReportExceptionHandler::~CrashReportExceptionHandler() = default;
|
|||||||
|
|
||||||
bool CrashReportExceptionHandler::HandleException(
|
bool CrashReportExceptionHandler::HandleException(
|
||||||
pid_t client_process_id,
|
pid_t client_process_id,
|
||||||
VMAddress exception_info_address) {
|
const ClientInformation& info) {
|
||||||
Metrics::ExceptionEncountered();
|
Metrics::ExceptionEncountered();
|
||||||
|
|
||||||
DirectPtraceConnection connection;
|
DirectPtraceConnection connection;
|
||||||
@ -53,12 +55,12 @@ bool CrashReportExceptionHandler::HandleException(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return HandleExceptionWithConnection(&connection, exception_info_address);
|
return HandleExceptionWithConnection(&connection, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CrashReportExceptionHandler::HandleExceptionWithBroker(
|
bool CrashReportExceptionHandler::HandleExceptionWithBroker(
|
||||||
pid_t client_process_id,
|
pid_t client_process_id,
|
||||||
VMAddress exception_info_address,
|
const ClientInformation& info,
|
||||||
int broker_sock) {
|
int broker_sock) {
|
||||||
Metrics::ExceptionEncountered();
|
Metrics::ExceptionEncountered();
|
||||||
|
|
||||||
@ -69,19 +71,20 @@ bool CrashReportExceptionHandler::HandleExceptionWithBroker(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return HandleExceptionWithConnection(&client, exception_info_address);
|
return HandleExceptionWithConnection(&client, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CrashReportExceptionHandler::HandleExceptionWithConnection(
|
bool CrashReportExceptionHandler::HandleExceptionWithConnection(
|
||||||
PtraceConnection* connection,
|
PtraceConnection* connection,
|
||||||
VMAddress exception_info_address) {
|
const ClientInformation& info) {
|
||||||
ProcessSnapshotLinux process_snapshot;
|
ProcessSnapshotLinux process_snapshot;
|
||||||
if (!process_snapshot.Initialize(connection)) {
|
if (!process_snapshot.Initialize(connection)) {
|
||||||
Metrics::ExceptionCaptureResult(Metrics::CaptureResult::kSnapshotFailed);
|
Metrics::ExceptionCaptureResult(Metrics::CaptureResult::kSnapshotFailed);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!process_snapshot.InitializeException(exception_info_address)) {
|
if (!process_snapshot.InitializeException(
|
||||||
|
info.exception_information_address)) {
|
||||||
Metrics::ExceptionCaptureResult(
|
Metrics::ExceptionCaptureResult(
|
||||||
Metrics::CaptureResult::kExceptionInitializationFailed);
|
Metrics::CaptureResult::kExceptionInitializationFailed);
|
||||||
return false;
|
return false;
|
||||||
@ -116,10 +119,50 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection(
|
|||||||
|
|
||||||
process_snapshot.SetReportID(new_report->ReportID());
|
process_snapshot.SetReportID(new_report->ReportID());
|
||||||
|
|
||||||
|
ProcessSnapshot* snapshot = nullptr;
|
||||||
|
ProcessSnapshotSanitized sanitized;
|
||||||
|
std::vector<std::string> whitelist;
|
||||||
|
if (info.sanitization_information_address) {
|
||||||
|
SanitizationInformation sanitization_info;
|
||||||
|
ProcessMemoryRange range;
|
||||||
|
if (!range.Initialize(connection->Memory(), connection->Is64Bit()) ||
|
||||||
|
!range.Read(info.sanitization_information_address,
|
||||||
|
sizeof(sanitization_info),
|
||||||
|
&sanitization_info)) {
|
||||||
|
Metrics::ExceptionCaptureResult(
|
||||||
|
Metrics::CaptureResult::kSanitizationInitializationFailed);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sanitization_info.annotations_whitelist_address &&
|
||||||
|
!ReadAnnotationsWhitelist(
|
||||||
|
range,
|
||||||
|
sanitization_info.annotations_whitelist_address,
|
||||||
|
&whitelist)) {
|
||||||
|
Metrics::ExceptionCaptureResult(
|
||||||
|
Metrics::CaptureResult::kSanitizationInitializationFailed);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sanitized.Initialize(&process_snapshot,
|
||||||
|
sanitization_info.annotations_whitelist_address
|
||||||
|
? &whitelist
|
||||||
|
: nullptr,
|
||||||
|
sanitization_info.target_module_address,
|
||||||
|
sanitization_info.sanitize_stacks)) {
|
||||||
|
Metrics::ExceptionCaptureResult(
|
||||||
|
Metrics::CaptureResult::kSkippedDueToSanitization);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshot = &sanitized;
|
||||||
|
} else {
|
||||||
|
snapshot = &process_snapshot;
|
||||||
|
}
|
||||||
|
|
||||||
MinidumpFileWriter minidump;
|
MinidumpFileWriter minidump;
|
||||||
minidump.InitializeFromSnapshot(&process_snapshot);
|
minidump.InitializeFromSnapshot(snapshot);
|
||||||
AddUserExtensionStreams(
|
AddUserExtensionStreams(user_stream_data_sources_, snapshot, &minidump);
|
||||||
user_stream_data_sources_, &process_snapshot, &minidump);
|
|
||||||
|
|
||||||
if (!minidump.WriteEverything(new_report->Writer())) {
|
if (!minidump.WriteEverything(new_report->Writer())) {
|
||||||
LOG(ERROR) << "WriteEverything failed";
|
LOG(ERROR) << "WriteEverything failed";
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "handler/crash_report_upload_thread.h"
|
#include "handler/crash_report_upload_thread.h"
|
||||||
#include "handler/linux/exception_handler_server.h"
|
#include "handler/linux/exception_handler_server.h"
|
||||||
#include "handler/user_stream_data_source.h"
|
#include "handler/user_stream_data_source.h"
|
||||||
|
#include "util/linux/exception_handler_protocol.h"
|
||||||
#include "util/linux/ptrace_connection.h"
|
#include "util/linux/ptrace_connection.h"
|
||||||
#include "util/misc/address_types.h"
|
#include "util/misc/address_types.h"
|
||||||
|
|
||||||
@ -63,15 +64,15 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate {
|
|||||||
// ExceptionHandlerServer::Delegate:
|
// ExceptionHandlerServer::Delegate:
|
||||||
|
|
||||||
bool HandleException(pid_t client_process_id,
|
bool HandleException(pid_t client_process_id,
|
||||||
VMAddress exception_info_address) override;
|
const ClientInformation& info) override;
|
||||||
|
|
||||||
bool HandleExceptionWithBroker(pid_t client_process_id,
|
bool HandleExceptionWithBroker(pid_t client_process_id,
|
||||||
VMAddress exception_info_address,
|
const ClientInformation& info,
|
||||||
int broker_sock) override;
|
int broker_sock) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool HandleExceptionWithConnection(PtraceConnection* connection,
|
bool HandleExceptionWithConnection(PtraceConnection* connection,
|
||||||
VMAddress exception_info_address);
|
const ClientInformation& info);
|
||||||
|
|
||||||
CrashReportDatabase* database_; // weak
|
CrashReportDatabase* database_; // weak
|
||||||
CrashReportUploadThread* upload_thread_; // weak
|
CrashReportUploadThread* upload_thread_; // weak
|
||||||
|
@ -446,15 +446,12 @@ bool ExceptionHandlerServer::HandleCrashDumpRequest(
|
|||||||
ServerToClientMessage::kTypeCrashDumpFailed);
|
ServerToClientMessage::kTypeCrashDumpFailed);
|
||||||
|
|
||||||
case PtraceStrategyDecider::Strategy::kDirectPtrace:
|
case PtraceStrategyDecider::Strategy::kDirectPtrace:
|
||||||
delegate_->HandleException(client_process_id,
|
delegate_->HandleException(client_process_id, client_info);
|
||||||
client_info.exception_information_address);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PtraceStrategyDecider::Strategy::kUseBroker:
|
case PtraceStrategyDecider::Strategy::kUseBroker:
|
||||||
delegate_->HandleExceptionWithBroker(
|
delegate_->HandleExceptionWithBroker(
|
||||||
client_process_id,
|
client_process_id, client_info, client_sock);
|
||||||
client_info.exception_information_address,
|
|
||||||
client_sock);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,24 +71,21 @@ class ExceptionHandlerServer {
|
|||||||
//! \brief Called on receipt of a crash dump request from a client.
|
//! \brief Called on receipt of a crash dump request from a client.
|
||||||
//!
|
//!
|
||||||
//! \param[in] client_process_id The process ID of the crashing client.
|
//! \param[in] client_process_id The process ID of the crashing client.
|
||||||
//! \param[in] exception_information_address The address in the client's
|
//! \param[in] info Information on the client.
|
||||||
//! address space of an ExceptionInformation struct.
|
|
||||||
//! \return `true` on success. `false` on failure with a message logged.
|
//! \return `true` on success. `false` on failure with a message logged.
|
||||||
virtual bool HandleException(pid_t client_process_id,
|
virtual bool HandleException(pid_t client_process_id,
|
||||||
VMAddress exception_information_address) = 0;
|
const ClientInformation& info) = 0;
|
||||||
|
|
||||||
//! \brief Called on the receipt of a crash dump request from a client for a
|
//! \brief Called on the receipt of a crash dump request from a client for a
|
||||||
//! crash that should be mediated by a PtraceBroker.
|
//! crash that should be mediated by a PtraceBroker.
|
||||||
//!
|
//!
|
||||||
//! \param[in] client_process_id The process ID of the crashing client.
|
//! \param[in] client_process_id The process ID of the crashing client.
|
||||||
//! \param[in] exception_information_address The address in the client's
|
//! \param[in] info Information on the client.
|
||||||
//! address space of an ExceptionInformation struct.
|
|
||||||
//! \param[in] broker_sock A socket connected to the PtraceBroker.
|
//! \param[in] broker_sock A socket connected to the PtraceBroker.
|
||||||
//! \return `true` on success. `false` on failure with a message logged.
|
//! \return `true` on success. `false` on failure with a message logged.
|
||||||
virtual bool HandleExceptionWithBroker(
|
virtual bool HandleExceptionWithBroker(pid_t client_process_id,
|
||||||
pid_t client_process_id,
|
const ClientInformation& info,
|
||||||
VMAddress exception_information_address,
|
int broker_sock) = 0;
|
||||||
int broker_sock) = 0;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
~Delegate() {}
|
~Delegate() {}
|
||||||
|
@ -101,25 +101,25 @@ class TestDelegate : public ExceptionHandlerServer::Delegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool HandleException(pid_t client_process_id,
|
bool HandleException(pid_t client_process_id,
|
||||||
VMAddress exception_information_address) override {
|
const ClientInformation& info) override {
|
||||||
DirectPtraceConnection connection;
|
DirectPtraceConnection connection;
|
||||||
bool connected = connection.Initialize(client_process_id);
|
bool connected = connection.Initialize(client_process_id);
|
||||||
EXPECT_TRUE(connected);
|
EXPECT_TRUE(connected);
|
||||||
|
|
||||||
last_exception_address_ = exception_information_address;
|
last_exception_address_ = info.exception_information_address;
|
||||||
last_client_ = client_process_id;
|
last_client_ = client_process_id;
|
||||||
sem_.Signal();
|
sem_.Signal();
|
||||||
return connected;
|
return connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HandleExceptionWithBroker(pid_t client_process_id,
|
bool HandleExceptionWithBroker(pid_t client_process_id,
|
||||||
VMAddress exception_information_address,
|
const ClientInformation& info,
|
||||||
int broker_sock) override {
|
int broker_sock) override {
|
||||||
PtraceClient client;
|
PtraceClient client;
|
||||||
bool connected = client.Initialize(broker_sock, client_process_id);
|
bool connected = client.Initialize(broker_sock, client_process_id);
|
||||||
EXPECT_TRUE(connected);
|
EXPECT_TRUE(connected);
|
||||||
|
|
||||||
last_exception_address_ = exception_information_address,
|
last_exception_address_ = info.exception_information_address,
|
||||||
last_client_ = client_process_id;
|
last_client_ = client_process_id;
|
||||||
sem_.Signal();
|
sem_.Signal();
|
||||||
return connected;
|
return connected;
|
||||||
|
@ -128,6 +128,8 @@ static_library("snapshot") {
|
|||||||
"sanitized/module_snapshot_sanitized.h",
|
"sanitized/module_snapshot_sanitized.h",
|
||||||
"sanitized/process_snapshot_sanitized.cc",
|
"sanitized/process_snapshot_sanitized.cc",
|
||||||
"sanitized/process_snapshot_sanitized.h",
|
"sanitized/process_snapshot_sanitized.h",
|
||||||
|
"sanitized/sanitization_information.cc",
|
||||||
|
"sanitized/sanitization_information.h",
|
||||||
"sanitized/thread_snapshot_sanitized.cc",
|
"sanitized/thread_snapshot_sanitized.cc",
|
||||||
"sanitized/thread_snapshot_sanitized.h",
|
"sanitized/thread_snapshot_sanitized.h",
|
||||||
]
|
]
|
||||||
@ -338,6 +340,7 @@ source_set("snapshot_test") {
|
|||||||
"linux/process_reader_linux_test.cc",
|
"linux/process_reader_linux_test.cc",
|
||||||
"linux/system_snapshot_linux_test.cc",
|
"linux/system_snapshot_linux_test.cc",
|
||||||
"sanitized/process_snapshot_sanitized_test.cc",
|
"sanitized/process_snapshot_sanitized_test.cc",
|
||||||
|
"sanitized/sanitization_information_test.cc",
|
||||||
]
|
]
|
||||||
} else {
|
} else {
|
||||||
sources += [ "crashpad_info_client_options_test.cc" ]
|
sources += [ "crashpad_info_client_options_test.cc" ]
|
||||||
|
61
snapshot/sanitized/sanitization_information.cc
Normal file
61
snapshot/sanitized/sanitization_information.cc
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#include "snapshot/sanitized/sanitization_information.h"
|
||||||
|
|
||||||
|
#include "client/annotation.h"
|
||||||
|
|
||||||
|
namespace crashpad {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
template <typename Pointer>
|
||||||
|
bool ReadWhitelist(const ProcessMemoryRange& memory,
|
||||||
|
VMAddress whitelist_address,
|
||||||
|
std::vector<std::string>* whitelist) {
|
||||||
|
if (!whitelist_address) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> local_whitelist;
|
||||||
|
Pointer name_address;
|
||||||
|
while (memory.Read(whitelist_address, sizeof(name_address), &name_address)) {
|
||||||
|
if (!name_address) {
|
||||||
|
whitelist->swap(local_whitelist);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
if (!memory.ReadCStringSizeLimited(
|
||||||
|
name_address, Annotation::kNameMaxLength, &name)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
local_whitelist.push_back(name);
|
||||||
|
whitelist_address += sizeof(Pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
bool ReadAnnotationsWhitelist(const ProcessMemoryRange& memory,
|
||||||
|
VMAddress whitelist_address,
|
||||||
|
std::vector<std::string>* whitelist) {
|
||||||
|
return memory.Is64Bit()
|
||||||
|
? ReadWhitelist<uint64_t>(memory, whitelist_address, whitelist)
|
||||||
|
: ReadWhitelist<uint32_t>(memory, whitelist_address, whitelist);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace crashpad
|
68
snapshot/sanitized/sanitization_information.h
Normal file
68
snapshot/sanitized/sanitization_information.h
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// 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_SNAPSHOT_SANITIZED_SANITIZATION_INFORMATION_H_
|
||||||
|
#define CRASHPAD_SNAPSHOT_SANITIZED_SANITIZATION_INFORMATION_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "util/misc/address_types.h"
|
||||||
|
#include "util/process/process_memory_range.h"
|
||||||
|
|
||||||
|
namespace crashpad {
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
|
//! \brief Struture containing information about how snapshots should be
|
||||||
|
//! sanitized.
|
||||||
|
//!
|
||||||
|
//! \see ProcessSnapshotSanitized
|
||||||
|
struct SanitizationInformation {
|
||||||
|
//! \brief The address in the client process' address space of a nullptr
|
||||||
|
//! terminated array of NUL-terminated strings. The string values are the
|
||||||
|
//! names of whitelisted annotations. This value is 0 if there is no
|
||||||
|
//! whitelist and all annotations are allowed.
|
||||||
|
VMAddress annotations_whitelist_address;
|
||||||
|
|
||||||
|
//! \brief An address in the client process' address space within a module to
|
||||||
|
//! target. When a target module is used, crash dumps are discarded unless
|
||||||
|
//! the crashing thread's program counter or pointer-aligned values on the
|
||||||
|
//! crashing thread's stack point into the target module. This value is 0
|
||||||
|
//! if there is no target module.
|
||||||
|
VMAddress target_module_address;
|
||||||
|
|
||||||
|
//! \brief Non-zero if stacks should be sanitized for possible PII.
|
||||||
|
uint8_t sanitize_stacks;
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
//! \brief Reads an annotations whitelist from another process.
|
||||||
|
//!
|
||||||
|
//! \param[in] memory A memory reader for the target process.
|
||||||
|
//! \param[in] whitelist_address The address in the target process' address
|
||||||
|
//! space of a nullptr terminated array of NUL-terminated strings.
|
||||||
|
//! \param[out] whitelist The whitelist read, valid only if this function
|
||||||
|
//! returns `true`.
|
||||||
|
//! \return `true` on success, `false` on failure with a message logged.
|
||||||
|
bool ReadAnnotationsWhitelist(const ProcessMemoryRange& memory,
|
||||||
|
VMAddress whitelist_address,
|
||||||
|
std::vector<std::string>* whitelist);
|
||||||
|
|
||||||
|
} // namespace crashpad
|
||||||
|
|
||||||
|
#endif // CRASHPAD_SNAPSHOT_SANITIZED_SANITIZATION_INFORMATION_H_
|
70
snapshot/sanitized/sanitization_information_test.cc
Normal file
70
snapshot/sanitized/sanitization_information_test.cc
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#include "snapshot/sanitized/sanitization_information.h"
|
||||||
|
|
||||||
|
#include "build/build_config.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "util/misc/from_pointer_cast.h"
|
||||||
|
#include "util/process/process_memory_linux.h"
|
||||||
|
|
||||||
|
namespace crashpad {
|
||||||
|
namespace test {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class WhitelistTest : public testing::Test {
|
||||||
|
public:
|
||||||
|
void SetUp() override {
|
||||||
|
ASSERT_TRUE(memory_.Initialize(getpid()));
|
||||||
|
#if defined(ARCH_CPU_64_BITS)
|
||||||
|
ASSERT_TRUE(range_.Initialize(&memory_, true));
|
||||||
|
#else
|
||||||
|
ASSERT_TRUE(range_.Initialize(&memory_, false));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool ReadWhitelist(const char* const* address) {
|
||||||
|
return ReadAnnotationsWhitelist(
|
||||||
|
range_, FromPointerCast<VMAddress>(address), &whitelist_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessMemoryLinux memory_;
|
||||||
|
ProcessMemoryRange range_;
|
||||||
|
std::vector<std::string> whitelist_;
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* const kEmptyWhitelist[] = {nullptr};
|
||||||
|
|
||||||
|
TEST_F(WhitelistTest, EmptyWhitelist) {
|
||||||
|
ASSERT_TRUE(ReadWhitelist(kEmptyWhitelist));
|
||||||
|
EXPECT_EQ(whitelist_, std::vector<std::string>());
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* const kNonEmptyWhitelist[] = {"string1",
|
||||||
|
"another_string",
|
||||||
|
"",
|
||||||
|
nullptr};
|
||||||
|
|
||||||
|
TEST_F(WhitelistTest, NonEmptyWhitelist) {
|
||||||
|
ASSERT_TRUE(ReadWhitelist(kNonEmptyWhitelist));
|
||||||
|
ASSERT_EQ(whitelist_.size(), arraysize(kNonEmptyWhitelist) - 1);
|
||||||
|
for (size_t index = 0; index < arraysize(kNonEmptyWhitelist) - 1; ++index) {
|
||||||
|
EXPECT_EQ(whitelist_[index], kNonEmptyWhitelist[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace test
|
||||||
|
} // namespace crashpad
|
@ -129,6 +129,8 @@
|
|||||||
'sanitized/module_snapshot_sanitized.h',
|
'sanitized/module_snapshot_sanitized.h',
|
||||||
'sanitized/process_snapshot_sanitized.cc',
|
'sanitized/process_snapshot_sanitized.cc',
|
||||||
'sanitized/process_snapshot_sanitized.h',
|
'sanitized/process_snapshot_sanitized.h',
|
||||||
|
'sanitized/sanitization_information.cc',
|
||||||
|
'sanitized/sanitization_information.h',
|
||||||
'sanitized/thread_snapshot_sanitized.cc',
|
'sanitized/thread_snapshot_sanitized.cc',
|
||||||
'sanitized/thread_snapshot_sanitized.h',
|
'sanitized/thread_snapshot_sanitized.h',
|
||||||
'snapshot_constants.h',
|
'snapshot_constants.h',
|
||||||
|
@ -93,6 +93,7 @@
|
|||||||
'minidump/process_snapshot_minidump_test.cc',
|
'minidump/process_snapshot_minidump_test.cc',
|
||||||
'posix/timezone_test.cc',
|
'posix/timezone_test.cc',
|
||||||
'sanitized/process_snapshot_sanitized_test.cc',
|
'sanitized/process_snapshot_sanitized_test.cc',
|
||||||
|
'sanitized/sanitization_information_test.cc',
|
||||||
'win/cpu_context_win_test.cc',
|
'win/cpu_context_win_test.cc',
|
||||||
'win/exception_snapshot_win_test.cc',
|
'win/exception_snapshot_win_test.cc',
|
||||||
'win/extra_memory_ranges_test.cc',
|
'win/extra_memory_ranges_test.cc',
|
||||||
|
@ -281,6 +281,7 @@ static_library("util") {
|
|||||||
"linux/direct_ptrace_connection.h",
|
"linux/direct_ptrace_connection.h",
|
||||||
"linux/exception_handler_client.cc",
|
"linux/exception_handler_client.cc",
|
||||||
"linux/exception_handler_client.h",
|
"linux/exception_handler_client.h",
|
||||||
|
"linux/exception_handler_protocol.cc",
|
||||||
"linux/exception_handler_protocol.h",
|
"linux/exception_handler_protocol.h",
|
||||||
"linux/exception_information.h",
|
"linux/exception_information.h",
|
||||||
"linux/memory_map.cc",
|
"linux/memory_map.cc",
|
||||||
|
25
util/linux/exception_handler_protocol.cc
Normal file
25
util/linux/exception_handler_protocol.cc
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#include "util/linux/exception_handler_protocol.h"
|
||||||
|
|
||||||
|
namespace crashpad {
|
||||||
|
|
||||||
|
ClientInformation::ClientInformation()
|
||||||
|
: exception_information_address(0), sanitization_information_address(0) {}
|
||||||
|
|
||||||
|
ClientToServerMessage::ClientToServerMessage()
|
||||||
|
: version(kVersion), type(kCrashDumpRequest), client_info() {}
|
||||||
|
|
||||||
|
} // namespace crashpad
|
@ -35,17 +35,27 @@ enum Bool : char { kBoolFalse, kBoolTrue };
|
|||||||
|
|
||||||
//! \brief Information about a client registered with an ExceptionHandlerServer.
|
//! \brief Information about a client registered with an ExceptionHandlerServer.
|
||||||
struct ClientInformation {
|
struct ClientInformation {
|
||||||
|
//! \brief Constructs this object.
|
||||||
|
ClientInformation();
|
||||||
|
|
||||||
//! \brief The address in the client's address space of an
|
//! \brief The address in the client's address space of an
|
||||||
//! ExceptionInformation struct.
|
//! ExceptionInformation struct.
|
||||||
VMAddress exception_information_address;
|
VMAddress exception_information_address;
|
||||||
|
|
||||||
|
//! \brief The address in the client's address space of a
|
||||||
|
//! SanitizationInformation struct, or 0 if there is no such struct.
|
||||||
|
VMAddress sanitization_information_address;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! \brief The message passed from client to server.
|
//! \brief The message passed from client to server.
|
||||||
struct ClientToServerMessage {
|
struct ClientToServerMessage {
|
||||||
static constexpr int32_t kVersion = 1;
|
static constexpr int32_t kVersion = 1;
|
||||||
|
|
||||||
|
//! \brief Constructs this object.
|
||||||
|
ClientToServerMessage();
|
||||||
|
|
||||||
//! \brief Indicates what message version is being used.
|
//! \brief Indicates what message version is being used.
|
||||||
int32_t version = kVersion;
|
int32_t version;
|
||||||
|
|
||||||
enum Type : uint32_t {
|
enum Type : uint32_t {
|
||||||
//! \brief Used to request a crash dump for the sending client.
|
//! \brief Used to request a crash dump for the sending client.
|
||||||
|
@ -129,6 +129,12 @@ class Metrics {
|
|||||||
//! This value is only used on Linux/Android.
|
//! This value is only used on Linux/Android.
|
||||||
kBrokeredPtraceFailed = 9,
|
kBrokeredPtraceFailed = 9,
|
||||||
|
|
||||||
|
//! \brief Sanitization was requested but could not be initialized.
|
||||||
|
kSanitizationInitializationFailed = 10,
|
||||||
|
|
||||||
|
//! \brief Sanitization caused this crash dump to be skipped.
|
||||||
|
kSkippedDueToSanitization = 11,
|
||||||
|
|
||||||
//! \brief The number of values in this enumeration; not a valid value.
|
//! \brief The number of values in this enumeration; not a valid value.
|
||||||
kMaxValue
|
kMaxValue
|
||||||
};
|
};
|
||||||
|
@ -60,6 +60,7 @@
|
|||||||
'linux/direct_ptrace_connection.h',
|
'linux/direct_ptrace_connection.h',
|
||||||
'linux/exception_handler_client.cc',
|
'linux/exception_handler_client.cc',
|
||||||
'linux/exception_handler_client.h',
|
'linux/exception_handler_client.h',
|
||||||
|
'linux/exception_handler_protocol.cc',
|
||||||
'linux/exception_handler_protocol.h',
|
'linux/exception_handler_protocol.h',
|
||||||
'linux/exception_information.h',
|
'linux/exception_information.h',
|
||||||
'linux/memory_map.cc',
|
'linux/memory_map.cc',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user