Browse Source

Merge pull request #36 from FenrirWolf/errDisp

Display panics via the Error applet
pull/10/head
Ronald Kinard 8 years ago committed by GitHub
parent
commit
23e9e4ef98
  1. 3
      ctr-std/Cargo.toml
  2. 8
      ctr-std/src/macros.rs
  3. 90
      ctr-std/src/panicking.rs
  4. 2
      ctru-sys/src/bindings.rs

3
ctr-std/Cargo.toml

@ -15,3 +15,6 @@ default-features = false
[dependencies.ctru-sys] [dependencies.ctru-sys]
path = "../ctru-sys" path = "../ctru-sys"
[features]
citra = []

8
ctr-std/src/macros.rs

@ -43,8 +43,8 @@ macro_rules! panic {
($msg:expr) => ({ ($msg:expr) => ({
$crate::rt::begin_panic($msg, { $crate::rt::begin_panic($msg, {
// static requires less code at runtime, more constant data // static requires less code at runtime, more constant data
static _FILE_LINE: (&'static str, u32) = (file!(), line!()); static _FILE_LINE_COL: (&'static str, u32, u32) = (file!(), line!(), column!());
&_FILE_LINE &_FILE_LINE_COL
}) })
}); });
($fmt:expr, $($arg:tt)+) => ({ ($fmt:expr, $($arg:tt)+) => ({
@ -53,8 +53,8 @@ macro_rules! panic {
// used inside a dead function. Just `#[allow(dead_code)]` is // used inside a dead function. Just `#[allow(dead_code)]` is
// insufficient, since the user may have // insufficient, since the user may have
// `#[forbid(dead_code)]` and which cannot be overridden. // `#[forbid(dead_code)]` and which cannot be overridden.
static _FILE_LINE: (&'static str, u32) = (file!(), line!()); static _FILE_LINE_COL: (&'static str, u32, u32) = (file!(), line!(), column!());
&_FILE_LINE &_FILE_LINE_COL
}) })
}); });
} }

90
ctr-std/src/panicking.rs

@ -15,11 +15,10 @@ use io::prelude::*;
use any::Any; use any::Any;
use cell::RefCell; use cell::RefCell;
use fmt; use fmt::{self, Display};
use mem; use mem;
use ptr; use ptr;
use raw; use raw;
use __core::fmt::Display;
thread_local! { thread_local! {
pub static LOCAL_STDERR: RefCell<Option<Box<Write + Send>>> = { pub static LOCAL_STDERR: RefCell<Option<Box<Write + Send>>> = {
@ -33,8 +32,11 @@ pub extern fn eh_personality() {}
/// Entry point of panic from the libcore crate. /// Entry point of panic from the libcore crate.
#[lang = "panic_fmt"] #[lang = "panic_fmt"]
pub extern fn rust_begin_panic(msg: fmt::Arguments, file: &'static str, line: u32) -> ! { pub extern fn rust_begin_panic(msg: fmt::Arguments,
begin_panic_fmt(&msg, &(file, line)) file: &'static str,
line: u32,
col: u32) -> ! {
begin_panic_fmt(&msg, &(file, line, col))
} }
/// The entry point for panicking with a formatted message. /// The entry point for panicking with a formatted message.
@ -47,46 +49,76 @@ pub extern fn rust_begin_panic(msg: fmt::Arguments, file: &'static str, line: u3
reason = "used by the panic! macro", reason = "used by the panic! macro",
issue = "0")] issue = "0")]
#[inline(never)] #[cold] #[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; use fmt::Write;
let mut s = String::new(); let mut s = String::new();
let _ = s.write_fmt(*msg); 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 // Citra doesn't support the Error applet yet
/// and then crash or hang the application #[cfg(feature = "citra")]
#[inline(never)] #[unstable(feature = "libstd_sys_internals",
#[cold] reason = "used by the panic! macro",
pub fn begin_panic<M: Any + Send + Display>(msg: M, file_line: &(&'static str, u32)) -> ! { issue = "0")]
#[inline(never)] #[cold]
pub fn begin_panic<M: Any + Send + Display>(msg: M, file_line_col: &(&'static str, u32, u32)) -> ! {
let msg = Box::new(msg); let msg = Box::new(msg);
let (file, line) = *file_line; let (file, line, col) = *file_line_col;
use libctru::consoleInit; // 3DS-specific code begins here
use libctru::gfxScreen_t; use libctru::{consoleInit, gfxScreen_t};
unsafe {
// set up a new console, overwriting whatever was on the top screen // set up a new console, overwriting whatever was on the top screen
// before we started panicking // before we started panicking
let _console = unsafe { consoleInit(gfxScreen_t::GFX_TOP, ptr::null_mut()) }; let _console = consoleInit(gfxScreen_t::GFX_TOP, ptr::null_mut());
println!("PANIC in {} at line {}:", file, line); println!("thread '{}' panicked at '{}', {}:{}:{}",
println!(" {}", msg); "<unnamed>", msg, file, line, col);
// Terminate the process to ensure that all threads cease when panicking. // Citra seems to ignore calls to svcExitProcess, and libc::abort()
unsafe { ::libctru::svcExitProcess() } // 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
// On 3DS hardware, code execution will have terminated at the above function. // 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.
// 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 { } loop { }
} }
}
#[cfg(not(feature = "citra"))]
#[unstable(feature = "libstd_sys_internals",
reason = "used by the panic! macro",
issue = "0")]
#[inline(never)] #[cold]
pub fn begin_panic<M: Any + Send + Display>(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::{errorInit, errorText, errorDisp, svcExitProcess,
errorConf, errorType, CFG_Language};
use libc;
unsafe {
// Setup error payload
let error_text = format!("thread '{}' panicked at '{}', {}:{}:{}",
"<unnamed>", 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
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. /// Invoke a closure, capturing the cause of an unwinding panic if one occurs.
pub unsafe fn try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<Any + Send>> { pub unsafe fn try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<Any + Send>> {

2
ctru-sys/src/bindings.rs

@ -1844,7 +1844,7 @@ extern "C" {
pub fn svcOpenProcess(process: *mut Handle, processId: u32) -> Result; pub fn svcOpenProcess(process: *mut Handle, processId: u32) -> Result;
} }
extern "C" { extern "C" {
pub fn svcExitProcess(); pub fn svcExitProcess() -> !;
} }
extern "C" { extern "C" {
pub fn svcTerminateProcess(process: Handle) -> Result; pub fn svcTerminateProcess(process: Handle) -> Result;

Loading…
Cancel
Save