Skip to content

Commit

Permalink
Refactor - Error handling (#527)
Browse files Browse the repository at this point in the history
* Stops allocating errors on the heap.

* Removes all fields from runtime errors, leaving only the discriminant.

* Also removes the pc field from EbpfError::AccessViolation.
  • Loading branch information
Lichtso authored Sep 29, 2023
1 parent 5b77958 commit 3568ee3
Show file tree
Hide file tree
Showing 9 changed files with 286 additions and 417 deletions.
13 changes: 5 additions & 8 deletions benches/memory_mapping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ macro_rules! bench_gapped_randomized_access_with_1024_entries {
AccessType::Load,
0x100000000 + (prng.gen::<u64>() % frame_count * (frame_size * 2)),
1,
0,
)
.is_ok());
});
Expand Down Expand Up @@ -119,7 +118,6 @@ macro_rules! bench_randomized_access_with_0001_entry {
AccessType::Load,
0x100000000 + (prng.gen::<u64>() % content.len() as u64),
1,
0,
);
});
}
Expand Down Expand Up @@ -153,7 +151,6 @@ macro_rules! bench_randomized_access_with_n_entries {
AccessType::Load,
0x100000000 + (prng.gen::<u64>() % end_address),
1,
0,
);
});
}
Expand Down Expand Up @@ -199,7 +196,7 @@ macro_rules! bench_randomized_mapping_with_n_entries {
let config = Config::default();
let memory_mapping = $mem::new(memory_regions, &config, &SBPFVersion::V2).unwrap();
bencher.iter(|| {
let _ = memory_mapping.map(AccessType::Load, 0x100000000, 1, 0);
let _ = memory_mapping.map(AccessType::Load, 0x100000000, 1);
});
}
};
Expand Down Expand Up @@ -248,7 +245,7 @@ macro_rules! bench_mapping_with_n_entries {
let config = Config::default();
let memory_mapping = $mem::new(memory_regions, &config, &SBPFVersion::V2).unwrap();
bencher.iter(|| {
let _ = memory_mapping.map(AccessType::Load, 0x100000000, 1, 0);
let _ = memory_mapping.map(AccessType::Load, 0x100000000, 1);
});
}
};
Expand Down Expand Up @@ -310,13 +307,13 @@ fn do_bench_mapping_operation(bencher: &mut Bencher, op: MemoryOperation, vm_add

match op {
MemoryOperation::Map => bencher.iter(|| {
let _ = memory_mapping.map(AccessType::Load, vm_addr, 8, 0).unwrap();
let _ = memory_mapping.map(AccessType::Load, vm_addr, 8).unwrap();
}),
MemoryOperation::Load => bencher.iter(|| {
let _ = memory_mapping.load::<u64>(vm_addr, 0).unwrap();
let _ = memory_mapping.load::<u64>(vm_addr).unwrap();
}),
MemoryOperation::Store(val) => bencher.iter(|| {
let _ = memory_mapping.store(val, vm_addr, 0).unwrap();
let _ = memory_mapping.store(val, vm_addr).unwrap();
}),
}
}
Expand Down
7 changes: 3 additions & 4 deletions src/debugger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use gdbstub::target::ext::section_offsets::Offsets;

use crate::{
ebpf,
error::EbpfError,
interpreter::{DebugState, Interpreter},
memory_region::AccessType,
vm::{ContextObject, ProgramResult},
Expand Down Expand Up @@ -151,16 +152,14 @@ impl<'a, 'b, C: ContextObject> Target for Interpreter<'a, 'b, C> {
fn get_host_ptr<C: ContextObject>(
interpreter: &mut Interpreter<C>,
mut vm_addr: u64,
pc: usize,
) -> Result<*mut u8, Box<dyn std::error::Error>> {
) -> Result<*mut u8, EbpfError> {
if vm_addr < ebpf::MM_PROGRAM_START {
vm_addr += ebpf::MM_PROGRAM_START;
}
match interpreter.vm.memory_mapping.map(
AccessType::Load,
vm_addr,
std::mem::size_of::<u8>() as u64,
pc + ebpf::ELF_INSN_DUMP_OFFSET,
) {
ProgramResult::Ok(host_addr) => Ok(host_addr as *mut u8),
ProgramResult::Err(err) => Err(err),
Expand Down Expand Up @@ -196,7 +195,7 @@ impl<'a, 'b, C: ContextObject> SingleThreadBase for Interpreter<'a, 'b, C> {

fn read_addrs(&mut self, start_addr: u64, data: &mut [u8]) -> TargetResult<(), Self> {
for (vm_addr, val) in (start_addr..).zip(data.iter_mut()) {
let host_ptr = match get_host_ptr(self, vm_addr, self.pc) {
let host_ptr = match get_host_ptr(self, vm_addr) {
Ok(host_ptr) => host_ptr,
// The debugger is sometimes requesting more data than we have access to, just skip these
_ => continue,
Expand Down
54 changes: 27 additions & 27 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@
//! <https://www.kernel.org/doc/Documentation/networking/filter.txt>, or for a shorter version of
//! the list of the operation codes: <https://github.com/iovisor/bpf-docs/blob/master/eBPF.md>
use crate::{elf::ElfError, memory_region::AccessType, verifier::VerifierError};
use {
crate::{elf::ElfError, memory_region::AccessType, verifier::VerifierError},
std::error::Error,
};

/// Error definitions
#[derive(Debug, thiserror::Error)]
Expand All @@ -30,28 +33,26 @@ pub enum EbpfError {
#[error("function #{0} was already registered")]
FunctionAlreadyRegistered(usize),
/// Exceeded max BPF to BPF call depth
#[error("exceeded max BPF to BPF call depth of {1} at BPF instruction #{0}")]
CallDepthExceeded(usize, usize),
#[error("exceeded max BPF to BPF call depth")]
CallDepthExceeded,
/// Attempt to exit from root call frame
#[error("attempted to exit root call frame")]
ExitRootCallFrame,
/// Divide by zero"
#[error("divide by zero at BPF instruction {0}")]
DivideByZero(usize),
#[error("divide by zero at BPF instruction")]
DivideByZero,
/// Divide overflow
#[error("division overflow at BPF instruction {0}")]
DivideOverflow(usize),
#[error("division overflow at BPF instruction")]
DivideOverflow,
/// Exceeded max instructions allowed
#[error("attempted to execute past the end of the text segment at BPF instruction #{0}")]
ExecutionOverrun(usize),
#[error("attempted to execute past the end of the text segment at BPF instruction")]
ExecutionOverrun,
/// Attempt to call to an address outside the text segment
#[error(
"callx at BPF instruction {0} attempted to call outside of the text segment to addr 0x{1:x}"
)]
CallOutsideTextSegment(usize, u64),
#[error("callx attempted to call outside of the text segment")]
CallOutsideTextSegment,
/// Exceeded max instructions allowed
#[error("exceeded CUs meter at BPF instruction #{0}")]
ExceededMaxInstructions(usize),
#[error("exceeded CUs meter at BPF instruction")]
ExceededMaxInstructions,
/// Program has not been JIT-compiled
#[error("program has not been JIT-compiled")]
JitNotCompiled,
Expand All @@ -62,21 +63,17 @@ pub enum EbpfError {
#[error("Invalid memory region at index {0}")]
InvalidMemoryRegion(usize),
/// Access violation (general)
#[error(
"Access violation in {4} section at address {2:#x} of size {3:?} at BPF instruction #{0}"
)]
AccessViolation(usize, AccessType, u64, u64, &'static str),
#[error("Access violation in {3} section at address {1:#x} of size {2:?}")]
AccessViolation(AccessType, u64, u64, &'static str),
/// Access violation (stack specific)
#[error(
"Access violation in stack frame {4} at address {2:#x} of size {3:?} at BPF instruction #{0}"
)]
StackAccessViolation(usize, AccessType, u64, u64, i64),
#[error("Access violation in stack frame {3} at address {1:#x} of size {2:?}")]
StackAccessViolation(AccessType, u64, u64, i64),
/// Invalid instruction
#[error("invalid BPF instruction at {0}")]
InvalidInstruction(usize),
#[error("invalid BPF instruction")]
InvalidInstruction,
/// Unsupported instruction
#[error("unsupported BPF instruction at {0}")]
UnsupportedInstruction(usize),
#[error("unsupported BPF instruction")]
UnsupportedInstruction,
/// Compilation is too big to fit
#[error("Compilation exhausted text segment at BPF instruction {0}")]
ExhaustedTextSegment(usize),
Expand All @@ -86,4 +83,7 @@ pub enum EbpfError {
/// Verifier error
#[error("Verifier error: {0}")]
VerifierError(#[from] VerifierError),
/// Syscall error
#[error("Syscall error: {0}")]
SyscallError(Box<dyn Error>),
}
Loading

0 comments on commit 3568ee3

Please sign in to comment.