aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrmcilroy@chromium.org <rmcilroy@chromium.org@4c0a9323-5329-0410-9bdc-e9ce6186880e>2014-04-02 23:12:40 +0000
committerrmcilroy@chromium.org <rmcilroy@chromium.org@4c0a9323-5329-0410-9bdc-e9ce6186880e>2014-04-02 23:12:40 +0000
commit83b9a28cf94979f9b6c33f492a4072766eff3e6e (patch)
treee43731eb28abb4b5d192e20efb9286de01dfe927
parentRemove some unecessary Android system header definitions. (diff)
downloadbreakpad-83b9a28cf94979f9b6c33f492a4072766eff3e6e.tar.xz
First cut at adding arm64 Linux / Android support to Breakpad.
This is an initial attempt to add Arm64 (aarch64) support to Breakpad for Linux / Android platforms. This CL adds the Arm64 data structures, but does not yet implement the Android getcontext support or CPUFillFromThreadInfo / CPUFillFromUContext. BUG=354405,335641 R=mark@chromium.org Review URL: https://breakpad.appspot.com/1354002 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1301 4c0a9323-5329-0410-9bdc-e9ce6186880e
-rw-r--r--src/client/linux/handler/exception_handler.cc9
-rw-r--r--src/client/linux/handler/exception_handler.h10
-rw-r--r--src/client/linux/minidump_writer/linux_core_dumper.cc4
-rw-r--r--src/client/linux/minidump_writer/linux_dumper.h6
-rw-r--r--src/client/linux/minidump_writer/linux_ptrace_dumper.cc18
-rw-r--r--src/client/linux/minidump_writer/minidump_writer.cc32
-rw-r--r--src/common/android/breakpad_getcontext.S4
-rw-r--r--src/common/android/include/elf.h9
-rw-r--r--src/common/android/include/link.h6
-rw-r--r--src/common/android/include/sys/procfs.h4
-rw-r--r--src/common/android/include/sys/ucontext.h13
-rw-r--r--src/common/android/include/sys/user.h5
-rw-r--r--src/common/android/ucontext_constants.h5
-rw-r--r--src/common/linux/memory_mapped_file.cc4
-rw-r--r--src/common/memory.h2
-rw-r--r--src/third_party/curl/curlbuild.h6
16 files changed, 118 insertions, 19 deletions
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<void*>(context.context.uc_mcontext.arm_pc);
+#elif defined(__aarch64__)
+ context.siginfo.si_addr =
+ reinterpret_cast<void*>(context.context.uc_mcontext.pc);
#elif defined(__mips__)
context.siginfo.si_addr =
reinterpret_cast<void*>(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<uint8_t*>(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 <asm/ptrace.h>
+ 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 <stdlib.h>
#include <string.h>
#include <sys/ptrace.h>
+#include <sys/uio.h>
#include <sys/wait.h>
#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<uint8_t*>(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 <elf.h> 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 <link.h>
+// 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 <asm/sigcontext.h>
+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 <asm/user.h>, instead
+// use the definitions in <asm/ptrace.h>, which we don't need to redefine here.
+
#elif defined(__i386__)
#define _I386_USER_H 1 // Prevent <asm/user.h> 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