| File: Compiler\ObjectWriter\Dwarf\DwarfEhFrame.cs | Web Access |
| Project: 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.Collections.Generic; using System.Buffers.Binary; using ILCompiler.DependencyAnalysis; using Internal.Text; using static ILCompiler.ObjectWriter.DwarfNative; namespace ILCompiler.ObjectWriter { internal sealed class DwarfEhFrame { private readonly SectionWriter _sectionWriter; private readonly bool _is64Bit; private readonly Dictionary<DwarfCie, uint> _cieOffset = new(); public DwarfEhFrame(SectionWriter sectionWriter, bool is64Bit) { _sectionWriter = sectionWriter; _is64Bit = is64Bit; } public void AddCie(DwarfCie cie) { _cieOffset.Add(cie, (uint)_sectionWriter.Position); WriteCie(cie); } public void AddFde(in DwarfFde fde) { uint cieOffset; if (!_cieOffset.TryGetValue(fde.Cie, out cieOffset)) { AddCie(fde.Cie); cieOffset = _cieOffset[fde.Cie]; } WriteFde(fde, cieOffset); } private static uint PaddingSize(uint length, uint alignment) { return ((length + alignment - 1u) & ~(alignment - 1u)) - length; } private void WriteCie(DwarfCie cie) { Utf8StringBuilder augmentationString = new Utf8StringBuilder(); uint augmentationLength = 0; if (cie.FdesHaveAugmentationData) { augmentationString.Append('z'); } if (cie.PersonalitySymbolName != null) { augmentationString.Append('P'); augmentationLength += 1u + AddressSize(cie.PersonalityEncoding); } if (cie.LsdaEncoding != 0) { augmentationString.Append('L'); augmentationLength++; } if (cie.PointerEncoding != 0) { augmentationString.Append('R'); augmentationLength++; } if (cie.IsSignalFrame) { augmentationString.Append('S'); } uint length = 4u + // Length 4u + // CIE Offset (0) 1u + // Version (uint)augmentationString.Length + 1u + // null-terminator DwarfHelper.SizeOfULEB128(cie.CodeAlignFactor) + DwarfHelper.SizeOfSLEB128(cie.DataAlignFactor) + DwarfHelper.SizeOfULEB128(cie.ReturnAddressRegister) + (uint)(augmentationLength > 0 ? DwarfHelper.SizeOfULEB128(augmentationLength) + augmentationLength : 0) + (uint)cie.Instructions.Length; uint padding = PaddingSize(length, AddressSize(cie.PointerEncoding)); _sectionWriter.WriteLittleEndian<uint>(length + padding - 4u); _sectionWriter.WriteLittleEndian<uint>(0); _sectionWriter.WriteByte(cie.ReturnAddressRegister < 0x7F ? (byte)1u : (byte)3u); // Version _sectionWriter.Write(augmentationString.AsSpan()); _sectionWriter.WriteByte(0); // null-terminator _sectionWriter.WriteULEB128(cie.CodeAlignFactor); _sectionWriter.WriteSLEB128(cie.DataAlignFactor); _sectionWriter.WriteULEB128(cie.ReturnAddressRegister); _sectionWriter.WriteULEB128(augmentationLength); if (cie.PersonalitySymbolName != null) { _sectionWriter.WriteByte(cie.PersonalityEncoding); WriteAddress(cie.PersonalityEncoding, new Utf8String(cie.PersonalitySymbolName)); } if (cie.LsdaEncoding != 0) { _sectionWriter.WriteByte(cie.LsdaEncoding); } if (cie.PointerEncoding != 0) { _sectionWriter.WriteByte(cie.PointerEncoding); } _sectionWriter.Write(cie.Instructions); _sectionWriter.WritePadding((int)padding); } private void WriteFde(in DwarfFde fde, uint cieOffset) { uint augmentationLength = fde.Cie.FdesHaveAugmentationData ? 1u + // Length (fde.Cie.PersonalityEncoding != 0 ? AddressSize(fde.Cie.PersonalityEncoding) : 0) + (fde.Cie.LsdaEncoding != 0 ? AddressSize(fde.Cie.LsdaEncoding) : 0) : 0; uint pointerEncodingSize = AddressSize(fde.Cie.PointerEncoding); uint length = 4u + // Length 4u + // CIE offset pointerEncodingSize + // PC start pointerEncodingSize + // PC end augmentationLength + (uint)fde.Instructions.Length; uint padding = PaddingSize(length, pointerEncodingSize); _sectionWriter.WriteLittleEndian<uint>(length + padding - 4u); _sectionWriter.WriteLittleEndian<uint>((uint)(_sectionWriter.Position - cieOffset)); WriteAddress(fde.Cie.PointerEncoding, fde.PcStartSymbolName, fde.PcStartSymbolOffset); WriteSize(fde.Cie.PointerEncoding, fde.PcLength); if (fde.Cie.FdesHaveAugmentationData) { _sectionWriter.WriteByte((byte)(augmentationLength - 1)); if (fde.Cie.PersonalityEncoding != 0) { WriteAddress(fde.Cie.PersonalityEncoding, fde.PersonalitySymbolName); } if (fde.Cie.LsdaEncoding != 0) { WriteAddress(fde.Cie.LsdaEncoding, fde.LsdaSymbolName); } } _sectionWriter.Write(fde.Instructions); _sectionWriter.WritePadding((int)padding); } private uint AddressSize(byte encoding) { switch (encoding & 0xF) { case DW_EH_PE_ptr: return _is64Bit ? 8u : 4u; case DW_EH_PE_sdata4: return 4u; default: throw new NotSupportedException(); } } private void WriteAddress(byte encoding, Utf8String symbolName, long symbolOffset = 0) { if (!symbolName.IsNull) { RelocType relocationType = encoding switch { DW_EH_PE_pcrel | DW_EH_PE_sdata4 => RelocType.IMAGE_REL_BASED_RELPTR32, DW_EH_PE_absptr => RelocType.IMAGE_REL_BASED_DIR64, _ => throw new NotSupportedException() }; _sectionWriter.EmitSymbolReference(relocationType, symbolName, symbolOffset); } else { _sectionWriter.WritePadding((int)AddressSize(encoding)); } } private void WriteSize(byte encoding, ulong size) { if (AddressSize(encoding) == 4) { _sectionWriter.WriteLittleEndian<uint>((uint)size); } else { _sectionWriter.WriteLittleEndian<ulong>(size); } } } }