diff options
author | Pavel Chupin <pavel.v.chupin@intel.com> | 2014-09-26 16:02:09 +0400 |
---|---|---|
committer | Elliott Hughes <enh@google.com> | 2014-10-27 16:42:49 -0700 |
commit | 8eb8c3929974060e0d8b5063886d6ed250198d41 (patch) | |
tree | 123461b5b038f82f6b5a0e1dc4dcb4c2bb71299e /tests | |
parent | 190dce9e56c750be6b8d113ffdd32a9c20c19e3d (diff) | |
download | bionic-8eb8c3929974060e0d8b5063886d6ed250198d41.tar.gz |
[x86,x86_64] Fix libgcc unwinding through signal
This change provides __restore/__restore_rt on x86 and __restore_rt on
x86_64 with unwinding information to be able to unwind through signal
frame via libgcc provided unwinding interface. See comments inlined for
more details.
Also remove the test that had a dependency on
__attribute__((cleanup(foo_cleanup))). It doesn't provide us with any
better test coverage than we have from the newer tests, and it doesn't
work well across a variety architectures (presumably because no one uses
this attribute in the real world).
Tested this on host via bionic-unit-tests-run-on-host on both x86 and
x86-64.
Bug: 17436734
Signed-off-by: Pavel Chupin <pavel.v.chupin@intel.com>
(cherry picked from commit 50321e2e66f19998970e59d666bc9af387345b3a)
Change-Id: Iba90e36958b00c7cc7db5eeebf888dc89ce4d619
Diffstat (limited to 'tests')
-rw-r--r-- | tests/Android.mk | 3 | ||||
-rw-r--r-- | tests/ScopedSignalHandler.h | 5 | ||||
-rw-r--r-- | tests/stack_unwinding_test.cpp | 17 | ||||
-rw-r--r-- | tests/stack_unwinding_test_impl.c | 64 |
4 files changed, 14 insertions, 75 deletions
diff --git a/tests/Android.mk b/tests/Android.mk index 23a2cb3ed..407f21bc5 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -88,6 +88,7 @@ libBionicStandardTests_src_files := \ search_test.cpp \ signal_test.cpp \ stack_protector_test.cpp \ + stack_unwinding_test.cpp \ stdatomic_test.cpp \ stdint_test.cpp \ stdio_test.cpp \ @@ -224,8 +225,6 @@ bionic-unit-tests_src_files := \ atexit_test.cpp \ dlext_test.cpp \ dlfcn_test.cpp \ - stack_unwinding_test.cpp \ - stack_unwinding_test_impl.c \ bionic-unit-tests_cflags := $(test_cflags) diff --git a/tests/ScopedSignalHandler.h b/tests/ScopedSignalHandler.h index 89a14a6b2..3ec23b0d8 100644 --- a/tests/ScopedSignalHandler.h +++ b/tests/ScopedSignalHandler.h @@ -21,9 +21,10 @@ class ScopedSignalHandler { public: - ScopedSignalHandler(int signal_number, void (*handler)(int)) : signal_number_(signal_number) { + ScopedSignalHandler(int signal_number, void (*handler)(int), int sa_flags = 0) + : signal_number_(signal_number) { sigemptyset(&action_.sa_mask); - action_.sa_flags = 0; + action_.sa_flags = sa_flags; action_.sa_handler = handler; sigaction(signal_number_, &action_, &old_action_); } diff --git a/tests/stack_unwinding_test.cpp b/tests/stack_unwinding_test.cpp index 017a5f2e8..3fc45c537 100644 --- a/tests/stack_unwinding_test.cpp +++ b/tests/stack_unwinding_test.cpp @@ -31,7 +31,8 @@ #include "ScopedSignalHandler.h" -#define noinline __attribute__((noinline)) +#define noinline __attribute__((__noinline__)) +#define __unused __attribute__((__unused__)) static _Unwind_Reason_Code FrameCounter(_Unwind_Context* ctx __unused, void* arg) { int* count_ptr = reinterpret_cast<int*>(arg); @@ -85,6 +86,7 @@ static void noinline UnwindSignalHandler(int) { } TEST(stack_unwinding, unwind_through_signal_frame) { + killer_count = handler_count = handler_one_deeper_count = 0; ScopedSignalHandler ssh(SIGUSR1, UnwindSignalHandler); _Unwind_Backtrace(FrameCounter, &killer_count); @@ -92,11 +94,12 @@ TEST(stack_unwinding, unwind_through_signal_frame) { ASSERT_EQ(0, kill(getpid(), SIGUSR1)); } -extern "C" void unwind_through_frame_with_cleanup_function(); +// On LP32, the SA_SIGINFO flag gets you __restore_rt instead of __restore. +TEST(stack_unwinding, unwind_through_signal_frame_SA_SIGINFO) { + killer_count = handler_count = handler_one_deeper_count = 0; + ScopedSignalHandler ssh(SIGUSR1, UnwindSignalHandler, SA_SIGINFO); -// We have to say "DeathTest" here so gtest knows to run this test (which exits) -// in its own process. -TEST(stack_unwinding_DeathTest, unwind_through_frame_with_cleanup_function) { - ::testing::FLAGS_gtest_death_test_style = "threadsafe"; - ASSERT_EXIT(unwind_through_frame_with_cleanup_function(), ::testing::ExitedWithCode(42), ""); + _Unwind_Backtrace(FrameCounter, &killer_count); + + ASSERT_EQ(0, kill(getpid(), SIGUSR1)); } diff --git a/tests/stack_unwinding_test_impl.c b/tests/stack_unwinding_test_impl.c deleted file mode 100644 index 2e0393847..000000000 --- a/tests/stack_unwinding_test_impl.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Contributed by: Intel Corporation - */ - -#include <dlfcn.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <unwind.h> - -#define noinline __attribute__((__noinline__)) - -#ifndef __unused -#define __unused __attribute__((__unused__)) -#endif - -static noinline _Unwind_Reason_Code cleanup_unwind_fn(int a __unused, - _Unwind_Action action, - _Unwind_Exception_Class b __unused, - struct _Unwind_Exception* c __unused, - struct _Unwind_Context* ctx __unused, - void* e __unused) { - if ((action & _UA_END_OF_STACK) != 0) { - abort(); // We reached the end of the stack without executing foo_cleanup (which would have exited). Test failed. - } - return _URC_NO_REASON; -} - -static void noinline foo_cleanup(char* param __unused) { - exit(42); -} - -static void noinline function_with_cleanup_function() { - char c __attribute__((cleanup(foo_cleanup))) __unused; - *((int*) 1) = 0; -} - -static void noinline cleanup_sigsegv_handler(int param __unused) { - struct _Unwind_Exception* exception = (struct _Unwind_Exception*) calloc(1, sizeof(*exception)); - _Unwind_ForcedUnwind(exception, cleanup_unwind_fn, 0); -} - -void unwind_through_frame_with_cleanup_function() { - signal(SIGSEGV, &cleanup_sigsegv_handler); - function_with_cleanup_function(); -} |