| 1 | use core::fmt::Debug; | 
| 2 | use core::{iter, result, slice, str}; | 
| 3 |  | 
| 4 | use crate::{ | 
| 5 |     xcoff, BigEndian as BE, CompressedData, CompressedFileRange, Pod, SectionFlags, SectionKind, | 
| 6 | }; | 
| 7 |  | 
| 8 | use crate::read::{self, Error, ObjectSection, ReadError, ReadRef, Result, SectionIndex}; | 
| 9 |  | 
| 10 | use super::{AuxHeader, FileHeader, Rel, XcoffFile, XcoffRelocationIterator}; | 
| 11 |  | 
| 12 | /// An iterator for the sections in an [`XcoffFile32`](super::XcoffFile32). | 
| 13 | pub type XcoffSectionIterator32<'data, 'file, R = &'data [u8]> = | 
| 14 |     XcoffSectionIterator<'data, 'file, xcoff::FileHeader32, R>; | 
| 15 | /// An iterator for the sections in an [`XcoffFile64`](super::XcoffFile64). | 
| 16 | pub type XcoffSectionIterator64<'data, 'file, R = &'data [u8]> = | 
| 17 |     XcoffSectionIterator<'data, 'file, xcoff::FileHeader64, R>; | 
| 18 |  | 
| 19 | /// An iterator for the sections in an [`XcoffFile`]. | 
| 20 | #[derive (Debug)] | 
| 21 | pub struct XcoffSectionIterator<'data, 'file, Xcoff, R = &'data [u8]> | 
| 22 | where | 
| 23 |     Xcoff: FileHeader, | 
| 24 |     R: ReadRef<'data>, | 
| 25 | { | 
| 26 |     pub(super) file: &'file XcoffFile<'data, Xcoff, R>, | 
| 27 |     pub(super) iter: iter::Enumerate<slice::Iter<'data, Xcoff::SectionHeader>>, | 
| 28 | } | 
| 29 |  | 
| 30 | impl<'data, 'file, Xcoff, R> Iterator for XcoffSectionIterator<'data, 'file, Xcoff, R> | 
| 31 | where | 
| 32 |     Xcoff: FileHeader, | 
| 33 |     R: ReadRef<'data>, | 
| 34 | { | 
| 35 |     type Item = XcoffSection<'data, 'file, Xcoff, R>; | 
| 36 |  | 
| 37 |     fn next(&mut self) -> Option<Self::Item> { | 
| 38 |         self.iter.next().map(|(index: usize, section: &'data {unknown})| XcoffSection { | 
| 39 |             index: SectionIndex(index + 1), | 
| 40 |             file: self.file, | 
| 41 |             section, | 
| 42 |         }) | 
| 43 |     } | 
| 44 | } | 
| 45 |  | 
| 46 | /// A section in an [`XcoffFile32`](super::XcoffFile32). | 
| 47 | pub type XcoffSection32<'data, 'file, R = &'data [u8]> = | 
| 48 |     XcoffSection<'data, 'file, xcoff::FileHeader32, R>; | 
| 49 | /// A section in an [`XcoffFile64`](super::XcoffFile64). | 
| 50 | pub type XcoffSection64<'data, 'file, R = &'data [u8]> = | 
| 51 |     XcoffSection<'data, 'file, xcoff::FileHeader64, R>; | 
| 52 |  | 
| 53 | /// A section in an [`XcoffFile`]. | 
| 54 | /// | 
| 55 | /// Most functionality is provided by the [`ObjectSection`] trait implementation. | 
| 56 | #[derive (Debug)] | 
| 57 | pub struct XcoffSection<'data, 'file, Xcoff, R = &'data [u8]> | 
| 58 | where | 
| 59 |     Xcoff: FileHeader, | 
| 60 |     R: ReadRef<'data>, | 
| 61 | { | 
| 62 |     pub(super) file: &'file XcoffFile<'data, Xcoff, R>, | 
| 63 |     pub(super) section: &'data Xcoff::SectionHeader, | 
| 64 |     pub(super) index: SectionIndex, | 
| 65 | } | 
| 66 |  | 
| 67 | impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> XcoffSection<'data, 'file, Xcoff, R> { | 
| 68 |     fn bytes(&self) -> Result<&'data [u8]> { | 
| 69 |         self.section | 
| 70 |             .data(self.file.data) | 
| 71 |             .read_error("Invalid XCOFF section offset or size" ) | 
| 72 |     } | 
| 73 | } | 
| 74 |  | 
| 75 | impl<'data, 'file, Xcoff, R> read::private::Sealed for XcoffSection<'data, 'file, Xcoff, R> | 
| 76 | where | 
| 77 |     Xcoff: FileHeader, | 
| 78 |     R: ReadRef<'data>, | 
| 79 | { | 
| 80 | } | 
| 81 |  | 
| 82 | impl<'data, 'file, Xcoff, R> ObjectSection<'data> for XcoffSection<'data, 'file, Xcoff, R> | 
| 83 | where | 
| 84 |     Xcoff: FileHeader, | 
| 85 |     R: ReadRef<'data>, | 
| 86 | { | 
| 87 |     type RelocationIterator = XcoffRelocationIterator<'data, 'file, Xcoff, R>; | 
| 88 |  | 
| 89 |     fn index(&self) -> SectionIndex { | 
| 90 |         self.index | 
| 91 |     } | 
| 92 |  | 
| 93 |     fn address(&self) -> u64 { | 
| 94 |         self.section.s_paddr().into() | 
| 95 |     } | 
| 96 |  | 
| 97 |     fn size(&self) -> u64 { | 
| 98 |         self.section.s_size().into() | 
| 99 |     } | 
| 100 |  | 
| 101 |     fn align(&self) -> u64 { | 
| 102 |         // The default section alignment is 4. | 
| 103 |         if let Some(aux_header) = self.file.aux_header { | 
| 104 |             match self.kind() { | 
| 105 |                 SectionKind::Text => aux_header.o_algntext().into(), | 
| 106 |                 SectionKind::Data => aux_header.o_algndata().into(), | 
| 107 |                 _ => 4, | 
| 108 |             } | 
| 109 |         } else { | 
| 110 |             4 | 
| 111 |         } | 
| 112 |     } | 
| 113 |  | 
| 114 |     fn file_range(&self) -> Option<(u64, u64)> { | 
| 115 |         self.section.file_range() | 
| 116 |     } | 
| 117 |  | 
| 118 |     fn data(&self) -> Result<&'data [u8]> { | 
| 119 |         self.bytes() | 
| 120 |     } | 
| 121 |  | 
| 122 |     fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>> { | 
| 123 |         Ok(read::util::data_range( | 
| 124 |             self.bytes()?, | 
| 125 |             self.address(), | 
| 126 |             address, | 
| 127 |             size, | 
| 128 |         )) | 
| 129 |     } | 
| 130 |  | 
| 131 |     fn compressed_file_range(&self) -> Result<CompressedFileRange> { | 
| 132 |         Ok(CompressedFileRange::none(self.file_range())) | 
| 133 |     } | 
| 134 |  | 
| 135 |     fn compressed_data(&self) -> Result<CompressedData<'data>> { | 
| 136 |         self.data().map(CompressedData::none) | 
| 137 |     } | 
| 138 |  | 
| 139 |     fn name_bytes(&self) -> read::Result<&[u8]> { | 
| 140 |         Ok(self.section.name()) | 
| 141 |     } | 
| 142 |  | 
| 143 |     fn name(&self) -> read::Result<&str> { | 
| 144 |         let name = self.name_bytes()?; | 
| 145 |         str::from_utf8(name) | 
| 146 |             .ok() | 
| 147 |             .read_error("Non UTF-8 XCOFF section name" ) | 
| 148 |     } | 
| 149 |  | 
| 150 |     fn segment_name_bytes(&self) -> Result<Option<&[u8]>> { | 
| 151 |         Ok(None) | 
| 152 |     } | 
| 153 |  | 
| 154 |     fn segment_name(&self) -> Result<Option<&str>> { | 
| 155 |         Ok(None) | 
| 156 |     } | 
| 157 |  | 
| 158 |     fn kind(&self) -> SectionKind { | 
| 159 |         let section_type = self.section.s_flags() as u16; | 
| 160 |         if section_type & xcoff::STYP_TEXT != 0 { | 
| 161 |             SectionKind::Text | 
| 162 |         } else if section_type & xcoff::STYP_DATA != 0 { | 
| 163 |             SectionKind::Data | 
| 164 |         } else if section_type & xcoff::STYP_TDATA != 0 { | 
| 165 |             SectionKind::Tls | 
| 166 |         } else if section_type & xcoff::STYP_BSS != 0 { | 
| 167 |             SectionKind::UninitializedData | 
| 168 |         } else if section_type & xcoff::STYP_TBSS != 0 { | 
| 169 |             SectionKind::UninitializedTls | 
| 170 |         } else if section_type & (xcoff::STYP_DEBUG | xcoff::STYP_DWARF) != 0 { | 
| 171 |             SectionKind::Debug | 
| 172 |         } else if section_type & (xcoff::STYP_LOADER | xcoff::STYP_OVRFLO) != 0 { | 
| 173 |             SectionKind::Metadata | 
| 174 |         } else if section_type | 
| 175 |             & (xcoff::STYP_INFO | xcoff::STYP_EXCEPT | xcoff::STYP_PAD | xcoff::STYP_TYPCHK) | 
| 176 |             != 0 | 
| 177 |         { | 
| 178 |             SectionKind::Other | 
| 179 |         } else { | 
| 180 |             SectionKind::Unknown | 
| 181 |         } | 
| 182 |     } | 
| 183 |  | 
| 184 |     fn relocations(&self) -> Self::RelocationIterator { | 
| 185 |         let rel = self.section.relocations(self.file.data).unwrap_or(&[]); | 
| 186 |         XcoffRelocationIterator { | 
| 187 |             file: self.file, | 
| 188 |             relocations: rel.iter(), | 
| 189 |         } | 
| 190 |     } | 
| 191 |  | 
| 192 |     fn flags(&self) -> SectionFlags { | 
| 193 |         SectionFlags::Xcoff { | 
| 194 |             s_flags: self.section.s_flags(), | 
| 195 |         } | 
| 196 |     } | 
| 197 |  | 
| 198 |     fn uncompressed_data(&self) -> Result<alloc::borrow::Cow<'data, [u8]>> { | 
| 199 |         self.compressed_data()?.decompress() | 
| 200 |     } | 
| 201 | } | 
| 202 |  | 
| 203 | /// The table of section headers in an XCOFF file. | 
| 204 | /// | 
| 205 | /// Returned by [`FileHeader::sections`]. | 
| 206 | #[derive (Debug, Clone, Copy)] | 
| 207 | pub struct SectionTable<'data, Xcoff: FileHeader> { | 
| 208 |     sections: &'data [Xcoff::SectionHeader], | 
| 209 | } | 
| 210 |  | 
| 211 | impl<'data, Xcoff> Default for SectionTable<'data, Xcoff> | 
| 212 | where | 
| 213 |     Xcoff: FileHeader, | 
| 214 | { | 
| 215 |     fn default() -> Self { | 
| 216 |         Self { sections: &[] } | 
| 217 |     } | 
| 218 | } | 
| 219 |  | 
| 220 | impl<'data, Xcoff> SectionTable<'data, Xcoff> | 
| 221 | where | 
| 222 |     Xcoff: FileHeader, | 
| 223 | { | 
| 224 |     /// Parse the section table. | 
| 225 |     /// | 
| 226 |     /// `data` must be the entire file data. | 
| 227 |     /// `offset` must be after the optional file header. | 
| 228 |     pub fn parse<R: ReadRef<'data>>(header: &Xcoff, data: R, offset: &mut u64) -> Result<Self> { | 
| 229 |         let section_num = header.f_nscns(); | 
| 230 |         if section_num == 0 { | 
| 231 |             return Ok(SectionTable::default()); | 
| 232 |         } | 
| 233 |         let sections = data | 
| 234 |             .read_slice(offset, section_num as usize) | 
| 235 |             .read_error("Invalid XCOFF section headers" )?; | 
| 236 |         Ok(SectionTable { sections }) | 
| 237 |     } | 
| 238 |  | 
| 239 |     /// Iterate over the section headers. | 
| 240 |     #[inline ] | 
| 241 |     pub fn iter(&self) -> slice::Iter<'data, Xcoff::SectionHeader> { | 
| 242 |         self.sections.iter() | 
| 243 |     } | 
| 244 |  | 
| 245 |     /// Return true if the section table is empty. | 
| 246 |     #[inline ] | 
| 247 |     pub fn is_empty(&self) -> bool { | 
| 248 |         self.sections.is_empty() | 
| 249 |     } | 
| 250 |  | 
| 251 |     /// The number of section headers. | 
| 252 |     #[inline ] | 
| 253 |     pub fn len(&self) -> usize { | 
| 254 |         self.sections.len() | 
| 255 |     } | 
| 256 |  | 
| 257 |     /// Return the section header at the given index. | 
| 258 |     /// | 
| 259 |     /// The index is 1-based. | 
| 260 |     pub fn section(&self, index: SectionIndex) -> read::Result<&'data Xcoff::SectionHeader> { | 
| 261 |         self.sections | 
| 262 |             .get(index.0.wrapping_sub(1)) | 
| 263 |             .read_error("Invalid XCOFF section index" ) | 
| 264 |     } | 
| 265 | } | 
| 266 |  | 
| 267 | /// A trait for generic access to [`xcoff::SectionHeader32`] and [`xcoff::SectionHeader64`]. | 
| 268 | #[allow (missing_docs)] | 
| 269 | pub trait SectionHeader: Debug + Pod { | 
| 270 |     type Word: Into<u64>; | 
| 271 |     type HalfWord: Into<u32>; | 
| 272 |     type Xcoff: FileHeader<SectionHeader = Self, Word = Self::Word>; | 
| 273 |     type Rel: Rel<Word = Self::Word>; | 
| 274 |  | 
| 275 |     fn s_name(&self) -> &[u8; 8]; | 
| 276 |     fn s_paddr(&self) -> Self::Word; | 
| 277 |     fn s_vaddr(&self) -> Self::Word; | 
| 278 |     fn s_size(&self) -> Self::Word; | 
| 279 |     fn s_scnptr(&self) -> Self::Word; | 
| 280 |     fn s_relptr(&self) -> Self::Word; | 
| 281 |     fn s_lnnoptr(&self) -> Self::Word; | 
| 282 |     fn s_nreloc(&self) -> Self::HalfWord; | 
| 283 |     fn s_nlnno(&self) -> Self::HalfWord; | 
| 284 |     fn s_flags(&self) -> u32; | 
| 285 |  | 
| 286 |     /// Return the section name. | 
| 287 |     fn name(&self) -> &[u8] { | 
| 288 |         let sectname = &self.s_name()[..]; | 
| 289 |         match memchr::memchr(b' \0' , sectname) { | 
| 290 |             Some(end) => §name[..end], | 
| 291 |             None => sectname, | 
| 292 |         } | 
| 293 |     } | 
| 294 |  | 
| 295 |     /// Return the offset and size of the section in the file. | 
| 296 |     fn file_range(&self) -> Option<(u64, u64)> { | 
| 297 |         Some((self.s_scnptr().into(), self.s_size().into())) | 
| 298 |     } | 
| 299 |  | 
| 300 |     /// Return the section data. | 
| 301 |     /// | 
| 302 |     /// Returns `Ok(&[])` if the section has no data. | 
| 303 |     /// Returns `Err` for invalid values. | 
| 304 |     fn data<'data, R: ReadRef<'data>>(&self, data: R) -> result::Result<&'data [u8], ()> { | 
| 305 |         if let Some((offset, size)) = self.file_range() { | 
| 306 |             data.read_bytes_at(offset, size) | 
| 307 |         } else { | 
| 308 |             Ok(&[]) | 
| 309 |         } | 
| 310 |     } | 
| 311 |  | 
| 312 |     /// Read the relocations. | 
| 313 |     fn relocations<'data, R: ReadRef<'data>>(&self, data: R) -> read::Result<&'data [Self::Rel]>; | 
| 314 | } | 
| 315 |  | 
| 316 | impl SectionHeader for xcoff::SectionHeader32 { | 
| 317 |     type Word = u32; | 
| 318 |     type HalfWord = u16; | 
| 319 |     type Xcoff = xcoff::FileHeader32; | 
| 320 |     type Rel = xcoff::Rel32; | 
| 321 |  | 
| 322 |     fn s_name(&self) -> &[u8; 8] { | 
| 323 |         &self.s_name | 
| 324 |     } | 
| 325 |  | 
| 326 |     fn s_paddr(&self) -> Self::Word { | 
| 327 |         self.s_paddr.get(BE) | 
| 328 |     } | 
| 329 |  | 
| 330 |     fn s_vaddr(&self) -> Self::Word { | 
| 331 |         self.s_vaddr.get(BE) | 
| 332 |     } | 
| 333 |  | 
| 334 |     fn s_size(&self) -> Self::Word { | 
| 335 |         self.s_size.get(BE) | 
| 336 |     } | 
| 337 |  | 
| 338 |     fn s_scnptr(&self) -> Self::Word { | 
| 339 |         self.s_scnptr.get(BE) | 
| 340 |     } | 
| 341 |  | 
| 342 |     fn s_relptr(&self) -> Self::Word { | 
| 343 |         self.s_relptr.get(BE) | 
| 344 |     } | 
| 345 |  | 
| 346 |     fn s_lnnoptr(&self) -> Self::Word { | 
| 347 |         self.s_lnnoptr.get(BE) | 
| 348 |     } | 
| 349 |  | 
| 350 |     fn s_nreloc(&self) -> Self::HalfWord { | 
| 351 |         self.s_nreloc.get(BE) | 
| 352 |     } | 
| 353 |  | 
| 354 |     fn s_nlnno(&self) -> Self::HalfWord { | 
| 355 |         self.s_nlnno.get(BE) | 
| 356 |     } | 
| 357 |  | 
| 358 |     fn s_flags(&self) -> u32 { | 
| 359 |         self.s_flags.get(BE) | 
| 360 |     } | 
| 361 |  | 
| 362 |     /// Read the relocations in a XCOFF32 file. | 
| 363 |     /// | 
| 364 |     /// `data` must be the entire file data. | 
| 365 |     fn relocations<'data, R: ReadRef<'data>>(&self, data: R) -> read::Result<&'data [Self::Rel]> { | 
| 366 |         let reloc_num = self.s_nreloc() as usize; | 
| 367 |         // TODO: If more than 65,534 relocation entries are required, the field value will be 65535, | 
| 368 |         // and an STYP_OVRFLO section header will contain the actual count of relocation entries in | 
| 369 |         // the s_paddr field. | 
| 370 |         if reloc_num == 65535 { | 
| 371 |             return Err(Error("Overflow section is not supported yet." )); | 
| 372 |         } | 
| 373 |         data.read_slice_at(self.s_relptr().into(), reloc_num) | 
| 374 |             .read_error("Invalid XCOFF relocation offset or number" ) | 
| 375 |     } | 
| 376 | } | 
| 377 |  | 
| 378 | impl SectionHeader for xcoff::SectionHeader64 { | 
| 379 |     type Word = u64; | 
| 380 |     type HalfWord = u32; | 
| 381 |     type Xcoff = xcoff::FileHeader64; | 
| 382 |     type Rel = xcoff::Rel64; | 
| 383 |  | 
| 384 |     fn s_name(&self) -> &[u8; 8] { | 
| 385 |         &self.s_name | 
| 386 |     } | 
| 387 |  | 
| 388 |     fn s_paddr(&self) -> Self::Word { | 
| 389 |         self.s_paddr.get(BE) | 
| 390 |     } | 
| 391 |  | 
| 392 |     fn s_vaddr(&self) -> Self::Word { | 
| 393 |         self.s_vaddr.get(BE) | 
| 394 |     } | 
| 395 |  | 
| 396 |     fn s_size(&self) -> Self::Word { | 
| 397 |         self.s_size.get(BE) | 
| 398 |     } | 
| 399 |  | 
| 400 |     fn s_scnptr(&self) -> Self::Word { | 
| 401 |         self.s_scnptr.get(BE) | 
| 402 |     } | 
| 403 |  | 
| 404 |     fn s_relptr(&self) -> Self::Word { | 
| 405 |         self.s_relptr.get(BE) | 
| 406 |     } | 
| 407 |  | 
| 408 |     fn s_lnnoptr(&self) -> Self::Word { | 
| 409 |         self.s_lnnoptr.get(BE) | 
| 410 |     } | 
| 411 |  | 
| 412 |     fn s_nreloc(&self) -> Self::HalfWord { | 
| 413 |         self.s_nreloc.get(BE) | 
| 414 |     } | 
| 415 |  | 
| 416 |     fn s_nlnno(&self) -> Self::HalfWord { | 
| 417 |         self.s_nlnno.get(BE) | 
| 418 |     } | 
| 419 |  | 
| 420 |     fn s_flags(&self) -> u32 { | 
| 421 |         self.s_flags.get(BE) | 
| 422 |     } | 
| 423 |  | 
| 424 |     /// Read the relocations in a XCOFF64 file. | 
| 425 |     /// | 
| 426 |     /// `data` must be the entire file data. | 
| 427 |     fn relocations<'data, R: ReadRef<'data>>(&self, data: R) -> read::Result<&'data [Self::Rel]> { | 
| 428 |         data.read_slice_at(self.s_relptr(), self.s_nreloc() as usize) | 
| 429 |             .read_error("Invalid XCOFF relocation offset or number" ) | 
| 430 |     } | 
| 431 | } | 
| 432 |  |