Skip to content

Commit 1b0e6ac

Browse files
authored
modernize error handling (#88)
Problem Currently, we do error handling with the `failure` crate which requires that users are aware of `failure` and use it in their library or application. Solution Switch error handling to use the `thiserror` crate which allows us to derive `std::error::Error` for our error type. Result This library's public API now uses `std::error::Error` in the `Result`s. This allows better composition within higher level libraries and applications.
1 parent 32f2808 commit 1b0e6ac

22 files changed

+270
-203
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ edition = '2018'
1414
[dependencies]
1515
bcc-sys = "0.13.0"
1616
byteorder = "1.3.4"
17-
failure = "0.1.7"
1817
libc = "0.2.68"
1918
regex = "1.3.5"
19+
thiserror = "1.0.19"
2020

2121
[dev-dependencies]
2222
clap = "2.33.0"

examples/biosnoop.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use bcc::core::BPF;
22
use bcc::perf::init_perf_map;
3+
use bcc::BccError;
34
use clap::{App, Arg};
4-
use failure::Error;
55

66
use core::sync::atomic::{AtomicBool, Ordering};
77
use std::ptr;
@@ -24,7 +24,7 @@ struct data_t {
2424
name: [u8; 16],
2525
}
2626

27-
fn do_main(runnable: Arc<AtomicBool>) -> Result<(), Error> {
27+
fn do_main(runnable: Arc<AtomicBool>) -> Result<(), BccError> {
2828
let matches = App::new("biosnoop")
2929
.about("Trace block I/O")
3030
.arg(
@@ -134,7 +134,6 @@ fn main() {
134134

135135
if let Err(x) = do_main(runnable) {
136136
eprintln!("Error: {}", x);
137-
eprintln!("{}", x.backtrace());
138137
std::process::exit(1);
139138
}
140139
}

examples/opensnoop.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
1-
extern crate bcc;
2-
extern crate byteorder;
3-
extern crate failure;
4-
extern crate libc;
5-
61
use bcc::core::BPF;
72
use bcc::perf::init_perf_map;
3+
use bcc::BccError;
84
use clap::{App, Arg};
9-
use failure::Error;
105

116
use core::sync::atomic::{AtomicBool, Ordering};
127
use std::ptr;
@@ -34,7 +29,7 @@ struct data_t {
3429
fname: [u8; 255], // NAME_MAX
3530
}
3631

37-
fn do_main(runnable: Arc<AtomicBool>) -> Result<(), Error> {
32+
fn do_main(runnable: Arc<AtomicBool>) -> Result<(), BccError> {
3833
let matches = App::new("opensnoop")
3934
.about("Prints out filename + PID every time a file is opened")
4035
.arg(
@@ -112,7 +107,6 @@ fn main() {
112107
match do_main(runnable) {
113108
Err(x) => {
114109
eprintln!("Error: {}", x);
115-
eprintln!("{}", x.backtrace());
116110
std::process::exit(1);
117111
}
118112
_ => {}

examples/runqlat.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use bcc::core::BPF;
2+
use bcc::BccError;
23
use clap::{App, Arg};
3-
use failure::Error;
44

55
use core::sync::atomic::{AtomicBool, Ordering};
66
use std::sync::Arc;
@@ -23,7 +23,7 @@ fn attach_events(bpf: &mut BPF) {
2323
.unwrap();
2424
}
2525

26-
#[cfg(any(not(feature = "v0_4_0"), not(feature = "v0_5_0"),))]
26+
#[cfg(not(any(feature = "v0_4_0", feature = "v0_5_0")))]
2727
fn attach_events(bpf: &mut BPF) {
2828
if bpf.support_raw_tracepoint() {
2929
let raw_tp_sched_wakeup = bpf.load_raw_tracepoint("raw_tp__sched_wakeup").unwrap();
@@ -50,7 +50,7 @@ fn attach_events(bpf: &mut BPF) {
5050
}
5151
}
5252

53-
fn do_main(runnable: Arc<AtomicBool>) -> Result<(), Error> {
53+
fn do_main(runnable: Arc<AtomicBool>) -> Result<(), BccError> {
5454
let matches = App::new("runqlat")
5555
.about("Reports distribution of scheduler latency")
5656
.arg(
@@ -131,7 +131,6 @@ fn main() {
131131
match do_main(runnable) {
132132
Err(x) => {
133133
eprintln!("Error: {}", x);
134-
eprintln!("{}", x.backtrace());
135134
std::process::exit(1);
136135
}
137136
_ => {}

examples/softirqs.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use bcc::core::BPF;
2+
use bcc::BccError;
23
use clap::{App, Arg};
3-
use failure::Error;
4+
use std::error::Error;
45

56
use core::sync::atomic::{AtomicBool, Ordering};
67
use std::sync::Arc;
@@ -73,7 +74,7 @@ impl fmt::Display for SoftIRQ {
7374
}
7475
}
7576

76-
fn do_main(runnable: Arc<AtomicBool>) -> Result<(), Error> {
77+
fn do_main(runnable: Arc<AtomicBool>) -> Result<(), BccError> {
7778
let matches = App::new("softirqs")
7879
.about("Reports time spent in IRQ Handlers")
7980
.arg(
@@ -169,7 +170,6 @@ fn main() {
169170
match do_main(runnable) {
170171
Err(x) => {
171172
eprintln!("Error: {}", x);
172-
eprintln!("{}", x.backtrace());
173173
std::process::exit(1);
174174
}
175175
_ => {}

examples/strlen.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
extern crate bcc;
22
extern crate byteorder;
3-
extern crate failure;
43
extern crate libc;
54

65
use bcc::core::BPF;
6+
use bcc::BccError;
77
use byteorder::{NativeEndian, ReadBytesExt};
8-
use failure::Error;
98

109
use core::sync::atomic::{AtomicBool, Ordering};
1110
use std::io::Cursor;
1211
use std::sync::Arc;
1312

14-
fn do_main(runnable: Arc<AtomicBool>) -> Result<(), Error> {
13+
fn do_main(runnable: Arc<AtomicBool>) -> Result<(), BccError> {
1514
let code = "
1615
#include <uapi/linux/ptrace.h>
1716
@@ -75,7 +74,6 @@ fn main() {
7574
match do_main(runnable) {
7675
Err(x) => {
7776
eprintln!("Error: {}", x);
78-
eprintln!("{}", x.backtrace());
7977
std::process::exit(1);
8078
}
8179
_ => {}

examples/tcpretrans.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
use bcc::core::BPF;
2-
extern crate chrono;
2+
use bcc::BccError;
33
use chrono::Utc;
44
use clap::{App, Arg};
5-
use failure::Error;
65

76
use core::sync::atomic::{AtomicBool, Ordering};
87
use std::net::Ipv4Addr;
@@ -38,7 +37,7 @@ struct ipv6_data_t {
3837
type_: u64,
3938
}
4039

41-
fn do_main(runnable: Arc<AtomicBool>) -> Result<(), Error> {
40+
fn do_main(runnable: Arc<AtomicBool>) -> Result<(), BccError> {
4241
let matches = App::new("biosnoop")
4342
.arg(
4443
Arg::with_name("duration")
@@ -81,7 +80,7 @@ fn do_main(runnable: Arc<AtomicBool>) -> Result<(), Error> {
8180
Ok(())
8281
}
8382

84-
fn print_ipv4_event() -> Box<FnMut(&[u8]) + Send> {
83+
fn print_ipv4_event() -> Box<dyn FnMut(&[u8]) + Send> {
8584
Box::new(|x| {
8685
let event = parse_ipv4_struct(x);
8786
println!(
@@ -97,7 +96,7 @@ fn print_ipv4_event() -> Box<FnMut(&[u8]) + Send> {
9796
})
9897
}
9998

100-
fn print_ipv6_event() -> Box<FnMut(&[u8]) + Send> {
99+
fn print_ipv6_event() -> Box<dyn FnMut(&[u8]) + Send> {
101100
Box::new(|x| {
102101
let event = parse_ipv6_struct(x);
103102
println!(
@@ -131,7 +130,6 @@ fn main() {
131130

132131
if let Err(x) = do_main(runnable) {
133132
eprintln!("Error: {}", x);
134-
eprintln!("{}", x.backtrace());
135133
std::process::exit(1);
136134
}
137135
}

src/core/kprobe/v0_4_0.rs

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use bcc_sys::bccapi::bpf_probe_attach_type_BPF_PROBE_ENTRY as BPF_PROBE_ENTRY;
22
use bcc_sys::bccapi::bpf_probe_attach_type_BPF_PROBE_RETURN as BPF_PROBE_RETURN;
33
use bcc_sys::bccapi::*;
4-
use failure::*;
54

65
use crate::core::make_alphanumeric;
76
use crate::types::MutPointer;
7+
use crate::BccError;
88

99
use regex::Regex;
1010

@@ -23,11 +23,9 @@ pub struct Kprobe {
2323
}
2424

2525
impl Kprobe {
26-
fn new(name: &str, attach_type: u32, function: &str, code: File) -> Result<Self, Error> {
27-
let cname =
28-
CString::new(name).map_err(|_| format_err!("Nul byte in Kprobe name: {}", name))?;
29-
let cfunction = CString::new(function)
30-
.map_err(|_| format_err!("Nul byte in Kprobe function: {}", function))?;
26+
fn new(name: &str, attach_type: u32, function: &str, code: File) -> Result<Self, BccError> {
27+
let cname = CString::new(name)?;
28+
let cfunction = CString::new(function)?;
3129
let (pid, cpu, group_fd) = (-1, 0, -1);
3230
let ptr = unsafe {
3331
bpf_attach_kprobe(
@@ -43,7 +41,15 @@ impl Kprobe {
4341
)
4442
};
4543
if ptr.is_null() {
46-
Err(format_err!("Failed to attach Kprobe: {}", name))
44+
match attach_type {
45+
BPF_PROBE_ENTRY => Err(BccError::AttachKprobe {
46+
name: name.to_string(),
47+
}),
48+
BPF_PROBE_RETURN => Err(BccError::AttachKretprobe {
49+
name: name.to_string(),
50+
}),
51+
_ => unreachable!(),
52+
}
4753
} else {
4854
Ok(Self {
4955
p: ptr,
@@ -53,19 +59,17 @@ impl Kprobe {
5359
}
5460
}
5561

56-
pub fn attach_kprobe(function: &str, code: File) -> Result<Self, Error> {
62+
pub fn attach_kprobe(function: &str, code: File) -> Result<Self, BccError> {
5763
let name = format!("p_{}", &make_alphanumeric(function));
5864
Kprobe::new(&name, BPF_PROBE_ENTRY, function, code)
59-
.map_err(|_| format_err!("Failed to attach Kprobe: {}", name))
6065
}
6166

62-
pub fn attach_kretprobe(function: &str, code: File) -> Result<Self, Error> {
67+
pub fn attach_kretprobe(function: &str, code: File) -> Result<Self, BccError> {
6368
let name = format!("r_{}", &make_alphanumeric(function));
6469
Kprobe::new(&name, BPF_PROBE_RETURN, function, code)
65-
.map_err(|_| format_err!("Failed to attach Kretprobe: {}", name))
6670
}
6771

68-
pub fn get_kprobe_functions(event_re: &str) -> Result<Vec<String>, Error> {
72+
pub fn get_kprobe_functions(event_re: &str) -> Result<Vec<String>, BccError> {
6973
let mut fns: Vec<String> = vec![];
7074

7175
enum Section {
@@ -117,19 +121,18 @@ impl Kprobe {
117121
Section::End => (),
118122
}
119123
// All functions defined as NOKPROBE_SYMBOL() start with the
120-
// prefix _kbl_addr_*, blacklisting them by looking at the name
124+
// prefix _kbl_addr_*, excluding them by looking at the name
121125
// allows to catch also those symbols that are defined in kernel
122126
// modules.
123127
if fname.starts_with("_kbl_addr_") {
124128
continue;
125129
}
126-
// Explicitly blacklist perf-related functions, they are all
127-
// non-attachable.
128-
else if fname.starts_with("__perf") || fname.starts_with("perf_") {
130+
// Exclude perf-related functions, they are all non-attachable.
131+
if fname.starts_with("__perf") || fname.starts_with("perf_") {
129132
continue;
130133
}
131134
// Exclude all gcc 8's extra .cold functions
132-
else if re.is_match(fname) {
135+
if re.is_match(fname) {
133136
continue;
134137
}
135138
if (t == "t" || t == "w") && fname.contains(event_re) {

src/core/kprobe/v0_6_0.rs

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use bcc_sys::bccapi::bpf_probe_attach_type_BPF_PROBE_ENTRY as BPF_PROBE_ENTRY;
22
use bcc_sys::bccapi::bpf_probe_attach_type_BPF_PROBE_RETURN as BPF_PROBE_RETURN;
33
use bcc_sys::bccapi::*;
4-
use failure::*;
54

65
use crate::core::make_alphanumeric;
6+
use crate::BccError;
77

88
use regex::Regex;
99

@@ -21,11 +21,9 @@ pub struct Kprobe {
2121
}
2222

2323
impl Kprobe {
24-
fn new(name: &str, attach_type: u32, function: &str, code: File) -> Result<Self, Error> {
25-
let cname =
26-
CString::new(name).map_err(|_| format_err!("Nul byte in Kprobe name: {}", name))?;
27-
let cfunction = CString::new(function)
28-
.map_err(|_| format_err!("Nul byte in Kprobe function: {}", function))?;
24+
fn new(name: &str, attach_type: u32, function: &str, code: File) -> Result<Self, BccError> {
25+
let cname = CString::new(name)?;
26+
let cfunction = CString::new(function)?;
2927
let ptr = unsafe {
3028
bpf_attach_kprobe(
3129
code.as_raw_fd(),
@@ -36,7 +34,15 @@ impl Kprobe {
3634
)
3735
};
3836
if ptr < 0 {
39-
Err(format_err!("Failed to attach Kprobe: {}", name))
37+
match attach_type {
38+
BPF_PROBE_ENTRY => Err(BccError::AttachKprobe {
39+
name: name.to_string(),
40+
}),
41+
BPF_PROBE_RETURN => Err(BccError::AttachKretprobe {
42+
name: name.to_string(),
43+
}),
44+
_ => unreachable!(),
45+
}
4046
} else {
4147
Ok(Self {
4248
p: ptr,
@@ -46,19 +52,17 @@ impl Kprobe {
4652
}
4753
}
4854

49-
pub fn attach_kprobe(function: &str, code: File) -> Result<Self, Error> {
55+
pub fn attach_kprobe(function: &str, code: File) -> Result<Self, BccError> {
5056
let name = format!("p_{}", &make_alphanumeric(function));
5157
Kprobe::new(&name, BPF_PROBE_ENTRY, function, code)
52-
.map_err(|_| format_err!("Failed to attach Kprobe: {}", name))
5358
}
5459

55-
pub fn attach_kretprobe(function: &str, code: File) -> Result<Self, Error> {
60+
pub fn attach_kretprobe(function: &str, code: File) -> Result<Self, BccError> {
5661
let name = format!("r_{}", &make_alphanumeric(function));
5762
Kprobe::new(&name, BPF_PROBE_RETURN, function, code)
58-
.map_err(|_| format_err!("Failed to attach Kretprobe: {}", name))
5963
}
6064

61-
pub fn get_kprobe_functions(event_re: &str) -> Result<Vec<String>, Error> {
65+
pub fn get_kprobe_functions(event_re: &str) -> Result<Vec<String>, BccError> {
6266
let mut fns: Vec<String> = vec![];
6367

6468
enum Section {
@@ -110,19 +114,18 @@ impl Kprobe {
110114
Section::End => (),
111115
}
112116
// All functions defined as NOKPROBE_SYMBOL() start with the
113-
// prefix _kbl_addr_*, blacklisting them by looking at the name
117+
// prefix _kbl_addr_*, excluding them by looking at the name
114118
// allows to catch also those symbols that are defined in kernel
115119
// modules.
116120
if fname.starts_with("_kbl_addr_") {
117121
continue;
118122
}
119-
// Explicitly blacklist perf-related functions, they are all
120-
// non-attachable.
121-
else if fname.starts_with("__perf") || fname.starts_with("perf_") {
123+
// Exclude perf-related functions, they are all non-attachable.
124+
if fname.starts_with("__perf") || fname.starts_with("perf_") {
122125
continue;
123126
}
124127
// Exclude all gcc 8's extra .cold functions
125-
else if re.is_match(fname) {
128+
if re.is_match(fname) {
126129
continue;
127130
}
128131
if (t == "t" || t == "w") && fname.contains(event_re) {

0 commit comments

Comments
 (0)