use gaia_binary::{LittleEndian, ReadBytesExt};
use gaia_types::{helpers::Architecture, GaiaError};
use serde::{Deserialize, Serialize};
use std::io::Read;
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub struct CoffHeader {
pub machine: u16,
pub number_of_sections: u16,
pub time_date_stamp: u32,
pub pointer_to_symbol_table: u32,
pub number_of_symbols: u32,
pub size_of_optional_header: u16,
pub characteristics: u16,
}
impl CoffHeader {
pub fn new(machine: u16, number_of_sections: u16) -> Self {
CoffHeader {
machine,
number_of_sections,
time_date_stamp: 0,
pointer_to_symbol_table: 0,
number_of_symbols: 0,
size_of_optional_header: 0,
characteristics: 0,
}
}
pub fn with_timestamp(mut self, time_date_stamp: u32) -> Self {
self.time_date_stamp = time_date_stamp;
self
}
pub fn with_symbol_table(mut self, pointer_to_symbol_table: u32, number_of_symbols: u32) -> Self {
self.pointer_to_symbol_table = pointer_to_symbol_table;
self.number_of_symbols = number_of_symbols;
self
}
pub fn with_optional_header_size(mut self, size_of_optional_header: u16) -> Self {
self.size_of_optional_header = size_of_optional_header;
self
}
pub fn with_characteristics(mut self, characteristics: u16) -> Self {
self.characteristics = characteristics;
self
}
pub fn read<R: Read>(mut reader: R) -> Result<Self, GaiaError> {
Ok(CoffHeader {
machine: reader.read_u16::<LittleEndian>()?,
number_of_sections: reader.read_u16::<LittleEndian>()?,
time_date_stamp: reader.read_u32::<LittleEndian>()?,
pointer_to_symbol_table: reader.read_u32::<LittleEndian>()?,
number_of_symbols: reader.read_u32::<LittleEndian>()?,
size_of_optional_header: reader.read_u16::<LittleEndian>()?,
characteristics: reader.read_u16::<LittleEndian>()?,
})
}
pub fn get_architecture(&self) -> Architecture {
match self.machine {
0x014C => Architecture::X86,
0x8664 => Architecture::X86_64,
0x0200 => Architecture::ARM32,
0xAA64 => Architecture::ARM64,
_ => Architecture::Unknown,
}
}
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub struct SectionHeader {
pub name: [u8; 8],
pub virtual_size: u32,
pub virtual_address: u32,
pub size_of_raw_data: u32,
pub pointer_to_raw_data: u32,
pub pointer_to_relocations: u32,
pub pointer_to_line_numbers: u32,
pub number_of_relocations: u16,
pub number_of_line_numbers: u16,
pub characteristics: u32,
}
impl SectionHeader {
pub fn get_name(&self) -> &str {
unsafe {
let name = std::str::from_utf8_unchecked(&self.name);
name.trim_end_matches('\0')
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CoffSymbol {
pub name: String,
pub value: u32,
pub section_number: i16,
pub symbol_type: u16,
pub storage_class: u8,
pub number_of_aux_symbols: u8,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub struct CoffRelocation {
pub virtual_address: u32,
pub symbol_table_index: u32,
pub relocation_type: u16,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CoffSection {
pub header: SectionHeader,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub data: Vec<u8>,
pub relocations: Vec<CoffRelocation>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CoffObject {
pub header: CoffHeader,
pub sections: Vec<CoffSection>,
pub symbols: Vec<CoffSymbol>,
pub string_table: Vec<u8>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ArchiveMemberHeader {
pub name: String,
pub timestamp: u32,
pub user_id: u16,
pub group_id: u16,
pub mode: u32,
pub size: u32,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ArchiveMember {
pub header: ArchiveMemberHeader,
pub data: Vec<u8>,
pub coff_object: Option<CoffObject>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct StaticLibrary {
pub signature: String,
pub members: Vec<ArchiveMember>,
pub symbol_index: Vec<(String, usize)>, }
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub enum CoffFileType {
Object,
StaticLibrary,
Executable,
DynamicLibrary,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CoffInfo {
pub file_type: CoffFileType,
pub target_arch: Architecture,
pub section_count: u16,
pub symbol_count: u32,
pub file_size: u64,
pub timestamp: u32,
}