1/*===-- debuginfo.c - tool for testing libLLVM and llvm-c API -------------===*\
2|* *|
3|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *|
4|* Exceptions. *|
5|* See https://llvm.org/LICENSE.txt for license information. *|
6|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *|
7|* *|
8|*===----------------------------------------------------------------------===*|
9|* *|
10|* Tests for the LLVM C DebugInfo API *|
11|* *|
12\*===----------------------------------------------------------------------===*/
13
14#include "llvm-c-test.h"
15#include "llvm-c/DebugInfo.h"
16
17#include <assert.h>
18#include <stdio.h>
19#include <string.h>
20
21static LLVMMetadataRef
22declare_objc_class(LLVMDIBuilderRef DIB, LLVMMetadataRef File) {
23 LLVMMetadataRef Decl = LLVMDIBuilderCreateStructType(Builder: DIB, Scope: File, Name: "TestClass", NameLen: 9, File, LineNumber: 42, SizeInBits: 64, AlignInBits: 0, Flags: LLVMDIFlagObjcClassComplete, NULL, NULL, NumElements: 0, RunTimeLang: 0, NULL, NULL, UniqueIdLen: 0);
24 LLVMMetadataRef SuperDecl = LLVMDIBuilderCreateStructType(Builder: DIB, Scope: File, Name: "TestSuperClass", NameLen: 14, File, LineNumber: 42, SizeInBits: 64, AlignInBits: 0, Flags: LLVMDIFlagObjcClassComplete, NULL, NULL, NumElements: 0, RunTimeLang: 0, NULL, NULL, UniqueIdLen: 0);
25 LLVMDIBuilderCreateInheritance(Builder: DIB, Ty: Decl, BaseTy: SuperDecl, BaseOffset: 0, VBPtrOffset: 0, Flags: 0);
26 LLVMMetadataRef TestProperty =
27 LLVMDIBuilderCreateObjCProperty(Builder: DIB, Name: "test", NameLen: 4, File, LineNo: 42, GetterName: "getTest", GetterNameLen: 7, SetterName: "setTest", SetterNameLen: 7, PropertyAttributes: 0x20 /*copy*/ | 0x40 /*nonatomic*/, Ty: SuperDecl);
28 LLVMDIBuilderCreateObjCIVar(Builder: DIB, Name: "_test", NameLen: 5, File, LineNo: 42, SizeInBits: 64, AlignInBits: 0, OffsetInBits: 64, Flags: LLVMDIFlagPublic, Ty: SuperDecl, PropertyNode: TestProperty);
29 return Decl;
30}
31
32int llvm_test_dibuilder(void) {
33 const char *Filename = "debuginfo.c";
34 LLVMModuleRef M = LLVMModuleCreateWithName(ModuleID: Filename);
35
36 LLVMSetIsNewDbgInfoFormat(M, true);
37 assert(LLVMIsNewDbgInfoFormat(M));
38
39 LLVMDIBuilderRef DIB = LLVMCreateDIBuilder(M);
40
41 LLVMMetadataRef File = LLVMDIBuilderCreateFile(Builder: DIB, Filename,
42 FilenameLen: strlen(s: Filename), Directory: ".", DirectoryLen: 1);
43
44 LLVMMetadataRef CompileUnit = LLVMDIBuilderCreateCompileUnit(
45 Builder: DIB, Lang: LLVMDWARFSourceLanguageC, FileRef: File, Producer: "llvm-c-test", ProducerLen: 11, isOptimized: 0, NULL, FlagsLen: 0, RuntimeVer: 0,
46 NULL, SplitNameLen: 0, Kind: LLVMDWARFEmissionFull, DWOId: 0, SplitDebugInlining: 0, DebugInfoForProfiling: 0, SysRoot: "/", SysRootLen: 1, SDK: "", SDKLen: 0);
47
48 LLVMMetadataRef Module =
49 LLVMDIBuilderCreateModule(Builder: DIB, ParentScope: CompileUnit,
50 Name: "llvm-c-test", NameLen: 11,
51 ConfigMacros: "", ConfigMacrosLen: 0,
52 IncludePath: "/test/include/llvm-c-test.h", IncludePathLen: 27,
53 APINotesFile: "", APINotesFileLen: 0);
54
55 LLVMMetadataRef OtherModule =
56 LLVMDIBuilderCreateModule(Builder: DIB, ParentScope: CompileUnit,
57 Name: "llvm-c-test-import", NameLen: 18,
58 ConfigMacros: "", ConfigMacrosLen: 0,
59 IncludePath: "/test/include/llvm-c-test-import.h", IncludePathLen: 34,
60 APINotesFile: "", APINotesFileLen: 0);
61 LLVMMetadataRef ImportedModule = LLVMDIBuilderCreateImportedModuleFromModule(
62 Builder: DIB, Scope: Module, M: OtherModule, File, Line: 42, NULL, NumElements: 0);
63 LLVMDIBuilderCreateImportedModuleFromAlias(Builder: DIB, Scope: Module, ImportedEntity: ImportedModule, File,
64 Line: 42, NULL, NumElements: 0);
65
66 LLVMMetadataRef ClassTy = declare_objc_class(DIB, File);
67 LLVMMetadataRef GlobalClassValueExpr =
68 LLVMDIBuilderCreateConstantValueExpression(Builder: DIB, Value: 0);
69 LLVMDIBuilderCreateGlobalVariableExpression(
70 Builder: DIB, Scope: Module, Name: "globalClass", NameLen: 11, Linkage: "", LinkLen: 0, File, LineNo: 1, Ty: ClassTy, true,
71 Expr: GlobalClassValueExpr, NULL, AlignInBits: 0);
72
73 LLVMMetadataRef Int64Ty =
74 LLVMDIBuilderCreateBasicType(Builder: DIB, Name: "Int64", NameLen: 5, SizeInBits: 64, Encoding: 0, Flags: LLVMDIFlagZero);
75 LLVMMetadataRef Int64TypeDef =
76 LLVMDIBuilderCreateTypedef(Builder: DIB, Type: Int64Ty, Name: "int64_t", NameLen: 7, File, LineNo: 42, Scope: File, AlignInBits: 0);
77
78 LLVMMetadataRef GlobalVarValueExpr =
79 LLVMDIBuilderCreateConstantValueExpression(Builder: DIB, Value: 0);
80 LLVMDIBuilderCreateGlobalVariableExpression(
81 Builder: DIB, Scope: Module, Name: "global", NameLen: 6, Linkage: "", LinkLen: 0, File, LineNo: 1, Ty: Int64TypeDef, true,
82 Expr: GlobalVarValueExpr, NULL, AlignInBits: 0);
83
84 LLVMMetadataRef NameSpace =
85 LLVMDIBuilderCreateNameSpace(Builder: DIB, ParentScope: Module, Name: "NameSpace", NameLen: 9, false);
86
87 LLVMMetadataRef StructDbgElts[] = {Int64Ty, Int64Ty, Int64Ty};
88 LLVMMetadataRef StructDbgTy =
89 LLVMDIBuilderCreateStructType(Builder: DIB, Scope: NameSpace, Name: "MyStruct",
90 NameLen: 8, File, LineNumber: 0, SizeInBits: 192, AlignInBits: 0, Flags: 0, NULL, Elements: StructDbgElts, NumElements: 3,
91 RunTimeLang: LLVMDWARFSourceLanguageC, NULL, UniqueId: "MyStruct", UniqueIdLen: 8);
92
93 LLVMMetadataRef StructDbgPtrTy =
94 LLVMDIBuilderCreatePointerType(Builder: DIB, PointeeTy: StructDbgTy, SizeInBits: 192, AlignInBits: 0, AddressSpace: 0, Name: "", NameLen: 0);
95
96 LLVMAddNamedMetadataOperand(M, Name: "FooType",
97 Val: LLVMMetadataAsValue(C: LLVMGetModuleContext(M), MD: StructDbgPtrTy));
98
99
100 LLVMTypeRef FooParamTys[] = {
101 LLVMInt64Type(),
102 LLVMInt64Type(),
103 LLVMVectorType(ElementType: LLVMInt64Type(), ElementCount: 10),
104 };
105 LLVMTypeRef FooFuncTy = LLVMFunctionType(ReturnType: LLVMInt64Type(), ParamTypes: FooParamTys, ParamCount: 3, IsVarArg: 0);
106 LLVMValueRef FooFunction = LLVMAddFunction(M, Name: "foo", FunctionTy: FooFuncTy);
107 LLVMBasicBlockRef FooEntryBlock = LLVMAppendBasicBlock(Fn: FooFunction, Name: "entry");
108
109 LLVMMetadataRef Subscripts[] = {
110 LLVMDIBuilderGetOrCreateSubrange(Builder: DIB, LowerBound: 0, Count: 10),
111 };
112 LLVMMetadataRef VectorTy =
113 LLVMDIBuilderCreateVectorType(Builder: DIB, Size: 64 * 10, AlignInBits: 0,
114 Ty: Int64Ty, Subscripts, NumSubscripts: 1);
115
116
117 LLVMMetadataRef ParamTypes[] = {Int64Ty, Int64Ty, VectorTy};
118 LLVMMetadataRef FunctionTy =
119 LLVMDIBuilderCreateSubroutineType(Builder: DIB, File, ParameterTypes: ParamTypes, NumParameterTypes: 3, Flags: 0);
120
121 LLVMMetadataRef ReplaceableFunctionMetadata =
122 LLVMDIBuilderCreateReplaceableCompositeType(Builder: DIB, Tag: 0x15, Name: "foo", NameLen: 3,
123 Scope: File, File, Line: 42,
124 RuntimeLang: 0, SizeInBits: 0, AlignInBits: 0,
125 Flags: LLVMDIFlagFwdDecl,
126 UniqueIdentifier: "", UniqueIdentifierLen: 0);
127
128 LLVMMetadataRef FooParamLocation =
129 LLVMDIBuilderCreateDebugLocation(Ctx: LLVMGetGlobalContext(), Line: 42, Column: 0,
130 Scope: ReplaceableFunctionMetadata, NULL);
131 LLVMMetadataRef FunctionMetadata =
132 LLVMDIBuilderCreateFunction(Builder: DIB, Scope: File, Name: "foo", NameLen: 3, LinkageName: "foo", LinkageNameLen: 3,
133 File, LineNo: 42, Ty: FunctionTy, true, true,
134 ScopeLine: 42, Flags: 0, false);
135 LLVMMetadataReplaceAllUsesWith(TempTargetMetadata: ReplaceableFunctionMetadata, Replacement: FunctionMetadata);
136
137 LLVMMetadataRef FooParamExpression =
138 LLVMDIBuilderCreateExpression(Builder: DIB, NULL, Length: 0);
139 LLVMMetadataRef FooParamVar1 =
140 LLVMDIBuilderCreateParameterVariable(Builder: DIB, Scope: FunctionMetadata, Name: "a", NameLen: 1, ArgNo: 1, File,
141 LineNo: 42, Ty: Int64Ty, true, Flags: 0);
142
143 LLVMDIBuilderInsertDeclareRecordAtEnd(
144 Builder: DIB, Storage: LLVMConstInt(IntTy: LLVMInt64Type(), N: 0, false), VarInfo: FooParamVar1,
145 Expr: FooParamExpression, DebugLoc: FooParamLocation, Block: FooEntryBlock);
146
147 LLVMMetadataRef FooParamVar2 =
148 LLVMDIBuilderCreateParameterVariable(Builder: DIB, Scope: FunctionMetadata, Name: "b", NameLen: 1, ArgNo: 2, File,
149 LineNo: 42, Ty: Int64Ty, true, Flags: 0);
150
151 LLVMDIBuilderInsertDeclareRecordAtEnd(
152 Builder: DIB, Storage: LLVMConstInt(IntTy: LLVMInt64Type(), N: 0, false), VarInfo: FooParamVar2,
153 Expr: FooParamExpression, DebugLoc: FooParamLocation, Block: FooEntryBlock);
154
155 LLVMMetadataRef FooParamVar3 = LLVMDIBuilderCreateParameterVariable(
156 Builder: DIB, Scope: FunctionMetadata, Name: "c", NameLen: 1, ArgNo: 3, File, LineNo: 42, Ty: VectorTy, true, Flags: 0);
157
158 LLVMDIBuilderInsertDeclareRecordAtEnd(
159 Builder: DIB, Storage: LLVMConstInt(IntTy: LLVMInt64Type(), N: 0, false), VarInfo: FooParamVar3,
160 Expr: FooParamExpression, DebugLoc: FooParamLocation, Block: FooEntryBlock);
161
162 LLVMSetSubprogram(Func: FooFunction, SP: FunctionMetadata);
163
164 LLVMMetadataRef FooLexicalBlock =
165 LLVMDIBuilderCreateLexicalBlock(Builder: DIB, Scope: FunctionMetadata, File, Line: 42, Column: 0);
166
167 LLVMBasicBlockRef FooVarBlock = LLVMAppendBasicBlock(Fn: FooFunction, Name: "vars");
168 LLVMMetadataRef FooVarsLocation =
169 LLVMDIBuilderCreateDebugLocation(Ctx: LLVMGetGlobalContext(), Line: 43, Column: 0,
170 Scope: FunctionMetadata, NULL);
171 LLVMMetadataRef FooVar1 =
172 LLVMDIBuilderCreateAutoVariable(Builder: DIB, Scope: FooLexicalBlock, Name: "d", NameLen: 1, File,
173 LineNo: 43, Ty: Int64Ty, true, Flags: 0, AlignInBits: 0);
174 LLVMValueRef FooVal1 = LLVMConstInt(IntTy: LLVMInt64Type(), N: 0, false);
175 LLVMMetadataRef FooVarValueExpr =
176 LLVMDIBuilderCreateConstantValueExpression(Builder: DIB, Value: 0);
177
178 LLVMDIBuilderInsertDbgValueRecordAtEnd(Builder: DIB, Val: FooVal1, VarInfo: FooVar1, Expr: FooVarValueExpr,
179 DebugLoc: FooVarsLocation, Block: FooVarBlock);
180
181 LLVMMetadataRef MacroFile =
182 LLVMDIBuilderCreateTempMacroFile(Builder: DIB, NULL, Line: 0, File);
183 LLVMDIBuilderCreateMacro(Builder: DIB, ParentMacroFile: MacroFile, Line: 0, RecordType: LLVMDWARFMacinfoRecordTypeDefine,
184 Name: "SIMPLE_DEFINE", NameLen: 13, NULL, ValueLen: 0);
185 LLVMDIBuilderCreateMacro(Builder: DIB, ParentMacroFile: MacroFile, Line: 0, RecordType: LLVMDWARFMacinfoRecordTypeDefine,
186 Name: "VALUE_DEFINE", NameLen: 12, Value: "1", ValueLen: 1);
187
188 LLVMMetadataRef EnumeratorTestA =
189 LLVMDIBuilderCreateEnumerator(Builder: DIB, Name: "Test_A", NameLen: strlen(s: "Test_A"), Value: 0, true);
190 LLVMMetadataRef EnumeratorTestB =
191 LLVMDIBuilderCreateEnumerator(Builder: DIB, Name: "Test_B", NameLen: strlen(s: "Test_B"), Value: 1, true);
192 LLVMMetadataRef EnumeratorTestC =
193 LLVMDIBuilderCreateEnumerator(Builder: DIB, Name: "Test_B", NameLen: strlen(s: "Test_C"), Value: 2, true);
194 LLVMMetadataRef EnumeratorsTest[] = {EnumeratorTestA, EnumeratorTestB,
195 EnumeratorTestC};
196 LLVMMetadataRef EnumTest = LLVMDIBuilderCreateEnumerationType(
197 Builder: DIB, Scope: NameSpace, Name: "EnumTest", NameLen: strlen(s: "EnumTest"), File, LineNumber: 0, SizeInBits: 64, AlignInBits: 0,
198 Elements: EnumeratorsTest, NumElements: 3, ClassTy: Int64Ty);
199 LLVMAddNamedMetadataOperand(
200 M, Name: "EnumTest", Val: LLVMMetadataAsValue(C: LLVMGetModuleContext(M), MD: EnumTest));
201
202 LLVMDIBuilderFinalize(Builder: DIB);
203
204 // Using the new debug format, debug records get attached to instructions.
205 // Insert a `br` and `ret` now to absorb the debug records which are
206 // currently "trailing", meaning that they're associated with a block
207 // but no particular instruction, which is only valid as a transient state.
208 LLVMContextRef Ctx = LLVMGetModuleContext(M);
209 LLVMBuilderRef Builder = LLVMCreateBuilderInContext(C: Ctx);
210 LLVMPositionBuilderAtEnd(Builder, Block: FooEntryBlock);
211 // Build `br label %vars` in entry.
212 LLVMBuildBr(Builder, Dest: FooVarBlock);
213 // Build `ret i64 0` in vars.
214 LLVMPositionBuilderAtEnd(Builder, Block: FooVarBlock);
215 LLVMTypeRef I64 = LLVMInt64TypeInContext(C: Ctx);
216 LLVMValueRef Zero = LLVMConstInt(IntTy: I64, N: 0, false);
217 LLVMValueRef Ret = LLVMBuildRet(Builder, V: Zero);
218
219 // Insert a `phi` before the `ret`. In the new debug info mode we need to
220 // be careful to insert before debug records too, else the debug records
221 // will come before the `phi` (and be absorbed onto it) which is an invalid
222 // state.
223 LLVMValueRef InsertPos = LLVMGetFirstInstruction(BB: FooVarBlock);
224 LLVMPositionBuilderBeforeInstrAndDbgRecords(Builder, Instr: InsertPos);
225 LLVMValueRef Phi1 = LLVMBuildPhi(Builder, Ty: I64, Name: "p1");
226 LLVMAddIncoming(PhiNode: Phi1, IncomingValues: &Zero, IncomingBlocks: &FooEntryBlock, Count: 1);
227 // Do the same again using the other position-setting function.
228 LLVMPositionBuilderBeforeDbgRecords(Builder, Block: FooVarBlock, Inst: InsertPos);
229 LLVMValueRef Phi2 = LLVMBuildPhi(Builder, Ty: I64, Name: "p2");
230 LLVMAddIncoming(PhiNode: Phi2, IncomingValues: &Zero, IncomingBlocks: &FooEntryBlock, Count: 1);
231 // Insert a non-phi before the `ret` but not before the debug records to
232 // test that works as expected.
233 LLVMPositionBuilder(Builder, Block: FooVarBlock, Instr: Ret);
234 LLVMBuildAdd(Builder, LHS: Phi1, RHS: Phi2, Name: "a");
235
236 char *MStr = LLVMPrintModuleToString(M);
237 puts(s: MStr);
238 LLVMDisposeMessage(Message: MStr);
239
240 LLVMDisposeBuilder(Builder);
241 LLVMDisposeDIBuilder(Builder: DIB);
242 LLVMDisposeModule(M);
243
244 return 0;
245}
246
247int llvm_get_di_tag(void) {
248 LLVMModuleRef M = LLVMModuleCreateWithName(ModuleID: "Mod");
249 LLVMContextRef Context = LLVMGetModuleContext(M);
250
251 const char String[] = "foo";
252 LLVMMetadataRef StringMD =
253 LLVMMDStringInContext2(C: Context, Str: String, SLen: strlen(s: String));
254 LLVMMetadataRef NodeMD = LLVMMDNodeInContext2(C: Context, MDs: &StringMD, Count: 1);
255 assert(LLVMGetDINodeTag(NodeMD) == 0);
256 (void)NodeMD;
257
258 LLVMDIBuilderRef Builder = LLVMCreateDIBuilder(M);
259 const char Filename[] = "metadata.c";
260 const char Directory[] = ".";
261 LLVMMetadataRef File = LLVMDIBuilderCreateFile(
262 Builder, Filename, FilenameLen: strlen(s: Filename), Directory, DirectoryLen: strlen(s: Directory));
263 const char Name[] = "TestClass";
264 LLVMMetadataRef Struct = LLVMDIBuilderCreateStructType(
265 Builder, Scope: File, Name, NameLen: strlen(s: Name), File, LineNumber: 42, SizeInBits: 64, AlignInBits: 0,
266 Flags: LLVMDIFlagObjcClassComplete, NULL, NULL, NumElements: 0, RunTimeLang: 0, NULL, NULL, UniqueIdLen: 0);
267 assert(LLVMGetDINodeTag(Struct) == 0x13);
268 (void)Struct;
269
270 LLVMDisposeDIBuilder(Builder);
271 LLVMDisposeModule(M);
272
273 return 0;
274}
275
276int llvm_di_type_get_name(void) {
277 LLVMModuleRef M = LLVMModuleCreateWithName(ModuleID: "Mod");
278
279 LLVMDIBuilderRef Builder = LLVMCreateDIBuilder(M);
280 const char Filename[] = "metadata.c";
281 const char Directory[] = ".";
282 LLVMMetadataRef File = LLVMDIBuilderCreateFile(
283 Builder, Filename, FilenameLen: strlen(s: Filename), Directory, DirectoryLen: strlen(s: Directory));
284 const char Name[] = "TestClass";
285 LLVMMetadataRef Struct = LLVMDIBuilderCreateStructType(
286 Builder, Scope: File, Name, NameLen: strlen(s: Name), File, LineNumber: 42, SizeInBits: 64, AlignInBits: 0,
287 Flags: LLVMDIFlagObjcClassComplete, NULL, NULL, NumElements: 0, RunTimeLang: 0, NULL, NULL, UniqueIdLen: 0);
288
289 size_t Len;
290 const char *TypeName = LLVMDITypeGetName(DType: Struct, Length: &Len);
291 assert(Len == strlen(Name));
292 assert(strncmp(TypeName, Name, Len) == 0);
293 (void)TypeName;
294
295 LLVMDisposeDIBuilder(Builder);
296 LLVMDisposeModule(M);
297
298 return 0;
299}
300