From 309c17349c19b26b4c2d53582f29ff8bd7e5a315 Mon Sep 17 00:00:00 2001 From: = Date: Mon, 29 Jan 2024 17:26:01 +0100 Subject: [PATCH 1/2] Add support for small format --- src/msf/big.rs | 262 +++++++++++++++++++++++++++++++++++++++++++ src/msf/mod.rs | 277 +--------------------------------------------- src/msf/small.rs | 204 ++++++++++++++++++++++++++++++++++ src/symbol/mod.rs | 3 + 4 files changed, 474 insertions(+), 272 deletions(-) create mode 100644 src/msf/big.rs create mode 100644 src/msf/small.rs diff --git a/src/msf/big.rs b/src/msf/big.rs new file mode 100644 index 0000000..40ea2e5 --- /dev/null +++ b/src/msf/big.rs @@ -0,0 +1,262 @@ +use super::*; + +pub const MAGIC: &[u8; 32] = b"Microsoft C/C++ MSF 7.00\r\n\x1a\x44\x53\x00\x00\x00"; + +/// The PDB header as stored on disk. +/// +/// See the Microsoft code for reference: +#[repr(C)] +#[derive(Debug, Copy, Clone)] +struct RawHeader { + magic: [u8; 32], + page_size: u32, + free_page_map: u32, + pages_used: u32, + directory_size: u32, + _reserved: u32, +} + +impl<'t> TryFromCtx<'t, Endian> for RawHeader { + type Error = scroll::Error; + + fn try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)> { + let mut offset = 0; + let data = Self { + magic: { + let mut tmp = [0; 32]; + this.gread_inout_with(&mut offset, &mut tmp, le)?; + tmp + }, + page_size: this.gread_with(&mut offset, le)?, + free_page_map: this.gread_with(&mut offset, le)?, + pages_used: this.gread_with(&mut offset, le)?, + directory_size: this.gread_with(&mut offset, le)?, + _reserved: this.gread_with(&mut offset, le)?, + }; + Ok((data, offset)) + } +} + +#[derive(Debug)] +pub struct BigMSF<'s, S> { + header: Header, + source: S, + stream_table: StreamTable<'s>, +} + +impl<'s, S: Source<'s>> BigMSF<'s, S> { + pub fn new(source: S, header_view: Box>) -> Result> { + let mut buf = ParseBuffer::from(header_view.as_slice()); + let header: RawHeader = buf.parse()?; + + if &header.magic != MAGIC { + return Err(Error::UnrecognizedFileFormat); + } + + if !header.page_size.is_power_of_two() + || header.page_size < 0x100 + || header.page_size > (128 * 0x10000) + { + return Err(Error::InvalidPageSize(header.page_size)); + } + + let header_object = Header { + page_size: header.page_size as usize, + maximum_valid_page_number: header.pages_used, + }; + + // calculate how many pages are needed to store the stream table + let size_of_stream_table_in_pages = + header_object.pages_needed_to_store(header.directory_size as usize); + + // now: how many pages are needed to store the list of pages that store the stream table? + // each page entry is a u32, so multiply by four + let size_of_stream_table_page_list_in_pages = + header_object.pages_needed_to_store(size_of_stream_table_in_pages * 4); + + // read the list of stream table page list pages, which immediately follow the header + // yes, this is a stupid level of indirection + let mut stream_table_page_list_page_list = PageList::new(header_object.page_size); + for _ in 0..size_of_stream_table_page_list_in_pages { + let n = buf.parse_u32()?; + stream_table_page_list_page_list.push(header_object.validate_page_number(n)?); + } + + // truncate the stream table location location to the correct size + stream_table_page_list_page_list.truncate(size_of_stream_table_in_pages * 4); + + Ok(BigMSF { + header: header_object, + source, + stream_table: StreamTable::HeaderOnly { + size_in_bytes: header.directory_size as usize, + stream_table_location_location: stream_table_page_list_page_list, + }, + }) + } + + fn find_stream_table(&mut self) -> Result<()> { + let mut new_stream_table: Option> = None; + + if let StreamTable::HeaderOnly { + size_in_bytes, + ref stream_table_location_location, + } = self.stream_table + { + // the header indicated we need to read size_in_pages page numbers from the + // specified PageList. + + // ask to view the location location + let location_location = view(&mut self.source, stream_table_location_location)?; + + // build a PageList + let mut page_list = PageList::new(self.header.page_size); + let mut buf = ParseBuffer::from(location_location.as_slice()); + while !buf.is_empty() { + let n = buf.parse_u32()?; + page_list.push(self.header.validate_page_number(n)?); + } + + page_list.truncate(size_in_bytes); + + // remember what we learned + new_stream_table = Some(StreamTable::TableFound { + stream_table_location: page_list, + }); + } + + if let Some(st) = new_stream_table { + self.stream_table = st; + } + + Ok(()) + } + + fn make_stream_table_available(&mut self) -> Result<()> { + // do the initial read if we must + if let StreamTable::HeaderOnly { .. } = self.stream_table { + self.find_stream_table()?; + } + + // do we need to map the stream table itself? + let mut new_stream_table = None; + if let StreamTable::TableFound { + ref stream_table_location, + } = self.stream_table + { + // ask the source to view it + let stream_table_view = view(&mut self.source, stream_table_location)?; + new_stream_table = Some(StreamTable::Available { stream_table_view }); + } + + if let Some(st) = new_stream_table { + self.stream_table = st; + } + + // stream table is available + assert!(matches!(self.stream_table, StreamTable::Available { .. })); + + Ok(()) + } + + fn look_up_stream(&mut self, stream_number: u32) -> Result { + // ensure the stream table is available + self.make_stream_table_available()?; + + let header = self.header; + + // declare the things we're going to find + let bytes_in_stream: u32; + let page_list: PageList; + + if let StreamTable::Available { + ref stream_table_view, + } = self.stream_table + { + let stream_table_slice = stream_table_view.as_slice(); + let mut stream_table = ParseBuffer::from(stream_table_slice); + + // the stream table is structured as: + // stream_count + // 0..stream_count: size of stream in bytes (0xffffffff indicating "stream does not exist") + // stream 0: PageNumber + // stream 1: PageNumber, PageNumber + // stream 2: PageNumber, PageNumber, PageNumber, PageNumber, PageNumber + // stream 3: PageNumber, PageNumber, PageNumber, PageNumber + // (number of pages determined by number of bytes) + + let stream_count = stream_table.parse_u32()?; + + // check if we've already outworn our welcome + if stream_number >= stream_count { + return Err(Error::StreamNotFound(stream_number)); + } + + // we now have {stream_count} u32s describing the length of each stream + + // walk over the streams before the requested stream + // we need to pay attention to how big each one is, since their page numbers come + // before our page numbers in the stream table + let mut page_numbers_to_skip: usize = 0; + for _ in 0..stream_number { + let bytes = stream_table.parse_u32()?; + if bytes == u32::max_value() { + // stream is not present, ergo nothing to skip + } else { + page_numbers_to_skip += header.pages_needed_to_store(bytes as usize); + } + } + + // read our stream's size + bytes_in_stream = stream_table.parse_u32()?; + if bytes_in_stream == u32::max_value() { + return Err(Error::StreamNotFound(stream_number)); + } + let pages_in_stream = header.pages_needed_to_store(bytes_in_stream as usize); + + // skip the remaining streams' byte counts + let _ = stream_table.take((stream_count - stream_number - 1) as usize * 4)?; + + // skip the preceding streams' page numbers + let _ = stream_table.take((page_numbers_to_skip as usize) * 4)?; + + // we're now at the list of pages for our stream + // accumulate them into a PageList + let mut list = PageList::new(header.page_size); + for _ in 0..pages_in_stream { + let page_number = stream_table.parse_u32()?; + list.push(self.header.validate_page_number(page_number)?); + } + + // truncate to the size of the stream + list.truncate(bytes_in_stream as usize); + + page_list = list; + } else { + unreachable!(); + } + + // done! + Ok(page_list) + } +} + +impl<'s, S: Source<'s>> Msf<'s, S> for BigMSF<'s, S> { + fn get(&mut self, stream_number: u32, limit: Option) -> Result> { + // look up the stream + let mut page_list = self.look_up_stream(stream_number)?; + + // apply any limits we have + if let Some(limit) = limit { + page_list.truncate(limit); + } + + // now that we know where this stream lives, we can view it + let view = view(&mut self.source, &page_list)?; + + // pack it into a Stream + let stream = Stream { source_view: view }; + + Ok(stream) + } +} diff --git a/src/msf/mod.rs b/src/msf/mod.rs index e00ca44..0bbf402 100644 --- a/src/msf/mod.rs +++ b/src/msf/mod.rs @@ -72,275 +72,8 @@ fn view<'s>(source: &mut dyn Source<'s>, page_list: &PageList) -> Result - #[repr(C)] - #[derive(Debug, Copy, Clone)] - struct RawHeader { - magic: [u8; 32], - page_size: u32, - free_page_map: u32, - pages_used: u32, - directory_size: u32, - _reserved: u32, - } - - impl<'t> TryFromCtx<'t, Endian> for RawHeader { - type Error = scroll::Error; - - fn try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)> { - let mut offset = 0; - let data = Self { - magic: { - let mut tmp = [0; 32]; - this.gread_inout_with(&mut offset, &mut tmp, le)?; - tmp - }, - page_size: this.gread_with(&mut offset, le)?, - free_page_map: this.gread_with(&mut offset, le)?, - pages_used: this.gread_with(&mut offset, le)?, - directory_size: this.gread_with(&mut offset, le)?, - _reserved: this.gread_with(&mut offset, le)?, - }; - Ok((data, offset)) - } - } - - #[derive(Debug)] - pub struct BigMSF<'s, S> { - header: Header, - source: S, - stream_table: StreamTable<'s>, - } - - impl<'s, S: Source<'s>> BigMSF<'s, S> { - pub fn new(source: S, header_view: Box>) -> Result> { - let mut buf = ParseBuffer::from(header_view.as_slice()); - let header: RawHeader = buf.parse()?; - - if header.magic != MAGIC { - return Err(Error::UnrecognizedFileFormat); - } - - if header.page_size.count_ones() != 1 - || header.page_size < 0x100 - || header.page_size > (128 * 0x10000) - { - return Err(Error::InvalidPageSize(header.page_size)); - } - - let header_object = Header { - page_size: header.page_size as usize, - maximum_valid_page_number: header.pages_used, - }; - - // calculate how many pages are needed to store the stream table - let size_of_stream_table_in_pages = - header_object.pages_needed_to_store(header.directory_size as usize); - - // now: how many pages are needed to store the list of pages that store the stream table? - // each page entry is a u32, so multiply by four - let size_of_stream_table_page_list_in_pages = - header_object.pages_needed_to_store(size_of_stream_table_in_pages * 4); - - // read the list of stream table page list pages, which immediately follow the header - // yes, this is a stupid level of indirection - let mut stream_table_page_list_page_list = PageList::new(header_object.page_size); - for _ in 0..size_of_stream_table_page_list_in_pages { - let n = buf.parse_u32()?; - stream_table_page_list_page_list.push(header_object.validate_page_number(n)?); - } - - // truncate the stream table location location to the correct size - stream_table_page_list_page_list.truncate(size_of_stream_table_in_pages * 4); - - Ok(BigMSF { - header: header_object, - source, - stream_table: StreamTable::HeaderOnly { - size_in_bytes: header.directory_size as usize, - stream_table_location_location: stream_table_page_list_page_list, - }, - }) - } - - fn find_stream_table(&mut self) -> Result<()> { - let mut new_stream_table: Option> = None; - - if let StreamTable::HeaderOnly { - size_in_bytes, - ref stream_table_location_location, - } = self.stream_table - { - // the header indicated we need to read size_in_pages page numbers from the - // specified PageList. - - // ask to view the location location - let location_location = view(&mut self.source, stream_table_location_location)?; - - // build a PageList - let mut page_list = PageList::new(self.header.page_size); - let mut buf = ParseBuffer::from(location_location.as_slice()); - while !buf.is_empty() { - let n = buf.parse_u32()?; - page_list.push(self.header.validate_page_number(n)?); - } - - page_list.truncate(size_in_bytes); - - // remember what we learned - new_stream_table = Some(StreamTable::TableFound { - stream_table_location: page_list, - }); - } - - if let Some(st) = new_stream_table { - self.stream_table = st; - } - - Ok(()) - } - - fn make_stream_table_available(&mut self) -> Result<()> { - // do the initial read if we must - if let StreamTable::HeaderOnly { .. } = self.stream_table { - self.find_stream_table()?; - } - - // do we need to map the stream table itself? - let mut new_stream_table = None; - if let StreamTable::TableFound { - ref stream_table_location, - } = self.stream_table - { - // ask the source to view it - let stream_table_view = view(&mut self.source, stream_table_location)?; - new_stream_table = Some(StreamTable::Available { stream_table_view }); - } - - if let Some(st) = new_stream_table { - self.stream_table = st; - } - - // stream table is available - assert!(matches!(self.stream_table, StreamTable::Available { .. })); - - Ok(()) - } - - fn look_up_stream(&mut self, stream_number: u32) -> Result { - // ensure the stream table is available - self.make_stream_table_available()?; - - let header = self.header; - - // declare the things we're going to find - let bytes_in_stream: u32; - let page_list: PageList; - - if let StreamTable::Available { - ref stream_table_view, - } = self.stream_table - { - let stream_table_slice = stream_table_view.as_slice(); - let mut stream_table = ParseBuffer::from(stream_table_slice); - - // the stream table is structured as: - // stream_count - // 0..stream_count: size of stream in bytes (0xffffffff indicating "stream does not exist") - // stream 0: PageNumber - // stream 1: PageNumber, PageNumber - // stream 2: PageNumber, PageNumber, PageNumber, PageNumber, PageNumber - // stream 3: PageNumber, PageNumber, PageNumber, PageNumber - // (number of pages determined by number of bytes) - - let stream_count = stream_table.parse_u32()?; - - // check if we've already outworn our welcome - if stream_number >= stream_count { - return Err(Error::StreamNotFound(stream_number)); - } - - // we now have {stream_count} u32s describing the length of each stream - - // walk over the streams before the requested stream - // we need to pay attention to how big each one is, since their page numbers come - // before our page numbers in the stream table - let mut page_numbers_to_skip: usize = 0; - for _ in 0..stream_number { - let bytes = stream_table.parse_u32()?; - if bytes == u32::max_value() { - // stream is not present, ergo nothing to skip - } else { - page_numbers_to_skip += header.pages_needed_to_store(bytes as usize); - } - } - - // read our stream's size - bytes_in_stream = stream_table.parse_u32()?; - if bytes_in_stream == u32::max_value() { - return Err(Error::StreamNotFound(stream_number)); - } - let pages_in_stream = header.pages_needed_to_store(bytes_in_stream as usize); - - // skip the remaining streams' byte counts - let _ = stream_table.take((stream_count - stream_number - 1) as usize * 4)?; - - // skip the preceding streams' page numbers - let _ = stream_table.take((page_numbers_to_skip as usize) * 4)?; - - // we're now at the list of pages for our stream - // accumulate them into a PageList - let mut list = PageList::new(header.page_size); - for _ in 0..pages_in_stream { - let page_number = stream_table.parse_u32()?; - list.push(self.header.validate_page_number(page_number)?); - } - - // truncate to the size of the stream - list.truncate(bytes_in_stream as usize); - - page_list = list; - } else { - unreachable!(); - } - - // done! - Ok(page_list) - } - } - - impl<'s, S: Source<'s>> Msf<'s, S> for BigMSF<'s, S> { - fn get(&mut self, stream_number: u32, limit: Option) -> Result> { - // look up the stream - let mut page_list = self.look_up_stream(stream_number)?; - - // apply any limits we have - if let Some(limit) = limit { - page_list.truncate(limit); - } - - // now that we know where this stream lives, we can view it - let view = view(&mut self.source, &page_list)?; - - // pack it into a Stream - let stream = Stream { source_view: view }; - - Ok(stream) - } - } -} - -mod small { - pub const MAGIC: &[u8] = b"Microsoft C/C++ program database 2.00\r\n\x1a\x4a\x47"; - // TODO: implement SmallMSF -} +mod big; +mod small; /// Represents a single Stream within the multi-stream file. #[derive(Debug)] @@ -376,7 +109,7 @@ pub trait Msf<'s, S>: fmt::Debug { fn get(&mut self, stream_number: u32, limit: Option) -> Result>; } -fn header_matches(actual: &[u8], expected: &[u8]) -> bool { +fn header_matches(actual: &[u8], expected: &[u8; N]) -> bool { actual.len() >= expected.len() && &actual[0..expected.len()] == expected } @@ -406,8 +139,8 @@ pub fn open_msf<'s, S: Source<'s> + 's>(mut source: S) -> Result TryFromCtx<'t, Endian> for RawHeader { + type Error = scroll::Error; + + fn try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)> { + let mut offset = 0; + let data = Self { + magic: { + let mut tmp = [0; 44]; + this.gread_inout_with(&mut offset, &mut tmp, le)?; + tmp + }, + page_size: this.gread_with(&mut offset, le)?, + start_page: this.gread_with(&mut offset, le)?, + pages_used: this.gread_with(&mut offset, le)?, + directory_size: this.gread_with(&mut offset, le)?, + _reserved: this.gread_with(&mut offset, le)?, + }; + Ok((data, offset)) + } +} + +#[derive(Debug)] +pub struct SmallMSF<'s, S> { + header: Header, + source: S, + stream_table: StreamTable<'s>, +} + +impl<'s, S: Source<'s>> SmallMSF<'s, S> { + fn read_page_list(hdr: &Header, size: usize, buf: &mut ParseBuffer) -> Result { + let pages = hdr.pages_needed_to_store(size); + + let mut page_list = PageList::new(hdr.page_size); + for _ in 0..pages { + let n = buf.parse_u16()?; + page_list.push(hdr.validate_page_number(n as u32)?); + } + page_list.truncate(size); + + Ok(page_list) + } + + pub fn new(source: S, header_view: Box>) -> Result> { + let mut buf = ParseBuffer::from(header_view.as_slice()); + let header: RawHeader = buf.parse()?; + + if &header.magic != MAGIC { + return Err(Error::UnrecognizedFileFormat); + } + + if !header.page_size.is_power_of_two() + || header.page_size < 0x100 + || header.page_size > (128 * 0x10000) + { + return Err(Error::InvalidPageSize(header.page_size)); + } + + let header_object = Header { + page_size: header.page_size as usize, + maximum_valid_page_number: header.pages_used as u32, + }; + + let stream_table_location = + Self::read_page_list(&header_object, header.directory_size as usize, &mut buf)?; + + Ok(Self { + header: header_object, + source, + stream_table: StreamTable::TableFound { + stream_table_location, + }, + }) + } + + fn make_stream_table_available(&mut self) -> Result<()> { + // do we need to map the stream table itself? + let mut new_stream_table = None; + if let StreamTable::TableFound { + ref stream_table_location, + } = self.stream_table + { + // ask the source to view it + let stream_table_view = view(&mut self.source, stream_table_location)?; + new_stream_table = Some(StreamTable::Available { stream_table_view }); + } + + if let Some(st) = new_stream_table { + self.stream_table = st; + } + + // stream table is available + assert!(matches!(self.stream_table, StreamTable::Available { .. })); + + Ok(()) + } + + fn look_up_stream(&mut self, stream_number: u32) -> Result { + // ensure the stream table is available + self.make_stream_table_available()?; + + let header = self.header; + + // declare the things we're going to find + let bytes_in_stream: u32; + let page_list: PageList; + + if let StreamTable::Available { + ref stream_table_view, + } = self.stream_table + { + let stream_table_slice = stream_table_view.as_slice(); + let mut stream_table = ParseBuffer::from(stream_table_slice); + + // the stream table is structured as: + // stream_count + // 0..stream_count: size of stream in bytes (0xffffffff indicating "stream does not exist") + // stream 0: PageNumber + // stream 1: PageNumber, PageNumber + // stream 2: PageNumber, PageNumber, PageNumber, PageNumber, PageNumber + // stream 3: PageNumber, PageNumber, PageNumber, PageNumber + // (number of pages determined by number of bytes) + + let stream_count = stream_table.parse_u16()? as u32; + let _reserved = stream_table.parse_u16()?; + + // check if we've already outworn our welcome + if stream_number >= stream_count { + return Err(Error::StreamNotFound(stream_number)); + } + + // we now have {stream_count} u32s describing the length of each stream + + // walk over the streams before the requested stream + // we need to pay attention to how big each one is, since their page numbers come + // before our page numbers in the stream table + let mut page_numbers_to_skip: usize = 0; + for _ in 0..stream_number { + let bytes = stream_table.parse_u32()?; + let _reserved = stream_table.parse_u32()?; + if bytes == u32::max_value() { + // stream is not present, ergo nothing to skip + } else { + page_numbers_to_skip += header.pages_needed_to_store(bytes as usize); + } + } + + // read our stream's size + bytes_in_stream = stream_table.parse_u32()?; + let _reserved = stream_table.parse_u32()?; + if bytes_in_stream == u32::max_value() { + return Err(Error::StreamNotFound(stream_number)); + } + + // skip the remaining streams' byte counts + let _ = stream_table.take((stream_count - stream_number - 1) as usize * 8)?; + + // skip the preceding streams' page numbers + let _ = stream_table.take((page_numbers_to_skip as usize) * 2)?; + + page_list = + Self::read_page_list(&self.header, bytes_in_stream as usize, &mut stream_table)?; + } else { + unreachable!(); + } + + // done! + Ok(page_list) + } +} + +impl<'s, S: Source<'s>> Msf<'s, S> for SmallMSF<'s, S> { + fn get(&mut self, stream_number: u32, limit: Option) -> Result> { + // look up the stream + let mut page_list = self.look_up_stream(stream_number)?; + + // apply any limits we have + if let Some(limit) = limit { + page_list.truncate(limit); + } + + // now that we know where this stream lives, we can view it + let view = view(&mut self.source, &page_list)?; + + // pack it into a Stream + let stream = Stream { source_view: view }; + + Ok(stream) + } +} diff --git a/src/symbol/mod.rs b/src/symbol/mod.rs index bbad78b..c4e1ae4 100644 --- a/src/symbol/mod.rs +++ b/src/symbol/mod.rs @@ -2392,6 +2392,7 @@ mod tests { type_index: TypeIndex(8824), register: Register(18), name: "this".into(), + slot: None }) ); } @@ -2444,6 +2445,7 @@ mod tests { type_index: TypeIndex(0x1030), register: Register(22), name: "maximum_count".into(), + slot: None }) ); } @@ -2896,6 +2898,7 @@ mod tests { isenreg_stat: false, }, name: "this".into(), + slot: None }) ); } From 99ca912c248133aa398275efa97b93b4f84ab412 Mon Sep 17 00:00:00 2001 From: = Date: Fri, 2 Feb 2024 14:22:46 +0100 Subject: [PATCH 2/2] Add support for the small/2.0 format --- src/msf/big.rs | 30 ++++++++++++++--------------- src/msf/mod.rs | 3 +++ src/tpi/primitive.rs | 4 ++++ tests/version2.rs | 45 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 15 deletions(-) create mode 100644 tests/version2.rs diff --git a/src/msf/big.rs b/src/msf/big.rs index 40ea2e5..14b495c 100644 --- a/src/msf/big.rs +++ b/src/msf/big.rs @@ -45,6 +45,19 @@ pub struct BigMSF<'s, S> { } impl<'s, S: Source<'s>> BigMSF<'s, S> { + fn read_page_list(hdr: &Header, size: usize, buf: &mut ParseBuffer) -> Result { + let pages = hdr.pages_needed_to_store(size); + + let mut page_list = PageList::new(hdr.page_size); + for _ in 0..pages { + let n = buf.parse_u32()?; + page_list.push(hdr.validate_page_number(n as u32)?); + } + page_list.truncate(size); + + Ok(page_list) + } + pub fn new(source: S, header_view: Box>) -> Result> { let mut buf = ParseBuffer::from(header_view.as_slice()); let header: RawHeader = buf.parse()?; @@ -69,21 +82,8 @@ impl<'s, S: Source<'s>> BigMSF<'s, S> { let size_of_stream_table_in_pages = header_object.pages_needed_to_store(header.directory_size as usize); - // now: how many pages are needed to store the list of pages that store the stream table? - // each page entry is a u32, so multiply by four - let size_of_stream_table_page_list_in_pages = - header_object.pages_needed_to_store(size_of_stream_table_in_pages * 4); - - // read the list of stream table page list pages, which immediately follow the header - // yes, this is a stupid level of indirection - let mut stream_table_page_list_page_list = PageList::new(header_object.page_size); - for _ in 0..size_of_stream_table_page_list_in_pages { - let n = buf.parse_u32()?; - stream_table_page_list_page_list.push(header_object.validate_page_number(n)?); - } - - // truncate the stream table location location to the correct size - stream_table_page_list_page_list.truncate(size_of_stream_table_in_pages * 4); + let stream_table_page_list_page_list = + Self::read_page_list(&header_object, size_of_stream_table_in_pages * 4, &mut buf)?; Ok(BigMSF { header: header_object, diff --git a/src/msf/mod.rs b/src/msf/mod.rs index 0bbf402..0ec906b 100644 --- a/src/msf/mod.rs +++ b/src/msf/mod.rs @@ -138,7 +138,10 @@ pub fn open_msf<'s, S: Source<'s> + 's>(mut source: S) -> Result Result> { 0x71 => PrimitiveKind::WChar, 0x7a => PrimitiveKind::RChar16, 0x7b => PrimitiveKind::RChar32, + 0x7C => PrimitiveKind::Char8, 0x11 => PrimitiveKind::Short, 0x21 => PrimitiveKind::UShort, diff --git a/tests/version2.rs b/tests/version2.rs new file mode 100644 index 0000000..b20dd6f --- /dev/null +++ b/tests/version2.rs @@ -0,0 +1,45 @@ +use std::fs::File; + +use fallible_iterator::FallibleIterator; + +fn setup(func: F) +where + F: FnOnce(&mut pdb::PDB), +{ + let file = if let Ok(filename) = std::env::var("PDB_FILE") { + std::fs::File::open(filename) + } else { + unimplemented!("Set a file via the PDB_FILE environment variable"); + } + + .expect("opening file"); + + let mut pdb = pdb::PDB::open(file).expect("opening pdb"); + func(&mut pdb); +} + +#[test] +fn version2_parse() { + setup(|pdb| { + let pdb_info = pdb.pdb_information().unwrap(); + dbg!(&pdb_info); + /*let stream_names = pdb_info.stream_names().unwrap(); + for name in stream_names.into_iter() { + dbg!(&name); + + }*/ + + let sym = pdb.global_symbols().unwrap(); + let mut iter = sym.iter(); + while let Ok(Some(symbol)) = iter.next() { + println!("{:?}", symbol.parse()); + } + + let tpes = pdb.type_information().unwrap(); + let mut iter = tpes.iter(); + while let Ok(Some(typ)) = iter.next() { + println!("{:?}", typ.parse()); + } + }); + +} \ No newline at end of file