From 0192fc21b9a5e93cbf57f63444ee1cca73e58d84 Mon Sep 17 00:00:00 2001 From: "digit@chromium.org" Date: Thu, 21 Mar 2013 08:22:37 +0000 Subject: Fix three unit tests on recent ARM devices. Three unit tests were failing on recent ARM devices (e.g. Galaxy Nexus or Nexus 4), while ran properly on older ones (e.g. Nexus S). The main issue is that the instruction cache needs to be explicitely cleared on ARM after writing machine code bytes to a malloc()-ed page with PROT_EXEC. Review URL: https://breakpad.appspot.com/540002 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1132 4c0a9323-5329-0410-9bdc-e9ce6186880e --- .../linux/handler/exception_handler_unittest.cc | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'src') diff --git a/src/client/linux/handler/exception_handler_unittest.cc b/src/client/linux/handler/exception_handler_unittest.cc index 27a7a777..0ba52163 100644 --- a/src/client/linux/handler/exception_handler_unittest.cc +++ b/src/client/linux/handler/exception_handler_unittest.cc @@ -54,6 +54,27 @@ using namespace google_breakpad; namespace { +// Flush the instruction cache for a given memory range. +// Only required on ARM. +void FlushInstructionCache(const char* memory, uint32_t memory_size) { +#if defined(__arm__) + long begin = reinterpret_cast(memory); + long end = begin + static_cast(memory_size); +# if defined(__ANDROID__) + // Provided by Android's + cacheflush(begin, end, 0); +# elif defined(__linux__) + // GLibc/ARM doesn't provide a wrapper for it, do a direct syscall. +# ifndef __ARM_NR_cacheflush +# define __ARM_NR_cacheflush 0xf0002 +# endif + syscall(__ARM_NR_cacheflush, begin, end, 0); +# else +# error "Your operating system is not supported yet" +# endif +#endif +} + // Length of a formatted GUID string = // sizeof(MDGUID) * 2 + 4 (for dashes) + 1 (null terminator) const int kGUIDStringSize = 37; @@ -449,6 +470,7 @@ TEST(ExceptionHandlerTest, InstructionPointerMemory) { // 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)); + FlushInstructionCache(memory, kMemorySize); // Now execute the instructions, which should crash. typedef void (*void_function)(void); @@ -541,6 +563,7 @@ TEST(ExceptionHandlerTest, InstructionPointerMemoryMinBound) { // 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)); + FlushInstructionCache(memory, kMemorySize); // Now execute the instructions, which should crash. typedef void (*void_function)(void); @@ -632,6 +655,7 @@ TEST(ExceptionHandlerTest, InstructionPointerMemoryMaxBound) { // 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)); + FlushInstructionCache(memory, kMemorySize); // Now execute the instructions, which should crash. typedef void (*void_function)(void); -- cgit v1.2.1