1use std::mem::size_of;
18
19use zerocopy::IntoBytes;
20
21use crate::dof_bindings::*;
22use crate::Section;
23
24fn build_section_data(section: &Section) -> Vec<(u32, Vec<u8>)> {
27    let mut probe_sections = Vec::new();
28    let mut provider_sections = Vec::new();
29    let mut strings = Vec::<u8>::new();
30    strings.push(0); let mut arguments = Vec::<u8>::new();
32    let mut offsets = Vec::new();
33    let mut enabled_offsets = Vec::new();
34
35    for (i, provider) in section.providers.values().enumerate() {
36        let mut provider_section = dof_provider {
37            dofpv_name: strings.len() as _,
38            ..Default::default()
39        };
40        strings.extend_from_slice(provider.name.as_bytes());
41        strings.push(0);
42
43        provider_section.dofpv_strtab = 0;
46        provider_section.dofpv_prargs = 1;
47        provider_section.dofpv_proffs = 2;
48        provider_section.dofpv_prenoffs = 3;
49        provider_section.dofpv_probes = (4 + i) as _;
50
51        let mut probe_section = Vec::with_capacity(provider.probes.len() * size_of::<dof_probe>());
52        for probe in provider.probes.values() {
53            let mut probe_t = dof_probe {
54                dofpr_addr: probe.address,
55                ..Default::default()
56            };
57
58            probe_t.dofpr_func = strings.len() as _;
60            strings.extend_from_slice(probe.function.as_bytes());
61            strings.push(0);
62
63            probe_t.dofpr_name = strings.len() as _;
65            strings.extend_from_slice(probe.name.as_bytes());
66            strings.push(0);
67
68            probe_t.dofpr_argidx = arguments.len() as _;
70            let argv = strings.len() as u32;
71            for (i, arg) in probe.arguments.iter().enumerate() {
72                strings.extend_from_slice(arg.as_bytes());
73                strings.push(0);
74                arguments.push(i as _);
75            }
76            probe_t.dofpr_nargv = argv;
77            probe_t.dofpr_nargc = probe.arguments.len() as _;
78            probe_t.dofpr_xargv = argv;
79            probe_t.dofpr_xargc = probe.arguments.len() as _;
80
81            probe_t.dofpr_offidx = offsets.len() as _;
83            offsets.extend_from_slice(&probe.offsets);
84            probe_t.dofpr_noffs = probe.offsets.len() as _;
85
86            probe_t.dofpr_enoffidx = enabled_offsets.len() as _;
88            enabled_offsets.extend_from_slice(&probe.enabled_offsets);
89            probe_t.dofpr_nenoffs = probe.enabled_offsets.len() as _;
90
91            probe_section.extend_from_slice(probe_t.as_bytes());
92        }
93        probe_sections.push(probe_section);
94        provider_sections.push(provider_section.as_bytes().to_vec());
95    }
96
97    let mut section_data = Vec::with_capacity(4 + 2 * probe_sections.len());
99    section_data.push((DOF_SECT_STRTAB, strings));
100
101    if arguments.is_empty() {
103        arguments.push(0);
104    }
105    section_data.push((DOF_SECT_PRARGS, arguments));
106
107    let offset_section = offsets
109        .iter()
110        .flat_map(|offset| offset.to_ne_bytes().to_vec())
111        .collect::<Vec<_>>();
112    section_data.push((DOF_SECT_PROFFS, offset_section));
113
114    let enabled_offset_section = enabled_offsets
116        .iter()
117        .flat_map(|offset| offset.to_ne_bytes().to_vec())
118        .collect::<Vec<_>>();
119    section_data.push((DOF_SECT_PRENOFFS, enabled_offset_section));
120
121    for probe_section in probe_sections.into_iter() {
124        section_data.push((DOF_SECT_PROBES, probe_section));
125    }
126    for provider_section in provider_sections.into_iter() {
127        section_data.push((DOF_SECT_PROVIDER, provider_section));
128    }
129
130    section_data
131}
132
133fn build_section_headers(
134    sections: Vec<(u32, Vec<u8>)>,
135    mut offset: usize,
136) -> (Vec<dof_sec>, Vec<Vec<u8>>, usize) {
137    let mut section_headers = Vec::with_capacity(sections.len());
138    let mut section_data = Vec::<Vec<u8>>::with_capacity(sections.len());
139
140    for (sec_type, data) in sections.into_iter() {
141        let (alignment, entry_size) = match sec_type {
143            DOF_SECT_STRTAB | DOF_SECT_PRARGS => (1, 1),
144            DOF_SECT_PROFFS | DOF_SECT_PRENOFFS => (size_of::<u32>(), size_of::<u32>()),
145            DOF_SECT_PROVIDER => (size_of::<u32>(), 0),
146            DOF_SECT_PROBES => (size_of::<u64>(), size_of::<dof_probe>()),
147            _ => unimplemented!(),
148        };
149
150        if offset % alignment > 0 {
154            let padding = alignment - offset % alignment;
155            section_data.last_mut().unwrap().extend(vec![0; padding]);
156            offset += padding;
157        }
158
159        let header = dof_sec {
160            dofs_type: sec_type,
161            dofs_align: alignment as u32,
162            dofs_flags: DOF_SECF_LOAD,
163            dofs_entsize: entry_size as u32,
164            dofs_offset: offset as u64,
165            dofs_size: data.len() as u64,
166        };
167
168        offset += data.len();
169        section_headers.push(header);
170        section_data.push(data);
171    }
172
173    (section_headers, section_data, offset)
174}
175
176pub fn serialize_section(section: &Section) -> Vec<u8> {
178    let sections = build_section_data(section);
179    let hdr_size = size_of::<dof_hdr>() + sections.len() * size_of::<dof_sec>();
180    let (section_headers, section_data, size) = build_section_headers(sections, hdr_size);
181
182    let header = dof_hdr {
183        dofh_ident: section.ident.as_bytes(),
184        dofh_flags: 0,
185        dofh_hdrsize: size_of::<dof_hdr>() as _,
186        dofh_secsize: size_of::<dof_sec>() as _,
187        dofh_secnum: section_headers.len() as _,
188        dofh_secoff: size_of::<dof_hdr>() as _,
189        dofh_loadsz: size as _,
190        dofh_filesz: size as _,
191        dofh_pad: 0,
192    };
193
194    let mut file_data = Vec::with_capacity(header.dofh_filesz as _);
195    file_data.extend(header.as_bytes());
196    for header in section_headers.into_iter() {
197        file_data.extend(header.as_bytes());
198    }
199    for data in section_data.into_iter() {
200        file_data.extend(data);
201    }
202    file_data
203}
204
205#[cfg(test)]
206mod test {
207    use super::build_section_headers;
208    use crate::dof_bindings::*;
209    #[test]
210    fn test_padding() {
211        let sections = vec![
212            (DOF_SECT_STRTAB, vec![96_u8]),
213            (DOF_SECT_PROFFS, vec![0x11_u8, 0x22_u8, 0x33_u8, 0x44_u8]),
214        ];
215
216        assert_eq!(sections[0].1.len(), 1);
217
218        let (_, section_data, size) = build_section_headers(sections, 0);
219
220        assert_eq!(section_data[0].len(), 4);
221        assert_eq!(size, 8);
222    }
223}