1 // Copyright 2017 pdb Developers
2 //
3 // Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4 // http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5 // http://opensource.org/licenses/MIT>, at your option. This file may not be
6 // copied, modified, or distributed except according to those terms.
7 
8 use std::borrow::Cow;
9 use std::fmt;
10 use std::io;
11 use std::mem;
12 use std::ops::{Add, AddAssign, Sub};
13 use std::result;
14 use std::slice;
15 
16 use scroll::ctx::TryFromCtx;
17 use scroll::{self, Endian, Pread, LE};
18 
19 use crate::tpi::constants;
20 
21 /// An error that occurred while reading or parsing the PDB.
22 #[non_exhaustive]
23 #[derive(Debug)]
24 pub enum Error {
25     /// The input data was not recognized as a MSF (PDB) file.
26     UnrecognizedFileFormat,
27 
28     /// The MSF header specifies an invalid page size.
29     InvalidPageSize(u32),
30 
31     /// MSF referred to page number out of range.
32     ///
33     /// This likely indicates file corruption.
34     PageReferenceOutOfRange(u32),
35 
36     /// The requested stream is not stored in this file.
37     StreamNotFound(u32),
38 
39     /// A stream requested by name was not found.
40     StreamNameNotFound,
41 
42     /// Invalid length or alignment of a stream.
43     InvalidStreamLength(&'static str),
44 
45     /// An IO error occurred while reading from the data source.
46     IoError(io::Error),
47 
48     /// Unexpectedly reached end of input.
49     UnexpectedEof,
50 
51     /// This data might be understandable, but the code needed to understand it hasn't been written.
52     UnimplementedFeature(&'static str),
53 
54     /// The global shared symbol table is missing.
55     GlobalSymbolsNotFound,
56 
57     /// A symbol record's length value was impossibly small.
58     SymbolTooShort,
59 
60     /// Support for symbols of this kind is not implemented.
61     UnimplementedSymbolKind(u16),
62 
63     /// The type information header was invalid.
64     InvalidTypeInformationHeader(&'static str),
65 
66     /// A type record's length value was impossibly small.
67     TypeTooShort,
68 
69     /// Type or Id not found.
70     TypeNotFound(u32),
71 
72     /// Type or Id not indexed -- the requested type (`.0`) is larger than the maximum index covered
73     /// by the `ItemFinder` (`.1`).
74     TypeNotIndexed(u32, u32),
75 
76     /// Support for types of this kind is not implemented.
77     UnimplementedTypeKind(u16),
78 
79     /// Type index is not a cross module reference.
80     NotACrossModuleRef(u32),
81 
82     /// Cross module reference not found in imports.
83     CrossModuleRefNotFound(u32),
84 
85     /// Variable-length numeric parsing encountered an unexpected prefix.
86     UnexpectedNumericPrefix(u16),
87 
88     /// Required mapping for virtual addresses (OMAP) was not found.
89     AddressMapNotFound,
90 
91     /// A parse error from scroll.
92     ScrollError(scroll::Error),
93 
94     /// This debug subsection kind is unknown or unimplemented.
95     UnimplementedDebugSubsection(u32),
96 
97     /// This source file checksum kind is unknown or unimplemented.
98     UnimplementedFileChecksumKind(u8),
99 
100     /// There is no source file checksum at the given offset.
101     InvalidFileChecksumOffset(u32),
102 
103     /// The lines table is missing.
104     LinesNotFound,
105 
106     /// A binary annotation was compressed incorrectly.
107     InvalidCompressedAnnotation,
108 
109     /// An unknown binary annotation was encountered.
110     UnknownBinaryAnnotation(u32),
111 }
112 
113 impl std::error::Error for Error {
source(&self) -> Option<&(dyn std::error::Error + 'static)>114     fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
115         match *self {
116             Self::IoError(ref error) => Some(error),
117             _ => None,
118         }
119     }
120 }
121 
122 impl fmt::Display for Error {
fmt(&self, f: &mut fmt::Formatter<'_>) -> ::std::result::Result<(), fmt::Error>123     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> ::std::result::Result<(), fmt::Error> {
124         match *self {
125             Error::PageReferenceOutOfRange(p) => {
126                 write!(f, "MSF referred to page number ({}) out of range", p)
127             }
128             Error::InvalidPageSize(n) => write!(
129                 f,
130                 "The MSF header specifies an invalid page size ({} bytes)",
131                 n
132             ),
133             Error::StreamNotFound(s) => {
134                 write!(f, "The requested stream ({}) is not stored in this file", s)
135             }
136             Error::InvalidStreamLength(s) => write!(
137                 f,
138                 "{} stream has an invalid length or alignment for its records",
139                 s
140             ),
141             Error::IoError(ref e) => write!(f, "IO error while reading PDB: {}", e),
142             Error::UnimplementedFeature(feature) => {
143                 write!(f, "Unimplemented PDB feature: {}", feature)
144             }
145             Error::UnimplementedSymbolKind(kind) => write!(
146                 f,
147                 "Support for symbols of kind {:#06x} is not implemented",
148                 kind
149             ),
150             Error::InvalidTypeInformationHeader(reason) => {
151                 write!(f, "The type information header was invalid: {}", reason)
152             }
153             Error::TypeNotFound(type_index) => write!(f, "Type {} not found", type_index),
154             Error::TypeNotIndexed(type_index, indexed_count) => write!(
155                 f,
156                 "Type {} not indexed (index covers {})",
157                 type_index, indexed_count
158             ),
159             Error::UnimplementedTypeKind(kind) => write!(
160                 f,
161                 "Support for types of kind {:#06x} is not implemented",
162                 kind
163             ),
164             Error::NotACrossModuleRef(index) => {
165                 write!(f, "Type {:#06x} is not a cross module reference", index)
166             }
167             Error::CrossModuleRefNotFound(index) => write!(
168                 f,
169                 "Cross module reference {:#06x} not found in imports",
170                 index
171             ),
172             Error::UnexpectedNumericPrefix(prefix) => write!(
173                 f,
174                 "Variable-length numeric parsing encountered an unexpected prefix ({:#06x}",
175                 prefix
176             ),
177             Error::UnimplementedDebugSubsection(kind) => write!(
178                 f,
179                 "Debug module subsection of kind {:#06x} is not implemented",
180                 kind
181             ),
182             Error::UnimplementedFileChecksumKind(kind) => {
183                 write!(f, "Unknown source file checksum kind {}", kind)
184             }
185             Error::InvalidFileChecksumOffset(offset) => {
186                 write!(f, "Invalid source file checksum offset {:#x}", offset)
187             }
188             Error::UnknownBinaryAnnotation(num) => write!(f, "Unknown binary annotation {}", num),
189             _ => fmt::Debug::fmt(self, f),
190         }
191     }
192 }
193 
194 impl From<io::Error> for Error {
from(e: io::Error) -> Self195     fn from(e: io::Error) -> Self {
196         Error::IoError(e)
197     }
198 }
199 
200 impl From<scroll::Error> for Error {
from(e: scroll::Error) -> Self201     fn from(e: scroll::Error) -> Self {
202         match e {
203             // Convert a couple of scroll errors into EOF.
204             scroll::Error::BadOffset(_) | scroll::Error::TooBig { .. } => Error::UnexpectedEof,
205             _ => Error::ScrollError(e),
206         }
207     }
208 }
209 
210 /// The result type returned by this crate.
211 pub type Result<T> = result::Result<T, Error>;
212 
213 /// Implements `Pread` using the inner type.
214 macro_rules! impl_pread {
215     ($type:ty) => {
216         impl<'a> TryFromCtx<'a, Endian> for $type {
217             type Error = scroll::Error;
218 
219             fn try_from_ctx(this: &'a [u8], le: Endian) -> scroll::Result<(Self, usize)> {
220                 TryFromCtx::try_from_ctx(this, le).map(|(i, s)| (Self(i), s))
221             }
222         }
223     };
224 }
225 
226 /// Displays the type as hexadecimal number. Debug prints the type name around.
227 macro_rules! impl_hex_fmt {
228     ($type:ty) => {
229         impl fmt::Display for $type {
230             fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
231                 write!(f, "{:#x}", self.0)
232             }
233         }
234 
235         impl fmt::Debug for $type {
236             fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
237                 write!(f, concat!(stringify!($type), "({})"), self)
238             }
239         }
240     };
241 }
242 
243 /// Implements bidirectional conversion traits for the newtype.
244 macro_rules! impl_convert {
245     ($type:ty, $inner:ty) => {
246         impl From<$inner> for $type {
247             fn from(offset: $inner) -> Self {
248                 Self(offset)
249             }
250         }
251 
252         impl From<$type> for $inner {
253             fn from(string_ref: $type) -> Self {
254                 string_ref.0
255             }
256         }
257     };
258 }
259 
260 /// Declares that the given value represents `None`.
261 ///
262 ///  - `Type::none` and `Default::default` return the none value.
263 ///  - `Type::is_some` and `Type::is_none` check for the none value.
264 macro_rules! impl_opt {
265     ($type:ty, $none:literal) => {
266         impl $type {
267             /// Returns an index that points to no value.
268             #[inline]
269             pub const fn none() -> Self {
270                 Self($none)
271             }
272 
273             /// Returns `true` if the index points to a valid value.
274             #[inline]
275             #[must_use]
276             pub fn is_some(self) -> bool {
277                 self.0 != $none
278             }
279 
280             /// Returns `true` if the index indicates the absence of a value.
281             #[inline]
282             #[must_use]
283             pub fn is_none(self) -> bool {
284                 self.0 == $none
285             }
286         }
287 
288         impl Default for $type {
289             #[inline]
290             fn default() -> Self {
291                 Self::none()
292             }
293         }
294     };
295 }
296 
297 /// Implements common functionality for virtual addresses.
298 macro_rules! impl_va {
299     ($type:ty) => {
300         impl $type {
301             /// Checked addition of an offset. Returns `None` if overflow occurred.
302             pub fn checked_add(self, offset: u32) -> Option<Self> {
303                 Some(Self(self.0.checked_add(offset)?))
304             }
305 
306             /// Checked computation of an offset between two addresses. Returns `None` if `other` is
307             /// larger.
308             pub fn checked_sub(self, other: Self) -> Option<u32> {
309                 self.0.checked_sub(other.0)
310             }
311 
312             /// Saturating addition of an offset, clipped at the numeric bounds.
313             pub fn saturating_add(self, offset: u32) -> Self {
314                 Self(self.0.saturating_add(offset))
315             }
316 
317             /// Saturating computation of an offset between two addresses, clipped at zero.
318             pub fn saturating_sub(self, other: Self) -> u32 {
319                 self.0.saturating_sub(other.0)
320             }
321 
322             /// Wrapping (modular) addition of an offset.
323             pub fn wrapping_add(self, offset: u32) -> Self {
324                 Self(self.0.wrapping_add(offset))
325             }
326 
327             /// Wrapping (modular) computation of an offset between two addresses.
328             pub fn wrapping_sub(self, other: Self) -> u32 {
329                 self.0.wrapping_sub(other.0)
330             }
331         }
332 
333         impl Add<u32> for $type {
334             type Output = Self;
335 
336             /// Adds the given offset to this address.
337             #[inline]
338             fn add(mut self, offset: u32) -> Self {
339                 self.0 += offset;
340                 self
341             }
342         }
343 
344         impl AddAssign<u32> for $type {
345             /// Adds the given offset to this address.
346             #[inline]
347             fn add_assign(&mut self, offset: u32) {
348                 self.0 += offset;
349             }
350         }
351 
352         impl Sub for $type {
353             type Output = u32;
354 
355             fn sub(self, other: Self) -> Self::Output {
356                 self.0 - other.0
357             }
358         }
359 
360         impl_convert!($type, u32);
361         impl_hex_fmt!($type);
362     };
363 }
364 
365 /// A Relative Virtual Address as it appears in a PE file.
366 ///
367 /// RVAs are always relative to the image base address, as it is loaded into process memory. This
368 /// address is reported by debuggers in stack traces and may refer to symbols or instruction
369 /// pointers.
370 #[derive(Clone, Copy, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
371 pub struct Rva(pub u32);
372 
373 impl_va!(Rva);
374 
375 /// A Relative Virtual Address in an unoptimized PE file.
376 ///
377 /// An internal RVA points into the PDB internal address space and may not correspond to RVAs of the
378 /// executable. It can be converted into an actual [`Rva`] suitable for debugging purposes using
379 /// [`to_rva`](Self::to_rva).
380 #[derive(Clone, Copy, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
381 pub struct PdbInternalRva(pub u32);
382 
383 impl_va!(PdbInternalRva);
384 impl_pread!(PdbInternalRva);
385 
386 /// Implements common functionality for section offsets.
387 macro_rules! impl_section_offset {
388     ($type:ty) => {
389         impl $type {
390             /// Creates a new section offset.
391             pub fn new(section: u16, offset: u32) -> Self {
392                 Self { offset, section }
393             }
394 
395             /// Returns whether this section offset points to a valid section or into the void.
396             pub fn is_valid(self) -> bool {
397                 self.section != 0
398             }
399 
400             /// Checked addition of an offset. Returns `None` if overflow occurred.
401             ///
402             /// This does not check whether the offset is still valid within the given section. If
403             /// the offset is out of bounds, the conversion to `Rva` will return `None`.
404             pub fn checked_add(mut self, offset: u32) -> Option<Self> {
405                 self.offset = self.offset.checked_add(offset)?;
406                 Some(self)
407             }
408 
409             /// Saturating addition of an offset, clipped at the numeric bounds.
410             ///
411             /// This does not check whether the offset is still valid within the given section. If
412             /// the offset is out of bounds, the conversion to `Rva` will return `None`.
413             pub fn saturating_add(mut self, offset: u32) -> Self {
414                 self.offset = self.offset.saturating_add(offset);
415                 self
416             }
417 
418             /// Wrapping (modular) addition of an offset.
419             ///
420             /// This does not check whether the offset is still valid within the given section. If
421             /// the offset is out of bounds, the conversion to `Rva` will return `None`.
422             pub fn wrapping_add(mut self, offset: u32) -> Self {
423                 self.offset = self.offset.wrapping_add(offset);
424                 self
425             }
426         }
427 
428         impl Add<u32> for $type {
429             type Output = Self;
430 
431             /// Adds the given offset to this section offset.
432             ///
433             /// This does not check whether the offset is still valid within the given section. If
434             /// the offset is out of bounds, the conversion to `Rva` will return `None`.
435             #[inline]
436             fn add(mut self, offset: u32) -> Self {
437                 self.offset += offset;
438                 self
439             }
440         }
441 
442         impl AddAssign<u32> for $type {
443             /// Adds the given offset to this section offset.
444             ///
445             /// This does not check whether the offset is still valid within the given section. If
446             /// the offset is out of bounds, the conversion to `Rva` will return `None`.
447             #[inline]
448             fn add_assign(&mut self, offset: u32) {
449                 self.offset += offset;
450             }
451         }
452 
453         impl PartialOrd for $type {
454             /// Compares offsets if they reside in the same section.
455             #[inline]
456             fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
457                 if self.section == other.section {
458                     Some(self.offset.cmp(&other.offset))
459                 } else {
460                     None
461                 }
462             }
463         }
464 
465         impl fmt::Debug for $type {
466             fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
467                 f.debug_struct(stringify!($type))
468                     .field("section", &format_args!("{:#x}", self.section))
469                     .field("offset", &format_args!("{:#x}", self.offset))
470                     .finish()
471             }
472         }
473     };
474 }
475 
476 /// An offset relative to a PE section.
477 ///
478 /// This offset can be converted to an `Rva` to receive the address relative to the entire image.
479 /// Note that this offset applies to the actual PE headers. The PDB debug information actually
480 /// stores [`PdbInternalSectionOffset`]s.
481 #[derive(Clone, Copy, Default, Eq, Hash, PartialEq)]
482 pub struct SectionOffset {
483     /// The memory offset relative from the start of the section's memory.
484     pub offset: u32,
485 
486     /// The index of the section in the PE's section headers list, incremented by `1`. A value of
487     /// `0` indicates an invalid or missing reference.
488     pub section: u16,
489 }
490 
491 impl_section_offset!(SectionOffset);
492 
493 /// An offset relative to a PE section in the original unoptimized binary.
494 ///
495 /// For optimized Microsoft binaries, this offset points to a virtual address space before the
496 /// rearrangement of sections has been performed. This kind of offset is usually stored in PDB debug
497 /// information. It can be converted to an RVA in the transformed address space of the optimized
498 /// binary using [`to_rva`](PdbInternalSectionOffset::to_rva). Likewise, there is a conversion to [`SectionOffset`] in the actual address
499 /// space.
500 ///
501 /// For binaries and their PDBs that have not been optimized, both address spaces are equal and the
502 /// offsets are interchangeable. The conversion operations are cheap no-ops in this case.
503 #[derive(Clone, Copy, Default, Eq, Hash, PartialEq)]
504 pub struct PdbInternalSectionOffset {
505     /// The memory offset relative from the start of the section's memory.
506     pub offset: u32,
507 
508     /// The index of the section in the PDB's section headers list, incremented by `1`. A value of
509     /// `0` indicates an invalid or missing reference.
510     pub section: u16,
511 }
512 
513 impl<'t> TryFromCtx<'t, Endian> for PdbInternalSectionOffset {
514     type Error = scroll::Error;
515 
try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)>516     fn try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)> {
517         let mut offset = 0;
518         let data = PdbInternalSectionOffset {
519             offset: this.gread_with(&mut offset, le)?,
520             section: this.gread_with(&mut offset, le)?,
521         };
522         Ok((data, offset))
523     }
524 }
525 
526 impl_section_offset!(PdbInternalSectionOffset);
527 
528 /// Index of a PDB stream.
529 ///
530 /// This index can either refer to a stream, or indicate the absence of a stream. Check
531 /// [`is_none`](Self::is_none) to see whether a stream should exist.
532 ///
533 /// Use [`get`](Self::get) to load data for this stream.
534 #[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
535 pub struct StreamIndex(pub u16);
536 
537 impl StreamIndex {
538     /// Returns the MSF stream number, if this stream is not a NULL stream.
539     #[inline]
msf_number(self) -> Option<u32>540     pub(crate) fn msf_number(self) -> Option<u32> {
541         match self.0 {
542             0xffff => None,
543             index => Some(u32::from(index)),
544         }
545     }
546 }
547 
548 impl fmt::Display for StreamIndex {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result549     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
550         match self.msf_number() {
551             Some(number) => write!(f, "{}", number),
552             None => write!(f, "None"),
553         }
554     }
555 }
556 
557 impl fmt::Debug for StreamIndex {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result558     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
559         write!(f, "StreamIndex({})", self)
560     }
561 }
562 
563 impl_opt!(StreamIndex, 0xffff);
564 impl_pread!(StreamIndex);
565 
566 /// An index into either the [`TypeInformation`](crate::TypeInformation) or
567 /// [`IdInformation`](crate::IdInformation) stream.
568 pub trait ItemIndex:
569     Copy + Default + fmt::Debug + fmt::Display + PartialEq + PartialOrd + From<u32> + Into<u32>
570 {
571     /// Returns `true` if this is a cross module reference.
572     ///
573     /// When compiling with LTO, the compiler may reference types and ids across modules. In such
574     /// cases, a lookup in the global streams will not succeed. Instead, the import must be resolved
575     /// using cross module references:
576     ///
577     ///  1. Look up the index in [`CrossModuleImports`](crate::CrossModuleImports) of the current
578     ///     module.
579     ///  2. Use [`StringTable`](crate::StringTable) to resolve the name of the referenced module.
580     ///  3. Find the [`Module`](crate::Module) with the same module name and load its
581     ///     [`ModuleInfo`](crate::ModuleInfo).
582     ///  4. Resolve the [`Local`](crate::Local) index into a global one using
583     ///     [`CrossModuleExports`](crate::CrossModuleExports).
584     ///
585     /// Cross module references are specially formatted indexes with the most significant bit set to
586     /// `1`. The remaining bits are divided into a module and index offset into the
587     /// [`CrossModuleImports`](crate::CrossModuleImports) section.
is_cross_module(self) -> bool588     fn is_cross_module(self) -> bool {
589         (self.into() & 0x8000_0000) != 0
590     }
591 }
592 
593 /// Index of [`TypeData`](crate::TypeData) in the [`TypeInformation`](crate::TypeInformation) stream.
594 ///
595 /// If this index is a [cross module reference](ItemIndex::is_cross_module), it must be resolved
596 /// before lookup in the stream.
597 #[derive(Clone, Copy, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
598 pub struct TypeIndex(pub u32);
599 
600 impl_convert!(TypeIndex, u32);
601 impl_hex_fmt!(TypeIndex);
602 impl_pread!(TypeIndex);
603 
604 impl ItemIndex for TypeIndex {}
605 
606 /// Index of an [`Id`](crate::Id) in [`IdInformation`](crate::IdInformation) stream.
607 ///
608 /// If this index is a [cross module reference](ItemIndex::is_cross_module), it must be resolved
609 /// before lookup in the stream.
610 #[derive(Clone, Copy, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
611 pub struct IdIndex(pub u32);
612 
613 impl_convert!(IdIndex, u32);
614 impl_hex_fmt!(IdIndex);
615 impl_pread!(IdIndex);
616 
617 impl ItemIndex for IdIndex {}
618 
619 /// An [`ItemIndex`] that is local to a module.
620 ///
621 /// This index is usually part of a [`CrossModuleRef`](crate::CrossModuleRef). It cannot be used to
622 /// query the [`TypeInformation`](crate::TypeInformation) or [`IdInformation`](crate::IdInformation)
623 /// streams directly. Instead, it must be looked up in the
624 /// [`CrossModuleImports`](crate::CrossModuleImports) of the module it belongs to in order to obtain
625 /// the global index.
626 ///
627 /// See [`ItemIndex::is_cross_module`] for more information.
628 #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
629 pub struct Local<I: ItemIndex>(pub I);
630 
631 impl<I> fmt::Display for Local<I>
632 where
633     I: ItemIndex + fmt::Display,
634 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result635     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
636         write!(f, "{}", self.0)
637     }
638 }
639 
640 /// A reference to a string in the string table.
641 ///
642 /// This type stores an offset into the global string table of the PDB. To retrieve the string
643 /// value, use [`to_raw_string`](Self::to_raw_string), [`to_string_lossy`](Self::to_string_lossy) or
644 /// methods on [`StringTable`](crate::StringTable).
645 #[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
646 pub struct StringRef(pub u32);
647 
648 impl_convert!(StringRef, u32);
649 impl_hex_fmt!(StringRef);
650 impl_pread!(StringRef);
651 
652 /// Index of a file entry in the module.
653 ///
654 /// Use the [`LineProgram`](crate::LineProgram) to resolve information on the file from this offset.
655 #[derive(Clone, Copy, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
656 pub struct FileIndex(pub u32);
657 
658 impl_convert!(FileIndex, u32);
659 impl_hex_fmt!(FileIndex);
660 impl_pread!(FileIndex);
661 
662 /// A reference into the symbol table of a module.
663 ///
664 /// To retrieve the symbol referenced by this index, use
665 /// [`ModuleInfo::symbols_at`](crate::ModuleInfo::symbols_at). When iterating, use
666 /// [`SymbolIter::seek`](crate::SymbolIter::seek) to jump between symbols.
667 #[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
668 pub struct SymbolIndex(pub u32);
669 
670 impl_convert!(SymbolIndex, u32);
671 impl_hex_fmt!(SymbolIndex);
672 impl_pread!(SymbolIndex);
673 
674 /// A register referred to by its number.
675 #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
676 pub struct Register(pub u16);
677 
678 impl_convert!(Register, u16);
679 impl_pread!(Register);
680 
681 /// Provides little-endian access to a &[u8].
682 #[derive(Debug, Clone)]
683 pub(crate) struct ParseBuffer<'b>(&'b [u8], usize);
684 
685 macro_rules! def_parse {
686     ( $( ($n:ident, $t:ty) ),* $(,)* ) => {
687         $(#[doc(hidden)]
688           #[inline]
689           #[allow(unused)]
690           pub fn $n(&mut self) -> Result<$t> {
691               Ok(self.parse()?)
692           })*
693     }
694 }
695 
696 macro_rules! def_peek {
697     ( $( ($n:ident, $t:ty) ),* $(,)* ) => {
698         $(#[doc(hidden)]
699           #[inline]
700           pub fn $n(&mut self) -> Result<$t> {
701               Ok(self.0.pread_with(self.1, LE)?)
702           })*
703     }
704 }
705 
706 impl<'b> ParseBuffer<'b> {
707     /// Return the remaining length of the buffer.
708     #[inline]
len(&self) -> usize709     pub fn len(&self) -> usize {
710         self.0.len() - self.1
711     }
712 
713     /// Determines whether this ParseBuffer has been consumed.
714     #[inline]
is_empty(&self) -> bool715     pub fn is_empty(&self) -> bool {
716         self.len() == 0
717     }
718 
719     /// Return the position within the parent slice.
720     #[inline]
pos(&self) -> usize721     pub fn pos(&self) -> usize {
722         self.1
723     }
724 
725     /// Seek to the given absolute position.
726     #[inline]
seek(&mut self, pos: usize)727     pub fn seek(&mut self, pos: usize) {
728         self.1 = std::cmp::min(pos, self.0.len());
729     }
730 
731     /// Truncates the buffer at the given absolute position.
732     #[inline]
truncate(&mut self, len: usize) -> Result<()>733     pub fn truncate(&mut self, len: usize) -> Result<()> {
734         if self.0.len() >= len {
735             self.0 = &self.0[..len];
736             Ok(())
737         } else {
738             Err(Error::UnexpectedEof)
739         }
740     }
741 
742     /// Align the current position to the next multiple of `alignment` bytes.
743     #[inline]
align(&mut self, alignment: usize) -> Result<()>744     pub fn align(&mut self, alignment: usize) -> Result<()> {
745         let diff = self.1 % alignment;
746         if diff > 0 {
747             if self.len() < (alignment - diff) {
748                 return Err(Error::UnexpectedEof);
749             }
750             self.1 += alignment - diff;
751         }
752         Ok(())
753     }
754 
755     /// Parse an object that implements `Pread`.
parse<T>(&mut self) -> Result<T> where T: TryFromCtx<'b, Endian, [u8]>, T::Error: From<scroll::Error>, Error: From<T::Error>,756     pub fn parse<T>(&mut self) -> Result<T>
757     where
758         T: TryFromCtx<'b, Endian, [u8]>,
759         T::Error: From<scroll::Error>,
760         Error: From<T::Error>,
761     {
762         Ok(self.0.gread_with(&mut self.1, LE)?)
763     }
764 
765     /// Parse an object that implements `Pread` with the given context.
parse_with<T, C>(&mut self, ctx: C) -> Result<T> where T: TryFromCtx<'b, C, [u8]>, T::Error: From<scroll::Error>, Error: From<T::Error>, C: Copy,766     pub fn parse_with<T, C>(&mut self, ctx: C) -> Result<T>
767     where
768         T: TryFromCtx<'b, C, [u8]>,
769         T::Error: From<scroll::Error>,
770         Error: From<T::Error>,
771         C: Copy,
772     {
773         Ok(self.0.gread_with(&mut self.1, ctx)?)
774     }
775 
776     def_parse!(
777         (parse_u8, u8),
778         (parse_u16, u16),
779         (parse_i16, i16),
780         (parse_u32, u32),
781         (parse_i32, i32),
782         (parse_u64, u64),
783         (parse_i64, i64),
784     );
785 
786     def_peek!((peek_u8, u8), (peek_u16, u16),);
787 
788     /// Parse a NUL-terminated string from the input.
789     #[inline]
parse_cstring(&mut self) -> Result<RawString<'b>>790     pub fn parse_cstring(&mut self) -> Result<RawString<'b>> {
791         let input = &self.0[self.1..];
792         let null_idx = input.iter().position(|ch| *ch == 0);
793 
794         if let Some(idx) = null_idx {
795             self.1 += idx + 1;
796             Ok(RawString::from(&input[..idx]))
797         } else {
798             Err(Error::UnexpectedEof)
799         }
800     }
801 
802     /// Parse a u8-length-prefixed string from the input.
803     #[inline]
parse_u8_pascal_string(&mut self) -> Result<RawString<'b>>804     pub fn parse_u8_pascal_string(&mut self) -> Result<RawString<'b>> {
805         let length = self.parse_u8()? as usize;
806         Ok(RawString::from(self.take(length)?))
807     }
808 
809     /// Take n bytes from the input
810     #[inline]
take(&mut self, n: usize) -> Result<&'b [u8]>811     pub fn take(&mut self, n: usize) -> Result<&'b [u8]> {
812         let input = &self.0[self.1..];
813         if input.len() >= n {
814             self.1 += n;
815             Ok(&input[..n])
816         } else {
817             Err(Error::UnexpectedEof)
818         }
819     }
820 }
821 
822 impl Default for ParseBuffer<'_> {
default() -> Self823     fn default() -> Self {
824         ParseBuffer(&[], 0)
825     }
826 }
827 
828 impl<'b> From<&'b [u8]> for ParseBuffer<'b> {
from(buf: &'b [u8]) -> Self829     fn from(buf: &'b [u8]) -> Self {
830         ParseBuffer(buf, 0)
831     }
832 }
833 
834 impl<'b> fmt::LowerHex for ParseBuffer<'b> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> result::Result<(), fmt::Error>835     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> result::Result<(), fmt::Error> {
836         write!(f, "ParseBuf::from(\"")?;
837         for byte in self.0 {
838             write!(f, "\\x{:02x}", byte)?;
839         }
840         write!(f, "\").as_bytes() at offset {}", self.1)
841     }
842 }
843 
844 /// Value of an enumerate type.
845 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
846 #[allow(missing_docs)]
847 pub enum Variant {
848     U8(u8),
849     U16(u16),
850     U32(u32),
851     U64(u64),
852     I8(i8),
853     I16(i16),
854     I32(i32),
855     I64(i64),
856 }
857 
858 impl fmt::Display for Variant {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result859     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
860         match *self {
861             Variant::U8(value) => write!(f, "{}", value),
862             Variant::U16(value) => write!(f, "{}", value),
863             Variant::U32(value) => write!(f, "{}", value),
864             Variant::U64(value) => write!(f, "{}", value),
865             Variant::I8(value) => write!(f, "{}", value),
866             Variant::I16(value) => write!(f, "{}", value),
867             Variant::I32(value) => write!(f, "{}", value),
868             Variant::I64(value) => write!(f, "{}", value),
869         }
870     }
871 }
872 
873 impl<'a> TryFromCtx<'a, Endian> for Variant {
874     type Error = Error;
875 
try_from_ctx(this: &'a [u8], le: Endian) -> Result<(Self, usize)>876     fn try_from_ctx(this: &'a [u8], le: Endian) -> Result<(Self, usize)> {
877         let mut offset = 0;
878 
879         let variant = match this.gread_with(&mut offset, le)? {
880             value if value < constants::LF_NUMERIC => Variant::U16(value),
881             constants::LF_CHAR => Variant::U8(this.gread_with(&mut offset, le)?),
882             constants::LF_SHORT => Variant::I16(this.gread_with(&mut offset, le)?),
883             constants::LF_LONG => Variant::I32(this.gread_with(&mut offset, le)?),
884             constants::LF_QUADWORD => Variant::I64(this.gread_with(&mut offset, le)?),
885             constants::LF_USHORT => Variant::U16(this.gread_with(&mut offset, le)?),
886             constants::LF_ULONG => Variant::U32(this.gread_with(&mut offset, le)?),
887             constants::LF_UQUADWORD => Variant::U64(this.gread_with(&mut offset, le)?),
888             _ if cfg!(debug_assertions) => unreachable!(),
889             other => return Err(Error::UnexpectedNumericPrefix(other)),
890         };
891 
892         Ok((variant, offset))
893     }
894 }
895 
896 /// `RawString` refers to a `&[u8]` that physically resides somewhere inside a PDB data structure.
897 ///
898 /// A `RawString` may not be valid UTF-8.
899 #[derive(Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
900 pub struct RawString<'b>(&'b [u8]);
901 
902 impl fmt::Debug for RawString<'_> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result903     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
904         write!(f, "RawString({:?})", self.to_string())
905     }
906 }
907 
908 impl fmt::Display for RawString<'_> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result909     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
910         write!(f, "{}", self.to_string())
911     }
912 }
913 
914 impl<'b> RawString<'b> {
915     /// Return the raw bytes of this string, as found in the PDB file.
916     #[inline]
as_bytes(&self) -> &'b [u8]917     pub fn as_bytes(&self) -> &'b [u8] {
918         self.0
919     }
920 
921     /// Return the length of this string in bytes.
922     #[inline]
len(&self) -> usize923     pub fn len(&self) -> usize {
924         self.0.len()
925     }
926 
927     /// Returns a boolean indicating if this string is empty.
928     #[inline]
is_empty(&self) -> bool929     pub fn is_empty(&self) -> bool {
930         self.0.len() == 0
931     }
932 
933     /// Returns a UTF-8 `String`, substituting in replacement characters as needed.
934     ///
935     /// This uses [`String::from_utf8_lossy`] and thus avoids copying in cases where the original
936     /// string was valid UTF-8. This is the expected case for strings that appear in PDB files,
937     /// since they are almost always composed of printable 7-bit ASCII characters.
938     #[inline]
to_string(&self) -> Cow<'b, str>939     pub fn to_string(&self) -> Cow<'b, str> {
940         String::from_utf8_lossy(self.0)
941     }
942 }
943 
944 impl<'b> From<RawString<'b>> for &'b [u8] {
from(str: RawString<'b>) -> Self945     fn from(str: RawString<'b>) -> Self {
946         str.as_bytes()
947     }
948 }
949 
950 impl<'b> From<&'b str> for RawString<'b> {
from(buf: &'b str) -> Self951     fn from(buf: &'b str) -> Self {
952         RawString(buf.as_bytes())
953     }
954 }
955 
956 impl<'b> From<&'b [u8]> for RawString<'b> {
from(buf: &'b [u8]) -> Self957     fn from(buf: &'b [u8]) -> Self {
958         RawString(buf)
959     }
960 }
961 
962 /// Cast a binary slice to a slice of types.
963 ///
964 /// This function performs a cast of a binary slice to a slice of some type, returning `Some` if the
965 /// following two conditions are met:
966 ///
967 ///  1. The size of the slize must be a multiple of the type's size.
968 ///  2. The slice must be aligned to the alignment of the type.
969 ///
970 /// Note that this function will not convert any endianness. The types must be capable of reading
971 /// endianness correclty in case data from other hosts is read.
cast_aligned<T>(data: &[u8]) -> Option<&[T]>972 pub(crate) fn cast_aligned<T>(data: &[u8]) -> Option<&[T]> {
973     let alignment = mem::align_of::<T>();
974     let size = mem::size_of::<T>();
975 
976     let ptr = data.as_ptr();
977     let bytes = data.len();
978 
979     match (bytes % size, ptr.align_offset(alignment)) {
980         (0, 0) => Some(unsafe { slice::from_raw_parts(ptr as *const T, bytes / size) }),
981         (_, _) => None,
982     }
983 }
984 
985 #[cfg(test)]
986 mod tests {
987     mod parse_buffer {
988         use crate::common::*;
989 
990         #[test]
test_parse_u8()991         fn test_parse_u8() {
992             let vec: Vec<u8> = vec![1, 2, 3, 4];
993             let mut buf = ParseBuffer::from(vec.as_slice());
994             assert_eq!(buf.pos(), 0);
995 
996             assert_eq!(buf.peek_u8().expect("peek"), 1);
997             assert_eq!(buf.peek_u8().expect("peek"), 1);
998             assert_eq!(buf.peek_u8().expect("peek"), 1);
999             let val = buf.parse_u8().unwrap();
1000             assert_eq!(buf.len(), 3);
1001             assert_eq!(buf.pos(), 1);
1002             assert_eq!(val, 1);
1003 
1004             assert_eq!(buf.peek_u8().expect("peek"), 2);
1005             let val = buf.parse_u8().unwrap();
1006             assert_eq!(buf.len(), 2);
1007             assert_eq!(buf.pos(), 2);
1008             assert_eq!(val, 2);
1009 
1010             assert_eq!(buf.peek_u8().expect("peek"), 3);
1011             let val = buf.parse_u8().unwrap();
1012             assert_eq!(buf.len(), 1);
1013             assert_eq!(buf.pos(), 3);
1014             assert_eq!(val, 3);
1015 
1016             assert_eq!(buf.peek_u8().expect("peek"), 4);
1017             let val = buf.parse_u8().unwrap();
1018             assert_eq!(buf.len(), 0);
1019             assert_eq!(buf.pos(), 4);
1020             assert_eq!(val, 4);
1021 
1022             match buf.parse_u8() {
1023                 Err(Error::UnexpectedEof) => (),
1024                 _ => panic!("expected EOF"),
1025             }
1026         }
1027 
1028         #[test]
test_parse_u16()1029         fn test_parse_u16() {
1030             let vec: Vec<u8> = vec![1, 2, 3];
1031             let mut buf = ParseBuffer::from(vec.as_slice());
1032 
1033             assert_eq!(buf.peek_u16().expect("peek"), 0x0201);
1034             assert_eq!(buf.peek_u16().expect("peek"), 0x0201);
1035 
1036             let val = buf.parse_u16().unwrap();
1037             assert_eq!(buf.len(), 1);
1038             assert_eq!(buf.pos(), 2);
1039             assert_eq!(val, 0x0201);
1040 
1041             match buf.parse_u16() {
1042                 Err(Error::UnexpectedEof) => (),
1043                 _ => panic!("expected EOF"),
1044             }
1045 
1046             buf.take(1).unwrap();
1047             match buf.parse_u16() {
1048                 Err(Error::UnexpectedEof) => (),
1049                 _ => panic!("expected EOF"),
1050             }
1051         }
1052 
1053         #[test]
test_parse_u32()1054         fn test_parse_u32() {
1055             let vec: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7];
1056             let mut buf = ParseBuffer::from(vec.as_slice());
1057 
1058             let val = buf.parse_u32().unwrap();
1059             assert_eq!(buf.len(), 3);
1060             assert_eq!(buf.pos(), 4);
1061             assert_eq!(val, 0x0403_0201);
1062 
1063             match buf.parse_u32() {
1064                 Err(Error::UnexpectedEof) => (),
1065                 _ => panic!("expected EOF"),
1066             }
1067 
1068             buf.take(1).unwrap();
1069             assert_eq!(buf.pos(), 5);
1070             match buf.parse_u32() {
1071                 Err(Error::UnexpectedEof) => (),
1072                 _ => panic!("expected EOF"),
1073             }
1074 
1075             buf.take(1).unwrap();
1076             assert_eq!(buf.pos(), 6);
1077             match buf.parse_u32() {
1078                 Err(Error::UnexpectedEof) => (),
1079                 _ => panic!("expected EOF"),
1080             }
1081 
1082             buf.take(1).unwrap();
1083             assert_eq!(buf.pos(), 7);
1084             match buf.parse_u32() {
1085                 Err(Error::UnexpectedEof) => (),
1086                 _ => panic!("expected EOF"),
1087             }
1088         }
1089 
1090         #[test]
test_parse_u64()1091         fn test_parse_u64() {
1092             let vec: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
1093             let mut buf = ParseBuffer::from(vec.as_slice());
1094 
1095             let val = buf.parse_u64().unwrap();
1096             assert_eq!(val, 0x0807_0605_0403_0201);
1097 
1098             match buf.parse_u64() {
1099                 Err(Error::UnexpectedEof) => (),
1100                 _ => panic!("expected EOF"),
1101             }
1102         }
1103 
1104         #[test]
test_parse_i32()1105         fn test_parse_i32() {
1106             let vec: Vec<u8> = vec![254, 255, 255, 255, 5, 6, 7];
1107             let mut buf = ParseBuffer::from(vec.as_slice());
1108 
1109             let val = buf.parse_i32().unwrap();
1110             assert_eq!(buf.len(), 3);
1111             assert_eq!(val, -2);
1112             assert_eq!(buf.pos(), 4);
1113 
1114             match buf.parse_u32() {
1115                 Err(Error::UnexpectedEof) => (),
1116                 _ => panic!("expected EOF"),
1117             }
1118 
1119             buf.take(1).unwrap();
1120             match buf.parse_u32() {
1121                 Err(Error::UnexpectedEof) => (),
1122                 _ => panic!("expected EOF"),
1123             }
1124 
1125             buf.take(1).unwrap();
1126             match buf.parse_u32() {
1127                 Err(Error::UnexpectedEof) => (),
1128                 _ => panic!("expected EOF"),
1129             }
1130 
1131             buf.take(1).unwrap();
1132             match buf.parse_u32() {
1133                 Err(Error::UnexpectedEof) => (),
1134                 _ => panic!("expected EOF"),
1135             }
1136         }
1137 
1138         #[test]
test_parse_cstring()1139         fn test_parse_cstring() {
1140             let mut buf = ParseBuffer::from(&b"hello\x00world\x00\x00\x01"[..]);
1141 
1142             let val = buf.parse_cstring().unwrap();
1143             assert_eq!(buf.len(), 8);
1144             assert_eq!(buf.pos(), 6);
1145             assert_eq!(val, RawString::from(&b"hello"[..]));
1146 
1147             let val = buf.parse_cstring().unwrap();
1148             assert_eq!(buf.len(), 2);
1149             assert_eq!(buf.pos(), 12);
1150             assert_eq!(val, RawString::from(&b"world"[..]));
1151 
1152             let val = buf.parse_cstring().unwrap();
1153             assert_eq!(buf.len(), 1);
1154             assert_eq!(buf.pos(), 13);
1155             assert_eq!(val, RawString::from(&b""[..]));
1156 
1157             match buf.parse_cstring() {
1158                 Err(Error::UnexpectedEof) => (),
1159                 _ => panic!("expected EOF"),
1160             }
1161         }
1162 
1163         #[test]
test_parse_u8_pascal_string()1164         fn test_parse_u8_pascal_string() {
1165             let mut buf = ParseBuffer::from(&b"\x05hello\x05world\x00\x01"[..]);
1166 
1167             let val = buf.parse_u8_pascal_string().unwrap();
1168             assert_eq!(buf.len(), 8);
1169             assert_eq!(buf.pos(), 6);
1170             assert_eq!(val, RawString::from(&b"hello"[..]));
1171 
1172             let val = buf.parse_u8_pascal_string().unwrap();
1173             assert_eq!(buf.len(), 2);
1174             assert_eq!(buf.pos(), 12);
1175             assert_eq!(val, RawString::from(&b"world"[..]));
1176 
1177             let val = buf.parse_u8_pascal_string().unwrap();
1178             assert_eq!(buf.len(), 1);
1179             assert_eq!(buf.pos(), 13);
1180             assert_eq!(val, RawString::from(&b""[..]));
1181 
1182             match buf.parse_u8_pascal_string() {
1183                 Err(Error::UnexpectedEof) => (),
1184                 _ => panic!("expected EOF"),
1185             }
1186         }
1187 
1188         #[test]
test_parse_buffer_align()1189         fn test_parse_buffer_align() {
1190             let mut buf = ParseBuffer::from(&b"1234"[..]);
1191             buf.take(1).unwrap();
1192             assert!(buf.align(4).is_ok());
1193             assert_eq!(buf.pos(), 4);
1194             assert_eq!(buf.len(), 0);
1195 
1196             let mut buf = ParseBuffer::from(&b"1234"[..]);
1197             buf.take(3).unwrap();
1198             assert!(buf.align(4).is_ok());
1199             assert_eq!(buf.pos(), 4);
1200             assert_eq!(buf.len(), 0);
1201 
1202             let mut buf = ParseBuffer::from(&b"12345"[..]);
1203             buf.take(3).unwrap();
1204             assert!(buf.align(4).is_ok());
1205             assert_eq!(buf.pos(), 4);
1206             assert_eq!(buf.len(), 1);
1207 
1208             let mut buf = ParseBuffer::from(&b"123"[..]);
1209             buf.take(3).unwrap();
1210             assert!(buf.align(4).is_err());
1211         }
1212 
1213         #[test]
test_seek()1214         fn test_seek() {
1215             let mut buf = ParseBuffer::from(&b"hello"[..]);
1216             buf.seek(5);
1217             assert_eq!(buf.pos(), 5);
1218             buf.seek(2);
1219             assert_eq!(buf.pos(), 2);
1220             buf.seek(10);
1221             assert_eq!(buf.pos(), 5);
1222         }
1223     }
1224 
1225     mod newtypes {
1226         use crate::common::*;
1227 
1228         // These tests use SymbolIndex as a proxy for all other types.
1229 
1230         #[test]
test_format_newtype()1231         fn test_format_newtype() {
1232             let val = SymbolIndex(0x42);
1233             assert_eq!(format!("{}", val), "0x42");
1234         }
1235 
1236         #[test]
test_debug_newtype()1237         fn test_debug_newtype() {
1238             let val = SymbolIndex(0x42);
1239             assert_eq!(format!("{:?}", val), "SymbolIndex(0x42)");
1240         }
1241 
1242         #[test]
test_pread()1243         fn test_pread() {
1244             let mut buf = ParseBuffer::from(&[0x42, 0, 0, 0][..]);
1245             let val = buf.parse::<SymbolIndex>().expect("parse");
1246             assert_eq!(val, SymbolIndex(0x42));
1247             assert!(buf.is_empty());
1248         }
1249     }
1250 
1251     mod cast_aligned {
1252         use crate::common::cast_aligned;
1253         use std::slice;
1254 
1255         #[test]
test_cast_aligned()1256         fn test_cast_aligned() {
1257             let data: &[u32] = &[1, 2, 3];
1258 
1259             let ptr = data.as_ptr() as *const u8;
1260             let bin: &[u8] = unsafe { slice::from_raw_parts(ptr, 12) };
1261 
1262             assert_eq!(cast_aligned(bin), Some(data));
1263         }
1264 
1265         #[test]
test_cast_empty()1266         fn test_cast_empty() {
1267             let data: &[u32] = &[];
1268 
1269             let ptr = data.as_ptr() as *const u8;
1270             let bin: &[u8] = unsafe { slice::from_raw_parts(ptr, 0) };
1271 
1272             assert_eq!(cast_aligned(bin), Some(data));
1273         }
1274 
1275         #[test]
test_cast_unaligned()1276         fn test_cast_unaligned() {
1277             let data: &[u32] = &[1, 2, 3];
1278 
1279             let ptr = data.as_ptr() as *const u8;
1280             let bin: &[u8] = unsafe { slice::from_raw_parts(ptr.offset(2), 8) };
1281 
1282             assert_eq!(cast_aligned::<u32>(bin), None);
1283         }
1284 
1285         #[test]
test_cast_wrong_size()1286         fn test_cast_wrong_size() {
1287             let data: &[u32] = &[1, 2, 3];
1288 
1289             let ptr = data.as_ptr() as *const u8;
1290             let bin: &[u8] = unsafe { slice::from_raw_parts(ptr, 11) };
1291 
1292             assert_eq!(cast_aligned::<u32>(bin), None);
1293         }
1294     }
1295 }
1296