Skip to content

Commit 6d9c630

Browse files
committed
[Rust] Update examples to use tracing
1 parent 83edc64 commit 6d9c630

File tree

15 files changed

+202
-142
lines changed

15 files changed

+202
-142
lines changed

plugins/warp/examples/headless/Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ edition = "2021"
55

66
[dependencies]
77
clap = { version = "4.5", features = ["derive"] }
8-
indicatif = "0.18.2"
98
warp_ninja.workspace = true
109
binaryninjacore-sys.workspace = true
1110
binaryninja.workspace = true
12-
log = "0.4"
13-
env_logger = "0.11"
14-
ctrlc = "3.5"
11+
ctrlc = "3.5"
12+
tracing = "0.1"
13+
tracing-subscriber = "0.3"
14+
tracing-indicatif = "0.3"
Lines changed: 49 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
use binaryninja::headless::Session;
2+
use binaryninja::tracing::TracingLogListener;
23
use clap::Parser;
3-
use indicatif::{ProgressBar, ProgressStyle};
44
use std::collections::HashMap;
55
use std::path::PathBuf;
6+
use std::sync::atomic::{AtomicBool, Ordering};
67
use std::sync::Arc;
78
use std::time::Duration;
9+
use tracing_indicatif::span_ext::IndicatifSpanExt;
10+
use tracing_indicatif::style::ProgressStyle;
11+
use tracing_indicatif::IndicatifLayer;
12+
use tracing_subscriber::layer::SubscriberExt;
13+
use tracing_subscriber::util::SubscriberInitExt;
814
use warp_ninja::processor::{
915
CompressionTypeField, ProcessingFileState, ProcessingState, WarpFileProcessor,
1016
};
@@ -50,9 +56,15 @@ struct Args {
5056
}
5157

5258
fn main() {
59+
let indicatif_layer = IndicatifLayer::new();
60+
tracing_subscriber::registry()
61+
.with(tracing_subscriber::fmt::layer().with_writer(indicatif_layer.get_stderr_writer()))
62+
.with(indicatif_layer)
63+
.init();
64+
let _listener = TracingLogListener::new().register();
65+
5366
let _session = Session::new().expect("Failed to create session");
5467
let args = Args::parse();
55-
env_logger::init();
5668

5769
let compression_ty = match args.compressed {
5870
true => CompressionTypeField::Zstd,
@@ -72,22 +84,27 @@ fn main() {
7284
})
7385
.expect("Error setting Ctrl-C handler");
7486

75-
let progress_guard = run_progress_bar(processor.state());
87+
let finished_signal = Arc::new(AtomicBool::new(false));
88+
// Report progress to the terminal.
89+
let progress_state = processor.state();
90+
let progress_finished_signal = finished_signal.clone();
91+
let progress_thread =
92+
std::thread::spawn(|| run_progress_bar(progress_state, progress_finished_signal));
7693

7794
let outputs: HashMap<PathBuf, WarpFile<'static>> = args
7895
.input
7996
.into_iter()
8097
.filter_map(|i| match processor.process(i.clone()) {
8198
Ok(o) => Some((i, o)),
8299
Err(err) => {
83-
log::error!("{}", err);
100+
tracing::error!("{}", err);
84101
None
85102
}
86103
})
87104
.collect();
88105

89-
// Stop progress UI
90-
progress_guard.finish();
106+
finished_signal.store(true, Ordering::Relaxed);
107+
progress_thread.join().expect("Progress thread exited");
91108

92109
match args.output.is_dir() {
93110
true => {
@@ -98,85 +115,56 @@ fn main() {
98115
None => input.components().last().unwrap().as_os_str(),
99116
};
100117
let output_path = args.output.join(output_name).with_extension("warp");
101-
log::info!("Writing to {:?}", output_path);
118+
tracing::info!("Writing to {:?}", output_path);
102119
std::fs::write(output_path, output.to_bytes()).unwrap();
103120
}
104121
}
105122
false => {
106123
// Given a non-existing directory, merge all outputs and place at the output path.
107124
match processor.merge_files(outputs.values().cloned().collect()) {
108125
Ok(output) => {
109-
log::info!("Writing to {:?}", args.output);
126+
tracing::info!("Writing to {:?}", args.output);
110127
std::fs::write(args.output, output.to_bytes()).unwrap();
111128
}
112129
Err(err) => {
113-
log::error!("{}", err);
130+
tracing::error!("{}", err);
114131
}
115132
}
116133
}
117134
}
118135
}
119136

120137
// TODO: Also poll for background tasks and display them as independent progress bars.
121-
fn run_progress_bar(state: Arc<ProcessingState>) -> ProgressGuard {
122-
let pb = ProgressBar::new(0);
123-
pb.set_style(
124-
ProgressStyle::with_template(
125-
"{spinner} {bar:40.cyan/blue} {pos}/{len} ({percent}%) [{elapsed_precise}] {msg}",
126-
)
127-
.unwrap()
128-
.progress_chars("=>-"),
129-
);
130-
131-
let pb_clone = pb.clone();
132-
let state_clone = state.clone();
133-
let handle = std::thread::spawn(move || loop {
134-
let total = state_clone.total_files() as u64;
135-
let done = state_clone.files_with_state(ProcessingFileState::Processed) as u64;
136-
let unprocessed = state_clone.files_with_state(ProcessingFileState::Unprocessed);
137-
let analyzing = state_clone.files_with_state(ProcessingFileState::Analyzing);
138-
let processing = state_clone.files_with_state(ProcessingFileState::Processing);
139-
140-
if pb_clone.length().unwrap_or(0) != total {
141-
pb_clone.set_length(total);
142-
}
143-
pb_clone.set_position(done.min(total));
144-
pb_clone.set_message(format!(
138+
fn run_progress_bar(state: Arc<ProcessingState>, finished: Arc<AtomicBool>) {
139+
let progress_span = tracing::info_span!("loading");
140+
let progress_style = ProgressStyle::with_template("{msg} {elapsed} {wide_bar}").unwrap();
141+
progress_span.pb_set_style(&progress_style);
142+
progress_span.pb_set_message("Processing files");
143+
progress_span.pb_set_finish_message("Files processed");
144+
145+
let elapsed = std::time::Instant::now();
146+
progress_span.in_scope(|| loop {
147+
let total = state.total_files() as u64;
148+
let done = state.files_with_state(ProcessingFileState::Processed) as u64;
149+
let unprocessed = state.files_with_state(ProcessingFileState::Unprocessed);
150+
let analyzing = state.files_with_state(ProcessingFileState::Analyzing);
151+
let processing = state.files_with_state(ProcessingFileState::Processing);
152+
153+
progress_span.pb_set_length(total);
154+
progress_span.pb_set_position(done.min(total));
155+
progress_span.pb_set_message(&format!(
145156
"{{u:{}|a:{}|p:{}|d:{}}}",
146157
unprocessed, analyzing, processing, done
147158
));
148159

149-
if pb_clone.is_finished() {
160+
if state.is_cancelled() || finished.load(Ordering::Relaxed) {
150161
break;
151162
}
152163
std::thread::sleep(Duration::from_millis(100));
153164
});
154165

155-
ProgressGuard {
156-
pb,
157-
handle: Some(handle),
158-
}
159-
}
160-
161-
struct ProgressGuard {
162-
pb: ProgressBar,
163-
handle: Option<std::thread::JoinHandle<()>>,
164-
}
165-
166-
impl ProgressGuard {
167-
fn finish(mut self) {
168-
self.pb.finish_and_clear();
169-
if let Some(h) = self.handle.take() {
170-
let _ = h.join();
171-
}
172-
}
173-
}
174-
175-
impl Drop for ProgressGuard {
176-
fn drop(&mut self) {
177-
self.pb.finish_and_clear();
178-
if let Some(h) = self.handle.take() {
179-
let _ = h.join();
180-
}
181-
}
166+
tracing::info!(
167+
"Finished processing in {:.2} seconds",
168+
elapsed.elapsed().as_secs_f32()
169+
);
182170
}
Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,65 @@
11
// Usage: cargo run --example bndb_to_type_library <bndb_path> <type_library_path>
22

33
use binaryninja::binary_view::BinaryViewExt;
4+
use binaryninja::tracing::TracingLogListener;
45
use binaryninja::types::{QualifiedName, TypeLibrary};
6+
use tracing_indicatif::span_ext::IndicatifSpanExt;
7+
use tracing_indicatif::style::ProgressStyle;
8+
use tracing_subscriber::layer::SubscriberExt;
9+
use tracing_subscriber::util::SubscriberInitExt;
510

611
fn main() {
12+
let indicatif_layer = tracing_indicatif::IndicatifLayer::new();
13+
tracing_subscriber::registry()
14+
.with(tracing_subscriber::fmt::layer().with_writer(indicatif_layer.get_stderr_writer()))
15+
.with(indicatif_layer)
16+
.init();
17+
let _listener = TracingLogListener::new().register();
18+
719
let bndb_path_str = std::env::args().nth(1).expect("No header provided");
820
let bndb_path = std::path::Path::new(&bndb_path_str);
921

1022
let type_lib_path_str = std::env::args().nth(2).expect("No type library provided");
1123
let type_lib_path = std::path::Path::new(&type_lib_path_str);
1224
let type_lib_name = type_lib_path.file_stem().unwrap().to_str().unwrap();
1325

14-
println!("Starting session...");
1526
// This loads all the core architecture, platform, etc plugins
1627
let headless_session =
1728
binaryninja::headless::Session::new().expect("Failed to initialize session");
1829

19-
let file = headless_session
20-
.load(bndb_path)
21-
.expect("Failed to load BNDB");
30+
let file = {
31+
let loading_span = tracing::info_span!("loading");
32+
let progress_style = ProgressStyle::with_template("{msg} {elapsed} {wide_bar}").unwrap();
33+
loading_span.pb_set_style(&progress_style);
34+
loading_span.pb_set_message("Loading database");
35+
loading_span.pb_set_finish_message("Database loaded");
36+
loading_span.in_scope(|| {
37+
headless_session
38+
.load_with_progress(bndb_path, |pos, total| {
39+
loading_span.pb_set_length(total as u64);
40+
loading_span.pb_set_position(pos as u64);
41+
true
42+
})
43+
.expect("Failed to load BNDB")
44+
})
45+
};
2246

2347
let type_lib = TypeLibrary::new(file.default_arch().unwrap(), type_lib_name);
2448

25-
for ty in &file.types() {
26-
println!("Adding type: {}", ty.name);
49+
let types = file.types();
50+
tracing::info!("Adding {} types", types.len());
51+
for ty in &types {
2752
type_lib.add_named_type(ty.name, &ty.ty);
2853
}
2954

30-
for func in &file.functions() {
31-
println!("Adding function: {}", func.symbol());
55+
let functions = file.functions();
56+
tracing::info!("Adding {} functions", functions.len());
57+
for func in &functions {
3258
let qualified_name =
3359
QualifiedName::from(func.symbol().short_name().to_string_lossy().to_string());
3460
type_lib.add_named_object(qualified_name, &func.function_type());
3561
}
3662

63+
tracing::info!("Writing out file... {:?}", type_lib_path);
3764
type_lib.write_to_file(&type_lib_path);
3865
}

rust/examples/create_type_library.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
// Usage: cargo run --example create_type_library <header_file_path> <platform> <type_library_path>
22

33
use binaryninja::platform::Platform;
4+
use binaryninja::tracing::TracingLogListener;
45
use binaryninja::types::{CoreTypeParser, TypeLibrary, TypeParser};
56

67
fn main() {
8+
tracing_subscriber::fmt::init();
9+
let _listener = TracingLogListener::new().register();
10+
711
let header_path_str = std::env::args().nth(1).expect("No header provided");
812
let header_path = std::path::Path::new(&header_path_str);
913
let header_name = header_path.file_stem().unwrap().to_str().unwrap();
@@ -14,7 +18,6 @@ fn main() {
1418

1519
let header_contents = std::fs::read_to_string(header_path).expect("Failed to read header file");
1620

17-
println!("Starting session...");
1821
// This loads all the core architecture, platform, etc plugins
1922
let _headless_session =
2023
binaryninja::headless::Session::new().expect("Failed to initialize session");
@@ -38,14 +41,19 @@ fn main() {
3841
.expect("Parsed types");
3942

4043
for ty in parsed_types.types {
41-
println!("Adding type: {}", ty.name);
44+
tracing::debug!("Adding type: {}", ty.name);
4245
type_lib.add_named_type(ty.name, &ty.ty);
4346
}
4447

4548
for func in parsed_types.functions {
46-
println!("Adding function: {}", func.name);
49+
tracing::debug!("Adding function: {}", func.name);
4750
type_lib.add_named_object(func.name, &func.ty);
4851
}
4952

53+
tracing::info!(
54+
"Created type library with {} types and {} functions",
55+
type_lib.named_types().len(),
56+
type_lib.named_objects().len()
57+
);
5058
type_lib.write_to_file(&type_lib_path);
5159
}

rust/examples/decompile.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use binaryninja::binary_view::{BinaryView, BinaryViewBase, BinaryViewExt};
22
use binaryninja::disassembly::{DisassemblyOption, DisassemblySettings};
33
use binaryninja::function::Function;
44
use binaryninja::linear_view::LinearViewObject;
5+
use binaryninja::tracing::TracingLogListener;
56

67
fn decompile_to_c(view: &BinaryView, func: &Function) {
78
let settings = DisassemblySettings::new();
@@ -22,26 +23,28 @@ fn decompile_to_c(view: &BinaryView, func: &Function) {
2223
let lines = first.into_iter().chain(&last);
2324

2425
for line in lines {
25-
println!("{}", line);
26+
tracing::info!("{}", line);
2627
}
2728
}
2829

2930
pub fn main() {
31+
tracing_subscriber::fmt::init();
32+
let _listener = TracingLogListener::new().register();
33+
3034
let filename = std::env::args().nth(1).expect("No filename provided");
3135

32-
println!("Starting session...");
3336
// This loads all the core architecture, platform, etc plugins
3437
let headless_session =
3538
binaryninja::headless::Session::new().expect("Failed to initialize session");
3639

37-
println!("Loading binary...");
40+
tracing::info!("Loading binary...");
3841
let bv = headless_session
3942
.load(&filename)
4043
.expect("Couldn't open file!");
4144

42-
println!("Filename: `{}`", bv.file().filename());
43-
println!("File size: `{:#x}`", bv.len());
44-
println!("Function count: {}", bv.functions().len());
45+
tracing::info!("Filename: `{}`", bv.file().filename());
46+
tracing::info!("File size: `{:#x}`", bv.len());
47+
tracing::info!("Function count: {}", bv.functions().len());
4548

4649
for func in &bv.functions() {
4750
decompile_to_c(bv.as_ref(), func.as_ref());

0 commit comments

Comments
 (0)