From f41d0a4c98a2bedf8495f413a51a98ffabb1968d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thi=C3=A9baud=20Weksteen?= Date: Mon, 15 Mar 2021 11:21:39 +0100 Subject: [PATCH] android: set abort message Android has the ability to supply an abort message [1]. This message is automatically included in the debug trace, which helps debugging [2]. Modify panic_abort to populate this message before calling abort(). [1] https://android.googlesource.com/platform/bionic/+/master/libc/include/android/set_abort_message.h [2] https://source.android.com/devices/tech/debug/native-crash --- Cargo.lock | 1 + library/panic_abort/Cargo.toml | 1 + library/panic_abort/src/android.rs | 44 ++++++++++++++++++++++++++++++ library/panic_abort/src/lib.rs | 7 +++++ 4 files changed, 53 insertions(+) create mode 100644 library/panic_abort/src/android.rs diff --git a/Cargo.lock b/Cargo.lock index e5a7b7d9b6056..71831325b324f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2471,6 +2471,7 @@ dependencies = [ name = "panic_abort" version = "0.0.0" dependencies = [ + "alloc", "cfg-if 0.1.10", "compiler_builtins", "core", diff --git a/library/panic_abort/Cargo.toml b/library/panic_abort/Cargo.toml index caa89aa30d0bb..bdab664cd64fc 100644 --- a/library/panic_abort/Cargo.toml +++ b/library/panic_abort/Cargo.toml @@ -13,6 +13,7 @@ bench = false doc = false [dependencies] +alloc = { path = "../alloc" } cfg-if = { version = "0.1.8", features = ['rustc-dep-of-std'] } core = { path = "../core" } libc = { version = "0.2", default-features = false } diff --git a/library/panic_abort/src/android.rs b/library/panic_abort/src/android.rs new file mode 100644 index 0000000000000..6c9135e6610ac --- /dev/null +++ b/library/panic_abort/src/android.rs @@ -0,0 +1,44 @@ +use alloc::string::String; +use alloc::vec::Vec; +use core::mem::transmute; +use core::panic::BoxMeUp; + +const ANDROID_SET_ABORT_MESSAGE: &[u8] = b"android_set_abort_message\0"; +type SetAbortMessageType = unsafe extern "C" fn(*const libc::c_char) -> (); + +// Forward the abort message to libc's android_set_abort_message. The fallible allocator is used +// to avoid panicking, as this function may already be called as part of a failed allocation. +// +// Weakly resolve the symbol for android_set_abort_message. This function is only available +// for API >= 21. +pub(crate) unsafe fn android_set_abort_message(payload: *mut &mut dyn BoxMeUp) { + let func_addr = + libc::dlsym(libc::RTLD_DEFAULT, ANDROID_SET_ABORT_MESSAGE.as_ptr() as *const libc::c_char) + as usize; + if func_addr == 0 { + return; + } + + let payload = (*payload).get(); + let msg = match payload.downcast_ref::<&'static str>() { + Some(msg) => msg.as_bytes(), + None => match payload.downcast_ref::() { + Some(msg) => msg.as_bytes(), + None => &[], + }, + }; + if msg.is_empty() { + return; + } + + let size = msg.len() + 1; + let mut v = Vec::new(); + if v.try_reserve(size).is_err() { + return; + } + + v.extend(msg); + v.push(0); + let func = transmute::(func_addr); + func(v.as_ptr() as *const libc::c_char); +} diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs index eb2277d8baacd..64491474f664c 100644 --- a/library/panic_abort/src/lib.rs +++ b/library/panic_abort/src/lib.rs @@ -18,6 +18,9 @@ #![feature(staged_api)] #![feature(rustc_attrs)] #![feature(asm)] +#![cfg_attr(target_os = "android", feature(try_reserve))] +#[cfg(target_os = "android")] +mod android; use core::any::Any; use core::panic::BoxMeUp; @@ -31,6 +34,10 @@ pub unsafe extern "C" fn __rust_panic_cleanup(_: *mut u8) -> *mut (dyn Any + Sen // "Leak" the payload and shim to the relevant abort on the platform in question. #[rustc_std_internal_symbol] pub unsafe extern "C" fn __rust_start_panic(_payload: *mut &mut dyn BoxMeUp) -> u32 { + // Android has the ability to attach a message as part of the abort. + #[cfg(target_os = "android")] + android::android_set_abort_message(_payload); + abort(); cfg_if::cfg_if! {