/// <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); }