/// <summary> /// Try to read elf header. /// </summary> /// <exception cref="ObjectDisposedException"> /// Thrown if the stream was disposed. /// </exception> /// <exception cref="IOException"> /// Thrown in case of any problems during reading. /// </exception> /// <param name="reader">Input stream reader.</param> /// <param name="result">Read header or empty header.</param> /// <returns> /// True if x64 elf header with little endianness and correct elf version was successfully /// read and false otherwise. /// </returns> public static bool TryRead(BinaryReader reader, out ElfHeader result) { result = EmptyHeader; if (!HeadersReadingUtils.IsEnoughBytes(reader, Size)) { return(false); } var ei_magic = reader.ReadInt32(); var ei_bitness = reader.ReadByte(); var ei_endianness = reader.ReadByte(); var ei_version = reader.ReadByte(); var ei_abi = reader.ReadByte(); var ei_abi_version = reader.ReadByte(); var ei_padding = reader.ReadBytes(PaddingSize); var e_type = reader.ReadInt16(); var e_machine = reader.ReadInt16(); var e_version = reader.ReadInt32(); var e_entry = reader.ReadInt64(); // Points to the start of the program header table. var e_phoff = reader.ReadUInt64(); var e_shoff = reader.ReadUInt64(); var e_flags = reader.ReadInt32(); var e_ehsize = reader.ReadUInt16(); // Contains the size of a program header table entry. var e_phentsize = reader.ReadUInt16(); // Contains the number of entries in the program header table. var e_phnum = reader.ReadUInt16(); var e_shentsize = reader.ReadUInt16(); var e_shnum = reader.ReadUInt16(); var e_shstrndx = reader.ReadUInt16(); if (ei_magic != ElfMagicNumber) { Trace.WriteLine($"Invalid ELF magic {ElfMagicNumber} expected {ei_magic}."); return(false); } if (ei_bitness != (byte)Bitness.x64) { Trace.WriteLine("Only 64-bit elf supported."); return(false); } if (ei_endianness != (byte)Endianness.Little) { Trace.WriteLine("Only little endian supported."); return(false); } if (ei_version != CurrentElfVersion) { Trace.WriteLine($"Invalid elf version: {ei_version} expected: " + $"{CurrentElfVersion}."); return(false); } result = new ElfHeader(e_phoff, e_phentsize, e_phnum, e_type == (byte)Type.Executable); return(true); }
DumpReadResult GetModules(BinaryReader dumpReader) { ulong dumpSize = (ulong)dumpReader.BaseStream.Length; var moduleList = new List <DumpModule>(); if (!ElfHeader.TryRead(dumpReader, out ElfHeader elfHeader)) { return(new DumpReadResult(moduleList, DumpReadWarning.ElfHeaderIsCorrupted)); } var fileSections = new List <FileSection>(); var loadSegments = new List <ProgramHeader>(); DumpReadWarning warning = DumpReadWarning.None; // Go through each program header sections, look for the notes sections and the // loadable segments. for (ulong i = 0; i < elfHeader.EntriesCount; ++i) { ulong headerOffset = elfHeader.StartOffset + i * elfHeader.EntrySize; dumpReader.BaseStream.Seek((long)headerOffset, SeekOrigin.Begin); if (!ProgramHeader.TryRead(dumpReader, out ProgramHeader header)) { return(new DumpReadResult(moduleList, DumpReadWarning.FileIsTruncated)); } // Set the warning if the program header is outside of the file. if (header.OffsetInFile + header.SizeInFile > dumpSize && warning == DumpReadWarning.None) { warning = DumpReadWarning.FileIsTruncated; } switch (header.HeaderType) { // We found the notes section. Now we need to extract module section from // the NT_FILE notes. case ProgramHeader.Type.NoteSegment: if (header.SizeInFile > int.MaxValue) { Trace.WriteLine("Can't extract note segment sections from program" + "header. Note size is more then int.Max."); continue; } int size = (int)header.SizeInFile; dumpReader.BaseStream.Seek((long)header.OffsetInFile, SeekOrigin.Begin); byte[] notesBytes = dumpReader.ReadBytes(size); var notesStream = new MemoryStream(notesBytes); using (var notesReader = new BinaryReader(notesStream)) { IEnumerable <FileSection> moduleSections = NoteSection.ReadModuleSections(notesReader, size); fileSections.AddRange(moduleSections); } break; // Collect memory mappings for the core files. case ProgramHeader.Type.LoadableSegment: loadSegments.Add(header); break; } } var loadableSegmentsReader = new ModuleReader(loadSegments, dumpReader); // Go through each module and try to find build id in the mapped regions. foreach (FileSection file in fileSections) { DumpModule module = loadableSegmentsReader.GetModule(file); if (module.Id == BuildId.Empty) { Trace.WriteLine($"Can't find build id for module {module.Path}."); } else { moduleList.Add(module); } } return(new DumpReadResult(moduleList, warning)); }
/// <summary> /// Looks for build id for specified module index in core dump. /// Method also returns information about the module: is it executable and path. /// </summary> /// <returns>Dump module or DumpModule.Empty.</returns> public DumpModule GetModule(FileSection file) { byte[] elfHeaderBytes = ReadBlockByAddress(file.StartAddress, ElfHeader.Size); using (var elfHeaderReader = new BinaryReader(new MemoryStream(elfHeaderBytes))) { if (!ElfHeader.TryRead(elfHeaderReader, out ElfHeader moduleHeader)) { Trace.WriteLine($"Failed to read elf header for module {file.Path}."); return(DumpModule.Empty); } int headersSize = moduleHeader.EntriesCount * moduleHeader.EntrySize; byte[] headerBytes = ReadBlockByAddress(file.StartAddress + moduleHeader.StartOffset, headersSize); using (var headerReader = new BinaryReader(new MemoryStream(headerBytes))) { // Iterate through the program headers, until we find the note with the build // id. for (ulong i = 0; i < moduleHeader.EntriesCount; ++i) { ulong offset = i * moduleHeader.EntrySize; headerReader.BaseStream.Seek((long)offset, SeekOrigin.Begin); if (!ProgramHeader.TryRead(headerReader, out ProgramHeader header)) { Trace.WriteLine( $"Failed to read program header with offset: {offset} " + $"from module {file.Path}."); continue; } if (header.HeaderType != ProgramHeader.Type.NoteSegment) { continue; } ulong fileSize = file.EndAddress - file.StartAddress; ulong headerEnd = header.OffsetInFile + header.SizeInFile; if (headerEnd > fileSize) { Trace.WriteLine( "Can't extract note sections from program header. " + "Note section is outside of the first mapped location."); continue; } if (header.SizeInFile > int.MaxValue) { Trace.WriteLine("Can't extract note sections from program header. " + "Note size is more then int.Max."); continue; } int size = (int)header.SizeInFile; byte[] noteSegmentBytes = ReadBlockByAddress(file.StartAddress + header.OffsetInFile, size); if (noteSegmentBytes.Length < size) { Trace.WriteLine("Can't extract build ids from note section. " + "Note is not fully in load segments."); continue; } var notesStream = new MemoryStream(noteSegmentBytes); using (var notesReader = new BinaryReader(notesStream)) { BuildId buildId = NoteSection.ReadBuildId(notesReader, size); if (buildId != BuildId.Empty) { return(new DumpModule(file.Path, buildId, moduleHeader.IsExecutable)); } } } } } return(DumpModule.Empty); }