private static void AssertReadElfInternal(ElfObjectFile elf, string fileName, bool writeFile = true, string context = null) { if (writeFile) { using (var stream = new FileStream(Path.Combine(Environment.CurrentDirectory, fileName), FileMode.Create)) { elf.Write(stream); stream.Flush(); Assert.AreEqual(stream.Length, (long)elf.Layout.TotalSize); } } var stringWriter = new StringWriter(); elf.Print(stringWriter); var result = stringWriter.ToString().Replace("\r\n", "\n").TrimEnd(); var readelf = LinuxUtil.ReadElf(fileName).TrimEnd(); if (readelf != result) { Console.WriteLine("=== Expected:"); Console.WriteLine(readelf); Console.WriteLine("=== Result:"); Console.WriteLine(result); if (context != null) { Assert.AreEqual(readelf, result, context); } else { Assert.AreEqual(readelf, result); } } }
public void TestDebugLineSmall() { var cppName = "small"; var cppObj = $"{cppName}_debug.o"; LinuxUtil.RunLinuxExe("gcc", $"{cppName}.cpp -g -c -o {cppObj}"); ElfObjectFile elf; using (var inStream = File.OpenRead(cppObj)) { Console.WriteLine($"ReadBack from {cppObj}"); elf = ElfObjectFile.Read(inStream); elf.Print(Console.Out); } var elfContext = new DwarfElfContext(elf); var inputContext = new DwarfReaderContext(elfContext); inputContext.DebugLinePrinter = Console.Out; var dwarf = DwarfFile.Read(inputContext); inputContext.DebugLineStream.Position = 0; var copyInputDebugLineStream = new MemoryStream(); inputContext.DebugLineStream.CopyTo(copyInputDebugLineStream); inputContext.DebugLineStream.Position = 0; var outputContext = new DwarfWriterContext { IsLittleEndian = inputContext.IsLittleEndian, AddressSize = inputContext.AddressSize, DebugLineStream = new MemoryStream() }; dwarf.Write(outputContext); Console.WriteLine(); Console.WriteLine("====================================================="); Console.WriteLine("Readback"); Console.WriteLine("====================================================="); Console.WriteLine(); var reloadContext = new DwarfReaderContext() { IsLittleEndian = outputContext.IsLittleEndian, AddressSize = outputContext.AddressSize, DebugLineStream = outputContext.DebugLineStream }; reloadContext.DebugLineStream.Position = 0; reloadContext.DebugLineStream = outputContext.DebugLineStream; reloadContext.DebugLinePrinter = Console.Out; var dwarf2 = DwarfFile.Read(reloadContext); var inputDebugLineBuffer = copyInputDebugLineStream.ToArray(); var outputDebugLineBuffer = ((MemoryStream)reloadContext.DebugLineStream).ToArray(); Assert.AreEqual(inputDebugLineBuffer, outputDebugLineBuffer); }
public void SimpleDwarf() { var cppName = "helloworld"; var cppExe = $"{cppName}_debug"; LinuxUtil.RunLinuxExe("gcc", $"{cppName}.cpp -g -o {cppExe}"); ElfObjectFile elf; using (var inStream = File.OpenRead(cppExe)) { Console.WriteLine($"ReadBack from {cppExe}"); elf = ElfObjectFile.Read(inStream); elf.Print(Console.Out); } var debugInfo = (ElfCustomSection)elf.Sections.FirstOrDefault(x => x.Name.Value == ".debug_info"); var debugAbbrev = (ElfCustomSection)elf.Sections.FirstOrDefault(x => x.Name.Value == ".debug_abbrev"); var debugStr = (ElfCustomSection)elf.Sections.FirstOrDefault(x => x.Name.Value == ".debug_str"); //var dwarfReader = new DwarfReaderWriter(debugInfo.Stream, debugAbbrev.Stream, debugStr.Stream); DwarfDebugStringTable stringTable = new DwarfDebugStringTable() { Stream = debugStr.Stream }; DwarfDebugAbbrevTable abbrevTable = new DwarfDebugAbbrevTable() { Stream = debugAbbrev.Stream }; var debugInfoReadContext = new DwarfDebugInfoReadContext(stringTable, abbrevTable); DwarfDebugInfoSection.TryRead(debugInfo.Stream, elf.Encoding == ElfEncoding.Lsb, debugInfoReadContext, out var debugInfoSection, out var diagnostics); }
private void ProcessElf(string name, ElfObjectFile elfObjectFile) { foreach (var symbolTable in elfObjectFile.Sections.OfType <ElfSymbolTable>()) { foreach (var symbol in symbolTable.Entries) { if (symbol.Type != ElfSymbolType.Function) { continue; } if (symbol.Bind == ElfSymbolBind.Local) { continue; } if (FunctionRegexFilters.Count > 0) { foreach (var functionRegexFilter in FunctionRegexFilters) { if (functionRegexFilter.Match(symbol.Name).Success) { DumpFunction(symbol); break; } } } else { DumpFunction(symbol); } } } }
protected static void AssertReadElf(ElfObjectFile elf, string fileName) { AssertReadElfInternal(elf, fileName); AssertReadBack(elf, fileName, readAsReadOnly: false); AssertReadBack(elf, fileName, readAsReadOnly: true); AssertLsbMsb(elf, fileName); }
public void Run() { foreach (var file in Files) { using var stream = new FileStream(file, FileMode.Open, FileAccess.Read); if (ArArchiveFile.IsAr(stream)) { var options = new ArArchiveFileReaderOptions(ArArchiveKind.GNU); var archive = ArArchiveFile.Read(stream, options); foreach (var objFile in archive.Files) { if (objFile is ArElfFile elfFile) { ProcessElf(objFile.Name, elfFile.ElfObjectFile); } } } else if (ElfObjectFile.IsElf(stream)) { var elfObjectFile = ElfObjectFile.Read(stream, new ElfReaderOptions() { ReadOnly = true }); ProcessElf(Path.GetFileName(file), elfObjectFile); } } }
private static void AssertReadBack(ElfObjectFile elf, string fileName, bool readAsReadOnly) { ElfObjectFile newObjectFile; var filePath = Path.Combine(Environment.CurrentDirectory, fileName); using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read)) { newObjectFile = ElfObjectFile.Read(stream, new ElfReaderOptions() { ReadOnly = readAsReadOnly }); Console.WriteLine(); Console.WriteLine("============================================================================="); Console.WriteLine($"readback {(readAsReadOnly ? "as readonly" : "as readwrite")}"); Console.WriteLine("============================================================================="); Console.WriteLine(); AssertReadElfInternal(newObjectFile, fileName, false, $"Unexpected error while reading back {fileName}"); var originalBuffer = File.ReadAllBytes(filePath); var memoryStream = new MemoryStream(); newObjectFile.Write(memoryStream); var newBuffer = memoryStream.ToArray(); Assert.AreEqual(originalBuffer, newBuffer, "Invalid binary diff between write -> (original) -> read -> write -> (new)"); } }
public void TestDebugInfoSmall() { var cppName = "small"; var cppObj = $"{cppName}_debug.o"; LinuxUtil.RunLinuxExe("gcc", $"{cppName}.cpp -g -c -o {cppObj}"); ElfObjectFile elf; using (var inStream = File.OpenRead(cppObj)) { elf = ElfObjectFile.Read(inStream); elf.Print(Console.Out); } var elfContext = new DwarfElfContext(elf); var inputContext = new DwarfReaderContext(elfContext); var dwarf = DwarfFile.Read(inputContext); dwarf.AbbreviationTable.Print(Console.Out); dwarf.InfoSection.Print(Console.Out); dwarf.AddressRangeTable.Print(Console.Out); PrintStreamLength(inputContext); Console.WriteLine(); Console.WriteLine("===================================================================="); Console.WriteLine("Write Back"); Console.WriteLine("===================================================================="); var outputContext = new DwarfWriterContext { IsLittleEndian = inputContext.IsLittleEndian, AddressSize = inputContext.AddressSize, DebugAbbrevStream = new MemoryStream(), DebugLineStream = new MemoryStream(), DebugInfoStream = new MemoryStream(), DebugStringStream = new MemoryStream(), DebugAddressRangeStream = new MemoryStream() }; dwarf.Write(outputContext); dwarf.AbbreviationTable.Print(Console.Out); dwarf.InfoSection.Print(Console.Out); dwarf.InfoSection.PrintRelocations(Console.Out); dwarf.AddressRangeTable.Print(Console.Out); dwarf.AddressRangeTable.PrintRelocations(Console.Out); dwarf.WriteToElf(elfContext); var cppObj2 = $"{cppName}_debug2.o"; using (var outStream = new FileStream(cppObj2, FileMode.Create)) { elf.Write(outStream); } PrintStreamLength(outputContext); }
public void TestHelloWorld() { var cppName = "helloworld"; LinuxUtil.RunLinuxExe("gcc", $"{cppName}.cpp -o {cppName}"); ElfObjectFile elf; using (var inStream = File.OpenRead(cppName)) { Console.WriteLine($"ReadBack from {cppName}"); elf = ElfObjectFile.Read(inStream); elf.Print(Console.Out); } using (var outStream = File.OpenWrite($"{cppName}_copy")) { elf.Write(outStream); outStream.Flush(); } var expected = LinuxUtil.ReadElf(cppName); var result = LinuxUtil.ReadElf($"{cppName}_copy"); if (expected != result) { Console.WriteLine("=== Result:"); Console.WriteLine(result); Console.WriteLine("=== Expected:"); Console.WriteLine(expected); Assert.AreEqual(expected, result); } }
protected override void Read(ArArchiveFileReader reader) { var startPosition = reader.Stream.Position; var endPosition = startPosition + (long)Size; ElfObjectFile = ElfObjectFile.Read(new SliceStream(reader.Stream, reader.Stream.Position, (long)Size)); reader.Stream.Position = endPosition; }
public void SimpleEmpty() { var elf = new ElfObjectFile(); for (int i = elf.Sections.Count - 1; i >= 0; i--) { elf.RemoveSectionAt(i); } AssertReadElf(elf, "empty.elf"); }
public void SimpleCodeSectionAndSymbolSection() { var elf = new ElfObjectFile(); var codeStream = new MemoryStream(); codeStream.Write(Encoding.UTF8.GetBytes("This is a text")); codeStream.Position = 0; var codeSection = new ElfCustomSection(codeStream).ConfigureAs(ElfSectionSpecialType.Text); elf.AddSection(codeSection); var stringSection = new ElfStringTable(); elf.AddSection(stringSection); var symbolSection = new ElfSymbolTable() { Link = stringSection, Entries = { new ElfSymbol() { Name = "local_symbol", Bind = ElfSymbolBind.Local, Section = codeSection, Size = 16, Type = ElfSymbolType.Function, Visibility = ElfSymbolVisibility.Protected, Value = 0x7896 }, new ElfSymbol() { Name = "GlobalSymbol", Bind = ElfSymbolBind.Global, Section = codeSection, Size = 4, Type = ElfSymbolType.Function, Value = 0x12345 } } }; elf.AddSection(symbolSection); elf.AddSection(new ElfSectionHeaderStringTable()); AssertReadElf(elf, "test2.elf"); }
private static void AssertLsbMsb(ElfObjectFile elf, string fileName) { Console.WriteLine(); Console.WriteLine("*****************************************************************************"); Console.WriteLine("LSB to MSB"); Console.WriteLine("*****************************************************************************"); Console.WriteLine(); elf.Encoding = ElfEncoding.Msb; var newFileName = Path.GetFileNameWithoutExtension(fileName) + "_msb.elf"; AssertReadElfInternal(elf, newFileName); AssertReadBack(elf, newFileName, readAsReadOnly: false); AssertReadBack(elf, newFileName, readAsReadOnly: true); }
static void CheckInvalidLib(bool isReadOnly) { using var stream = File.OpenRead("TestFiles/cmnlib.b00"); Assert.False(ElfObjectFile.TryRead(stream, out var elf, out var diagnostics, new ElfReaderOptions() { ReadOnly = isReadOnly })); Assert.NotNull(elf); Assert.AreEqual(4, diagnostics.Messages.Count, "Invalid number of error messages found"); Assert.AreEqual(DiagnosticId.ELF_ERR_IncompleteProgramHeader32Size, diagnostics.Messages[0].Id); for (int i = 1; i < diagnostics.Messages.Count; i++) { Assert.AreEqual(DiagnosticId.CMN_ERR_UnexpectedEndOfFile, diagnostics.Messages[i].Id); } }
public void SimpleCodeSection() { var elf = new ElfObjectFile(); var codeStream = new MemoryStream(); codeStream.Write(Encoding.UTF8.GetBytes("This is a text")); codeStream.Position = 0; var codeSection = new ElfCustomSection(codeStream).ConfigureAs(ElfSectionSpecialType.Text); elf.AddSection(codeSection); elf.AddSection(new ElfSectionHeaderStringTable()); AssertReadElf(elf, "test.elf"); }
public void CreateDwarf() { // Create ELF object var elf = new ElfObjectFile(ElfArch.X86_64); var codeSection = new ElfBinarySection(new MemoryStream(new byte[0x64])).ConfigureAs(ElfSectionSpecialType.Text); elf.AddSection(codeSection); var stringSection = new ElfStringTable(); elf.AddSection(stringSection); elf.AddSection(new ElfSymbolTable() { Link = stringSection }); elf.AddSection(new ElfSectionHeaderStringTable()); var elfDiagnostics = new DiagnosticBag(); elf.UpdateLayout(elfDiagnostics); Assert.False(elfDiagnostics.HasErrors); // Create DWARF Object var dwarfFile = new DwarfFile(); // Create .debug_line information var fileName = new DwarfFileName() { Name = "check1.cpp", Directory = Environment.CurrentDirectory, }; var fileName2 = new DwarfFileName() { Name = "check2.cpp", Directory = Environment.CurrentDirectory, }; // First line table for (int i = 0; i < 2; i++) { var lineTable = new DwarfLineProgramTable(); dwarfFile.LineSection.AddLineProgramTable(lineTable); lineTable.AddressSize = DwarfAddressSize.Bit64; lineTable.FileNames.Add(fileName); lineTable.FileNames.Add(fileName2); lineTable.AddLineSequence(new DwarfLineSequence() { new DwarfLine() { File = fileName, Address = 0, Column = 1, Line = 1, }, new DwarfLine() { File = fileName, Address = 1, Column = 1, Line = 2, } } ); // NOTE: doesn't seem to be generated by regular GCC // (it seems that only one line sequence is usually used) lineTable.AddLineSequence(new DwarfLineSequence() { new DwarfLine() { File = fileName2, Address = 0, Column = 1, Line = 1, }, } ); } // Create .debug_info var rootDIE = new DwarfDIECompileUnit() { Name = fileName.Name, LowPC = 0, // 0 relative to base virtual address HighPC = (int)codeSection.Size, // default is offset/length after LowPC CompDir = fileName.Directory, StmtList = dwarfFile.LineSection.LineTables[0], }; var subProgram = new DwarfDIESubprogram() { Name = "MyFunction", }; rootDIE.AddChild(subProgram); var cu = new DwarfCompilationUnit() { AddressSize = DwarfAddressSize.Bit64, Root = rootDIE }; dwarfFile.InfoSection.AddUnit(cu); // AddressRange table dwarfFile.AddressRangeTable.AddressSize = DwarfAddressSize.Bit64; dwarfFile.AddressRangeTable.Unit = cu; dwarfFile.AddressRangeTable.Ranges.Add(new DwarfAddressRange(0, 0, codeSection.Size)); // Transfer DWARF To ELF var dwarfElfContext = new DwarfElfContext(elf); dwarfFile.WriteToElf(dwarfElfContext); var outputFileName = "create_dwarf.o"; using (var output = new FileStream(outputFileName, FileMode.Create)) { elf.Write(output); } elf.Print(Console.Out); Console.WriteLine(); dwarfFile.AbbreviationTable.Print(Console.Out); Console.WriteLine(); dwarfFile.AddressRangeTable.Print(Console.Out); Console.WriteLine(); dwarfFile.InfoSection.Print(Console.Out); Console.WriteLine("ReadBack --debug-dump=rawline"); var readelf = LinuxUtil.ReadElf(outputFileName, "--debug-dump=rawline").TrimEnd(); Console.WriteLine(readelf); }
public DwarfElfContext(ElfObjectFile elf) { Elf = elf ?? throw new ArgumentNullException(nameof(elf)); var relocContext = new ElfRelocationContext(); var codeSection = elf.Sections.OfType <ElfBinarySection>().FirstOrDefault(s => s.Name == ".text"); _symbolTable = elf.Sections.OfType <ElfSymbolTable>().FirstOrDefault(); var mapSectionToSymbolIndex = new Dictionary <ElfSection, int>(); if (_symbolTable != null) { for (var i = 0; i < _symbolTable.Entries.Count; i++) { var entry = _symbolTable.Entries[i]; if (entry.Type == ElfSymbolType.Section && entry.Section.Section != null) { mapSectionToSymbolIndex[entry.Section.Section] = i; } } if (codeSection != null) { if (!mapSectionToSymbolIndex.TryGetValue(codeSection, out _codeSectionSymbolIndex)) { _codeSectionSymbolIndex = _symbolTable.Entries.Count; _symbolTable.Entries.Add(new ElfSymbol() { Type = ElfSymbolType.Section, Section = codeSection, }); } } } foreach (var section in elf.Sections) { switch (section.Name.Value) { case ".debug_info": InfoSection = ((ElfBinarySection)section); mapSectionToSymbolIndex.TryGetValue(InfoSection, out _infoSectionSymbolIndex); break; case ".debug_abbrev": AbbreviationTable = ((ElfBinarySection)section); mapSectionToSymbolIndex.TryGetValue(AbbreviationTable, out _abbreviationTableSymbolIndex); break; case ".debug_aranges": AddressRangeTable = ((ElfBinarySection)section); break; case ".debug_str": StringTable = ((ElfBinarySection)section); mapSectionToSymbolIndex.TryGetValue(StringTable, out _stringTableSymbolIndex); break; case ".debug_line": LineTable = ((ElfBinarySection)section); mapSectionToSymbolIndex.TryGetValue(LineTable, out _lineTableSymbolIndex); break; case ".rela.debug_aranges": case ".rel.debug_aranges": RelocAddressRangeTable = (ElfRelocationTable)section; RelocAddressRangeTable.Relocate(relocContext); break; case ".rela.debug_line": case ".rel.debug_line": RelocLineTable = (ElfRelocationTable)section; RelocLineTable.Relocate(relocContext); break; case ".rela.debug_info": case ".rel.debug_info": RelocInfoSection = (ElfRelocationTable)section; RelocInfoSection.Relocate(relocContext); break; } } }
public void SimpleEmptyWithDefaultSections() { var elf = new ElfObjectFile(); AssertReadElf(elf, "empty_default.elf"); }
public void SimpleProgramHeaderAndCodeSectionAndSymbolSectionAndRelocation() { var arch = ElfArch.X86_64; var elf = new ElfObjectFile(); var codeStream = new MemoryStream(); codeStream.Write(new byte[4096]); var codeSection = elf.AddSection( new ElfCustomSection(codeStream) { VirtualAddress = 0x1000, Alignment = 4096 }.ConfigureAs(ElfSectionSpecialType.Text) ); var dataStream = new MemoryStream(); dataStream.Write(new byte[1024]); var dataSection = elf.AddSection( new ElfCustomSection(dataStream) { VirtualAddress = 0x2000, Alignment = 4096 }.ConfigureAs(ElfSectionSpecialType.ReadOnlyData) ); var stringSection = elf.AddSection(new ElfStringTable()); var symbolSection = elf.AddSection( new ElfSymbolTable() { Link = stringSection, Entries = { new ElfSymbol() { Name = "local_symbol", Bind = ElfSymbolBind.Local, Section = codeSection, Size = 16, Type = ElfSymbolType.Function, Visibility = ElfSymbolVisibility.Protected, Value = 0x7896 }, new ElfSymbol() { Name = "GlobalSymbol", Bind = ElfSymbolBind.Global, Section = codeSection, Size = 4, Type = ElfSymbolType.Function, Value = 0x12345 } } } ); elf.AddSegment( new ElfSegment() { Type = ElfSegmentTypeCore.Load, Range = codeSection, VirtualAddress = 0x1000, PhysicalAddress = 0x1000, Flags = ElfSegmentFlagsCore.Readable | ElfSegmentFlagsCore.Executable, Size = 4096, SizeInMemory = 4096, Alignment = 4096, } ); elf.AddSegment( new ElfSegment() { Type = ElfSegmentTypeCore.Load, Range = dataSection, VirtualAddress = 0x2000, PhysicalAddress = 0x2000, Flags = ElfSegmentFlagsCore.Readable | ElfSegmentFlagsCore.Writable, Size = 1024, SizeInMemory = 1024, Alignment = 4096, } ); var relocTable = elf.AddSection( new ElfRelocationTable { Name = ".rela.text", Link = symbolSection, Info = codeSection, Entries = { new ElfRelocation() { SymbolIndex = 1, Type = ElfRelocationType.R_X86_64_32, Offset = 0 }, new ElfRelocation() { SymbolIndex = 2, Type = ElfRelocationType.R_X86_64_8, Offset = 0 } } } ); elf.AddSection(new ElfSectionHeaderStringTable()); AssertReadElf(elf, "test4.elf"); }
public ArElfFile(ElfObjectFile elfObjectFile) { ElfObjectFile = elfObjectFile; }