diff options
-rw-r--r-- | libc/arch-x86/bionic/__restore.S | 104 | ||||
-rw-r--r-- | libc/arch-x86/bionic/__restore_rt.S | 36 | ||||
-rw-r--r-- | libc/arch-x86/x86.mk | 1 | ||||
-rw-r--r-- | libc/arch-x86_64/bionic/__restore_rt.S | 113 | ||||
-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 |
8 files changed, 225 insertions, 118 deletions
diff --git a/libc/arch-x86/bionic/__restore.S b/libc/arch-x86/bionic/__restore.S index 755c3f8..cb18fd0 100644 --- a/libc/arch-x86/bionic/__restore.S +++ b/libc/arch-x86/bionic/__restore.S @@ -28,10 +28,108 @@ #include <private/bionic_asm.h> -// This function must have exactly this instruction sequence for gdb and libunwind. -// This function must have exactly this name for gdb. -ENTRY(__restore) +// DWARF constants. +#define DW_CFA_def_cfa_expression 0x0f +#define DW_CFA_expression 0x10 +#define DW_EH_PE_pcrel 0x10 +#define DW_EH_PE_sdata4 0x0b +#define DW_OP_breg4 0x74 +#define DW_OP_deref 0x06 + +// Offsets into struct sigcontext. +#define OFFSET_EDI 16 +#define OFFSET_ESI 20 +#define OFFSET_EBP 24 +#define OFFSET_ESP 28 +#define OFFSET_EBX 32 +#define OFFSET_EDX 36 +#define OFFSET_ECX 40 +#define OFFSET_EAX 44 +#define OFFSET_EIP 56 + +// Non-standard DWARF constants for the x86 registers. +#define DW_x86_REG_EAX 0 +#define DW_x86_REG_ECX 1 +#define DW_x86_REG_EDX 2 +#define DW_x86_REG_EBX 3 +#define DW_x86_REG_EBP 5 +#define DW_x86_REG_ESI 6 +#define DW_x86_REG_EDI 7 +#define DW_x86_REG_EIP 8 + +#define cfi_signal_frame_start(f) \ +.section .eh_frame,"a",@progbits; \ +.L ## f ## _START_EH_FRAME: \ + .long 2f - 1f; /* CIE length. */ \ +1:.long 0; /* CIE ID. */ \ + .byte 1; /* Version. */ \ + .string "zRS"; /* Augmentation string. */ \ + .uleb128 1; /* Code alignment factor. */ \ + .sleb128 -4; /* Data alignment factor. */ \ + .uleb128 DW_x86_REG_EIP; /* Return address register. */ \ + .uleb128 1; /* 1 byte of augmentation data. */ \ + .byte (DW_EH_PE_pcrel|DW_EH_PE_sdata4); /* FDE encoding. */ \ + .align 8; \ +2: \ + .long .L ## f ## _END_FDE - .L ## f ## _START_FDE; /* FDE length. */ \ +.L ## f ## _START_FDE: \ + .long .L ## f ## _START_FDE - .L ## f ## _START_EH_FRAME; /* CIE location. */ \ + .long (.L ## f ## _START - 1) - .; /* pcrel start address (see FDE encoding above). */ \ + .long .L ## f ## _END - (.L ## f ## _START - 1); /* Function this FDE applies to. */ \ + .uleb128 0; /* FDE augmentation length. */ \ + +#define cfi_signal_frame_end(f) \ +.L ## f ## _END_FDE: \ + +#define cfi_def_cfa(offset) \ + .byte DW_CFA_def_cfa_expression; \ + .uleb128 2f-1f; \ +1:.byte DW_OP_breg4; \ + .sleb128 offset; \ + .byte DW_OP_deref; \ +2: \ + +#define cfi_offset(reg_number,offset) \ + .byte DW_CFA_expression; \ + .uleb128 reg_number; \ + .uleb128 2f-1f; \ +1:.byte DW_OP_breg4; \ + .sleb128 offset; \ +2: \ + +ENTRY_PRIVATE(__restore) +.L__restore_START: popl %eax movl $__NR_sigreturn, %eax int $0x80 +.L__restore_END: END(__restore) +cfi_signal_frame_start(__restore) + cfi_def_cfa(OFFSET_ESP + 4) + cfi_offset(DW_x86_REG_EDI, OFFSET_EDI + 4) + cfi_offset(DW_x86_REG_ESI, OFFSET_ESI + 4) + cfi_offset(DW_x86_REG_EBP, OFFSET_EBP + 4) + cfi_offset(DW_x86_REG_EBX, OFFSET_EBX + 4) + cfi_offset(DW_x86_REG_EDX, OFFSET_EDX + 4) + cfi_offset(DW_x86_REG_ECX, OFFSET_ECX + 4) + cfi_offset(DW_x86_REG_EAX, OFFSET_EAX + 4) + cfi_offset(DW_x86_REG_EIP, OFFSET_EIP + 4) +cfi_signal_frame_end(__restore) + +ENTRY_PRIVATE(__restore_rt) +.L__restore_rt_START: + movl $__NR_rt_sigreturn, %eax + int $0x80 +.L__restore_rt_END: +END(__restore_rt) +cfi_signal_frame_start(__restore_rt) + cfi_def_cfa(OFFSET_ESP + 160) + cfi_offset(DW_x86_REG_EDI, OFFSET_EDI + 160) + cfi_offset(DW_x86_REG_ESI, OFFSET_ESI + 160) + cfi_offset(DW_x86_REG_EBP, OFFSET_EBP + 160) + cfi_offset(DW_x86_REG_EBX, OFFSET_EBX + 160) + cfi_offset(DW_x86_REG_EDX, OFFSET_EDX + 160) + cfi_offset(DW_x86_REG_ECX, OFFSET_ECX + 160) + cfi_offset(DW_x86_REG_EAX, OFFSET_EAX + 160) + cfi_offset(DW_x86_REG_EIP, OFFSET_EIP + 160) +cfi_signal_frame_end(__restore_rt) diff --git a/libc/arch-x86/bionic/__restore_rt.S b/libc/arch-x86/bionic/__restore_rt.S deleted file mode 100644 index 0cd8081..0000000 --- a/libc/arch-x86/bionic/__restore_rt.S +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <private/bionic_asm.h> - -// This function must have exactly this instruction sequence for gdb and libunwind. -// This function must have exactly this name for gdb. -ENTRY(__restore_rt) - movl $__NR_rt_sigreturn, %eax - int $0x80 -END(__restore_rt) diff --git a/libc/arch-x86/x86.mk b/libc/arch-x86/x86.mk index e73ed1d..2c90317 100644 --- a/libc/arch-x86/x86.mk +++ b/libc/arch-x86/x86.mk @@ -39,7 +39,6 @@ libc_bionic_src_files_x86 += \ arch-x86/bionic/__bionic_clone.S \ arch-x86/bionic/_exit_with_stack_teardown.S \ arch-x86/bionic/libgcc_compat.c \ - arch-x86/bionic/__restore_rt.S \ arch-x86/bionic/__restore.S \ arch-x86/bionic/_setjmp.S \ arch-x86/bionic/setjmp.S \ diff --git a/libc/arch-x86_64/bionic/__restore_rt.S b/libc/arch-x86_64/bionic/__restore_rt.S index d84be21..785b3b3 100644 --- a/libc/arch-x86_64/bionic/__restore_rt.S +++ b/libc/arch-x86_64/bionic/__restore_rt.S @@ -28,9 +28,116 @@ #include <private/bionic_asm.h> -// This function must have exactly this instruction sequence for gdb and libunwind. -// This function must have exactly this name for gdb. -ENTRY(__restore_rt) +// DWARF constants. +#define DW_CFA_def_cfa_expression 0x0f +#define DW_CFA_expression 0x10 +#define DW_EH_PE_pcrel 0x10 +#define DW_EH_PE_sdata4 0x0b +#define DW_OP_breg4 0x74 +#define DW_OP_breg7 0x77 +#define DW_OP_deref 0x06 + +// Offsets into struct ucontext_t of uc_mcontext.gregs[x]. +#define OFFSET_R8 40 +#define OFFSET_R9 48 +#define OFFSET_R10 56 +#define OFFSET_R11 64 +#define OFFSET_R12 72 +#define OFFSET_R13 80 +#define OFFSET_R14 88 +#define OFFSET_R15 96 +#define OFFSET_RDI 104 +#define OFFSET_RSI 112 +#define OFFSET_RBP 120 +#define OFFSET_RSP 160 +#define OFFSET_RBX 128 +#define OFFSET_RDX 136 +#define OFFSET_RAX 144 +#define OFFSET_RCX 152 +#define OFFSET_RIP 168 + +// Non-standard DWARF constants for the x86-64 registers. +#define DW_x86_64_RAX 0 +#define DW_x86_64_RDX 1 +#define DW_x86_64_RCX 2 +#define DW_x86_64_RBX 3 +#define DW_x86_64_RSI 4 +#define DW_x86_64_RDI 5 +#define DW_x86_64_RBP 6 +#define DW_x86_64_RSP 7 +#define DW_x86_64_R8 8 +#define DW_x86_64_R9 9 +#define DW_x86_64_R10 10 +#define DW_x86_64_R11 11 +#define DW_x86_64_R12 12 +#define DW_x86_64_R13 13 +#define DW_x86_64_R14 14 +#define DW_x86_64_R15 15 +#define DW_x86_64_RIP 16 + +#define cfi_signal_frame_start(f) \ +.section .eh_frame,"a",@progbits; \ +.L ## f ## _START_EH_FRAME: \ + .long 2f - 1f; /* CIE length. */ \ +1:.long 0; /* CIE ID. */ \ + .byte 1; /* Version. */ \ + .string "zRS"; /* Augmentation string. */ \ + .uleb128 1; /* Code alignment factor. */ \ + .sleb128 -8; /* Data alignment factor. */ \ + .uleb128 DW_x86_64_RIP; /* Return address register. */ \ + .uleb128 1; /* 1 byte of augmentation data. */ \ + .byte (DW_EH_PE_pcrel | DW_EH_PE_sdata4); /* FDE encoding. */ \ + .align 8; \ +2: \ + .long .L ## f ## _END_FDE - .L ## f ## _START_FDE; /* FDE length. */ \ +.L ## f ## _START_FDE: \ + .long .L ## f ## _START_FDE - .L ## f ## _START_EH_FRAME; /* CIE location. */ \ + .long (.L ## f ## _START - 1) - .; /* pcrel start address (see FDE encoding above). */ \ + .long .L ## f ## _END - (.L ## f ## _START - 1); /* Function this FDE applies to. */ \ + .uleb128 0; /* FDE augmentation length. */ \ + +#define cfi_signal_frame_end(f) \ +.L ## f ## _END_FDE: \ + +#define cfi_def_cfa(offset) \ + .byte DW_CFA_def_cfa_expression; \ + .uleb128 2f-1f; \ +1:.byte DW_OP_breg7; \ + .sleb128 offset; \ + .byte DW_OP_deref; \ +2: \ + +#define cfi_offset(reg_number,offset) \ + .byte DW_CFA_expression; \ + .uleb128 reg_number; \ + .uleb128 2f-1f; \ +1:.byte DW_OP_breg7; \ + .sleb128 offset; \ +2: \ + +ENTRY_PRIVATE(__restore_rt) +.L__restore_rt_START: mov $__NR_rt_sigreturn, %rax syscall +.L__restore_rt_END: END(__restore_rt) +cfi_signal_frame_start(__restore_rt) + cfi_def_cfa(OFFSET_RSP) + cfi_offset(DW_x86_64_R8, OFFSET_R8) + cfi_offset(DW_x86_64_R9, OFFSET_R9) + cfi_offset(DW_x86_64_R10, OFFSET_R10) + cfi_offset(DW_x86_64_R11, OFFSET_R11) + cfi_offset(DW_x86_64_R12, OFFSET_R12) + cfi_offset(DW_x86_64_R13, OFFSET_R13) + cfi_offset(DW_x86_64_R14, OFFSET_R14) + cfi_offset(DW_x86_64_R15, OFFSET_R15) + cfi_offset(DW_x86_64_RDI, OFFSET_RDI) + cfi_offset(DW_x86_64_RSI, OFFSET_RSI) + cfi_offset(DW_x86_64_RBP, OFFSET_RBP) + cfi_offset(DW_x86_64_RSP, OFFSET_RSP) + cfi_offset(DW_x86_64_RBX, OFFSET_RBX) + cfi_offset(DW_x86_64_RDX, OFFSET_RDX) + cfi_offset(DW_x86_64_RAX, OFFSET_RAX) + cfi_offset(DW_x86_64_RCX, OFFSET_RCX) + cfi_offset(DW_x86_64_RIP, OFFSET_RIP) +cfi_signal_frame_end(__restore_rt) diff --git a/tests/Android.mk b/tests/Android.mk index f61f175..c0345e4 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -91,6 +91,7 @@ libBionicStandardTests_src_files := \ semaphore_test.cpp \ signal_test.cpp \ stack_protector_test.cpp \ + stack_unwinding_test.cpp \ stdatomic_test.cpp \ stdint_test.cpp \ stdio_test.cpp \ @@ -234,8 +235,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 89a14a6..3ec23b0 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 017a5f2..3fc45c5 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 2e03938..0000000 --- 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(); -} |