in src/Microsoft.Diagnostics.Runtime/src/Utilities/Platform/LinuxFunctions.cs [59:166]
internal override unsafe bool GetFileVersion(string dll, out int major, out int minor, out int revision, out int patch)
{
using FileStream stream = File.OpenRead(dll);
StreamAddressSpace streamAddressSpace = new StreamAddressSpace(stream);
Reader streamReader = new Reader(streamAddressSpace);
using ElfFile file = new ElfFile(streamReader);
IElfHeader header = file.Header;
ElfSectionHeader headerStringHeader = new ElfSectionHeader(streamReader, header.Is64Bit, header.SectionHeaderOffset + (ulong)header.SectionHeaderStringIndex * header.SectionHeaderEntrySize);
ulong headerStringOffset = headerStringHeader.FileOffset;
ulong dataOffset = 0;
ulong dataSize = 0;
for (uint i = 0; i < header.SectionHeaderCount; i++)
{
if (i == header.SectionHeaderStringIndex)
{
continue;
}
ElfSectionHeader sectionHeader = new ElfSectionHeader(streamReader, header.Is64Bit, header.SectionHeaderOffset + i * header.SectionHeaderEntrySize);
if (sectionHeader.Type == ElfSectionHeaderType.ProgBits)
{
string sectionName = streamReader.ReadNullTerminatedAscii(headerStringOffset + sectionHeader.NameIndex * sizeof(byte));
if (sectionName == ".data")
{
dataOffset = sectionHeader.FileOffset;
dataSize = sectionHeader.FileSize;
break;
}
}
}
DebugOnly.Assert(dataOffset != 0);
DebugOnly.Assert(dataSize != 0);
Span<byte> buffer = stackalloc byte[s_versionLength];
ulong address = dataOffset;
ulong endAddress = address + dataSize;
Span<byte> bytes = stackalloc byte[1];
Span<char> chars = stackalloc char[1];
while (address < endAddress)
{
int read = streamAddressSpace.Read(address, buffer);
if (read < s_versionLength)
{
break;
}
if (!buffer.SequenceEqual(s_versionString))
{
address++;
continue;
}
address += (uint)s_versionLength;
// TODO: This should be cleaned up to not read byte by byte in the future. Leaving it here
// until we decide whether to rewrite the Linux coredumpreader or not.
StringBuilder builder = new StringBuilder();
while (address < endAddress)
{
read = streamAddressSpace.Read(address, bytes);
if (read < bytes.Length)
{
break;
}
if (bytes[0] == '\0')
{
break;
}
if (bytes[0] == ' ')
{
try
{
Version v = Version.Parse(builder.ToString());
major = v.Major;
minor = v.Minor;
revision = v.Build;
patch = v.Revision;
return true;
}
catch (FormatException)
{
break;
}
}
fixed (byte* bytesPtr = &MemoryMarshal.GetReference(bytes))
fixed (char* charsPtr = &MemoryMarshal.GetReference(chars))
{
_ = Encoding.ASCII.GetChars(bytesPtr, bytes.Length, charsPtr, chars.Length);
}
_ = builder.Append(chars[0]);
address++;
}
break;
}
major = minor = revision = patch = 0;
return false;
}