1 // Copyright 2018 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 //! Definitions for PE headers contained in PDBs.
9 
10 // PDBs contain PE section headers in one or two streams. `pdb::pe` is responsible for parsing them.
11 
12 use std::fmt;
13 
14 use crate::common::*;
15 
16 /// A PE `IMAGE_SECTION_HEADER`, as described in [the Microsoft documentation](https://msdn.microsoft.com/en-us/library/windows/desktop/ms680341(v=vs.85).aspx).
17 #[derive(Copy, Clone, PartialEq, Eq, Default)]
18 pub struct ImageSectionHeader {
19     /// An 8-byte, null-padded UTF-8 string. There is no terminating null character if the string is
20     /// exactly eight characters long. For longer names, this member contains a forward slash (`/`)
21     /// followed by an ASCII representation of a decimal number that is an offset into the string
22     /// table. Executable images do not use a string table and do not support section names longer
23     /// than eight characters.
24     pub name: [u8; 8],
25 
26     /// The file address.
27     pub physical_address: u32,
28 
29     /// The address of the first byte of the section when loaded into memory, relative to the image
30     /// base. For object files, this is the address of the first byte before relocation is applied.
31     pub virtual_address: u32,
32 
33     /// The size of the initialized data on disk, in bytes. This value must be a multiple of the
34     /// `FileAlignment` member of the `IMAGE_OPTIONAL_HEADER` structure. If this value is less than
35     /// the `VirtualSize` member, the remainder of the section is filled with zeroes. If the section
36     /// contains only uninitialized data, the member is zero.
37     pub size_of_raw_data: u32,
38 
39     /// A file pointer to the first page within the COFF file. This value must be a multiple of the
40     /// `FileAlignment` member of the `IMAGE_OPTIONAL_HEADER` structure. If a section contains only
41     /// uninitialized data, set this member is zero.
42     pub pointer_to_raw_data: u32,
43 
44     /// A file pointer to the beginning of the relocation entries for the section. If there are no
45     /// relocations, this value is zero.
46     pub pointer_to_relocations: u32,
47 
48     /// A file pointer to the beginning of the line-number entries for the section. If there are no
49     /// COFF line numbers, this value is zero.
50     pub pointer_to_line_numbers: u32,
51 
52     /// The number of relocation entries for the section. This value is zero for executable images.
53     pub number_of_relocations: u16,
54 
55     /// The number of line-number entries for the section.
56     pub number_of_line_numbers: u16,
57 
58     /// The characteristics of the image.
59     pub characteristics: u32,
60 }
61 
62 impl ImageSectionHeader {
parse(parse_buffer: &mut ParseBuffer<'_>) -> Result<Self>63     pub(crate) fn parse(parse_buffer: &mut ParseBuffer<'_>) -> Result<Self> {
64         let name_bytes = parse_buffer.take(8)?;
65 
66         Ok(ImageSectionHeader {
67             name: [
68                 name_bytes[0],
69                 name_bytes[1],
70                 name_bytes[2],
71                 name_bytes[3],
72                 name_bytes[4],
73                 name_bytes[5],
74                 name_bytes[6],
75                 name_bytes[7],
76             ],
77             physical_address: parse_buffer.parse_u32()?,
78             virtual_address: parse_buffer.parse_u32()?,
79             size_of_raw_data: parse_buffer.parse_u32()?,
80             pointer_to_raw_data: parse_buffer.parse_u32()?,
81             pointer_to_relocations: parse_buffer.parse_u32()?,
82             pointer_to_line_numbers: parse_buffer.parse_u32()?,
83             number_of_relocations: parse_buffer.parse_u16()?,
84             number_of_line_numbers: parse_buffer.parse_u16()?,
85             characteristics: parse_buffer.parse_u32()?,
86         })
87     }
88 
89     /// Returns the name of the section.
name(&self) -> &str90     pub fn name(&self) -> &str {
91         let end = self
92             .name
93             .iter()
94             .position(|ch| *ch == 0)
95             .unwrap_or_else(|| self.name.len());
96 
97         // The spec guarantees that the name is a proper UTF-8 string.
98         // TODO: Look up long names from the string table.
99         std::str::from_utf8(&self.name[0..end]).unwrap_or("")
100     }
101 }
102 
103 impl fmt::Debug for ImageSectionHeader {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result104     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105         f.debug_struct("ImageSectionHeader")
106             .field("name()", &self.name().to_string())
107             .field(
108                 "physical_address",
109                 &format_args!("{:#x}", self.physical_address),
110             )
111             .field(
112                 "virtual_address",
113                 &format_args!("{:#x}", self.virtual_address),
114             )
115             .field("size_of_raw_data", &self.size_of_raw_data)
116             .field(
117                 "pointer_to_raw_data",
118                 &format_args!("{:#x}", self.pointer_to_raw_data),
119             )
120             .field(
121                 "pointer_to_relocations",
122                 &format_args!("{:#x}", self.pointer_to_relocations),
123             )
124             .field(
125                 "pointer_to_line_numbers",
126                 &format_args!("{:#x}", self.pointer_to_line_numbers),
127             )
128             .field("number_of_relocations", &self.number_of_relocations)
129             .field("number_of_line_numbers", &self.number_of_line_numbers)
130             .field(
131                 "characteristics",
132                 &format_args!("{:#x}", self.characteristics),
133             )
134             .finish()
135     }
136 }
137 
138 #[cfg(test)]
139 mod tests {
140     use super::*;
141 
142     #[test]
image_section_header()143     fn image_section_header() {
144         let bytes: Vec<u8> = vec![
145             0x2E, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x48, 0x35, 0x09, 0x00, 0x00, 0xD0,
146             0x1E, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0xA2, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00,
147             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0xC8,
148         ];
149 
150         let mut parse_buffer = ParseBuffer::from(bytes.as_slice());
151 
152         let ish = ImageSectionHeader::parse(&mut parse_buffer).expect("parse");
153         assert_eq!(&ish.name, b".data\0\0\0");
154         assert_eq!(ish.name(), ".data");
155         assert_eq!(ish.physical_address, 0x93548);
156         assert_eq!(ish.virtual_address, 0x001e_d000);
157         assert_eq!(ish.size_of_raw_data, 0xfe00);
158         assert_eq!(ish.pointer_to_raw_data, 0x001e_a200);
159         assert_eq!(ish.pointer_to_relocations, 0);
160         assert_eq!(ish.pointer_to_line_numbers, 0);
161         assert_eq!(ish.number_of_relocations, 0);
162         assert_eq!(ish.number_of_line_numbers, 0);
163         assert_eq!(ish.characteristics, 0xc800_0040);
164     }
165 }
166