1 | //===-- DWARFASTParserClangTests.cpp --------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "Plugins/SymbolFile/DWARF/DWARFASTParserClang.h" |
10 | #include "Plugins/SymbolFile/DWARF/DWARFCompileUnit.h" |
11 | #include "Plugins/SymbolFile/DWARF/DWARFDIE.h" |
12 | #include "TestingSupport/Symbol/ClangTestUtils.h" |
13 | #include "TestingSupport/Symbol/YAMLModuleTester.h" |
14 | #include "lldb/Core/Debugger.h" |
15 | #include "gmock/gmock.h" |
16 | #include "gtest/gtest.h" |
17 | |
18 | using namespace lldb; |
19 | using namespace lldb_private; |
20 | using namespace lldb_private::dwarf; |
21 | using namespace lldb_private::plugin::dwarf; |
22 | |
23 | namespace { |
24 | static std::once_flag debugger_initialize_flag; |
25 | |
26 | class DWARFASTParserClangTests : public testing::Test { |
27 | void SetUp() override { |
28 | std::call_once(once&: debugger_initialize_flag, |
29 | f: []() { Debugger::Initialize(load_plugin_callback: nullptr); }); |
30 | } |
31 | }; |
32 | |
33 | class DWARFASTParserClangStub : public DWARFASTParserClang { |
34 | public: |
35 | using DWARFASTParserClang::DWARFASTParserClang; |
36 | using DWARFASTParserClang::LinkDeclContextToDIE; |
37 | |
38 | std::vector<const clang::DeclContext *> GetDeclContextToDIEMapKeys() { |
39 | std::vector<const clang::DeclContext *> keys; |
40 | for (const auto &it : m_decl_ctx_to_die) |
41 | keys.push_back(x: it.first); |
42 | return keys; |
43 | } |
44 | }; |
45 | } // namespace |
46 | |
47 | // If your implementation needs to dereference the dummy pointers we are |
48 | // defining here, causing this test to fail, feel free to delete it. |
49 | TEST_F(DWARFASTParserClangTests, |
50 | EnsureAllDIEsInDeclContextHaveBeenParsedParsesOnlyMatchingEntries) { |
51 | |
52 | /// Auxiliary debug info. |
53 | const char *yamldata = R"( |
54 | --- !ELF |
55 | FileHeader: |
56 | Class: ELFCLASS64 |
57 | Data: ELFDATA2LSB |
58 | Type: ET_EXEC |
59 | Machine: EM_386 |
60 | DWARF: |
61 | debug_abbrev: |
62 | - Table: |
63 | - Code: 0x00000001 |
64 | Tag: DW_TAG_compile_unit |
65 | Children: DW_CHILDREN_yes |
66 | Attributes: |
67 | - Attribute: DW_AT_language |
68 | Form: DW_FORM_data2 |
69 | - Code: 0x00000002 |
70 | Tag: DW_TAG_base_type |
71 | Children: DW_CHILDREN_no |
72 | Attributes: |
73 | - Attribute: DW_AT_encoding |
74 | Form: DW_FORM_data1 |
75 | - Attribute: DW_AT_byte_size |
76 | Form: DW_FORM_data1 |
77 | debug_info: |
78 | - Version: 4 |
79 | AddrSize: 8 |
80 | Entries: |
81 | - AbbrCode: 0x00000001 |
82 | Values: |
83 | - Value: 0x000000000000000C |
84 | - AbbrCode: 0x00000002 |
85 | Values: |
86 | - Value: 0x0000000000000007 # DW_ATE_unsigned |
87 | - Value: 0x0000000000000004 |
88 | - AbbrCode: 0x00000002 |
89 | Values: |
90 | - Value: 0x0000000000000007 # DW_ATE_unsigned |
91 | - Value: 0x0000000000000008 |
92 | - AbbrCode: 0x00000002 |
93 | Values: |
94 | - Value: 0x0000000000000005 # DW_ATE_signed |
95 | - Value: 0x0000000000000008 |
96 | - AbbrCode: 0x00000002 |
97 | Values: |
98 | - Value: 0x0000000000000008 # DW_ATE_unsigned_char |
99 | - Value: 0x0000000000000001 |
100 | - AbbrCode: 0x00000000 |
101 | )" ; |
102 | |
103 | YAMLModuleTester t(yamldata); |
104 | ASSERT_TRUE((bool)t.GetDwarfUnit()); |
105 | |
106 | auto holder = std::make_unique<clang_utils::TypeSystemClangHolder>(args: "ast" ); |
107 | auto &ast_ctx = *holder->GetAST(); |
108 | |
109 | DWARFASTParserClangStub ast_parser(ast_ctx); |
110 | |
111 | DWARFUnit *unit = t.GetDwarfUnit(); |
112 | const DWARFDebugInfoEntry *die_first = unit->DIE().GetDIE(); |
113 | const DWARFDebugInfoEntry *die_child0 = die_first->GetFirstChild(); |
114 | const DWARFDebugInfoEntry *die_child1 = die_child0->GetSibling(); |
115 | const DWARFDebugInfoEntry *die_child2 = die_child1->GetSibling(); |
116 | const DWARFDebugInfoEntry *die_child3 = die_child2->GetSibling(); |
117 | std::vector<DWARFDIE> dies = { |
118 | DWARFDIE(unit, die_child0), DWARFDIE(unit, die_child1), |
119 | DWARFDIE(unit, die_child2), DWARFDIE(unit, die_child3)}; |
120 | std::vector<clang::DeclContext *> decl_ctxs = { |
121 | (clang::DeclContext *)1LL, (clang::DeclContext *)2LL, |
122 | (clang::DeclContext *)2LL, (clang::DeclContext *)3LL}; |
123 | for (int i = 0; i < 4; ++i) |
124 | ast_parser.LinkDeclContextToDIE(decl_ctx: decl_ctxs[i], die: dies[i]); |
125 | ast_parser.EnsureAllDIEsInDeclContextHaveBeenParsed( |
126 | decl_context: CompilerDeclContext(nullptr, decl_ctxs[1])); |
127 | |
128 | EXPECT_THAT(ast_parser.GetDeclContextToDIEMapKeys(), |
129 | testing::UnorderedElementsAre(decl_ctxs[0], decl_ctxs[3])); |
130 | } |
131 | |
132 | TEST_F(DWARFASTParserClangTests, TestCallingConventionParsing) { |
133 | // Tests parsing DW_AT_calling_convention values. |
134 | |
135 | // The DWARF below just declares a list of function types with |
136 | // DW_AT_calling_convention on them. |
137 | const char *yamldata = R"( |
138 | --- !ELF |
139 | FileHeader: |
140 | Class: ELFCLASS32 |
141 | Data: ELFDATA2LSB |
142 | Type: ET_EXEC |
143 | Machine: EM_386 |
144 | DWARF: |
145 | debug_str: |
146 | - func1 |
147 | - func2 |
148 | - func3 |
149 | - func4 |
150 | - func5 |
151 | - func6 |
152 | - func7 |
153 | - func8 |
154 | - func9 |
155 | debug_abbrev: |
156 | - ID: 0 |
157 | Table: |
158 | - Code: 0x1 |
159 | Tag: DW_TAG_compile_unit |
160 | Children: DW_CHILDREN_yes |
161 | Attributes: |
162 | - Attribute: DW_AT_language |
163 | Form: DW_FORM_data2 |
164 | - Code: 0x2 |
165 | Tag: DW_TAG_subprogram |
166 | Children: DW_CHILDREN_no |
167 | Attributes: |
168 | - Attribute: DW_AT_low_pc |
169 | Form: DW_FORM_addr |
170 | - Attribute: DW_AT_high_pc |
171 | Form: DW_FORM_data4 |
172 | - Attribute: DW_AT_name |
173 | Form: DW_FORM_strp |
174 | - Attribute: DW_AT_calling_convention |
175 | Form: DW_FORM_data1 |
176 | - Attribute: DW_AT_external |
177 | Form: DW_FORM_flag_present |
178 | debug_info: |
179 | - Version: 4 |
180 | AddrSize: 4 |
181 | Entries: |
182 | - AbbrCode: 0x1 |
183 | Values: |
184 | - Value: 0xC |
185 | - AbbrCode: 0x2 |
186 | Values: |
187 | - Value: 0x0 |
188 | - Value: 0x5 |
189 | - Value: 0x00 |
190 | - Value: 0xCB |
191 | - Value: 0x1 |
192 | - AbbrCode: 0x2 |
193 | Values: |
194 | - Value: 0x10 |
195 | - Value: 0x5 |
196 | - Value: 0x06 |
197 | - Value: 0xB3 |
198 | - Value: 0x1 |
199 | - AbbrCode: 0x2 |
200 | Values: |
201 | - Value: 0x20 |
202 | - Value: 0x5 |
203 | - Value: 0x0C |
204 | - Value: 0xB1 |
205 | - Value: 0x1 |
206 | - AbbrCode: 0x2 |
207 | Values: |
208 | - Value: 0x30 |
209 | - Value: 0x5 |
210 | - Value: 0x12 |
211 | - Value: 0xC0 |
212 | - Value: 0x1 |
213 | - AbbrCode: 0x2 |
214 | Values: |
215 | - Value: 0x40 |
216 | - Value: 0x5 |
217 | - Value: 0x18 |
218 | - Value: 0xB2 |
219 | - Value: 0x1 |
220 | - AbbrCode: 0x2 |
221 | Values: |
222 | - Value: 0x50 |
223 | - Value: 0x5 |
224 | - Value: 0x1E |
225 | - Value: 0xC1 |
226 | - Value: 0x1 |
227 | - AbbrCode: 0x2 |
228 | Values: |
229 | - Value: 0x60 |
230 | - Value: 0x5 |
231 | - Value: 0x24 |
232 | - Value: 0xC2 |
233 | - Value: 0x1 |
234 | - AbbrCode: 0x2 |
235 | Values: |
236 | - Value: 0x70 |
237 | - Value: 0x5 |
238 | - Value: 0x2a |
239 | - Value: 0xEE |
240 | - Value: 0x1 |
241 | - AbbrCode: 0x2 |
242 | Values: |
243 | - Value: 0x80 |
244 | - Value: 0x5 |
245 | - Value: 0x30 |
246 | - Value: 0x01 |
247 | - Value: 0x1 |
248 | - AbbrCode: 0x0 |
249 | ... |
250 | )" ; |
251 | YAMLModuleTester t(yamldata); |
252 | |
253 | DWARFUnit *unit = t.GetDwarfUnit(); |
254 | ASSERT_NE(unit, nullptr); |
255 | const DWARFDebugInfoEntry *cu_entry = unit->DIE().GetDIE(); |
256 | ASSERT_EQ(cu_entry->Tag(), DW_TAG_compile_unit); |
257 | DWARFDIE cu_die(unit, cu_entry); |
258 | |
259 | auto holder = std::make_unique<clang_utils::TypeSystemClangHolder>(args: "ast" ); |
260 | auto &ast_ctx = *holder->GetAST(); |
261 | DWARFASTParserClangStub ast_parser(ast_ctx); |
262 | |
263 | std::vector<std::string> found_function_types; |
264 | // The DWARF above is just a list of functions. Parse all of them to |
265 | // extract the function types and their calling convention values. |
266 | for (DWARFDIE func : cu_die.children()) { |
267 | ASSERT_EQ(func.Tag(), DW_TAG_subprogram); |
268 | SymbolContext sc; |
269 | bool new_type = false; |
270 | lldb::TypeSP type = ast_parser.ParseTypeFromDWARF(sc, die: func, type_is_new_ptr: &new_type); |
271 | found_function_types.push_back( |
272 | x: type->GetForwardCompilerType().GetTypeName().AsCString()); |
273 | } |
274 | |
275 | // Compare the parsed function types against the expected list of types. |
276 | const std::vector<std::string> expected_function_types = { |
277 | "void () __attribute__((regcall))" , |
278 | "void () __attribute__((fastcall))" , |
279 | "void () __attribute__((stdcall))" , |
280 | "void () __attribute__((vectorcall))" , |
281 | "void () __attribute__((pascal))" , |
282 | "void () __attribute__((ms_abi))" , |
283 | "void () __attribute__((sysv_abi))" , |
284 | "void ()" , // invalid calling convention. |
285 | "void ()" , // DW_CC_normal -> no attribute |
286 | }; |
287 | ASSERT_EQ(found_function_types, expected_function_types); |
288 | } |
289 | |
290 | TEST_F(DWARFASTParserClangTests, TestPtrAuthParsing) { |
291 | // Tests parsing values with type DW_TAG_LLVM_ptrauth_type corresponding to |
292 | // explicitly signed raw function pointers |
293 | |
294 | // This is Dwarf for the following C code: |
295 | // ``` |
296 | // void (*__ptrauth(0, 0, 42) a)(); |
297 | // ``` |
298 | |
299 | const char *yamldata = R"( |
300 | --- !ELF |
301 | FileHeader: |
302 | Class: ELFCLASS64 |
303 | Data: ELFDATA2LSB |
304 | Type: ET_EXEC |
305 | Machine: EM_AARCH64 |
306 | DWARF: |
307 | debug_str: |
308 | - a |
309 | debug_abbrev: |
310 | - ID: 0 |
311 | Table: |
312 | - Code: 0x01 |
313 | Tag: DW_TAG_compile_unit |
314 | Children: DW_CHILDREN_yes |
315 | Attributes: |
316 | - Attribute: DW_AT_language |
317 | Form: DW_FORM_data2 |
318 | - Code: 0x02 |
319 | Tag: DW_TAG_variable |
320 | Children: DW_CHILDREN_no |
321 | Attributes: |
322 | - Attribute: DW_AT_name |
323 | Form: DW_FORM_strp |
324 | - Attribute: DW_AT_type |
325 | Form: DW_FORM_ref4 |
326 | - Attribute: DW_AT_external |
327 | Form: DW_FORM_flag_present |
328 | - Code: 0x03 |
329 | Tag: DW_TAG_LLVM_ptrauth_type |
330 | Children: DW_CHILDREN_no |
331 | Attributes: |
332 | - Attribute: DW_AT_type |
333 | Form: DW_FORM_ref4 |
334 | - Attribute: DW_AT_LLVM_ptrauth_key |
335 | Form: DW_FORM_data1 |
336 | - Attribute: DW_AT_LLVM_ptrauth_extra_discriminator |
337 | Form: DW_FORM_data2 |
338 | - Code: 0x04 |
339 | Tag: DW_TAG_pointer_type |
340 | Children: DW_CHILDREN_no |
341 | Attributes: |
342 | - Attribute: DW_AT_type |
343 | Form: DW_FORM_ref4 |
344 | - Code: 0x05 |
345 | Tag: DW_TAG_subroutine_type |
346 | Children: DW_CHILDREN_yes |
347 | - Code: 0x06 |
348 | Tag: DW_TAG_unspecified_parameters |
349 | Children: DW_CHILDREN_no |
350 | |
351 | debug_info: |
352 | - Version: 5 |
353 | UnitType: DW_UT_compile |
354 | AddrSize: 8 |
355 | Entries: |
356 | # 0x0c: DW_TAG_compile_unit |
357 | # DW_AT_language [DW_FORM_data2] (DW_LANG_C99) |
358 | - AbbrCode: 0x01 |
359 | Values: |
360 | - Value: 0x0c |
361 | |
362 | # 0x0f: DW_TAG_variable |
363 | # DW_AT_name [DW_FORM_strp] (\"a\") |
364 | # DW_AT_type [DW_FORM_ref4] (0x00000018 \"void (*__ptrauth(0, 0, 0x02a)\") |
365 | # DW_AT_external [DW_FORM_flag_present] (true) |
366 | - AbbrCode: 0x02 |
367 | Values: |
368 | - Value: 0x00 |
369 | - Value: 0x18 |
370 | |
371 | # 0x18: DW_TAG_LLVM_ptrauth_type |
372 | # DW_AT_type [DW_FORM_ref4] (0x00000020 \"void (*)(...)\") |
373 | # DW_AT_LLVM_ptrauth_key [DW_FORM_data1] (0x00) |
374 | # DW_AT_LLVM_ptrauth_extra_discriminator [DW_FORM_data2] (0x002a) |
375 | - AbbrCode: 0x03 |
376 | Values: |
377 | - Value: 0x20 |
378 | - Value: 0x00 |
379 | - Value: 0x2a |
380 | |
381 | # 0x20: DW_TAG_pointer_type |
382 | # DW_AT_type [DW_AT_type [DW_FORM_ref4] (0x00000025 \"void (...)\") |
383 | - AbbrCode: 0x04 |
384 | Values: |
385 | - Value: 0x25 |
386 | |
387 | # 0x25: DW_TAG_subroutine_type |
388 | - AbbrCode: 0x05 |
389 | |
390 | # 0x26: DW_TAG_unspecified_parameters |
391 | - AbbrCode: 0x06 |
392 | |
393 | - AbbrCode: 0x00 # end of child tags of 0x25 |
394 | - AbbrCode: 0x00 # end of child tags of 0x0c |
395 | ... |
396 | )" ; |
397 | YAMLModuleTester t(yamldata); |
398 | |
399 | DWARFUnit *unit = t.GetDwarfUnit(); |
400 | ASSERT_NE(unit, nullptr); |
401 | const DWARFDebugInfoEntry *cu_entry = unit->DIE().GetDIE(); |
402 | ASSERT_EQ(cu_entry->Tag(), DW_TAG_compile_unit); |
403 | DWARFDIE cu_die(unit, cu_entry); |
404 | |
405 | auto holder = std::make_unique<clang_utils::TypeSystemClangHolder>(args: "ast" ); |
406 | auto &ast_ctx = *holder->GetAST(); |
407 | DWARFASTParserClangStub ast_parser(ast_ctx); |
408 | |
409 | DWARFDIE ptrauth_variable = cu_die.GetFirstChild(); |
410 | ASSERT_EQ(ptrauth_variable.Tag(), DW_TAG_variable); |
411 | DWARFDIE ptrauth_type = |
412 | ptrauth_variable.GetAttributeValueAsReferenceDIE(attr: DW_AT_type); |
413 | ASSERT_EQ(ptrauth_type.Tag(), DW_TAG_LLVM_ptrauth_type); |
414 | |
415 | SymbolContext sc; |
416 | bool new_type = false; |
417 | lldb::TypeSP type_sp = |
418 | ast_parser.ParseTypeFromDWARF(sc, die: ptrauth_type, type_is_new_ptr: &new_type); |
419 | CompilerType compiler_type = type_sp->GetForwardCompilerType(); |
420 | ASSERT_EQ(compiler_type.GetPtrAuthKey(), 0U); |
421 | ASSERT_EQ(compiler_type.GetPtrAuthAddressDiversity(), false); |
422 | ASSERT_EQ(compiler_type.GetPtrAuthDiscriminator(), 42U); |
423 | } |
424 | |
425 | struct : public testing::Test { |
426 | SubsystemRAII<FileSystem, HostInfo> ; |
427 | clang_utils::TypeSystemClangHolder ; |
428 | TypeSystemClang &; |
429 | |
430 | DWARFASTParserClang ; |
431 | () |
432 | : holder("dummy ASTContext" ), ts(*holder.GetAST()), parser(ts) {} |
433 | |
434 | /// Takes the given integer value, stores it in a DWARFFormValue and then |
435 | /// tries to extract the value back via |
436 | /// DWARFASTParserClang::ExtractIntFromFormValue. |
437 | /// Returns the string representation of the extracted value or the error |
438 | /// that was returned from ExtractIntFromFormValue. |
439 | llvm::Expected<std::string> (clang::QualType qt, uint64_t value) { |
440 | DWARFFormValue form_value; |
441 | form_value.SetUnsigned(value); |
442 | llvm::Expected<llvm::APInt> result = |
443 | parser.ExtractIntFromFormValue(int_type: ts.GetType(qt), form_value); |
444 | if (!result) |
445 | return result.takeError(); |
446 | llvm::SmallString<16> result_str; |
447 | result->toStringUnsigned(Str&: result_str); |
448 | return std::string(result_str.str()); |
449 | } |
450 | |
451 | /// Same as ExtractIntFromFormValueTest::Extract but takes a signed integer |
452 | /// and treats the result as a signed integer. |
453 | llvm::Expected<std::string> (clang::QualType qt, int64_t value) { |
454 | DWARFFormValue form_value; |
455 | form_value.SetSigned(value); |
456 | llvm::Expected<llvm::APInt> result = |
457 | parser.ExtractIntFromFormValue(int_type: ts.GetType(qt), form_value); |
458 | if (!result) |
459 | return result.takeError(); |
460 | llvm::SmallString<16> result_str; |
461 | result->toStringSigned(Str&: result_str); |
462 | return std::string(result_str.str()); |
463 | } |
464 | }; |
465 | |
466 | TEST_F(ExtractIntFromFormValueTest, TestBool) { |
467 | using namespace llvm; |
468 | clang::ASTContext &ast = ts.getASTContext(); |
469 | |
470 | EXPECT_THAT_EXPECTED(Extract(ast.BoolTy, 0), HasValue("0" )); |
471 | EXPECT_THAT_EXPECTED(Extract(ast.BoolTy, 1), HasValue("1" )); |
472 | EXPECT_THAT_EXPECTED(Extract(ast.BoolTy, 2), Failed()); |
473 | EXPECT_THAT_EXPECTED(Extract(ast.BoolTy, 3), Failed()); |
474 | } |
475 | |
476 | TEST_F(ExtractIntFromFormValueTest, TestInt) { |
477 | using namespace llvm; |
478 | |
479 | clang::ASTContext &ast = ts.getASTContext(); |
480 | |
481 | // Find the min/max values for 'int' on the current host target. |
482 | constexpr int64_t int_max = std::numeric_limits<int>::max(); |
483 | constexpr int64_t int_min = std::numeric_limits<int>::min(); |
484 | |
485 | // Check that the bit width of int matches the int width in our type system. |
486 | ASSERT_EQ(sizeof(int) * 8, ast.getIntWidth(ast.IntTy)); |
487 | |
488 | // Check values around int_min. |
489 | EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_min - 2), llvm::Failed()); |
490 | EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_min - 1), llvm::Failed()); |
491 | EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_min), |
492 | HasValue(std::to_string(int_min))); |
493 | EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_min + 1), |
494 | HasValue(std::to_string(int_min + 1))); |
495 | EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_min + 2), |
496 | HasValue(std::to_string(int_min + 2))); |
497 | |
498 | // Check values around 0. |
499 | EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, -128), HasValue("-128" )); |
500 | EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, -10), HasValue("-10" )); |
501 | EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, -1), HasValue("-1" )); |
502 | EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, 0), HasValue("0" )); |
503 | EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, 1), HasValue("1" )); |
504 | EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, 10), HasValue("10" )); |
505 | EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, 128), HasValue("128" )); |
506 | |
507 | // Check values around int_max. |
508 | EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_max - 2), |
509 | HasValue(std::to_string(int_max - 2))); |
510 | EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_max - 1), |
511 | HasValue(std::to_string(int_max - 1))); |
512 | EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_max), |
513 | HasValue(std::to_string(int_max))); |
514 | EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_max + 1), llvm::Failed()); |
515 | EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_max + 5), llvm::Failed()); |
516 | |
517 | // Check some values not near an edge case. |
518 | EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_max / 2), |
519 | HasValue(std::to_string(int_max / 2))); |
520 | EXPECT_THAT_EXPECTED(ExtractS(ast.IntTy, int_min / 2), |
521 | HasValue(std::to_string(int_min / 2))); |
522 | } |
523 | |
524 | TEST_F(ExtractIntFromFormValueTest, TestUnsignedInt) { |
525 | using namespace llvm; |
526 | |
527 | clang::ASTContext &ast = ts.getASTContext(); |
528 | constexpr uint64_t uint_max = std::numeric_limits<uint32_t>::max(); |
529 | |
530 | // Check values around 0. |
531 | EXPECT_THAT_EXPECTED(Extract(ast.UnsignedIntTy, 0), HasValue("0" )); |
532 | EXPECT_THAT_EXPECTED(Extract(ast.UnsignedIntTy, 1), HasValue("1" )); |
533 | EXPECT_THAT_EXPECTED(Extract(ast.UnsignedIntTy, 1234), HasValue("1234" )); |
534 | |
535 | // Check some values not near an edge case. |
536 | EXPECT_THAT_EXPECTED(Extract(ast.UnsignedIntTy, uint_max / 2), |
537 | HasValue(std::to_string(uint_max / 2))); |
538 | |
539 | // Check values around uint_max. |
540 | EXPECT_THAT_EXPECTED(Extract(ast.UnsignedIntTy, uint_max - 2), |
541 | HasValue(std::to_string(uint_max - 2))); |
542 | EXPECT_THAT_EXPECTED(Extract(ast.UnsignedIntTy, uint_max - 1), |
543 | HasValue(std::to_string(uint_max - 1))); |
544 | EXPECT_THAT_EXPECTED(Extract(ast.UnsignedIntTy, uint_max), |
545 | HasValue(std::to_string(uint_max))); |
546 | EXPECT_THAT_EXPECTED(Extract(ast.UnsignedIntTy, uint_max + 1), |
547 | llvm::Failed()); |
548 | EXPECT_THAT_EXPECTED(Extract(ast.UnsignedIntTy, uint_max + 2), |
549 | llvm::Failed()); |
550 | } |
551 | |
552 | TEST_F(DWARFASTParserClangTests, TestDefaultTemplateParamParsing) { |
553 | // Tests parsing DW_AT_default_value for template parameters. |
554 | auto BufferOrError = llvm::MemoryBuffer::getFile( |
555 | Filename: GetInputFilePath(name: "DW_AT_default_value-test.yaml" ), /*IsText=*/true); |
556 | ASSERT_TRUE(BufferOrError); |
557 | YAMLModuleTester t(BufferOrError.get()->getBuffer()); |
558 | |
559 | DWARFUnit *unit = t.GetDwarfUnit(); |
560 | ASSERT_NE(unit, nullptr); |
561 | const DWARFDebugInfoEntry *cu_entry = unit->DIE().GetDIE(); |
562 | ASSERT_EQ(cu_entry->Tag(), DW_TAG_compile_unit); |
563 | DWARFDIE cu_die(unit, cu_entry); |
564 | |
565 | auto holder = std::make_unique<clang_utils::TypeSystemClangHolder>(args: "ast" ); |
566 | auto &ast_ctx = *holder->GetAST(); |
567 | DWARFASTParserClangStub ast_parser(ast_ctx); |
568 | |
569 | llvm::SmallVector<lldb::TypeSP, 2> types; |
570 | for (DWARFDIE die : cu_die.children()) { |
571 | if (die.Tag() == DW_TAG_class_type) { |
572 | SymbolContext sc; |
573 | bool new_type = false; |
574 | types.push_back(Elt: ast_parser.ParseTypeFromDWARF(sc, die, type_is_new_ptr: &new_type)); |
575 | } |
576 | } |
577 | |
578 | ASSERT_EQ(types.size(), 3U); |
579 | |
580 | auto check_decl = [](auto const *decl) { |
581 | clang::ClassTemplateSpecializationDecl const *ctsd = |
582 | llvm::dyn_cast_or_null<clang::ClassTemplateSpecializationDecl>(decl); |
583 | ASSERT_NE(ctsd, nullptr); |
584 | |
585 | auto const &args = ctsd->getTemplateArgs(); |
586 | ASSERT_GT(args.size(), 0U); |
587 | |
588 | for (auto const &arg : args.asArray()) { |
589 | EXPECT_TRUE(arg.getIsDefaulted()); |
590 | } |
591 | }; |
592 | |
593 | for (auto const &type_sp : types) { |
594 | ASSERT_NE(type_sp, nullptr); |
595 | auto const *decl = ClangUtil::GetAsTagDecl(type: type_sp->GetFullCompilerType()); |
596 | if (decl->getName() == "bar" || decl->getName() == "baz" ) { |
597 | check_decl(decl); |
598 | } |
599 | } |
600 | } |
601 | |
602 | TEST_F(DWARFASTParserClangTests, TestUniqueDWARFASTTypeMap_CppInsertMapFind) { |
603 | // This tests the behaviour of UniqueDWARFASTTypeMap under |
604 | // following scenario: |
605 | // 1. DWARFASTParserClang parses a forward declaration and |
606 | // inserts it into the UniqueDWARFASTTypeMap. |
607 | // 2. We then MapDeclDIEToDefDIE which updates the map |
608 | // entry with the line number/file information of the definition. |
609 | // 3. Parse the definition DIE, which should return the previously |
610 | // parsed type from the UniqueDWARFASTTypeMap. |
611 | |
612 | const char *yamldata = R"( |
613 | --- !ELF |
614 | FileHeader: |
615 | Class: ELFCLASS64 |
616 | Data: ELFDATA2LSB |
617 | Type: ET_EXEC |
618 | Machine: EM_AARCH64 |
619 | DWARF: |
620 | debug_str: |
621 | - Foo |
622 | |
623 | debug_line: |
624 | - Version: 4 |
625 | MinInstLength: 1 |
626 | MaxOpsPerInst: 1 |
627 | DefaultIsStmt: 1 |
628 | LineBase: 0 |
629 | LineRange: 0 |
630 | Files: |
631 | - Name: main.cpp |
632 | DirIdx: 0 |
633 | ModTime: 0 |
634 | Length: 0 |
635 | |
636 | debug_abbrev: |
637 | - ID: 0 |
638 | Table: |
639 | - Code: 0x01 |
640 | Tag: DW_TAG_compile_unit |
641 | Children: DW_CHILDREN_yes |
642 | Attributes: |
643 | - Attribute: DW_AT_language |
644 | Form: DW_FORM_data2 |
645 | - Attribute: DW_AT_stmt_list |
646 | Form: DW_FORM_sec_offset |
647 | - Code: 0x02 |
648 | Tag: DW_TAG_structure_type |
649 | Children: DW_CHILDREN_no |
650 | Attributes: |
651 | - Attribute: DW_AT_name |
652 | Form: DW_FORM_strp |
653 | - Attribute: DW_AT_declaration |
654 | Form: DW_FORM_flag_present |
655 | - Code: 0x03 |
656 | Tag: DW_TAG_structure_type |
657 | Children: DW_CHILDREN_no |
658 | Attributes: |
659 | - Attribute: DW_AT_name |
660 | Form: DW_FORM_strp |
661 | - Attribute: DW_AT_decl_file |
662 | Form: DW_FORM_data1 |
663 | - Attribute: DW_AT_decl_line |
664 | Form: DW_FORM_data1 |
665 | |
666 | debug_info: |
667 | - Version: 5 |
668 | UnitType: DW_UT_compile |
669 | AddrSize: 8 |
670 | Entries: |
671 | # 0x0c: DW_TAG_compile_unit |
672 | # DW_AT_language [DW_FORM_data2] (DW_LANG_C_plus_plus) |
673 | # DW_AT_stmt_list [DW_FORM_sec_offset] |
674 | - AbbrCode: 0x01 |
675 | Values: |
676 | - Value: 0x04 |
677 | - Value: 0x0000000000000000 |
678 | |
679 | # 0x0d: DW_TAG_structure_type |
680 | # DW_AT_name [DW_FORM_strp] (\"Foo\") |
681 | # DW_AT_declaration [DW_FORM_flag_present] (true) |
682 | - AbbrCode: 0x02 |
683 | Values: |
684 | - Value: 0x00 |
685 | |
686 | # 0x0f: DW_TAG_structure_type |
687 | # DW_AT_name [DW_FORM_strp] (\"Foo\") |
688 | # DW_AT_decl_file [DW_FORM_data1] (main.cpp) |
689 | # DW_AT_decl_line [DW_FORM_data1] (3) |
690 | - AbbrCode: 0x03 |
691 | Values: |
692 | - Value: 0x00 |
693 | - Value: 0x01 |
694 | - Value: 0x03 |
695 | |
696 | - AbbrCode: 0x00 # end of child tags of 0x0c |
697 | ... |
698 | )" ; |
699 | YAMLModuleTester t(yamldata); |
700 | |
701 | DWARFUnit *unit = t.GetDwarfUnit(); |
702 | ASSERT_NE(unit, nullptr); |
703 | const DWARFDebugInfoEntry *cu_entry = unit->DIE().GetDIE(); |
704 | ASSERT_EQ(cu_entry->Tag(), DW_TAG_compile_unit); |
705 | ASSERT_EQ(unit->GetDWARFLanguageType(), DW_LANG_C_plus_plus); |
706 | DWARFDIE cu_die(unit, cu_entry); |
707 | |
708 | auto holder = std::make_unique<clang_utils::TypeSystemClangHolder>(args: "ast" ); |
709 | auto &ast_ctx = *holder->GetAST(); |
710 | DWARFASTParserClangStub ast_parser(ast_ctx); |
711 | |
712 | DWARFDIE decl_die; |
713 | DWARFDIE def_die; |
714 | for (auto const &die : cu_die.children()) { |
715 | if (die.Tag() != DW_TAG_structure_type) |
716 | continue; |
717 | |
718 | if (die.GetAttributeValueAsOptionalUnsigned(attr: llvm::dwarf::DW_AT_declaration)) |
719 | decl_die = die; |
720 | else |
721 | def_die = die; |
722 | } |
723 | |
724 | ASSERT_TRUE(decl_die.IsValid()); |
725 | ASSERT_TRUE(def_die.IsValid()); |
726 | ASSERT_NE(decl_die, def_die); |
727 | |
728 | ParsedDWARFTypeAttributes attrs(def_die); |
729 | ASSERT_TRUE(attrs.decl.IsValid()); |
730 | |
731 | SymbolContext sc; |
732 | bool new_type = false; |
733 | lldb::TypeSP type_sp = ast_parser.ParseTypeFromDWARF(sc, die: decl_die, type_is_new_ptr: &new_type); |
734 | ASSERT_NE(type_sp, nullptr); |
735 | |
736 | ast_parser.MapDeclDIEToDefDIE(decl_die, def_die); |
737 | |
738 | lldb::TypeSP reparsed_type_sp = |
739 | ast_parser.ParseTypeFromDWARF(sc, die: def_die, type_is_new_ptr: &new_type); |
740 | ASSERT_NE(reparsed_type_sp, nullptr); |
741 | |
742 | ASSERT_EQ(type_sp, reparsed_type_sp); |
743 | } |
744 | |
745 | TEST_F(DWARFASTParserClangTests, TestParseDWARFAttributes_ObjectPointer) { |
746 | // This tests the behaviour of ParsedDWARFTypeAttributes |
747 | // for DW_TAG_subprogram definitions which have a DW_AT_object_pointer |
748 | // *and* a DW_AT_specification that also has a DW_AT_object_pointer. |
749 | // We don't want the declaration DW_AT_object_pointer to overwrite the |
750 | // one from the more specific definition's. |
751 | |
752 | const char *yamldata = R"( |
753 | --- !ELF |
754 | FileHeader: |
755 | Class: ELFCLASS64 |
756 | Data: ELFDATA2LSB |
757 | Type: ET_EXEC |
758 | Machine: EM_AARCH64 |
759 | DWARF: |
760 | debug_str: |
761 | - Context |
762 | - func |
763 | - this |
764 | debug_abbrev: |
765 | - ID: 0 |
766 | Table: |
767 | - Code: 0x1 |
768 | Tag: DW_TAG_compile_unit |
769 | Children: DW_CHILDREN_yes |
770 | Attributes: |
771 | - Attribute: DW_AT_language |
772 | Form: DW_FORM_data2 |
773 | - Code: 0x2 |
774 | Tag: DW_TAG_structure_type |
775 | Children: DW_CHILDREN_yes |
776 | Attributes: |
777 | - Attribute: DW_AT_name |
778 | Form: DW_FORM_strp |
779 | - Code: 0x3 |
780 | Tag: DW_TAG_subprogram |
781 | Children: DW_CHILDREN_yes |
782 | Attributes: |
783 | - Attribute: DW_AT_name |
784 | Form: DW_FORM_strp |
785 | - Attribute: DW_AT_declaration |
786 | Form: DW_FORM_flag_present |
787 | - Attribute: DW_AT_object_pointer |
788 | Form: DW_FORM_ref4 |
789 | - Attribute: DW_AT_artificial |
790 | Form: DW_FORM_flag_present |
791 | - Attribute: DW_AT_external |
792 | Form: DW_FORM_flag_present |
793 | - Code: 0x4 |
794 | Tag: DW_TAG_formal_parameter |
795 | Children: DW_CHILDREN_no |
796 | Attributes: |
797 | - Attribute: DW_AT_artificial |
798 | Form: DW_FORM_flag_present |
799 | - Code: 0x5 |
800 | Tag: DW_TAG_subprogram |
801 | Children: DW_CHILDREN_yes |
802 | Attributes: |
803 | - Attribute: DW_AT_object_pointer |
804 | Form: DW_FORM_ref4 |
805 | - Attribute: DW_AT_specification |
806 | Form: DW_FORM_ref4 |
807 | - Code: 0x6 |
808 | Tag: DW_TAG_formal_parameter |
809 | Children: DW_CHILDREN_no |
810 | Attributes: |
811 | - Attribute: DW_AT_name |
812 | Form: DW_FORM_strp |
813 | - Attribute: DW_AT_artificial |
814 | Form: DW_FORM_flag_present |
815 | debug_info: |
816 | - Version: 5 |
817 | UnitType: DW_UT_compile |
818 | AddrSize: 8 |
819 | Entries: |
820 | |
821 | # DW_TAG_compile_unit |
822 | # DW_AT_language [DW_FORM_data2] (DW_LANG_C_plus_plus) |
823 | |
824 | - AbbrCode: 0x1 |
825 | Values: |
826 | - Value: 0x04 |
827 | |
828 | # DW_TAG_structure_type |
829 | # DW_AT_name [DW_FORM_strp] ("Context") |
830 | |
831 | - AbbrCode: 0x2 |
832 | Values: |
833 | - Value: 0x0 |
834 | |
835 | # DW_TAG_subprogram |
836 | # DW_AT_name [DW_FORM_strp] ("func") |
837 | # DW_AT_object_pointer [DW_FORM_ref4] |
838 | - AbbrCode: 0x3 |
839 | Values: |
840 | - Value: 0x8 |
841 | - Value: 0x1 |
842 | - Value: 0x1d |
843 | - Value: 0x1 |
844 | - Value: 0x1 |
845 | |
846 | # DW_TAG_formal_parameter |
847 | # DW_AT_artificial |
848 | - AbbrCode: 0x4 |
849 | Values: |
850 | - Value: 0x1 |
851 | |
852 | - AbbrCode: 0x0 |
853 | - AbbrCode: 0x0 |
854 | |
855 | # DW_TAG_subprogram |
856 | # DW_AT_object_pointer [DW_FORM_ref4] ("this") |
857 | # DW_AT_specification [DW_FORM_ref4] ("func") |
858 | - AbbrCode: 0x5 |
859 | Values: |
860 | - Value: 0x29 |
861 | - Value: 0x14 |
862 | |
863 | # DW_TAG_formal_parameter |
864 | # DW_AT_name [DW_FORM_strp] ("this") |
865 | # DW_AT_artificial |
866 | - AbbrCode: 0x6 |
867 | Values: |
868 | - Value: 0xd |
869 | - Value: 0x1 |
870 | |
871 | - AbbrCode: 0x0 |
872 | - AbbrCode: 0x0 |
873 | ... |
874 | )" ; |
875 | YAMLModuleTester t(yamldata); |
876 | |
877 | DWARFUnit *unit = t.GetDwarfUnit(); |
878 | ASSERT_NE(unit, nullptr); |
879 | const DWARFDebugInfoEntry *cu_entry = unit->DIE().GetDIE(); |
880 | ASSERT_EQ(cu_entry->Tag(), DW_TAG_compile_unit); |
881 | ASSERT_EQ(unit->GetDWARFLanguageType(), DW_LANG_C_plus_plus); |
882 | DWARFDIE cu_die(unit, cu_entry); |
883 | |
884 | auto holder = std::make_unique<clang_utils::TypeSystemClangHolder>(args: "ast" ); |
885 | auto &ast_ctx = *holder->GetAST(); |
886 | DWARFASTParserClangStub ast_parser(ast_ctx); |
887 | |
888 | auto context_die = cu_die.GetFirstChild(); |
889 | ASSERT_TRUE(context_die.IsValid()); |
890 | ASSERT_EQ(context_die.Tag(), DW_TAG_structure_type); |
891 | |
892 | auto subprogram_definition = context_die.GetSibling(); |
893 | ASSERT_TRUE(subprogram_definition.IsValid()); |
894 | ASSERT_EQ(subprogram_definition.Tag(), DW_TAG_subprogram); |
895 | ASSERT_FALSE(subprogram_definition.GetAttributeValueAsOptionalUnsigned( |
896 | DW_AT_external)); |
897 | |
898 | auto param_die = subprogram_definition.GetFirstChild(); |
899 | ASSERT_TRUE(param_die.IsValid()); |
900 | |
901 | ParsedDWARFTypeAttributes attrs(subprogram_definition); |
902 | EXPECT_TRUE(attrs.object_pointer.IsValid()); |
903 | EXPECT_EQ(attrs.object_pointer, param_die); |
904 | } |
905 | |
906 | TEST_F(DWARFASTParserClangTests, TestParseSubroutine_ExplicitObjectParameter) { |
907 | // Tests parsing of a C++ non-static member function with an explicit object |
908 | // parameter that isn't called "this" and is not a pointer (but a CV-qualified |
909 | // rvalue reference instead). |
910 | |
911 | const char *yamldata = R"( |
912 | --- !ELF |
913 | FileHeader: |
914 | Class: ELFCLASS64 |
915 | Data: ELFDATA2LSB |
916 | Type: ET_EXEC |
917 | Machine: EM_AARCH64 |
918 | DWARF: |
919 | debug_str: |
920 | - Context |
921 | - func |
922 | - mySelf |
923 | debug_abbrev: |
924 | - ID: 0 |
925 | Table: |
926 | - Code: 0x1 |
927 | Tag: DW_TAG_compile_unit |
928 | Children: DW_CHILDREN_yes |
929 | Attributes: |
930 | - Attribute: DW_AT_language |
931 | Form: DW_FORM_data2 |
932 | - Code: 0x2 |
933 | Tag: DW_TAG_structure_type |
934 | Children: DW_CHILDREN_yes |
935 | Attributes: |
936 | - Attribute: DW_AT_name |
937 | Form: DW_FORM_strp |
938 | - Code: 0x3 |
939 | Tag: DW_TAG_subprogram |
940 | Children: DW_CHILDREN_yes |
941 | Attributes: |
942 | - Attribute: DW_AT_name |
943 | Form: DW_FORM_strp |
944 | - Attribute: DW_AT_declaration |
945 | Form: DW_FORM_flag_present |
946 | - Attribute: DW_AT_object_pointer |
947 | Form: DW_FORM_ref4 |
948 | - Attribute: DW_AT_external |
949 | Form: DW_FORM_flag_present |
950 | - Code: 0x4 |
951 | Tag: DW_TAG_formal_parameter |
952 | Children: DW_CHILDREN_no |
953 | Attributes: |
954 | - Attribute: DW_AT_name |
955 | Form: DW_FORM_strp |
956 | - Attribute: DW_AT_type |
957 | Form: DW_FORM_ref4 |
958 | - Code: 0x5 |
959 | Tag: DW_TAG_rvalue_reference_type |
960 | Children: DW_CHILDREN_no |
961 | Attributes: |
962 | - Attribute: DW_AT_type |
963 | Form: DW_FORM_ref4 |
964 | - Code: 0x6 |
965 | Tag: DW_TAG_const_type |
966 | Children: DW_CHILDREN_no |
967 | Attributes: |
968 | - Attribute: DW_AT_type |
969 | Form: DW_FORM_ref4 |
970 | - Code: 0x7 |
971 | Tag: DW_TAG_volatile_type |
972 | Children: DW_CHILDREN_no |
973 | Attributes: |
974 | - Attribute: DW_AT_type |
975 | Form: DW_FORM_ref4 |
976 | debug_info: |
977 | - Version: 5 |
978 | UnitType: DW_UT_compile |
979 | AddrSize: 8 |
980 | Entries: |
981 | |
982 | # DW_TAG_compile_unit |
983 | # DW_AT_language [DW_FORM_data2] (DW_LANG_C_plus_plus) |
984 | |
985 | - AbbrCode: 0x1 |
986 | Values: |
987 | - Value: 0x04 |
988 | |
989 | # DW_TAG_structure_type |
990 | # DW_AT_name [DW_FORM_strp] ("Context") |
991 | |
992 | - AbbrCode: 0x2 |
993 | Values: |
994 | - Value: 0x0 |
995 | |
996 | # DW_TAG_subprogram |
997 | # DW_AT_name [DW_FORM_strp] ("func") |
998 | # DW_AT_object_pointer [DW_FORM_ref4] |
999 | - AbbrCode: 0x3 |
1000 | Values: |
1001 | - Value: 0x8 |
1002 | - Value: 0x1 |
1003 | - Value: 0x1d |
1004 | - Value: 0x1 |
1005 | |
1006 | # DW_TAG_formal_parameter |
1007 | # DW_AT_name [DW_FORM_strp] ("mySelf") |
1008 | # DW_AT_type [DW_FORM_ref4] (const volatile Context &&) |
1009 | - AbbrCode: 0x4 |
1010 | Values: |
1011 | - Value: 0xd |
1012 | - Value: 0x28 |
1013 | |
1014 | - AbbrCode: 0x0 |
1015 | - AbbrCode: 0x0 |
1016 | |
1017 | # DW_TAG_rvalue_reference_type |
1018 | # DW_AT_type [DW_FORM_ref4] ("const volatile Context") |
1019 | |
1020 | - AbbrCode: 0x5 |
1021 | Values: |
1022 | - Value: 0x2d |
1023 | |
1024 | # DW_TAG_const_type |
1025 | # DW_AT_type [DW_FORM_ref4] ("volatile Context") |
1026 | |
1027 | - AbbrCode: 0x6 |
1028 | Values: |
1029 | - Value: 0x32 |
1030 | |
1031 | # DW_TAG_volatile_type |
1032 | # DW_AT_type [DW_FORM_ref4] ("Context") |
1033 | |
1034 | - AbbrCode: 0x7 |
1035 | Values: |
1036 | - Value: 0xf |
1037 | |
1038 | - AbbrCode: 0x0 |
1039 | ... |
1040 | )" ; |
1041 | YAMLModuleTester t(yamldata); |
1042 | |
1043 | DWARFUnit *unit = t.GetDwarfUnit(); |
1044 | ASSERT_NE(unit, nullptr); |
1045 | const DWARFDebugInfoEntry *cu_entry = unit->DIE().GetDIE(); |
1046 | ASSERT_EQ(cu_entry->Tag(), DW_TAG_compile_unit); |
1047 | ASSERT_EQ(unit->GetDWARFLanguageType(), DW_LANG_C_plus_plus); |
1048 | DWARFDIE cu_die(unit, cu_entry); |
1049 | |
1050 | auto ts_or_err = |
1051 | cu_die.GetDWARF()->GetTypeSystemForLanguage(language: eLanguageTypeC_plus_plus); |
1052 | ASSERT_TRUE(static_cast<bool>(ts_or_err)); |
1053 | llvm::consumeError(Err: ts_or_err.takeError()); |
1054 | auto *parser = |
1055 | static_cast<DWARFASTParserClang *>((*ts_or_err)->GetDWARFParser()); |
1056 | |
1057 | auto context_die = cu_die.GetFirstChild(); |
1058 | ASSERT_TRUE(context_die.IsValid()); |
1059 | ASSERT_EQ(context_die.Tag(), DW_TAG_structure_type); |
1060 | |
1061 | SymbolContext sc; |
1062 | bool new_type; |
1063 | auto context_type_sp = parser->ParseTypeFromDWARF(sc, die: context_die, type_is_new_ptr: &new_type); |
1064 | ASSERT_NE(context_type_sp, nullptr); |
1065 | |
1066 | ASSERT_TRUE( |
1067 | parser->CompleteTypeFromDWARF(context_die, context_type_sp.get(), |
1068 | context_type_sp->GetForwardCompilerType())); |
1069 | |
1070 | auto *record_decl = llvm::dyn_cast_or_null<clang::CXXRecordDecl>( |
1071 | Val: ClangUtil::GetAsTagDecl(type: context_type_sp->GetForwardCompilerType())); |
1072 | ASSERT_NE(record_decl, nullptr); |
1073 | |
1074 | auto method_it = record_decl->method_begin(); |
1075 | ASSERT_NE(method_it, record_decl->method_end()); |
1076 | |
1077 | // Check that we didn't parse the function as static. |
1078 | EXPECT_FALSE(method_it->isStatic()); |
1079 | |
1080 | // Check that method qualifiers were correctly set. |
1081 | EXPECT_EQ(method_it->getMethodQualifiers(), |
1082 | clang::Qualifiers::fromCVRMask(clang::Qualifiers::Const | |
1083 | clang::Qualifiers::Volatile)); |
1084 | } |
1085 | |
1086 | TEST_F(DWARFASTParserClangTests, TestParseSubroutine_ParameterCreation) { |
1087 | // Tests parsing of a C++ free function will create clang::ParmVarDecls with |
1088 | // the correct clang::DeclContext. |
1089 | // |
1090 | // Also ensures we attach names to the ParmVarDecls (even when DWARF contains |
1091 | // a mix of named/unnamed parameters). |
1092 | |
1093 | const char *yamldata = R"( |
1094 | --- !ELF |
1095 | FileHeader: |
1096 | Class: ELFCLASS64 |
1097 | Data: ELFDATA2LSB |
1098 | Type: ET_EXEC |
1099 | Machine: EM_AARCH64 |
1100 | DWARF: |
1101 | debug_str: |
1102 | - func |
1103 | - int |
1104 | - short |
1105 | - namedParam |
1106 | debug_abbrev: |
1107 | - ID: 0 |
1108 | Table: |
1109 | - Code: 0x1 |
1110 | Tag: DW_TAG_compile_unit |
1111 | Children: DW_CHILDREN_yes |
1112 | Attributes: |
1113 | - Attribute: DW_AT_language |
1114 | Form: DW_FORM_data2 |
1115 | - Code: 0x2 |
1116 | Tag: DW_TAG_structure_type |
1117 | Children: DW_CHILDREN_yes |
1118 | Attributes: |
1119 | - Attribute: DW_AT_name |
1120 | Form: DW_FORM_strp |
1121 | - Code: 0x3 |
1122 | Tag: DW_TAG_subprogram |
1123 | Children: DW_CHILDREN_yes |
1124 | Attributes: |
1125 | - Attribute: DW_AT_name |
1126 | Form: DW_FORM_strp |
1127 | - Attribute: DW_AT_declaration |
1128 | Form: DW_FORM_flag_present |
1129 | - Attribute: DW_AT_external |
1130 | Form: DW_FORM_flag_present |
1131 | - Code: 0x4 |
1132 | Tag: DW_TAG_formal_parameter |
1133 | Children: DW_CHILDREN_no |
1134 | Attributes: |
1135 | - Attribute: DW_AT_type |
1136 | Form: DW_FORM_ref4 |
1137 | - Code: 0x5 |
1138 | Tag: DW_TAG_formal_parameter |
1139 | Children: DW_CHILDREN_no |
1140 | Attributes: |
1141 | - Attribute: DW_AT_type |
1142 | Form: DW_FORM_ref4 |
1143 | - Attribute: DW_AT_name |
1144 | Form: DW_FORM_strp |
1145 | - Code: 0x6 |
1146 | Tag: DW_TAG_base_type |
1147 | Children: DW_CHILDREN_no |
1148 | Attributes: |
1149 | - Attribute: DW_AT_name |
1150 | Form: DW_FORM_strp |
1151 | - Attribute: DW_AT_encoding |
1152 | Form: DW_FORM_data1 |
1153 | - Attribute: DW_AT_byte_size |
1154 | Form: DW_FORM_data1 |
1155 | debug_info: |
1156 | - Version: 5 |
1157 | UnitType: DW_UT_compile |
1158 | AddrSize: 8 |
1159 | Entries: |
1160 | |
1161 | # DW_TAG_compile_unit |
1162 | # DW_AT_language [DW_FORM_data2] (DW_LANG_C_plus_plus) |
1163 | |
1164 | - AbbrCode: 0x1 |
1165 | Values: |
1166 | - Value: 0x04 |
1167 | |
1168 | # DW_TAG_subprogram |
1169 | # DW_AT_name [DW_FORM_strp] ("func") |
1170 | - AbbrCode: 0x3 |
1171 | Values: |
1172 | - Value: 0x0 |
1173 | - Value: 0x1 |
1174 | - Value: 0x1 |
1175 | |
1176 | # DW_TAG_formal_parameter |
1177 | # DW_AT_type [DW_FORM_ref4] (int) |
1178 | - AbbrCode: 0x4 |
1179 | Values: |
1180 | - Value: 0x23 |
1181 | |
1182 | # DW_TAG_formal_parameter |
1183 | # DW_AT_type [DW_FORM_ref4] (short) |
1184 | # DW_AT_name [DW_FORM_strp] ("namedParam") |
1185 | - AbbrCode: 0x5 |
1186 | Values: |
1187 | - Value: 0x2a |
1188 | - Value: 0xf |
1189 | |
1190 | - AbbrCode: 0x0 |
1191 | |
1192 | # DW_TAG_base_type |
1193 | # DW_AT_name [DW_FORM_strp] ("int") |
1194 | # DW_AT_encoding [DW_FORM_data1] |
1195 | # DW_AT_byte_size [DW_FORM_data1] |
1196 | |
1197 | - AbbrCode: 0x6 |
1198 | Values: |
1199 | - Value: 0x0000000000000005 |
1200 | - Value: 0x0000000000000005 # DW_ATE_signed |
1201 | - Value: 0x0000000000000004 |
1202 | |
1203 | # DW_TAG_base_type |
1204 | # DW_AT_name [DW_FORM_strp] ("short") |
1205 | # DW_AT_encoding [DW_FORM_data1] |
1206 | # DW_AT_byte_size [DW_FORM_data1] |
1207 | |
1208 | - AbbrCode: 0x6 |
1209 | Values: |
1210 | - Value: 0x0000000000000009 |
1211 | - Value: 0x0000000000000005 # DW_ATE_signed |
1212 | - Value: 0x0000000000000004 |
1213 | |
1214 | - AbbrCode: 0x0 |
1215 | ... |
1216 | )" ; |
1217 | YAMLModuleTester t(yamldata); |
1218 | |
1219 | DWARFUnit *unit = t.GetDwarfUnit(); |
1220 | ASSERT_NE(unit, nullptr); |
1221 | const DWARFDebugInfoEntry *cu_entry = unit->DIE().GetDIE(); |
1222 | ASSERT_EQ(cu_entry->Tag(), DW_TAG_compile_unit); |
1223 | ASSERT_EQ(unit->GetDWARFLanguageType(), DW_LANG_C_plus_plus); |
1224 | DWARFDIE cu_die(unit, cu_entry); |
1225 | |
1226 | auto ts_or_err = |
1227 | cu_die.GetDWARF()->GetTypeSystemForLanguage(language: eLanguageTypeC_plus_plus); |
1228 | ASSERT_TRUE(static_cast<bool>(ts_or_err)); |
1229 | llvm::consumeError(Err: ts_or_err.takeError()); |
1230 | |
1231 | auto *ts = static_cast<TypeSystemClang *>(ts_or_err->get()); |
1232 | auto *parser = static_cast<DWARFASTParserClang *>(ts->GetDWARFParser()); |
1233 | |
1234 | auto subprogram = cu_die.GetFirstChild(); |
1235 | ASSERT_TRUE(subprogram.IsValid()); |
1236 | ASSERT_EQ(subprogram.Tag(), DW_TAG_subprogram); |
1237 | |
1238 | SymbolContext sc; |
1239 | bool new_type; |
1240 | auto type_sp = parser->ParseTypeFromDWARF(sc, die: subprogram, type_is_new_ptr: &new_type); |
1241 | ASSERT_NE(type_sp, nullptr); |
1242 | |
1243 | auto result = ts->GetTranslationUnitDecl()->lookup( |
1244 | clang_utils::getDeclarationName(ast&: *ts, name: "func" )); |
1245 | ASSERT_TRUE(result.isSingleResult()); |
1246 | |
1247 | auto const *func = llvm::cast<clang::FunctionDecl>(result.front()); |
1248 | |
1249 | EXPECT_EQ(func->getNumParams(), 2U); |
1250 | EXPECT_EQ(func->getParamDecl(0)->getDeclContext(), func); |
1251 | EXPECT_TRUE(func->getParamDecl(0)->getName().empty()); |
1252 | EXPECT_EQ(func->getParamDecl(1)->getDeclContext(), func); |
1253 | EXPECT_EQ(func->getParamDecl(1)->getName(), "namedParam" ); |
1254 | } |
1255 | |