1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//! High level bindings to the SIMICS API in idiomatic Rust
#![deny(clippy::unwrap_used)]
#![deny(missing_docs)]
// NOTE: Unsafe code is allowed in the API, as it is wrapping a C API
pub mod api;
#[forbid(unsafe_code)]
pub mod error;
#[forbid(unsafe_code)]
pub mod log;
#[forbid(unsafe_code)]
pub mod util;
use std::{any::Any, panic::PanicHookInfo};
// Glob re-export the api and utilities
pub use api::*;
pub use error::*;
// NOTE: the log module only contains macros, so we don't need to re-export it
pub use util::*;
// Re-export simics_macro
pub use simics_macro::*;
#[cfg(feature = "global-allocator")]
#[global_allocator]
/// All crates using the SIMICS API must also use the SIMICS allocator as their
/// global allocator, hence we set it here
static GLOBAL: SimicsAlloc = SimicsAlloc;
/// Attempt to produce a `&str` message (with a default)
/// from a [`std::panic::catch_unwind`] payload.
/// See [module docs][crate] for usage.
pub fn panic_message(payload: &Box<dyn Any + Send>) -> &str {
imp::get_panic_message(payload.as_ref()).unwrap_or({
// Copy what rustc does in the default panic handler
"Box<dyn Any>"
})
}
/// Attempt to produce a `&str` message
/// from a [`std::panic::catch_unwind`] payload.
/// See [module docs][crate] for usage.
pub fn get_panic_message(payload: &Box<dyn Any + Send>) -> Option<&str> {
imp::get_panic_message(payload.as_ref())
}
/// Attempt to produce a `&str` message (with a default)
/// from a [`std::panic::PanicHookInfo`].
/// See [module docs][crate] for usage.
pub fn panic_info_message<'pi>(panic_info: &'pi PanicHookInfo<'_>) -> &'pi str {
imp::get_panic_message(panic_info.payload()).unwrap_or({
// Copy what rustc does in the default panic handler
"Box<dyn Any>"
})
}
/// Attempt to produce a `&str` message (with a default)
/// from a [`std::panic::PanicHookInfo`].
/// See [module docs][crate] for usage.
pub fn get_panic_info_message<'pi>(panic_info: &'pi PanicHookInfo<'_>) -> Option<&'pi str> {
imp::get_panic_message(panic_info.payload())
}
mod imp {
use std::any::Any;
/// Attempt to produce a message from a borrowed `dyn Any`. Note that care must be taken
/// when calling this to avoid a `Box<dyn Any>` being coerced to a `dyn Any` itself.
pub(super) fn get_panic_message(payload: &(dyn Any + Send)) -> Option<&str> {
// taken from: https://github.com/rust-lang/rust/blob/4b9f4b221b92193c7e95b1beb502c6eb32c3b613/library/std/src/panicking.rs#L194-L200
match payload.downcast_ref::<&'static str>() {
Some(msg) => Some(*msg),
None => match payload.downcast_ref::<String>() {
Some(msg) => Some(msg.as_str()),
// Copy what rustc does in the default panic handler
None => None,
},
}
}
}
/// Panic handler for Simics modules.
///
/// This will log the panic message and then call `SIM_quit` to exit the simulator
/// (backtraces are not available in the simulator, so we don't bother trying to print
/// one). It is usually automatically installed by any #[simics_init] attribute macro,
/// but can be manually installed using `std::panic::set_hook`.
pub fn panic_handler(info: &PanicHookInfo<'_>) -> ! {
let message = panic_info_message(info);
if let Some(location) = info.location() {
eprintln!("{message}: {location}");
} else {
eprintln!("{message}");
}
unsafe { crate::sys::SIM_quit(1) }
}