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: