55// http://opensource.org/licenses/MIT>, at your option. This file may not be
66// copied, modified, or distributed except according to those terms.
77
8- use crate :: common:: * ;
8+ use fallible_iterator:: FallibleIterator ;
9+
910use crate :: dbi:: { DBIExtraStreams , DBIHeader , DebugInformation , Module } ;
1011use crate :: framedata:: FrameTable ;
1112use crate :: modi:: ModuleInfo ;
@@ -17,6 +18,7 @@ use crate::source::Source;
1718use crate :: strings:: StringTable ;
1819use crate :: symbol:: SymbolTable ;
1920use crate :: tpi:: { IdInformation , TypeInformation } ;
21+ use crate :: { common:: * , SectionCharacteristics } ;
2022
2123// Some streams have a fixed stream index.
2224// http://llvm.org/docs/PDB/index.html
@@ -242,7 +244,7 @@ impl<'s, S: Source<'s> + 's> PDB<'s, S> {
242244 let index = self . extra_streams ( ) ?. section_headers ;
243245 let stream = match self . raw_stream ( index) ? {
244246 Some ( stream) => stream,
245- None => return Ok ( None ) ,
247+ None => return self . maybe_synthesize_section ( ) ,
246248 } ;
247249
248250 let mut buf = stream. parse_buffer ( ) ;
@@ -254,6 +256,67 @@ impl<'s, S: Source<'s> + 's> PDB<'s, S> {
254256 Ok ( Some ( headers) )
255257 }
256258
259+ // If there are no section_headers in the file, attempt to synthesize sections
260+ // based on the section map. This seems to be necessary to handle NGEN-generated PDB
261+ // files (.ni.pdb from Crossgen2).
262+ fn maybe_synthesize_section ( & mut self ) -> Result < Option < Vec < ImageSectionHeader > > > {
263+ // If we have OMAP From data, I don't believe we can do this, because the RVAs
264+ // won't map. But I'm not 100% sure of that, be conservative.
265+ if self . omap_from_src ( ) ?. is_some ( ) {
266+ return Ok ( None ) ;
267+ }
268+
269+ let debug_info = self . debug_information ( ) ?;
270+ let sec_map = debug_info. section_map ( ) ?;
271+ if sec_map. sec_count != sec_map. sec_count_log {
272+ return Ok ( None ) ;
273+ }
274+ let sec_map = sec_map. collect :: < Vec < _ > > ( ) ?;
275+
276+ let mut rva = 0x1000u32 ; // in the absence of explicit section data, this starts at 0x1000
277+ let sections = sec_map. into_iter ( )
278+ . filter ( |sm| {
279+ // the section with a bogus section length also doesn't have any rwx flags,
280+ // and has section_type == 2
281+ sm. section_type == 1 && // "SEL" section, not ABS (0x2) or GROUP (0x10)
282+ sm. section_length != u32:: MAX // shouldn't happen, but just in case
283+ } )
284+ . map ( |sm| {
285+ let mut characteristics = 0u32 ;
286+ if sm. flags & 0x1 != 0 { // R
287+ characteristics |= 0x40000000 ; // IMAGE_SCN_MEM_READ
288+ }
289+ if sm. flags & 0x2 != 0 { // W
290+ characteristics |= 0x80000000 ; // IMAGE_SCN_MEM_WRITE
291+ }
292+ if sm. flags & 0x4 != 0 { // X
293+ characteristics |= 0x20000000 ; // IMAGE_SCN_MEM_EXECUTE
294+ characteristics |= 0x20 ; // IMAGE_SCN_CNT_CODE
295+ }
296+
297+ if sm. rva_offset != 0 {
298+ eprintln ! ( "pdb: synthesizing section with rva_offset != 0, might not be correct! {:?}" , sm) ;
299+ }
300+
301+ let this_rva = rva + sm. rva_offset ;
302+ rva = this_rva + sm. section_length ;
303+ ImageSectionHeader {
304+ name : [ 0 ; 8 ] ,
305+ virtual_size : sm. section_length ,
306+ virtual_address : this_rva,
307+ size_of_raw_data : sm. section_length ,
308+ pointer_to_raw_data : 0 ,
309+ pointer_to_relocations : 0 ,
310+ pointer_to_line_numbers : 0 ,
311+ number_of_relocations : 0 ,
312+ number_of_line_numbers : 0 ,
313+ characteristics : SectionCharacteristics ( characteristics) ,
314+ }
315+ } ) . collect :: < Vec < _ > > ( ) ;
316+
317+ Ok ( Some ( sections) )
318+ }
319+
257320 /// Retrieve the global frame data table.
258321 ///
259322 /// This table describes the stack frame layout for functions from all modules in the PDB. Not
0 commit comments