xref: /llvm-project/llvm/tools/llvm-c-test/debuginfo.c (revision f23bdbbaff5b89b1c102a155d062fc32f99d4a92)
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/DebugInfo.h"
15 #include "llvm-c-test.h"
16 #include "llvm-c/Core.h"
17 #include "llvm-c/Types.h"
18 
19 #include <assert.h>
20 #include <stdio.h>
21 #include <string.h>
22 
23 static LLVMMetadataRef
24 declare_objc_class(LLVMDIBuilderRef DIB, LLVMMetadataRef File) {
25   LLVMMetadataRef Decl = LLVMDIBuilderCreateStructType(DIB, File, "TestClass", 9, File, 42, 64, 0, LLVMDIFlagObjcClassComplete, NULL, NULL, 0, 0, NULL, NULL, 0);
26   LLVMMetadataRef SuperDecl = LLVMDIBuilderCreateStructType(DIB, File, "TestSuperClass", 14, File, 42, 64, 0, LLVMDIFlagObjcClassComplete, NULL, NULL, 0, 0, NULL, NULL, 0);
27   LLVMDIBuilderCreateInheritance(DIB, Decl, SuperDecl, 0, 0, 0);
28   LLVMMetadataRef TestProperty =
29       LLVMDIBuilderCreateObjCProperty(DIB, "test", 4, File, 42, "getTest", 7, "setTest", 7, 0x20 /*copy*/ | 0x40 /*nonatomic*/, SuperDecl);
30   LLVMDIBuilderCreateObjCIVar(DIB, "_test", 5, File, 42, 64, 0, 64, LLVMDIFlagPublic, SuperDecl, TestProperty);
31   return Decl;
32 }
33 
34 int llvm_test_dibuilder(void) {
35   const char *Filename = "debuginfo.c";
36   LLVMModuleRef M = LLVMModuleCreateWithName(Filename);
37 
38   LLVMSetIsNewDbgInfoFormat(M, true);
39   assert(LLVMIsNewDbgInfoFormat(M));
40 
41   LLVMDIBuilderRef DIB = LLVMCreateDIBuilder(M);
42 
43   LLVMMetadataRef File = LLVMDIBuilderCreateFile(DIB, Filename,
44     strlen(Filename), ".", 1);
45 
46   LLVMMetadataRef CompileUnit = LLVMDIBuilderCreateCompileUnit(
47       DIB, LLVMDWARFSourceLanguageC, File, "llvm-c-test", 11, 0, NULL, 0, 0,
48       NULL, 0, LLVMDWARFEmissionFull, 0, 0, 0, "/", 1, "", 0);
49 
50   LLVMMetadataRef Module =
51     LLVMDIBuilderCreateModule(DIB, CompileUnit,
52                               "llvm-c-test", 11,
53                               "", 0,
54                               "/test/include/llvm-c-test.h", 27,
55                               "", 0);
56 
57   LLVMMetadataRef OtherModule =
58     LLVMDIBuilderCreateModule(DIB, CompileUnit,
59                               "llvm-c-test-import", 18,
60                               "", 0,
61                               "/test/include/llvm-c-test-import.h", 34,
62                               "", 0);
63   LLVMMetadataRef ImportedModule = LLVMDIBuilderCreateImportedModuleFromModule(
64       DIB, Module, OtherModule, File, 42, NULL, 0);
65   LLVMDIBuilderCreateImportedModuleFromAlias(DIB, Module, ImportedModule, File,
66                                              42, NULL, 0);
67 
68   LLVMMetadataRef ClassTy = declare_objc_class(DIB, File);
69   LLVMMetadataRef GlobalClassValueExpr =
70       LLVMDIBuilderCreateConstantValueExpression(DIB, 0);
71   LLVMDIBuilderCreateGlobalVariableExpression(
72       DIB, Module, "globalClass", 11, "", 0, File, 1, ClassTy, true,
73       GlobalClassValueExpr, NULL, 0);
74 
75   LLVMMetadataRef Int64Ty =
76       LLVMDIBuilderCreateBasicType(DIB, "Int64", 5, 64, 0, LLVMDIFlagZero);
77   LLVMMetadataRef Int64TypeDef =
78       LLVMDIBuilderCreateTypedef(DIB, Int64Ty, "int64_t", 7, File, 42, File, 0);
79 
80   LLVMMetadataRef GlobalVarValueExpr =
81       LLVMDIBuilderCreateConstantValueExpression(DIB, 0);
82   LLVMDIBuilderCreateGlobalVariableExpression(
83       DIB, Module, "global", 6, "", 0, File, 1, Int64TypeDef, true,
84       GlobalVarValueExpr, NULL, 0);
85 
86   LLVMMetadataRef NameSpace =
87       LLVMDIBuilderCreateNameSpace(DIB, Module, "NameSpace", 9, false);
88 
89   LLVMMetadataRef StructDbgElts[] = {Int64Ty, Int64Ty, Int64Ty};
90   LLVMMetadataRef StructDbgTy =
91     LLVMDIBuilderCreateStructType(DIB, NameSpace, "MyStruct",
92     8, File, 0, 192, 0, 0, NULL, StructDbgElts, 3,
93     LLVMDWARFSourceLanguageC, NULL, "MyStruct", 8);
94 
95   LLVMMetadataRef StructDbgPtrTy =
96     LLVMDIBuilderCreatePointerType(DIB, StructDbgTy, 192, 0, 0, "", 0);
97 
98   LLVMAddNamedMetadataOperand(M, "FooType",
99     LLVMMetadataAsValue(LLVMGetModuleContext(M), StructDbgPtrTy));
100 
101 
102   LLVMTypeRef FooParamTys[] = {
103     LLVMInt64Type(),
104     LLVMInt64Type(),
105     LLVMVectorType(LLVMInt64Type(), 10),
106   };
107   LLVMTypeRef FooFuncTy = LLVMFunctionType(LLVMInt64Type(), FooParamTys, 3, 0);
108   LLVMValueRef FooFunction = LLVMAddFunction(M, "foo", FooFuncTy);
109   LLVMBasicBlockRef FooEntryBlock = LLVMAppendBasicBlock(FooFunction, "entry");
110 
111   LLVMMetadataRef Subscripts[] = {
112     LLVMDIBuilderGetOrCreateSubrange(DIB, 0, 10),
113   };
114   LLVMMetadataRef VectorTy =
115     LLVMDIBuilderCreateVectorType(DIB, 64 * 10, 0,
116                                   Int64Ty, Subscripts, 1);
117 
118 
119   LLVMMetadataRef ParamTypes[] = {Int64Ty, Int64Ty, VectorTy};
120   LLVMMetadataRef FunctionTy =
121     LLVMDIBuilderCreateSubroutineType(DIB, File, ParamTypes, 3, 0);
122 
123   LLVMMetadataRef ReplaceableFunctionMetadata =
124     LLVMDIBuilderCreateReplaceableCompositeType(DIB, 0x15, "foo", 3,
125                                                 File, File, 42,
126                                                 0, 0, 0,
127                                                 LLVMDIFlagFwdDecl,
128                                                 "", 0);
129 
130   LLVMMetadataRef FooParamLocation =
131     LLVMDIBuilderCreateDebugLocation(LLVMGetGlobalContext(), 42, 0,
132                                      ReplaceableFunctionMetadata, NULL);
133   LLVMMetadataRef FunctionMetadata =
134     LLVMDIBuilderCreateFunction(DIB, File, "foo", 3, "foo", 3,
135                                 File, 42, FunctionTy, true, true,
136                                 42, 0, false);
137   LLVMMetadataReplaceAllUsesWith(ReplaceableFunctionMetadata, FunctionMetadata);
138 
139   LLVMMetadataRef FooParamExpression =
140     LLVMDIBuilderCreateExpression(DIB, NULL, 0);
141   LLVMMetadataRef FooParamVar1 =
142     LLVMDIBuilderCreateParameterVariable(DIB, FunctionMetadata, "a", 1, 1, File,
143                                          42, Int64Ty, true, 0);
144 
145   LLVMDIBuilderInsertDeclareRecordAtEnd(
146       DIB, LLVMConstInt(LLVMInt64Type(), 0, false), FooParamVar1,
147       FooParamExpression, FooParamLocation, FooEntryBlock);
148 
149   LLVMMetadataRef FooParamVar2 =
150     LLVMDIBuilderCreateParameterVariable(DIB, FunctionMetadata, "b", 1, 2, File,
151                                          42, Int64Ty, true, 0);
152 
153   LLVMDIBuilderInsertDeclareRecordAtEnd(
154       DIB, LLVMConstInt(LLVMInt64Type(), 0, false), FooParamVar2,
155       FooParamExpression, FooParamLocation, FooEntryBlock);
156 
157   LLVMMetadataRef FooParamVar3 = LLVMDIBuilderCreateParameterVariable(
158       DIB, FunctionMetadata, "c", 1, 3, File, 42, VectorTy, true, 0);
159 
160   LLVMDIBuilderInsertDeclareRecordAtEnd(
161       DIB, LLVMConstInt(LLVMInt64Type(), 0, false), FooParamVar3,
162       FooParamExpression, FooParamLocation, FooEntryBlock);
163 
164   LLVMSetSubprogram(FooFunction, FunctionMetadata);
165 
166   LLVMMetadataRef FooLabel1 = LLVMDIBuilderCreateLabel(DIB, FunctionMetadata,
167     "label1", 6, File, 42, false);
168   LLVMDIBuilderInsertLabelAtEnd(DIB, FooLabel1, FooParamLocation,
169     FooEntryBlock);
170 
171   LLVMMetadataRef FooLexicalBlock =
172     LLVMDIBuilderCreateLexicalBlock(DIB, FunctionMetadata, File, 42, 0);
173 
174   LLVMBasicBlockRef FooVarBlock = LLVMAppendBasicBlock(FooFunction, "vars");
175   LLVMMetadataRef FooVarsLocation =
176     LLVMDIBuilderCreateDebugLocation(LLVMGetGlobalContext(), 43, 0,
177                                      FunctionMetadata, NULL);
178   LLVMMetadataRef FooVar1 =
179     LLVMDIBuilderCreateAutoVariable(DIB, FooLexicalBlock, "d", 1, File,
180                                     43, Int64Ty, true, 0, 0);
181   LLVMValueRef FooVal1 = LLVMConstInt(LLVMInt64Type(), 0, false);
182   LLVMMetadataRef FooVarValueExpr1 =
183       LLVMDIBuilderCreateConstantValueExpression(DIB, 0);
184 
185   LLVMDIBuilderInsertDbgValueRecordAtEnd(
186       DIB, FooVal1, FooVar1, FooVarValueExpr1, FooVarsLocation, FooVarBlock);
187 
188   LLVMMetadataRef FooVar2 = LLVMDIBuilderCreateAutoVariable(
189       DIB, FooLexicalBlock, "e", 1, File, 44, Int64Ty, true, 0, 0);
190   LLVMValueRef FooVal2 = LLVMConstInt(LLVMInt64Type(), 1, false);
191   LLVMMetadataRef FooVarValueExpr2 =
192       LLVMDIBuilderCreateConstantValueExpression(DIB, 1);
193 
194   LLVMDIBuilderInsertDbgValueRecordAtEnd(
195       DIB, FooVal2, FooVar2, FooVarValueExpr2, FooVarsLocation, FooVarBlock);
196 
197   LLVMMetadataRef MacroFile =
198       LLVMDIBuilderCreateTempMacroFile(DIB, NULL, 0, File);
199   LLVMDIBuilderCreateMacro(DIB, MacroFile, 0, LLVMDWARFMacinfoRecordTypeDefine,
200                            "SIMPLE_DEFINE", 13, NULL, 0);
201   LLVMDIBuilderCreateMacro(DIB, MacroFile, 0, LLVMDWARFMacinfoRecordTypeDefine,
202                            "VALUE_DEFINE", 12, "1", 1);
203 
204   LLVMMetadataRef EnumeratorTestA =
205       LLVMDIBuilderCreateEnumerator(DIB, "Test_A", strlen("Test_A"), 0, true);
206   LLVMMetadataRef EnumeratorTestB =
207       LLVMDIBuilderCreateEnumerator(DIB, "Test_B", strlen("Test_B"), 1, true);
208   LLVMMetadataRef EnumeratorTestC =
209       LLVMDIBuilderCreateEnumerator(DIB, "Test_B", strlen("Test_C"), 2, true);
210   LLVMMetadataRef EnumeratorsTest[] = {EnumeratorTestA, EnumeratorTestB,
211                                        EnumeratorTestC};
212   LLVMMetadataRef EnumTest = LLVMDIBuilderCreateEnumerationType(
213       DIB, NameSpace, "EnumTest", strlen("EnumTest"), File, 0, 64, 0,
214       EnumeratorsTest, 3, Int64Ty);
215   LLVMAddNamedMetadataOperand(
216       M, "EnumTest", LLVMMetadataAsValue(LLVMGetModuleContext(M), EnumTest));
217 
218   // Using the new debug format, debug records get attached to instructions.
219   // Insert a `br` and `ret` now to absorb the debug records which are
220   // currently "trailing", meaning that they're associated with a block
221   // but no particular instruction, which is only valid as a transient state.
222   LLVMContextRef Ctx = LLVMGetModuleContext(M);
223   LLVMBuilderRef Builder = LLVMCreateBuilderInContext(Ctx);
224   LLVMPositionBuilderAtEnd(Builder, FooEntryBlock);
225   // Build `br label %vars` in entry.
226   LLVMBuildBr(Builder, FooVarBlock);
227 
228   // Build another br for the sake of testing labels.
229   LLVMMetadataRef FooLabel2 = LLVMDIBuilderCreateLabel(DIB, FunctionMetadata,
230     "label2", 6, File, 42, false);
231   LLVMDIBuilderInsertLabelBefore(DIB, FooLabel2, FooParamLocation,
232     LLVMBuildBr(Builder, FooVarBlock));
233   // label3 will be emitted, but label4 won't be emitted
234   // because label3 is AlwaysPreserve and label4 is not.
235   LLVMDIBuilderCreateLabel(DIB, FunctionMetadata,
236     "label3", 6, File, 42, true);
237   LLVMDIBuilderCreateLabel(DIB, FunctionMetadata,
238     "label4", 6, File, 42, false);
239   LLVMDIBuilderFinalize(DIB);
240 
241   // Build `ret i64 0` in vars.
242   LLVMPositionBuilderAtEnd(Builder, FooVarBlock);
243   LLVMTypeRef I64 = LLVMInt64TypeInContext(Ctx);
244   LLVMValueRef Zero = LLVMConstInt(I64, 0, false);
245   LLVMValueRef Ret = LLVMBuildRet(Builder, Zero);
246 
247   // Insert a `phi` before the `ret`. In the new debug info mode we need to
248   // be careful to insert before debug records too, else the debug records
249   // will come before the `phi` (and be absorbed onto it) which is an invalid
250   // state.
251   LLVMValueRef InsertPos = LLVMGetFirstInstruction(FooVarBlock);
252   LLVMPositionBuilderBeforeInstrAndDbgRecords(Builder, InsertPos);
253   LLVMValueRef Phi1 = LLVMBuildPhi(Builder, I64, "p1");
254   LLVMAddIncoming(Phi1, &Zero, &FooEntryBlock, 1);
255 
256   // Do the same again using the other position-setting function.
257   LLVMPositionBuilderBeforeDbgRecords(Builder, FooVarBlock, InsertPos);
258   LLVMValueRef Phi2 = LLVMBuildPhi(Builder, I64, "p2");
259   LLVMAddIncoming(Phi2, &Zero, &FooEntryBlock, 1);
260 
261   // Insert a non-phi before the `ret` but not before the debug records to
262   // test that works as expected.
263   LLVMPositionBuilder(Builder, FooVarBlock, Ret);
264   LLVMValueRef Add = LLVMBuildAdd(Builder, Phi1, Phi2, "a");
265 
266   // Iterate over debug records in the add instruction. There should be two.
267   LLVMDbgRecordRef AddDbgRecordFirst = LLVMGetFirstDbgRecord(Add);
268   assert(AddDbgRecordFirst != NULL);
269   LLVMDbgRecordRef AddDbgRecordSecond = LLVMGetNextDbgRecord(AddDbgRecordFirst);
270   assert(AddDbgRecordSecond != NULL);
271   LLVMDbgRecordRef AddDbgRecordLast = LLVMGetLastDbgRecord(Add);
272   assert(AddDbgRecordLast != NULL);
273   (void)AddDbgRecordLast;
274   assert(AddDbgRecordSecond == AddDbgRecordLast);
275   LLVMDbgRecordRef AddDbgRecordOverTheRange =
276       LLVMGetNextDbgRecord(AddDbgRecordSecond);
277   assert(AddDbgRecordOverTheRange == NULL);
278   (void)AddDbgRecordOverTheRange;
279   LLVMDbgRecordRef AddDbgRecordFirstPrev =
280       LLVMGetPreviousDbgRecord(AddDbgRecordSecond);
281   assert(AddDbgRecordFirstPrev != NULL);
282   assert(AddDbgRecordFirst == AddDbgRecordFirstPrev);
283   LLVMDbgRecordRef AddDbgRecordUnderTheRange =
284       LLVMGetPreviousDbgRecord(AddDbgRecordFirstPrev);
285   assert(AddDbgRecordUnderTheRange == NULL);
286   (void)AddDbgRecordUnderTheRange;
287 
288   char *MStr = LLVMPrintModuleToString(M);
289   puts(MStr);
290   LLVMDisposeMessage(MStr);
291 
292   LLVMDisposeBuilder(Builder);
293   LLVMDisposeDIBuilder(DIB);
294   LLVMDisposeModule(M);
295 
296   return 0;
297 }
298 
299 int llvm_get_di_tag(void) {
300   LLVMModuleRef M = LLVMModuleCreateWithName("Mod");
301   LLVMContextRef Context = LLVMGetModuleContext(M);
302 
303   const char String[] = "foo";
304   LLVMMetadataRef StringMD =
305       LLVMMDStringInContext2(Context, String, strlen(String));
306   LLVMMetadataRef NodeMD = LLVMMDNodeInContext2(Context, &StringMD, 1);
307   assert(LLVMGetDINodeTag(NodeMD) == 0);
308   (void)NodeMD;
309 
310   LLVMDIBuilderRef Builder = LLVMCreateDIBuilder(M);
311   const char Filename[] = "metadata.c";
312   const char Directory[] = ".";
313   LLVMMetadataRef File = LLVMDIBuilderCreateFile(
314       Builder, Filename, strlen(Filename), Directory, strlen(Directory));
315   const char Name[] = "TestClass";
316   LLVMMetadataRef Struct = LLVMDIBuilderCreateStructType(
317       Builder, File, Name, strlen(Name), File, 42, 64, 0,
318       LLVMDIFlagObjcClassComplete, NULL, NULL, 0, 0, NULL, NULL, 0);
319   assert(LLVMGetDINodeTag(Struct) == 0x13);
320   (void)Struct;
321 
322   LLVMDisposeDIBuilder(Builder);
323   LLVMDisposeModule(M);
324 
325   return 0;
326 }
327 
328 int llvm_di_type_get_name(void) {
329   LLVMModuleRef M = LLVMModuleCreateWithName("Mod");
330 
331   LLVMDIBuilderRef Builder = LLVMCreateDIBuilder(M);
332   const char Filename[] = "metadata.c";
333   const char Directory[] = ".";
334   LLVMMetadataRef File = LLVMDIBuilderCreateFile(
335       Builder, Filename, strlen(Filename), Directory, strlen(Directory));
336   const char Name[] = "TestClass";
337   LLVMMetadataRef Struct = LLVMDIBuilderCreateStructType(
338       Builder, File, Name, strlen(Name), File, 42, 64, 0,
339       LLVMDIFlagObjcClassComplete, NULL, NULL, 0, 0, NULL, NULL, 0);
340 
341   size_t Len;
342   const char *TypeName = LLVMDITypeGetName(Struct, &Len);
343   assert(Len == strlen(Name));
344   assert(strncmp(TypeName, Name, Len) == 0);
345   (void)TypeName;
346 
347   LLVMDisposeDIBuilder(Builder);
348   LLVMDisposeModule(M);
349 
350   return 0;
351 }
352