Skip to main content

riscv_etrace/binary/
error.rs

1// Copyright (C) 2025, 2026 FZI Forschungszentrum Informatik
2// SPDX-License-Identifier: Apache-2.0
3//! Binary related error types and traits
4
5#[cfg(feature = "alloc")]
6use alloc::boxed::Box;
7use core::fmt;
8
9/// A [`MaybeMiss`] allowing the construction of a miss
10pub trait Miss: MaybeMiss {
11    /// Construct a value indicating a miss
12    ///
13    /// This error value indicates that the [`Binary`][super::Binary] does not
14    /// cover the given `address`.
15    fn miss(address: u64) -> Self;
16}
17
18impl<T, E: Miss> Miss for Result<T, E> {
19    fn miss(address: u64) -> Self {
20        Err(<E as Miss>::miss(address))
21    }
22}
23
24#[cfg(feature = "alloc")]
25impl Miss for Box<dyn MaybeMiss> {
26    fn miss(address: u64) -> Self {
27        Box::new(NoInstruction::miss(address))
28    }
29}
30
31#[cfg(feature = "alloc")]
32impl Miss for Box<dyn MaybeMissError> {
33    fn miss(address: u64) -> Self {
34        Box::new(NoInstruction::miss(address))
35    }
36}
37
38#[cfg(feature = "either")]
39impl<L: Miss, R: MaybeMiss> Miss for either::Either<L, R> {
40    fn miss(address: u64) -> Self {
41        either::Left(Miss::miss(address))
42    }
43}
44
45/// May indicate that an address is not covered by a [`Binary`][super::Binary]
46///
47/// A [`Binary`][super::Binary] usually only covers a subset of all possible
48/// addresses, e.g. a memory area on the target device. Requesting an
49/// [`Instruction`][super::Instruction] at an addresses outside that area will
50/// naturally yield an error. This trait allows identifying these particular
51/// errors.
52pub trait MaybeMiss {
53    /// Check whether this value indicates a miss
54    ///
55    /// This error value indicates that the [`Binary`][super::Binary] does not
56    /// cover the address for which an [`Instruction`][super::Instruction] was
57    /// requested.
58    fn is_miss(&self) -> bool;
59}
60
61impl<T, E: MaybeMiss> MaybeMiss for Result<T, E> {
62    fn is_miss(&self) -> bool {
63        match self {
64            Ok(_) => false,
65            Err(e) => e.is_miss(),
66        }
67    }
68}
69
70#[cfg(feature = "alloc")]
71impl<E: MaybeMiss + ?Sized> MaybeMiss for Box<E> {
72    fn is_miss(&self) -> bool {
73        E::is_miss(self.as_ref())
74    }
75}
76
77#[cfg(feature = "either")]
78impl<L: MaybeMiss, R: MaybeMiss> MaybeMiss for either::Either<L, R> {
79    fn is_miss(&self) -> bool {
80        either::for_both!(self, e => e.is_miss())
81    }
82}
83
84/// [`MaybeMiss`] that is also an [`Error`][core::error::Error]
85pub trait MaybeMissError: MaybeMiss + core::error::Error + Sync + Send {}
86
87impl<T: MaybeMiss + core::error::Error + Sync + Send + ?Sized> MaybeMissError for T {}
88
89/// An error for single segments of encoded [`Instruction`][super::Instruction]s
90#[derive(Copy, Clone, Debug, PartialEq, Eq)]
91pub enum SegmentError {
92    /// The address was not covered
93    AddressNotCovered,
94    /// Could not use an address or offset because it is too big for the host
95    ExceededHostUSize(core::num::TryFromIntError),
96    /// An [`Instruction`][super::Instruction] could not be decoded
97    InvalidInstruction,
98}
99
100impl Miss for SegmentError {
101    fn miss(_: u64) -> Self {
102        Self::AddressNotCovered
103    }
104}
105
106impl MaybeMiss for SegmentError {
107    fn is_miss(&self) -> bool {
108        matches!(self, Self::AddressNotCovered)
109    }
110}
111
112impl core::error::Error for SegmentError {
113    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
114        match self {
115            Self::ExceededHostUSize(e) => Some(e),
116            _ => None,
117        }
118    }
119}
120
121impl fmt::Display for SegmentError {
122    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123        match self {
124            Self::AddressNotCovered => write!(f, "Given address not covered"),
125            Self::ExceededHostUSize(_) => write!(
126                f,
127                "An offset exceeds what can be represented with host native addresses"
128            ),
129            Self::InvalidInstruction => write!(f, "No valid instruction at address"),
130        }
131    }
132}
133
134/// An error type expressing absence of an [`Instruction`][super::Instruction]
135#[derive(Copy, Clone, Debug, PartialEq, Eq)]
136pub struct NoInstruction;
137
138impl Miss for NoInstruction {
139    fn miss(_: u64) -> Self {
140        NoInstruction
141    }
142}
143
144impl MaybeMiss for NoInstruction {
145    fn is_miss(&self) -> bool {
146        true
147    }
148}
149
150impl core::error::Error for NoInstruction {}
151
152impl fmt::Display for NoInstruction {
153    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154        write!(f, "No Instruction availible")
155    }
156}