]> git.proxmox.com Git - rustc.git/blob - vendor/object/src/read/coff/section.rs
New upstream version 1.54.0+dfsg1
[rustc.git] / vendor / object / src / read / coff / section.rs
1 use core::{iter, result, slice, str};
2
3 use crate::endian::LittleEndian as LE;
4 use crate::pe;
5 use crate::read::util::StringTable;
6 use crate::read::{
7 self, CompressedData, CompressedFileRange, Error, ObjectSection, ObjectSegment, ReadError,
8 ReadRef, Result, SectionFlags, SectionIndex, SectionKind,
9 };
10
11 use super::{CoffFile, CoffRelocationIterator};
12
13 /// The table of section headers in a COFF or PE file.
14 #[derive(Debug, Default, Clone, Copy)]
15 pub struct SectionTable<'data> {
16 sections: &'data [pe::ImageSectionHeader],
17 }
18
19 impl<'data> SectionTable<'data> {
20 /// Parse the section table.
21 ///
22 /// `data` must be the entire file data.
23 /// `offset` must be after the optional file header.
24 pub fn parse<R: ReadRef<'data>>(
25 header: &pe::ImageFileHeader,
26 data: R,
27 offset: u64,
28 ) -> Result<Self> {
29 let sections = data
30 .read_slice_at(offset, header.number_of_sections.get(LE).into())
31 .read_error("Invalid COFF/PE section headers")?;
32 Ok(SectionTable { sections })
33 }
34
35 /// Iterate over the section headers.
36 ///
37 /// Warning: sections indices start at 1.
38 #[inline]
39 pub fn iter(&self) -> slice::Iter<'data, pe::ImageSectionHeader> {
40 self.sections.iter()
41 }
42
43 /// Return true if the section table is empty.
44 #[inline]
45 pub fn is_empty(&self) -> bool {
46 self.sections.is_empty()
47 }
48
49 /// The number of section headers.
50 #[inline]
51 pub fn len(&self) -> usize {
52 self.sections.len()
53 }
54
55 /// Return the section header at the given index.
56 ///
57 /// The index is 1-based.
58 pub fn section(&self, index: usize) -> read::Result<&'data pe::ImageSectionHeader> {
59 self.sections
60 .get(index.wrapping_sub(1))
61 .read_error("Invalid COFF/PE section index")
62 }
63
64 /// Return the section header with the given name.
65 ///
66 /// The returned index is 1-based.
67 ///
68 /// Ignores sections with invalid names.
69 pub fn section_by_name(
70 &self,
71 strings: StringTable<'data>,
72 name: &[u8],
73 ) -> Option<(usize, &'data pe::ImageSectionHeader)> {
74 self.sections
75 .iter()
76 .enumerate()
77 .find(|(_, section)| section.name(strings) == Ok(name))
78 .map(|(index, section)| (index + 1, section))
79 }
80 }
81
82 /// An iterator over the loadable sections of a `CoffFile`.
83 #[derive(Debug)]
84 pub struct CoffSegmentIterator<'data, 'file, R: ReadRef<'data> = &'data [u8]> {
85 pub(super) file: &'file CoffFile<'data, R>,
86 pub(super) iter: slice::Iter<'data, pe::ImageSectionHeader>,
87 }
88
89 impl<'data, 'file, R: ReadRef<'data>> Iterator for CoffSegmentIterator<'data, 'file, R> {
90 type Item = CoffSegment<'data, 'file, R>;
91
92 fn next(&mut self) -> Option<Self::Item> {
93 self.iter.next().map(|section| CoffSegment {
94 file: self.file,
95 section,
96 })
97 }
98 }
99
100 /// A loadable section of a `CoffFile`.
101 #[derive(Debug)]
102 pub struct CoffSegment<'data, 'file, R: ReadRef<'data> = &'data [u8]> {
103 pub(super) file: &'file CoffFile<'data, R>,
104 pub(super) section: &'data pe::ImageSectionHeader,
105 }
106
107 impl<'data, 'file, R: ReadRef<'data>> CoffSegment<'data, 'file, R> {
108 fn bytes(&self) -> Result<&'data [u8]> {
109 self.section
110 .coff_data(self.file.data)
111 .read_error("Invalid COFF section offset or size")
112 }
113 }
114
115 impl<'data, 'file, R: ReadRef<'data>> read::private::Sealed for CoffSegment<'data, 'file, R> {}
116
117 impl<'data, 'file, R: ReadRef<'data>> ObjectSegment<'data> for CoffSegment<'data, 'file, R> {
118 #[inline]
119 fn address(&self) -> u64 {
120 u64::from(self.section.virtual_address.get(LE))
121 }
122
123 #[inline]
124 fn size(&self) -> u64 {
125 u64::from(self.section.virtual_size.get(LE))
126 }
127
128 #[inline]
129 fn align(&self) -> u64 {
130 self.section.coff_alignment()
131 }
132
133 #[inline]
134 fn file_range(&self) -> (u64, u64) {
135 let (offset, size) = self.section.coff_file_range().unwrap_or((0, 0));
136 (u64::from(offset), u64::from(size))
137 }
138
139 fn data(&self) -> Result<&'data [u8]> {
140 self.bytes()
141 }
142
143 fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> {
144 Ok(read::util::data_range(
145 self.bytes()?,
146 self.address(),
147 address,
148 size,
149 ))
150 }
151
152 #[inline]
153 fn name(&self) -> Result<Option<&str>> {
154 let name = self.section.name(self.file.common.symbols.strings())?;
155 Ok(Some(
156 str::from_utf8(name)
157 .ok()
158 .read_error("Non UTF-8 COFF section name")?,
159 ))
160 }
161 }
162
163 /// An iterator over the sections of a `CoffFile`.
164 #[derive(Debug)]
165 pub struct CoffSectionIterator<'data, 'file, R: ReadRef<'data> = &'data [u8]> {
166 pub(super) file: &'file CoffFile<'data, R>,
167 pub(super) iter: iter::Enumerate<slice::Iter<'data, pe::ImageSectionHeader>>,
168 }
169
170 impl<'data, 'file, R: ReadRef<'data>> Iterator for CoffSectionIterator<'data, 'file, R> {
171 type Item = CoffSection<'data, 'file, R>;
172
173 fn next(&mut self) -> Option<Self::Item> {
174 self.iter.next().map(|(index, section)| CoffSection {
175 file: self.file,
176 index: SectionIndex(index + 1),
177 section,
178 })
179 }
180 }
181
182 /// A section of a `CoffFile`.
183 #[derive(Debug)]
184 pub struct CoffSection<'data, 'file, R: ReadRef<'data> = &'data [u8]> {
185 pub(super) file: &'file CoffFile<'data, R>,
186 pub(super) index: SectionIndex,
187 pub(super) section: &'data pe::ImageSectionHeader,
188 }
189
190 impl<'data, 'file, R: ReadRef<'data>> CoffSection<'data, 'file, R> {
191 fn bytes(&self) -> Result<&'data [u8]> {
192 self.section
193 .coff_data(self.file.data)
194 .read_error("Invalid COFF section offset or size")
195 }
196 }
197
198 impl<'data, 'file, R: ReadRef<'data>> read::private::Sealed for CoffSection<'data, 'file, R> {}
199
200 impl<'data, 'file, R: ReadRef<'data>> ObjectSection<'data> for CoffSection<'data, 'file, R> {
201 type RelocationIterator = CoffRelocationIterator<'data, 'file, R>;
202
203 #[inline]
204 fn index(&self) -> SectionIndex {
205 self.index
206 }
207
208 #[inline]
209 fn address(&self) -> u64 {
210 u64::from(self.section.virtual_address.get(LE))
211 }
212
213 #[inline]
214 fn size(&self) -> u64 {
215 // TODO: This may need to be the length from the auxiliary symbol for this section.
216 u64::from(self.section.size_of_raw_data.get(LE))
217 }
218
219 #[inline]
220 fn align(&self) -> u64 {
221 self.section.coff_alignment()
222 }
223
224 #[inline]
225 fn file_range(&self) -> Option<(u64, u64)> {
226 let (offset, size) = self.section.coff_file_range()?;
227 Some((u64::from(offset), u64::from(size)))
228 }
229
230 fn data(&self) -> Result<&'data [u8]> {
231 self.bytes()
232 }
233
234 fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> {
235 Ok(read::util::data_range(
236 self.bytes()?,
237 self.address(),
238 address,
239 size,
240 ))
241 }
242
243 #[inline]
244 fn compressed_file_range(&self) -> Result<CompressedFileRange> {
245 Ok(CompressedFileRange::none(self.file_range()))
246 }
247
248 #[inline]
249 fn compressed_data(&self) -> Result<CompressedData<'data>> {
250 self.data().map(CompressedData::none)
251 }
252
253 #[inline]
254 fn name(&self) -> Result<&str> {
255 let name = self.section.name(self.file.common.symbols.strings())?;
256 str::from_utf8(name)
257 .ok()
258 .read_error("Non UTF-8 COFF section name")
259 }
260
261 #[inline]
262 fn segment_name(&self) -> Result<Option<&str>> {
263 Ok(None)
264 }
265
266 #[inline]
267 fn kind(&self) -> SectionKind {
268 self.section.kind()
269 }
270
271 fn relocations(&self) -> CoffRelocationIterator<'data, 'file, R> {
272 let relocations = self.section.coff_relocations(self.file.data).unwrap_or(&[]);
273 CoffRelocationIterator {
274 file: self.file,
275 iter: relocations.iter(),
276 }
277 }
278
279 fn flags(&self) -> SectionFlags {
280 SectionFlags::Coff {
281 characteristics: self.section.characteristics.get(LE),
282 }
283 }
284 }
285
286 impl pe::ImageSectionHeader {
287 pub(crate) fn kind(&self) -> SectionKind {
288 let characteristics = self.characteristics.get(LE);
289 if characteristics & (pe::IMAGE_SCN_CNT_CODE | pe::IMAGE_SCN_MEM_EXECUTE) != 0 {
290 SectionKind::Text
291 } else if characteristics & pe::IMAGE_SCN_CNT_INITIALIZED_DATA != 0 {
292 if characteristics & pe::IMAGE_SCN_MEM_DISCARDABLE != 0 {
293 SectionKind::Other
294 } else if characteristics & pe::IMAGE_SCN_MEM_WRITE != 0 {
295 SectionKind::Data
296 } else {
297 SectionKind::ReadOnlyData
298 }
299 } else if characteristics & pe::IMAGE_SCN_CNT_UNINITIALIZED_DATA != 0 {
300 SectionKind::UninitializedData
301 } else if characteristics & pe::IMAGE_SCN_LNK_INFO != 0 {
302 SectionKind::Linker
303 } else {
304 SectionKind::Unknown
305 }
306 }
307 }
308
309 impl pe::ImageSectionHeader {
310 /// Return the section name.
311 ///
312 /// This handles decoding names that are offsets into the symbol string table.
313 pub fn name<'data>(&'data self, strings: StringTable<'data>) -> Result<&'data [u8]> {
314 let bytes = &self.name;
315 Ok(if bytes[0] == b'/' {
316 let mut offset = 0;
317 if bytes[1] == b'/' {
318 for byte in bytes[2..].iter() {
319 let digit = match byte {
320 b'A'..=b'Z' => byte - b'A',
321 b'a'..=b'z' => byte - b'a' + 26,
322 b'0'..=b'9' => byte - b'0' + 52,
323 b'+' => 62,
324 b'/' => 63,
325 _ => return Err(Error("Invalid COFF section name base-64 offset")),
326 };
327 offset = offset * 64 + digit as u32;
328 }
329 } else {
330 for byte in bytes[1..].iter() {
331 let digit = match byte {
332 b'0'..=b'9' => byte - b'0',
333 0 => break,
334 _ => return Err(Error("Invalid COFF section name base-10 offset")),
335 };
336 offset = offset * 10 + digit as u32;
337 }
338 };
339 strings
340 .get(offset)
341 .read_error("Invalid COFF section name offset")?
342 } else {
343 self.raw_name()
344 })
345 }
346
347 /// Return the raw section name.
348 pub fn raw_name(&self) -> &[u8] {
349 let bytes = &self.name;
350 match memchr::memchr(b'\0', bytes) {
351 Some(end) => &bytes[..end],
352 None => &bytes[..],
353 }
354 }
355
356 /// Return the offset and size of the section in a COFF file.
357 ///
358 /// Returns `None` for sections that have no data in the file.
359 pub fn coff_file_range(&self) -> Option<(u32, u32)> {
360 if self.characteristics.get(LE) & pe::IMAGE_SCN_CNT_UNINITIALIZED_DATA != 0 {
361 None
362 } else {
363 let offset = self.pointer_to_raw_data.get(LE);
364 // Note: virtual size is not used for COFF.
365 let size = self.size_of_raw_data.get(LE);
366 Some((offset, size))
367 }
368 }
369
370 /// Return the section data in a COFF file.
371 ///
372 /// Returns `Ok(&[])` if the section has no data.
373 /// Returns `Err` for invalid values.
374 pub fn coff_data<'data, R: ReadRef<'data>>(&self, data: R) -> result::Result<&'data [u8], ()> {
375 if let Some((offset, size)) = self.coff_file_range() {
376 data.read_bytes_at(offset.into(), size.into())
377 } else {
378 Ok(&[])
379 }
380 }
381
382 /// Return the section alignment in bytes.
383 ///
384 /// This is only valid for sections in a COFF file.
385 pub fn coff_alignment(&self) -> u64 {
386 match self.characteristics.get(LE) & pe::IMAGE_SCN_ALIGN_MASK {
387 pe::IMAGE_SCN_ALIGN_1BYTES => 1,
388 pe::IMAGE_SCN_ALIGN_2BYTES => 2,
389 pe::IMAGE_SCN_ALIGN_4BYTES => 4,
390 pe::IMAGE_SCN_ALIGN_8BYTES => 8,
391 pe::IMAGE_SCN_ALIGN_16BYTES => 16,
392 pe::IMAGE_SCN_ALIGN_32BYTES => 32,
393 pe::IMAGE_SCN_ALIGN_64BYTES => 64,
394 pe::IMAGE_SCN_ALIGN_128BYTES => 128,
395 pe::IMAGE_SCN_ALIGN_256BYTES => 256,
396 pe::IMAGE_SCN_ALIGN_512BYTES => 512,
397 pe::IMAGE_SCN_ALIGN_1024BYTES => 1024,
398 pe::IMAGE_SCN_ALIGN_2048BYTES => 2048,
399 pe::IMAGE_SCN_ALIGN_4096BYTES => 4096,
400 pe::IMAGE_SCN_ALIGN_8192BYTES => 8192,
401 _ => 16,
402 }
403 }
404
405 /// Read the relocations in a COFF file.
406 ///
407 /// `data` must be the entire file data.
408 pub fn coff_relocations<'data, R: ReadRef<'data>>(
409 &self,
410 data: R,
411 ) -> read::Result<&'data [pe::ImageRelocation]> {
412 let pointer = self.pointer_to_relocations.get(LE).into();
413 let number = self.number_of_relocations.get(LE).into();
414 data.read_slice_at(pointer, number)
415 .read_error("Invalid COFF relocation offset or number")
416 }
417 }