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