/// <summary> /// Detect whether a given stream contains portable or Windows PDB format data /// and deserialize CCI PDB information from the given format. /// </summary> /// <param name="peFilePath">Path to IL PE module (needed only for portable PDB's)</param> /// <param name="standalonePdbPath">Path to standalone Windows PDB (not used for portable PDBs)</param> public static PdbInfo TryLoadFunctions( string peFilePath, string standalonePdbPath) { if (!string.IsNullOrEmpty(peFilePath)) { using (Stream peStream = new FileStream(peFilePath, FileMode.Open, FileAccess.Read)) using (PEReader peReader = new PEReader(peStream)) { MetadataReaderProvider pdbReaderProvider; string pdbPath; if (peReader.TryOpenAssociatedPortablePdb(peFilePath, File.OpenRead, out pdbReaderProvider, out pdbPath)) { using (pdbReaderProvider) { // Load associated portable PDB PdbWriterForCci cciWriter = new PdbWriterForCci(); new PdbConverter().ConvertPortableToWindows( peReader, pdbReaderProvider.GetMetadataReader(), cciWriter, PdbConversionOptions.SuppressSourceLinkConversion); PdbInfo pdbInfo = new PdbInfo() { Functions = cciWriter.Functions, TokenToSourceMapping = cciWriter.TokenToSourceMapping, Age = cciWriter.Age, Guid = cciWriter.Guid, // Ignored for portable PDBs to avoid bringing in a dependency on Newtonsoft.Json SourceServerData = null, SourceLinkData = cciWriter.SourceLinkData }; return(pdbInfo); } } } } if (File.Exists(standalonePdbPath)) { using (FileStream pdbInputStream = new FileStream(standalonePdbPath, FileMode.Open, FileAccess.Read)) { if (!PdbConverter.IsPortable(pdbInputStream)) { // Load CCI data from Windows PDB return(PdbFile.LoadFunctions(pdbInputStream)); } } } // Non-existent Windows PDB or mismatched portable PDB return(null); }
internal static PdbInfo LoadFunctions(Stream read) { PdbInfo pdbInfo = new PdbInfo(); pdbInfo.TokenToSourceMapping = new Dictionary <uint, PdbTokenLine>(); BitAccess bits = new BitAccess(64 * 1024); PdbFileHeader head = new PdbFileHeader(read, bits); PdbReader reader = new PdbReader(read, head.pageSize); MsfDirectory dir = new MsfDirectory(reader, head, bits); DbiModuleInfo[] modules = null; DbiDbgHdr header; Dictionary <string, PdbSource> sourceCache = new Dictionary <string, PdbSource>(); dir.streams[1].Read(reader, bits); Dictionary <string, int> nameIndex = LoadNameIndex(bits, out pdbInfo.Age, out pdbInfo.Guid); int nameStream; if (!nameIndex.TryGetValue("/NAMES", out nameStream)) { throw new PdbException("Could not find the '/NAMES' stream: the PDB file may be a public symbol file instead of a private symbol file"); } dir.streams[nameStream].Read(reader, bits); IntHashTable names = LoadNameStream(bits); int srcsrvStream; if (!nameIndex.TryGetValue("SRCSRV", out srcsrvStream)) { pdbInfo.SourceServerData = string.Empty; } else { DataStream dataStream = dir.streams[srcsrvStream]; byte[] bytes = new byte[dataStream.contentSize]; dataStream.Read(reader, bits); pdbInfo.SourceServerData = bits.ReadBString(bytes.Length); } dir.streams[3].Read(reader, bits); LoadDbiStream(bits, out modules, out header, true); List <PdbFunction> funcList = new List <PdbFunction>(); if (modules != null) { for (int m = 0; m < modules.Length; m++) { var module = modules[m]; if (module.stream > 0) { dir.streams[module.stream].Read(reader, bits); if (module.moduleName == "TokenSourceLineInfo") { LoadTokenToSourceInfo(bits, module, names, dir, nameIndex, reader, pdbInfo.TokenToSourceMapping, sourceCache); continue; } LoadFuncsFromDbiModule(bits, module, names, funcList, true, dir, nameIndex, reader, sourceCache); } } } PdbFunction[] funcs = funcList.ToArray(); // After reading the functions, apply the token remapping table if it exists. if (header.snTokenRidMap != 0 && header.snTokenRidMap != 0xffff) { dir.streams[header.snTokenRidMap].Read(reader, bits); uint[] ridMap = new uint[dir.streams[header.snTokenRidMap].Length / 4]; bits.ReadUInt32(ridMap); foreach (PdbFunction func in funcs) { func.token = 0x06000000 | ridMap[func.token & 0xffffff]; } } // Array.Sort(funcs, PdbFunction.byAddressAndToken); //Array.Sort(funcs, PdbFunction.byToken); pdbInfo.Functions = funcs; return(pdbInfo); }