| 1 | use core::convert::TryFrom; | 
| 2 | use core::{iter, result, slice, str}; | 
| 3 |  | 
| 4 | use crate::endian::LittleEndian as LE; | 
| 5 | use crate::pe; | 
| 6 | use crate::read::util::StringTable; | 
| 7 | use crate::read::{ | 
| 8 |     self, CompressedData, CompressedFileRange, Error, ObjectSection, ObjectSegment, ReadError, | 
| 9 |     ReadRef, Result, SectionFlags, SectionIndex, SectionKind, SegmentFlags, | 
| 10 | }; | 
| 11 |  | 
| 12 | use super::{CoffFile, CoffHeader, CoffRelocationIterator}; | 
| 13 |  | 
| 14 | /// The table of section headers in a COFF or PE file. | 
| 15 | /// | 
| 16 | /// Returned by [`CoffHeader::sections`] and | 
| 17 | /// [`ImageNtHeaders::sections`](crate::read::pe::ImageNtHeaders::sections). | 
| 18 | #[derive (Debug, Default, Clone, Copy)] | 
| 19 | pub struct SectionTable<'data> { | 
| 20 |     sections: &'data [pe::ImageSectionHeader], | 
| 21 | } | 
| 22 |  | 
| 23 | impl<'data> SectionTable<'data> { | 
| 24 |     /// Parse the section table. | 
| 25 |     /// | 
| 26 |     /// `data` must be the entire file data. | 
| 27 |     /// `offset` must be after the optional file header. | 
| 28 |     pub fn parse<Coff: CoffHeader, R: ReadRef<'data>>( | 
| 29 |         header: &Coff, | 
| 30 |         data: R, | 
| 31 |         offset: u64, | 
| 32 |     ) -> Result<Self> { | 
| 33 |         let sections = data | 
| 34 |             .read_slice_at(offset, header.number_of_sections() as usize) | 
| 35 |             .read_error("Invalid COFF/PE section headers" )?; | 
| 36 |         Ok(SectionTable { sections }) | 
| 37 |     } | 
| 38 |  | 
| 39 |     /// Iterate over the section headers. | 
| 40 |     /// | 
| 41 |     /// Warning: sections indices start at 1. | 
| 42 |     #[inline ] | 
| 43 |     pub fn iter(&self) -> slice::Iter<'data, pe::ImageSectionHeader> { | 
| 44 |         self.sections.iter() | 
| 45 |     } | 
| 46 |  | 
| 47 |     /// Return true if the section table is empty. | 
| 48 |     #[inline ] | 
| 49 |     pub fn is_empty(&self) -> bool { | 
| 50 |         self.sections.is_empty() | 
| 51 |     } | 
| 52 |  | 
| 53 |     /// The number of section headers. | 
| 54 |     #[inline ] | 
| 55 |     pub fn len(&self) -> usize { | 
| 56 |         self.sections.len() | 
| 57 |     } | 
| 58 |  | 
| 59 |     /// Return the section header at the given index. | 
| 60 |     /// | 
| 61 |     /// The index is 1-based. | 
| 62 |     pub fn section(&self, index: usize) -> read::Result<&'data pe::ImageSectionHeader> { | 
| 63 |         self.sections | 
| 64 |             .get(index.wrapping_sub(1)) | 
| 65 |             .read_error("Invalid COFF/PE section index" ) | 
| 66 |     } | 
| 67 |  | 
| 68 |     /// Return the section header with the given name. | 
| 69 |     /// | 
| 70 |     /// The returned index is 1-based. | 
| 71 |     /// | 
| 72 |     /// Ignores sections with invalid names. | 
| 73 |     pub fn section_by_name<R: ReadRef<'data>>( | 
| 74 |         &self, | 
| 75 |         strings: StringTable<'data, R>, | 
| 76 |         name: &[u8], | 
| 77 |     ) -> Option<(usize, &'data pe::ImageSectionHeader)> { | 
| 78 |         self.sections | 
| 79 |             .iter() | 
| 80 |             .enumerate() | 
| 81 |             .find(|(_, section)| section.name(strings) == Ok(name)) | 
| 82 |             .map(|(index, section)| (index + 1, section)) | 
| 83 |     } | 
| 84 |  | 
| 85 |     /// Compute the maximum file offset used by sections. | 
| 86 |     /// | 
| 87 |     /// This will usually match the end of file, unless the PE file has a | 
| 88 |     /// [data overlay](https://security.stackexchange.com/questions/77336/how-is-the-file-overlay-read-by-an-exe-virus) | 
| 89 |     pub fn max_section_file_offset(&self) -> u64 { | 
| 90 |         let mut max = 0; | 
| 91 |         for section in self.iter() { | 
| 92 |             match (section.pointer_to_raw_data.get(LE) as u64) | 
| 93 |                 .checked_add(section.size_of_raw_data.get(LE) as u64) | 
| 94 |             { | 
| 95 |                 None => { | 
| 96 |                     // This cannot happen, we're suming two u32 into a u64 | 
| 97 |                     continue; | 
| 98 |                 } | 
| 99 |                 Some(end_of_section) => { | 
| 100 |                     if end_of_section > max { | 
| 101 |                         max = end_of_section; | 
| 102 |                     } | 
| 103 |                 } | 
| 104 |             } | 
| 105 |         } | 
| 106 |         max | 
| 107 |     } | 
| 108 | } | 
| 109 |  | 
| 110 | /// An iterator for the loadable sections in a [`CoffBigFile`](super::CoffBigFile). | 
| 111 | pub type CoffBigSegmentIterator<'data, 'file, R = &'data [u8]> = | 
| 112 |     CoffSegmentIterator<'data, 'file, R, pe::AnonObjectHeaderBigobj>; | 
| 113 |  | 
| 114 | /// An iterator for the loadable sections in a [`CoffFile`]. | 
| 115 | #[derive (Debug)] | 
| 116 | pub struct CoffSegmentIterator< | 
| 117 |     'data, | 
| 118 |     'file, | 
| 119 |     R: ReadRef<'data> = &'data [u8], | 
| 120 |     Coff: CoffHeader = pe::ImageFileHeader, | 
| 121 | > { | 
| 122 |     pub(super) file: &'file CoffFile<'data, R, Coff>, | 
| 123 |     pub(super) iter: slice::Iter<'data, pe::ImageSectionHeader>, | 
| 124 | } | 
| 125 |  | 
| 126 | impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> Iterator | 
| 127 |     for CoffSegmentIterator<'data, 'file, R, Coff> | 
| 128 | { | 
| 129 |     type Item = CoffSegment<'data, 'file, R, Coff>; | 
| 130 |  | 
| 131 |     fn next(&mut self) -> Option<Self::Item> { | 
| 132 |         self.iter.next().map(|section: &'data ImageSectionHeader| CoffSegment { | 
| 133 |             file: self.file, | 
| 134 |             section, | 
| 135 |         }) | 
| 136 |     } | 
| 137 | } | 
| 138 |  | 
| 139 | /// A loadable section in a [`CoffBigFile`](super::CoffBigFile). | 
| 140 | /// | 
| 141 | /// Most functionality is provided by the [`ObjectSegment`] trait implementation. | 
| 142 | pub type CoffBigSegment<'data, 'file, R = &'data [u8]> = | 
| 143 |     CoffSegment<'data, 'file, R, pe::AnonObjectHeaderBigobj>; | 
| 144 |  | 
| 145 | /// A loadable section in a [`CoffFile`]. | 
| 146 | /// | 
| 147 | /// Most functionality is provided by the [`ObjectSegment`] trait implementation. | 
| 148 | #[derive (Debug)] | 
| 149 | pub struct CoffSegment< | 
| 150 |     'data, | 
| 151 |     'file, | 
| 152 |     R: ReadRef<'data> = &'data [u8], | 
| 153 |     Coff: CoffHeader = pe::ImageFileHeader, | 
| 154 | > { | 
| 155 |     pub(super) file: &'file CoffFile<'data, R, Coff>, | 
| 156 |     pub(super) section: &'data pe::ImageSectionHeader, | 
| 157 | } | 
| 158 |  | 
| 159 | impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> CoffSegment<'data, 'file, R, Coff> { | 
| 160 |     fn bytes(&self) -> Result<&'data [u8]> { | 
| 161 |         self.section | 
| 162 |             .coff_data(self.file.data) | 
| 163 |             .read_error("Invalid COFF section offset or size" ) | 
| 164 |     } | 
| 165 | } | 
| 166 |  | 
| 167 | impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> read::private::Sealed | 
| 168 |     for CoffSegment<'data, 'file, R, Coff> | 
| 169 | { | 
| 170 | } | 
| 171 |  | 
| 172 | impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> ObjectSegment<'data> | 
| 173 |     for CoffSegment<'data, 'file, R, Coff> | 
| 174 | { | 
| 175 |     #[inline ] | 
| 176 |     fn address(&self) -> u64 { | 
| 177 |         u64::from(self.section.virtual_address.get(LE)) | 
| 178 |     } | 
| 179 |  | 
| 180 |     #[inline ] | 
| 181 |     fn size(&self) -> u64 { | 
| 182 |         u64::from(self.section.virtual_size.get(LE)) | 
| 183 |     } | 
| 184 |  | 
| 185 |     #[inline ] | 
| 186 |     fn align(&self) -> u64 { | 
| 187 |         self.section.coff_alignment() | 
| 188 |     } | 
| 189 |  | 
| 190 |     #[inline ] | 
| 191 |     fn file_range(&self) -> (u64, u64) { | 
| 192 |         let (offset, size) = self.section.coff_file_range().unwrap_or((0, 0)); | 
| 193 |         (u64::from(offset), u64::from(size)) | 
| 194 |     } | 
| 195 |  | 
| 196 |     fn data(&self) -> Result<&'data [u8]> { | 
| 197 |         self.bytes() | 
| 198 |     } | 
| 199 |  | 
| 200 |     fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> { | 
| 201 |         Ok(read::util::data_range( | 
| 202 |             self.bytes()?, | 
| 203 |             self.address(), | 
| 204 |             address, | 
| 205 |             size, | 
| 206 |         )) | 
| 207 |     } | 
| 208 |  | 
| 209 |     #[inline ] | 
| 210 |     fn name_bytes(&self) -> Result<Option<&[u8]>> { | 
| 211 |         self.section | 
| 212 |             .name(self.file.common.symbols.strings()) | 
| 213 |             .map(Some) | 
| 214 |     } | 
| 215 |  | 
| 216 |     #[inline ] | 
| 217 |     fn name(&self) -> Result<Option<&str>> { | 
| 218 |         let name = self.section.name(self.file.common.symbols.strings())?; | 
| 219 |         str::from_utf8(name) | 
| 220 |             .ok() | 
| 221 |             .read_error("Non UTF-8 COFF section name" ) | 
| 222 |             .map(Some) | 
| 223 |     } | 
| 224 |  | 
| 225 |     #[inline ] | 
| 226 |     fn flags(&self) -> SegmentFlags { | 
| 227 |         let characteristics = self.section.characteristics.get(LE); | 
| 228 |         SegmentFlags::Coff { characteristics } | 
| 229 |     } | 
| 230 | } | 
| 231 |  | 
| 232 | /// An iterator for the sections in a [`CoffBigFile`](super::CoffBigFile). | 
| 233 | pub type CoffBigSectionIterator<'data, 'file, R = &'data [u8]> = | 
| 234 |     CoffSectionIterator<'data, 'file, R, pe::AnonObjectHeaderBigobj>; | 
| 235 |  | 
| 236 | /// An iterator for the sections in a [`CoffFile`]. | 
| 237 | #[derive (Debug)] | 
| 238 | pub struct CoffSectionIterator< | 
| 239 |     'data, | 
| 240 |     'file, | 
| 241 |     R: ReadRef<'data> = &'data [u8], | 
| 242 |     Coff: CoffHeader = pe::ImageFileHeader, | 
| 243 | > { | 
| 244 |     pub(super) file: &'file CoffFile<'data, R, Coff>, | 
| 245 |     pub(super) iter: iter::Enumerate<slice::Iter<'data, pe::ImageSectionHeader>>, | 
| 246 | } | 
| 247 |  | 
| 248 | impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> Iterator | 
| 249 |     for CoffSectionIterator<'data, 'file, R, Coff> | 
| 250 | { | 
| 251 |     type Item = CoffSection<'data, 'file, R, Coff>; | 
| 252 |  | 
| 253 |     fn next(&mut self) -> Option<Self::Item> { | 
| 254 |         self.iter.next().map(|(index: usize, section: &'data ImageSectionHeader)| CoffSection { | 
| 255 |             file: self.file, | 
| 256 |             index: SectionIndex(index + 1), | 
| 257 |             section, | 
| 258 |         }) | 
| 259 |     } | 
| 260 | } | 
| 261 |  | 
| 262 | /// A section in a [`CoffBigFile`](super::CoffBigFile). | 
| 263 | /// | 
| 264 | /// Most functionality is provided by the [`ObjectSection`] trait implementation. | 
| 265 | pub type CoffBigSection<'data, 'file, R = &'data [u8]> = | 
| 266 |     CoffSection<'data, 'file, R, pe::AnonObjectHeaderBigobj>; | 
| 267 |  | 
| 268 | /// A section in a [`CoffFile`]. | 
| 269 | /// | 
| 270 | /// Most functionality is provided by the [`ObjectSection`] trait implementation. | 
| 271 | #[derive (Debug)] | 
| 272 | pub struct CoffSection< | 
| 273 |     'data, | 
| 274 |     'file, | 
| 275 |     R: ReadRef<'data> = &'data [u8], | 
| 276 |     Coff: CoffHeader = pe::ImageFileHeader, | 
| 277 | > { | 
| 278 |     pub(super) file: &'file CoffFile<'data, R, Coff>, | 
| 279 |     pub(super) index: SectionIndex, | 
| 280 |     pub(super) section: &'data pe::ImageSectionHeader, | 
| 281 | } | 
| 282 |  | 
| 283 | impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> CoffSection<'data, 'file, R, Coff> { | 
| 284 |     fn bytes(&self) -> Result<&'data [u8]> { | 
| 285 |         self.section | 
| 286 |             .coff_data(self.file.data) | 
| 287 |             .read_error("Invalid COFF section offset or size" ) | 
| 288 |     } | 
| 289 | } | 
| 290 |  | 
| 291 | impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> read::private::Sealed | 
| 292 |     for CoffSection<'data, 'file, R, Coff> | 
| 293 | { | 
| 294 | } | 
| 295 |  | 
| 296 | impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> ObjectSection<'data> | 
| 297 |     for CoffSection<'data, 'file, R, Coff> | 
| 298 | { | 
| 299 |     type RelocationIterator = CoffRelocationIterator<'data, 'file, R, Coff>; | 
| 300 |  | 
| 301 |     #[inline ] | 
| 302 |     fn index(&self) -> SectionIndex { | 
| 303 |         self.index | 
| 304 |     } | 
| 305 |  | 
| 306 |     #[inline ] | 
| 307 |     fn address(&self) -> u64 { | 
| 308 |         u64::from(self.section.virtual_address.get(LE)) | 
| 309 |     } | 
| 310 |  | 
| 311 |     #[inline ] | 
| 312 |     fn size(&self) -> u64 { | 
| 313 |         // TODO: This may need to be the length from the auxiliary symbol for this section. | 
| 314 |         u64::from(self.section.size_of_raw_data.get(LE)) | 
| 315 |     } | 
| 316 |  | 
| 317 |     #[inline ] | 
| 318 |     fn align(&self) -> u64 { | 
| 319 |         self.section.coff_alignment() | 
| 320 |     } | 
| 321 |  | 
| 322 |     #[inline ] | 
| 323 |     fn file_range(&self) -> Option<(u64, u64)> { | 
| 324 |         let (offset, size) = self.section.coff_file_range()?; | 
| 325 |         Some((u64::from(offset), u64::from(size))) | 
| 326 |     } | 
| 327 |  | 
| 328 |     fn data(&self) -> Result<&'data [u8]> { | 
| 329 |         self.bytes() | 
| 330 |     } | 
| 331 |  | 
| 332 |     fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> { | 
| 333 |         Ok(read::util::data_range( | 
| 334 |             self.bytes()?, | 
| 335 |             self.address(), | 
| 336 |             address, | 
| 337 |             size, | 
| 338 |         )) | 
| 339 |     } | 
| 340 |  | 
| 341 |     #[inline ] | 
| 342 |     fn compressed_file_range(&self) -> Result<CompressedFileRange> { | 
| 343 |         Ok(CompressedFileRange::none(self.file_range())) | 
| 344 |     } | 
| 345 |  | 
| 346 |     #[inline ] | 
| 347 |     fn compressed_data(&self) -> Result<CompressedData<'data>> { | 
| 348 |         self.data().map(CompressedData::none) | 
| 349 |     } | 
| 350 |  | 
| 351 |     #[inline ] | 
| 352 |     fn name_bytes(&self) -> Result<&[u8]> { | 
| 353 |         self.section.name(self.file.common.symbols.strings()) | 
| 354 |     } | 
| 355 |  | 
| 356 |     #[inline ] | 
| 357 |     fn name(&self) -> Result<&str> { | 
| 358 |         let name = self.name_bytes()?; | 
| 359 |         str::from_utf8(name) | 
| 360 |             .ok() | 
| 361 |             .read_error("Non UTF-8 COFF section name" ) | 
| 362 |     } | 
| 363 |  | 
| 364 |     #[inline ] | 
| 365 |     fn segment_name_bytes(&self) -> Result<Option<&[u8]>> { | 
| 366 |         Ok(None) | 
| 367 |     } | 
| 368 |  | 
| 369 |     #[inline ] | 
| 370 |     fn segment_name(&self) -> Result<Option<&str>> { | 
| 371 |         Ok(None) | 
| 372 |     } | 
| 373 |  | 
| 374 |     #[inline ] | 
| 375 |     fn kind(&self) -> SectionKind { | 
| 376 |         self.section.kind() | 
| 377 |     } | 
| 378 |  | 
| 379 |     fn relocations(&self) -> CoffRelocationIterator<'data, 'file, R, Coff> { | 
| 380 |         let relocations = self.section.coff_relocations(self.file.data).unwrap_or(&[]); | 
| 381 |         CoffRelocationIterator { | 
| 382 |             file: self.file, | 
| 383 |             iter: relocations.iter(), | 
| 384 |         } | 
| 385 |     } | 
| 386 |  | 
| 387 |     fn flags(&self) -> SectionFlags { | 
| 388 |         SectionFlags::Coff { | 
| 389 |             characteristics: self.section.characteristics.get(LE), | 
| 390 |         } | 
| 391 |     } | 
| 392 | } | 
| 393 |  | 
| 394 | impl pe::ImageSectionHeader { | 
| 395 |     pub(crate) fn kind(&self) -> SectionKind { | 
| 396 |         let characteristics: u32 = self.characteristics.get(LE); | 
| 397 |         if characteristics & (pe::IMAGE_SCN_CNT_CODE | pe::IMAGE_SCN_MEM_EXECUTE) != 0 { | 
| 398 |             SectionKind::Text | 
| 399 |         } else if characteristics & pe::IMAGE_SCN_CNT_INITIALIZED_DATA != 0 { | 
| 400 |             if characteristics & pe::IMAGE_SCN_MEM_DISCARDABLE != 0 { | 
| 401 |                 SectionKind::Other | 
| 402 |             } else if characteristics & pe::IMAGE_SCN_MEM_WRITE != 0 { | 
| 403 |                 SectionKind::Data | 
| 404 |             } else { | 
| 405 |                 SectionKind::ReadOnlyData | 
| 406 |             } | 
| 407 |         } else if characteristics & pe::IMAGE_SCN_CNT_UNINITIALIZED_DATA != 0 { | 
| 408 |             SectionKind::UninitializedData | 
| 409 |         } else if characteristics & pe::IMAGE_SCN_LNK_INFO != 0 { | 
| 410 |             SectionKind::Linker | 
| 411 |         } else { | 
| 412 |             SectionKind::Unknown | 
| 413 |         } | 
| 414 |     } | 
| 415 | } | 
| 416 |  | 
| 417 | impl pe::ImageSectionHeader { | 
| 418 |     /// Return the string table offset of the section name. | 
| 419 |     /// | 
| 420 |     /// Returns `Ok(None)` if the name doesn't use the string table | 
| 421 |     /// and can be obtained with `raw_name` instead. | 
| 422 |     pub fn name_offset(&self) -> Result<Option<u32>> { | 
| 423 |         let bytes = &self.name; | 
| 424 |         if bytes[0] != b'/'  { | 
| 425 |             return Ok(None); | 
| 426 |         } | 
| 427 |  | 
| 428 |         if bytes[1] == b'/'  { | 
| 429 |             let mut offset = 0; | 
| 430 |             for byte in bytes[2..].iter() { | 
| 431 |                 let digit = match byte { | 
| 432 |                     b'A' ..=b'Z'  => byte - b'A' , | 
| 433 |                     b'a' ..=b'z'  => byte - b'a'  + 26, | 
| 434 |                     b'0' ..=b'9'  => byte - b'0'  + 52, | 
| 435 |                     b'+'  => 62, | 
| 436 |                     b'/'  => 63, | 
| 437 |                     _ => return Err(Error("Invalid COFF section name base-64 offset" )), | 
| 438 |                 }; | 
| 439 |                 offset = offset * 64 + digit as u64; | 
| 440 |             } | 
| 441 |             u32::try_from(offset) | 
| 442 |                 .ok() | 
| 443 |                 .read_error("Invalid COFF section name base-64 offset" ) | 
| 444 |                 .map(Some) | 
| 445 |         } else { | 
| 446 |             let mut offset = 0; | 
| 447 |             for byte in bytes[1..].iter() { | 
| 448 |                 let digit = match byte { | 
| 449 |                     b'0' ..=b'9'  => byte - b'0' , | 
| 450 |                     0 => break, | 
| 451 |                     _ => return Err(Error("Invalid COFF section name base-10 offset" )), | 
| 452 |                 }; | 
| 453 |                 offset = offset * 10 + digit as u32; | 
| 454 |             } | 
| 455 |             Ok(Some(offset)) | 
| 456 |         } | 
| 457 |     } | 
| 458 |  | 
| 459 |     /// Return the section name. | 
| 460 |     /// | 
| 461 |     /// This handles decoding names that are offsets into the symbol string table. | 
| 462 |     pub fn name<'data, R: ReadRef<'data>>( | 
| 463 |         &'data self, | 
| 464 |         strings: StringTable<'data, R>, | 
| 465 |     ) -> Result<&'data [u8]> { | 
| 466 |         if let Some(offset) = self.name_offset()? { | 
| 467 |             strings | 
| 468 |                 .get(offset) | 
| 469 |                 .read_error("Invalid COFF section name offset" ) | 
| 470 |         } else { | 
| 471 |             Ok(self.raw_name()) | 
| 472 |         } | 
| 473 |     } | 
| 474 |  | 
| 475 |     /// Return the raw section name. | 
| 476 |     pub fn raw_name(&self) -> &[u8] { | 
| 477 |         let bytes = &self.name; | 
| 478 |         match memchr::memchr(b' \0' , bytes) { | 
| 479 |             Some(end) => &bytes[..end], | 
| 480 |             None => &bytes[..], | 
| 481 |         } | 
| 482 |     } | 
| 483 |  | 
| 484 |     /// Return the offset and size of the section in a COFF file. | 
| 485 |     /// | 
| 486 |     /// Returns `None` for sections that have no data in the file. | 
| 487 |     pub fn coff_file_range(&self) -> Option<(u32, u32)> { | 
| 488 |         if self.characteristics.get(LE) & pe::IMAGE_SCN_CNT_UNINITIALIZED_DATA != 0 { | 
| 489 |             None | 
| 490 |         } else { | 
| 491 |             let offset = self.pointer_to_raw_data.get(LE); | 
| 492 |             // Note: virtual size is not used for COFF. | 
| 493 |             let size = self.size_of_raw_data.get(LE); | 
| 494 |             Some((offset, size)) | 
| 495 |         } | 
| 496 |     } | 
| 497 |  | 
| 498 |     /// Return the section data in a COFF file. | 
| 499 |     /// | 
| 500 |     /// Returns `Ok(&[])` if the section has no data. | 
| 501 |     /// Returns `Err` for invalid values. | 
| 502 |     pub fn coff_data<'data, R: ReadRef<'data>>(&self, data: R) -> result::Result<&'data [u8], ()> { | 
| 503 |         if let Some((offset, size)) = self.coff_file_range() { | 
| 504 |             data.read_bytes_at(offset.into(), size.into()) | 
| 505 |         } else { | 
| 506 |             Ok(&[]) | 
| 507 |         } | 
| 508 |     } | 
| 509 |  | 
| 510 |     /// Return the section alignment in bytes. | 
| 511 |     /// | 
| 512 |     /// This is only valid for sections in a COFF file. | 
| 513 |     pub fn coff_alignment(&self) -> u64 { | 
| 514 |         match self.characteristics.get(LE) & pe::IMAGE_SCN_ALIGN_MASK { | 
| 515 |             pe::IMAGE_SCN_ALIGN_1BYTES => 1, | 
| 516 |             pe::IMAGE_SCN_ALIGN_2BYTES => 2, | 
| 517 |             pe::IMAGE_SCN_ALIGN_4BYTES => 4, | 
| 518 |             pe::IMAGE_SCN_ALIGN_8BYTES => 8, | 
| 519 |             pe::IMAGE_SCN_ALIGN_16BYTES => 16, | 
| 520 |             pe::IMAGE_SCN_ALIGN_32BYTES => 32, | 
| 521 |             pe::IMAGE_SCN_ALIGN_64BYTES => 64, | 
| 522 |             pe::IMAGE_SCN_ALIGN_128BYTES => 128, | 
| 523 |             pe::IMAGE_SCN_ALIGN_256BYTES => 256, | 
| 524 |             pe::IMAGE_SCN_ALIGN_512BYTES => 512, | 
| 525 |             pe::IMAGE_SCN_ALIGN_1024BYTES => 1024, | 
| 526 |             pe::IMAGE_SCN_ALIGN_2048BYTES => 2048, | 
| 527 |             pe::IMAGE_SCN_ALIGN_4096BYTES => 4096, | 
| 528 |             pe::IMAGE_SCN_ALIGN_8192BYTES => 8192, | 
| 529 |             _ => 16, | 
| 530 |         } | 
| 531 |     } | 
| 532 |  | 
| 533 |     /// Read the relocations in a COFF file. | 
| 534 |     /// | 
| 535 |     /// `data` must be the entire file data. | 
| 536 |     pub fn coff_relocations<'data, R: ReadRef<'data>>( | 
| 537 |         &self, | 
| 538 |         data: R, | 
| 539 |     ) -> read::Result<&'data [pe::ImageRelocation]> { | 
| 540 |         let mut pointer = self.pointer_to_relocations.get(LE).into(); | 
| 541 |         let mut number: usize = self.number_of_relocations.get(LE).into(); | 
| 542 |         if number == core::u16::MAX.into() | 
| 543 |             && self.characteristics.get(LE) & pe::IMAGE_SCN_LNK_NRELOC_OVFL != 0 | 
| 544 |         { | 
| 545 |             // Extended relocations. Read first relocation (which contains extended count) & adjust | 
| 546 |             // relocations pointer. | 
| 547 |             let extended_relocation_info = data | 
| 548 |                 .read_at::<pe::ImageRelocation>(pointer) | 
| 549 |                 .read_error("Invalid COFF relocation offset or number" )?; | 
| 550 |             number = extended_relocation_info.virtual_address.get(LE) as usize; | 
| 551 |             if number == 0 { | 
| 552 |                 return Err(Error("Invalid COFF relocation number" )); | 
| 553 |             } | 
| 554 |             pointer += core::mem::size_of::<pe::ImageRelocation>() as u64; | 
| 555 |             // Extended relocation info does not contribute to the count of sections. | 
| 556 |             number -= 1; | 
| 557 |         } | 
| 558 |         data.read_slice_at(pointer, number) | 
| 559 |             .read_error("Invalid COFF relocation offset or number" ) | 
| 560 |     } | 
| 561 | } | 
| 562 |  | 
| 563 | #[cfg (test)] | 
| 564 | mod tests { | 
| 565 |     use super::*; | 
| 566 |  | 
| 567 |     #[test ] | 
| 568 |     fn name_offset() { | 
| 569 |         let mut section = pe::ImageSectionHeader::default(); | 
| 570 |         section.name = *b"xxxxxxxx" ; | 
| 571 |         assert_eq!(section.name_offset(), Ok(None)); | 
| 572 |         section.name = *b"/0 \0\0\0\0\0\0" ; | 
| 573 |         assert_eq!(section.name_offset(), Ok(Some(0))); | 
| 574 |         section.name = *b"/9999999" ; | 
| 575 |         assert_eq!(section.name_offset(), Ok(Some(999_9999))); | 
| 576 |         section.name = *b"//AAAAAA" ; | 
| 577 |         assert_eq!(section.name_offset(), Ok(Some(0))); | 
| 578 |         section.name = *b"//D/////" ; | 
| 579 |         assert_eq!(section.name_offset(), Ok(Some(0xffff_ffff))); | 
| 580 |         section.name = *b"//EAAAAA" ; | 
| 581 |         assert!(section.name_offset().is_err()); | 
| 582 |         section.name = *b"////////" ; | 
| 583 |         assert!(section.name_offset().is_err()); | 
| 584 |     } | 
| 585 | } | 
| 586 |  |