Skip to content

[debug] Add manticore::debug #108

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ version = "0.3"
optional = true
features = ["arbitrary-derive"]

[dependencies.log]
version = "0.4"
optional = true

[dependencies.ring]
version = "0.16.11"
optional = true
Expand All @@ -41,13 +45,15 @@ default-features = false
features = ["derive"]

[dev-dependencies]
ctor = "0.1"
env_logger = "0.8"
pretty_assertions = "0.6.1"
ring = "0.16.11"
serde_json = "1.0"
testutil = { path = "testutil" }

[features]
default = ["std", "ring"]
default = ["std", "ring", "log"]

# Enables deriving `arbitrary::Arbitrary` for various manticore types.
arbitrary-derive = ["libfuzzer-sys", "std"]
Expand Down
2 changes: 2 additions & 0 deletions src/cert/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ impl From<untrusted::EndOfInput> for Error {
}
}

debug_from!(Error => io::Error, untrusted::EndOfInput);

impl<'cert> Cert<'cert> {
/// Parses `cert`, producing a parsed certificate in the given format.
///
Expand Down
202 changes: 202 additions & 0 deletions src/debug.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

//! Debug-logging functionality.
//!
//! This module is still present when the `log` feature is disabled, but all
//! logging operations are redacted. Redaction completely compiles out log
//! statements: not even the format strings remain in the final binary.
//!
//! Manticore code *should not* call into the [`log`] crate directly outside of
//! this module.

// TODO: Remove this once we start using these macros in Manticore.
#![allow(unused)]

use core::fmt;

#[cfg(doc)]
use __raw_log as log;

/// A wrapped Manticore error.
///
/// This type should always be referred to as `manticore::Error`. It represents
/// an error with extra (potentially redacted) information attached. This type
/// cannot be directly created by users of the library.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Error<E> {
inner: E,
}

impl<E> Error<E> {
/// Creates a new `Error`. This function is an implementation detail,
/// and should not be called by users.
#[doc(hidden)]
pub fn __new(inner: E) -> Self {
Self { inner }
}

/// Transforms the wrapper error by way of an [`Into`] conversion.
///
/// Generally, this function should not be necessary, because Manticore-
/// defined error types manually implement the relevant [`From`]
/// implementations for `manticore::Error`, which in turn call `cast()`.
pub fn cast<F>(self) -> Error<F>
where
F: From<E>,
{
Error {
inner: self.inner.into(),
}
}

/// Gets the wrapper error.
pub fn into_inner(self) -> E {
self.inner
}
}

impl<E> AsRef<E> for Error<E> {
fn as_ref(&self) -> &E {
&self.inner
}
}

impl<E> AsMut<E> for Error<E> {
fn as_mut(&mut self) -> &mut E {
&mut self.inner
}
}

impl<E: fmt::Display> fmt::Display for Error<E> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
struct DisplayAsDebug<'a, E>(&'a E);
impl<E: fmt::Display> fmt::Debug for DisplayAsDebug<'_, E> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}

f.debug_struct("manticore::Error")
.field("inner", &DisplayAsDebug(&self.inner))
.finish()
}
}

/// Generates `From` implementations for `manticore::Error`.
///
/// We would like to write this `impl`:
/// ```compile_fail
/// # use manticore::Error;
/// impl<E1, E2> From<Error<E1>> for Error<E2> where E2: From<E1> {
/// fn from(e: Error<E1>) -> Error<E2> {
/// e.cast()
/// }
/// }
/// ```
///
/// Unfortunately, the trait coherence rules mean that for `E1 == E2`,
/// this conflicts with the standard library's `impl<T> From<T> for T`
/// impl. We work around this by calling this macro for every Manticore
/// error definition that has `From` impls.
macro_rules! debug_from {
($e:ty => $($f:ty),+ $(,)?) => {$(
impl From<$crate::Error<$f>> for $crate::Error<$e> {
fn from(e: $crate::Error<$f>) -> Self {
e.cast()
}
}
)*}
}

/// Checks a condition, logging if it fails.
///
/// If the condition does not hold, constructs the given error, logs it, and
/// returns out of the current function with it.
macro_rules! check {
($cond:expr, $error:expr) => {
if !$cond {
let error = $error;
trace!(
error,
"check failure: `{}`; returned {:?}"
stringify!($cond), error,
)?;
}
}
}

/// Logs a newly-created error value and returns it.
///
/// This macro is the main way to generate [`Error`] values.
///
/// For example, instead of writing `foo.ok_or(MyError)`, instead write
/// `foo.ok_or_else(|| trace!(MyError))`.
macro_rules! trace {
($error:expr, $($format:tt)+) => {{
error!($($format)+);
$crate::debug::Error::__new($error)
}};
($error:expr) => {{
let error = $error;
error!("generated error: `{:?}`", error);
$crate::debug::Error::__new(error)
}};
}

/// Redactable version of [`log::info!()`].
macro_rules! info {
($($args:tt)*) => {
#[cfg(feature = "log")]
let _ = __raw_log::info!($($args)*);
}
}

/// Redactable version of [`log::warn!()`].
macro_rules! warn {
($($args:tt)*) => {
#[cfg(feature = "log")]
let _ = __raw_log::warn!($($args)*);
}
}

/// Redactable version of [`log::error!()`].
macro_rules! error {
($($args:tt)*) => {
#[cfg(feature = "log")]
let _ = __raw_log::error!($($args)*);
}
}

/// Set up some life-before-main code that initializes a basic logger for the
/// test binary.
///
/// This needs to happen here, since the test binary's main() cannot be
/// overriden.
#[cfg(test)]
#[ctor::ctor]
fn init_test_logger() {
env_logger::builder()
.format(move |_, record| {
use std::io::Write;

let thread = std::thread::current();
let name = thread.name().unwrap_or("<unknown>");
for line in record.args().to_string().trim().lines() {
// NOTE: we explicitly print to stderr, since this allows the
// Rust test harness to supress log statements originating from
// passing tests.
eprintln!(
"[{level}({thread}) {file}:{line}] {msg}",
level = record.level(),
thread = name,
file = record.file().unwrap_or("<unknown>"),
line = record.line().unwrap_or(0),
msg = line,
)
}
Ok(())
})
.init();
}
1 change: 1 addition & 0 deletions src/hardware/flash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ impl From<OutOfMemory> for Error {
Error::Internal
}
}
debug_from!(Error => OutOfMemory);

/// Provides access to a flash-like storage device.
///
Expand Down
19 changes: 19 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
//! - `ring` (default) enables the [`crypto::ring` module], which provides
//! software implementations for cryptography traits used by `manticore`.
//! This feature is not intended for on-device use-cases either.
//! - `log` (default) enables debug logging throughout manticore, via the `log`
//! crate. This feature can be disabled to redact all logging.
//! - `serde` enables implementations of `serde`'s (de)serialization traits.
//! - `inject-alloc` makes it possible to replace borrowed content in some
//! structs with allocated content. This is mostly useful for tooling that
Expand All @@ -49,6 +51,14 @@
#![deny(unused)]
#![deny(unsafe_code)]

// Pull in the `log` crate via a different name, to help prevent code from
// accidentally using it without going through the redactable versions in
// `debug`.
#[cfg(feature = "log")]
extern crate log as __raw_log;
#[macro_use]
mod debug;

#[macro_use]
pub mod protocol;

Expand All @@ -63,3 +73,12 @@ pub mod manifest;
pub mod mem;
pub mod net;
pub mod server;

pub use debug::Error;

/// [`Result`] type to use throughout Manticore, which incorporates the
/// [`manticore::Error`] type.
///
/// [`Result`]: std::result::Result
/// [`manticore::Error`]: crate::Error
pub type Result<T, E> = core::result::Result<T, Error<E>>;
2 changes: 2 additions & 0 deletions src/manifest/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ impl From<sha256::Error> for Error {
}
}

debug_from!(Error => io::Error, flash::Error, OutOfMemory, sig::Error, sha256::Error);

/// A manifest type.
///
/// A type that implements this trait is not itself a "parsed" instance of the
Expand Down
2 changes: 2 additions & 0 deletions src/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ impl From<io::Error> for Error {
}
}

debug_from!(Error => io::Error);

/// Represents a physical port that can be used to interact with host devices.
///
/// This trait provides a generic mechanism for recieving and responding to
Expand Down
11 changes: 10 additions & 1 deletion src/protocol/wire.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ impl From<OutOfMemory> for FromWireError {
}
}

debug_from!(FromWireError => io::Error, OutOfMemory);

/// A type which can be serialized into the Cerberus wire format.
pub trait ToWire: Sized {
/// Serializes `self` into `w`.
Expand All @@ -76,6 +78,8 @@ impl From<io::Error> for ToWireError {
}
}

debug_from!(ToWireError => io::Error);

/// Represents a C-like enum that can be converted to and from a wire
/// representation as well as to and from a string representation.
///
Expand Down Expand Up @@ -231,7 +235,12 @@ macro_rules! wire_enum {
impl core::str::FromStr for $name {
type Err = $crate::protocol::wire::WireEnumFromStrError;

fn from_str(s: &str) -> Result<Self, $crate::protocol::wire::WireEnumFromStrError> {
fn from_str(
s: &str
) -> core::result::Result<
Self,
$crate::protocol::wire::WireEnumFromStrError
> {
use $crate::protocol::wire::WireEnum;

match $name::from_name(s) {
Expand Down
2 changes: 2 additions & 0 deletions src/server/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ impl From<net::Error> for Error {
}
}

debug_from!(Error => FromWireError, ToWireError, net::Error);

/// A request handler builder.
///
/// See the module documentation for more information.
Expand Down