|
// 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 ILCompiler.DependencyAnalysis;
using Internal.Text;
using Internal.TypeSystem;
namespace ILCompiler.ObjectWriter
{
internal sealed class DwarfInfoWriter : IDisposable
{
private sealed record InfoReference(uint TypeIndex, int Position, byte[] Data);
private readonly SectionWriter _infoSectionWriter;
private readonly SectionWriter _stringTableWriter;
private readonly SectionWriter _abbrevSectionWriter;
private readonly SectionWriter _locSectionWriter;
private readonly SectionWriter _rangeSectionWriter;
private readonly DwarfBuilder _builder;
private readonly RelocType _codeRelocType;
private readonly List<InfoReference> _lateBoundReferences = new();
private readonly Stack<DwarfAbbrev> _dieStack = new();
private readonly Dictionary<DwarfAbbrev, int> _usedAbbrevs = new();
private readonly ArrayBufferWriter<byte> _expressionBufferWriter = new();
public DwarfInfoWriter(
SectionWriter infoSectionWriter,
SectionWriter stringTableWriter,
SectionWriter abbrevSectionWriter,
SectionWriter locSectionWriter,
SectionWriter rangeSectionWriter,
DwarfBuilder builder,
RelocType codeRelocType)
{
_infoSectionWriter = infoSectionWriter;
_stringTableWriter = stringTableWriter;
_abbrevSectionWriter = abbrevSectionWriter;
_locSectionWriter = locSectionWriter;
_rangeSectionWriter = rangeSectionWriter;
_builder = builder;
_codeRelocType = codeRelocType;
}
public TargetArchitecture TargetArchitecture => _builder.TargetArchitecture;
public int FrameRegister => _builder.FrameRegister;
public byte TargetPointerSize => _builder.TargetPointerSize;
public long Position => _infoSectionWriter.Position;
public void WriteStartDIE(DwarfAbbrev abbrev)
{
if (_dieStack.Count > 0 && !_dieStack.Peek().HasChildren)
{
throw new InvalidOperationException($"Trying to write a children into DIE (Tag {_dieStack.Peek().Tag}) with DW_CHILDREN_no");
}
if (!_usedAbbrevs.TryGetValue(abbrev, out int abbreviationCode))
{
abbreviationCode = _usedAbbrevs.Count + 1;
_usedAbbrevs.Add(abbrev, abbreviationCode);
}
_dieStack.Push(abbrev);
WriteULEB128((ulong)abbreviationCode);
}
public void WriteEndDIE()
{
var abbrev = _dieStack.Pop();
if (abbrev.HasChildren)
{
// End children list
WriteUInt8(0);
}
}
public void Write(ReadOnlySpan<byte> buffer) => _infoSectionWriter.Write(buffer);
public void WriteULEB128(ulong value) => _infoSectionWriter.WriteULEB128(value);
public void WriteUInt8(byte value) => _infoSectionWriter.WriteLittleEndian<byte>(value);
public void WriteUInt16(ushort value) => _infoSectionWriter.WriteLittleEndian<ushort>(value);
public void WriteUInt32(uint value) => _infoSectionWriter.WriteLittleEndian<uint>(value);
public void WriteUInt64(ulong value) => _infoSectionWriter.WriteLittleEndian<ulong>(value);
public void WriteAddressSize(ulong value)
{
switch (TargetPointerSize)
{
case 4: WriteUInt32((uint)value); break;
case 8: WriteUInt64(value); break;
default: throw new NotSupportedException();
}
}
public void WriteStringReference(Utf8String value)
{
long stringsOffset = _stringTableWriter.Position;
_stringTableWriter.WriteUtf8String(value);
Debug.Assert(stringsOffset < uint.MaxValue);
_infoSectionWriter.EmitSymbolReference(RelocType.IMAGE_REL_BASED_HIGHLOW, new Utf8String(".debug_str"u8), stringsOffset);
}
public void WriteStringReference(string value)
{
long stringsOffset = _stringTableWriter.Position;
_stringTableWriter.WriteUtf8String(value);
Debug.Assert(stringsOffset < uint.MaxValue);
_infoSectionWriter.EmitSymbolReference(RelocType.IMAGE_REL_BASED_HIGHLOW, new Utf8String(".debug_str"u8), stringsOffset);
}
public void WriteInfoAbsReference(long offset)
{
Debug.Assert(offset < uint.MaxValue);
WriteUInt32((uint)offset);
}
public void WriteInfoReference(uint typeIndex)
{
uint offset = _builder.ResolveOffset(typeIndex);
if (offset == 0)
{
// Late bound forward reference
var data = new byte[sizeof(uint)];
_lateBoundReferences.Add(new InfoReference(typeIndex, (int)_infoSectionWriter.Position, data));
_infoSectionWriter.EmitData(data);
}
else
{
WriteUInt32(offset);
}
}
public void WriteCodeReference(Utf8String sectionSymbolName, long offset = 0)
{
Debug.Assert(offset >= 0);
_infoSectionWriter.EmitSymbolReference(_codeRelocType, sectionSymbolName, offset);
}
public void WriteLineReference(long offset)
{
Debug.Assert(offset < uint.MaxValue);
_infoSectionWriter.EmitSymbolReference(RelocType.IMAGE_REL_BASED_HIGHLOW, new Utf8String(".debug_line"u8), offset);
}
public DwarfExpressionBuilder GetExpressionBuilder()
{
_expressionBufferWriter.ResetWrittenCount();
return new DwarfExpressionBuilder(TargetArchitecture, TargetPointerSize, _expressionBufferWriter);
}
public void WriteExpression(DwarfExpressionBuilder expressionBuilder)
{
_ = expressionBuilder;
WriteULEB128((uint)_expressionBufferWriter.WrittenCount);
Write(_expressionBufferWriter.WrittenSpan);
}
public void WriteStartLocationList()
{
long offset = _locSectionWriter.Position;
Debug.Assert(offset < uint.MaxValue);
_infoSectionWriter.EmitSymbolReference(RelocType.IMAGE_REL_BASED_HIGHLOW, new Utf8String(".debug_loc"u8), (int)offset);
}
public void WriteLocationListExpression(Utf8String methodName, long startOffset, long endOffset, DwarfExpressionBuilder expressionBuilder)
{
_ = expressionBuilder;
_locSectionWriter.EmitSymbolReference(_codeRelocType, methodName, startOffset);
_locSectionWriter.EmitSymbolReference(_codeRelocType, methodName, endOffset);
_locSectionWriter.WriteLittleEndian<ushort>((ushort)_expressionBufferWriter.WrittenCount);
_locSectionWriter.Write(_expressionBufferWriter.WrittenSpan);
}
public void WriteEndLocationList()
{
_locSectionWriter.WritePadding(TargetPointerSize * 2);
}
public void WriteStartRangeList()
{
long offset = _rangeSectionWriter.Position;
Debug.Assert(offset < uint.MaxValue);
_infoSectionWriter.EmitSymbolReference(RelocType.IMAGE_REL_BASED_HIGHLOW, new Utf8String(".debug_ranges"u8), offset);
}
public void WriteRangeListEntry(Utf8String symbolName, long startOffset, long endOffset)
{
_rangeSectionWriter.EmitSymbolReference(_codeRelocType, symbolName, startOffset);
_rangeSectionWriter.EmitSymbolReference(_codeRelocType, symbolName, endOffset);
}
public void WriteEndRangeList()
{
_rangeSectionWriter.WritePadding(TargetPointerSize * 2);
}
public void Dispose()
{
// Debug.Assert(_dieStack.Count == 0);
// Flush late bound forward references
foreach (var lateBoundReference in _lateBoundReferences)
{
uint offset = _builder.ResolveOffset(lateBoundReference.TypeIndex);
BinaryPrimitives.WriteUInt32LittleEndian(lateBoundReference.Data, offset);
}
// Write abbreviation section
foreach ((DwarfAbbrev abbrev, int abbreviationCode) in _usedAbbrevs)
{
_abbrevSectionWriter.WriteULEB128((ulong)abbreviationCode);
abbrev.Write(_abbrevSectionWriter, TargetPointerSize);
}
_abbrevSectionWriter.Write([0, 0]);
}
}
}
|