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