Add libunwindstack support for Mips and Mips64

This patch requires v3.18 kernel or above, because v3.10 kernel
has a bug (as of 8/1/2017) in the ptrace(GETREGSET) function for mips
and mips64.

Change-Id: I004c1fa190193eebe1c84440b366289122a6bd8a
Signed-off-by: Douglas Leung <douglas.leung@mips.com>
Signed-off-by: Dejan Jovicevic <dejan.jovicevic@mips.com>
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index 00192f1..7491d40 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -145,7 +145,7 @@
   ASSERT_FALSE(elf.Init(false));
 
   ASSERT_EQ("", GetFakeLogBuf());
-  ASSERT_EQ("4 unwind 32 bit elf that is neither arm nor x86: e_machine = 20\n\n",
+  ASSERT_EQ("4 unwind 32 bit elf that is neither arm nor x86 nor mips: e_machine = 20\n\n",
             GetFakeLogPrint());
 }
 
@@ -158,7 +158,7 @@
   ASSERT_FALSE(elf.Init(false));
 
   ASSERT_EQ("", GetFakeLogBuf());
-  ASSERT_EQ("4 unwind 64 bit elf that is neither aarch64 nor x86_64: e_machine = 21\n\n",
+  ASSERT_EQ("4 unwind 64 bit elf that is neither aarch64 nor x86_64 nor mips64: e_machine = 21\n\n",
             GetFakeLogPrint());
 }
 
@@ -174,6 +174,18 @@
   ASSERT_TRUE(elf.interface() != nullptr);
 }
 
+TEST_F(ElfTest, elf_mips) {
+  Elf elf(memory_);
+
+  InitElf32(EM_MIPS);
+
+  ASSERT_TRUE(elf.Init(false));
+  ASSERT_TRUE(elf.valid());
+  ASSERT_EQ(static_cast<uint32_t>(EM_MIPS), elf.machine_type());
+  ASSERT_EQ(ELFCLASS32, elf.class_type());
+  ASSERT_TRUE(elf.interface() != nullptr);
+}
+
 TEST_F(ElfTest, elf_x86) {
   Elf elf(memory_);
 
@@ -210,6 +222,18 @@
   ASSERT_TRUE(elf.interface() != nullptr);
 }
 
+TEST_F(ElfTest, elf_mips64) {
+  Elf elf(memory_);
+
+  InitElf64(EM_MIPS);
+
+  ASSERT_TRUE(elf.Init(false));
+  ASSERT_TRUE(elf.valid());
+  ASSERT_EQ(static_cast<uint32_t>(EM_MIPS), elf.machine_type());
+  ASSERT_EQ(ELFCLASS64, elf.class_type());
+  ASSERT_TRUE(elf.interface() != nullptr);
+}
+
 TEST_F(ElfTest, gnu_debugdata_init_fail32) {
   TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, false,
                                                [&](uint64_t offset, const void* ptr, size_t size) {
diff --git a/libunwindstack/tests/RegsIterateTest.cpp b/libunwindstack/tests/RegsIterateTest.cpp
index 0cb70ba..8b5b31f 100644
--- a/libunwindstack/tests/RegsIterateTest.cpp
+++ b/libunwindstack/tests/RegsIterateTest.cpp
@@ -29,11 +29,15 @@
 #include <unwindstack/RegsArm64.h>
 #include <unwindstack/RegsX86.h>
 #include <unwindstack/RegsX86_64.h>
+#include <unwindstack/RegsMips.h>
+#include <unwindstack/RegsMips64.h>
 
 #include "MachineArm.h"
 #include "MachineArm64.h"
 #include "MachineX86.h"
 #include "MachineX86_64.h"
+#include "MachineMips.h"
+#include "MachineMips64.h"
 
 namespace unwindstack {
 
@@ -152,7 +156,87 @@
   return result;
 }
 
-using RegTypes = ::testing::Types<RegsArm, RegsArm64, RegsX86, RegsX86_64>;
+template<>
+std::vector<Register> ExpectedRegisters<RegsMips>() {
+  std::vector<Register> result;
+  result.push_back({"r0", MIPS_REG_R0});
+  result.push_back({"r1", MIPS_REG_R1});
+  result.push_back({"r2", MIPS_REG_R2});
+  result.push_back({"r3", MIPS_REG_R3});
+  result.push_back({"r4", MIPS_REG_R4});
+  result.push_back({"r5", MIPS_REG_R5});
+  result.push_back({"r6", MIPS_REG_R6});
+  result.push_back({"r7", MIPS_REG_R7});
+  result.push_back({"r8", MIPS_REG_R8});
+  result.push_back({"r9", MIPS_REG_R9});
+  result.push_back({"r10", MIPS_REG_R10});
+  result.push_back({"r11", MIPS_REG_R11});
+  result.push_back({"r12", MIPS_REG_R12});
+  result.push_back({"r13", MIPS_REG_R13});
+  result.push_back({"r14", MIPS_REG_R14});
+  result.push_back({"r15", MIPS_REG_R15});
+  result.push_back({"r16", MIPS_REG_R16});
+  result.push_back({"r17", MIPS_REG_R17});
+  result.push_back({"r18", MIPS_REG_R18});
+  result.push_back({"r19", MIPS_REG_R19});
+  result.push_back({"r20", MIPS_REG_R20});
+  result.push_back({"r21", MIPS_REG_R21});
+  result.push_back({"r22", MIPS_REG_R22});
+  result.push_back({"r23", MIPS_REG_R23});
+  result.push_back({"r24", MIPS_REG_R24});
+  result.push_back({"r25", MIPS_REG_R25});
+  result.push_back({"r26", MIPS_REG_R26});
+  result.push_back({"r27", MIPS_REG_R27});
+  result.push_back({"r28", MIPS_REG_R28});
+  result.push_back({"sp", MIPS_REG_SP});
+  result.push_back({"r30", MIPS_REG_R30});
+  result.push_back({"ra", MIPS_REG_RA});
+  result.push_back({"pc", MIPS_REG_PC});
+
+  return result;
+}
+
+template<>
+std::vector<Register> ExpectedRegisters<RegsMips64>() {
+  std::vector<Register> result;
+  result.push_back({"r0", MIPS64_REG_R0});
+  result.push_back({"r1", MIPS64_REG_R1});
+  result.push_back({"r2", MIPS64_REG_R2});
+  result.push_back({"r3", MIPS64_REG_R3});
+  result.push_back({"r4", MIPS64_REG_R4});
+  result.push_back({"r5", MIPS64_REG_R5});
+  result.push_back({"r6", MIPS64_REG_R6});
+  result.push_back({"r7", MIPS64_REG_R7});
+  result.push_back({"r8", MIPS64_REG_R8});
+  result.push_back({"r9", MIPS64_REG_R9});
+  result.push_back({"r10", MIPS64_REG_R10});
+  result.push_back({"r11", MIPS64_REG_R11});
+  result.push_back({"r12", MIPS64_REG_R12});
+  result.push_back({"r13", MIPS64_REG_R13});
+  result.push_back({"r14", MIPS64_REG_R14});
+  result.push_back({"r15", MIPS64_REG_R15});
+  result.push_back({"r16", MIPS64_REG_R16});
+  result.push_back({"r17", MIPS64_REG_R17});
+  result.push_back({"r18", MIPS64_REG_R18});
+  result.push_back({"r19", MIPS64_REG_R19});
+  result.push_back({"r20", MIPS64_REG_R20});
+  result.push_back({"r21", MIPS64_REG_R21});
+  result.push_back({"r22", MIPS64_REG_R22});
+  result.push_back({"r23", MIPS64_REG_R23});
+  result.push_back({"r24", MIPS64_REG_R24});
+  result.push_back({"r25", MIPS64_REG_R25});
+  result.push_back({"r26", MIPS64_REG_R26});
+  result.push_back({"r27", MIPS64_REG_R27});
+  result.push_back({"r28", MIPS64_REG_R28});
+  result.push_back({"sp", MIPS64_REG_SP});
+  result.push_back({"r30", MIPS64_REG_R30});
+  result.push_back({"ra", MIPS64_REG_RA});
+  result.push_back({"pc", MIPS64_REG_PC});
+
+  return result;
+}
+
+using RegTypes = ::testing::Types<RegsArm, RegsArm64, RegsX86, RegsX86_64, RegsMips, RegsMips64>;
 TYPED_TEST_CASE(RegsIterateTest, RegTypes);
 
 TYPED_TEST(RegsIterateTest, iterate) {
diff --git a/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp b/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
index ae57caf..ef9e61c 100644
--- a/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
+++ b/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
@@ -23,11 +23,15 @@
 #include <unwindstack/RegsArm64.h>
 #include <unwindstack/RegsX86.h>
 #include <unwindstack/RegsX86_64.h>
+#include <unwindstack/RegsMips.h>
+#include <unwindstack/RegsMips64.h>
 
 #include "MachineArm.h"
 #include "MachineArm64.h"
 #include "MachineX86.h"
 #include "MachineX86_64.h"
+#include "MachineMips.h"
+#include "MachineMips64.h"
 
 #include "MemoryFake.h"
 
@@ -204,4 +208,64 @@
   EXPECT_EQ(0x150U, regs.pc());
 }
 
+TEST_F(RegsStepIfSignalHandlerTest, mips_step_if_signal_handler_non_rt) {
+  uint64_t addr = 0x1000;
+  RegsMips regs;
+  regs[MIPS_REG_PC] = 0x8000;
+  regs[MIPS_REG_SP] = addr;
+  regs.SetFromRaw();
+
+  elf_memory_->SetData64(0x8000, 0x0000000c24021017ULL);
+
+  for (uint64_t index = 0; index <= 50; index++) {
+    process_memory_.SetData64(addr + index * 8, index * 0x10);
+  }
+
+  ASSERT_TRUE(regs.StepIfSignalHandler(0x8000, elf_.get(), &process_memory_));
+  EXPECT_EQ(0x220U, regs[MIPS_REG_SP]);
+  EXPECT_EQ(0x040U, regs[MIPS_REG_PC]);
+  EXPECT_EQ(0x220U, regs.sp());
+  EXPECT_EQ(0x040U, regs.pc());
+}
+
+TEST_F(RegsStepIfSignalHandlerTest, mips_step_if_signal_handler_rt) {
+  uint64_t addr = 0x1000;
+  RegsMips regs;
+  regs[MIPS_REG_PC] = 0x8000;
+  regs[MIPS_REG_SP] = addr;
+  regs.SetFromRaw();
+
+  elf_memory_->SetData64(0x8000, 0x0000000c24021061ULL);
+
+  for (uint64_t index = 0; index <= 100; index++) {
+    process_memory_.SetData64(addr + index * 8, index * 0x10);
+  }
+
+  ASSERT_TRUE(regs.StepIfSignalHandler(0x8000, elf_.get(), &process_memory_));
+  EXPECT_EQ(0x350U, regs[MIPS_REG_SP]);
+  EXPECT_EQ(0x170U, regs[MIPS_REG_PC]);
+  EXPECT_EQ(0x350U, regs.sp());
+  EXPECT_EQ(0x170U, regs.pc());
+}
+
+TEST_F(RegsStepIfSignalHandlerTest, mips64_step_if_signal_handler) {
+  uint64_t addr = 0x1000;
+  RegsMips64 regs;
+  regs[MIPS64_REG_PC] = 0x8000;
+  regs[MIPS64_REG_SP] = addr;
+  regs.SetFromRaw();
+
+  elf_memory_->SetData64(0x8000, 0x0000000c2402145bULL);
+
+  for (uint64_t index = 0; index <= 100; index++) {
+    process_memory_.SetData64(addr + index * 8, index * 0x10);
+  }
+
+  ASSERT_TRUE(regs.StepIfSignalHandler(0x8000, elf_.get(), &process_memory_));
+  EXPECT_EQ(0x350U, regs[MIPS64_REG_SP]);
+  EXPECT_EQ(0x600U, regs[MIPS64_REG_PC]);
+  EXPECT_EQ(0x350U, regs.sp());
+  EXPECT_EQ(0x600U, regs.pc());
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp
index a932973..3f84890 100644
--- a/libunwindstack/tests/RegsTest.cpp
+++ b/libunwindstack/tests/RegsTest.cpp
@@ -25,6 +25,8 @@
 #include <unwindstack/RegsArm64.h>
 #include <unwindstack/RegsX86.h>
 #include <unwindstack/RegsX86_64.h>
+#include <unwindstack/RegsMips.h>
+#include <unwindstack/RegsMips64.h>
 
 #include "ElfFake.h"
 #include "MemoryFake.h"
@@ -112,6 +114,30 @@
   ASSERT_EQ(0x1U,  x86_64.GetAdjustedPc(0x2, elf_.get()));
   ASSERT_EQ(0x0U,  x86_64.GetAdjustedPc(0x1, elf_.get()));
   ASSERT_EQ(0x0U,  x86_64.GetAdjustedPc(0x0, elf_.get()));
+
+  RegsMips mips;
+  ASSERT_EQ(0x8U, mips.GetAdjustedPc(0x10, elf_.get()));
+  ASSERT_EQ(0x0U, mips.GetAdjustedPc(0x8, elf_.get()));
+  ASSERT_EQ(0x7U, mips.GetAdjustedPc(0x7, elf_.get()));
+  ASSERT_EQ(0x6U, mips.GetAdjustedPc(0x6, elf_.get()));
+  ASSERT_EQ(0x5U, mips.GetAdjustedPc(0x5, elf_.get()));
+  ASSERT_EQ(0x4U, mips.GetAdjustedPc(0x4, elf_.get()));
+  ASSERT_EQ(0x3U, mips.GetAdjustedPc(0x3, elf_.get()));
+  ASSERT_EQ(0x2U, mips.GetAdjustedPc(0x2, elf_.get()));
+  ASSERT_EQ(0x1U, mips.GetAdjustedPc(0x1, elf_.get()));
+  ASSERT_EQ(0x0U, mips.GetAdjustedPc(0x0, elf_.get()));
+
+  RegsMips64 mips64;
+  ASSERT_EQ(0x8U, mips64.GetAdjustedPc(0x10, elf_.get()));
+  ASSERT_EQ(0x0U, mips64.GetAdjustedPc(0x8, elf_.get()));
+  ASSERT_EQ(0x7U, mips64.GetAdjustedPc(0x7, elf_.get()));
+  ASSERT_EQ(0x6U, mips64.GetAdjustedPc(0x6, elf_.get()));
+  ASSERT_EQ(0x5U, mips64.GetAdjustedPc(0x5, elf_.get()));
+  ASSERT_EQ(0x4U, mips64.GetAdjustedPc(0x4, elf_.get()));
+  ASSERT_EQ(0x3U, mips64.GetAdjustedPc(0x3, elf_.get()));
+  ASSERT_EQ(0x2U, mips64.GetAdjustedPc(0x2, elf_.get()));
+  ASSERT_EQ(0x1U, mips64.GetAdjustedPc(0x1, elf_.get()));
+  ASSERT_EQ(0x0U, mips64.GetAdjustedPc(0x0, elf_.get()));
 }
 
 TEST_F(RegsTest, rel_pc_arm) {
@@ -154,6 +180,8 @@
   RegsArm64 regs_arm64;
   RegsX86 regs_x86;
   RegsX86_64 regs_x86_64;
+  RegsMips regs_mips;
+  RegsMips64 regs_mips64;
   MapInfo map_info(0x1000, 0x2000);
   Elf* invalid_elf = new Elf(new MemoryFake);
   map_info.elf = invalid_elf;
@@ -173,6 +201,14 @@
   regs_x86_64.set_pc(0x1800);
   EXPECT_EQ(0x800U, invalid_elf->GetRelPc(regs_x86_64.pc(), &map_info));
   EXPECT_EQ(0x800U, regs_x86_64.GetAdjustedPc(0x800U, invalid_elf));
+
+  regs_mips.set_pc(0x1900);
+  EXPECT_EQ(0x900U, invalid_elf->GetRelPc(regs_mips.pc(), &map_info));
+  EXPECT_EQ(0x900U, regs_mips.GetAdjustedPc(0x900U, invalid_elf));
+
+  regs_mips64.set_pc(0x1a00);
+  EXPECT_EQ(0xa00U, invalid_elf->GetRelPc(regs_mips64.pc(), &map_info));
+  EXPECT_EQ(0xa00U, regs_mips64.GetAdjustedPc(0xa00U, invalid_elf));
 }
 
 TEST_F(RegsTest, arm_set_from_raw) {
@@ -215,6 +251,26 @@
   EXPECT_EQ(0x4900000000U, x86_64.pc());
 }
 
+TEST_F(RegsTest, mips_set_from_raw) {
+  RegsMips mips;
+  uint32_t* regs = reinterpret_cast<uint32_t*>(mips.RawData());
+  regs[29] = 0x100;
+  regs[32] = 0x200;
+  mips.SetFromRaw();
+  EXPECT_EQ(0x100U, mips.sp());
+  EXPECT_EQ(0x200U, mips.pc());
+}
+
+TEST_F(RegsTest, mips64_set_from_raw) {
+  RegsMips64 mips64;
+  uint64_t* regs = reinterpret_cast<uint64_t*>(mips64.RawData());
+  regs[29] = 0xb100000000ULL;
+  regs[32] = 0xc200000000ULL;
+  mips64.SetFromRaw();
+  EXPECT_EQ(0xb100000000U, mips64.sp());
+  EXPECT_EQ(0xc200000000U, mips64.pc());
+}
+
 TEST_F(RegsTest, machine_type) {
   RegsArm arm_regs;
   EXPECT_EQ(ARCH_ARM, arm_regs.Arch());
@@ -227,6 +283,12 @@
 
   RegsX86_64 x86_64_regs;
   EXPECT_EQ(ARCH_X86_64, x86_64_regs.Arch());
+
+  RegsMips mips_regs;
+  EXPECT_EQ(ARCH_MIPS, mips_regs.Arch());
+
+  RegsMips64 mips64_regs;
+  EXPECT_EQ(ARCH_MIPS64, mips64_regs.Arch());
 }
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 2034191..cd46807 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -32,6 +32,8 @@
 #include <unwindstack/RegsArm64.h>
 #include <unwindstack/RegsX86.h>
 #include <unwindstack/RegsX86_64.h>
+#include <unwindstack/RegsMips.h>
+#include <unwindstack/RegsMips64.h>
 #include <unwindstack/Unwinder.h>
 
 #include "ElfFake.h"
@@ -733,6 +735,16 @@
   x86_64->set_sp(0x10000);
   reg_list.push_back(x86_64);
 
+  RegsMips* mips = new RegsMips;
+  mips->set_pc(0x2300);
+  mips->set_sp(0x10000);
+  reg_list.push_back(mips);
+
+  RegsMips64* mips64 = new RegsMips64;
+  mips64->set_pc(0x2300);
+  mips64->set_sp(0x10000);
+  reg_list.push_back(mips64);
+
   for (auto regs : reg_list) {
     ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 10));
 
@@ -744,10 +756,12 @@
     switch (regs->Arch()) {
       case ARCH_ARM:
       case ARCH_X86:
+      case ARCH_MIPS:
         expected = "  #00 pc 00001300  /system/fake/libc.so (Frame0+10)";
         break;
       case ARCH_ARM64:
       case ARCH_X86_64:
+      case ARCH_MIPS64:
         expected = "  #00 pc 0000000000001300  /system/fake/libc.so (Frame0+10)";
         break;
       default: