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