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 crate::common::*; 9 10 // OFFCB: 11 #[derive(Debug, Copy, Clone, Eq, PartialEq)] 12 pub struct Slice { 13 pub offset: i32, // technically a "long", but... 32 bits for life? 14 pub size: u32, 15 } 16 17 // HDR: 18 // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/PDB/dbi/tpi.h#L45 19 #[derive(Debug, Copy, Clone, Eq, PartialEq)] 20 pub struct Header { 21 pub version: u32, 22 pub header_size: u32, 23 pub minimum_index: u32, 24 pub maximum_index: u32, 25 pub gprec_size: u32, 26 pub tpi_hash_stream: u16, 27 pub tpi_hash_pad_stream: u16, 28 pub hash_key_size: u32, 29 pub hash_bucket_size: u32, 30 pub hash_values: Slice, 31 pub ti_off: Slice, 32 pub hash_adj: Slice, // "offcb of hash head list, maps (hashval,ti), where ti is the head of the hashval chain." 33 } 34 35 impl Header { empty() -> Self36 pub(crate) fn empty() -> Self { 37 let empty_slice = Slice { offset: 0, size: 0 }; 38 39 Header { 40 version: 0, 41 header_size: 0, 42 minimum_index: 0, 43 maximum_index: 0, 44 gprec_size: 0, 45 tpi_hash_stream: 0, 46 tpi_hash_pad_stream: 0, 47 hash_key_size: 0, 48 hash_bucket_size: 0, 49 hash_values: empty_slice, 50 ti_off: empty_slice, 51 hash_adj: empty_slice, 52 } 53 } 54 parse(buf: &mut ParseBuffer<'_>) -> Result<Self>55 pub(crate) fn parse(buf: &mut ParseBuffer<'_>) -> Result<Self> { 56 debug_assert!(buf.pos() == 0); 57 58 if buf.is_empty() { 59 // Special case when the buffer is completely empty. This indicates a missing TPI or IPI 60 // stream. In this case, `ItemInformation` acts like an empty shell that never resolves 61 // any types. 62 return Ok(Self::empty()); 63 } 64 65 let header = Header { 66 version: buf.parse()?, 67 header_size: buf.parse()?, 68 minimum_index: buf.parse()?, 69 maximum_index: buf.parse()?, 70 gprec_size: buf.parse()?, 71 tpi_hash_stream: buf.parse()?, 72 tpi_hash_pad_stream: buf.parse()?, 73 hash_key_size: buf.parse()?, 74 hash_bucket_size: buf.parse()?, 75 hash_values: Slice { 76 offset: buf.parse()?, 77 size: buf.parse()?, 78 }, 79 ti_off: Slice { 80 offset: buf.parse()?, 81 size: buf.parse()?, 82 }, 83 hash_adj: Slice { 84 offset: buf.parse()?, 85 size: buf.parse()?, 86 }, 87 }; 88 89 // we read 56 bytes 90 // make sure that's okay 91 let bytes_read = buf.pos() as u32; 92 if header.header_size < bytes_read { 93 return Err(Error::InvalidTypeInformationHeader( 94 "header size is impossibly small", 95 )); 96 } else if header.header_size > 1024 { 97 return Err(Error::InvalidTypeInformationHeader( 98 "header size is unreasonably large", 99 )); 100 } 101 102 // consume anything else the header says belongs to the header 103 buf.take((header.header_size - bytes_read) as usize)?; 104 105 // do some final validations 106 if header.minimum_index < 4096 { 107 return Err(Error::InvalidTypeInformationHeader( 108 "minimum type index is < 4096", 109 )); 110 } 111 if header.maximum_index < header.minimum_index { 112 return Err(Error::InvalidTypeInformationHeader( 113 "maximum type index is < minimum type index", 114 )); 115 } 116 117 // success 118 Ok(header) 119 } 120 } 121