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}