| /*===-- debuginfo.c - tool for testing libLLVM and llvm-c API -------------===*\ |
| |* *| |
| |* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| |
| |* Exceptions. *| |
| |* See https://llvm.org/LICENSE.txt for license information. *| |
| |* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| |
| |* *| |
| |*===----------------------------------------------------------------------===*| |
| |* *| |
| |* Tests for the LLVM C DebugInfo API *| |
| |* *| |
| \*===----------------------------------------------------------------------===*/ |
| |
| #include "llvm-c/DebugInfo.h" |
| #include "llvm-c-test.h" |
| #include "llvm-c/Core.h" |
| #include "llvm-c/Types.h" |
| |
| #include <assert.h> |
| #include <stdio.h> |
| #include <string.h> |
| |
| static LLVMMetadataRef |
| declare_objc_class(LLVMDIBuilderRef DIB, LLVMMetadataRef File) { |
| LLVMMetadataRef Decl = LLVMDIBuilderCreateStructType(DIB, File, "TestClass", 9, File, 42, 64, 0, LLVMDIFlagObjcClassComplete, NULL, NULL, 0, 0, NULL, NULL, 0); |
| LLVMMetadataRef SuperDecl = LLVMDIBuilderCreateStructType(DIB, File, "TestSuperClass", 14, File, 42, 64, 0, LLVMDIFlagObjcClassComplete, NULL, NULL, 0, 0, NULL, NULL, 0); |
| LLVMDIBuilderCreateInheritance(DIB, Decl, SuperDecl, 0, 0, 0); |
| LLVMMetadataRef TestProperty = |
| LLVMDIBuilderCreateObjCProperty(DIB, "test", 4, File, 42, "getTest", 7, "setTest", 7, 0x20 /*copy*/ | 0x40 /*nonatomic*/, SuperDecl); |
| LLVMDIBuilderCreateObjCIVar(DIB, "_test", 5, File, 42, 64, 0, 64, LLVMDIFlagPublic, SuperDecl, TestProperty); |
| return Decl; |
| } |
| |
| int llvm_test_dibuilder(void) { |
| const char *Filename = "debuginfo.c"; |
| LLVMModuleRef M = LLVMModuleCreateWithName(Filename); |
| |
| LLVMSetIsNewDbgInfoFormat(M, true); |
| assert(LLVMIsNewDbgInfoFormat(M)); |
| |
| LLVMDIBuilderRef DIB = LLVMCreateDIBuilder(M); |
| |
| LLVMMetadataRef File = LLVMDIBuilderCreateFile(DIB, Filename, |
| strlen(Filename), ".", 1); |
| |
| LLVMMetadataRef CompileUnit = LLVMDIBuilderCreateCompileUnit( |
| DIB, LLVMDWARFSourceLanguageC, File, "llvm-c-test", 11, 0, NULL, 0, 0, |
| NULL, 0, LLVMDWARFEmissionFull, 0, 0, 0, "/", 1, "", 0); |
| |
| LLVMMetadataRef Module = |
| LLVMDIBuilderCreateModule(DIB, CompileUnit, |
| "llvm-c-test", 11, |
| "", 0, |
| "/test/include/llvm-c-test.h", 27, |
| "", 0); |
| |
| LLVMMetadataRef OtherModule = |
| LLVMDIBuilderCreateModule(DIB, CompileUnit, |
| "llvm-c-test-import", 18, |
| "", 0, |
| "/test/include/llvm-c-test-import.h", 34, |
| "", 0); |
| LLVMMetadataRef ImportedModule = LLVMDIBuilderCreateImportedModuleFromModule( |
| DIB, Module, OtherModule, File, 42, NULL, 0); |
| LLVMDIBuilderCreateImportedModuleFromAlias(DIB, Module, ImportedModule, File, |
| 42, NULL, 0); |
| |
| LLVMMetadataRef ClassTy = declare_objc_class(DIB, File); |
| LLVMMetadataRef GlobalClassValueExpr = |
| LLVMDIBuilderCreateConstantValueExpression(DIB, 0); |
| LLVMDIBuilderCreateGlobalVariableExpression( |
| DIB, Module, "globalClass", 11, "", 0, File, 1, ClassTy, true, |
| GlobalClassValueExpr, NULL, 0); |
| |
| LLVMMetadataRef Int64Ty = |
| LLVMDIBuilderCreateBasicType(DIB, "Int64", 5, 64, 0, LLVMDIFlagZero); |
| LLVMMetadataRef Int64TypeDef = |
| LLVMDIBuilderCreateTypedef(DIB, Int64Ty, "int64_t", 7, File, 42, File, 0); |
| |
| LLVMMetadataRef GlobalVarValueExpr = |
| LLVMDIBuilderCreateConstantValueExpression(DIB, 0); |
| LLVMDIBuilderCreateGlobalVariableExpression( |
| DIB, Module, "global", 6, "", 0, File, 1, Int64TypeDef, true, |
| GlobalVarValueExpr, NULL, 0); |
| |
| LLVMMetadataRef NameSpace = |
| LLVMDIBuilderCreateNameSpace(DIB, Module, "NameSpace", 9, false); |
| |
| LLVMMetadataRef StructDbgElts[] = {Int64Ty, Int64Ty, Int64Ty}; |
| LLVMMetadataRef StructDbgTy = |
| LLVMDIBuilderCreateStructType(DIB, NameSpace, "MyStruct", |
| 8, File, 0, 192, 0, 0, NULL, StructDbgElts, 3, |
| LLVMDWARFSourceLanguageC, NULL, "MyStruct", 8); |
| |
| LLVMMetadataRef StructDbgPtrTy = |
| LLVMDIBuilderCreatePointerType(DIB, StructDbgTy, 192, 0, 0, "", 0); |
| |
| LLVMAddNamedMetadataOperand(M, "FooType", |
| LLVMMetadataAsValue(LLVMGetModuleContext(M), StructDbgPtrTy)); |
| |
| |
| LLVMTypeRef FooParamTys[] = { |
| LLVMInt64Type(), |
| LLVMInt64Type(), |
| LLVMVectorType(LLVMInt64Type(), 10), |
| }; |
| LLVMTypeRef FooFuncTy = LLVMFunctionType(LLVMInt64Type(), FooParamTys, 3, 0); |
| LLVMValueRef FooFunction = LLVMAddFunction(M, "foo", FooFuncTy); |
| LLVMBasicBlockRef FooEntryBlock = LLVMAppendBasicBlock(FooFunction, "entry"); |
| |
| LLVMMetadataRef Subscripts[] = { |
| LLVMDIBuilderGetOrCreateSubrange(DIB, 0, 10), |
| }; |
| LLVMMetadataRef VectorTy = |
| LLVMDIBuilderCreateVectorType(DIB, 64 * 10, 0, |
| Int64Ty, Subscripts, 1); |
| |
| |
| LLVMMetadataRef ParamTypes[] = {Int64Ty, Int64Ty, VectorTy}; |
| LLVMMetadataRef FunctionTy = |
| LLVMDIBuilderCreateSubroutineType(DIB, File, ParamTypes, 3, 0); |
| |
| LLVMMetadataRef ReplaceableFunctionMetadata = |
| LLVMDIBuilderCreateReplaceableCompositeType(DIB, 0x15, "foo", 3, |
| File, File, 42, |
| 0, 0, 0, |
| LLVMDIFlagFwdDecl, |
| "", 0); |
| |
| LLVMMetadataRef FooParamLocation = |
| LLVMDIBuilderCreateDebugLocation(LLVMGetGlobalContext(), 42, 0, |
| ReplaceableFunctionMetadata, NULL); |
| LLVMMetadataRef FunctionMetadata = |
| LLVMDIBuilderCreateFunction(DIB, File, "foo", 3, "foo", 3, |
| File, 42, FunctionTy, true, true, |
| 42, 0, false); |
| LLVMMetadataReplaceAllUsesWith(ReplaceableFunctionMetadata, FunctionMetadata); |
| |
| LLVMMetadataRef FooParamExpression = |
| LLVMDIBuilderCreateExpression(DIB, NULL, 0); |
| LLVMMetadataRef FooParamVar1 = |
| LLVMDIBuilderCreateParameterVariable(DIB, FunctionMetadata, "a", 1, 1, File, |
| 42, Int64Ty, true, 0); |
| |
| LLVMDIBuilderInsertDeclareRecordAtEnd( |
| DIB, LLVMConstInt(LLVMInt64Type(), 0, false), FooParamVar1, |
| FooParamExpression, FooParamLocation, FooEntryBlock); |
| |
| LLVMMetadataRef FooParamVar2 = |
| LLVMDIBuilderCreateParameterVariable(DIB, FunctionMetadata, "b", 1, 2, File, |
| 42, Int64Ty, true, 0); |
| |
| LLVMDIBuilderInsertDeclareRecordAtEnd( |
| DIB, LLVMConstInt(LLVMInt64Type(), 0, false), FooParamVar2, |
| FooParamExpression, FooParamLocation, FooEntryBlock); |
| |
| LLVMMetadataRef FooParamVar3 = LLVMDIBuilderCreateParameterVariable( |
| DIB, FunctionMetadata, "c", 1, 3, File, 42, VectorTy, true, 0); |
| |
| LLVMDIBuilderInsertDeclareRecordAtEnd( |
| DIB, LLVMConstInt(LLVMInt64Type(), 0, false), FooParamVar3, |
| FooParamExpression, FooParamLocation, FooEntryBlock); |
| |
| LLVMSetSubprogram(FooFunction, FunctionMetadata); |
| |
| LLVMMetadataRef FooLabel1 = LLVMDIBuilderCreateLabel(DIB, FunctionMetadata, |
| "label1", 6, File, 42, false); |
| LLVMDIBuilderInsertLabelAtEnd(DIB, FooLabel1, FooParamLocation, |
| FooEntryBlock); |
| |
| LLVMMetadataRef FooLexicalBlock = |
| LLVMDIBuilderCreateLexicalBlock(DIB, FunctionMetadata, File, 42, 0); |
| |
| LLVMBasicBlockRef FooVarBlock = LLVMAppendBasicBlock(FooFunction, "vars"); |
| LLVMMetadataRef FooVarsLocation = |
| LLVMDIBuilderCreateDebugLocation(LLVMGetGlobalContext(), 43, 0, |
| FunctionMetadata, NULL); |
| LLVMMetadataRef FooVar1 = |
| LLVMDIBuilderCreateAutoVariable(DIB, FooLexicalBlock, "d", 1, File, |
| 43, Int64Ty, true, 0, 0); |
| LLVMValueRef FooVal1 = LLVMConstInt(LLVMInt64Type(), 0, false); |
| LLVMMetadataRef FooVarValueExpr1 = |
| LLVMDIBuilderCreateConstantValueExpression(DIB, 0); |
| |
| LLVMDIBuilderInsertDbgValueRecordAtEnd( |
| DIB, FooVal1, FooVar1, FooVarValueExpr1, FooVarsLocation, FooVarBlock); |
| |
| LLVMMetadataRef FooVar2 = LLVMDIBuilderCreateAutoVariable( |
| DIB, FooLexicalBlock, "e", 1, File, 44, Int64Ty, true, 0, 0); |
| LLVMValueRef FooVal2 = LLVMConstInt(LLVMInt64Type(), 1, false); |
| LLVMMetadataRef FooVarValueExpr2 = |
| LLVMDIBuilderCreateConstantValueExpression(DIB, 1); |
| |
| LLVMDIBuilderInsertDbgValueRecordAtEnd( |
| DIB, FooVal2, FooVar2, FooVarValueExpr2, FooVarsLocation, FooVarBlock); |
| |
| LLVMMetadataRef MacroFile = |
| LLVMDIBuilderCreateTempMacroFile(DIB, NULL, 0, File); |
| LLVMDIBuilderCreateMacro(DIB, MacroFile, 0, LLVMDWARFMacinfoRecordTypeDefine, |
| "SIMPLE_DEFINE", 13, NULL, 0); |
| LLVMDIBuilderCreateMacro(DIB, MacroFile, 0, LLVMDWARFMacinfoRecordTypeDefine, |
| "VALUE_DEFINE", 12, "1", 1); |
| |
| LLVMMetadataRef EnumeratorTestA = |
| LLVMDIBuilderCreateEnumerator(DIB, "Test_A", strlen("Test_A"), 0, true); |
| LLVMMetadataRef EnumeratorTestB = |
| LLVMDIBuilderCreateEnumerator(DIB, "Test_B", strlen("Test_B"), 1, true); |
| LLVMMetadataRef EnumeratorTestC = |
| LLVMDIBuilderCreateEnumerator(DIB, "Test_B", strlen("Test_C"), 2, true); |
| LLVMMetadataRef EnumeratorsTest[] = {EnumeratorTestA, EnumeratorTestB, |
| EnumeratorTestC}; |
| LLVMMetadataRef EnumTest = LLVMDIBuilderCreateEnumerationType( |
| DIB, NameSpace, "EnumTest", strlen("EnumTest"), File, 0, 64, 0, |
| EnumeratorsTest, 3, Int64Ty); |
| LLVMAddNamedMetadataOperand( |
| M, "EnumTest", LLVMMetadataAsValue(LLVMGetModuleContext(M), EnumTest)); |
| |
| // Using the new debug format, debug records get attached to instructions. |
| // Insert a `br` and `ret` now to absorb the debug records which are |
| // currently "trailing", meaning that they're associated with a block |
| // but no particular instruction, which is only valid as a transient state. |
| LLVMContextRef Ctx = LLVMGetModuleContext(M); |
| LLVMBuilderRef Builder = LLVMCreateBuilderInContext(Ctx); |
| LLVMPositionBuilderAtEnd(Builder, FooEntryBlock); |
| // Build `br label %vars` in entry. |
| LLVMBuildBr(Builder, FooVarBlock); |
| |
| // Build another br for the sake of testing labels. |
| LLVMMetadataRef FooLabel2 = LLVMDIBuilderCreateLabel(DIB, FunctionMetadata, |
| "label2", 6, File, 42, false); |
| LLVMDIBuilderInsertLabelBefore(DIB, FooLabel2, FooParamLocation, |
| LLVMBuildBr(Builder, FooVarBlock)); |
| // label3 will be emitted, but label4 won't be emitted |
| // because label3 is AlwaysPreserve and label4 is not. |
| LLVMDIBuilderCreateLabel(DIB, FunctionMetadata, |
| "label3", 6, File, 42, true); |
| LLVMDIBuilderCreateLabel(DIB, FunctionMetadata, |
| "label4", 6, File, 42, false); |
| LLVMDIBuilderFinalize(DIB); |
| |
| // Build `ret i64 0` in vars. |
| LLVMPositionBuilderAtEnd(Builder, FooVarBlock); |
| LLVMTypeRef I64 = LLVMInt64TypeInContext(Ctx); |
| LLVMValueRef Zero = LLVMConstInt(I64, 0, false); |
| LLVMValueRef Ret = LLVMBuildRet(Builder, Zero); |
| |
| // Insert a `phi` before the `ret`. In the new debug info mode we need to |
| // be careful to insert before debug records too, else the debug records |
| // will come before the `phi` (and be absorbed onto it) which is an invalid |
| // state. |
| LLVMValueRef InsertPos = LLVMGetFirstInstruction(FooVarBlock); |
| LLVMPositionBuilderBeforeInstrAndDbgRecords(Builder, InsertPos); |
| LLVMValueRef Phi1 = LLVMBuildPhi(Builder, I64, "p1"); |
| LLVMAddIncoming(Phi1, &Zero, &FooEntryBlock, 1); |
| |
| // Do the same again using the other position-setting function. |
| LLVMPositionBuilderBeforeDbgRecords(Builder, FooVarBlock, InsertPos); |
| LLVMValueRef Phi2 = LLVMBuildPhi(Builder, I64, "p2"); |
| LLVMAddIncoming(Phi2, &Zero, &FooEntryBlock, 1); |
| |
| // Insert a non-phi before the `ret` but not before the debug records to |
| // test that works as expected. |
| LLVMPositionBuilder(Builder, FooVarBlock, Ret); |
| LLVMValueRef Add = LLVMBuildAdd(Builder, Phi1, Phi2, "a"); |
| |
| // Iterate over debug records in the add instruction. There should be two. |
| LLVMDbgRecordRef AddDbgRecordFirst = LLVMGetFirstDbgRecord(Add); |
| assert(AddDbgRecordFirst != NULL); |
| LLVMDbgRecordRef AddDbgRecordSecond = LLVMGetNextDbgRecord(AddDbgRecordFirst); |
| assert(AddDbgRecordSecond != NULL); |
| LLVMDbgRecordRef AddDbgRecordLast = LLVMGetLastDbgRecord(Add); |
| assert(AddDbgRecordLast != NULL); |
| (void)AddDbgRecordLast; |
| assert(AddDbgRecordSecond == AddDbgRecordLast); |
| LLVMDbgRecordRef AddDbgRecordOverTheRange = |
| LLVMGetNextDbgRecord(AddDbgRecordSecond); |
| assert(AddDbgRecordOverTheRange == NULL); |
| (void)AddDbgRecordOverTheRange; |
| LLVMDbgRecordRef AddDbgRecordFirstPrev = |
| LLVMGetPreviousDbgRecord(AddDbgRecordSecond); |
| assert(AddDbgRecordFirstPrev != NULL); |
| assert(AddDbgRecordFirst == AddDbgRecordFirstPrev); |
| LLVMDbgRecordRef AddDbgRecordUnderTheRange = |
| LLVMGetPreviousDbgRecord(AddDbgRecordFirstPrev); |
| assert(AddDbgRecordUnderTheRange == NULL); |
| (void)AddDbgRecordUnderTheRange; |
| |
| char *MStr = LLVMPrintModuleToString(M); |
| puts(MStr); |
| LLVMDisposeMessage(MStr); |
| |
| LLVMDisposeBuilder(Builder); |
| LLVMDisposeDIBuilder(DIB); |
| LLVMDisposeModule(M); |
| |
| return 0; |
| } |
| |
| int llvm_get_di_tag(void) { |
| LLVMModuleRef M = LLVMModuleCreateWithName("Mod"); |
| LLVMContextRef Context = LLVMGetModuleContext(M); |
| |
| const char String[] = "foo"; |
| LLVMMetadataRef StringMD = |
| LLVMMDStringInContext2(Context, String, strlen(String)); |
| LLVMMetadataRef NodeMD = LLVMMDNodeInContext2(Context, &StringMD, 1); |
| assert(LLVMGetDINodeTag(NodeMD) == 0); |
| (void)NodeMD; |
| |
| LLVMDIBuilderRef Builder = LLVMCreateDIBuilder(M); |
| const char Filename[] = "metadata.c"; |
| const char Directory[] = "."; |
| LLVMMetadataRef File = LLVMDIBuilderCreateFile( |
| Builder, Filename, strlen(Filename), Directory, strlen(Directory)); |
| const char Name[] = "TestClass"; |
| LLVMMetadataRef Struct = LLVMDIBuilderCreateStructType( |
| Builder, File, Name, strlen(Name), File, 42, 64, 0, |
| LLVMDIFlagObjcClassComplete, NULL, NULL, 0, 0, NULL, NULL, 0); |
| assert(LLVMGetDINodeTag(Struct) == 0x13); |
| (void)Struct; |
| |
| LLVMDisposeDIBuilder(Builder); |
| LLVMDisposeModule(M); |
| |
| return 0; |
| } |
| |
| int llvm_di_type_get_name(void) { |
| LLVMModuleRef M = LLVMModuleCreateWithName("Mod"); |
| |
| LLVMDIBuilderRef Builder = LLVMCreateDIBuilder(M); |
| const char Filename[] = "metadata.c"; |
| const char Directory[] = "."; |
| LLVMMetadataRef File = LLVMDIBuilderCreateFile( |
| Builder, Filename, strlen(Filename), Directory, strlen(Directory)); |
| const char Name[] = "TestClass"; |
| LLVMMetadataRef Struct = LLVMDIBuilderCreateStructType( |
| Builder, File, Name, strlen(Name), File, 42, 64, 0, |
| LLVMDIFlagObjcClassComplete, NULL, NULL, 0, 0, NULL, NULL, 0); |
| |
| size_t Len; |
| const char *TypeName = LLVMDITypeGetName(Struct, &Len); |
| assert(Len == strlen(Name)); |
| assert(strncmp(TypeName, Name, Len) == 0); |
| (void)TypeName; |
| |
| LLVMDisposeDIBuilder(Builder); |
| LLVMDisposeModule(M); |
| |
| return 0; |
| } |