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 | |
21 | static LLVMMetadataRef |
22 | declare_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 | |
32 | int 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 | |
247 | int 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 | |
276 | int 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 | |