diff --git a/src/client/linux/handler/exception_handler.cc b/src/client/linux/handler/exception_handler.cc index 58fbacbd..9d081ca8 100644 --- a/src/client/linux/handler/exception_handler.cc +++ b/src/client/linux/handler/exception_handler.cc @@ -398,8 +398,8 @@ bool ExceptionHandler::HandleSignal(int sig, siginfo_t* info, void* uc) { CrashContext context; memcpy(&context.siginfo, info, sizeof(siginfo_t)); memcpy(&context.context, uc, sizeof(struct ucontext)); -#if !defined(__ARM_EABI__) && !defined(__mips__) - // FP state is not part of user ABI on ARM Linux. +#if !defined(__ARM_EABI__) && !defined(__aarch64__) && !defined(__mips__) + // FP state is not part of user ABI on ARM or ARM64 Linux. // In case of MIPS Linux FP state is already part of struct ucontext // and 'float_state' is not a member of CrashContext. struct ucontext *uc_ptr = (struct ucontext*)uc; @@ -608,7 +608,7 @@ bool ExceptionHandler::WriteMinidump() { } #endif -#if !defined(__ARM_EABI__) && !defined(__mips__) +#if !defined(__ARM_EABI__) && !defined(__aarch64__) && !defined(__mips__) // FPU state is not part of ARM EABI ucontext_t. memcpy(&context.float_state, context.context.uc_mcontext.fpregs, sizeof(context.float_state)); @@ -627,6 +627,9 @@ bool ExceptionHandler::WriteMinidump() { #elif defined(__arm__) context.siginfo.si_addr = reinterpret_cast(context.context.uc_mcontext.arm_pc); +#elif defined(__aarch64__) + context.siginfo.si_addr = + reinterpret_cast(context.context.uc_mcontext.pc); #elif defined(__mips__) context.siginfo.si_addr = reinterpret_cast(context.context.uc_mcontext.pc); diff --git a/src/client/linux/handler/exception_handler.h b/src/client/linux/handler/exception_handler.h index b57f58d4..2e842d83 100644 --- a/src/client/linux/handler/exception_handler.h +++ b/src/client/linux/handler/exception_handler.h @@ -190,10 +190,10 @@ class ExceptionHandler { siginfo_t siginfo; pid_t tid; // the crashing thread. struct ucontext context; -#if !defined(__ARM_EABI__) && !defined(__mips__) - // #ifdef this out because FP state is not part of user ABI for Linux ARM. - // In case of MIPS Linux FP state is already part of struct ucontext - // so 'float_state' is not required. +#if !defined(__ARM_EABI__) && !defined(__aarch64__) && !defined(__mips__) + // #ifdef this out because FP state is not part of user ABI for Linux ARM + // or ARM64. In case of MIPS Linux FP state is already part of struct + // ucontext so 'float_state' is not required. struct _libc_fpstate float_state; #endif }; @@ -259,7 +259,7 @@ class ExceptionHandler { // We need to explicitly enable ptrace of parent processes on some // kernels, but we need to know the PID of the cloned process before we // can do this. We create a pipe which we can use to block the - // cloned process after creating it, until we have explicitly enabled + // cloned process after creating it, until we have explicitly enabled // ptrace. This is used to store the file descriptors for the pipe int fdes[2]; diff --git a/src/client/linux/minidump_writer/linux_core_dumper.cc b/src/client/linux/minidump_writer/linux_core_dumper.cc index f5b19d10..eb9e3fd0 100644 --- a/src/client/linux/minidump_writer/linux_core_dumper.cc +++ b/src/client/linux/minidump_writer/linux_core_dumper.cc @@ -99,8 +99,10 @@ bool LinuxCoreDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) { memcpy(&stack_pointer, &info->regs.rsp, sizeof(info->regs.rsp)); #elif defined(__ARM_EABI__) memcpy(&stack_pointer, &info->regs.ARM_sp, sizeof(info->regs.ARM_sp)); +#elif defined(__aarch64__) + memcpy(&stack_pointer, &info->regs.sp, sizeof(info->regs.sp)); #elif defined(__mips__) - stack_pointer = + stack_pointer = reinterpret_cast(info->regs.regs[MD_CONTEXT_MIPS_REG_SP]); #else #error "This code hasn't been ported to your platform yet." diff --git a/src/client/linux/minidump_writer/linux_dumper.h b/src/client/linux/minidump_writer/linux_dumper.h index 2bb4cac7..335a2ce9 100644 --- a/src/client/linux/minidump_writer/linux_dumper.h +++ b/src/client/linux/minidump_writer/linux_dumper.h @@ -56,7 +56,7 @@ typedef typeof(((struct user*) 0)->u_debugreg[0]) debugreg_t; // Typedef for our parsing of the auxv variables in /proc/pid/auxv. #if defined(__i386) || defined(__ARM_EABI__) || defined(__mips__) typedef Elf32_auxv_t elf_aux_entry; -#elif defined(__x86_64) +#elif defined(__x86_64) || defined(__aarch64__) typedef Elf64_auxv_t elf_aux_entry; #endif @@ -88,6 +88,10 @@ struct ThreadInfo { // Mimicking how strace does this(see syscall.c, search for GETREGS) struct user_regs regs; struct user_fpregs fpregs; +#elif defined(__aarch64__) + // Use the structures defined in + struct user_pt_regs regs; + struct user_fpsimd_state fpregs; #elif defined(__mips__) user_regs_struct regs; user_fpregs_struct fpregs; diff --git a/src/client/linux/minidump_writer/linux_ptrace_dumper.cc b/src/client/linux/minidump_writer/linux_ptrace_dumper.cc index 8b96037e..5ab59c27 100644 --- a/src/client/linux/minidump_writer/linux_ptrace_dumper.cc +++ b/src/client/linux/minidump_writer/linux_ptrace_dumper.cc @@ -47,6 +47,7 @@ #include #include #include +#include #include #if defined(__i386) @@ -186,6 +187,20 @@ bool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) { if (info->ppid == -1 || info->tgid == -1) return false; +#ifdef PTRACE_GETREGSET + struct iovec io; + io.iov_base = &info->regs; + io.iov_len = sizeof(info->regs); + if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, (void*)&io) == -1) { + return false; + } + + io.iov_base = &info->fpregs; + io.iov_len = sizeof(info->fpregs); + if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_FPREGSET, (void*)&io) == -1) { + return false; + } +#else if (sys_ptrace(PTRACE_GETREGS, tid, NULL, &info->regs) == -1) { return false; } @@ -193,6 +208,7 @@ bool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) { if (sys_ptrace(PTRACE_GETFPREGS, tid, NULL, &info->fpregs) == -1) { return false; } +#endif #if defined(__i386) #if !defined(bit_FXSAVE) // e.g. Clang @@ -241,6 +257,8 @@ bool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) { my_memcpy(&stack_pointer, &info->regs.rsp, sizeof(info->regs.rsp)); #elif defined(__ARM_EABI__) my_memcpy(&stack_pointer, &info->regs.ARM_sp, sizeof(info->regs.ARM_sp)); +#elif defined(__aarch64__) + my_memcpy(&stack_pointer, &info->regs.sp, sizeof(info->regs.sp)); #elif defined(__mips__) stack_pointer = reinterpret_cast(info->regs.regs[MD_CONTEXT_MIPS_REG_SP]); diff --git a/src/client/linux/minidump_writer/minidump_writer.cc b/src/client/linux/minidump_writer/minidump_writer.cc index ee759274..50929f80 100644 --- a/src/client/linux/minidump_writer/minidump_writer.cc +++ b/src/client/linux/minidump_writer/minidump_writer.cc @@ -374,6 +374,19 @@ void CPUFillFromUContext(MDRawContextARM* out, const ucontext* uc, my_memset(&out->float_save.extra, 0, sizeof(out->float_save.extra)); } +#elif defined(__aarch64__) +typedef MDRawContextARM64 RawContextCPU; + +void CPUFillFromThreadInfo(MDRawContextARM64* out, + const google_breakpad::ThreadInfo& info) { + // TODO(rmcilroy): Implement for arm64. +} + +void CPUFillFromUContext(MDRawContextARM64* out, const ucontext* uc, + const struct _libc_fpstate* fpregs) { + // TODO(rmcilroy): Implement for arm64. +} + #elif defined(__mips__) typedef MDRawContextMIPS RawContextCPU; @@ -470,7 +483,7 @@ class MinidumpWriter { : fd_(minidump_fd), path_(minidump_path), ucontext_(context ? &context->context : NULL), -#if !defined(__ARM_EABI__) && !defined(__mips__) +#if !defined(__ARM_EABI__) && !defined(__mips__) && !defined(__aarch64__) float_state_(context ? &context->float_state : NULL), #else // TODO: fix this after fixing ExceptionHandler @@ -1271,6 +1284,18 @@ class MinidumpWriter { uintptr_t GetInstructionPointer(const ThreadInfo& info) { return info.regs.uregs[15]; } +#elif defined(__aarch64__) + uintptr_t GetStackPointer() { + return ucontext_->uc_mcontext.sp; + } + + uintptr_t GetInstructionPointer() { + return ucontext_->uc_mcontext.pc; + } + + uintptr_t GetInstructionPointer(const ThreadInfo& info) { + return info.regs.pc; + } #elif defined(__mips__) uintptr_t GetStackPointer() { return ucontext_->uc_mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]; @@ -1581,6 +1606,11 @@ class MinidumpWriter { return true; } +#elif defined(__aarch64__) + bool WriteCPUInformation(MDRawSystemInfo* sys_info) { + // TODO(rmcilroy): Implement for arm64. + return false; + } #else # error "Unsupported CPU" #endif diff --git a/src/common/android/breakpad_getcontext.S b/src/common/android/breakpad_getcontext.S index 13f242d8..849ffaf6 100644 --- a/src/common/android/breakpad_getcontext.S +++ b/src/common/android/breakpad_getcontext.S @@ -140,6 +140,10 @@ breakpad_getcontext: .size breakpad_getcontext, . - breakpad_getcontext +#elif defined(__aarch64__) + + // TODO(rmcilroy): Implement for arm64. + #elif defined(__mips__) #if _MIPS_SIM != _ABIO32 diff --git a/src/common/android/include/elf.h b/src/common/android/include/elf.h index af50a799..b2a28df4 100644 --- a/src/common/android/include/elf.h +++ b/src/common/android/include/elf.h @@ -38,7 +38,7 @@ extern "C" { #endif // __cplusplus // The Android provides BSD-based definitions for the ElfXX_Nhdr -// types +// types // always source-compatible with the GLibc/kernel ones. To overcome this // issue without modifying a lot of code in Breakpad, use an ugly macro // renaming trick with #include_next @@ -110,9 +110,14 @@ typedef struct { // __WORDSIZE is GLibc-specific and used by Google Breakpad on Linux. -// All Android platforms are 32-bit for now. #ifndef __WORDSIZE +#if defined(__i386__) || defined(__ARM_EABI__) || defined(__mips__) #define __WORDSIZE 32 +#elif defined(__x86_64__) || defined(__aarch64__) +#define __WORDSIZE 64 +#else +#error "Unsupported Android CPU ABI" +#endif #endif // The Android headers don't always define this constant. diff --git a/src/common/android/include/link.h b/src/common/android/include/link.h index 6c4e9411..0f5010c0 100644 --- a/src/common/android/include/link.h +++ b/src/common/android/include/link.h @@ -34,6 +34,10 @@ Provide custom version here. */ #include_next +// TODO(rmcilroy): Remove this file once the ndk is updated for other +// architectures - crbug.com/358831 +#if !defined(__aarch64__) && !defined(__x86_64__) + #ifdef __cplusplus extern "C" { #endif // __cplusplus @@ -61,4 +65,6 @@ struct link_map { } // extern "C" #endif // __cplusplus +#endif // !defined(__aarch64__) && !defined(__x86_64__) + #endif /* GOOGLE_BREAKPAD_ANDROID_INCLUDE_LINK_H */ diff --git a/src/common/android/include/sys/procfs.h b/src/common/android/include/sys/procfs.h index 9cfdd01c..ec65b91c 100644 --- a/src/common/android/include/sys/procfs.h +++ b/src/common/android/include/sys/procfs.h @@ -44,7 +44,7 @@ extern "C" { #endif // __cplusplus -#ifdef __x86_64__ +#if defined(__x86_64__) || defined(__aarch64__) typedef unsigned long long elf_greg_t; #else typedef unsigned long elf_greg_t; @@ -52,6 +52,8 @@ typedef unsigned long elf_greg_t; #ifdef __arm__ #define ELF_NGREG (sizeof(struct user_regs) / sizeof(elf_greg_t)) +#elif defined(__aarch64__) +#define ELF_NGREG (sizeof(struct user_pt_regs) / sizeof(elf_greg_t)) #else #define ELF_NGREG (sizeof(struct user_regs_struct) / sizeof(elf_greg_t)) #endif diff --git a/src/common/android/include/sys/ucontext.h b/src/common/android/include/sys/ucontext.h index 85c69ebd..8bd5877f 100644 --- a/src/common/android/include/sys/ucontext.h +++ b/src/common/android/include/sys/ucontext.h @@ -62,6 +62,19 @@ typedef struct ucontext { // Other fields are not used by Google Breakpad. Don't define them. } ucontext_t; +#elif defined(__aarch64__) + +#include +typedef struct sigcontext mcontext_t; + +typedef struct ucontext { + unsigned long uc_flags; + struct ucontext *uc_link; + stack_t uc_stack; + sigset_t uc_sigmask; + mcontext_t uc_mcontext; +} ucontext_t; + #elif defined(__i386__) /* 80-bit floating-point register */ diff --git a/src/common/android/include/sys/user.h b/src/common/android/include/sys/user.h index bc275bbe..257cd803 100644 --- a/src/common/android/include/sys/user.h +++ b/src/common/android/include/sys/user.h @@ -75,6 +75,11 @@ struct user_vfpregs { unsigned long fpscr; }; +#elif defined(__aarch64__) + +// aarch64 does not have user_regs definitions in , instead +// use the definitions in , which we don't need to redefine here. + #elif defined(__i386__) #define _I386_USER_H 1 // Prevent conflicts diff --git a/src/common/android/ucontext_constants.h b/src/common/android/ucontext_constants.h index c99c51fa..87069517 100644 --- a/src/common/android/ucontext_constants.h +++ b/src/common/android/ucontext_constants.h @@ -45,6 +45,11 @@ #define MCONTEXT_GREGS_OFFSET 32 #define UCONTEXT_SIGMASK_OFFSET 104 +#elif defined(__aarch64__) + +#define MCONTEXT_GREGS_OFFSET 56 +#define UCONTEXT_SIGMASK_OFFSET 40 + #elif defined(__i386__) #define MCONTEXT_GREGS_OFFSET 20 diff --git a/src/common/linux/memory_mapped_file.cc b/src/common/linux/memory_mapped_file.cc index 853cce57..0f0fcb2b 100644 --- a/src/common/linux/memory_mapped_file.cc +++ b/src/common/linux/memory_mapped_file.cc @@ -62,7 +62,7 @@ bool MemoryMappedFile::Map(const char* path) { return false; } -#if defined(__x86_64__) +#if defined(__x86_64__) || defined(__aarch64__) struct kernel_stat st; if (sys_fstat(fd, &st) == -1 || st.st_size < 0) { #else @@ -81,7 +81,7 @@ bool MemoryMappedFile::Map(const char* path) { return true; } -#if defined(__x86_64__) +#if defined(__x86_64__) || defined(__aarch64__) void* data = sys_mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); #else void* data = sys_mmap2(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); diff --git a/src/common/memory.h b/src/common/memory.h index a4636059..a4cad94c 100644 --- a/src/common/memory.h +++ b/src/common/memory.h @@ -110,7 +110,7 @@ class PageAllocator { private: uint8_t *GetNPages(size_t num_pages) { -#ifdef __x86_64 +#if defined(__x86_64__) || defined(__aarch64__) void *a = sys_mmap(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); #else diff --git a/src/third_party/curl/curlbuild.h b/src/third_party/curl/curlbuild.h index 648cf02d..87d0c7bb 100644 --- a/src/third_party/curl/curlbuild.h +++ b/src/third_party/curl/curlbuild.h @@ -154,7 +154,8 @@ #endif /* The size of `long', as computed by sizeof. */ -#if defined(_M_X64) || (defined(__x86_64__) && !defined(__ILP32__)) +#if defined(_M_X64) || (defined(__x86_64__) && !defined(__ILP32__)) || \ + defined(__aarch64__) #define CURL_SIZEOF_LONG 8 #else #define CURL_SIZEOF_LONG 4 @@ -170,7 +171,8 @@ typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; /* Signed integral data type used for curl_off_t. */ -#if defined(_M_X64) || (defined(__x86_64__) && !defined(__ILP32__)) +#if defined(_M_X64) || (defined(__x86_64__) && !defined(__ILP32__)) || \ + defined(__aarch64__) #define CURL_TYPEOF_CURL_OFF_T long #else #define CURL_TYPEOF_CURL_OFF_T int64_t