Add Windows ARM64 support to Chromium crashpad

Bug: chromium:893460
Change-Id: Ifbeb6f937a6b96c77b02dcf8afe492c5bc617435
Reviewed-on: https://chromium-review.googlesource.com/c/1347773
Reviewed-by: Mark Mentovai <mark@chromium.org>
Commit-Queue: Mark Mentovai <mark@chromium.org>
This commit is contained in:
Tom Tan 2018-12-12 12:58:24 -08:00 committed by Commit Bot
parent 9b6dde9101
commit 761c6fe8be
20 changed files with 229 additions and 69 deletions

View File

@ -36,6 +36,7 @@
#include "util/misc/random_string.h" #include "util/misc/random_string.h"
#include "util/win/address_types.h" #include "util/win/address_types.h"
#include "util/win/command_line.h" #include "util/win/command_line.h"
#include "util/win/context_wrappers.h"
#include "util/win/critical_section_with_debug_info.h" #include "util/win/critical_section_with_debug_info.h"
#include "util/win/get_function.h" #include "util/win/get_function.h"
#include "util/win/handle.h" #include "util/win/handle.h"
@ -187,11 +188,7 @@ void HandleAbortSignal(int signum) {
EXCEPTION_RECORD record = {}; EXCEPTION_RECORD record = {};
record.ExceptionCode = STATUS_FATAL_APP_EXIT; record.ExceptionCode = STATUS_FATAL_APP_EXIT;
record.ExceptionFlags = EXCEPTION_NONCONTINUABLE; record.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
#if defined(ARCH_CPU_64_BITS) record.ExceptionAddress = ProgramCounterFromCONTEXT(&context);
record.ExceptionAddress = reinterpret_cast<void*>(context.Rip);
#else
record.ExceptionAddress = reinterpret_cast<void*>(context.Eip);
#endif // ARCH_CPU_64_BITS
EXCEPTION_POINTERS exception_pointers; EXCEPTION_POINTERS exception_pointers;
exception_pointers.ContextRecord = &context; exception_pointers.ContextRecord = &context;
@ -773,11 +770,7 @@ void CrashpadClient::DumpWithoutCrash(const CONTEXT& context) {
constexpr uint32_t kSimulatedExceptionCode = 0x517a7ed; constexpr uint32_t kSimulatedExceptionCode = 0x517a7ed;
EXCEPTION_RECORD record = {}; EXCEPTION_RECORD record = {};
record.ExceptionCode = kSimulatedExceptionCode; record.ExceptionCode = kSimulatedExceptionCode;
#if defined(ARCH_CPU_64_BITS) record.ExceptionAddress = ProgramCounterFromCONTEXT(&context);
record.ExceptionAddress = reinterpret_cast<void*>(context.Rip);
#else
record.ExceptionAddress = reinterpret_cast<void*>(context.Eip);
#endif // ARCH_CPU_64_BITS
exception_pointers.ExceptionRecord = &record; exception_pointers.ExceptionRecord = &record;

View File

@ -126,7 +126,13 @@ void CommonInitializeX86Context(const T& context, CPUContextX86* out) {
} // namespace } // namespace
#if defined(ARCH_CPU_64_BITS) #if defined(ARCH_CPU_X86)
void InitializeX86Context(const CONTEXT& context, CPUContextX86* out) {
CommonInitializeX86Context(context, out);
}
#elif defined(ARCH_CPU_X86_64)
void InitializeX86Context(const WOW64_CONTEXT& context, CPUContextX86* out) { void InitializeX86Context(const WOW64_CONTEXT& context, CPUContextX86* out) {
CommonInitializeX86Context(context, out); CommonInitializeX86Context(context, out);
@ -192,12 +198,36 @@ void InitializeX64Context(const CONTEXT& context, CPUContextX86_64* out) {
} }
} }
#else // ARCH_CPU_64_BITS #elif defined(ARCH_CPU_ARM64)
void InitializeX86Context(const CONTEXT& context, CPUContextX86* out) { void InitializeARM64Context(const CONTEXT& context, CPUContextARM64* out) {
CommonInitializeX86Context(context, out); memset(out, 0, sizeof(*out));
LOG_IF(ERROR, !HasContextPart(context, CONTEXT_ARM64)) << "non-arm64 context";
if (HasContextPart(context, CONTEXT_CONTROL)) {
out->spsr = context.Cpsr;
out->pc = context.Pc;
out->regs[30] = context.Lr;
out->sp = context.Sp;
out->regs[29] = context.Fp;
} }
#endif // ARCH_CPU_64_BITS if (HasContextPart(context, CONTEXT_INTEGER)) {
memcpy(&out->regs[0], &context.X0, 18 * sizeof(context.X0));
// Don't copy x18 which is reserved as platform register.
memcpy(&out->regs[19], &context.X19, 10 * sizeof(context.X0));
}
if (HasContextPart(context, CONTEXT_FLOATING_POINT)) {
static_assert(sizeof(out->fpsimd) == sizeof(context.V),
"types must be equivalent");
memcpy(&out->fpsimd, &context.V, sizeof(out->fpsimd));
}
}
#else
#error Unsupported Windows Arch
#endif // ARCH_CPU_X86
} // namespace crashpad } // namespace crashpad

View File

@ -23,8 +23,17 @@ namespace crashpad {
struct CPUContextX86; struct CPUContextX86;
struct CPUContextX86_64; struct CPUContextX86_64;
struct CPUContextARM64;
#if defined(ARCH_CPU_64_BITS) || DOXYGEN #if defined(ARCH_CPU_X86) || DOXYGEN
//! \brief Initializes a CPUContextX86 structure from a native context structure
//! on Windows.
void InitializeX86Context(const CONTEXT& context, CPUContextX86* out);
#endif // ARCH_CPU_X86
#if defined(ARCH_CPU_X86_64) || DOXYGEN
//! \brief Initializes a CPUContextX86 structure from a native context structure //! \brief Initializes a CPUContextX86 structure from a native context structure
//! on Windows. //! on Windows.
@ -34,13 +43,15 @@ void InitializeX86Context(const WOW64_CONTEXT& context, CPUContextX86* out);
//! structure on Windows. //! structure on Windows.
void InitializeX64Context(const CONTEXT& context, CPUContextX86_64* out); void InitializeX64Context(const CONTEXT& context, CPUContextX86_64* out);
#else // ARCH_CPU_64_BITS #endif // ARCH_CPU_X86_64
//! \brief Initializes a CPUContextX86 structure from a native context structure #if defined(ARCH_CPU_ARM64) || DOXYGEN
//! on Windows.
void InitializeX86Context(const CONTEXT& context, CPUContextX86* out);
#endif // ARCH_CPU_64_BITS //! \brief Initializes a CPUContextARM64 structure from a native context
//! structure on Windows.
void InitializeARM64Context(const CONTEXT& context, CPUContextARM64* out);
#endif // ARCH_CPU_ARM64
} // namespace crashpad } // namespace crashpad

View File

@ -16,10 +16,10 @@
#include <windows.h> #include <windows.h>
#include "base/logging.h" #include "base/logging.h"
#include "build/build_config.h"
#include "client/crashpad_client.h" #include "client/crashpad_client.h"
#include "util/misc/capture_context.h" #include "util/misc/capture_context.h"
#include "util/win/address_types.h" #include "util/win/address_types.h"
#include "util/win/context_wrappers.h"
int wmain(int argc, wchar_t* argv[]) { int wmain(int argc, wchar_t* argv[]) {
CHECK_EQ(argc, 2); CHECK_EQ(argc, 2);
@ -32,11 +32,9 @@ int wmain(int argc, wchar_t* argv[]) {
CONTEXT context; CONTEXT context;
crashpad::CaptureContext(&context); crashpad::CaptureContext(&context);
#if defined(ARCH_CPU_64_BITS) crashpad::WinVMAddress break_address =
crashpad::WinVMAddress break_address = context.Rip; reinterpret_cast<crashpad::WinVMAddress>(
#else crashpad::ProgramCounterFromCONTEXT(&context));
crashpad::WinVMAddress break_address = context.Eip;
#endif
// This does not used CheckedWriteFile() because at high optimization // This does not used CheckedWriteFile() because at high optimization
// settings, a lot of logging code can be inlined, causing there to be a large // settings, a lot of logging code can be inlined, causing there to be a large

View File

@ -20,6 +20,7 @@
#include "client/simulate_crash.h" #include "client/simulate_crash.h"
#include "util/misc/capture_context.h" #include "util/misc/capture_context.h"
#include "util/win/address_types.h" #include "util/win/address_types.h"
#include "util/win/context_wrappers.h"
int wmain(int argc, wchar_t* argv[]) { int wmain(int argc, wchar_t* argv[]) {
CHECK_EQ(argc, 2); CHECK_EQ(argc, 2);
@ -32,11 +33,9 @@ int wmain(int argc, wchar_t* argv[]) {
CONTEXT context; CONTEXT context;
crashpad::CaptureContext(&context); crashpad::CaptureContext(&context);
#if defined(ARCH_CPU_64_BITS) crashpad::WinVMAddress break_address =
crashpad::WinVMAddress break_address = context.Rip; reinterpret_cast<crashpad::WinVMAddress>(
#else crashpad::ProgramCounterFromCONTEXT(&context));
crashpad::WinVMAddress break_address = context.Eip;
#endif
// This does not used CheckedWriteFile() because at high optimization // This does not used CheckedWriteFile() because at high optimization
// settings, a lot of logging code can be inlined, causing there to be a large // settings, a lot of logging code can be inlined, causing there to be a large

View File

@ -28,22 +28,13 @@ namespace internal {
namespace { namespace {
#if defined(ARCH_CPU_X86_FAMILY)
#if defined(ARCH_CPU_32_BITS) #if defined(ARCH_CPU_32_BITS)
using Context32 = CONTEXT; using Context32 = CONTEXT;
#elif defined(ARCH_CPU_64_BITS) #elif defined(ARCH_CPU_64_BITS)
using Context32 = WOW64_CONTEXT; using Context32 = WOW64_CONTEXT;
#endif #endif
#if defined(ARCH_CPU_64_BITS)
void NativeContextToCPUContext64(const CONTEXT& context_record,
CPUContext* context,
CPUContextUnion* context_union) {
context->architecture = kCPUArchitectureX86_64;
context->x86_64 = &context_union->x86_64;
InitializeX64Context(context_record, context->x86_64);
}
#endif
void NativeContextToCPUContext32(const Context32& context_record, void NativeContextToCPUContext32(const Context32& context_record,
CPUContext* context, CPUContext* context,
CPUContextUnion* context_union) { CPUContextUnion* context_union) {
@ -51,6 +42,25 @@ void NativeContextToCPUContext32(const Context32& context_record,
context->x86 = &context_union->x86; context->x86 = &context_union->x86;
InitializeX86Context(context_record, context->x86); InitializeX86Context(context_record, context->x86);
} }
#endif // ARCH_CPU_X86_FAMILY
#if defined(ARCH_CPU_64_BITS)
void NativeContextToCPUContext64(const CONTEXT& context_record,
CPUContext* context,
CPUContextUnion* context_union) {
#if defined(ARCH_CPU_X86_64)
context->architecture = kCPUArchitectureX86_64;
context->x86_64 = &context_union->x86_64;
InitializeX64Context(context_record, context->x86_64);
#elif defined(ARCH_CPU_ARM64)
context->architecture = kCPUArchitectureARM64;
context->arm64 = &context_union->arm64;
InitializeARM64Context(context_record, context->arm64);
#else
#error Unsupported Windows 64-bit Arch
#endif
}
#endif
} // namespace } // namespace
@ -106,6 +116,8 @@ bool ExceptionSnapshotWin::Initialize(
} }
} }
#endif #endif
#if !defined(ARCH_CPU_ARM64)
if (!is_64_bit) { if (!is_64_bit) {
if (!InitializeFromExceptionPointers<EXCEPTION_RECORD32, if (!InitializeFromExceptionPointers<EXCEPTION_RECORD32,
process_types::EXCEPTION_POINTERS32>( process_types::EXCEPTION_POINTERS32>(
@ -116,6 +128,7 @@ bool ExceptionSnapshotWin::Initialize(
return false; return false;
} }
} }
#endif
CaptureMemoryDelegateWin capture_memory_delegate( CaptureMemoryDelegateWin capture_memory_delegate(
process_reader, *thread, &extra_memory_, nullptr); process_reader, *thread, &extra_memory_, nullptr);

View File

@ -38,12 +38,14 @@ namespace internal {
class MemorySnapshotWin; class MemorySnapshotWin;
#if defined(ARCH_CPU_X86_FAMILY)
union CPUContextUnion { union CPUContextUnion {
#if defined(ARCH_CPU_X86_FAMILY)
CPUContextX86 x86; CPUContextX86 x86;
CPUContextX86_64 x86_64; CPUContextX86_64 x86_64;
}; #elif defined(ARCH_CPU_ARM64)
CPUContextARM64 arm64;
#endif #endif
};
class ExceptionSnapshotWin final : public ExceptionSnapshot { class ExceptionSnapshotWin final : public ExceptionSnapshot {
public: public:
@ -91,9 +93,7 @@ class ExceptionSnapshotWin final : public ExceptionSnapshot {
CPUContext* context, CPUContext* context,
CPUContextUnion* context_union)); CPUContextUnion* context_union));
#if defined(ARCH_CPU_X86_FAMILY)
CPUContextUnion context_union_; CPUContextUnion context_union_;
#endif
CPUContext context_; CPUContext context_;
std::vector<uint64_t> codes_; std::vector<uint64_t> codes_;
std::vector<std::unique_ptr<internal::MemorySnapshotWin>> extra_memory_; std::vector<std::unique_ptr<internal::MemorySnapshotWin>> extra_memory_;

View File

@ -22,6 +22,7 @@
#include "util/misc/from_pointer_cast.h" #include "util/misc/from_pointer_cast.h"
#include "util/synchronization/semaphore.h" #include "util/synchronization/semaphore.h"
#include "util/thread/thread.h" #include "util/thread/thread.h"
#include "util/win/context_wrappers.h"
#include "util/win/scoped_process_suspend.h" #include "util/win/scoped_process_suspend.h"
namespace crashpad { namespace crashpad {
@ -106,12 +107,7 @@ TEST(ProcessReaderWin, SelfOneThread) {
ASSERT_GE(threads.size(), 1u); ASSERT_GE(threads.size(), 1u);
EXPECT_EQ(threads[0].id, GetCurrentThreadId()); EXPECT_EQ(threads[0].id, GetCurrentThreadId());
#if defined(ARCH_CPU_64_BITS) EXPECT_NE(ProgramCounterFromCONTEXT(&threads[0].context.native), nullptr);
EXPECT_NE(threads[0].context.native.Rip, 0u);
#else
EXPECT_NE(threads[0].context.native.Eip, 0u);
#endif
EXPECT_EQ(threads[0].suspend_count, 0u); EXPECT_EQ(threads[0].suspend_count, 0u);
} }

View File

@ -23,6 +23,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/numerics/safe_conversions.h" #include "base/numerics/safe_conversions.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "util/misc/from_pointer_cast.h" #include "util/misc/from_pointer_cast.h"
#include "util/misc/time.h" #include "util/misc/time.h"
#include "util/win/nt_internals.h" #include "util/win/nt_internals.h"
@ -276,7 +277,7 @@ void ProcessSnapshotWin::InitializeUnloadedModules() {
// and 32-reading-32, so at the moment, we simply do not retrieve unloaded // and 32-reading-32, so at the moment, we simply do not retrieve unloaded
// modules for 64-reading-32. See https://crashpad.chromium.org/bug/89. // modules for 64-reading-32. See https://crashpad.chromium.org/bug/89.
#if defined(ARCH_CPU_X86_64) #if defined(ARCH_CPU_X86_64) || defined(ARCH_CPU_ARM64)
if (!process_reader_.Is64Bit()) { if (!process_reader_.Is64Bit()) {
LOG(ERROR) LOG(ERROR)
<< "reading unloaded modules across bitness not currently supported"; << "reading unloaded modules across bitness not currently supported";

View File

@ -26,6 +26,7 @@
#include "base/numerics/safe_conversions.h" #include "base/numerics/safe_conversions.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "util/win/module_version.h" #include "util/win/module_version.h"
namespace crashpad { namespace crashpad {
@ -125,13 +126,20 @@ void SystemSnapshotWin::Initialize(ProcessReaderWin* process_reader) {
CPUArchitecture SystemSnapshotWin::GetCPUArchitecture() const { CPUArchitecture SystemSnapshotWin::GetCPUArchitecture() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_); INITIALIZATION_STATE_DCHECK_VALID(initialized_);
#if defined(ARCH_CPU_X86_FAMILY)
return process_reader_->Is64Bit() ? kCPUArchitectureX86_64 return process_reader_->Is64Bit() ? kCPUArchitectureX86_64
: kCPUArchitectureX86; : kCPUArchitectureX86;
#elif defined(ARCH_CPU_ARM64)
return kCPUArchitectureARM64;
#else
#error Unsupported Windows Arch
#endif
} }
uint32_t SystemSnapshotWin::CPURevision() const { uint32_t SystemSnapshotWin::CPURevision() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_); INITIALIZATION_STATE_DCHECK_VALID(initialized_);
#if defined(ARCH_CPU_X86_FAMILY)
uint32_t raw = CPUX86Signature(); uint32_t raw = CPUX86Signature();
uint8_t stepping = raw & 0xf; uint8_t stepping = raw & 0xf;
uint8_t model = (raw & 0xf0) >> 4; uint8_t model = (raw & 0xf0) >> 4;
@ -149,6 +157,13 @@ uint32_t SystemSnapshotWin::CPURevision() const {
uint16_t adjusted_family = family + extended_family; uint16_t adjusted_family = family + extended_family;
uint8_t adjusted_model = model + (extended_model << 4); uint8_t adjusted_model = model + (extended_model << 4);
return (adjusted_family << 16) | (adjusted_model << 8) | stepping; return (adjusted_family << 16) | (adjusted_model << 8) | stepping;
#elif defined(ARCH_CPU_ARM64)
// TODO(jperaza): do this. https://crashpad.chromium.org/bug/30
// This is the same as SystemSnapshotLinux::CPURevision.
return 0;
#else
#error Unsupported Windows Arch
#endif
} }
uint8_t SystemSnapshotWin::CPUCount() const { uint8_t SystemSnapshotWin::CPUCount() const {
@ -166,6 +181,7 @@ uint8_t SystemSnapshotWin::CPUCount() const {
std::string SystemSnapshotWin::CPUVendor() const { std::string SystemSnapshotWin::CPUVendor() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_); INITIALIZATION_STATE_DCHECK_VALID(initialized_);
#if defined(ARCH_CPU_X86_FAMILY)
int cpu_info[4]; int cpu_info[4];
__cpuid(cpu_info, 0); __cpuid(cpu_info, 0);
char vendor[12]; char vendor[12];
@ -173,6 +189,13 @@ std::string SystemSnapshotWin::CPUVendor() const {
*reinterpret_cast<int*>(vendor + 4) = cpu_info[3]; *reinterpret_cast<int*>(vendor + 4) = cpu_info[3];
*reinterpret_cast<int*>(vendor + 8) = cpu_info[2]; *reinterpret_cast<int*>(vendor + 8) = cpu_info[2];
return std::string(vendor, sizeof(vendor)); return std::string(vendor, sizeof(vendor));
#elif defined(ARCH_CPU_ARM64)
// TODO(jperaza): do this. https://crashpad.chromium.org/bug/30
// This is the same as SystemSnapshotLinux::CPURevision.
return std::string();
#else
#error Unsupported Windows Arch
#endif
} }
void SystemSnapshotWin::CPUFrequency(uint64_t* current_hz, void SystemSnapshotWin::CPUFrequency(uint64_t* current_hz,
@ -212,36 +235,52 @@ void SystemSnapshotWin::CPUFrequency(uint64_t* current_hz,
uint32_t SystemSnapshotWin::CPUX86Signature() const { uint32_t SystemSnapshotWin::CPUX86Signature() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_); INITIALIZATION_STATE_DCHECK_VALID(initialized_);
#if defined(ARCH_CPU_X86_FAMILY)
int cpu_info[4]; int cpu_info[4];
// We will never run on any processors that don't support at least function 1. // We will never run on any processors that don't support at least function 1.
__cpuid(cpu_info, 1); __cpuid(cpu_info, 1);
return cpu_info[0]; return cpu_info[0];
#else
NOTREACHED();
return 0;
#endif
} }
uint64_t SystemSnapshotWin::CPUX86Features() const { uint64_t SystemSnapshotWin::CPUX86Features() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_); INITIALIZATION_STATE_DCHECK_VALID(initialized_);
#if defined(ARCH_CPU_X86_FAMILY)
int cpu_info[4]; int cpu_info[4];
// We will never run on any processors that don't support at least function 1. // We will never run on any processors that don't support at least function 1.
__cpuid(cpu_info, 1); __cpuid(cpu_info, 1);
return (static_cast<uint64_t>(cpu_info[2]) << 32) | return (static_cast<uint64_t>(cpu_info[2]) << 32) |
static_cast<uint64_t>(cpu_info[3]); static_cast<uint64_t>(cpu_info[3]);
#else
NOTREACHED();
return 0;
#endif
} }
uint64_t SystemSnapshotWin::CPUX86ExtendedFeatures() const { uint64_t SystemSnapshotWin::CPUX86ExtendedFeatures() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_); INITIALIZATION_STATE_DCHECK_VALID(initialized_);
#if defined(ARCH_CPU_X86_FAMILY)
int cpu_info[4]; int cpu_info[4];
// We will never run on any processors that don't support at least extended // We will never run on any processors that don't support at least extended
// function 1. // function 1.
__cpuid(cpu_info, 0x80000001); __cpuid(cpu_info, 0x80000001);
return (static_cast<uint64_t>(cpu_info[2]) << 32) | return (static_cast<uint64_t>(cpu_info[2]) << 32) |
static_cast<uint64_t>(cpu_info[3]); static_cast<uint64_t>(cpu_info[3]);
#else
NOTREACHED();
return 0;
#endif
} }
uint32_t SystemSnapshotWin::CPUX86Leaf7Features() const { uint32_t SystemSnapshotWin::CPUX86Leaf7Features() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_); INITIALIZATION_STATE_DCHECK_VALID(initialized_);
#if defined(ARCH_CPU_X86_FAMILY)
int cpu_info[4]; int cpu_info[4];
// Make sure leaf 7 can be called. // Make sure leaf 7 can be called.
@ -251,11 +290,16 @@ uint32_t SystemSnapshotWin::CPUX86Leaf7Features() const {
__cpuidex(cpu_info, 7, 0); __cpuidex(cpu_info, 7, 0);
return cpu_info[1]; return cpu_info[1];
#else
NOTREACHED();
return 0;
#endif
} }
bool SystemSnapshotWin::CPUX86SupportsDAZ() const { bool SystemSnapshotWin::CPUX86SupportsDAZ() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_); INITIALIZATION_STATE_DCHECK_VALID(initialized_);
#if defined(ARCH_CPU_X86_FAMILY)
// The correct way to check for denormals-as-zeros (DAZ) support is to examine // The correct way to check for denormals-as-zeros (DAZ) support is to examine
// mxcsr mask, which can be done with fxsave. See Intel Software Developer's // mxcsr mask, which can be done with fxsave. See Intel Software Developer's
// Manual, Volume 1: Basic Architecture (253665-051), 11.6.3 "Checking for the // Manual, Volume 1: Basic Architecture (253665-051), 11.6.3 "Checking for the
@ -277,6 +321,10 @@ bool SystemSnapshotWin::CPUX86SupportsDAZ() const {
// Test the DAZ bit. // Test the DAZ bit.
return (mxcsr_mask & (1 << 6)) != 0; return (mxcsr_mask & (1 << 6)) != 0;
#else
NOTREACHED();
return 0;
#endif
} }
SystemSnapshot::OperatingSystem SystemSnapshotWin::GetOperatingSystem() const { SystemSnapshot::OperatingSystem SystemSnapshotWin::GetOperatingSystem() const {

View File

@ -60,6 +60,10 @@ TEST_F(SystemSnapshotWinTest, GetCPUArchitecture) {
EXPECT_EQ(cpu_architecture, kCPUArchitectureX86); EXPECT_EQ(cpu_architecture, kCPUArchitectureX86);
#elif defined(ARCH_CPU_X86_64) #elif defined(ARCH_CPU_X86_64)
EXPECT_EQ(cpu_architecture, kCPUArchitectureX86_64); EXPECT_EQ(cpu_architecture, kCPUArchitectureX86_64);
#elif defined(ARCH_CPU_ARM64)
EXPECT_EQ(cpu_architecture, kCPUArchitectureARM64);
#else
#error Unsupported Windows Arch
#endif #endif
} }

View File

@ -63,7 +63,11 @@ bool ThreadSnapshotWin::Initialize(
teb_.Initialize(process_reader, 0, 0); teb_.Initialize(process_reader, 0, 0);
} }
#if defined(ARCH_CPU_X86_64) #if defined(ARCH_CPU_X86)
context_.architecture = kCPUArchitectureX86;
context_.x86 = &context_union_.x86;
InitializeX86Context(process_reader_thread.context.native, context_.x86);
#elif defined(ARCH_CPU_X86_64)
if (process_reader->Is64Bit()) { if (process_reader->Is64Bit()) {
context_.architecture = kCPUArchitectureX86_64; context_.architecture = kCPUArchitectureX86_64;
context_.x86_64 = &context_union_.x86_64; context_.x86_64 = &context_union_.x86_64;
@ -73,11 +77,13 @@ bool ThreadSnapshotWin::Initialize(
context_.x86 = &context_union_.x86; context_.x86 = &context_union_.x86;
InitializeX86Context(process_reader_thread.context.wow64, context_.x86); InitializeX86Context(process_reader_thread.context.wow64, context_.x86);
} }
#elif defined(ARCH_CPU_ARM64)
context_.architecture = kCPUArchitectureARM64;
context_.arm64 = &context_union_.arm64;
InitializeARM64Context(process_reader_thread.context.native, context_.arm64);
#else #else
context_.architecture = kCPUArchitectureX86; #error Unsupported Windows Arch
context_.x86 = &context_union_.x86; #endif // ARCH_CPU_X86
InitializeX86Context(process_reader_thread.context.native, context_.x86);
#endif // ARCH_CPU_X86_64
CaptureMemoryDelegateWin capture_memory_delegate( CaptureMemoryDelegateWin capture_memory_delegate(
process_reader, process_reader,

View File

@ -71,12 +71,16 @@ class ThreadSnapshotWin final : public ThreadSnapshot {
std::vector<const MemorySnapshot*> ExtraMemory() const override; std::vector<const MemorySnapshot*> ExtraMemory() const override;
private: private:
#if defined(ARCH_CPU_X86_FAMILY)
union { union {
#if defined(ARCH_CPU_X86_FAMILY)
CPUContextX86 x86; CPUContextX86 x86;
CPUContextX86_64 x86_64; CPUContextX86_64 x86_64;
} context_union_; #elif defined(ARCH_CPU_ARM64)
CPUContextARM64 arm64;
#else
#error Unsupported Windows Arch
#endif #endif
} context_union_;
CPUContext context_; CPUContext context_;
MemorySnapshotWin stack_; MemorySnapshotWin stack_;
MemorySnapshotWin teb_; MemorySnapshotWin teb_;

View File

@ -91,6 +91,12 @@ if (zlib_source == "external") {
"/wd4324", # structure was padded due to alignment specifier "/wd4324", # structure was padded due to alignment specifier
"/wd4702", # unreachable code "/wd4702", # unreachable code
] ]
if (current_cpu == "arm64" && !crashpad_is_clang) {
# Select code path for clang in zlib to avoid using MSVC x86/x64
# intrinsics for Windows ARM64.
# TODO: https://crashpad.chromium.org/bug/267
defines += [ "__clang__" ]
}
} else { } else {
defines += [ defines += [
"HAVE_HIDDEN", "HAVE_HIDDEN",

View File

@ -341,6 +341,7 @@ static_library("util") {
"win/checked_win_address_range.h", "win/checked_win_address_range.h",
"win/command_line.cc", "win/command_line.cc",
"win/command_line.h", "win/command_line.h",
"win/context_wrappers.h",
"win/critical_section_with_debug_info.cc", "win/critical_section_with_debug_info.cc",
"win/critical_section_with_debug_info.h", "win/critical_section_with_debug_info.h",
"win/exception_handler_server.cc", "win/exception_handler_server.cc",
@ -390,10 +391,15 @@ static_library("util") {
# TODO(thakis): Use the .asm file in cross builds somehow, # TODO(thakis): Use the .asm file in cross builds somehow,
# https://crbug.com/762167. # https://crbug.com/762167.
if (host_os == "win") { if (host_os == "win") {
if (current_cpu != "arm64") {
sources += [ sources += [
"misc/capture_context_win.asm", "misc/capture_context_win.asm",
"win/safe_terminate_process.asm", "win/safe_terminate_process.asm",
] ]
} else {
# TODO: Add assembly code of CaptureContext for Windows ARM64.
sources += [ "misc/capture_context_broken.cc" ]
}
} else { } else {
sources += [ sources += [
"misc/capture_context_broken.cc", "misc/capture_context_broken.cc",

View File

@ -13,6 +13,7 @@
// limitations under the License. // limitations under the License.
#include "util/misc/capture_context_test_util.h" #include "util/misc/capture_context_test_util.h"
#include "util/win/context_wrappers.h"
#include "base/macros.h" #include "base/macros.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
@ -95,11 +96,7 @@ void SanityCheckContext(const NativeCPUContext& context) {
} }
uintptr_t ProgramCounterFromContext(const NativeCPUContext& context) { uintptr_t ProgramCounterFromContext(const NativeCPUContext& context) {
#if defined(ARCH_CPU_X86) return reinterpret_cast<uintptr_t>(ProgramCounterFromCONTEXT(&context));
return context.Eip;
#elif defined(ARCH_CPU_X86_64)
return context.Rip;
#endif
} }
uintptr_t StackPointerFromContext(const NativeCPUContext& context) { uintptr_t StackPointerFromContext(const NativeCPUContext& context) {
@ -107,6 +104,8 @@ uintptr_t StackPointerFromContext(const NativeCPUContext& context) {
return context.Esp; return context.Esp;
#elif defined(ARCH_CPU_X86_64) #elif defined(ARCH_CPU_X86_64)
return context.Rsp; return context.Rsp;
#elif defined(ARCH_CPU_ARM64)
return context.Sp;
#endif #endif
} }

View File

@ -65,6 +65,8 @@ std::string UserAgent() {
user_agent.append("x86"); user_agent.append("x86");
#elif defined(ARCH_CPU_X86_64) #elif defined(ARCH_CPU_X86_64)
user_agent.append("x64"); user_agent.append("x64");
#elif defined(ARCH_CPU_ARM64)
user_agent.append("arm64");
#else #else
#error Port #error Port
#endif #endif

View File

@ -246,6 +246,7 @@
'win/checked_win_address_range.h', 'win/checked_win_address_range.h',
'win/command_line.cc', 'win/command_line.cc',
'win/command_line.h', 'win/command_line.h',
'win/context_wrappers.h',
'win/critical_section_with_debug_info.cc', 'win/critical_section_with_debug_info.cc',
'win/critical_section_with_debug_info.h', 'win/critical_section_with_debug_info.h',
'win/exception_handler_server.cc', 'win/exception_handler_server.cc',

View File

@ -0,0 +1,40 @@
// 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_UTIL_WIN_CONTEXT_WRAPPERS_H_
#define CRASHPAD_UTIL_WIN_CONTEXT_WRAPPERS_H_
#include <windows.h>
#include "build/build_config.h"
namespace crashpad {
//! \brief Retrieve program counter from `CONTEXT` structure for different
//! architectures supported by Windows.
inline void* ProgramCounterFromCONTEXT(const CONTEXT* context) {
#if defined(ARCH_CPU_X86)
return reinterpret_cast<void*>(context->Eip);
#elif defined(ARCH_CPU_X86_64)
return reinterpret_cast<void*>(context->Rip);
#elif defined(ARCH_CPU_ARM64)
return reinterpret_cast<void*>(context->Pc);
#else
#error Unsupported Windows Arch
#endif // ARCH_CPU_X86
}
} // namespace crashpad
#endif // CRASHPAD_UTIL_WIN_CONTEXT_WRAPPERS_H_

View File

@ -91,6 +91,8 @@ class ScopedExecutablePatch {
DISALLOW_COPY_AND_ASSIGN(ScopedExecutablePatch); DISALLOW_COPY_AND_ASSIGN(ScopedExecutablePatch);
}; };
// SafeTerminateProcess is calling convention specific only for x86.
#if defined(ARCH_CPU_X86_FAMILY)
TEST(SafeTerminateProcess, PatchBadly) { TEST(SafeTerminateProcess, PatchBadly) {
// This is a test of SafeTerminateProcess(), but it doesnt actually terminate // This is a test of SafeTerminateProcess(), but it doesnt actually terminate
// anything. Instead, it works with a process handle for the current process // anything. Instead, it works with a process handle for the current process
@ -161,6 +163,7 @@ TEST(SafeTerminateProcess, PatchBadly) {
EXPECT_FALSE(SafeTerminateProcess(process, 0)); EXPECT_FALSE(SafeTerminateProcess(process, 0));
EXPECT_EQ(GetLastError(), static_cast<DWORD>(ERROR_ACCESS_DENIED)); EXPECT_EQ(GetLastError(), static_cast<DWORD>(ERROR_ACCESS_DENIED));
} }
#endif // ARCH_CPU_X86_FAMILY
TEST(SafeTerminateProcess, TerminateChild) { TEST(SafeTerminateProcess, TerminateChild) {
base::FilePath child_executable = base::FilePath child_executable =