]>
Commit | Line | Data |
---|---|---|
49aad941 FG |
1 | use alloc::fmt; |
2 | use core::convert::TryInto; | |
3 | use core::fmt::Debug; | |
4 | use core::marker::PhantomData; | |
5 | use core::str; | |
6 | ||
7 | use crate::endian::{BigEndian as BE, U32Bytes}; | |
fe692bf9 | 8 | use crate::pod::{bytes_of, Pod}; |
49aad941 | 9 | use crate::read::util::StringTable; |
fe692bf9 | 10 | use crate::xcoff; |
49aad941 FG |
11 | |
12 | use crate::read::{ | |
13 | self, Bytes, Error, ObjectSymbol, ObjectSymbolTable, ReadError, ReadRef, Result, SectionIndex, | |
14 | SymbolFlags, SymbolIndex, SymbolKind, SymbolScope, SymbolSection, | |
15 | }; | |
16 | ||
17 | use super::{FileHeader, XcoffFile}; | |
18 | ||
19 | /// A table of symbol entries in an XCOFF file. | |
20 | /// | |
21 | /// Also includes the string table used for the symbol names. | |
22 | #[derive(Debug)] | |
23 | pub struct SymbolTable<'data, Xcoff, R = &'data [u8]> | |
24 | where | |
25 | Xcoff: FileHeader, | |
26 | R: ReadRef<'data>, | |
27 | { | |
28 | symbols: &'data [xcoff::SymbolBytes], | |
29 | strings: StringTable<'data, R>, | |
30 | header: PhantomData<Xcoff>, | |
31 | } | |
32 | ||
33 | impl<'data, Xcoff, R> Default for SymbolTable<'data, Xcoff, R> | |
34 | where | |
35 | Xcoff: FileHeader, | |
36 | R: ReadRef<'data>, | |
37 | { | |
38 | fn default() -> Self { | |
39 | Self { | |
40 | symbols: &[], | |
41 | strings: StringTable::default(), | |
42 | header: PhantomData, | |
43 | } | |
44 | } | |
45 | } | |
46 | ||
47 | impl<'data, Xcoff, R> SymbolTable<'data, Xcoff, R> | |
48 | where | |
49 | Xcoff: FileHeader, | |
50 | R: ReadRef<'data>, | |
51 | { | |
52 | /// Parse the symbol table. | |
53 | pub fn parse(header: Xcoff, data: R) -> Result<Self> { | |
54 | let mut offset = header.f_symptr().into(); | |
55 | let (symbols, strings) = if offset != 0 { | |
56 | let symbols = data | |
57 | .read_slice(&mut offset, header.f_nsyms() as usize) | |
58 | .read_error("Invalid XCOFF symbol table offset or size")?; | |
59 | ||
60 | // Parse the string table. | |
61 | // Note: don't update data when reading length; the length includes itself. | |
62 | let length = data | |
63 | .read_at::<U32Bytes<_>>(offset) | |
64 | .read_error("Missing XCOFF string table")? | |
65 | .get(BE); | |
66 | let str_end = offset | |
67 | .checked_add(length as u64) | |
68 | .read_error("Invalid XCOFF string table length")?; | |
69 | let strings = StringTable::new(data, offset, str_end); | |
70 | ||
71 | (symbols, strings) | |
72 | } else { | |
73 | (&[][..], StringTable::default()) | |
74 | }; | |
75 | ||
76 | Ok(SymbolTable { | |
77 | symbols, | |
78 | strings, | |
79 | header: PhantomData, | |
80 | }) | |
81 | } | |
82 | ||
83 | /// Return the symbol entry at the given index and offset. | |
84 | pub fn get<T: Pod>(&self, index: usize, offset: usize) -> Result<&'data T> { | |
85 | let entry = index | |
86 | .checked_add(offset) | |
87 | .and_then(|x| self.symbols.get(x)) | |
88 | .read_error("Invalid XCOFF symbol index")?; | |
89 | let bytes = bytes_of(entry); | |
90 | Bytes(bytes).read().read_error("Invalid XCOFF symbol data") | |
91 | } | |
92 | ||
93 | /// Return the symbol at the given index. | |
94 | pub fn symbol(&self, index: usize) -> Result<&'data Xcoff::Symbol> { | |
95 | self.get::<Xcoff::Symbol>(index, 0) | |
96 | } | |
97 | ||
fe692bf9 FG |
98 | /// Return a file auxiliary symbol. |
99 | pub fn aux_file(&self, index: usize, offset: usize) -> Result<&'data Xcoff::FileAux> { | |
49aad941 | 100 | debug_assert!(self.symbol(index)?.has_aux_file()); |
fe692bf9 | 101 | let aux_file = self.get::<Xcoff::FileAux>(index, offset)?; |
49aad941 FG |
102 | if let Some(aux_type) = aux_file.x_auxtype() { |
103 | if aux_type != xcoff::AUX_FILE { | |
104 | return Err(Error("Invalid index for file auxiliary symbol.")); | |
105 | } | |
106 | } | |
107 | Ok(aux_file) | |
108 | } | |
109 | ||
110 | /// Return the csect auxiliary symbol. | |
111 | pub fn aux_csect(&self, index: usize, offset: usize) -> Result<&'data Xcoff::CsectAux> { | |
112 | debug_assert!(self.symbol(index)?.has_aux_csect()); | |
113 | let aux_csect = self.get::<Xcoff::CsectAux>(index, offset)?; | |
114 | if let Some(aux_type) = aux_csect.x_auxtype() { | |
115 | if aux_type != xcoff::AUX_CSECT { | |
116 | return Err(Error("Invalid index/offset for csect auxiliary symbol.")); | |
117 | } | |
118 | } | |
119 | Ok(aux_csect) | |
120 | } | |
121 | ||
122 | /// Return true if the symbol table is empty. | |
123 | #[inline] | |
124 | pub fn is_empty(&self) -> bool { | |
125 | self.symbols.is_empty() | |
126 | } | |
127 | ||
128 | /// The number of symbol table entries. | |
129 | /// | |
130 | /// This includes auxiliary symbol table entries. | |
131 | #[inline] | |
132 | pub fn len(&self) -> usize { | |
133 | self.symbols.len() | |
134 | } | |
135 | } | |
136 | ||
137 | /// A symbol table of an `XcoffFile32`. | |
138 | pub type XcoffSymbolTable32<'data, 'file, R = &'data [u8]> = | |
139 | XcoffSymbolTable<'data, 'file, xcoff::FileHeader32, R>; | |
140 | /// A symbol table of an `XcoffFile64`. | |
141 | pub type XcoffSymbolTable64<'data, 'file, R = &'data [u8]> = | |
142 | XcoffSymbolTable<'data, 'file, xcoff::FileHeader64, R>; | |
143 | ||
144 | /// A symbol table of an `XcoffFile`. | |
145 | #[derive(Debug, Clone, Copy)] | |
146 | pub struct XcoffSymbolTable<'data, 'file, Xcoff, R = &'data [u8]> | |
147 | where | |
49aad941 FG |
148 | Xcoff: FileHeader, |
149 | R: ReadRef<'data>, | |
150 | { | |
151 | pub(crate) file: &'file XcoffFile<'data, Xcoff, R>, | |
152 | pub(super) symbols: &'file SymbolTable<'data, Xcoff, R>, | |
153 | } | |
154 | ||
155 | impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> read::private::Sealed | |
156 | for XcoffSymbolTable<'data, 'file, Xcoff, R> | |
157 | { | |
158 | } | |
159 | ||
160 | impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> ObjectSymbolTable<'data> | |
161 | for XcoffSymbolTable<'data, 'file, Xcoff, R> | |
162 | { | |
163 | type Symbol = XcoffSymbol<'data, 'file, Xcoff, R>; | |
164 | type SymbolIterator = XcoffSymbolIterator<'data, 'file, Xcoff, R>; | |
165 | ||
166 | fn symbols(&self) -> Self::SymbolIterator { | |
167 | XcoffSymbolIterator { | |
168 | file: self.file, | |
169 | symbols: self.symbols, | |
170 | index: 0, | |
171 | } | |
172 | } | |
173 | ||
174 | fn symbol_by_index(&self, index: SymbolIndex) -> read::Result<Self::Symbol> { | |
175 | let symbol = self.symbols.symbol(index.0)?; | |
176 | Ok(XcoffSymbol { | |
177 | file: self.file, | |
178 | symbols: self.symbols, | |
179 | index, | |
180 | symbol, | |
181 | }) | |
182 | } | |
183 | } | |
184 | ||
185 | /// An iterator over the symbols of an `XcoffFile32`. | |
186 | pub type XcoffSymbolIterator32<'data, 'file, R = &'data [u8]> = | |
187 | XcoffSymbolIterator<'data, 'file, xcoff::FileHeader32, R>; | |
188 | /// An iterator over the symbols of an `XcoffFile64`. | |
189 | pub type XcoffSymbolIterator64<'data, 'file, R = &'data [u8]> = | |
190 | XcoffSymbolIterator<'data, 'file, xcoff::FileHeader64, R>; | |
191 | ||
192 | /// An iterator over the symbols of an `XcoffFile`. | |
193 | pub struct XcoffSymbolIterator<'data, 'file, Xcoff, R = &'data [u8]> | |
194 | where | |
49aad941 FG |
195 | Xcoff: FileHeader, |
196 | R: ReadRef<'data>, | |
197 | { | |
198 | pub(crate) file: &'file XcoffFile<'data, Xcoff, R>, | |
199 | pub(super) symbols: &'file SymbolTable<'data, Xcoff, R>, | |
200 | pub(super) index: usize, | |
201 | } | |
202 | ||
203 | impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> fmt::Debug | |
204 | for XcoffSymbolIterator<'data, 'file, Xcoff, R> | |
205 | { | |
206 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
207 | f.debug_struct("XcoffSymbolIterator").finish() | |
208 | } | |
209 | } | |
210 | ||
211 | impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> Iterator | |
212 | for XcoffSymbolIterator<'data, 'file, Xcoff, R> | |
213 | { | |
214 | type Item = XcoffSymbol<'data, 'file, Xcoff, R>; | |
215 | ||
216 | fn next(&mut self) -> Option<Self::Item> { | |
217 | let index = self.index; | |
218 | let symbol = self.symbols.symbol(index).ok()?; | |
219 | // TODO: skip over the auxiliary symbols for now. | |
220 | self.index += 1 + symbol.n_numaux() as usize; | |
221 | Some(XcoffSymbol { | |
222 | file: self.file, | |
223 | symbols: self.symbols, | |
224 | index: SymbolIndex(index), | |
225 | symbol, | |
226 | }) | |
227 | } | |
228 | } | |
229 | ||
230 | /// A symbol of an `XcoffFile32`. | |
231 | pub type XcoffSymbol32<'data, 'file, R = &'data [u8]> = | |
232 | XcoffSymbol<'data, 'file, xcoff::FileHeader32, R>; | |
233 | /// A symbol of an `XcoffFile64`. | |
234 | pub type XcoffSymbol64<'data, 'file, R = &'data [u8]> = | |
235 | XcoffSymbol<'data, 'file, xcoff::FileHeader64, R>; | |
236 | ||
237 | /// A symbol of an `XcoffFile`. | |
238 | #[derive(Debug, Clone, Copy)] | |
239 | pub struct XcoffSymbol<'data, 'file, Xcoff, R = &'data [u8]> | |
240 | where | |
49aad941 FG |
241 | Xcoff: FileHeader, |
242 | R: ReadRef<'data>, | |
243 | { | |
244 | pub(crate) file: &'file XcoffFile<'data, Xcoff, R>, | |
245 | pub(super) symbols: &'file SymbolTable<'data, Xcoff, R>, | |
246 | pub(super) index: SymbolIndex, | |
247 | pub(super) symbol: &'data Xcoff::Symbol, | |
248 | } | |
249 | ||
250 | impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> read::private::Sealed | |
251 | for XcoffSymbol<'data, 'file, Xcoff, R> | |
252 | { | |
253 | } | |
254 | ||
255 | impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> ObjectSymbol<'data> | |
256 | for XcoffSymbol<'data, 'file, Xcoff, R> | |
257 | { | |
258 | #[inline] | |
259 | fn index(&self) -> SymbolIndex { | |
260 | self.index | |
261 | } | |
262 | ||
263 | fn name_bytes(&self) -> Result<&'data [u8]> { | |
fe692bf9 FG |
264 | if self.symbol.has_aux_file() { |
265 | // By convention the file name is in the first auxiliary entry. | |
266 | self.symbols | |
267 | .aux_file(self.index.0, 1)? | |
268 | .fname(self.symbols.strings) | |
269 | } else { | |
270 | self.symbol.name(self.symbols.strings) | |
271 | } | |
49aad941 FG |
272 | } |
273 | ||
274 | fn name(&self) -> Result<&'data str> { | |
275 | let name = self.name_bytes()?; | |
276 | str::from_utf8(name) | |
277 | .ok() | |
278 | .read_error("Non UTF-8 XCOFF symbol name") | |
279 | } | |
280 | ||
281 | #[inline] | |
282 | fn address(&self) -> u64 { | |
283 | match self.symbol.n_sclass() { | |
284 | // Relocatable address. | |
285 | xcoff::C_EXT | |
286 | | xcoff::C_WEAKEXT | |
287 | | xcoff::C_HIDEXT | |
288 | | xcoff::C_FCN | |
289 | | xcoff::C_BLOCK | |
fe692bf9 FG |
290 | | xcoff::C_STAT |
291 | | xcoff::C_INFO => self.symbol.n_value().into(), | |
49aad941 FG |
292 | _ => 0, |
293 | } | |
294 | } | |
295 | ||
296 | #[inline] | |
297 | fn size(&self) -> u64 { | |
298 | if self.symbol.has_aux_csect() { | |
299 | // XCOFF32 must have the csect auxiliary entry as the last auxiliary entry. | |
300 | // XCOFF64 doesn't require this, but conventionally does. | |
301 | if let Ok(aux_csect) = self | |
302 | .file | |
303 | .symbols | |
304 | .aux_csect(self.index.0, self.symbol.n_numaux() as usize) | |
305 | { | |
306 | let sym_type = aux_csect.sym_type() & 0x07; | |
307 | if sym_type == xcoff::XTY_SD || sym_type == xcoff::XTY_CM { | |
fe692bf9 | 308 | return aux_csect.x_scnlen(); |
49aad941 | 309 | } |
49aad941 | 310 | } |
49aad941 | 311 | } |
fe692bf9 | 312 | 0 |
49aad941 FG |
313 | } |
314 | ||
315 | fn kind(&self) -> SymbolKind { | |
fe692bf9 FG |
316 | if self.symbol.has_aux_csect() { |
317 | if let Ok(aux_csect) = self | |
318 | .file | |
319 | .symbols | |
320 | .aux_csect(self.index.0, self.symbol.n_numaux() as usize) | |
321 | { | |
322 | let sym_type = aux_csect.sym_type() & 0x07; | |
323 | if sym_type == xcoff::XTY_SD || sym_type == xcoff::XTY_CM { | |
324 | return match aux_csect.x_smclas() { | |
325 | xcoff::XMC_PR | xcoff::XMC_GL => SymbolKind::Text, | |
326 | xcoff::XMC_RO | xcoff::XMC_RW | xcoff::XMC_TD | xcoff::XMC_BS => { | |
327 | SymbolKind::Data | |
328 | } | |
329 | xcoff::XMC_TL | xcoff::XMC_UL => SymbolKind::Tls, | |
330 | xcoff::XMC_DS | xcoff::XMC_TC0 | xcoff::XMC_TC => { | |
331 | // `Metadata` might be a better kind for these if we had it. | |
332 | SymbolKind::Data | |
333 | } | |
334 | _ => SymbolKind::Unknown, | |
335 | }; | |
336 | } else if sym_type == xcoff::XTY_LD { | |
337 | // A function entry point. Neither `Text` nor `Label` are a good fit for this. | |
338 | return SymbolKind::Text; | |
339 | } else if sym_type == xcoff::XTY_ER { | |
340 | return SymbolKind::Unknown; | |
341 | } | |
342 | } | |
343 | } | |
49aad941 | 344 | match self.symbol.n_sclass() { |
49aad941 | 345 | xcoff::C_NULL => SymbolKind::Null, |
fe692bf9 FG |
346 | xcoff::C_FILE => SymbolKind::File, |
347 | _ => SymbolKind::Unknown, | |
49aad941 FG |
348 | } |
349 | } | |
350 | ||
351 | fn section(&self) -> SymbolSection { | |
352 | match self.symbol.n_scnum() { | |
353 | xcoff::N_ABS => SymbolSection::Absolute, | |
354 | xcoff::N_UNDEF => SymbolSection::Undefined, | |
355 | xcoff::N_DEBUG => SymbolSection::None, | |
356 | index if index > 0 => SymbolSection::Section(SectionIndex(index as usize)), | |
357 | _ => SymbolSection::Unknown, | |
358 | } | |
359 | } | |
360 | ||
361 | #[inline] | |
362 | fn is_undefined(&self) -> bool { | |
363 | self.symbol.is_undefined() | |
364 | } | |
365 | ||
366 | /// Return true if the symbol is a definition of a function or data object. | |
367 | #[inline] | |
368 | fn is_definition(&self) -> bool { | |
369 | if self.symbol.has_aux_csect() { | |
370 | if let Ok(aux_csect) = self | |
371 | .symbols | |
372 | .aux_csect(self.index.0, self.symbol.n_numaux() as usize) | |
373 | { | |
374 | let smclas = aux_csect.x_smclas(); | |
375 | self.symbol.n_scnum() != xcoff::N_UNDEF | |
376 | && (smclas == xcoff::XMC_PR | |
377 | || smclas == xcoff::XMC_RW | |
378 | || smclas == xcoff::XMC_RO) | |
379 | } else { | |
380 | false | |
381 | } | |
382 | } else { | |
383 | false | |
384 | } | |
385 | } | |
386 | ||
387 | #[inline] | |
388 | fn is_common(&self) -> bool { | |
389 | self.symbol.n_sclass() == xcoff::C_EXT && self.symbol.n_scnum() == xcoff::N_UNDEF | |
390 | } | |
391 | ||
392 | #[inline] | |
393 | fn is_weak(&self) -> bool { | |
394 | self.symbol.n_sclass() == xcoff::C_WEAKEXT | |
395 | } | |
396 | ||
397 | fn scope(&self) -> SymbolScope { | |
398 | if self.symbol.n_scnum() == xcoff::N_UNDEF { | |
399 | SymbolScope::Unknown | |
400 | } else { | |
401 | match self.symbol.n_sclass() { | |
402 | xcoff::C_EXT | xcoff::C_WEAKEXT | xcoff::C_HIDEXT => { | |
403 | let visibility = self.symbol.n_type() & xcoff::SYM_V_MASK; | |
404 | if visibility == xcoff::SYM_V_HIDDEN { | |
405 | SymbolScope::Linkage | |
406 | } else { | |
407 | SymbolScope::Dynamic | |
408 | } | |
409 | } | |
410 | _ => SymbolScope::Compilation, | |
411 | } | |
412 | } | |
413 | } | |
414 | ||
415 | #[inline] | |
416 | fn is_global(&self) -> bool { | |
417 | match self.symbol.n_sclass() { | |
418 | xcoff::C_EXT | xcoff::C_WEAKEXT => true, | |
419 | _ => false, | |
420 | } | |
421 | } | |
422 | ||
423 | #[inline] | |
424 | fn is_local(&self) -> bool { | |
425 | !self.is_global() | |
426 | } | |
427 | ||
428 | #[inline] | |
fe692bf9 FG |
429 | fn flags(&self) -> SymbolFlags<SectionIndex, SymbolIndex> { |
430 | let mut x_smtyp = 0; | |
431 | let mut x_smclas = 0; | |
432 | let mut containing_csect = None; | |
433 | if self.symbol.has_aux_csect() { | |
434 | if let Ok(aux_csect) = self | |
435 | .file | |
436 | .symbols | |
437 | .aux_csect(self.index.0, self.symbol.n_numaux() as usize) | |
438 | { | |
439 | x_smtyp = aux_csect.x_smtyp(); | |
440 | x_smclas = aux_csect.x_smclas(); | |
441 | if x_smtyp == xcoff::XTY_LD { | |
442 | containing_csect = Some(SymbolIndex(aux_csect.x_scnlen() as usize)) | |
443 | } | |
444 | } | |
445 | } | |
446 | SymbolFlags::Xcoff { | |
447 | n_sclass: self.symbol.n_sclass(), | |
448 | x_smtyp, | |
449 | x_smclas, | |
450 | containing_csect, | |
451 | } | |
49aad941 FG |
452 | } |
453 | } | |
454 | ||
455 | /// A trait for generic access to `Symbol32` and `Symbol64`. | |
456 | #[allow(missing_docs)] | |
457 | pub trait Symbol: Debug + Pod { | |
458 | type Word: Into<u64>; | |
459 | ||
460 | fn n_value(&self) -> Self::Word; | |
461 | fn n_scnum(&self) -> i16; | |
462 | fn n_type(&self) -> u16; | |
463 | fn n_sclass(&self) -> u8; | |
464 | fn n_numaux(&self) -> u8; | |
465 | ||
466 | fn name<'data, R: ReadRef<'data>>( | |
467 | &'data self, | |
468 | strings: StringTable<'data, R>, | |
469 | ) -> Result<&'data [u8]>; | |
470 | ||
471 | /// Return true if the symbol is undefined. | |
472 | #[inline] | |
473 | fn is_undefined(&self) -> bool { | |
474 | let n_sclass = self.n_sclass(); | |
475 | (n_sclass == xcoff::C_EXT || n_sclass == xcoff::C_WEAKEXT) | |
476 | && self.n_scnum() == xcoff::N_UNDEF | |
477 | } | |
478 | ||
479 | /// Return true if the symbol has file auxiliary entry. | |
480 | fn has_aux_file(&self) -> bool { | |
481 | self.n_numaux() > 0 && self.n_sclass() == xcoff::C_FILE | |
482 | } | |
483 | ||
484 | /// Return true if the symbol has csect auxiliary entry. | |
485 | /// | |
486 | /// A csect auxiliary entry is required for each symbol table entry that has | |
487 | /// a storage class value of C_EXT, C_WEAKEXT, or C_HIDEXT. | |
488 | fn has_aux_csect(&self) -> bool { | |
489 | let sclass = self.n_sclass(); | |
490 | self.n_numaux() > 0 | |
491 | && (sclass == xcoff::C_EXT || sclass == xcoff::C_WEAKEXT || sclass == xcoff::C_HIDEXT) | |
492 | } | |
493 | } | |
494 | ||
495 | impl Symbol for xcoff::Symbol64 { | |
496 | type Word = u64; | |
497 | ||
498 | fn n_value(&self) -> Self::Word { | |
499 | self.n_value.get(BE) | |
500 | } | |
501 | ||
502 | fn n_scnum(&self) -> i16 { | |
503 | self.n_scnum.get(BE) | |
504 | } | |
505 | ||
506 | fn n_type(&self) -> u16 { | |
507 | self.n_type.get(BE) | |
508 | } | |
509 | ||
510 | fn n_sclass(&self) -> u8 { | |
511 | self.n_sclass | |
512 | } | |
513 | ||
514 | fn n_numaux(&self) -> u8 { | |
515 | self.n_numaux | |
516 | } | |
517 | ||
518 | /// Parse the symbol name for XCOFF64. | |
519 | fn name<'data, R: ReadRef<'data>>( | |
520 | &'data self, | |
521 | strings: StringTable<'data, R>, | |
522 | ) -> Result<&'data [u8]> { | |
523 | strings | |
524 | .get(self.n_offset.get(BE)) | |
525 | .read_error("Invalid XCOFF symbol name offset") | |
526 | } | |
527 | } | |
528 | ||
529 | impl Symbol for xcoff::Symbol32 { | |
530 | type Word = u32; | |
531 | ||
532 | fn n_value(&self) -> Self::Word { | |
533 | self.n_value.get(BE) | |
534 | } | |
535 | ||
536 | fn n_scnum(&self) -> i16 { | |
537 | self.n_scnum.get(BE) | |
538 | } | |
539 | ||
540 | fn n_type(&self) -> u16 { | |
541 | self.n_type.get(BE) | |
542 | } | |
543 | ||
544 | fn n_sclass(&self) -> u8 { | |
545 | self.n_sclass | |
546 | } | |
547 | ||
548 | fn n_numaux(&self) -> u8 { | |
549 | self.n_numaux | |
550 | } | |
551 | ||
552 | /// Parse the symbol name for XCOFF32. | |
553 | fn name<'data, R: ReadRef<'data>>( | |
554 | &'data self, | |
555 | strings: StringTable<'data, R>, | |
556 | ) -> Result<&'data [u8]> { | |
557 | if self.n_name[0] == 0 { | |
558 | // If the name starts with 0 then the last 4 bytes are a string table offset. | |
559 | let offset = u32::from_be_bytes(self.n_name[4..8].try_into().unwrap()); | |
560 | strings | |
561 | .get(offset) | |
562 | .read_error("Invalid XCOFF symbol name offset") | |
563 | } else { | |
564 | // The name is inline and padded with nulls. | |
565 | Ok(match memchr::memchr(b'\0', &self.n_name) { | |
566 | Some(end) => &self.n_name[..end], | |
567 | None => &self.n_name, | |
568 | }) | |
569 | } | |
570 | } | |
571 | } | |
572 | ||
573 | /// A trait for generic access to `FileAux32` and `FileAux64`. | |
574 | #[allow(missing_docs)] | |
575 | pub trait FileAux: Debug + Pod { | |
576 | fn x_fname(&self) -> &[u8; 8]; | |
577 | fn x_ftype(&self) -> u8; | |
578 | fn x_auxtype(&self) -> Option<u8>; | |
fe692bf9 FG |
579 | |
580 | /// Parse the x_fname field, which may be an inline string or a string table offset. | |
581 | fn fname<'data, R: ReadRef<'data>>( | |
582 | &'data self, | |
583 | strings: StringTable<'data, R>, | |
584 | ) -> Result<&'data [u8]> { | |
585 | let x_fname = self.x_fname(); | |
586 | if x_fname[0] == 0 { | |
587 | // If the name starts with 0 then the last 4 bytes are a string table offset. | |
588 | let offset = u32::from_be_bytes(x_fname[4..8].try_into().unwrap()); | |
589 | strings | |
590 | .get(offset) | |
591 | .read_error("Invalid XCOFF symbol name offset") | |
592 | } else { | |
593 | // The name is inline and padded with nulls. | |
594 | Ok(match memchr::memchr(b'\0', x_fname) { | |
595 | Some(end) => &x_fname[..end], | |
596 | None => x_fname, | |
597 | }) | |
598 | } | |
599 | } | |
49aad941 FG |
600 | } |
601 | ||
602 | impl FileAux for xcoff::FileAux64 { | |
603 | fn x_fname(&self) -> &[u8; 8] { | |
604 | &self.x_fname | |
605 | } | |
606 | ||
607 | fn x_ftype(&self) -> u8 { | |
608 | self.x_ftype | |
609 | } | |
610 | ||
611 | fn x_auxtype(&self) -> Option<u8> { | |
612 | Some(self.x_auxtype) | |
613 | } | |
614 | } | |
615 | ||
616 | impl FileAux for xcoff::FileAux32 { | |
617 | fn x_fname(&self) -> &[u8; 8] { | |
618 | &self.x_fname | |
619 | } | |
620 | ||
621 | fn x_ftype(&self) -> u8 { | |
622 | self.x_ftype | |
623 | } | |
624 | ||
625 | fn x_auxtype(&self) -> Option<u8> { | |
626 | None | |
627 | } | |
628 | } | |
629 | ||
630 | /// A trait for generic access to `CsectAux32` and `CsectAux64`. | |
631 | #[allow(missing_docs)] | |
632 | pub trait CsectAux: Debug + Pod { | |
633 | fn x_scnlen(&self) -> u64; | |
634 | fn x_parmhash(&self) -> u32; | |
635 | fn x_snhash(&self) -> u16; | |
636 | fn x_smtyp(&self) -> u8; | |
637 | fn x_smclas(&self) -> u8; | |
638 | fn x_auxtype(&self) -> Option<u8>; | |
639 | ||
640 | fn sym_type(&self) -> u8 { | |
641 | self.x_smtyp() & 0x07 | |
642 | } | |
643 | } | |
644 | ||
645 | impl CsectAux for xcoff::CsectAux64 { | |
646 | fn x_scnlen(&self) -> u64 { | |
647 | self.x_scnlen_lo.get(BE) as u64 | ((self.x_scnlen_hi.get(BE) as u64) << 32) | |
648 | } | |
649 | ||
650 | fn x_parmhash(&self) -> u32 { | |
651 | self.x_parmhash.get(BE) | |
652 | } | |
653 | ||
654 | fn x_snhash(&self) -> u16 { | |
655 | self.x_snhash.get(BE) | |
656 | } | |
657 | ||
658 | fn x_smtyp(&self) -> u8 { | |
659 | self.x_smtyp | |
660 | } | |
661 | ||
662 | fn x_smclas(&self) -> u8 { | |
663 | self.x_smclas | |
664 | } | |
665 | ||
666 | fn x_auxtype(&self) -> Option<u8> { | |
667 | Some(self.x_auxtype) | |
668 | } | |
669 | } | |
670 | ||
671 | impl CsectAux for xcoff::CsectAux32 { | |
672 | fn x_scnlen(&self) -> u64 { | |
673 | self.x_scnlen.get(BE) as u64 | |
674 | } | |
675 | ||
676 | fn x_parmhash(&self) -> u32 { | |
677 | self.x_parmhash.get(BE) | |
678 | } | |
679 | ||
680 | fn x_snhash(&self) -> u16 { | |
681 | self.x_snhash.get(BE) | |
682 | } | |
683 | ||
684 | fn x_smtyp(&self) -> u8 { | |
685 | self.x_smtyp | |
686 | } | |
687 | ||
688 | fn x_smclas(&self) -> u8 { | |
689 | self.x_smclas | |
690 | } | |
691 | ||
692 | fn x_auxtype(&self) -> Option<u8> { | |
693 | None | |
694 | } | |
695 | } |