use std::mem::size_of;
use std::{
collections::BTreeMap,
convert::{TryFrom, TryInto},
};
use serde::Serialize;
use thiserror::Error;
pub(crate) const DOF_MAGIC: [u8; 4] = [0x7F, b'D', b'O', b'F'];
#[derive(Error, Debug)]
pub enum Error {
#[error("invalid DOF identifier (magic bytes, endianness, or version)")]
InvalidIdentifier,
#[error("data does not match expected struct layout or is misaligned")]
ParseError,
#[error("unsupported object file format")]
UnsupportedObjectFile,
#[cfg(feature = "des")]
#[error(transparent)]
ObjectError(#[from] goblin::error::Error),
#[error(transparent)]
IO(#[from] std::io::Error),
}
#[derive(Debug, Clone, Copy, Serialize)]
#[repr(u8)]
pub enum DataModel {
None = 0,
ILP32 = 1,
LP64 = 2,
}
impl Default for DataModel {
fn default() -> Self {
if cfg!(target_pointer_width = "64") {
DataModel::LP64
} else {
DataModel::ILP32
}
}
}
impl TryFrom<u8> for DataModel {
type Error = Error;
fn try_from(x: u8) -> Result<Self, Self::Error> {
match x {
0 => Ok(DataModel::None),
1 => Ok(DataModel::ILP32),
2 => Ok(DataModel::LP64),
_ => Err(Error::InvalidIdentifier),
}
}
}
#[derive(Debug, Clone, Copy, Serialize)]
#[repr(u8)]
pub enum DataEncoding {
None = 0,
LittleEndian = 1,
BigEndian = 2,
}
impl Default for DataEncoding {
fn default() -> Self {
if cfg!(target_endian = "big") {
DataEncoding::BigEndian
} else {
DataEncoding::LittleEndian
}
}
}
impl TryFrom<u8> for DataEncoding {
type Error = Error;
fn try_from(x: u8) -> Result<Self, Self::Error> {
match x {
0 => Ok(DataEncoding::None),
1 => Ok(DataEncoding::LittleEndian),
2 => Ok(DataEncoding::BigEndian),
_ => Err(Error::InvalidIdentifier),
}
}
}
#[derive(Debug, Clone, Copy, Serialize)]
pub struct Ident {
pub magic: [u8; 4],
pub model: DataModel,
pub encoding: DataEncoding,
pub version: u8,
pub dif_vers: u8,
pub dif_ireg: u8,
pub dif_treg: u8,
}
impl<'a> TryFrom<&'a [u8]> for Ident {
type Error = Error;
fn try_from(buf: &'a [u8]) -> Result<Self, Self::Error> {
if buf.len() < size_of::<Ident>() {
return Err(Error::ParseError);
}
let magic = &buf[..DOF_MAGIC.len()];
if magic != DOF_MAGIC {
return Err(Error::InvalidIdentifier);
}
let model = DataModel::try_from(buf[crate::dof_bindings::DOF_ID_MODEL as usize])?;
let encoding = DataEncoding::try_from(buf[crate::dof_bindings::DOF_ID_ENCODING as usize])?;
let version = buf[crate::dof_bindings::DOF_ID_VERSION as usize];
let dif_vers = buf[crate::dof_bindings::DOF_ID_DIFVERS as usize];
let dif_ireg = buf[crate::dof_bindings::DOF_ID_DIFIREG as usize];
let dif_treg = buf[crate::dof_bindings::DOF_ID_DIFTREG as usize];
Ok(Ident {
magic: magic.try_into().unwrap(),
model,
encoding,
version,
dif_vers,
dif_ireg,
dif_treg,
})
}
}
impl Ident {
pub fn as_bytes(&self) -> [u8; 16] {
let mut out = [0; 16];
let start = self.magic.len();
out[..start].copy_from_slice(&self.magic[..]);
out[start] = self.model as _;
out[start + 1] = self.encoding as _;
out[start + 2] = self.version;
out[start + 3] = self.dif_vers;
out[start + 4] = self.dif_ireg;
out[start + 5] = self.dif_treg;
out
}
}
#[derive(Debug, Clone, Serialize)]
pub struct Section {
pub ident: Ident,
pub providers: BTreeMap<String, Provider>,
}
impl Section {
#[cfg(feature = "des")]
pub fn from_bytes(buf: &[u8]) -> Result<Section, Error> {
crate::des::deserialize_section(buf)
}
pub fn as_bytes(&self) -> Vec<u8> {
crate::ser::serialize_section(self)
}
pub fn to_json(&self) -> String {
serde_json::to_string_pretty(self).unwrap()
}
}
impl Default for Section {
fn default() -> Self {
Self {
ident: Ident {
magic: DOF_MAGIC,
model: DataModel::LP64,
encoding: DataEncoding::LittleEndian,
version: crate::dof_bindings::DOF_VERSION as u8,
dif_vers: crate::dof_bindings::DIF_VERSION as u8,
dif_ireg: crate::dof_bindings::DIF_DIR_NREGS as u8,
dif_treg: crate::dof_bindings::DIF_DTR_NREGS as u8,
},
providers: BTreeMap::new(),
}
}
}
#[derive(Debug, Clone, Serialize)]
pub struct Probe {
pub name: String,
pub function: String,
pub address: u64,
pub offsets: Vec<u32>,
pub enabled_offsets: Vec<u32>,
pub arguments: Vec<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct Provider {
pub name: String,
pub probes: BTreeMap<String, Probe>,
}