From db877a13bbb35f8d6b2c645177aee8f3be51800e Mon Sep 17 00:00:00 2001
From: "gordana.cmiljanovic@imgtec.com"
 <gordana.cmiljanovic@imgtec.com@4c0a9323-5329-0410-9bdc-e9ce6186880e>
Date: Wed, 25 Sep 2013 08:18:03 +0000
Subject: Adding mips support for Android.

Mips linux support has been added previously in r1212. Some additional changes
are required to make breakpad functional on Android.

BUG=none
TEST=build, unittests, chrome test application

Review URL: https://breakpad.appspot.com/632002



git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1215 4c0a9323-5329-0410-9bdc-e9ce6186880e
---
 .../linux/handler/exception_handler_unittest.cc    |  7 +-
 .../linux/minidump_writer/minidump_writer.cc       |  4 ++
 src/common/android/breakpad_getcontext.S           | 79 ++++++++++++++++++++++
 src/common/android/breakpad_getcontext_unittest.cc | 13 ++++
 src/common/android/include/sys/ucontext.h          |  1 -
 src/common/android/include/sys/user.h              | 19 +++++-
 src/common/android/ucontext_constants.h            |  7 +-
 src/common/linux/dump_symbols.cc                   |  2 +-
 src/google_breakpad/common/minidump_cpu_mips.h     |  2 +-
 9 files changed, 126 insertions(+), 8 deletions(-)

(limited to 'src')

diff --git a/src/client/linux/handler/exception_handler_unittest.cc b/src/client/linux/handler/exception_handler_unittest.cc
index 702a3adb..cfd50bb3 100644
--- a/src/client/linux/handler/exception_handler_unittest.cc
+++ b/src/client/linux/handler/exception_handler_unittest.cc
@@ -76,7 +76,12 @@ void FlushInstructionCache(const char* memory, uint32_t memory_size) {
 #   error "Your operating system is not supported yet"
 # endif
 #elif defined(__mips__)
-# if defined(__linux__)
+# if defined(__ANDROID__)
+  // Provided by Android's <unistd.h>
+  long begin = reinterpret_cast<long>(memory);
+  long end = begin + static_cast<long>(memory_size);
+  cacheflush(begin, end, 0);
+# elif defined(__linux__)
   // See http://www.linux-mips.org/wiki/Cacheflush_Syscall.
   cacheflush(const_cast<char*>(memory), memory_size, ICACHE);
 # else
diff --git a/src/client/linux/minidump_writer/minidump_writer.cc b/src/client/linux/minidump_writer/minidump_writer.cc
index 413e0807..ee759274 100644
--- a/src/client/linux/minidump_writer/minidump_writer.cc
+++ b/src/client/linux/minidump_writer/minidump_writer.cc
@@ -429,7 +429,11 @@ static void CPUFillFromUContext(MDRawContextMIPS* out, const ucontext* uc,
   out->cause = 0;  // Not reported in signal context.
 
   for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i)
+#if defined (__ANDROID__)
+    out->float_save.regs[i] = uc->uc_mcontext.fpregs[i];
+#else
     out->float_save.regs[i] = uc->uc_mcontext.fpregs.fp_r.fp_dregs[i];
+#endif
 
   out->float_save.fpcsr = uc->uc_mcontext.fpc_csr;
   out->float_save.fir = uc->uc_mcontext.fpc_eir;  // Unused.
diff --git a/src/common/android/breakpad_getcontext.S b/src/common/android/breakpad_getcontext.S
index 13ccd46b..13f242d8 100644
--- a/src/common/android/breakpad_getcontext.S
+++ b/src/common/android/breakpad_getcontext.S
@@ -140,6 +140,85 @@ breakpad_getcontext:
 
   .size breakpad_getcontext, . - breakpad_getcontext
 
+#elif defined(__mips__)
+
+#if _MIPS_SIM != _ABIO32
+#error "Unsupported mips ISA. Only mips o32 is supported."
+#endif
+
+// This implementation is inspired by implementation of getcontext in glibc.
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/fpregdef.h>
+#include <asm/unistd.h> // for __NR_rt_sigprocmask
+
+#define _NSIG8 128 / 8
+#define SIG_BLOCK 1
+
+
+  .text
+LOCALS_NUM = 2	// save gp and ra on stack
+FRAME_SIZE = ((LOCALS_NUM * SZREG) + ALSZ) & ALMASK
+RA_FRAME_OFFSET = FRAME_SIZE - (1 * SZREG)
+GP_FRAME_OFFSET = FRAME_SIZE - (2 * SZREG)
+MCONTEXT_REG_SIZE = 8
+
+NESTED (breakpad_getcontext, FRAME_SIZE, ra)
+  .mask	0x00000000, 0
+  .fmask 0x00000000, 0
+
+  .set noreorder
+  .cpload t9
+  .set reorder
+
+  move a2, sp
+#define _SP a2
+
+  addiu sp, -FRAME_SIZE
+  sw ra, RA_FRAME_OFFSET(sp)
+  sw gp, GP_FRAME_OFFSET(sp)
+
+  sw s0, (16 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
+  sw s1, (17 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
+  sw s2, (18 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
+  sw s3, (19 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
+  sw s4, (20 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
+  sw s5, (21 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
+  sw s6, (22 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
+  sw s7, (23 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
+  sw _SP, (29 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
+  sw fp, (30 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
+  sw ra, (31 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
+  sw ra, MCONTEXT_PC_OFFSET(a0)
+
+#ifdef __mips_hard_float
+  s.d fs0, (20 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
+  s.d fs1, (22 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
+  s.d fs2, (24 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
+  s.d fs3, (26 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
+  s.d fs4, (28 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
+  s.d fs5, (30 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
+
+  cfc1 v1, fcr31
+  sw v1, MCONTEXT_FPC_CSR(a0)
+#endif  // __mips_hard_float
+
+  /* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */
+  li a3, _NSIG8
+  addu a2, a0, UCONTEXT_SIGMASK_OFFSET
+  move a1, zero
+  li a0, SIG_BLOCK
+  li v0, __NR_rt_sigprocmask
+  syscall
+
+  lw ra, RA_FRAME_OFFSET(sp)
+  lw gp, GP_FRAME_OFFSET(sp)
+  addiu sp, FRAME_SIZE
+  jr ra
+
+END (breakpad_getcontext)
+
+
 #else
 #error "This file has not been ported for your CPU!"
 #endif
diff --git a/src/common/android/breakpad_getcontext_unittest.cc b/src/common/android/breakpad_getcontext_unittest.cc
index 3bafb9a6..c1b69c25 100644
--- a/src/common/android/breakpad_getcontext_unittest.cc
+++ b/src/common/android/breakpad_getcontext_unittest.cc
@@ -69,6 +69,19 @@ TEST(AndroidUContext, GRegsOffset) {
 
   ASSERT_EQ(static_cast<size_t>(UCONTEXT_FPREGS_MEM_OFFSET),
             offsetof(ucontext_t,__fpregs_mem));
+#elif defined(__mips__)
+  ASSERT_EQ(static_cast<size_t>(MCONTEXT_GREGS_OFFSET),
+            offsetof(ucontext_t,uc_mcontext.gregs));
+
+  // PC for mips is not part of gregs.
+  ASSERT_EQ(static_cast<size_t>(MCONTEXT_PC_OFFSET),
+            offsetof(ucontext_t,uc_mcontext.pc));
+
+  ASSERT_EQ(static_cast<size_t>(MCONTEXT_FPREGS_OFFSET),
+            offsetof(ucontext_t,uc_mcontext.fpregs));
+
+  ASSERT_EQ(static_cast<size_t>(MCONTEXT_FPC_CSR),
+            offsetof(ucontext_t,uc_mcontext.fpc_csr));
 #else
   ASSERT_EQ(static_cast<size_t>(MCONTEXT_GREGS_OFFSET),
             offsetof(ucontext_t,uc_mcontext.gregs));
diff --git a/src/common/android/include/sys/ucontext.h b/src/common/android/include/sys/ucontext.h
index 4a4e77c1..85c69ebd 100644
--- a/src/common/android/include/sys/ucontext.h
+++ b/src/common/android/include/sys/ucontext.h
@@ -128,7 +128,6 @@ typedef struct ucontext {
 
 #elif defined(__mips__)
 
-// Not supported by Google Breakpad at this point, but just in case.
 typedef struct {
   uint32_t regmask;
   uint32_t status;
diff --git a/src/common/android/include/sys/user.h b/src/common/android/include/sys/user.h
index d13e5f6e..bc275bbe 100644
--- a/src/common/android/include/sys/user.h
+++ b/src/common/android/include/sys/user.h
@@ -120,8 +120,23 @@ struct user {
 
 #elif defined(__mips__)
 
-// TODO: Provide some useful definitions here, once the rest of Breakpad
-//        requires them.
+#define _ASM_USER_H 1  // Prevent <asm/user.h> conflicts
+
+struct user_regs_struct {
+  unsigned long long regs[32];
+  unsigned long long lo;
+  unsigned long long hi;
+  unsigned long long epc;
+  unsigned long long badvaddr;
+  unsigned long long status;
+  unsigned long long cause;
+};
+
+struct user_fpregs_struct {
+  unsigned long long regs[32];
+  unsigned int fpcsr;
+  unsigned int fir;
+};
 
 #else
 #  error "Unsupported Android CPU ABI"
diff --git a/src/common/android/ucontext_constants.h b/src/common/android/ucontext_constants.h
index 9c7a6971..c99c51fa 100644
--- a/src/common/android/ucontext_constants.h
+++ b/src/common/android/ucontext_constants.h
@@ -75,8 +75,11 @@
 
 #elif defined(__mips__)
 
-#define  MCONTEXT_GREGS_OFFSET     0
-#define  UCONTEXT_SIGMASK_OFFSET   0
+#define  MCONTEXT_PC_OFFSET        32
+#define  MCONTEXT_GREGS_OFFSET     40
+#define  MCONTEXT_FPREGS_OFFSET    296
+#define  MCONTEXT_FPC_CSR          556
+#define  UCONTEXT_SIGMASK_OFFSET   616
 
 #else
 #error "This header has not been ported for your CPU"
diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc
index 1f58d10f..75dcfd4c 100644
--- a/src/common/linux/dump_symbols.cc
+++ b/src/common/linux/dump_symbols.cc
@@ -617,7 +617,7 @@ bool LoadSymbols(const string& obj_file,
     // Linux C++ exception handling information can also provide
     // unwinding data.
     const Shdr* eh_frame_section =
-        FindElfSectionByName<ElfClass>(".eh_frame", debug_section_type,
+        FindElfSectionByName<ElfClass>(".eh_frame", SHT_PROGBITS,
                                        sections, names, names_end,
                                        elf_header->e_shnum);
     if (eh_frame_section) {
diff --git a/src/google_breakpad/common/minidump_cpu_mips.h b/src/google_breakpad/common/minidump_cpu_mips.h
index 7a6d0495..4378aac2 100644
--- a/src/google_breakpad/common/minidump_cpu_mips.h
+++ b/src/google_breakpad/common/minidump_cpu_mips.h
@@ -66,7 +66,7 @@
 #ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_MIPS_H__
 #define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_MIPS_H__
 
-#ifdef __mips__
+#if defined(__mips__) && !defined(__ANDROID__)
 typedef struct {
   uint64_t regs[32];
   uint64_t lo;
-- 
cgit v1.2.1