Beispiel #1
0
        private static void LoadFunctionsFromDBIModule(
            StreamInfo stream,
            Int32 pageSize,
            Int32[][] streamPages,
            Int32[] streamSizes,
            Byte[] array,
            IDictionary <String, Int32> streamNameIndices,
            IDictionary <Int32, String> nameIndex,
            DBIModuleInfo moduleInfo,
            PDBInstance instance
            )
        {
            var idx       = INT_SIZE; // Skip signature
            var thisFuncs = new List <PDBFunctionInfo>();
            var module    = instance.GetOrAddModule(moduleInfo.moduleName);

            while (idx < moduleInfo.symbolByteCount)
            {
                var blockLen    = array.ReadUInt16LEFromBytes(ref idx);
                var blockEndIdx = idx + blockLen;
#if DEBUG
                if (blockEndIdx % 4 != 0)
                {
                    throw new PDBException("Debyyg");
                }
#endif
                switch (array.ReadUInt16LEFromBytes(ref idx))
                {
                case SYM_GLOBAL_MANAGED_FUNC:
                case SYM_LOCAL_MANAGED_FUNC:
                    Int32 addr; UInt16 seg;
                    var   func = NewPDBFunction(moduleInfo.moduleName, array, ref idx, blockEndIdx, out addr, out seg);
                    module.Functions.Add(func);
                    thisFuncs.Add(new PDBFunctionInfo(func, addr, seg, -1));   // Function pointer is not used during reading
                    break;

                default:
#if DEBUG
                    throw new PDBException("Debyyg");
#else
                    idx = blockEndIdx;
                    break;
#endif
                }
            }

            if (thisFuncs.Count > 0)
            {
                // Seek to line information
                idx = moduleInfo.symbolByteCount + moduleInfo.oldLinesByteCount;
                // Sort the functions based on their address and token in order for fast lookup
                thisFuncs.Sort(PDB_FUNC_ADDRESS_AND_TOKEN_BASED);
                // Load PDBSources and PDBLines and modify PDBFunction's lineInfo to contain the information about sources and lines.
                LoadSourcesAndLinesFromModuleStream(stream, pageSize, streamPages, streamSizes, array, idx, idx + moduleInfo.linesByteCount, streamNameIndices, nameIndex, instance, thisFuncs);
            }
        }
Beispiel #2
0
        public static PDBInstance FromStream(Stream readingStream, Boolean ignoreCaseSourceFileStreamNames = true)
        {
            var stream = new StreamInfo(readingStream);

            // Header
            // Skip first 32 bytes (it's just text and magic ints)
            stream.stream.SeekFromCurrent(32);
            var array = new Byte[20];

            stream.stream.ReadWholeArray(array);
            var idx      = 0;
            var pageSize = array.ReadInt32LEFromBytes(ref idx);

            if (pageSize <= 0)
            {
                // Maybe instead just return empty PDBInstance ?
                throw new PDBException("Page size must be greater than zero, was: " + pageSize + ".");
            }
            array.Skip(ref idx, 8); // Skip free page map size and page count

            var directoryByteCount = array.ReadInt32LEFromBytes(ref idx);
            // Ignore last 4 bytes

            // Read directory page offsets
            var directoryPageCount           = AmountOfPagesTaken(directoryByteCount, pageSize);
            var directoryPageOffsetPageCount = AmountOfPagesTaken(
                INT_SIZE * directoryPageCount,
                pageSize);

            array = stream.stream.ReadWholeArray(INT_SIZE * directoryPageOffsetPageCount);
            idx   = 0;
            var directoryPageOffsets = array.ReadInt32ArrayLEFromBytes(ref idx, directoryPageOffsetPageCount);

            // Directory
            // Read directory pages
            array = stream.ReadPagedData(pageSize, directoryPageOffsets, directoryPageCount * INT_SIZE);
            idx   = 0;
            directoryPageOffsets = array.ReadInt32ArrayLEFromBytes(ref idx, directoryPageCount);

            // Read directory data
            array = stream.ReadPagedData(pageSize, directoryPageOffsets, directoryByteCount);
            idx   = 0;
            var dataStreamCount = array.ReadInt32LEFromBytes(ref idx);
            var dataStreamSizes = array.ReadInt32ArrayLEFromBytes(ref idx, dataStreamCount);
            var dataStreamPages = new Int32[dataStreamCount][];

            for (var i = 0; i < dataStreamCount; ++i)
            {
                var dSize = dataStreamSizes[i];
                if (dSize > 0)
                {
                    dataStreamPages[i] = array.ReadInt32ArrayLEFromBytes(ref idx, AmountOfPagesTaken(dSize, pageSize));
                }
            }

            // Read DBI data
            array = stream.ReadPagedData(pageSize, dataStreamPages[3], dataStreamSizes[3]);
            idx   = 0;
            DBIHeader dbiHeader; DBIModuleInfo[] modules; DBIDebugHeader debugHeader;

            LoadDBIStream(array, ref idx, out dbiHeader, out modules, out debugHeader);

            // Make array have the size of biggest stream size to be used, so we wouldn't need to create new array each time for stream
            // TODO this might still be too much in some gigantic function cases...
            array = new Byte[dataStreamSizes.Where((siz, i) => i != 3 && i != dbiHeader.symRecStream && i != dbiHeader.psSymStream && i != dbiHeader.gsSymStream).Max()];

            // Create result instance
            var instance = new PDBInstance();

            // Read root stream
            stream.ReadPagedData(pageSize, dataStreamPages[1], dataStreamSizes[1], array);
            idx                = 8; // Skip version & timestamp
            instance.Age       = array.ReadUInt32LEFromBytes(ref idx);
            instance.DebugGUID = array.ReadGUIDFromBytes(ref idx);
            var streamNameIndices = LoadStreamIndices(array, ref idx, ignoreCaseSourceFileStreamNames);

            Int32 namesStreamIdx;

            if (!streamNameIndices.TryGetValue(NAMES_STREAM_NAME, out namesStreamIdx))
            {
                throw new PDBException("The \"" + NAMES_STREAM_NAME + "\" stream is missing.");
            }
            else if (namesStreamIdx >= dataStreamCount)
            {
                throw new PDBException("The \"" + NAMES_STREAM_NAME + "\" stream was referencing to non-existant stream.");
            }

            // Read symbol server data, if any
            Int32 srcStrmIdx;

            if (streamNameIndices.TryGetValue(SOURCE_SERVER_STREAM_NAME, out srcStrmIdx) && srcStrmIdx < dataStreamCount)
            {
                stream.ReadPagedData(pageSize, dataStreamPages[srcStrmIdx], dataStreamSizes[srcStrmIdx], array);
                idx = 0;
                instance.SourceServer = array.ReadStringWithEncoding(ref idx, dataStreamSizes[srcStrmIdx], NAME_ENCODING);
            }

            // Read name index.
            stream.ReadPagedData(pageSize, dataStreamPages[namesStreamIdx], dataStreamSizes[namesStreamIdx], array);
            idx = 0;
            /*var nsSig = */
            array.ReadUInt32LEFromBytes(ref idx);
            /*var nsVer = */
            array.ReadInt32LEFromBytes(ref idx);
            var nameIndex = LoadNameIndex(array, ref idx);

            // TEMP BEGIN
            //stream.ReadPagedData( pageSize, dataStreamPages[7], dataStreamSizes[7], array );
            //idx = 4;
            //var max = array.ReadInt32LEFromBytes( ref idx );
            //idx = 0x58;
            //var srcHdrStrs = new List<String[]>();
            //while ( idx < max )
            //{
            //   var sIdx = array.ReadInt32LEFromBytes( ref idx );
            //   var str1 = nameIndex[sIdx];
            //   var max2 = array.ReadInt32LEFromBytes( ref idx );
            //   if ( max2 != 0x28 )
            //   {

            //   }
            //   max2 += idx - 4;
            //   idx += 8;
            //   if ( array.ReadInt32LEFromBytes( ref idx ) != 0x58 )
            //   {

            //   }
            //   var strs = new List<String>();
            //   strs.Add( str1 );
            //   while ( idx < max2 )
            //   {
            //      var curStr = nameIndex[array.ReadInt32LEFromBytes( ref idx )];
            //      strs.Add( curStr );
            //      if ( String.Equals( curStr, strs[0] ) )
            //      {
            //         if ( array.ReadInt32LEFromBytes( ref idx ) != 0x65 )
            //         {

            //         }
            //         idx = max2;
            //         break;
            //      }
            //   }
            //   srcHdrStrs.Add( new String[] { "" + sIdx + " - " + ( sIdx % 52 ) + ": " + str1 } );// strs.ToArray() );
            //}
            //var srcHdrStr = String.Join( "\n", srcHdrStrs.Select( s => String.Join( "\n", s ) ) );

            // TEMP END
            // Read modules.
            foreach (var module in modules)
            {
                if (module.stream > 0 && module.stream < dataStreamCount)
                {
                    stream.ReadPagedData(pageSize, dataStreamPages[module.stream], dataStreamSizes[module.stream], array);
                    LoadFunctionsFromDBIModule(stream, pageSize, dataStreamPages, dataStreamSizes, array, streamNameIndices, nameIndex, module, instance);
                }
            }

            // Apply token remapping table if exists
            if (debugHeader != null && debugHeader.snTokenRidMap != UInt16.MinValue && debugHeader.snTokenRidMap != UInt16.MaxValue)
            {
                var tokenRemapSize = dataStreamSizes[debugHeader.snTokenRidMap];
                stream.ReadPagedData(pageSize, dataStreamPages[debugHeader.snTokenRidMap], tokenRemapSize, array);
                idx = 0;
                var tokens = array.ReadUInt32ArrayLEFromBytes(ref idx, tokenRemapSize / INT_SIZE);
                foreach (var function in instance.Modules.SelectMany(mod => mod.Functions))
                {
                    function.Token = METHOD_TABLE | tokens[function.Token & METHOD_TABLE_INDEX_MASK];
                }
            }

            return(instance);
        }
Beispiel #3
0
        private static IDictionary <Int32, PDBSource> LoadSourcesAndLinesFromModuleStream(
            StreamInfo stream,
            Int32 pageSize,
            Int32[][] streamPages,
            Int32[] streamSizes,
            Byte[] array,
            Int32 idx,
            Int32 max,
            IDictionary <String, Int32> streamNameIndices,
            IDictionary <Int32, String> nameIndex,
            PDBInstance instance,
            List <PDBFunctionInfo> functions
            )
        {
            var sourcesLocal = new Dictionary <Int32, PDBSource>();
            var lines        = new List <Tuple <Int32, PDBLine> > [functions.Count];

            while (idx < max)
            {
                var sym      = array.ReadInt32LEFromBytes(ref idx);
                var size     = array.ReadInt32LEFromBytes(ref idx);
                var startIdx = idx;
                var endIdx   = idx + size;
                switch (sym)
                {
                case SYM_DEBUG_SOURCE_INFO:
                    while (idx < endIdx)
                    {
                        var curSrcFileIdx = idx - startIdx;
                        var nameIdx       = array.ReadInt32LEFromBytes(ref idx);
                        var thisLen       = array.ReadByteFromBytes(ref idx);
                        /*var kind = */
                        array.ReadByteFromBytes(ref idx);

                        var       name = nameIndex[nameIdx];
                        PDBSource pdbSource;
                        if (!instance.TryGetSource(name, out pdbSource))
                        {
                            pdbSource = new PDBSource(name);
                            Int32 sourceStreamIdx;
                            if (streamNameIndices.TryGetValue(SOURCE_FILE_PREFIX + name, out sourceStreamIdx))
                            {
                                var sourceBytes = stream.ReadPagedData(pageSize, streamPages[sourceStreamIdx], streamSizes[sourceStreamIdx]);
                                var tmpIdx      = 0;
                                pdbSource.Language      = sourceBytes.ReadGUIDFromBytes(ref tmpIdx);
                                pdbSource.Vendor        = sourceBytes.ReadGUIDFromBytes(ref tmpIdx);
                                pdbSource.DocumentType  = sourceBytes.ReadGUIDFromBytes(ref tmpIdx);
                                pdbSource.HashAlgorithm = sourceBytes.ReadGUIDFromBytes(ref tmpIdx);
                                pdbSource.Hash          = sourceBytes.CreateAndBlockCopyTo(ref tmpIdx, sourceBytes.Length - tmpIdx);
                            }
                            instance.AddSource(pdbSource);
                        }
                        ;

                        sourcesLocal.Add(curSrcFileIdx, pdbSource);
#if DEBUG
                        if (thisLen != 0)
                        {
                            throw new PDBException("Debyyg");
                        }
#endif
                        idx += thisLen;
                        Align4(ref idx);
                    }
                    break;

                case SYM_DEBUG_LINE_INFO:

                    var addr    = array.ReadInt32LEFromBytes(ref idx);
                    var section = array.ReadUInt16LEFromBytes(ref idx);
                    var flags   = array.ReadUInt16LEFromBytes(ref idx);
                    /*var cod = */
                    array.ReadUInt32LEFromBytes(ref idx);
                    var funcIdx = functions.BinarySearchDeferredEqualityDetection(new PDBFunctionInfo(null, addr, section, -1), PDB_FUNC_ADDRESS_AND_TOKEN_BASED);
                    if (funcIdx >= 0)
                    {
                        // Skip the functions that already have lines
                        while (funcIdx < lines.Length && lines[funcIdx] != null && functions[funcIdx].segment == section && functions[funcIdx].address == addr)
                        {
                            ++funcIdx;
                        }
                        if (funcIdx < lines.Length && functions[funcIdx].segment == section && functions[funcIdx].address == addr)
                        {
                            // We found the correct function index
                            var thisLines = new List <Tuple <Int32, PDBLine> >();
                            // Read line data
                            while (idx < endIdx)
                            {
                                var srcIdx    = array.ReadInt32LEFromBytes(ref idx);
                                var lineCount = array.ReadInt32LEFromBytes(ref idx);
                                // Skip size information
                                idx += INT_SIZE;
                                // Save line and column start indices
                                var lineStartIdx   = idx;
                                var columnStartIdx = idx + 8 * lineCount; // Each line is 2 integers
                                // Iterate each line
                                for (var i = 0; i < lineCount; ++i)
                                {
                                    // Reset index after possible column read
                                    idx = lineStartIdx + LINE_MULTIPLIER * i;
                                    var offset    = array.ReadInt32LEFromBytes(ref idx);
                                    var line      = new PDBLine(offset);
                                    var lineFlags = array.ReadUInt32LEFromBytes(ref idx);
                                    line.LineStart   = (Int32)(lineFlags & 0x00ffffffu);                          // Lower 3 bytes are start line of statement/expression
                                    line.LineEnd     = line.LineStart + (Int32)((lineFlags & 0x7f000000u) >> 24); // High seven bits is delta of line
                                    line.IsStatement = (lineFlags & 0x80000000u) == 0;                            // Highest bit is whether the line is statement
                                    if ((flags & 1) != 0)
                                    {
                                        // Column info present
                                        idx = columnStartIdx + COLUMN_MULTIPLIER * i; // Each column info is two shorts
                                        line.ColumnStart = array.ReadUInt16LEFromBytes(ref idx);
                                        line.ColumnEnd   = array.ReadUInt16LEFromBytes(ref idx);
                                    }
                                    thisLines.Add(Tuple.Create(srcIdx, line));
                                }
                            }
                            lines[funcIdx] = thisLines;
                        }
#if DEBUG
                        else
                        {
                            throw new PDBException("Debyyg");
                        }
#endif
                    }
#if DEBUG
                    else
                    {
                        throw new PDBException("Debyyg");
                    }
#endif
                    break;

                default:
#if DEBUG
                    throw new PDBException("Debyyg");
#else
                    break;
#endif
                }
                idx = endIdx;
            }

            // Postprocess line infos
            for (var i = 0; i < lines.Length; ++i)
            {
                var lineList = lines[i];
                if (lineList != null)
                {
                    foreach (var line in lineList)
                    {
                        functions[i].function.Lines.GetOrAdd_NotThreadSafe(sourcesLocal[line.Item1].Name, ni => new List <PDBLine>())
                        .Add(line.Item2);
                    }
                }
            }
            return(sourcesLocal);
        }