예제 #1
0
        /// <summary>
        /// Reads the data for single instance.
        /// </summary>
        /// <param name="debugLine">The debug line data stream.</param>
        /// <param name="addressNormalizer">Normalize address delegate (<see cref="NormalizeAddressDelegate"/>)</param>
        /// <returns>List of file information.</returns>
        private static List <DwarfFileInformation> ReadData(DwarfMemoryReader debugLine, NormalizeAddressDelegate addressNormalizer)
        {
            // Read header
            bool   is64bit;
            int    beginPosition            = debugLine.Position;
            ulong  length                   = debugLine.ReadLength(out is64bit);
            int    endPosition              = debugLine.Position + (int)length;
            ushort version                  = debugLine.ReadUshort();
            int    headerLength             = debugLine.ReadOffset(is64bit);
            byte   minimumInstructionLength = debugLine.ReadByte();
            bool   defaultIsStatement       = debugLine.ReadByte() != 0;
            sbyte  lineBase                 = (sbyte)debugLine.ReadByte();
            byte   lineRange                = debugLine.ReadByte();
            byte   operationCodeBase        = debugLine.ReadByte();

            // Read operation code lengths
            uint[] operationCodeLengths = new uint[operationCodeBase];

            operationCodeLengths[0] = 0;
            for (int i = 1; i < operationCodeLengths.Length && debugLine.Position < endPosition; i++)
            {
                operationCodeLengths[i] = debugLine.LEB128();
            }

            // Read directories
            List <string> directories = new List <string>();

            while (debugLine.Position < endPosition && debugLine.Peek() != 0)
            {
                string directory = debugLine.ReadString();

                directory = directory.Replace('/', Path.DirectorySeparatorChar);
                directories.Add(directory);
            }
            debugLine.ReadByte(); // Skip zero termination byte

            // Read files
            List <DwarfFileInformation> files = new List <DwarfFileInformation>();

            while (debugLine.Position < endPosition && debugLine.Peek() != 0)
            {
                files.Add(ReadFile(debugLine, directories));
            }
            debugLine.ReadByte(); // Skip zero termination byte

            // Parse lines
            ParsingState state       = new ParsingState(files.FirstOrDefault(), defaultIsStatement, minimumInstructionLength);
            uint         lastAddress = 0;

            while (debugLine.Position < endPosition)
            {
                byte operationCode = debugLine.ReadByte();

                if (operationCode >= operationCodeLengths.Length)
                {
                    // Special operation code
                    int adjustedOperationCode = operationCode - operationCodeBase;
                    int operationAdvance      = adjustedOperationCode / lineRange;
                    state.AdvanceAddress(operationAdvance);
                    int lineAdvance = lineBase + (adjustedOperationCode % lineRange);
                    state.Line += (uint)lineAdvance;
                    state.AddCurrentLineInfo();
                    state.IsBasicBlock  = false;
                    state.IsPrologueEnd = false;
                    state.IsEpilogueEnd = false;
                    state.Discriminator = 0;
                }
                else
                {
                    switch ((DwarfLineNumberStandardOpcode)operationCode)
                    {
                    case DwarfLineNumberStandardOpcode.Extended:
                    {
                        uint extendedLength = debugLine.LEB128();
                        int  newPosition    = debugLine.Position + (int)extendedLength;
                        DwarfLineNumberExtendedOpcode extendedCode = (DwarfLineNumberExtendedOpcode)debugLine.ReadByte();

                        switch (extendedCode)
                        {
                        case DwarfLineNumberExtendedOpcode.EndSequence:
                            lastAddress         = state.Address;
                            state.IsSequenceEnd = true;
                            state.AddCurrentLineInfo();
                            state.Reset(files.FirstOrDefault());
                            break;

                        case DwarfLineNumberExtendedOpcode.SetAddress:
                        {
                            state.Address = debugLine.ReadUint();
                            if (state.Address == 0)
                            {
                                state.Address = lastAddress;
                            }
                            state.OperationIndex = 0;
                        }
                        break;

                        case DwarfLineNumberExtendedOpcode.DefineFile:
                            state.File = ReadFile(debugLine, directories);
                            files.Add(state.File);
                            break;

                        case DwarfLineNumberExtendedOpcode.SetDiscriminator:
                            state.Discriminator = debugLine.LEB128();
                            break;

                        default:
                            throw new Exception($"Unsupported DwarfLineNumberExtendedOpcode: {extendedCode}");
                        }
                        debugLine.Position = newPosition;
                    }
                    break;

                    case DwarfLineNumberStandardOpcode.Copy:
                        state.AddCurrentLineInfo();
                        state.IsBasicBlock  = false;
                        state.IsPrologueEnd = false;
                        state.IsEpilogueEnd = false;
                        state.Discriminator = 0;
                        break;

                    case DwarfLineNumberStandardOpcode.AdvancePc:
                        state.AdvanceAddress((int)debugLine.LEB128());
                        break;

                    case DwarfLineNumberStandardOpcode.AdvanceLine:
                        state.Line += debugLine.SLEB128();
                        break;

                    case DwarfLineNumberStandardOpcode.SetFile:
                        state.File = files[(int)debugLine.LEB128() - 1];
                        break;

                    case DwarfLineNumberStandardOpcode.SetColumn:
                        state.Column = debugLine.LEB128();
                        break;

                    case DwarfLineNumberStandardOpcode.NegateStmt:
                        state.IsStatement = !state.IsStatement;
                        break;

                    case DwarfLineNumberStandardOpcode.SetBasicBlock:
                        state.IsBasicBlock = true;
                        break;

                    case DwarfLineNumberStandardOpcode.ConstAddPc:
                        state.AdvanceAddress((255 - operationCodeBase) / lineRange);
                        break;

                    case DwarfLineNumberStandardOpcode.FixedAdvancePc:
                        state.Address       += debugLine.ReadUshort();
                        state.OperationIndex = 0;
                        break;

                    case DwarfLineNumberStandardOpcode.SetPrologueEnd:
                        state.IsPrologueEnd = true;
                        break;

                    case DwarfLineNumberStandardOpcode.SetEpilogueBegin:
                        state.IsEpilogueEnd = true;
                        break;

                    case DwarfLineNumberStandardOpcode.SetIsa:
                        state.Isa = debugLine.LEB128();
                        break;

                    default:
                        throw new Exception($"Unsupported DwarfLineNumberStandardOpcode: {(DwarfLineNumberStandardOpcode)operationCode}");
                    }
                }
            }

            // Fix lines in files...
            foreach (DwarfFileInformation file in files)
            {
                for (int i = 0; i < file.Lines.Count; i++)
                {
                    file.Lines[i].Address = (uint)addressNormalizer(file.Lines[i].Address);
                }
            }
            return(files);
        }