1use std::mem::size_of;
23use std::{
24 collections::BTreeMap,
25 convert::{TryFrom, TryInto},
26};
27
28use serde::Serialize;
29use thiserror::Error;
30
31pub(crate) const DOF_MAGIC: [u8; 4] = [0x7F, b'D', b'O', b'F'];
33
34#[derive(Error, Debug)]
36pub enum Error {
37 #[error("invalid DOF identifier (magic bytes, endianness, or version)")]
39 InvalidIdentifier,
40
41 #[error("data does not match expected struct layout or is misaligned")]
43 ParseError,
44
45 #[error("unsupported object file format")]
47 UnsupportedObjectFile,
48
49 #[cfg(feature = "des")]
51 #[error(transparent)]
52 ObjectError(#[from] goblin::error::Error),
53
54 #[error(transparent)]
56 IO(#[from] std::io::Error),
57}
58
59#[derive(Debug, Clone, Copy, Serialize)]
61#[repr(u8)]
62pub enum DataModel {
63 None = 0,
64 ILP32 = 1,
65 LP64 = 2,
66}
67
68impl Default for DataModel {
69 fn default() -> Self {
70 if cfg!(target_pointer_width = "64") {
71 DataModel::LP64
72 } else {
73 DataModel::ILP32
74 }
75 }
76}
77
78impl TryFrom<u8> for DataModel {
79 type Error = Error;
80 fn try_from(x: u8) -> Result<Self, Self::Error> {
81 match x {
82 0 => Ok(DataModel::None),
83 1 => Ok(DataModel::ILP32),
84 2 => Ok(DataModel::LP64),
85 _ => Err(Error::InvalidIdentifier),
86 }
87 }
88}
89
90#[derive(Debug, Clone, Copy, Serialize)]
92#[repr(u8)]
93pub enum DataEncoding {
94 None = 0,
95 LittleEndian = 1,
96 BigEndian = 2,
97}
98
99impl Default for DataEncoding {
100 fn default() -> Self {
101 if cfg!(target_endian = "big") {
102 DataEncoding::BigEndian
103 } else {
104 DataEncoding::LittleEndian
105 }
106 }
107}
108
109impl TryFrom<u8> for DataEncoding {
110 type Error = Error;
111 fn try_from(x: u8) -> Result<Self, Self::Error> {
112 match x {
113 0 => Ok(DataEncoding::None),
114 1 => Ok(DataEncoding::LittleEndian),
115 2 => Ok(DataEncoding::BigEndian),
116 _ => Err(Error::InvalidIdentifier),
117 }
118 }
119}
120
121#[derive(Debug, Clone, Copy, Serialize)]
123pub struct Ident {
124 pub magic: [u8; 4],
125 pub model: DataModel,
126 pub encoding: DataEncoding,
127 pub version: u8,
128 pub dif_vers: u8,
129 pub dif_ireg: u8,
130 pub dif_treg: u8,
131}
132
133impl<'a> TryFrom<&'a [u8]> for Ident {
134 type Error = Error;
135 fn try_from(buf: &'a [u8]) -> Result<Self, Self::Error> {
136 if buf.len() < size_of::<Ident>() {
137 return Err(Error::ParseError);
138 }
139 let magic = &buf[..DOF_MAGIC.len()];
140 if magic != DOF_MAGIC {
141 return Err(Error::InvalidIdentifier);
142 }
143 let model = DataModel::try_from(buf[crate::dof_bindings::DOF_ID_MODEL as usize])?;
144 let encoding = DataEncoding::try_from(buf[crate::dof_bindings::DOF_ID_ENCODING as usize])?;
145 let version = buf[crate::dof_bindings::DOF_ID_VERSION as usize];
146 let dif_vers = buf[crate::dof_bindings::DOF_ID_DIFVERS as usize];
147 let dif_ireg = buf[crate::dof_bindings::DOF_ID_DIFIREG as usize];
148 let dif_treg = buf[crate::dof_bindings::DOF_ID_DIFTREG as usize];
149 Ok(Ident {
150 magic: magic.try_into().unwrap(),
152 model,
153 encoding,
154 version,
155 dif_vers,
156 dif_ireg,
157 dif_treg,
158 })
159 }
160}
161
162impl Ident {
163 pub fn as_bytes(&self) -> [u8; 16] {
164 let mut out = [0; 16];
165 let start = self.magic.len();
166 out[..start].copy_from_slice(&self.magic[..]);
167 out[start] = self.model as _;
168 out[start + 1] = self.encoding as _;
169 out[start + 2] = self.version;
170 out[start + 3] = self.dif_vers;
171 out[start + 4] = self.dif_ireg;
172 out[start + 5] = self.dif_treg;
173 out
174 }
175}
176
177#[derive(Debug, Clone, Serialize)]
179pub struct Section {
180 pub ident: Ident,
182 pub providers: BTreeMap<String, Provider>,
184}
185
186impl Section {
187 #[cfg(feature = "des")]
189 pub fn from_bytes(buf: &[u8]) -> Result<Section, Error> {
190 crate::des::deserialize_section(buf)
191 }
192
193 pub fn as_bytes(&self) -> Vec<u8> {
195 crate::ser::serialize_section(self)
196 }
197
198 pub fn to_json(&self) -> String {
200 serde_json::to_string_pretty(self).unwrap()
201 }
202}
203
204impl Default for Section {
205 fn default() -> Self {
206 Self {
207 ident: Ident {
208 magic: DOF_MAGIC,
209 model: DataModel::LP64,
210 encoding: DataEncoding::LittleEndian,
211 version: crate::dof_bindings::DOF_VERSION as u8,
212 dif_vers: crate::dof_bindings::DIF_VERSION as u8,
213 dif_ireg: crate::dof_bindings::DIF_DIR_NREGS as u8,
214 dif_treg: crate::dof_bindings::DIF_DTR_NREGS as u8,
215 },
216 providers: BTreeMap::new(),
217 }
218 }
219}
220
221#[derive(Debug, Clone, Serialize)]
223pub struct Probe {
224 pub name: String,
226 pub function: String,
228 pub address: u64,
230 pub offsets: Vec<u32>,
232 pub enabled_offsets: Vec<u32>,
234 pub arguments: Vec<String>,
236}
237
238#[derive(Debug, Clone, Serialize)]
240pub struct Provider {
241 pub name: String,
243 pub probes: BTreeMap<String, Probe>,
245}