|  | 
|  | 1 | +// Licensed to the .NET Foundation under one or more agreements. | 
|  | 2 | +// The .NET Foundation licenses this file to you under the MIT license. | 
|  | 3 | + | 
|  | 4 | +using System; | 
|  | 5 | +using System.Buffers; | 
|  | 6 | +using System.Buffers.Binary; | 
|  | 7 | +using System.Collections.Generic; | 
|  | 8 | +using System.Diagnostics; | 
|  | 9 | +using System.IO; | 
|  | 10 | +using System.Text; | 
|  | 11 | + | 
|  | 12 | +using static ILCompiler.ObjectWriter.CodeViewNative; | 
|  | 13 | + | 
|  | 14 | +namespace ILCompiler.ObjectWriter | 
|  | 15 | +{ | 
|  | 16 | +    internal sealed class CodeViewFileTableBuilder | 
|  | 17 | +    { | 
|  | 18 | +        private readonly MemoryStream _stringTableWriter = new(); | 
|  | 19 | +        private readonly MemoryStream _fileTableWriter = new(); | 
|  | 20 | +        private readonly Dictionary<string, uint> _fileNameToIndex = new(); | 
|  | 21 | + | 
|  | 22 | +        public CodeViewFileTableBuilder() | 
|  | 23 | +        { | 
|  | 24 | +            // Insert empty entry at the beginning of string table | 
|  | 25 | +            _stringTableWriter.Write(stackalloc byte[2] { 0, 0 }); | 
|  | 26 | +        } | 
|  | 27 | + | 
|  | 28 | +        public uint GetFileIndex(string fileName) | 
|  | 29 | +        { | 
|  | 30 | +            if (fileName == "") | 
|  | 31 | +            { | 
|  | 32 | +                // Match the placeholder value from LLVM. We need to use a non-empty | 
|  | 33 | +                // string to ensure that the null terminator of the UTF-8 representation | 
|  | 34 | +                // is not treated as the terminator of the whole file name table. | 
|  | 35 | +                fileName = "<stdin>"; | 
|  | 36 | +            } | 
|  | 37 | + | 
|  | 38 | +            if (_fileNameToIndex.TryGetValue(fileName, out uint fileIndex)) | 
|  | 39 | +            { | 
|  | 40 | +                return fileIndex; | 
|  | 41 | +            } | 
|  | 42 | +            else | 
|  | 43 | +            { | 
|  | 44 | +                uint stringTableIndex = (uint)_stringTableWriter.Position; | 
|  | 45 | +                _stringTableWriter.Write(Encoding.UTF8.GetBytes(fileName)); | 
|  | 46 | +                _stringTableWriter.WriteByte(0); | 
|  | 47 | + | 
|  | 48 | +                uint fileTableIndex = (uint)_fileTableWriter.Position; | 
|  | 49 | +                Span<byte> fileTableEntry = stackalloc byte[sizeof(uint) + sizeof(uint)]; | 
|  | 50 | +                BinaryPrimitives.WriteUInt32LittleEndian(fileTableEntry, stringTableIndex); | 
|  | 51 | +                BinaryPrimitives.WriteUInt32LittleEndian(fileTableEntry.Slice(4), 0); | 
|  | 52 | +                _fileTableWriter.Write(fileTableEntry); | 
|  | 53 | + | 
|  | 54 | +                _fileNameToIndex.Add(fileName, fileTableIndex); | 
|  | 55 | + | 
|  | 56 | +                return fileTableIndex; | 
|  | 57 | +            } | 
|  | 58 | +        } | 
|  | 59 | + | 
|  | 60 | +        public void Write(SectionWriter sectionWriter) | 
|  | 61 | +        { | 
|  | 62 | +            sectionWriter.WriteLittleEndian<uint>((uint)DebugSymbolsSubsectionType.FileChecksums); | 
|  | 63 | +            sectionWriter.WriteLittleEndian<uint>((uint)_fileTableWriter.Length); | 
|  | 64 | +            sectionWriter.EmitData(_fileTableWriter.GetBuffer().AsMemory(0, (int)_fileTableWriter.Length)); | 
|  | 65 | +            sectionWriter.WriteLittleEndian<uint>((uint)DebugSymbolsSubsectionType.StringTable); | 
|  | 66 | +            sectionWriter.WriteLittleEndian<uint>((uint)_stringTableWriter.Length); | 
|  | 67 | +            sectionWriter.EmitData(_stringTableWriter.GetBuffer().AsMemory(0, (int)_stringTableWriter.Length)); | 
|  | 68 | +        } | 
|  | 69 | +    } | 
|  | 70 | +} | 
0 commit comments