mozpdb/tpi/
header.rs

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
8use common::*;
9
10// OFFCB:
11#[derive(Debug,Copy,Clone,Eq,PartialEq)]
12pub 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)]
20pub struct Header {
21    pub version: u32,
22    pub header_size: u32,
23    pub minimum_type_index: TypeIndex,
24    pub maximum_type_index: TypeIndex,
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
35impl Header {
36    pub fn parse(buf: &mut ParseBuffer) -> Result<Header> {
37        assert!(buf.pos() == 0);
38
39        let h = Header{
40            version: buf.parse_u32()?,
41            header_size: buf.parse_u32()?,
42            minimum_type_index: buf.parse_u32()?,
43            maximum_type_index: buf.parse_u32()?,
44            gprec_size: buf.parse_u32()?,
45            tpi_hash_stream: buf.parse_u16()?,
46            tpi_hash_pad_stream: buf.parse_u16()?,
47            hash_key_size: buf.parse_u32()?,
48            hash_bucket_size: buf.parse_u32()?,
49            hash_values: Slice{
50                offset: buf.parse_i32()?,
51                size: buf.parse_u32()?,
52            },
53            ti_off: Slice{
54                offset: buf.parse_i32()?,
55                size: buf.parse_u32()?,
56            },
57            hash_adj: Slice{
58                offset: buf.parse_i32()?,
59                size: buf.parse_u32()?,
60            },
61        };
62
63        // we read 56 bytes
64        // make sure that's okay
65        let bytes_read = buf.pos() as u32;
66        if h.header_size < bytes_read {
67            return Err(Error::InvalidTypeInformationHeader("header size is impossibly small"));
68        } else if h.header_size > 1024 {
69            return Err(Error::InvalidTypeInformationHeader("header size is unreasonably large"));
70        }
71
72        // consume anything else the header says belongs to the header
73        buf.take((h.header_size - bytes_read) as usize)?;
74
75        // do some final validations
76        if h.minimum_type_index < 4096 {
77            return Err(Error::InvalidTypeInformationHeader("minimum type index is < 4096"));
78        }
79        if h.maximum_type_index < h.minimum_type_index {
80            return Err(Error::InvalidTypeInformationHeader("maximum type index is < minimum type index"));
81        }
82
83        // success
84        Ok(h)
85    }
86}