File: Compiler\ObjectWriter\CodeView\CodeViewFileTableBuilder.cs
Web Access
Project: src\src\runtime\src\coreclr\tools\aot\ILCompiler.Compiler\ILCompiler.Compiler.csproj (ILCompiler.Compiler)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Buffers;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;

using static ILCompiler.ObjectWriter.CodeViewNative;

namespace ILCompiler.ObjectWriter
{
    internal sealed class CodeViewFileTableBuilder
    {
        private readonly MemoryStream _stringTableWriter = new();
        private readonly MemoryStream _fileTableWriter = new();
        private readonly Dictionary<string, uint> _fileNameToIndex = new();

        public CodeViewFileTableBuilder()
        {
            // Insert empty entry at the beginning of string table
            _stringTableWriter.Write(stackalloc byte[2] { 0, 0 });
        }

        public uint GetFileIndex(string fileName)
        {
            if (fileName == "")
            {
                // Match the placeholder value from LLVM. We need to use a non-empty
                // string to ensure that the null terminator of the UTF-8 representation
                // is not treated as the terminator of the whole file name table.
                fileName = "<stdin>";
            }

            if (_fileNameToIndex.TryGetValue(fileName, out uint fileIndex))
            {
                return fileIndex;
            }
            else
            {
                uint stringTableIndex = (uint)_stringTableWriter.Position;
                _stringTableWriter.Write(Encoding.UTF8.GetBytes(fileName));
                _stringTableWriter.WriteByte(0);

                uint fileTableIndex = (uint)_fileTableWriter.Position;
                Span<byte> fileTableEntry = stackalloc byte[sizeof(uint) + sizeof(uint)];
                BinaryPrimitives.WriteUInt32LittleEndian(fileTableEntry, stringTableIndex);
                BinaryPrimitives.WriteUInt32LittleEndian(fileTableEntry.Slice(4), 0);
                _fileTableWriter.Write(fileTableEntry);

                _fileNameToIndex.Add(fileName, fileTableIndex);

                return fileTableIndex;
            }
        }

        public void Write(SectionWriter sectionWriter)
        {
            sectionWriter.WriteLittleEndian<uint>((uint)DebugSymbolsSubsectionType.FileChecksums);
            sectionWriter.WriteLittleEndian<uint>((uint)_fileTableWriter.Length);
            sectionWriter.EmitData(_fileTableWriter.GetBuffer().AsMemory(0, (int)_fileTableWriter.Length));
            sectionWriter.WriteLittleEndian<uint>((uint)DebugSymbolsSubsectionType.StringTable);
            sectionWriter.WriteLittleEndian<uint>((uint)_stringTableWriter.Length);
            sectionWriter.EmitData(_stringTableWriter.GetBuffer().AsMemory(0, (int)_stringTableWriter.Length));
        }
    }
}