1use std::collections::HashSet;
4
5use crate::*;
6
7use serde::{Deserialize, Serialize};
8
9use super::StrTabEntry;
10
11#[derive(Debug, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
12pub enum Contents32 {
14 Raw(Vec<u8>),
16 StrTab(Vec<StrTabEntry>),
18 Symbols(Vec<symbol::Symbol32>),
20 RelaSymbols(Vec<relocation::Rela32>),
22 Dynamics(Vec<dynamic::Dyn32>),
24}
25
26#[derive(Default, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
27pub struct Section32 {
28 pub name: String,
29 pub header: Shdr32,
30 pub contents: Contents32,
31}
32
33#[derive(Debug, Clone, Copy, Hash, PartialOrd, Ord, PartialEq, Eq, Serialize, Deserialize)]
34#[repr(C)]
35pub struct Shdr32 {
36 pub sh_name: Elf32Word,
38 pub sh_type: Elf32Word,
40 pub sh_flags: Elf32Word,
42 pub sh_addr: Elf32Addr,
44 pub sh_offset: Elf32Off,
46 pub sh_size: Elf32Word,
48 pub sh_link: Elf32Word,
50 pub sh_info: Elf32Word,
52 pub sh_addralign: Elf32Word,
54 pub sh_entsize: Elf32Word,
56}
57
58#[derive(Clone, Copy, Hash, PartialOrd, Ord, PartialEq, Eq)]
74#[repr(C)]
75pub struct ShdrPreparation32 {
76 pub sh_type: section::Type,
78 pub sh_flags: Elf32Word,
80 pub sh_link: Elf32Word,
82 pub sh_info: Elf32Word,
84 pub sh_addralign: Elf32Word,
86}
87
88impl Default for Contents32 {
89 fn default() -> Self {
90 Contents32::Raw(Default::default())
91 }
92}
93
94impl Contents32 {
95 pub fn size(&self) -> usize {
96 match self {
97 Contents32::Raw(bytes) => bytes.len(),
98 Contents32::StrTab(strs) => {
99 let total_len: usize = strs.iter().map(|s| s.v.len()).sum();
101 total_len + strs.len() + 1
102 }
103 Contents32::Symbols(syms) => symbol::Symbol32::SIZE * syms.len(),
104 Contents32::RelaSymbols(rela_syms) => {
105 relocation::Rela32::SIZE as usize * rela_syms.len()
106 }
107 Contents32::Dynamics(dyn_info) => dynamic::Dyn32::SIZE * dyn_info.len(),
108 }
109 }
110
111 pub fn new_string_table(strs: Vec<String>) -> Self {
112 let mut name_idx = 1;
113 let strs = strs
114 .iter()
115 .map(|s| {
116 let ent = StrTabEntry {
117 v: s.clone(),
118 idx: name_idx,
119 };
120 name_idx += s.len() + 1;
121 ent
122 })
123 .collect();
124
125 Contents32::StrTab(strs)
126 }
127}
128
129impl Default for Shdr32 {
130 fn default() -> Self {
131 Self {
132 sh_name: 0,
133 sh_type: 0,
134 sh_flags: 0,
135 sh_addr: 0,
136 sh_offset: 0,
137 sh_size: 0,
138 sh_link: 0,
139 sh_info: 0,
140 sh_addralign: 0,
141 sh_entsize: 0,
142 }
143 }
144}
145
146impl Section32 {
147 pub fn new(name: String, hdr: ShdrPreparation32, contents: Contents32) -> Self {
148 Self {
149 contents,
150 name,
151 header: hdr.into(),
152 }
153 }
154
155 pub fn to_le_bytes(&self) -> Vec<u8> {
157 match &self.contents {
158 Contents32::Raw(bytes) => bytes.clone(),
159 Contents32::StrTab(strs) => {
160 let mut string_table: Vec<u8> = vec![0x00];
163
164 for st in strs {
165 for byte in st.v.as_bytes() {
166 string_table.push(*byte);
167 }
168 string_table.push(0x00);
169 }
170
171 string_table
172 }
173 Contents32::Symbols(syms) => {
174 let mut bytes = Vec::new();
175 for sym in syms.iter() {
176 bytes.append(&mut sym.to_le_bytes());
177 }
178 bytes
179 }
180 Contents32::RelaSymbols(rela_syms) => {
181 let mut bytes = Vec::new();
182 for sym in rela_syms.iter() {
183 bytes.append(&mut sym.to_le_bytes());
184 }
185 bytes
186 }
187 Contents32::Dynamics(dynamics) => {
188 let mut bytes = Vec::new();
189 for sym in dynamics.iter() {
190 bytes.append(&mut sym.to_le_bytes());
191 }
192 bytes
193 }
194 }
195 }
196
197 pub fn new_null_section() -> Self {
198 Default::default()
199 }
200}
201
202#[allow(dead_code)]
203impl Shdr32 {
204 pub const SIZE: usize = 40;
205 pub fn get_type(&self) -> section::Type {
207 section::Type::from(self.sh_type)
208 }
209 pub fn get_flags(&self) -> HashSet<section::Flag> {
210 let mut mask: Elf32Word = 0b1;
211 let mut flags = HashSet::new();
212 loop {
213 if mask == 0 {
214 break;
215 }
216 if self.sh_flags & mask != 0 {
217 flags.insert(section::Flag::from(mask));
218 }
219 mask <<= 1;
220 }
221
222 flags
223 }
224 pub fn set_type(&mut self, ty: section::Type) {
226 self.sh_type = ty.into();
227 }
228 pub fn set_flags<'a, I>(&mut self, flags: I)
229 where
230 I: Iterator<Item = &'a section::Flag>,
231 {
232 for flag in flags {
233 self.sh_flags = self.sh_flags | Into::<Elf32Word>::into(*flag);
234 }
235 }
236
237 pub fn to_le_bytes(&self) -> Vec<u8> {
248 bincode::serialize(self).unwrap()
249 }
250}
251
252impl ShdrPreparation32 {
253 pub fn ty(mut self, t: section::Type) -> Self {
254 self.sh_type = t;
255 self
256 }
257
258 pub fn flags<'a, I>(mut self, flags: I) -> Self
259 where
260 I: Iterator<Item = &'a section::Flag>,
261 {
262 for flag in flags {
263 self.sh_flags |= Into::<Elf32Word>::into(*flag);
264 }
265
266 self
267 }
268
269 pub fn link(mut self, link: Elf32Word) -> Self {
270 self.sh_link = link;
271 self
272 }
273 pub fn info(mut self, info: Elf32Word) -> Self {
274 self.sh_info = info;
275 self
276 }
277}
278
279impl Default for ShdrPreparation32 {
280 fn default() -> Self {
281 Self {
282 sh_type: section::Type::Null,
283 sh_flags: 0,
284 sh_link: 0,
285 sh_info: 0,
286 sh_addralign: 0,
287 }
288 }
289}
290impl Into<Shdr32> for ShdrPreparation32 {
291 fn into(self) -> Shdr32 {
292 Shdr32 {
293 sh_name: 0,
294 sh_type: self.sh_type.into(),
295 sh_flags: self.sh_flags,
296 sh_addr: 0,
297 sh_offset: 0,
298 sh_size: 0,
299 sh_link: self.sh_link,
300 sh_info: self.sh_info,
301 sh_addralign: self.sh_addralign,
302 sh_entsize: 0,
303 }
304 }
305}
306
307#[cfg(test)]
308mod elf32_tests {
309 use super::*;
310
311 #[test]
312 fn section32_test() {
313 let sct = Section32::new_null_section();
314
315 assert_eq!(vec![0x00; Shdr32::SIZE], sct.header.to_le_bytes(),);
316
317 assert_eq!(Vec::new() as Vec<u8>, sct.to_le_bytes(),);
318 }
319}