diff --git a/Tests/LLVMSharp.UnitTests/DIBuilder.cs b/Tests/LLVMSharp.UnitTests/DIBuilder.cs new file mode 100644 index 00000000..79aa6912 --- /dev/null +++ b/Tests/LLVMSharp.UnitTests/DIBuilder.cs @@ -0,0 +1,65 @@ +using System; +using System.IO; +using LLVMSharp.Interop; +using NUnit.Framework; + +namespace LLVMSharp.UnitTests +{ + public class DIBuilder + { + [Test(Description = "Exercises some DIBuilder functions, does not test the actual debug information is correct")] + public void CreateDebugLocation() + { + string fileName = Path.GetFileName("DIBuilder.c"); + string directory = Path.GetDirectoryName("."); + LLVMModuleRef module = LLVMModuleRef.CreateWithName("netscripten"); + module.Target = "asmjs-unknown-emscripten"; + var dIBuilder = module.CreateDIBuilder(); + var builder = module.Context.CreateBuilder(); + LLVMMetadataRef fileMetadata = dIBuilder.CreateFile(fileName, directory); + + LLVMMetadataRef compileUnitMetadata = dIBuilder.CreateCompileUnit( + LLVMDWARFSourceLanguage.LLVMDWARFSourceLanguageC, + fileMetadata, "ILC", 0 /* Optimized */, String.Empty, 1, String.Empty, + LLVMDWARFEmissionKind.LLVMDWARFEmissionFull, 0, 0, 0); + module.AddNamedMetadataOperand("llvm.dbg.cu", compileUnitMetadata); + + LLVMMetadataRef functionMetaType = dIBuilder.CreateSubroutineType(fileMetadata, + ReadOnlySpan.Empty, LLVMDIFlags.LLVMDIFlagZero); + + uint lineNumber = 1; + var debugFunction = dIBuilder.CreateFunction(fileMetadata, "CreateDebugLocation", "CreateDebugLocation", + fileMetadata, + lineNumber, functionMetaType, 1, 1, lineNumber, 0, 0); + LLVMMetadataRef currentLine = + module.Context.CreateDebugLocation(lineNumber, 0, debugFunction, default(LLVMMetadataRef)); + + LLVMTypeRef[] FooParamTys = {LLVMTypeRef.Int64, LLVMTypeRef.Int64,}; + LLVMTypeRef FooFuncTy = LLVMTypeRef.CreateFunction(LLVMTypeRef.Int64, FooParamTys); + LLVMValueRef FooFunction = module.AddFunction("foo", FooFuncTy); + + var funcBlock = module.Context.AppendBasicBlock(FooFunction, "foo"); + builder.PositionAtEnd(funcBlock); + builder.BuildRet(LLVMValueRef.CreateConstInt(LLVMTypeRef.Int64, 0)); + builder.CurrentDebugLocation = module.Context.MetadataAsValue(currentLine); + var dwarfVersion = LLVMValueRef.CreateMDNode(new[] + { + LLVMValueRef.CreateConstInt(LLVMTypeRef.Int32, 2), module.Context.GetMDString("Dwarf Version", 13), + LLVMValueRef.CreateConstInt(LLVMTypeRef.Int32, 4) + }); + var dwarfSchemaVersion = LLVMValueRef.CreateMDNode(new[] + { + LLVMValueRef.CreateConstInt(LLVMTypeRef.Int32, 2), + module.Context.GetMDString("Debug Info Version", 18), + LLVMValueRef.CreateConstInt(LLVMTypeRef.Int32, 3) + }); + module.AddNamedMetadataOperand("llvm.module.flags", dwarfVersion); + module.AddNamedMetadataOperand("llvm.module.flags", dwarfSchemaVersion); + dIBuilder.DIBuilderFinalize(); + + module.TryVerify(LLVMVerifierFailureAction.LLVMPrintMessageAction, out string message); + + Assert.AreEqual("", message); + } + } +} diff --git a/sources/LLVMSharp/Interop.Extensions/LLVMContextRef.cs b/sources/LLVMSharp/Interop.Extensions/LLVMContextRef.cs index 56bb6c17..b323b7f5 100644 --- a/sources/LLVMSharp/Interop.Extensions/LLVMContextRef.cs +++ b/sources/LLVMSharp/Interop.Extensions/LLVMContextRef.cs @@ -71,12 +71,23 @@ public LLVMBuilderRef CreateBuilder() return LLVM.CreateBuilderInContext(this); } + public LLVMMetadataRef CreateDebugLocation(uint Line, uint Column, LLVMMetadataRef Scope, LLVMMetadataRef InlinedAt) + { + return LLVM.DIBuilderCreateDebugLocation(this, Line, Column, Scope, InlinedAt); + } + public LLVMModuleRef CreateModuleWithName(string ModuleID) { using var marshaledModuleID = new MarshaledString(ModuleID); return LLVM.ModuleCreateWithNameInContext(marshaledModuleID, this); } + public LLVMValueRef MetadataAsValue(LLVMMetadataRef MD) + { + return LLVM.MetadataAsValue(this, MD); + } + + public LLVMTypeRef CreateNamedStruct(string Name) { using var marshaledName = new MarshaledString(Name); diff --git a/sources/LLVMSharp/Interop.Extensions/LLVMDIBuilderRef.cs b/sources/LLVMSharp/Interop.Extensions/LLVMDIBuilderRef.cs index c829e1df..fed19373 100644 --- a/sources/LLVMSharp/Interop.Extensions/LLVMDIBuilderRef.cs +++ b/sources/LLVMSharp/Interop.Extensions/LLVMDIBuilderRef.cs @@ -13,6 +13,50 @@ public LLVMDIBuilderRef(IntPtr handle) public IntPtr Handle; + public LLVMMetadataRef CreateCompileUnit(LLVMDWARFSourceLanguage SourceLanguage, LLVMMetadataRef FileMetadata, string Producer, int IsOptimized, string Flags, uint RuntimeVersion, + string SplitName, LLVMDWARFEmissionKind DwarfEmissionKind, uint DWOld, int SplitDebugInlining, int DebugInfoForProfiling) + { + using var marshaledProducer= new MarshaledString(Producer); + using var marshaledFlags = new MarshaledString(Flags); + using var marshaledSplitNameFlags = new MarshaledString(SplitName); + + return LLVM.DIBuilderCreateCompileUnit(this, SourceLanguage, FileMetadata, marshaledProducer, (UIntPtr)marshaledProducer.Length, IsOptimized, marshaledFlags, (UIntPtr)marshaledFlags.Length, + RuntimeVersion, marshaledSplitNameFlags, (UIntPtr)marshaledSplitNameFlags.Length, DwarfEmissionKind, DWOld, SplitDebugInlining, DebugInfoForProfiling); + } + + public LLVMMetadataRef CreateFile(string FullPath, string Directory) + { + using var marshaledFullPath = new MarshaledString(FullPath); + using var marshaledDirectory = new MarshaledString(Directory); + return LLVM.DIBuilderCreateFile(this, marshaledFullPath, (UIntPtr)marshaledFullPath.Length, marshaledDirectory, (UIntPtr)marshaledDirectory.Length); + } + + public LLVMMetadataRef CreateFunction(LLVMMetadataRef Scope, string Name, string LinkageName, LLVMMetadataRef File, uint LineNo, LLVMMetadataRef Type, int IsLocalToUnit, int IsDefinition, + uint ScopeLine, LLVMDIFlags Flags, int IsOptimized) + { + using var marshaledName = new MarshaledString(Name); + using var marshaledLinkageName = new MarshaledString(LinkageName); + var methodNameLength = (uint)marshaledName.Length; + var linkageNameLength = (uint)marshaledLinkageName.Length; + + return LLVM.DIBuilderCreateFunction(this, Scope, marshaledName, (UIntPtr)(methodNameLength), marshaledLinkageName, (UIntPtr)(linkageNameLength), File, + LineNo, Type, IsLocalToUnit, IsDefinition, ScopeLine, Flags, IsOptimized); + } + + public LLVMMetadataRef CreateSubroutineType(LLVMMetadataRef File, ReadOnlySpan ParameterTypes, LLVMDIFlags Flags) + { + fixed (LLVMMetadataRef* pParameterTypes = ParameterTypes) + { + return LLVM.DIBuilderCreateSubroutineType(this, File, (LLVMOpaqueMetadata**)pParameterTypes, (uint)ParameterTypes.Length, Flags); + } + } + + public void DIBuilderFinalize() + { + LLVM.DIBuilderFinalize(this); + } + + public static implicit operator LLVMDIBuilderRef(LLVMOpaqueDIBuilder* value) { return new LLVMDIBuilderRef((IntPtr)value); diff --git a/sources/LLVMSharp/Interop.Extensions/LLVMModuleRef.cs b/sources/LLVMSharp/Interop.Extensions/LLVMModuleRef.cs index be9bdbd1..f7e6b10a 100644 --- a/sources/LLVMSharp/Interop.Extensions/LLVMModuleRef.cs +++ b/sources/LLVMSharp/Interop.Extensions/LLVMModuleRef.cs @@ -128,6 +128,11 @@ public void AddNamedMetadataOperand(string Name, LLVMValueRef Val) LLVM.AddNamedMetadataOperand(this, marshaledName, Val); } + public LLVMDIBuilderRef CreateDIBuilder() + { + return new LLVMDIBuilderRef((IntPtr)LLVM.CreateDIBuilder(this)); + } + public LLVMExecutionEngineRef CreateExecutionEngine() { if (!TryCreateExecutionEngine(out LLVMExecutionEngineRef EE, out string Error)) @@ -174,6 +179,12 @@ public LLVMExecutionEngineRef CreateMCJITCompiler(ref LLVMMCJITCompilerOptions O public LLVMModuleProviderRef CreateModuleProvider() => LLVM.CreateModuleProviderForExistingModule(this); + public void AddNamedMetadataOperand(string Name, LLVMMetadataRef CompileUnitMetadata) + { + using var marshaledName = new MarshaledString(Name); + LLVM.AddNamedMetadataOperand(this, marshaledName, LLVM.MetadataAsValue(Context, CompileUnitMetadata)); + } + public void Dispose() { if (Handle != IntPtr.Zero) @@ -333,9 +344,16 @@ public bool TryPrintToFile(string Filename, out string ErrorMessage) { using var marshaledFilename = new MarshaledString(Filename); - sbyte* pErrorMessage; - var result = LLVM.PrintModuleToFile(this, marshaledFilename, &pErrorMessage); + sbyte* pErrorMessage = null; + int result = 0; + try + { + result = LLVM.PrintModuleToFile(this, marshaledFilename, &pErrorMessage); + } + catch (Exception) + { + } if (pErrorMessage is null) {