Skip to content

Use C++ for unwinding on Android. #11147 #11281

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions mk/rt.mk
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand All @@ -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)
Expand All @@ -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)) \
Expand Down
98 changes: 90 additions & 8 deletions src/libstd/rt/unwind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand All @@ -140,6 +142,7 @@ impl Unwinder {
self.unwinding
}

#[cfg(not(target_os = "android"))]
pub fn try(&mut self, f: ||) {
use unstable::raw::Closure;

Expand Down Expand Up @@ -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()");

Expand All @@ -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(),
Expand All @@ -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 {
Expand All @@ -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
Expand All @@ -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"]
Expand All @@ -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
Expand All @@ -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)
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/libstd/rtdeps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down
23 changes: 23 additions & 0 deletions src/rt/rust_cxx_glue.cpp
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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) {
}
}