Skip to content

Commit b11a21b

Browse files
mcykesyog
authored andcommitted
[debug] Add manticore::debug
The `debug` module is intended to hold debugging helpers, to make debugging Manticore tests easier. This will include: - Redactable logging. - Error creation capture (e.g., capturing where `Err` variants are created). The generated logs can be captured by tests, and eventually get returned through Cerberus's "debug log" functionality. Signed-off-by: Miguel Young de la Sota <[email protected]>
1 parent 496e8cc commit b11a21b

File tree

3 files changed

+124
-1
lines changed

3 files changed

+124
-1
lines changed

Cargo.toml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ version = "0.3"
3030
optional = true
3131
features = ["arbitrary-derive"]
3232

33+
[dependencies.log]
34+
version = "0.4"
35+
optional = true
36+
3337
[dependencies.ring]
3438
version = "0.16.11"
3539
optional = true
@@ -42,13 +46,15 @@ default-features = false
4246
features = ["derive"]
4347

4448
[dev-dependencies]
49+
ctor = "0.1"
50+
env_logger = "0.8"
4551
pretty_assertions = "0.6.1"
4652
ring = "0.16.11"
4753
serde_json = "1.0"
4854
testutil = { path = "testutil" }
4955

5056
[features]
51-
default = ["std", "ring"]
57+
default = ["std", "ring", "log"]
5258

5359
# Enables deriving `arbitrary::Arbitrary` for various manticore types.
5460
arbitrary-derive = ["libfuzzer-sys", "std"]

src/debug.rs

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// Copyright lowRISC contributors.
2+
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
//! Debug-logging functionality.
6+
//!
7+
//! This module is still present when the `log` feature is disabled, but all
8+
//! logging operations are redacted. Redaction completely compiles out log
9+
//! statements: not even the format strings remain in the final binary.
10+
//!
11+
//! Manticore code *should not* call into the [`log`] crate directly outside of
12+
//! this module.
13+
14+
#![allow(unused)]
15+
16+
#[cfg(doc)]
17+
use __raw_log as log;
18+
19+
/// Checks a condition, logging if it fails.
20+
///
21+
/// If the condition does not hold, constructs the given error, logs it, and
22+
/// returns out of the current function with it.
23+
macro_rules! check {
24+
($cond:expr, $error:expr) => {
25+
if !$cond {
26+
let e = $error;
27+
error!(
28+
"check failure: `{}`; returned {:?}"
29+
stringify!($cond), e
30+
);
31+
return Err(e);
32+
}
33+
}
34+
}
35+
36+
/// Logs a newly-created error value and returns it.
37+
///
38+
/// This function is useful for marking where errors originate in tests.
39+
/// For example, instead of writing `foo.ok_or(MyError)`, instead write
40+
/// `foo.ok_or_else(|| trace!(MyError))`.
41+
macro_rules! trace {
42+
($error:expr, $($format:tt)+) => {{
43+
error!($($format)+);
44+
$error
45+
}};
46+
($error:expr) => {{
47+
let e = $error;
48+
error!("generated error: `{:?}`", e);
49+
e
50+
}};
51+
}
52+
53+
/// Redactable version of [`log::info!()`].
54+
macro_rules! info {
55+
($($args:tt)*) => {
56+
#[cfg(feature = "log")]
57+
let _ = __raw_log::info!($($args)*);
58+
}
59+
}
60+
61+
/// Redactable version of [`log::warn!()`].
62+
macro_rules! warn {
63+
($($args:tt)*) => {
64+
#[cfg(feature = "log")]
65+
let _ = __raw_log::warn!($($args)*);
66+
}
67+
}
68+
69+
/// Redactable version of [`log::error!()`].
70+
macro_rules! error {
71+
($($args:tt)*) => {
72+
#[cfg(feature = "log")]
73+
let _ = __raw_log::error!($($args)*);
74+
}
75+
}
76+
77+
/// Set up some life-before-main code that initializes a basic logger for the
78+
/// test binary.
79+
///
80+
/// This needs to happen here, since the test binary's main() cannot be
81+
/// overriden.
82+
#[cfg(test)]
83+
#[ctor::ctor]
84+
fn init_test_logger() {
85+
env_logger::builder()
86+
.format(move |_, record| {
87+
use std::io::Write;
88+
89+
let thread = std::thread::current();
90+
let name = thread.name().unwrap_or("<unknown>");
91+
for line in record.args().to_string().trim().lines() {
92+
// NOTE: we explicitly print to stderr, since this allows the
93+
// Rust test harness to supress log statements originating from
94+
// passing tests.
95+
eprintln!(
96+
"[{level}({thread}) {file}:{line}] {msg}",
97+
level = record.level(),
98+
thread = name,
99+
file = record.file().unwrap_or("<unknown>"),
100+
line = record.line().unwrap_or(0),
101+
msg = line,
102+
)
103+
}
104+
Ok(())
105+
})
106+
.init();
107+
}

src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
//! - `ring` (default) enables the [`crypto::ring` module], which provides
3131
//! software implementations for cryptography traits used by `manticore`.
3232
//! This feature is not intended for on-device use-cases either.
33+
//! - `log` (default) enables debug logging throughout manticore, via the `log`
34+
//! crate. This feature can be disabled to redact all logging.
3335
//! - `serde` enables implementations of `serde`'s (de)serialization traits.
3436
//! - `arbitrary-derive` enables implementations of fuzz-testing-related
3537
//! traits.
@@ -46,8 +48,16 @@
4648
#![deny(unused)]
4749
#![deny(unsafe_code)]
4850

51+
// Pull in the `log` crate via a different name, to help prevent code from
52+
// accidentally using it without going through the redactable versions in
53+
// `debug`.
54+
#[cfg(feature = "log")]
55+
extern crate log as __raw_log;
56+
4957
#[macro_use]
5058
pub mod protocol;
59+
#[macro_use]
60+
mod debug;
5161

5262
#[cfg(feature = "serde")]
5363
mod serde;

0 commit comments

Comments
 (0)