예제 #1
0
        /// <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);
        }
예제 #2
0
        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);
        }