1use std::collections::HashSet;
4
5use crate::section;
6use crate::*;
7
8use serde::{Deserialize, Serialize};
9
10use super::StrTabEntry;
11
12#[derive(Debug, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
13pub enum Contents64 {
14 Raw(Vec<u8>),
16 Symbols(Vec<symbol::Symbol64>),
18 RelaSymbols(Vec<relocation::Rela64>),
20 Dynamics(Vec<dynamic::Dyn64>),
22 StrTab(Vec<StrTabEntry>),
24}
25
26#[derive(Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
27pub struct Section64 {
28 pub name: String,
29 pub header: Shdr64,
30
31 pub contents: Contents64,
32}
33
34#[derive(Debug, Clone, Copy, Hash, PartialOrd, Ord, PartialEq, Eq, Serialize, Deserialize)]
35#[repr(C)]
36pub struct Shdr64 {
37 pub sh_name: Elf64Word,
39 pub sh_type: Elf64Word,
41 pub sh_flags: Elf64Xword,
43 pub sh_addr: Elf64Addr,
45 pub sh_offset: Elf64Off,
47 pub sh_size: Elf64Xword,
49 pub sh_link: Elf64Word,
51 pub sh_info: Elf64Word,
53 pub sh_addralign: Elf64Xword,
55 pub sh_entsize: Elf64Xword,
57}
58
59#[derive(Clone, Copy, Hash, PartialOrd, Ord, PartialEq, Eq)]
75#[repr(C)]
76pub struct ShdrPreparation64 {
77 pub sh_type: section::Type,
79 pub sh_flags: Elf64Xword,
81 pub sh_link: Elf64Word,
83 pub sh_info: Elf64Word,
85 pub sh_addralign: Elf64Xword,
87}
88
89impl Default for Shdr64 {
90 fn default() -> Self {
91 Self {
92 sh_name: 0,
93 sh_type: 0,
94 sh_flags: 0,
95 sh_addr: 0,
96 sh_offset: 0,
97 sh_size: 0,
98 sh_link: 0,
99 sh_info: 0,
100 sh_addralign: 0,
101 sh_entsize: 0,
102 }
103 }
104}
105
106#[allow(dead_code)]
107impl Shdr64 {
108 pub const SIZE: usize = 0x40;
109
110 pub fn get_type(&self) -> section::Type {
112 section::Type::from(self.sh_type)
113 }
114 pub fn get_flags(&self) -> HashSet<section::Flag> {
115 let mut mask: Elf64Xword = 0b1;
116 let mut flags = HashSet::new();
117 loop {
118 if mask == 0 {
119 break;
120 }
121 if self.sh_flags & mask != 0 {
122 flags.insert(section::Flag::from(mask));
123 }
124 mask <<= 1;
125 }
126
127 flags
128 }
129
130 pub fn set_type(&mut self, ty: section::Type) {
132 self.sh_type = ty.into();
133 }
134 pub fn set_flags<'a, I>(&mut self, flags: I)
135 where
136 I: Iterator<Item = &'a section::Flag>,
137 {
138 for flag in flags {
139 self.sh_flags = self.sh_flags | Into::<Elf64Xword>::into(*flag);
140 }
141 }
142
143 pub fn to_le_bytes(&self) -> Vec<u8> {
154 bincode::serialize(self).unwrap()
155 }
156}
157
158impl Section64 {
159 pub fn new_null_section() -> Self {
160 Self {
161 contents: Contents64::Raw(Default::default()),
162 header: Default::default(),
163 name: Default::default(),
164 }
165 }
166
167 pub fn new(name: String, hdr: ShdrPreparation64, contents: Contents64) -> Self {
168 Self {
169 contents,
170 name,
171 header: hdr.into(),
172 }
173 }
174
175 pub fn to_le_bytes(&self) -> Vec<u8> {
177 match &self.contents {
178 Contents64::Raw(bytes) => bytes.clone(),
179 Contents64::StrTab(strs) => {
180 let mut string_table: Vec<u8> = vec![0x00];
183
184 for st in strs {
185 for byte in st.v.as_bytes() {
186 string_table.push(*byte);
187 }
188 string_table.push(0x00);
189 }
190
191 string_table
192 }
193 Contents64::Symbols(syms) => {
194 let mut bytes = Vec::new();
195 for sym in syms.iter() {
196 bytes.append(&mut sym.to_le_bytes());
197 }
198 bytes
199 }
200 Contents64::RelaSymbols(rela_syms) => {
201 let mut bytes = Vec::new();
202 for sym in rela_syms.iter() {
203 bytes.append(&mut sym.to_le_bytes());
204 }
205 bytes
206 }
207 Contents64::Dynamics(dynamics) => {
208 let mut bytes = Vec::new();
209 for sym in dynamics.iter() {
210 bytes.append(&mut sym.to_le_bytes());
211 }
212 bytes
213 }
214 }
215 }
216}
217
218impl ShdrPreparation64 {
219 pub fn ty(mut self, t: section::Type) -> Self {
220 self.sh_type = t;
221 self
222 }
223
224 pub fn flags<'a, I>(mut self, flags: I) -> Self
225 where
226 I: Iterator<Item = &'a section::Flag>,
227 {
228 for flag in flags {
229 self.sh_flags |= Into::<Elf64Xword>::into(*flag);
230 }
231
232 self
233 }
234
235 pub fn link(mut self, link: Elf64Word) -> Self {
236 self.sh_link = link;
237 self
238 }
239 pub fn info(mut self, info: Elf64Word) -> Self {
240 self.sh_info = info;
241 self
242 }
243}
244
245impl Default for ShdrPreparation64 {
246 fn default() -> Self {
247 Self {
248 sh_type: section::Type::Null,
249 sh_flags: 0,
250 sh_link: 0,
251 sh_info: 0,
252 sh_addralign: 0,
253 }
254 }
255}
256
257impl Into<Shdr64> for ShdrPreparation64 {
258 fn into(self) -> Shdr64 {
259 Shdr64 {
260 sh_name: 0,
261 sh_type: self.sh_type.into(),
262 sh_flags: self.sh_flags,
263 sh_addr: 0,
264 sh_offset: 0,
265 sh_size: 0,
266 sh_link: self.sh_link,
267 sh_info: self.sh_info,
268 sh_addralign: self.sh_addralign,
269 sh_entsize: 0,
270 }
271 }
272}
273
274impl Contents64 {
275 pub fn size(&self) -> usize {
276 match self {
277 Contents64::Raw(bytes) => bytes.len(),
278 Contents64::StrTab(strs) => {
279 let total_len: usize = strs.iter().map(|s| s.v.len()).sum();
281 total_len + strs.len() + 1
282 }
283 Contents64::Symbols(syms) => symbol::Symbol64::SIZE * syms.len(),
284 Contents64::RelaSymbols(rela_syms) => {
285 relocation::Rela64::SIZE as usize * rela_syms.len()
286 }
287 Contents64::Dynamics(dyn_info) => dynamic::Dyn64::SIZE * dyn_info.len(),
288 }
289 }
290
291 pub fn new_string_table(strs: Vec<String>) -> Self {
292 let mut name_idx = 1;
293 let strs = strs
294 .iter()
295 .map(|s| {
296 let ent = StrTabEntry {
297 v: s.clone(),
298 idx: name_idx,
299 };
300 name_idx += s.len() + 1;
301 ent
302 })
303 .collect();
304
305 Contents64::StrTab(strs)
306 }
307}