From f7cb0d88bed0037642989180add6223a7eec86b9 Mon Sep 17 00:00:00 2001 From: Fenrir Date: Mon, 24 Jul 2017 19:35:49 -0600 Subject: [PATCH 1/4] Fix missing stability attribute --- ctr-std/src/panicking.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ctr-std/src/panicking.rs b/ctr-std/src/panicking.rs index 0de44be..57aa563 100644 --- a/ctr-std/src/panicking.rs +++ b/ctr-std/src/panicking.rs @@ -57,6 +57,10 @@ pub fn begin_panic_fmt(msg: &fmt::Arguments, file_line: &(&'static str, u32)) -> /// We don't have stack unwinding, so all we do is print the panic message /// and then crash or hang the application +#[unstable(feature = "libstd_sys_internals", + reason = "used by the panic! macro", + issue = "0")] +#[inline(never)] #[cold] #[inline(never)] #[cold] pub fn begin_panic(msg: M, file_line: &(&'static str, u32)) -> ! { From 59b0b6de00ea8212e9db455b588d0ff102680e3e Mon Sep 17 00:00:00 2001 From: Fenrir Date: Mon, 24 Jul 2017 19:48:21 -0600 Subject: [PATCH 2/4] Update to new panic ABI --- ctr-std/src/macros.rs | 8 ++++---- ctr-std/src/panicking.rs | 17 +++++++++-------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/ctr-std/src/macros.rs b/ctr-std/src/macros.rs index 0ce6b0a..21a7da9 100644 --- a/ctr-std/src/macros.rs +++ b/ctr-std/src/macros.rs @@ -43,8 +43,8 @@ macro_rules! panic { ($msg:expr) => ({ $crate::rt::begin_panic($msg, { // static requires less code at runtime, more constant data - static _FILE_LINE: (&'static str, u32) = (file!(), line!()); - &_FILE_LINE + static _FILE_LINE_COL: (&'static str, u32, u32) = (file!(), line!(), column!()); + &_FILE_LINE_COL }) }); ($fmt:expr, $($arg:tt)+) => ({ @@ -53,8 +53,8 @@ macro_rules! panic { // used inside a dead function. Just `#[allow(dead_code)]` is // insufficient, since the user may have // `#[forbid(dead_code)]` and which cannot be overridden. - static _FILE_LINE: (&'static str, u32) = (file!(), line!()); - &_FILE_LINE + static _FILE_LINE_COL: (&'static str, u32, u32) = (file!(), line!(), column!()); + &_FILE_LINE_COL }) }); } diff --git a/ctr-std/src/panicking.rs b/ctr-std/src/panicking.rs index 57aa563..422eef7 100644 --- a/ctr-std/src/panicking.rs +++ b/ctr-std/src/panicking.rs @@ -33,8 +33,11 @@ pub extern fn eh_personality() {} /// Entry point of panic from the libcore crate. #[lang = "panic_fmt"] -pub extern fn rust_begin_panic(msg: fmt::Arguments, file: &'static str, line: u32) -> ! { - begin_panic_fmt(&msg, &(file, line)) +pub extern fn rust_begin_panic(msg: fmt::Arguments, + file: &'static str, + line: u32, + col: u32) -> ! { + begin_panic_fmt(&msg, &(file, line, col)) } /// The entry point for panicking with a formatted message. @@ -47,12 +50,12 @@ pub extern fn rust_begin_panic(msg: fmt::Arguments, file: &'static str, line: u3 reason = "used by the panic! macro", issue = "0")] #[inline(never)] #[cold] -pub fn begin_panic_fmt(msg: &fmt::Arguments, file_line: &(&'static str, u32)) -> ! { +pub fn begin_panic_fmt(msg: &fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { use fmt::Write; let mut s = String::new(); let _ = s.write_fmt(*msg); - begin_panic(s, file_line); + begin_panic(s, file_line_col); } /// We don't have stack unwinding, so all we do is print the panic message @@ -61,11 +64,9 @@ pub fn begin_panic_fmt(msg: &fmt::Arguments, file_line: &(&'static str, u32)) -> reason = "used by the panic! macro", issue = "0")] #[inline(never)] #[cold] -#[inline(never)] -#[cold] -pub fn begin_panic(msg: M, file_line: &(&'static str, u32)) -> ! { +pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u32)) -> ! { let msg = Box::new(msg); - let (file, line) = *file_line; + let (file, line, col) = *file_line_col; use libctru::consoleInit; use libctru::gfxScreen_t; From d36057aee01205bd8062289cf95ba3ef198fdd4d Mon Sep 17 00:00:00 2001 From: Fenrir Date: Mon, 24 Jul 2017 22:50:08 -0600 Subject: [PATCH 3/4] Use Error applet to display panics --- ctr-std/src/panicking.rs | 48 +++++++++++++++++++--------------------- ctru-sys/src/bindings.rs | 2 +- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/ctr-std/src/panicking.rs b/ctr-std/src/panicking.rs index 422eef7..6d47fd3 100644 --- a/ctr-std/src/panicking.rs +++ b/ctr-std/src/panicking.rs @@ -15,11 +15,10 @@ use io::prelude::*; use any::Any; use cell::RefCell; -use fmt; +use fmt::{self, Display}; use mem; use ptr; use raw; -use __core::fmt::Display; thread_local! { pub static LOCAL_STDERR: RefCell>> = { @@ -68,29 +67,28 @@ pub fn begin_panic(msg: M, file_line_col: &(&'static st let msg = Box::new(msg); let (file, line, col) = *file_line_col; - use libctru::consoleInit; - use libctru::gfxScreen_t; - - // set up a new console, overwriting whatever was on the top screen - // before we started panicking - let _console = unsafe { consoleInit(gfxScreen_t::GFX_TOP, ptr::null_mut()) }; - - println!("PANIC in {} at line {}:", file, line); - println!(" {}", msg); - - // Terminate the process to ensure that all threads cease when panicking. - unsafe { ::libctru::svcExitProcess() } - - // On 3DS hardware, code execution will have terminated at the above function. - // - // Citra, however, will simply ignore the function and control flow becomes trapped - // in the following loop instead. However, this means that other threads may continue - // to run after a panic! - // - // This is actually a better outcome than calling libc::abort(), which seemingly - // causes the emulator to step into unreachable code, prompting it to freak out - // and spew endless nonsense into the console log. - loop {} + // 3DS-specific code begins here + use libctru::{errorInit, errorText, errorDisp, svcExitProcess, + errorConf, errorType, CFG_Language}; + use libc; + + unsafe { + // Setup error payload + let error_text = format!("thread '{}' panicked at '{}', {}:{}:{}", + "", msg, file, line, col); + let mut error_conf: errorConf = mem::uninitialized(); + errorInit(&mut error_conf, + errorType::ERROR_TEXT_WORD_WRAP, + CFG_Language::CFG_LANGUAGE_EN); + errorText(&mut error_conf, error_text.as_ptr() as *const libc::c_char); + + // Display error via Error applet + errorDisp(&mut error_conf); + + // Now that we're all done printing, it's time to exit the program. + // We don't have stack unwinding yet, so we just forcibly end the process + svcExitProcess() + } } /// Invoke a closure, capturing the cause of an unwinding panic if one occurs. diff --git a/ctru-sys/src/bindings.rs b/ctru-sys/src/bindings.rs index 7acfa38..2afcb00 100644 --- a/ctru-sys/src/bindings.rs +++ b/ctru-sys/src/bindings.rs @@ -1844,7 +1844,7 @@ extern "C" { pub fn svcOpenProcess(process: *mut Handle, processId: u32) -> Result; } extern "C" { - pub fn svcExitProcess(); + pub fn svcExitProcess() -> !; } extern "C" { pub fn svcTerminateProcess(process: Handle) -> Result; From cbe41e5304bee049fa9fa7293c2486b13b4a856e Mon Sep 17 00:00:00 2001 From: Fenrir Date: Tue, 25 Jul 2017 10:49:26 -0600 Subject: [PATCH 4/4] Enable old panic behavior for Citra --- ctr-std/Cargo.toml | 3 +++ ctr-std/src/panicking.rs | 37 +++++++++++++++++++++++++++++++++---- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/ctr-std/Cargo.toml b/ctr-std/Cargo.toml index 1a883f5..c4cbce4 100644 --- a/ctr-std/Cargo.toml +++ b/ctr-std/Cargo.toml @@ -15,3 +15,6 @@ default-features = false [dependencies.ctru-sys] path = "../ctru-sys" + +[features] +citra = [] diff --git a/ctr-std/src/panicking.rs b/ctr-std/src/panicking.rs index 6d47fd3..097be6f 100644 --- a/ctr-std/src/panicking.rs +++ b/ctr-std/src/panicking.rs @@ -57,8 +57,37 @@ pub fn begin_panic_fmt(msg: &fmt::Arguments, file_line_col: &(&'static str, u32, begin_panic(s, file_line_col); } -/// We don't have stack unwinding, so all we do is print the panic message -/// and then crash or hang the application +// Citra doesn't support the Error applet yet +#[cfg(feature = "citra")] +#[unstable(feature = "libstd_sys_internals", + reason = "used by the panic! macro", + issue = "0")] +#[inline(never)] #[cold] +pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u32)) -> ! { + let msg = Box::new(msg); + let (file, line, col) = *file_line_col; + + // 3DS-specific code begins here + use libctru::{consoleInit, gfxScreen_t}; + + unsafe { + // set up a new console, overwriting whatever was on the top screen + // before we started panicking + let _console = consoleInit(gfxScreen_t::GFX_TOP, ptr::null_mut()); + + println!("thread '{}' panicked at '{}', {}:{}:{}", + "", msg, file, line, col); + + // Citra seems to ignore calls to svcExitProcess, and libc::abort() + // causes it to lock up and fill the console with endless debug statements. + // So instead of terminating the program, we just let it spin in the following + // loop. This means that any background threads might continue to run after + // this thread panics, but there's not a lot we can do about that currently. + loop { } + } +} + +#[cfg(not(feature = "citra"))] #[unstable(feature = "libstd_sys_internals", reason = "used by the panic! macro", issue = "0")] @@ -75,14 +104,14 @@ pub fn begin_panic(msg: M, file_line_col: &(&'static st unsafe { // Setup error payload let error_text = format!("thread '{}' panicked at '{}', {}:{}:{}", - "", msg, file, line, col); + "", msg, file, line, col); let mut error_conf: errorConf = mem::uninitialized(); errorInit(&mut error_conf, errorType::ERROR_TEXT_WORD_WRAP, CFG_Language::CFG_LANGUAGE_EN); errorText(&mut error_conf, error_text.as_ptr() as *const libc::c_char); - // Display error via Error applet + // Display error errorDisp(&mut error_conf); // Now that we're all done printing, it's time to exit the program.