ms_pdb/dbi/
section_map.rs

1//! DBI Section Map Substream
2#![allow(missing_docs)]
3
4use super::*;
5use bitflags::bitflags;
6use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned};
7
8#[derive(IntoBytes, KnownLayout, Immutable, FromBytes, Unaligned)]
9#[repr(C)]
10pub struct SectionMapHeader {
11    /// Total number of segment descriptors
12    pub num_segments: U16<LE>,
13    /// Number of logical segment descriptors
14    pub num_logical_segments: U16<LE>,
15}
16
17#[derive(IntoBytes, KnownLayout, Immutable, FromBytes, Unaligned)]
18#[repr(C)]
19pub struct SectionMapEntry {
20    /// Descriptor flags bit field. See `SectionMapEntryFlags`.
21    pub flags: U16<LE>,
22    /// The logical overlay number
23    pub overlay: U16<LE>,
24    /// Group index into the descriptor array
25    pub group: U16<LE>,
26    /// Logical segment index, interpreted via flags
27    pub frame: U16<LE>,
28    /// Byte index of segment / group name in string table, or 0xFFFF.
29    pub section_name: U16<LE>,
30    /// Byte index of class in string table, or 0xFFFF.
31    pub class_name: U16<LE>,
32    /// Byte offset of the logical segment within physical segment.
33    /// If group is set in flags, this is the offset of the group.
34    pub offset: U32<LE>,
35    /// Byte count of the segment or group.
36    pub section_length: U32<LE>,
37}
38
39bitflags! {
40    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
41    pub struct SectionMapEntryFlags: u16 {
42        /// Segment is readable.
43        const READ = 1 << 0;
44        /// Segment is writable.
45        const WRITE = 1 << 1;
46        /// Segment is executable.
47        const EXECUTE = 1 << 2;
48        /// Descriptor describes a 32-bit linear address.
49        const ADDRESS_IS32_BIT = 1 << 3;
50        /// Frame represents a selector.
51        const IS_SELECTOR = 1 << 8;
52        /// Frame represents an absolute address.
53        const IS_ABSOLUTE_ADDRESS = 1 << 9;
54        /// If set, descriptor represents a group. (obsolete)
55        const IS_GROUP = 1 << 10;
56    }
57}
58
59pub struct SectionMap<'a> {
60    pub header: SectionMapHeader,
61    pub entries: &'a [SectionMapEntry],
62}
63
64impl<'a> SectionMap<'a> {
65    pub fn parse(bytes: &'a [u8]) -> anyhow::Result<Self> {
66        let mut p = Parser::new(bytes);
67        if p.is_empty() {
68            return Ok(Self {
69                entries: &[],
70                header: SectionMapHeader {
71                    num_logical_segments: U16::ZERO,
72                    num_segments: U16::ZERO,
73                },
74            });
75        }
76
77        let header: SectionMapHeader = p.copy()?;
78
79        let Ok(entries) = <[SectionMapEntry]>::ref_from_bytes(p.take_rest()) else {
80            bail!("Section map has invalid length (is not a multiple of SectionMapEntry size). Length (including 4-byte header): 0x{:x}", bytes.len());
81        };
82        Ok(Self { header, entries })
83    }
84}