From f78839c15730533fc433c50ea83a3afea835c245 Mon Sep 17 00:00:00 2001 From: "gordana.cmiljanovic@imgtec.com" Date: Wed, 11 Sep 2013 11:37:04 +0000 Subject: Adding support for mips. Support for mips cpu is added to all breakapad targets including unittests. BUG=none TEST=unittests Review URL: https://breakpad.appspot.com/614002 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1212 4c0a9323-5329-0410-9bdc-e9ce6186880e --- src/client/linux/handler/exception_handler.cc | 9 +++- src/client/linux/handler/exception_handler.h | 4 +- .../linux/handler/exception_handler_unittest.cc | 54 ++++++++++++++-------- 3 files changed, 45 insertions(+), 22 deletions(-) (limited to 'src/client/linux/handler') diff --git a/src/client/linux/handler/exception_handler.cc b/src/client/linux/handler/exception_handler.cc index 2808fc90..9df720dd 100644 --- a/src/client/linux/handler/exception_handler.cc +++ b/src/client/linux/handler/exception_handler.cc @@ -396,8 +396,10 @@ 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__) +#if !defined(__ARM_EABI__) && !defined(__mips__) // FP state is not part of user ABI on ARM 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; if (uc_ptr->uc_mcontext.fpregs) { memcpy(&context.float_state, @@ -602,7 +604,7 @@ bool ExceptionHandler::WriteMinidump() { } #endif -#if !defined(__ARM_EABI__) +#if !defined(__ARM_EABI__) && !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)); @@ -621,6 +623,9 @@ bool ExceptionHandler::WriteMinidump() { #elif defined(__arm__) context.siginfo.si_addr = reinterpret_cast(context.context.uc_mcontext.arm_pc); +#elif defined(__mips__) + context.siginfo.si_addr = + reinterpret_cast(context.context.uc_mcontext.pc); #else #error "This code has not been ported to your platform yet." #endif diff --git a/src/client/linux/handler/exception_handler.h b/src/client/linux/handler/exception_handler.h index 71554196..bbd962cb 100644 --- a/src/client/linux/handler/exception_handler.h +++ b/src/client/linux/handler/exception_handler.h @@ -190,8 +190,10 @@ class ExceptionHandler { siginfo_t siginfo; pid_t tid; // the crashing thread. struct ucontext context; -#if !defined(__ARM_EABI__) +#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. struct _libc_fpstate float_state; #endif }; diff --git a/src/client/linux/handler/exception_handler_unittest.cc b/src/client/linux/handler/exception_handler_unittest.cc index 0ba52163..702a3adb 100644 --- a/src/client/linux/handler/exception_handler_unittest.cc +++ b/src/client/linux/handler/exception_handler_unittest.cc @@ -35,6 +35,9 @@ #include #include #include +#if defined(__mips__) +#include +#endif #include @@ -55,7 +58,7 @@ using namespace google_breakpad; namespace { // Flush the instruction cache for a given memory range. -// Only required on ARM. +// Only required on ARM and mips. void FlushInstructionCache(const char* memory, uint32_t memory_size) { #if defined(__arm__) long begin = reinterpret_cast(memory); @@ -72,6 +75,13 @@ void FlushInstructionCache(const char* memory, uint32_t memory_size) { # else # error "Your operating system is not supported yet" # endif +#elif defined(__mips__) +# if defined(__linux__) + // See http://www.linux-mips.org/wiki/Cacheflush_Syscall. + cacheflush(const_cast(memory), memory_size, ICACHE); +# else +# error "Your operating system is not supported yet" +# endif #endif } @@ -435,6 +445,16 @@ TEST(ExceptionHandlerTest, StackedHandlersUnhandledToBottom) { ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL)); } +const unsigned char kIllegalInstruction[] = { +#if defined(__mips__) + // mfc2 zero,Impl - usually illegal in userspace. + 0x48, 0x00, 0x00, 0x48 +#else + // This crashes with SIGILL on x86/x86-64/arm. + 0xff, 0xff, 0xff, 0xff +#endif +}; + // Test that memory around the instruction pointer is written // to the dump as a MinidumpMemoryRegion. TEST(ExceptionHandlerTest, InstructionPointerMemory) { @@ -446,8 +466,6 @@ TEST(ExceptionHandlerTest, InstructionPointerMemory) { // data from the minidump afterwards. const uint32_t kMemorySize = 256; // bytes const int kOffset = kMemorySize / 2; - // This crashes with SIGILL on x86/x86-64/arm. - const unsigned char instructions[] = { 0xff, 0xff, 0xff, 0xff }; const pid_t child = fork(); if (child == 0) { @@ -469,7 +487,7 @@ TEST(ExceptionHandlerTest, InstructionPointerMemory) { // Write some instructions that will crash. Put them in the middle // of the block of memory, because the minidump should contain 128 // bytes on either side of the instruction pointer. - memcpy(memory + kOffset, instructions, sizeof(instructions)); + memcpy(memory + kOffset, kIllegalInstruction, sizeof(kIllegalInstruction)); FlushInstructionCache(memory, kMemorySize); // Now execute the instructions, which should crash. @@ -517,12 +535,13 @@ TEST(ExceptionHandlerTest, InstructionPointerMemory) { ASSERT_TRUE(bytes); uint8_t prefix_bytes[kOffset]; - uint8_t suffix_bytes[kMemorySize - kOffset - sizeof(instructions)]; + uint8_t suffix_bytes[kMemorySize - kOffset - sizeof(kIllegalInstruction)]; memset(prefix_bytes, 0, sizeof(prefix_bytes)); memset(suffix_bytes, 0, sizeof(suffix_bytes)); EXPECT_TRUE(memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)) == 0); - EXPECT_TRUE(memcmp(bytes + kOffset, instructions, sizeof(instructions)) == 0); - EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(instructions), + EXPECT_TRUE(memcmp(bytes + kOffset, kIllegalInstruction, + sizeof(kIllegalInstruction)) == 0); + EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(kIllegalInstruction), suffix_bytes, sizeof(suffix_bytes)) == 0); unlink(minidump_path.c_str()); @@ -539,8 +558,6 @@ TEST(ExceptionHandlerTest, InstructionPointerMemoryMinBound) { // data from the minidump afterwards. const uint32_t kMemorySize = 256; // bytes const int kOffset = 0; - // This crashes with SIGILL on x86/x86-64/arm. - const unsigned char instructions[] = { 0xff, 0xff, 0xff, 0xff }; const pid_t child = fork(); if (child == 0) { @@ -562,7 +579,7 @@ TEST(ExceptionHandlerTest, InstructionPointerMemoryMinBound) { // Write some instructions that will crash. Put them in the middle // of the block of memory, because the minidump should contain 128 // bytes on either side of the instruction pointer. - memcpy(memory + kOffset, instructions, sizeof(instructions)); + memcpy(memory + kOffset, kIllegalInstruction, sizeof(kIllegalInstruction)); FlushInstructionCache(memory, kMemorySize); // Now execute the instructions, which should crash. @@ -609,10 +626,11 @@ TEST(ExceptionHandlerTest, InstructionPointerMemoryMinBound) { const uint8_t* bytes = region->GetMemory(); ASSERT_TRUE(bytes); - uint8_t suffix_bytes[kMemorySize / 2 - sizeof(instructions)]; + uint8_t suffix_bytes[kMemorySize / 2 - sizeof(kIllegalInstruction)]; memset(suffix_bytes, 0, sizeof(suffix_bytes)); - EXPECT_TRUE(memcmp(bytes + kOffset, instructions, sizeof(instructions)) == 0); - EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(instructions), + EXPECT_TRUE(memcmp(bytes + kOffset, kIllegalInstruction, + sizeof(kIllegalInstruction)) == 0); + EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(kIllegalInstruction), suffix_bytes, sizeof(suffix_bytes)) == 0); unlink(minidump_path.c_str()); } @@ -630,9 +648,7 @@ TEST(ExceptionHandlerTest, InstructionPointerMemoryMaxBound) { // if a smaller size is requested, and this test wants to // test the upper bound of the memory range. const uint32_t kMemorySize = 4096; // bytes - // This crashes with SIGILL on x86/x86-64/arm. - const unsigned char instructions[] = { 0xff, 0xff, 0xff, 0xff }; - const int kOffset = kMemorySize - sizeof(instructions); + const int kOffset = kMemorySize - sizeof(kIllegalInstruction); const pid_t child = fork(); if (child == 0) { @@ -654,7 +670,7 @@ TEST(ExceptionHandlerTest, InstructionPointerMemoryMaxBound) { // Write some instructions that will crash. Put them in the middle // of the block of memory, because the minidump should contain 128 // bytes on either side of the instruction pointer. - memcpy(memory + kOffset, instructions, sizeof(instructions)); + memcpy(memory + kOffset, kIllegalInstruction, sizeof(kIllegalInstruction)); FlushInstructionCache(memory, kMemorySize); // Now execute the instructions, which should crash. @@ -697,7 +713,7 @@ TEST(ExceptionHandlerTest, InstructionPointerMemoryMaxBound) { ASSERT_TRUE(region); const size_t kPrefixSize = 128; // bytes - EXPECT_EQ(kPrefixSize + sizeof(instructions), region->GetSize()); + EXPECT_EQ(kPrefixSize + sizeof(kIllegalInstruction), region->GetSize()); const uint8_t* bytes = region->GetMemory(); ASSERT_TRUE(bytes); @@ -705,7 +721,7 @@ TEST(ExceptionHandlerTest, InstructionPointerMemoryMaxBound) { memset(prefix_bytes, 0, sizeof(prefix_bytes)); EXPECT_TRUE(memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)) == 0); EXPECT_TRUE(memcmp(bytes + kPrefixSize, - instructions, sizeof(instructions)) == 0); + kIllegalInstruction, sizeof(kIllegalInstruction)) == 0); unlink(minidump_path.c_str()); } -- cgit v1.2.1