diff --git a/Cargo.toml b/Cargo.toml index c352be0..5a5aa89 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ version = "0.1.17" default = ["display"] display = ["time"] integration_tests = [] +serde = ["dep:serde", "uuid/serde"] [dependencies] bitflags = "1.0" @@ -22,7 +23,8 @@ libc = "0.2" log = "0.4" thiserror = "1.0" uuid = "1.1" -time = {version = "0.3", features = ["formatting", "macros"], optional = true} +time = { version = "0.3", features = ["formatting", "macros"], optional = true } +serde = { version = "1.0", features = ["derive", "rc"], optional = true } [dev-dependencies] anyhow = "1.0" diff --git a/src/commands.rs b/src/commands.rs index 1f9e94b..a68be4e 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -23,6 +23,7 @@ use crate::{ /// X.Y.Z is encoded in nibbles xxxx.yy.zz /// #[derive(Debug, Default, Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct VersionTag(u32); impl VersionTag { @@ -83,6 +84,7 @@ impl fmt::Display for VersionTag { /// A.B.C.D.E packed as a24.b10.c10.d10.e10 /// #[derive(Debug, Default, Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct SourceVersionTag(u64); impl From for u64 { @@ -122,6 +124,7 @@ impl fmt::Display for SourceVersionTag { /// The min OS version on which this binary was built to run. /// #[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub enum BuildTarget { MacOsX, IPhoneOs, @@ -160,6 +163,7 @@ impl From for u32 { /// of 4 bytes must be zero. /// #[derive(Debug, Default, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct LcString(pub usize, pub String); impl LcString { @@ -193,6 +197,7 @@ impl Deref for LcString { /// The address of where the headers are loaded is in `header_addr`. /// (THIS IS OBSOLETE and no longer supported). #[derive(Debug, Default, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct FvmLib { /// library's target pathname pub name: LcString, @@ -211,6 +216,7 @@ pub struct FvmLib { /// built and copied into user so it can be use to determined if the library used /// at runtime is exactly the same as used to built the program. #[derive(Debug, Default, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct DyLib { /// library's path name pub name: LcString, @@ -223,6 +229,7 @@ pub struct DyLib { } /// a table of contents entry +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct DyLibTocEntry { /// the defined external symbol (index into the symbol table) pub symbol_index: u32, @@ -231,6 +238,7 @@ pub struct DyLibTocEntry { } /// a module table entry +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct DyLibModule { /// the module name (index into string table) pub module_name: u32, @@ -270,6 +278,7 @@ pub struct DyLibModule { /// of data in the __LINKEDIT segment. /// #[derive(Debug, Default, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct LinkEditData { /// file offset of data in __LINKEDIT segment pub off: u32, @@ -278,6 +287,7 @@ pub struct LinkEditData { } #[derive(Debug, Clone, Copy, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub enum X86ThreadFlavor { x86_THREAD_STATE32 = 1, x86_FLOAT_STATE32 = 2, @@ -294,6 +304,7 @@ pub enum X86ThreadFlavor { } #[derive(Debug, Clone, Copy, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub enum ARMThreadFlavors { ARM_THREAD_STATE = 1, ARM_VFP_STATE = 2, @@ -305,6 +316,7 @@ pub enum ARMThreadFlavors { } #[derive(Debug, Clone, Copy, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub enum PPCThreadFlavors { PPC_THREAD_STATE = 1, PPC_FLOAT_STATE = 2, @@ -316,6 +328,7 @@ pub enum PPCThreadFlavors { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub enum ThreadState { I386 { __eax: u32, @@ -408,6 +421,7 @@ pub enum ThreadState { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub enum Platform { macOS, iOS, @@ -418,6 +432,7 @@ pub enum Platform { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub enum Tool { Clang, Swift, @@ -429,6 +444,7 @@ pub enum Tool { /// binary was built to run for its platform. The list of known platforms and /// tool values following it. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct BuildVersion { pub platform: u32, /// X.Y.Z is encoded in nibbles xxxx.yy.zz @@ -453,6 +469,7 @@ impl BuildVersion { } #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct BuildTool { pub tool: u32, pub version: VersionTag, @@ -472,6 +489,7 @@ impl BuildTool { /// The load commands directly follow the mach header. /// #[derive(Debug, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub enum LoadCommand { /// The segment load command indicates that a part of this file is to be /// mapped into the task's address space. @@ -1665,6 +1683,7 @@ where /// but the section attributes are not (it may have more than one attribute). /// #[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct SectionFlags(u32); impl SectionFlags { @@ -1712,6 +1731,7 @@ impl From for u32 { /// /// #[derive(Debug, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct Section { /// name of this section pub sectname: String, diff --git a/src/consts.rs b/src/consts.rs index f02099b..230b0da 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -597,6 +597,7 @@ pub const LC_DYLD_CHAINED_FIXUPS: u32 = 0x34 | LC_REQ_DYLD; bitflags! { /// Constants for the flags field of the segment_command + #[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct SegmentFlags: u32 { /// the file contents for this segment is for the high part of the VM space, /// the low part is zero filled (for stacks in core files) @@ -689,6 +690,7 @@ pub const S_THREAD_LOCAL_INIT_FUNCTION_POINTERS: u32 = 0x15; bitflags! { /// Constants for the section attributes part of the flags field of a section structure. +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct SectionAttributes: u32 { /// User setable attributes const SECTION_ATTRIBUTES_USR = 0xff00_0000; @@ -860,6 +862,7 @@ pub const EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE: u8 = 0x02; bitflags! { /// The following are used on the flags byte of a terminal node in the export information. +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct ExportSymbolFlags: u32 { const EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION = 0x04; const EXPORT_SYMBOL_FLAGS_REEXPORT = 0x08; diff --git a/src/export.rs b/src/export.rs index 64271bc..e5c0e6e 100644 --- a/src/export.rs +++ b/src/export.rs @@ -7,6 +7,7 @@ use crate::consts::*; use crate::errors::{Error::*, Result}; #[derive(Clone, Copy, Debug, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub enum ExportKind { Regular, ThreadLocal, @@ -14,6 +15,7 @@ pub enum ExportKind { } #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub enum ExportType { Regular { address: usize }, Weak { address: usize }, @@ -22,6 +24,7 @@ pub enum ExportType { } #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] struct Exported { symbol: Option<(ExportKind, ExportType)>, edges: Vec<(String, Exported)>, @@ -102,6 +105,7 @@ impl Exported { } #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct ExportTrie<'a> { payload: &'a [u8], root: Exported, @@ -123,6 +127,7 @@ impl<'a> ExportTrie<'a> { } #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct ExportSymbol { pub name: String, pub kind: ExportKind, @@ -140,6 +145,7 @@ impl ExportSymbol { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct ExportSymbols<'a> { nodes: Vec<(String, &'a Exported)>, } diff --git a/src/loader.rs b/src/loader.rs index 058db55..b5b6727 100644 --- a/src/loader.rs +++ b/src/loader.rs @@ -23,8 +23,10 @@ type gid_t = libc::gid_t; type mode_t = libc::mode_t; /// The 32-bit mach/fat header +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub enum Arch32 {} /// The 64-bit mach/fat header +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub enum Arch64 {} /// The architecture of mach header @@ -71,6 +73,7 @@ impl MachHeaderParser for Arch64 { /// The mach header appears at the very beginning of the object file /// #[derive(Debug, Default, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct MachHeader { /// mach magic number identifier pub magic: u32, @@ -100,6 +103,7 @@ impl MachHeader { /// Wrap load command with size in the Mach-O file #[derive(Debug, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct MachCommand(pub LoadCommand, pub usize); impl MachCommand { @@ -117,6 +121,7 @@ impl MachCommand { /// structures. /// #[derive(Debug, Default, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct FatHeader { /// fat magic number identifier pub magic: u32, @@ -164,6 +169,7 @@ impl FatArchParser for Arch64 { /// in the file of the architecture specific member. /// #[derive(Debug, Default, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct FatArch { /// cpu specifier (int) pub cputype: cpu_type_t, @@ -185,6 +191,7 @@ impl FatArch { /// the archive file header #[derive(Debug, Default, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct ArHeader { pub ar_name: String, /// modification time @@ -263,6 +270,7 @@ impl ArHeader { /// string table whose first byte is numbered 0. /// #[derive(Debug, Default, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct RanLib { // string table index of pub ran_strx: off_t, @@ -272,6 +280,7 @@ pub struct RanLib { /// The abstract file block, including mach-o file, fat/universal file, /// archive file and symdef block #[derive(Debug, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub enum OFile { MachFile { header: MachHeader, diff --git a/src/opcode.rs b/src/opcode.rs index d387aa9..8988795 100644 --- a/src/opcode.rs +++ b/src/opcode.rs @@ -8,6 +8,7 @@ use crate::errors::{Error::*, Result}; /// Bind or rebase symbol type #[repr(u8)] #[derive(Clone, Copy, Debug, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub enum BindSymbolType { Pointer, TextAbsolute32, @@ -36,6 +37,7 @@ impl fmt::Display for BindSymbolType { bitflags! { /// Flags for bind symbol + #[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct BindSymbolFlags: u8 { const WEAK_IMPORT = BIND_SYMBOL_FLAGS_WEAK_IMPORT; const NON_WEAK_DEFINITION = BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION; @@ -50,6 +52,7 @@ impl Default for BindSymbolFlags { /// `OpCode` for the binding symbol #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub enum BindOpCode { Done, SetDyLibrary(isize), @@ -69,6 +72,21 @@ pub struct BindOpCodes<'a> { ptr_size: usize, } +#[cfg(feature = "serde")] +impl<'a> serde::Serialize for BindOpCodes<'a> { + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + // clone the iterator so we don't consume it + let this = BindOpCodes { + iter: self.iter.clone(), + ptr_size: self.ptr_size, + }; + serializer.collect_seq(this) + } +} + impl<'a> Iterator for BindOpCodes<'a> { type Item = BindOpCode; @@ -156,6 +174,7 @@ impl<'a> Iterator for BindOpCodes<'a> { /// The mach binding symbol information #[derive(Clone, Debug, Default, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct BindSymbol { pub dylib_ordinal: usize, pub segment_index: usize, @@ -167,6 +186,7 @@ pub struct BindSymbol { } /// A stream of BIND opcodes to bind all binding symbols. +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct Bind<'a> { opcodes: BindOpCodes<'a>, symbol: BindSymbol, @@ -253,6 +273,7 @@ impl<'a> Iterator for Bind<'a> { /// The mach weak binding symbol information #[derive(Clone, Debug, Default, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct WeakBindSymbol { pub segment_index: usize, pub name: String, @@ -263,6 +284,7 @@ pub struct WeakBindSymbol { } /// A stream of BIND opcodes to bind all weak binding symbols. +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct WeakBind<'a> { opcodes: BindOpCodes<'a>, symbol: WeakBindSymbol, @@ -351,6 +373,7 @@ impl<'a> Iterator for WeakBind<'a> { /// The mach lazy binding symbol information #[derive(Clone, Debug, Default, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct LazyBindSymbol { pub dylib_ordinal: usize, pub segment_index: usize, @@ -360,6 +383,7 @@ pub struct LazyBindSymbol { } /// A stream of BIND opcodes to bind all lazy symbols. +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct LazyBind<'a> { opcodes: BindOpCodes<'a>, symbol: LazyBindSymbol, @@ -433,6 +457,7 @@ impl<'a> Iterator for LazyBind<'a> { /// `OpCode` for the rebasing symbol #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub enum RebaseOpCode { Done, SetSymbolType(BindSymbolType), @@ -449,6 +474,21 @@ pub struct RebaseOpCodes<'a> { ptr_size: usize, } +#[cfg(feature = "serde")] +impl<'a> serde::Serialize for RebaseOpCodes<'a> { + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + // clone the iterator so we don't consume it + let this = RebaseOpCodes { + iter: self.iter.clone(), + ptr_size: self.ptr_size, + }; + serializer.collect_seq(this) + } +} + impl<'a> Iterator for RebaseOpCodes<'a> { type Item = RebaseOpCode; @@ -517,6 +557,7 @@ impl<'a> Iterator for RebaseOpCodes<'a> { } /// A stream of REBASE opcodes +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct Rebase<'a> { opcodes: RebaseOpCodes<'a>, symbol: RebaseSymbol, @@ -598,6 +639,7 @@ impl<'a> Iterator for Rebase<'a> { /// The rebase symbol information #[derive(Clone, Debug, Default, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub struct RebaseSymbol { pub segment_index: usize, pub symbol_offset: isize, diff --git a/src/symbol.rs b/src/symbol.rs index da63d30..88f163e 100644 --- a/src/symbol.rs +++ b/src/symbol.rs @@ -12,6 +12,7 @@ use crate::{ /// the link-edit 4.3BSD "stab" style symbol #[derive(Debug)] +#[cfg_attr(feature = "serde", derive(serde::Serialize))] pub enum Symbol<'a> { Undefined { name: Option<&'a str>, @@ -274,6 +275,28 @@ impl<'a> SymbolIter<'a> { } } +#[cfg(feature = "serde")] +impl<'a> serde::Serialize for SymbolIter<'a> { + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let mut cursor = self.cur.clone(); + let mut this = SymbolIter { + cur: &mut cursor, + sections: self.sections.clone(), + nsyms: self.nsyms.clone(), + stroff: self.stroff.clone(), + strsize: self.stroff.clone(), + is_bigend: self.is_bigend, + is_64bit: self.is_64bit, + }; + let res = serializer.collect_seq(this); + + res + } +} + impl<'a> Iterator for SymbolIter<'a> { type Item = Symbol<'a>;