Skip to content

Commit 930038f

Browse files
committed
Use C++ for unwinding on Android. rust-lang#11147
For some reason using libunwind directly is not working.
1 parent 2e98a93 commit 930038f

File tree

4 files changed

+130
-8
lines changed

4 files changed

+130
-8
lines changed

mk/rt.mk

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,14 @@ RUNTIME_CXXFLAGS_$(1)_$(2) = -D_RUST_STAGE1
7272
endif
7373
endif
7474

75+
ifeq ($(OSTYPE_$(1)), linux-androideabi)
76+
# Use c++ to unwind on Android. #11147
77+
RUNTIME_CXXS_$(1)_$(2) := \
78+
rt/rust_cxx_glue.cpp
79+
else
80+
RUNTIME_CXXS_$(1)_$(2) :=
81+
endif
82+
7583
RUNTIME_CS_$(1)_$(2) := \
7684
rt/rust_builtin.c \
7785
rt/miniz.c \
@@ -94,6 +102,7 @@ RUNTIME_DEF_$(1)_$(2) := $$(RT_OUTPUT_DIR_$(1))/rustrt$$(CFG_DEF_SUFFIX_$(1))
94102
RUNTIME_INCS_$(1)_$(2) := -I $$(S)src/rt -I $$(S)src/rt/isaac -I $$(S)src/rt/uthash \
95103
-I $$(S)src/rt/arch/$$(HOST_$(1))
96104
RUNTIME_OBJS_$(1)_$(2) := \
105+
$$(RUNTIME_CXXS_$(1)_$(2):rt/%.cpp=$$(RT_BUILD_DIR_$(1)_$(2))/%.o) \
97106
$$(RUNTIME_CS_$(1)_$(2):rt/%.c=$$(RT_BUILD_DIR_$(1)_$(2))/%.o) \
98107
$$(RUNTIME_S_$(1)_$(2):rt/%.S=$$(RT_BUILD_DIR_$(1)_$(2))/%.o) \
99108
$$(RUNTIME_LL_$(1)_$(2):rt/%.ll=$$(RT_BUILD_DIR_$(1)_$(2))/%.o)
@@ -103,6 +112,11 @@ ALL_OBJ_FILES += $$(RUNTIME_OBJS_$(1)_$(2))
103112
MORESTACK_OBJS_$(1)_$(2) := $$(RT_BUILD_DIR_$(1)_$(2))/arch/$$(HOST_$(1))/morestack.o
104113
ALL_OBJ_FILES += $$(MORESTACK_OBJS_$(1)_$(2))
105114

115+
$$(RT_BUILD_DIR_$(1)_$(2))/rust_cxx_glue.o: rt/rust_cxx_glue.cpp $$(MKFILE_DEPS)
116+
@$$(call E, compile: $$@)
117+
$$(Q)$$(call CFG_COMPILE_CXX_$(1), $$@, $$(RUNTIME_INCS_$(1)_$(2)) \
118+
$$(SNAP_DEFINES) $$(RUNTIME_CXXFLAGS_$(1)_$(2))) $$<
119+
106120
$$(RT_BUILD_DIR_$(1)_$(2))/%.o: rt/%.c $$(MKFILE_DEPS)
107121
@$$(call E, compile: $$@)
108122
$$(Q)$$(call CFG_COMPILE_C_$(1), $$@, $$(RUNTIME_INCS_$(1)_$(2)) \

src/libstd/rt/unwind.rs

Lines changed: 90 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,9 @@ mod libunwind {
118118
exception: *_Unwind_Exception);
119119

120120
extern "C" {
121+
#[cfg(not(target_os = "android"))]
121122
pub fn _Unwind_RaiseException(exception: *_Unwind_Exception) -> _Unwind_Reason_Code;
123+
#[cfg(not(target_os = "android"))]
122124
pub fn _Unwind_DeleteException(exception: *_Unwind_Exception);
123125
}
124126
}
@@ -140,6 +142,7 @@ impl Unwinder {
140142
self.unwinding
141143
}
142144

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

@@ -174,6 +177,35 @@ impl Unwinder {
174177
}
175178
}
176179

180+
// FIXME #11147. On Android we're using C++ to do our unwinding because
181+
// our initial attempts at using libunwind directly don't seem to work
182+
// correctly. Would love to not be doing this.
183+
#[cfg(target_os = "android")]
184+
pub fn try(&mut self, f: ||) {
185+
use unstable::raw::Closure;
186+
187+
unsafe {
188+
let closure: Closure = cast::transmute(f);
189+
rust_cxx_try(try_fn, closure.code as *c_void, closure.env as *c_void);
190+
}
191+
192+
extern fn try_fn(code: *c_void, env: *c_void) {
193+
unsafe {
194+
let closure: || = cast::transmute(Closure {
195+
code: code as *(),
196+
env: env as *(),
197+
});
198+
closure();
199+
}
200+
}
201+
202+
extern {
203+
fn rust_cxx_try(f: extern "C" fn(*c_void, *c_void),
204+
code: *c_void,
205+
data: *c_void);
206+
}
207+
}
208+
177209
pub fn begin_unwind(&mut self, cause: ~Any) -> ! {
178210
rtdebug!("begin_unwind()");
179211

@@ -186,6 +218,11 @@ impl Unwinder {
186218
#[inline(never)]
187219
#[no_mangle]
188220
fn rust_fail() -> ! {
221+
throw();
222+
}
223+
224+
#[cfg(not(target_os = "android"))]
225+
fn throw() -> ! {
189226
unsafe {
190227
let exception = ~uw::_Unwind_Exception {
191228
exception_class: rust_exception_class(),
@@ -205,6 +242,15 @@ impl Unwinder {
205242
}
206243
}
207244
}
245+
246+
#[cfg(target_os = "android")]
247+
fn throw() -> ! {
248+
unsafe { rust_cxx_throw(); }
249+
250+
extern {
251+
fn rust_cxx_throw() -> !;
252+
}
253+
}
208254
}
209255

210256
pub fn result(&mut self) -> TaskResult {
@@ -218,6 +264,7 @@ impl Unwinder {
218264

219265
// Rust's exception class identifier. This is used by personality routines to
220266
// determine whether the exception was thrown by their own runtime.
267+
#[cfg(not(target_os = "android"))]
221268
fn rust_exception_class() -> uw::_Unwind_Exception_Class {
222269
// M O Z \0 R U S T -- vendor, language
223270
0x4d4f5a_00_52555354
@@ -243,12 +290,21 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class {
243290
// say "catch!".
244291

245292
extern "C" {
293+
#[cfg(not(target_os = "android"))]
246294
fn __gcc_personality_v0(version: c_int,
247295
actions: uw::_Unwind_Action,
248296
exception_class: uw::_Unwind_Exception_Class,
249297
ue_header: *uw::_Unwind_Exception,
250298
context: *uw::_Unwind_Context)
251299
-> uw::_Unwind_Reason_Code;
300+
301+
#[cfg(target_os = "android")]
302+
fn __gxx_personality_v0(version: c_int,
303+
actions: uw::_Unwind_Action,
304+
exception_class: uw::_Unwind_Exception_Class,
305+
ue_header: *uw::_Unwind_Exception,
306+
context: *uw::_Unwind_Context)
307+
-> uw::_Unwind_Reason_Code;
252308
}
253309

254310
#[lang="eh_personality"]
@@ -263,10 +319,8 @@ pub extern "C" fn rust_eh_personality(
263319
context: *uw::_Unwind_Context
264320
) -> uw::_Unwind_Reason_Code
265321
{
266-
unsafe {
267-
__gcc_personality_v0(version, actions, exception_class, ue_header,
268-
context)
269-
}
322+
native_personality(version, actions, exception_class, ue_header,
323+
context)
270324
}
271325

272326
#[no_mangle] // referenced from rust_try.ll
@@ -284,10 +338,38 @@ pub extern "C" fn rust_eh_personality_catch(
284338
uw::_URC_HANDLER_FOUND // catch!
285339
}
286340
else { // cleanup phase
287-
unsafe {
288-
__gcc_personality_v0(version, actions, exception_class, ue_header,
289-
context)
290-
}
341+
native_personality(version, actions, exception_class, ue_header,
342+
context)
343+
}
344+
}
345+
346+
#[cfg(not(target_os = "android"))]
347+
fn native_personality(
348+
version: c_int,
349+
actions: uw::_Unwind_Action,
350+
exception_class: uw::_Unwind_Exception_Class,
351+
ue_header: *uw::_Unwind_Exception,
352+
context: *uw::_Unwind_Context
353+
) -> uw::_Unwind_Reason_Code
354+
{
355+
unsafe {
356+
__gcc_personality_v0(version, actions, exception_class, ue_header,
357+
context)
358+
}
359+
}
360+
361+
#[cfg(target_os = "android")]
362+
fn native_personality(
363+
version: c_int,
364+
actions: uw::_Unwind_Action,
365+
exception_class: uw::_Unwind_Exception_Class,
366+
ue_header: *uw::_Unwind_Exception,
367+
context: *uw::_Unwind_Context
368+
) -> uw::_Unwind_Reason_Code
369+
{
370+
unsafe {
371+
__gxx_personality_v0(version, actions, exception_class, ue_header,
372+
context)
291373
}
292374
}
293375

src/libstd/rtdeps.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ extern {}
3131
#[link(name = "dl")]
3232
#[link(name = "log")]
3333
#[link(name = "m")]
34+
// FIXME #11147. We're using C++ for unwinding on Android
35+
// but should be using libunwind directly.
36+
#[link(name = "stdc++")]
3437
extern {}
3538

3639
#[cfg(target_os = "freebsd")]

src/rt/rust_cxx_glue.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
extern "C" void rust_cxx_throw() {
12+
throw 0;
13+
}
14+
15+
typedef void *(rust_try_fn)(void*, void*);
16+
17+
extern "C" void
18+
rust_cxx_try(rust_try_fn f, void *fptr, void *env) {
19+
try {
20+
f(fptr, env);
21+
} catch (int t) {
22+
}
23+
}

0 commit comments

Comments
 (0)