use std::collections::HashSet;
use crate::*;
use serde::{Deserialize, Serialize};
use super::StrTabEntry;
#[derive(Debug, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
pub enum Contents32 {
Raw(Vec<u8>),
StrTab(Vec<StrTabEntry>),
Symbols(Vec<symbol::Symbol32>),
RelaSymbols(Vec<relocation::Rela32>),
Dynamics(Vec<dynamic::Dyn32>),
}
#[derive(Default, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
pub struct Section32 {
pub name: String,
pub header: Shdr32,
pub contents: Contents32,
}
#[derive(Debug, Clone, Copy, Hash, PartialOrd, Ord, PartialEq, Eq, Serialize, Deserialize)]
#[repr(C)]
pub struct Shdr32 {
pub sh_name: Elf32Word,
pub sh_type: Elf32Word,
pub sh_flags: Elf32Word,
pub sh_addr: Elf32Addr,
pub sh_offset: Elf32Off,
pub sh_size: Elf32Word,
pub sh_link: Elf32Word,
pub sh_info: Elf32Word,
pub sh_addralign: Elf32Word,
pub sh_entsize: Elf32Word,
}
#[derive(Clone, Copy, Hash, PartialOrd, Ord, PartialEq, Eq)]
#[repr(C)]
pub struct ShdrPreparation32 {
pub sh_type: section::Type,
pub sh_flags: Elf32Word,
pub sh_link: Elf32Word,
pub sh_info: Elf32Word,
pub sh_addralign: Elf32Word,
}
impl Default for Contents32 {
fn default() -> Self {
Contents32::Raw(Default::default())
}
}
impl Contents32 {
pub fn size(&self) -> usize {
match self {
Contents32::Raw(bytes) => bytes.len(),
Contents32::StrTab(strs) => {
let total_len: usize = strs.iter().map(|s| s.v.len()).sum();
total_len + strs.len() + 1
}
Contents32::Symbols(syms) => symbol::Symbol32::SIZE * syms.len(),
Contents32::RelaSymbols(rela_syms) => {
relocation::Rela32::SIZE as usize * rela_syms.len()
}
Contents32::Dynamics(dyn_info) => dynamic::Dyn32::SIZE * dyn_info.len(),
}
}
}
impl Default for Shdr32 {
fn default() -> Self {
Self {
sh_name: 0,
sh_type: 0,
sh_flags: 0,
sh_addr: 0,
sh_offset: 0,
sh_size: 0,
sh_link: 0,
sh_info: 0,
sh_addralign: 0,
sh_entsize: 0,
}
}
}
impl Section32 {
pub fn new(name: String, hdr: ShdrPreparation32, contents: Contents32) -> Self {
Self {
contents,
name,
header: hdr.into(),
}
}
pub fn to_le_bytes(&self) -> Vec<u8> {
match &self.contents {
Contents32::Raw(bytes) => bytes.clone(),
Contents32::StrTab(strs) => {
let mut string_table: Vec<u8> = vec![0x00];
for st in strs {
for byte in st.v.as_bytes() {
string_table.push(*byte);
}
string_table.push(0x00);
}
string_table
}
Contents32::Symbols(syms) => {
let mut bytes = Vec::new();
for sym in syms.iter() {
bytes.append(&mut sym.to_le_bytes());
}
bytes
}
Contents32::RelaSymbols(rela_syms) => {
let mut bytes = Vec::new();
for sym in rela_syms.iter() {
bytes.append(&mut sym.to_le_bytes());
}
bytes
}
Contents32::Dynamics(dynamics) => {
let mut bytes = Vec::new();
for sym in dynamics.iter() {
bytes.append(&mut sym.to_le_bytes());
}
bytes
}
}
}
pub fn new_null_section() -> Self {
Default::default()
}
}
#[allow(dead_code)]
impl Shdr32 {
pub const SIZE: usize = 40;
pub fn get_type(&self) -> section::Type {
section::Type::from(self.sh_type)
}
pub fn get_flags(&self) -> HashSet<section::Flag> {
let mut mask: Elf32Word = 0b1;
let mut flags = HashSet::new();
loop {
if mask == 0 {
break;
}
if self.sh_flags & mask != 0 {
flags.insert(section::Flag::from(mask));
}
mask <<= 1;
}
flags
}
pub fn set_type(&mut self, ty: section::Type) {
self.sh_type = ty.into();
}
pub fn set_flags<'a, I>(&mut self, flags: I)
where
I: Iterator<Item = &'a section::Flag>,
{
for flag in flags {
self.sh_flags = self.sh_flags | Into::<Elf32Word>::into(*flag);
}
}
pub fn to_le_bytes(&self) -> Vec<u8> {
bincode::serialize(self).unwrap()
}
}
impl ShdrPreparation32 {
pub fn ty(mut self, t: section::Type) -> Self {
self.sh_type = t;
self
}
pub fn flags<'a, I>(mut self, flags: I) -> Self
where
I: Iterator<Item = &'a section::Flag>,
{
for flag in flags {
self.sh_flags |= Into::<Elf32Word>::into(*flag);
}
self
}
pub fn link(mut self, link: Elf32Word) -> Self {
self.sh_link = link;
self
}
pub fn info(mut self, info: Elf32Word) -> Self {
self.sh_info = info;
self
}
}
impl Default for ShdrPreparation32 {
fn default() -> Self {
Self {
sh_type: section::Type::Null,
sh_flags: 0,
sh_link: 0,
sh_info: 0,
sh_addralign: 0,
}
}
}
impl Into<Shdr32> for ShdrPreparation32 {
fn into(self) -> Shdr32 {
Shdr32 {
sh_name: 0,
sh_type: self.sh_type.into(),
sh_flags: self.sh_flags,
sh_addr: 0,
sh_offset: 0,
sh_size: 0,
sh_link: self.sh_link,
sh_info: self.sh_info,
sh_addralign: self.sh_addralign,
sh_entsize: 0,
}
}
}
#[cfg(test)]
mod elf32_tests {
use super::*;
#[test]
fn section32_test() {
let sct = Section32::new_null_section();
assert_eq!(vec![0x00; Shdr32::SIZE], sct.header.to_le_bytes(),);
assert_eq!(Vec::new() as Vec<u8>, sct.to_le_bytes(),);
}
}