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