/// <summary> /// Parses the specified data for all common information entries and frame description entries. /// </summary> /// <param name="data">The data memory reader.</param> /// <param name="defaultAddressSize">Default size of the address.</param> /// <returns>All the parsed common information entries</returns> public static DwarfCommonInformationEntry[] ParseAll(DwarfMemoryReader data, byte defaultAddressSize) { Dictionary <int, DwarfCommonInformationEntry> entries = new Dictionary <int, DwarfCommonInformationEntry>(); while (!data.IsEnd) { bool is64bit; int startPosition = data.Position; ulong length = data.ReadLength(out is64bit); int endPosition = data.Position + (int)length; int offset = data.ReadOffset(is64bit); DwarfCommonInformationEntry entry; if (offset == -1) { entry = new DwarfCommonInformationEntry(data, defaultAddressSize, endPosition); entries.Add(startPosition, entry); } else { if (!entries.TryGetValue(offset, out entry)) { entry = ParseEntry(data, defaultAddressSize, offset); entries.Add(offset, entry); } DwarfFrameDescriptionEntry description = new DwarfFrameDescriptionEntry(data, entry, endPosition); entry.FrameDescriptionEntries.Add(description); } } return(entries.Values.ToArray()); }
/// <summary> /// Reads the file information from the specified stream. /// </summary> /// <param name="debugLine">The debug line data stream.</param> /// <param name="directories">The list of existing directories.</param> private static DwarfFileInformation ReadFile(DwarfMemoryReader debugLine, List <string> directories) { string name = debugLine.ReadString(); int directoryIndex = (int)debugLine.LEB128(); uint lastModification = debugLine.LEB128(); uint length = debugLine.LEB128(); string directory = directoryIndex > 0 ? directories[directoryIndex - 1] : null; string path = name; try { path = string.IsNullOrEmpty(directory) || Path.IsPathRooted(path) ? name : Path.Combine(directory, name); } catch { } return(new DwarfFileInformation() { Name = name, Directory = directory, Path = path, LastModification = lastModification, Length = length, }); }
/// <summary> /// Parses frame description from the specified data memory reader. /// </summary> /// <param name="data">The data memory reader.</param> /// <param name="entry">Common information entry for parsed frame description.</param> /// <param name="endPosition">Position in the data reader where parsed frame description ends.</param> /// <param name="input">The input data for parsing configuration.</param> /// <returns>Parsed frame description.</returns> private static DwarfFrameDescriptionEntry ParseDescription(DwarfMemoryReader data, DwarfExceptionHandlingCommonInformationEntry entry, int endPosition, DwarfExceptionHandlingFrameParsingInput input) { DwarfFrameDescriptionEntry description = new DwarfFrameDescriptionEntry(); description.InitialLocation = ReadEncodedAddress(data, entry.FrameDescriptionAddressEncoding, input); description.AddressRange = ReadEncodedAddress(data, entry.FrameDescriptionAddressEncoding & DwarfExceptionHandlingEncoding.Mask, input); description.CommonInformationEntry = entry; int instructionsStart = -1; if (entry.Augmentation.Length >= 1 && entry.Augmentation[0] == 'z') { uint length = data.LEB128(); instructionsStart = data.Position + (int)length; if (entry.LanguageSpecificDataAreaEncoding != DwarfExceptionHandlingEncoding.Omit) { ulong lsdaDataFileAddress = ReadEncodedAddress(data, entry.LanguageSpecificDataAreaEncoding, input); } } if (instructionsStart >= 0) { data.Position = instructionsStart; } description.Instructions = data.ReadBlock((uint)(endPosition - data.Position)); return(description); }
/// <summary> /// Parses the data for this instance. /// </summary> /// <param name="data">The data memory reader.</param> /// <param name="defaultAddressSize">Default size of the address.</param> /// <param name="endPosition">The end position.</param> private void ParseData(DwarfMemoryReader data, byte defaultAddressSize, int endPosition) { Version = data.ReadByte(); Augmentation = data.ReadString(); if (!string.IsNullOrEmpty(Augmentation)) { AddressSize = 4; SegmentSelectorSize = 0; CodeAlignmentFactor = 0; DataAlignmentFactor = 0; ReturnAddressRegister = 0; } else { if (Version >= 4) { AddressSize = data.ReadByte(); SegmentSelectorSize = data.ReadByte(); } else { AddressSize = defaultAddressSize; SegmentSelectorSize = 0; } CodeAlignmentFactor = data.LEB128(); DataAlignmentFactor = data.LEB128(); ReturnAddressRegister = data.LEB128(); } InitialInstructions = data.ReadBlock((uint)(endPosition - data.Position)); }
/// <summary> /// Initializes a new instance of the <see cref="ElfCoreDump"/> class. /// </summary> /// <param name="coreDumpPath">The core dump path.</param> public ElfCoreDump(string coreDumpPath) { elf = ELFReader.Load <ulong>(coreDumpPath); if (elf.Type != FileType.Core) { throw new Exception($"Expected core dump, but got: {elf.Type}"); } switch (elf.Machine) { case Machine.Intel386: instance = new Intel386Instance(elf); break; case Machine.AMD64: instance = new AMD64Instance(elf); break; default: throw new Exception($"Unsupported machine type: {elf.Machine}"); } Path = coreDumpPath; foreach (var segment in elf.Segments) { if (segment.Type == SegmentType.Note) { DwarfMemoryReader reader = new DwarfMemoryReader(ReadSegment(segment)); int noteStructSize = Marshal.SizeOf <elf_32note>(); while (reader.Position + noteStructSize < reader.Data.Length) { // Read note elf_32note note = reader.ReadStructure <elf_32note>(); int nameEnd = reader.Position + (int)note.NameSize; // Check if note is available to be read if (nameEnd + note.n_descsz > reader.Data.Length) { break; } // Read name and content string name = reader.ReadString(); reader.Position = nameEnd; byte[] content = reader.ReadBlock(note.n_descsz); instance.ProcessNote(name, content, note.n_type); if (note.n_type == elf_note_type.File) { DwarfMemoryReader data = new DwarfMemoryReader(content); files = elf_note_file.Parse(data, Is64bit); } } } } DumpFileMemoryReader = new CoreDumpReader(coreDumpPath, elf.Segments.Where(s => s.Type == SegmentType.Load)); }
/// <summary> /// Parses the data for this instance. /// </summary> /// <param name="data">The data memory reader.</param> /// <param name="endPosition">The end position.</param> /// <param name="input">The input data for parsing configuration.</param> private void ParseData(DwarfMemoryReader data, int endPosition, DwarfExceptionHandlingFrameParsingInput input) { Version = data.ReadByte(); Augmentation = data.ReadString(); CodeAlignmentFactor = data.LEB128(); DataAlignmentFactor = data.SLEB128(); if (Version == 1) { ReturnAddressRegister = data.ReadByte(); } else { ReturnAddressRegister = data.LEB128(); } AddressSize = input.DefaultAddressSize; SegmentSelectorSize = 0; int instructionsStart = -1; for (int i = 0; i < Augmentation.Length; i++) { if (Augmentation[i] == 'z') { uint length = data.LEB128(); instructionsStart = data.Position + (int)length; } else if (Augmentation[i] == 'L') { LanguageSpecificDataAreaEncoding = (DwarfExceptionHandlingEncoding)data.ReadByte(); } else if (Augmentation[i] == 'R') { FrameDescriptionAddressEncoding = (DwarfExceptionHandlingEncoding)data.ReadByte(); } else if (Augmentation[i] == 'S') { StackFrame = true; } else if (Augmentation[i] == 'P') { PersonalityEncoding = (DwarfExceptionHandlingEncoding)data.ReadByte(); PersonalityLocation = ReadEncodedAddress(data, PersonalityEncoding, input); } else { break; } } if (instructionsStart >= 0) { data.Position = instructionsStart; } InitialInstructions = data.ReadBlock((uint)(endPosition - data.Position)); }
/// <summary> /// Parses the line number programs. /// </summary> /// <param name="debugLine">The debug line.</param> /// <param name="codeSegmentOffset">The code segment offset.</param> private static DwarfLineNumberProgram[] ParseLineNumberPrograms(byte[] debugLine, ulong codeSegmentOffset) { using (DwarfMemoryReader debugLineReader = new DwarfMemoryReader(debugLine)) { List <DwarfLineNumberProgram> programs = new List <DwarfLineNumberProgram>(); while (!debugLineReader.IsEnd) { DwarfLineNumberProgram program = new DwarfLineNumberProgram(debugLineReader, codeSegmentOffset); programs.Add(program); } return(programs.ToArray()); } }
/// <summary> /// Parses the line number programs. /// </summary> /// <param name="debugLine">The debug line.</param> /// <param name="addressNormalizer">Normalize address delegate (<see cref="NormalizeAddressDelegate"/>)</param> private static DwarfLineNumberProgram[] ParseLineNumberPrograms(byte[] debugLine, NormalizeAddressDelegate addressNormalizer) { using (DwarfMemoryReader debugLineReader = new DwarfMemoryReader(debugLine)) { List <DwarfLineNumberProgram> programs = new List <DwarfLineNumberProgram>(); while (!debugLineReader.IsEnd) { DwarfLineNumberProgram program = new DwarfLineNumberProgram(debugLineReader, addressNormalizer); programs.Add(program); } return(programs.ToArray()); } }
/// <summary> /// Parses the common information entries. /// </summary> /// <param name="debugFrame">The debug frame.</param> /// <param name="ehFrame">The exception handling frames.</param> /// <param name="input">The input data for parsing configuration.</param> private static DwarfCommonInformationEntry[] ParseCommonInformationEntries(byte[] debugFrame, byte[] ehFrame, DwarfExceptionHandlingFrameParsingInput input) { List <DwarfCommonInformationEntry> entries = new List <DwarfCommonInformationEntry>(); using (DwarfMemoryReader debugFrameReader = new DwarfMemoryReader(debugFrame)) { entries.AddRange(DwarfCommonInformationEntry.ParseAll(debugFrameReader, input.DefaultAddressSize)); } using (DwarfMemoryReader ehFrameReader = new DwarfMemoryReader(ehFrame)) { entries.AddRange(DwarfExceptionHandlingCommonInformationEntry.ParseAll(ehFrameReader, input)); } return(entries.ToArray()); }
/// <summary> /// Parses the compilation units. /// </summary> /// <param name="debugData">The debug data.</param> /// <param name="debugDataDescription">The debug data description.</param> /// <param name="debugStrings">The debug strings.</param> /// <param name="codeSegmentOffset">The code segment offset.</param> private static DwarfCompilationUnit[] ParseCompilationUnits(byte[] debugData, byte[] debugDataDescription, byte[] debugStrings, ulong codeSegmentOffset) { using (DwarfMemoryReader debugDataReader = new DwarfMemoryReader(debugData)) using (DwarfMemoryReader debugDataDescriptionReader = new DwarfMemoryReader(debugDataDescription)) using (DwarfMemoryReader debugStringsReader = new DwarfMemoryReader(debugStrings)) { List <DwarfCompilationUnit> compilationUnits = new List <DwarfCompilationUnit>(); while (!debugDataReader.IsEnd) { DwarfCompilationUnit compilationUnit = new DwarfCompilationUnit(debugDataReader, debugDataDescriptionReader, debugStringsReader, codeSegmentOffset); compilationUnits.Add(compilationUnit); } return(compilationUnits.ToArray()); } }
/// <summary> /// Parses the compilation units. /// </summary> /// <param name="debugData">The debug data.</param> /// <param name="debugDataDescription">The debug data description.</param> /// <param name="debugStrings">The debug strings.</param> /// <param name="addressNormalizer">Normalize address delegate (<see cref="NormalizeAddressDelegate"/>)</param> private static DwarfCompilationUnit[] ParseCompilationUnits(byte[] debugData, byte[] debugDataDescription, byte[] debugStrings, NormalizeAddressDelegate addressNormalizer) { using (DwarfMemoryReader debugDataReader = new DwarfMemoryReader(debugData)) using (DwarfMemoryReader debugDataDescriptionReader = new DwarfMemoryReader(debugDataDescription)) using (DwarfMemoryReader debugStringsReader = new DwarfMemoryReader(debugStrings)) { List <DwarfCompilationUnit> compilationUnits = new List <DwarfCompilationUnit>(); while (!debugDataReader.IsEnd) { DwarfCompilationUnit compilationUnit = new DwarfCompilationUnit(debugDataReader, debugDataDescriptionReader, debugStringsReader, addressNormalizer); compilationUnits.Add(compilationUnit); } return(compilationUnits.ToArray()); } }
/// <summary> /// Processes the parsed note. /// </summary> /// <param name="name">The note name.</param> /// <param name="content">The note content.</param> /// <param name="type">The note type.</param> public void ProcessNote(string name, byte[] content, elf_note_type type) { if (type == elf_note_type.Prstatus) { DwarfMemoryReader data = new DwarfMemoryReader(content); elf_prstatus prstatus = data.ReadStructure <elf_prstatus>(); threads.Add(prstatus); } else if (type == elf_note_type.Prpsinfo) { // TODO: Use when needed //DwarfMemoryReader data = new DwarfMemoryReader(content); //elf_prpsinfo prpsinfo = data.ReadStructure<elf_prpsinfo>(); //Console.WriteLine($" Filename: {prpsinfo.Filename}"); //Console.WriteLine($" ArgList: {prpsinfo.ArgList}"); } }
/// <summary> /// Parses the specified data for all common information entries and frame description entries. /// </summary> /// <param name="data">The data memory reader.</param> /// <param name="input">The input data for parsing configuration.</param> /// <returns>All the parsed common information entries</returns> public static DwarfExceptionHandlingCommonInformationEntry[] ParseAll(DwarfMemoryReader data, DwarfExceptionHandlingFrameParsingInput input) { Dictionary <int, DwarfExceptionHandlingCommonInformationEntry> entries = new Dictionary <int, DwarfExceptionHandlingCommonInformationEntry>(); while (!data.IsEnd) { bool is64bit; int startPosition = data.Position; ulong length = data.ReadLength(out is64bit); int endPosition = data.Position + (int)length; if (length == 0 || endPosition >= data.Data.Length) { break; } int offsetBase = data.Position; int offset = data.ReadOffset(is64bit); DwarfExceptionHandlingCommonInformationEntry entry; if (offset == 0) { entry = new DwarfExceptionHandlingCommonInformationEntry(data, endPosition, input); entries.Add(startPosition, entry); } else { int entryOffset = offsetBase - offset; if (!entries.TryGetValue(entryOffset, out entry)) { entry = ParseEntry(data, entryOffset, input); entries.Add(entryOffset, entry); } DwarfFrameDescriptionEntry description = ParseDescription(data, entry, endPosition, input); entry.FrameDescriptionEntries.Add(description); } } return(entries.Values.ToArray()); }
public static elf_note_file[] Parse(DwarfMemoryReader reader, bool is64bit) { ulong count = is64bit ? reader.ReadUlong() : reader.ReadUint(); ulong page_size = is64bit ? reader.ReadUlong() : reader.ReadUint(); elf_note_file[] files = new elf_note_file[count]; for (int i = 0; i < files.Length; i++) { files[i].start = is64bit ? reader.ReadUlong() : reader.ReadUint(); files[i].end = is64bit ? reader.ReadUlong() : reader.ReadUint(); files[i].file_ofs = (is64bit ? reader.ReadUlong() : reader.ReadUint()) * page_size; } for (int i = 0; i < files.Length; i++) { files[i].name = reader.ReadString(); } return(files); }
/// <summary> /// Parses the single entry from the specified data. /// </summary> /// <param name="data">The data memory reader.</param> /// <param name="startPosition">The start position.</param> /// <param name="input">The input data for parsing configuration.</param> /// <returns>Parsed common information entry.</returns> private static DwarfExceptionHandlingCommonInformationEntry ParseEntry(DwarfMemoryReader data, int startPosition, DwarfExceptionHandlingFrameParsingInput input) { int position = data.Position; data.Position = startPosition; bool is64bit; ulong length = data.ReadLength(out is64bit); int endPosition = data.Position + (int)length; int offset = data.ReadOffset(is64bit); if (offset != 0) { throw new Exception("Expected CommonInformationEntry"); } DwarfExceptionHandlingCommonInformationEntry entry = new DwarfExceptionHandlingCommonInformationEntry(data, endPosition, input); data.Position = position; return(entry); }
/// <summary> /// Parses the single entry from the specified data. /// </summary> /// <param name="data">The data memory reader.</param> /// <param name="defaultAddressSize">Default size of the address.</param> /// <param name="startPosition">The start position.</param> /// <returns>Parsed common information entry.</returns> private static DwarfCommonInformationEntry ParseEntry(DwarfMemoryReader data, byte defaultAddressSize, int startPosition) { int position = data.Position; data.Position = startPosition; bool is64bit; ulong length = data.ReadLength(out is64bit); int endPosition = data.Position + (int)length; int offset = data.ReadOffset(is64bit); if (offset != -1) { throw new Exception("Expected CommonInformationEntry"); } DwarfCommonInformationEntry entry = new DwarfCommonInformationEntry(data, defaultAddressSize, endPosition); data.Position = position; return(entry); }
/// <summary> /// Initializes a new instance of the <see cref="DwarfCompilationUnit"/> class. /// </summary> /// <param name="debugData">The debug data stream.</param> /// <param name="debugDataDescription">The debug data description stream.</param> /// <param name="debugStrings">The debug strings.</param> /// <param name="codeSegmentOffset">The code segment offset.</param> public DwarfCompilationUnit(DwarfMemoryReader debugData, DwarfMemoryReader debugDataDescription, DwarfMemoryReader debugStrings, ulong codeSegmentOffset) { ReadData(debugData, debugDataDescription, debugStrings, codeSegmentOffset); }
/// <summary> /// Initializes a new instance of the <see cref="DwarfLineNumberProgram"/> class. /// </summary> /// <param name="debugLine">The debug line data stream.</param> /// <param name="addressNormalizer">Normalize address delegate (<see cref="NormalizeAddressDelegate"/>)</param> public DwarfLineNumberProgram(DwarfMemoryReader debugLine, NormalizeAddressDelegate addressNormalizer) { Files = ReadData(debugLine, addressNormalizer); }
/// <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); }
/// <summary> /// Initializes a new instance of the <see cref="DwarfLineNumberProgram"/> class. /// </summary> /// <param name="debugLine">The debug line data stream.</param> /// <param name="codeSegmentOffset">The code segment offset.</param> public DwarfLineNumberProgram(DwarfMemoryReader debugLine, ulong codeSegmentOffset) { Files = ReadData(debugLine, (uint)codeSegmentOffset); }
/// <summary> /// Initializes a new instance of the <see cref="DwarfCommonInformationEntry"/> class. /// </summary> /// <param name="data">The data memory reader.</param> /// <param name="defaultAddressSize">Default size of the address.</param> /// <param name="endPosition">The end position in the memory stream.</param> private DwarfCommonInformationEntry(DwarfMemoryReader data, byte defaultAddressSize, int endPosition) { ParseData(data, defaultAddressSize, endPosition); }
/// <summary> /// Initializes a new instance of the <see cref="DwarfExceptionHandlingCommonInformationEntry"/> class. /// </summary> /// <param name="data">The data memory reader.</param> /// <param name="endPosition">The end position in the memory stream.</param> /// <param name="input">The input data for parsing configuration.</param> public DwarfExceptionHandlingCommonInformationEntry(DwarfMemoryReader data, int endPosition, DwarfExceptionHandlingFrameParsingInput input) { ParseData(data, endPosition, input); }
/// <summary> /// Reads encoded address from the specified data memory reader. /// </summary> /// <param name="data">The data memory reader.</param> /// <param name="encoding">Encoding used for storing address value.</param> /// <param name="input">The input data for parsing configuration.</param> /// <returns>Decoded address value.</returns> private static ulong ReadEncodedAddress(DwarfMemoryReader data, DwarfExceptionHandlingEncoding encoding, DwarfExceptionHandlingFrameParsingInput input) { bool signExtendValue = false; ulong baseAddress = 0; switch (encoding & DwarfExceptionHandlingEncoding.Modifiers) { case DwarfExceptionHandlingEncoding.PcRelative: signExtendValue = true; baseAddress = (ulong)data.Position; if (input.PcRelativeAddress != ulong.MaxValue) { baseAddress += input.PcRelativeAddress; } break; case DwarfExceptionHandlingEncoding.TextRelative: signExtendValue = true; if (input.TextAddress != ulong.MaxValue) { baseAddress = input.TextAddress; } break; case DwarfExceptionHandlingEncoding.DataRelative: signExtendValue = true; if (input.DataAddress != ulong.MaxValue) { baseAddress = input.DataAddress; } break; case DwarfExceptionHandlingEncoding.FunctionRelative: signExtendValue = true; break; case DwarfExceptionHandlingEncoding.Aligned: { int alignment = data.Position % input.DefaultAddressSize; if (alignment > 0) { data.Position += input.DefaultAddressSize - alignment; } } break; } ulong address = 0; switch (encoding & DwarfExceptionHandlingEncoding.Mask) { case DwarfExceptionHandlingEncoding.Signed: case DwarfExceptionHandlingEncoding.AbsolutePointer: address = data.ReadUlong(input.DefaultAddressSize); break; case DwarfExceptionHandlingEncoding.UnsignedData2: address = data.ReadUshort(); break; case DwarfExceptionHandlingEncoding.UnsignedData4: address = data.ReadUint(); break; case DwarfExceptionHandlingEncoding.SignedData8: case DwarfExceptionHandlingEncoding.UnsignedData8: address = data.ReadUlong(); break; case DwarfExceptionHandlingEncoding.Uleb128: address = data.LEB128(); break; case DwarfExceptionHandlingEncoding.Sleb128: address = data.SLEB128(); break; case DwarfExceptionHandlingEncoding.SignedData2: address = (ulong)(long)(short)data.ReadUshort(); break; case DwarfExceptionHandlingEncoding.SignedData4: address = (ulong)(long)(int)data.ReadUint(); break; } if (signExtendValue && input.DefaultAddressSize < System.Runtime.InteropServices.Marshal.SizeOf(address.GetType())) { ulong sign_bit = 1UL << ((input.DefaultAddressSize * 8) - 1); if ((sign_bit & address) != 0) { ulong mask = ~sign_bit + 1; address |= mask; } } return(baseAddress + address); }
/// <summary> /// Parses the specified data. /// </summary> /// <param name="data">The PE image data.</param> private void ParseData(byte[] data) { using (DwarfMemoryReader reader = new DwarfMemoryReader(data)) { dosHeader = reader.ReadStructure <IMAGE_DOS_HEADER>(); if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE) { throw new ArgumentException($"Invalid IMAGE_DOS_HEADER magic constant. Expected: 0x{IMAGE_DOS_SIGNATURE:X}, Got: 0x{dosHeader.e_magic:X}"); } reader.Position = (int)dosHeader.e_lfanew; ntHeaders32 = reader.ReadStructure <IMAGE_NT_HEADERS32>(); if (ntHeaders32.Signature != IMAGE_NT_SIGNATURE) { throw new ArgumentException($"Invalid optional header signature. Expected: 0x{IMAGE_NT_SIGNATURE:X}, Got: 0x{ntHeaders32.Signature:X}"); } if (ntHeaders32.FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64 || ntHeaders32.FileHeader.Machine == IMAGE_FILE_MACHINE_IA64) { reader.Position = (int)dosHeader.e_lfanew; ntHeaders64 = reader.ReadStructure <IMAGE_NT_HEADERS64>(); Is64bit = true; fileHeader = ntHeaders64.FileHeader; reader.Position += ntHeaders64.FileHeader.SizeOfOptionalHeader - Marshal.SizeOf <IMAGE_OPTIONAL_HEADER64>(); CodeSegmentOffset = ntHeaders64.OptionalHeader.ImageBase; } else { Is64bit = false; fileHeader = ntHeaders32.FileHeader; reader.Position += ntHeaders32.FileHeader.SizeOfOptionalHeader - Marshal.SizeOf <IMAGE_OPTIONAL_HEADER32>(); CodeSegmentOffset = ntHeaders32.OptionalHeader.ImageBase; } // Load image section headers uint stringTablePosition = fileHeader.PointerToSymbolTable + fileHeader.NumberOfSymbols * IMAGE_SIZEOF_SYMBOL; imageSectionHeaders = new IMAGE_SECTION_HEADER[fileHeader.NumberOfSections]; for (int section = 0; section < imageSectionHeaders.Length; section++) { IMAGE_SECTION_HEADER imageSectionHeader = reader.ReadStructure <IMAGE_SECTION_HEADER>(); imageSectionHeaders[section] = imageSectionHeader; string name = imageSectionHeader.Section; if (imageSectionHeader.Name[0] == '/') { uint position = stringTablePosition + uint.Parse(imageSectionHeader.Section.Substring(1)); name = reader.ReadString((int)position); } switch (name) { case ".debug_info": DebugData = reader.ReadBlock(imageSectionHeader.SizeInImage, (int)imageSectionHeader.PointerToRawData); break; case ".debug_abbrev": DebugDataDescription = reader.ReadBlock(imageSectionHeader.SizeInImage, (int)imageSectionHeader.PointerToRawData); break; case ".debug_line": DebugLine = reader.ReadBlock(imageSectionHeader.SizeInImage, (int)imageSectionHeader.PointerToRawData); break; case ".debug_frame": DebugFrame = reader.ReadBlock(imageSectionHeader.SizeInImage, (int)imageSectionHeader.PointerToRawData); break; case ".debug_str": DebugDataStrings = reader.ReadBlock(imageSectionHeader.SizeInImage, (int)imageSectionHeader.PointerToRawData); break; case ".eh_frame": EhFrame = reader.ReadBlock(imageSectionHeader.SizeInImage, (int)imageSectionHeader.PointerToRawData); EhFrameAddress = imageSectionHeader.PointerToRawData + CodeSegmentOffset; break; case ".data": DataSectionAddress = imageSectionHeader.PointerToRawData + CodeSegmentOffset; break; case ".text": TextSectionAddress = imageSectionHeader.PointerToRawData + CodeSegmentOffset; break; } } // Load image symbols List <PublicSymbol> publicSymbols = new List <PublicSymbol>(); byte toSkip = 0; reader.Position = (int)fileHeader.PointerToSymbolTable; for (uint i = 0; i < fileHeader.NumberOfSymbols; i++) { int position = reader.Position; IMAGE_SYMBOL symbol = reader.ReadStructure <IMAGE_SYMBOL>(); if (toSkip == 0) { string name = symbol.SymbolName; if (string.IsNullOrEmpty(name)) { int stringPosition = (int)reader.ReadUint(position); stringPosition = (int)reader.ReadUint(position + 4); name = reader.ReadString((int)stringTablePosition + stringPosition); } if (symbol.SectionNumber > 0 && symbol.SectionNumber <= imageSectionHeaders.Length) { uint sectionAddress = imageSectionHeaders[symbol.SectionNumber - 1].VirtualAddress; sectionAddress += symbol.Value; publicSymbols.Add(new PublicSymbol(name, sectionAddress)); } toSkip = symbol.NumberOfAuxSymbols; } else { toSkip--; } } PublicSymbols = publicSymbols; } }
/// <summary> /// Reads the data for this instance. /// </summary> /// <param name="debugData">The debug data.</param> /// <param name="debugDataDescription">The debug data description.</param> /// <param name="debugStrings">The debug strings.</param> /// <param name="codeSegmentOffset">The code segment offset.</param> private void ReadData(DwarfMemoryReader debugData, DwarfMemoryReader debugDataDescription, DwarfMemoryReader debugStrings, ulong codeSegmentOffset) { // Read header bool is64bit; int beginPosition = debugData.Position; ulong length = debugData.ReadLength(out is64bit); int endPosition = debugData.Position + (int)length; ushort version = debugData.ReadUshort(); int debugDataDescriptionOffset = debugData.ReadOffset(is64bit); byte addressSize = debugData.ReadByte(); DataDescriptionReader dataDescriptionReader = new DataDescriptionReader(debugDataDescription, debugDataDescriptionOffset); // Read data List <DwarfSymbol> symbols = new List <DwarfSymbol>(); Stack <DwarfSymbol> parents = new Stack <DwarfSymbol>(); while (debugData.Position < endPosition) { int dataPosition = debugData.Position; uint code = debugData.LEB128(); if (code == 0) { parents.Pop(); continue; } DataDescription description = dataDescriptionReader.GetDebugDataDescription(code); Dictionary <DwarfAttribute, DwarfAttributeValue> attributes = new Dictionary <DwarfAttribute, DwarfAttributeValue>(); foreach (DataDescriptionAttribute descriptionAttribute in description.Attributes) { DwarfAttribute attribute = descriptionAttribute.Attribute; DwarfFormat format = descriptionAttribute.Format; DwarfAttributeValue attributeValue = new DwarfAttributeValue(); switch (format) { case DwarfFormat.Address: attributeValue.Type = DwarfAttributeValueType.Address; attributeValue.Value = debugData.ReadUlong(addressSize); break; case DwarfFormat.Block: attributeValue.Type = DwarfAttributeValueType.Block; attributeValue.Value = debugData.ReadBlock(debugData.LEB128()); break; case DwarfFormat.Block1: attributeValue.Type = DwarfAttributeValueType.Block; attributeValue.Value = debugData.ReadBlock(debugData.ReadByte()); break; case DwarfFormat.Block2: attributeValue.Type = DwarfAttributeValueType.Block; attributeValue.Value = debugData.ReadBlock(debugData.ReadUshort()); break; case DwarfFormat.Block4: attributeValue.Type = DwarfAttributeValueType.Block; attributeValue.Value = debugData.ReadBlock(debugData.ReadUint()); break; case DwarfFormat.Data1: attributeValue.Type = DwarfAttributeValueType.Constant; attributeValue.Value = (ulong)debugData.ReadByte(); break; case DwarfFormat.Data2: attributeValue.Type = DwarfAttributeValueType.Constant; attributeValue.Value = (ulong)debugData.ReadUshort(); break; case DwarfFormat.Data4: attributeValue.Type = DwarfAttributeValueType.Constant; attributeValue.Value = (ulong)debugData.ReadUint(); break; case DwarfFormat.Data8: attributeValue.Type = DwarfAttributeValueType.Constant; attributeValue.Value = (ulong)debugData.ReadUlong(); break; case DwarfFormat.SData: attributeValue.Type = DwarfAttributeValueType.Constant; attributeValue.Value = (ulong)debugData.SLEB128(); break; case DwarfFormat.UData: attributeValue.Type = DwarfAttributeValueType.Constant; attributeValue.Value = (ulong)debugData.LEB128(); break; case DwarfFormat.String: attributeValue.Type = DwarfAttributeValueType.String; attributeValue.Value = debugData.ReadString(); break; case DwarfFormat.Strp: attributeValue.Type = DwarfAttributeValueType.String; attributeValue.Value = debugStrings.ReadString(debugData.ReadOffset(is64bit)); break; case DwarfFormat.Flag: attributeValue.Type = DwarfAttributeValueType.Flag; attributeValue.Value = debugData.ReadByte() != 0; break; case DwarfFormat.FlagPresent: attributeValue.Type = DwarfAttributeValueType.Flag; attributeValue.Value = true; break; case DwarfFormat.Ref1: attributeValue.Type = DwarfAttributeValueType.Reference; attributeValue.Value = (ulong)debugData.ReadByte() + (ulong)beginPosition; break; case DwarfFormat.Ref2: attributeValue.Type = DwarfAttributeValueType.Reference; attributeValue.Value = (ulong)debugData.ReadUshort() + (ulong)beginPosition; break; case DwarfFormat.Ref4: attributeValue.Type = DwarfAttributeValueType.Reference; attributeValue.Value = (ulong)debugData.ReadUint() + (ulong)beginPosition; break; case DwarfFormat.Ref8: attributeValue.Type = DwarfAttributeValueType.Reference; attributeValue.Value = (ulong)debugData.ReadUlong() + (ulong)beginPosition; break; case DwarfFormat.RefUData: attributeValue.Type = DwarfAttributeValueType.Reference; attributeValue.Value = (ulong)debugData.LEB128() + (ulong)beginPosition; break; case DwarfFormat.RefAddr: attributeValue.Type = DwarfAttributeValueType.Reference; attributeValue.Value = (ulong)debugData.ReadOffset(is64bit); break; case DwarfFormat.RefSig8: attributeValue.Type = DwarfAttributeValueType.Invalid; debugData.Position += 8; break; case DwarfFormat.ExpressionLocation: attributeValue.Type = DwarfAttributeValueType.ExpressionLocation; attributeValue.Value = debugData.ReadBlock(debugData.LEB128()); break; case DwarfFormat.SecOffset: attributeValue.Type = DwarfAttributeValueType.SecOffset; attributeValue.Value = (ulong)debugData.ReadOffset(is64bit); break; default: throw new Exception($"Unsupported DwarfFormat: {format}"); } if (attributes.ContainsKey(attribute)) { if (attributes[attribute] != attributeValue) { attributes[attribute] = attributeValue; } } else { attributes.Add(attribute, attributeValue); } } DwarfSymbol symbol = new DwarfSymbol() { Tag = description.Tag, Attributes = attributes, Offset = dataPosition, }; symbolsByOffset.Add(symbol.Offset, symbol); if (parents.Count > 0) { parents.Peek().Children.Add(symbol); symbol.Parent = parents.Peek(); } else { symbols.Add(symbol); } if (description.HasChildren) { symbol.Children = new List <DwarfSymbol>(); parents.Push(symbol); } } SymbolsTree = symbols.ToArray(); if (SymbolsTree.Length > 0) { // Add void type symbol DwarfSymbol voidSymbol = new DwarfSymbol() { Tag = DwarfTag.BaseType, Offset = -1, Parent = SymbolsTree[0], Attributes = new Dictionary <DwarfAttribute, DwarfAttributeValue>() { { DwarfAttribute.Name, new DwarfAttributeValue() { Type = DwarfAttributeValueType.String, Value = "void" } }, { DwarfAttribute.ByteSize, new DwarfAttributeValue() { Type = DwarfAttributeValueType.Constant, Value = (ulong)0 } }, }, }; if (SymbolsTree[0].Children == null) { SymbolsTree[0].Children = new List <DwarfSymbol>(); } SymbolsTree[0].Children.Insert(0, voidSymbol); symbolsByOffset.Add(voidSymbol.Offset, voidSymbol); // Post process all symbols foreach (DwarfSymbol symbol in Symbols) { Dictionary <DwarfAttribute, DwarfAttributeValue> attributes = symbol.Attributes as Dictionary <DwarfAttribute, DwarfAttributeValue>; foreach (DwarfAttributeValue value in attributes.Values) { if (value.Type == DwarfAttributeValueType.Reference) { DwarfSymbol reference; if (symbolsByOffset.TryGetValue((int)value.Address, out reference)) { value.Type = DwarfAttributeValueType.ResolvedReference; value.Value = reference; } } else if (value.Type == DwarfAttributeValueType.Address) { value.Value = value.Address - codeSegmentOffset; } } if ((symbol.Tag == DwarfTag.PointerType && !attributes.ContainsKey(DwarfAttribute.Type)) || (symbol.Tag == DwarfTag.Typedef && !attributes.ContainsKey(DwarfAttribute.Type))) { attributes.Add(DwarfAttribute.Type, new DwarfAttributeValue() { Type = DwarfAttributeValueType.ResolvedReference, Value = voidSymbol, }); } } // Merge specifications foreach (DwarfSymbol symbol in Symbols) { Dictionary <DwarfAttribute, DwarfAttributeValue> attributes = symbol.Attributes as Dictionary <DwarfAttribute, DwarfAttributeValue>; DwarfAttributeValue specificationValue; if (attributes.TryGetValue(DwarfAttribute.Specification, out specificationValue) && specificationValue.Type == DwarfAttributeValueType.ResolvedReference) { DwarfSymbol reference = specificationValue.Reference; Dictionary <DwarfAttribute, DwarfAttributeValue> referenceAttributes = reference.Attributes as Dictionary <DwarfAttribute, DwarfAttributeValue>; foreach (KeyValuePair <DwarfAttribute, DwarfAttributeValue> kvp in attributes) { if (kvp.Key != DwarfAttribute.Specification) { referenceAttributes[kvp.Key] = kvp.Value; } } } } } }
/// <summary> /// Initializes a new instance of the <see cref="DataDescriptionReader"/> class. /// </summary> /// <param name="debugDataDescription">The debug data description.</param> /// <param name="startingPosition">The starting position.</param> public DataDescriptionReader(DwarfMemoryReader debugDataDescription, int startingPosition) { readDescriptions = new Dictionary <uint, DataDescription>(); lastReadPosition = startingPosition; this.debugDataDescription = debugDataDescription; }
/// <summary> /// Initializes a new instance of the <see cref="DwarfCompilationUnit"/> class. /// </summary> /// <param name="debugData">The debug data stream.</param> /// <param name="debugDataDescription">The debug data description stream.</param> /// <param name="debugStrings">The debug strings.</param> /// <param name="addressNormalizer">Normalize address delegate (<see cref="NormalizeAddressDelegate"/>)</param> public DwarfCompilationUnit(DwarfMemoryReader debugData, DwarfMemoryReader debugDataDescription, DwarfMemoryReader debugStrings, NormalizeAddressDelegate addressNormalizer) { ReadData(debugData, debugDataDescription, debugStrings, addressNormalizer); }