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 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); } }
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); }
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 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 CheckLibraryWithELF() { var cppName = "helloworld"; var cppObj = $"{cppName}.o"; var cppLib = $"lib{cppName}.a"; File.Delete(cppObj); File.Delete(cppLib); LinuxUtil.RunLinuxExe("gcc", $"{cppName}.cpp -c -o {cppObj}"); LinuxUtil.RunLinuxExe("ar", $"rcs {cppLib} {cppObj}"); using (var stream = new FileStream(cppLib, FileMode.Open, FileAccess.Read)) { Assert.True(ArArchiveFile.IsAr(stream)); var arFile = ArArchiveFile.Read(stream, new ArArchiveFileReaderOptions(ArArchiveKind.GNU) { ProcessObjectFiles = false }); var elfFile = arFile.Files.FirstOrDefault(x => x.Name == cppObj); Assert.NotNull(elfFile, $"Unable to find {cppObj} file in {cppLib}"); Assert.NotNull(arFile.SymbolTable, $"Unable to find symbol table in {cppLib}"); Assert.AreEqual(1, arFile.SymbolTable.Symbols.Count, "Invalid number of symbols in Symbol table"); Assert.AreEqual("main", arFile.SymbolTable.Symbols[0].Name, "Invalid symbol found"); Assert.AreEqual(elfFile, arFile.SymbolTable.Symbols[0].File, "Invalid symbol to file found"); var outStream = new MemoryStream(); arFile.Write(outStream); var newArray = outStream.ToArray(); outStream.Position = 0; var cppLibCopy = $"lib{cppName}_copy.a"; using (var copyStream = new FileStream(cppLibCopy, FileMode.Create, FileAccess.Write)) { outStream.CopyTo(copyStream); } var originalStream = new MemoryStream(); stream.Position = 0; stream.CopyTo(originalStream); var originalArray = originalStream.ToArray(); Assert.AreEqual(originalArray, newArray, $"Non binary matching between file {cppLib} and {cppLibCopy}"); } }
public void CheckCreateArLibrary() { var libName = "libcustom.a"; var file = new ArArchiveFile(); using (var stream = new FileStream(libName, FileMode.Create, FileAccess.Write)) { var symbolTable = new ArSymbolTable(); file.AddFile(symbolTable); file.AddFile(new ArBinaryFile() { Name = "file2.txt", OwnerId = 0666, Stream = new MemoryStream(Encoding.UTF8.GetBytes("this is file")) }); file.AddFile(new ArBinaryFile() { Name = "file3.txt", OwnerId = 0777, GroupId = 0744, Stream = new MemoryStream(Encoding.UTF8.GetBytes("this is file3")) }); file.AddFile(new ArBinaryFile() { Name = "file4.txt", OwnerId = 0777, GroupId = 0744, Stream = new MemoryStream(Encoding.UTF8.GetBytes("this is file4")) }); file.AddFile(new ArBinaryFile() { Name = "file5.txt", OwnerId = 0706, GroupId = 0705, FileMode = 0x123456, Stream = new MemoryStream(Encoding.UTF8.GetBytes("this is file5")) }); file.AddFile(new ArBinaryFile() { Name = "long_file_name_large_file6.txt", Timestamp = DateTimeOffset.UtcNow.AddSeconds(-2), Stream = new MemoryStream(Encoding.UTF8.GetBytes("this is file6 yoyo")) }); symbolTable.Symbols.Add(new ArSymbol() { File = file.Files[1], Name = "my_symbol" }); file.Write(stream); stream.Flush(); } // Check that AR is able to read back what we just serialized { var fileNameBuilder = new StringBuilder(); foreach (var fileEntry in file.Files) { if (fileEntry.IsSystem) { continue; } fileNameBuilder.Append($"{fileEntry.Name}\n"); } var fileNameList = fileNameBuilder.ToString().Trim(); var fileNameListFromAr = LinuxUtil.RunLinuxExe("ar", $"t {libName}").Trim(); Assert.AreEqual(fileNameListFromAr, fileNameList); } // Display the content of each file via AR { var contentBuilder = new StringBuilder(); foreach (var fileEntry in file.Files) { if (!(fileEntry is ArBinaryFile arBinary)) { continue; } arBinary.Stream.Position = 0; contentBuilder.Append(Encoding.UTF8.GetString(((MemoryStream)arBinary.Stream).ToArray())); } var content = contentBuilder.ToString().Trim(); var contentFromAr = LinuxUtil.RunLinuxExe("ar", $"p {libName}").Trim(); Assert.AreEqual(contentFromAr, content); } ArArchiveFile file2; using (var stream = new FileStream(libName, FileMode.Open, FileAccess.Read)) { file2 = ArArchiveFile.Read(stream, ArArchiveKind.GNU); } Assert.NotNull(file2.SymbolTable); CompareArFiles(file, file2); var libNameBsd = "libcustom_bsd.a"; file.Kind = ArArchiveKind.BSD; using (var stream = new FileStream(libNameBsd, FileMode.Create, FileAccess.Write)) { file.Write(stream); stream.Flush(); } ArArchiveFile archiveFileBsd; using (var stream = new FileStream(libNameBsd, FileMode.Open, FileAccess.Read)) { archiveFileBsd = ArArchiveFile.Read(stream, ArArchiveKind.BSD); } CompareArFiles(file, archiveFileBsd); }
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); }