From 930038fd8bd0eb758f8d4cadc38a5a4ce6fa055e Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 2 Jan 2014 19:22:25 -0800 Subject: [PATCH] Use C++ for unwinding on Android. #11147 For some reason using libunwind directly is not working. --- mk/rt.mk | 14 ++++++ src/libstd/rt/unwind.rs | 98 ++++++++++++++++++++++++++++++++++++---- src/libstd/rtdeps.rs | 3 ++ src/rt/rust_cxx_glue.cpp | 23 ++++++++++ 4 files changed, 130 insertions(+), 8 deletions(-) create mode 100644 src/rt/rust_cxx_glue.cpp diff --git a/mk/rt.mk b/mk/rt.mk index ddffcb3ffb96a..99d5f07d30041 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -72,6 +72,14 @@ RUNTIME_CXXFLAGS_$(1)_$(2) = -D_RUST_STAGE1 endif endif +ifeq ($(OSTYPE_$(1)), linux-androideabi) +# Use c++ to unwind on Android. #11147 +RUNTIME_CXXS_$(1)_$(2) := \ + rt/rust_cxx_glue.cpp +else +RUNTIME_CXXS_$(1)_$(2) := +endif + RUNTIME_CS_$(1)_$(2) := \ rt/rust_builtin.c \ rt/miniz.c \ @@ -94,6 +102,7 @@ RUNTIME_DEF_$(1)_$(2) := $$(RT_OUTPUT_DIR_$(1))/rustrt$$(CFG_DEF_SUFFIX_$(1)) RUNTIME_INCS_$(1)_$(2) := -I $$(S)src/rt -I $$(S)src/rt/isaac -I $$(S)src/rt/uthash \ -I $$(S)src/rt/arch/$$(HOST_$(1)) RUNTIME_OBJS_$(1)_$(2) := \ + $$(RUNTIME_CXXS_$(1)_$(2):rt/%.cpp=$$(RT_BUILD_DIR_$(1)_$(2))/%.o) \ $$(RUNTIME_CS_$(1)_$(2):rt/%.c=$$(RT_BUILD_DIR_$(1)_$(2))/%.o) \ $$(RUNTIME_S_$(1)_$(2):rt/%.S=$$(RT_BUILD_DIR_$(1)_$(2))/%.o) \ $$(RUNTIME_LL_$(1)_$(2):rt/%.ll=$$(RT_BUILD_DIR_$(1)_$(2))/%.o) @@ -103,6 +112,11 @@ ALL_OBJ_FILES += $$(RUNTIME_OBJS_$(1)_$(2)) MORESTACK_OBJS_$(1)_$(2) := $$(RT_BUILD_DIR_$(1)_$(2))/arch/$$(HOST_$(1))/morestack.o ALL_OBJ_FILES += $$(MORESTACK_OBJS_$(1)_$(2)) +$$(RT_BUILD_DIR_$(1)_$(2))/rust_cxx_glue.o: rt/rust_cxx_glue.cpp $$(MKFILE_DEPS) + @$$(call E, compile: $$@) + $$(Q)$$(call CFG_COMPILE_CXX_$(1), $$@, $$(RUNTIME_INCS_$(1)_$(2)) \ + $$(SNAP_DEFINES) $$(RUNTIME_CXXFLAGS_$(1)_$(2))) $$< + $$(RT_BUILD_DIR_$(1)_$(2))/%.o: rt/%.c $$(MKFILE_DEPS) @$$(call E, compile: $$@) $$(Q)$$(call CFG_COMPILE_C_$(1), $$@, $$(RUNTIME_INCS_$(1)_$(2)) \ diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs index 358df7260f4af..bfdcc454fc8a0 100644 --- a/src/libstd/rt/unwind.rs +++ b/src/libstd/rt/unwind.rs @@ -118,7 +118,9 @@ mod libunwind { exception: *_Unwind_Exception); extern "C" { + #[cfg(not(target_os = "android"))] pub fn _Unwind_RaiseException(exception: *_Unwind_Exception) -> _Unwind_Reason_Code; + #[cfg(not(target_os = "android"))] pub fn _Unwind_DeleteException(exception: *_Unwind_Exception); } } @@ -140,6 +142,7 @@ impl Unwinder { self.unwinding } + #[cfg(not(target_os = "android"))] pub fn try(&mut self, f: ||) { use unstable::raw::Closure; @@ -174,6 +177,35 @@ impl Unwinder { } } + // FIXME #11147. On Android we're using C++ to do our unwinding because + // our initial attempts at using libunwind directly don't seem to work + // correctly. Would love to not be doing this. + #[cfg(target_os = "android")] + pub fn try(&mut self, f: ||) { + use unstable::raw::Closure; + + unsafe { + let closure: Closure = cast::transmute(f); + rust_cxx_try(try_fn, closure.code as *c_void, closure.env as *c_void); + } + + extern fn try_fn(code: *c_void, env: *c_void) { + unsafe { + let closure: || = cast::transmute(Closure { + code: code as *(), + env: env as *(), + }); + closure(); + } + } + + extern { + fn rust_cxx_try(f: extern "C" fn(*c_void, *c_void), + code: *c_void, + data: *c_void); + } + } + pub fn begin_unwind(&mut self, cause: ~Any) -> ! { rtdebug!("begin_unwind()"); @@ -186,6 +218,11 @@ impl Unwinder { #[inline(never)] #[no_mangle] fn rust_fail() -> ! { + throw(); + } + + #[cfg(not(target_os = "android"))] + fn throw() -> ! { unsafe { let exception = ~uw::_Unwind_Exception { exception_class: rust_exception_class(), @@ -205,6 +242,15 @@ impl Unwinder { } } } + + #[cfg(target_os = "android")] + fn throw() -> ! { + unsafe { rust_cxx_throw(); } + + extern { + fn rust_cxx_throw() -> !; + } + } } pub fn result(&mut self) -> TaskResult { @@ -218,6 +264,7 @@ impl Unwinder { // Rust's exception class identifier. This is used by personality routines to // determine whether the exception was thrown by their own runtime. +#[cfg(not(target_os = "android"))] fn rust_exception_class() -> uw::_Unwind_Exception_Class { // M O Z \0 R U S T -- vendor, language 0x4d4f5a_00_52555354 @@ -243,12 +290,21 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class { // say "catch!". extern "C" { + #[cfg(not(target_os = "android"))] fn __gcc_personality_v0(version: c_int, actions: uw::_Unwind_Action, exception_class: uw::_Unwind_Exception_Class, ue_header: *uw::_Unwind_Exception, context: *uw::_Unwind_Context) -> uw::_Unwind_Reason_Code; + + #[cfg(target_os = "android")] + fn __gxx_personality_v0(version: c_int, + actions: uw::_Unwind_Action, + exception_class: uw::_Unwind_Exception_Class, + ue_header: *uw::_Unwind_Exception, + context: *uw::_Unwind_Context) + -> uw::_Unwind_Reason_Code; } #[lang="eh_personality"] @@ -263,10 +319,8 @@ pub extern "C" fn rust_eh_personality( context: *uw::_Unwind_Context ) -> uw::_Unwind_Reason_Code { - unsafe { - __gcc_personality_v0(version, actions, exception_class, ue_header, - context) - } + native_personality(version, actions, exception_class, ue_header, + context) } #[no_mangle] // referenced from rust_try.ll @@ -284,10 +338,38 @@ pub extern "C" fn rust_eh_personality_catch( uw::_URC_HANDLER_FOUND // catch! } else { // cleanup phase - unsafe { - __gcc_personality_v0(version, actions, exception_class, ue_header, - context) - } + native_personality(version, actions, exception_class, ue_header, + context) + } +} + +#[cfg(not(target_os = "android"))] +fn native_personality( + version: c_int, + actions: uw::_Unwind_Action, + exception_class: uw::_Unwind_Exception_Class, + ue_header: *uw::_Unwind_Exception, + context: *uw::_Unwind_Context +) -> uw::_Unwind_Reason_Code +{ + unsafe { + __gcc_personality_v0(version, actions, exception_class, ue_header, + context) + } +} + +#[cfg(target_os = "android")] +fn native_personality( + version: c_int, + actions: uw::_Unwind_Action, + exception_class: uw::_Unwind_Exception_Class, + ue_header: *uw::_Unwind_Exception, + context: *uw::_Unwind_Context +) -> uw::_Unwind_Reason_Code +{ + unsafe { + __gxx_personality_v0(version, actions, exception_class, ue_header, + context) } } diff --git a/src/libstd/rtdeps.rs b/src/libstd/rtdeps.rs index 045cdf574f62f..25fd8a10ce139 100644 --- a/src/libstd/rtdeps.rs +++ b/src/libstd/rtdeps.rs @@ -31,6 +31,9 @@ extern {} #[link(name = "dl")] #[link(name = "log")] #[link(name = "m")] +// FIXME #11147. We're using C++ for unwinding on Android +// but should be using libunwind directly. +#[link(name = "stdc++")] extern {} #[cfg(target_os = "freebsd")] diff --git a/src/rt/rust_cxx_glue.cpp b/src/rt/rust_cxx_glue.cpp new file mode 100644 index 0000000000000..35157000ed322 --- /dev/null +++ b/src/rt/rust_cxx_glue.cpp @@ -0,0 +1,23 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern "C" void rust_cxx_throw() { + throw 0; +} + +typedef void *(rust_try_fn)(void*, void*); + +extern "C" void +rust_cxx_try(rust_try_fn f, void *fptr, void *env) { + try { + f(fptr, env); + } catch (int t) { + } +}