1 | //===-- MangledTest.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/ObjectFile/ELF/ObjectFileELF.h" |
10 | #include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h" |
11 | #include "TestingSupport/SubsystemRAII.h" |
12 | #include "TestingSupport/TestUtilities.h" |
13 | |
14 | #include "lldb/Core/DemangledNameInfo.h" |
15 | #include "lldb/Core/Mangled.h" |
16 | #include "lldb/Core/Module.h" |
17 | #include "lldb/Core/ModuleSpec.h" |
18 | #include "lldb/Host/FileSystem.h" |
19 | #include "lldb/Host/HostInfo.h" |
20 | #include "lldb/Symbol/SymbolContext.h" |
21 | |
22 | #include "llvm/Support/FileUtilities.h" |
23 | #include "llvm/Support/Path.h" |
24 | #include "llvm/Support/Program.h" |
25 | #include "llvm/Testing/Support/Error.h" |
26 | |
27 | #include "gtest/gtest.h" |
28 | |
29 | #include <cstdlib> |
30 | #include <memory> |
31 | |
32 | using namespace lldb; |
33 | using namespace lldb_private; |
34 | |
35 | /// Custom deleter to use with unique_ptr. |
36 | /// |
37 | /// Usage: |
38 | /// \code{.cpp} |
39 | /// |
40 | /// auto OB = |
41 | /// std::unique_ptr<TrackingOutputBuffer, TrackingOutputBufferDeleter>( |
42 | /// new TrackingOutputBuffer()); |
43 | /// |
44 | /// \endcode |
45 | struct TrackingOutputBufferDeleter { |
46 | void operator()(TrackingOutputBuffer *TOB) { |
47 | if (!TOB) |
48 | return; |
49 | std::free(ptr: TOB->getBuffer()); |
50 | delete TOB; |
51 | } |
52 | }; |
53 | |
54 | TEST(MangledTest, ResultForValidName) { |
55 | ConstString MangledName("_ZN1a1b1cIiiiEEvm" ); |
56 | Mangled TheMangled(MangledName); |
57 | ConstString TheDemangled = TheMangled.GetDemangledName(); |
58 | |
59 | ConstString ExpectedResult("void a::b::c<int, int, int>(unsigned long)" ); |
60 | EXPECT_STREQ(ExpectedResult.GetCString(), TheDemangled.GetCString()); |
61 | } |
62 | |
63 | TEST(MangledTest, ResultForBlockInvocation) { |
64 | ConstString MangledName("___Z1fU13block_pointerFviE_block_invoke" ); |
65 | Mangled TheMangled(MangledName); |
66 | ConstString TheDemangled = TheMangled.GetDemangledName(); |
67 | |
68 | ConstString ExpectedResult( |
69 | "invocation function for block in f(void (int) block_pointer)" ); |
70 | EXPECT_STREQ(ExpectedResult.GetCString(), TheDemangled.GetCString()); |
71 | } |
72 | |
73 | TEST(MangledTest, EmptyForInvalidName) { |
74 | ConstString MangledName("_ZN1a1b1cmxktpEEvm" ); |
75 | Mangled TheMangled(MangledName); |
76 | ConstString TheDemangled = TheMangled.GetDemangledName(); |
77 | |
78 | EXPECT_STREQ("" , TheDemangled.GetCString()); |
79 | } |
80 | |
81 | TEST(MangledTest, ResultForValidRustV0Name) { |
82 | ConstString mangled_name("_RNvC1a4main" ); |
83 | Mangled the_mangled(mangled_name); |
84 | ConstString the_demangled = the_mangled.GetDemangledName(); |
85 | |
86 | ConstString expected_result("a::main" ); |
87 | EXPECT_STREQ(expected_result.GetCString(), the_demangled.GetCString()); |
88 | } |
89 | |
90 | TEST(MangledTest, EmptyForInvalidRustV0Name) { |
91 | ConstString mangled_name("_RRR" ); |
92 | Mangled the_mangled(mangled_name); |
93 | ConstString the_demangled = the_mangled.GetDemangledName(); |
94 | |
95 | EXPECT_STREQ("" , the_demangled.GetCString()); |
96 | } |
97 | |
98 | TEST(MangledTest, ResultForValidDLangName) { |
99 | ConstString mangled_name("_Dmain" ); |
100 | Mangled the_mangled(mangled_name); |
101 | ConstString the_demangled = the_mangled.GetDemangledName(); |
102 | |
103 | ConstString expected_result("D main" ); |
104 | EXPECT_STREQ(expected_result.GetCString(), the_demangled.GetCString()); |
105 | } |
106 | |
107 | TEST(MangledTest, SameForInvalidDLangPrefixedName) { |
108 | ConstString mangled_name("_DDD" ); |
109 | Mangled the_mangled(mangled_name); |
110 | ConstString the_demangled = the_mangled.GetDemangledName(); |
111 | |
112 | EXPECT_STREQ("_DDD" , the_demangled.GetCString()); |
113 | } |
114 | |
115 | TEST(MangledTest, RecognizeSwiftMangledNames) { |
116 | llvm::StringRef valid_swift_mangled_names[] = { |
117 | "_TtC4main7MyClass" , // Mangled objc class name |
118 | "_TtP4main3Foo_" , // Mangld objc protocol name |
119 | "$s4main3BarCACycfC" , // Mangled name |
120 | "_$s4main3BarCACycfC" , // Mangled name with leading underscore |
121 | "$S4main3BarCACycfC" , // Older swift mangled name |
122 | "_$S4main3BarCACycfC" , // Older swift mangled name |
123 | // with leading underscore |
124 | // Mangled swift filename |
125 | "@__swiftmacro_4main16FunVariableNames9OptionSetfMm_.swift" , |
126 | }; |
127 | |
128 | for (llvm::StringRef mangled : valid_swift_mangled_names) |
129 | EXPECT_EQ(Mangled::GetManglingScheme(mangled), |
130 | Mangled::eManglingSchemeSwift); |
131 | } |
132 | |
133 | TEST(MangledTest, BoolConversionOperator) { |
134 | { |
135 | ConstString MangledName("_ZN1a1b1cIiiiEEvm" ); |
136 | Mangled TheMangled(MangledName); |
137 | EXPECT_EQ(true, bool(TheMangled)); |
138 | EXPECT_EQ(false, !TheMangled); |
139 | } |
140 | { |
141 | ConstString UnmangledName("puts" ); |
142 | Mangled TheMangled(UnmangledName); |
143 | EXPECT_EQ(true, bool(TheMangled)); |
144 | EXPECT_EQ(false, !TheMangled); |
145 | } |
146 | { |
147 | Mangled TheMangled{}; |
148 | EXPECT_EQ(false, bool(TheMangled)); |
149 | EXPECT_EQ(true, !TheMangled); |
150 | } |
151 | } |
152 | |
153 | TEST(MangledTest, NameIndexes_FindFunctionSymbols) { |
154 | SubsystemRAII<FileSystem, HostInfo, ObjectFileELF, SymbolFileSymtab> |
155 | subsystems; |
156 | |
157 | auto ExpectedFile = TestFile::fromYaml(Yaml: R"( |
158 | --- !ELF |
159 | FileHeader: |
160 | Class: ELFCLASS64 |
161 | Data: ELFDATA2LSB |
162 | Type: ET_EXEC |
163 | Machine: EM_X86_64 |
164 | Sections: |
165 | - Name: .text |
166 | Type: SHT_PROGBITS |
167 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] |
168 | AddressAlign: 0x0000000000000010 |
169 | Size: 0x20 |
170 | - Name: .anothertext |
171 | Type: SHT_PROGBITS |
172 | Flags: [ SHF_ALLOC, SHF_EXECINSTR ] |
173 | Address: 0x0000000000000010 |
174 | AddressAlign: 0x0000000000000010 |
175 | Size: 0x40 |
176 | - Name: .data |
177 | Type: SHT_PROGBITS |
178 | Flags: [ SHF_WRITE, SHF_ALLOC ] |
179 | Address: 0x00000000000000A8 |
180 | AddressAlign: 0x0000000000000004 |
181 | Content: '01000000' |
182 | Symbols: |
183 | - Name: somedata |
184 | Type: STT_OBJECT |
185 | Section: .anothertext |
186 | Value: 0x0000000000000045 |
187 | Binding: STB_GLOBAL |
188 | - Name: main |
189 | Type: STT_FUNC |
190 | Section: .anothertext |
191 | Value: 0x0000000000000010 |
192 | Size: 0x000000000000003F |
193 | Binding: STB_GLOBAL |
194 | - Name: _Z3foov |
195 | Type: STT_FUNC |
196 | Section: .text |
197 | Size: 0x000000000000000D |
198 | Binding: STB_GLOBAL |
199 | - Name: puts@GLIBC_2.5 |
200 | Type: STT_FUNC |
201 | Section: .text |
202 | Size: 0x000000000000000D |
203 | Binding: STB_GLOBAL |
204 | - Name: puts@GLIBC_2.6 |
205 | Type: STT_FUNC |
206 | Section: .text |
207 | Size: 0x000000000000000D |
208 | Binding: STB_GLOBAL |
209 | - Name: _Z5annotv@VERSION3 |
210 | Type: STT_FUNC |
211 | Section: .text |
212 | Size: 0x000000000000000D |
213 | Binding: STB_GLOBAL |
214 | - Name: _ZN1AC2Ev |
215 | Type: STT_FUNC |
216 | Section: .text |
217 | Size: 0x000000000000000D |
218 | Binding: STB_GLOBAL |
219 | - Name: _ZN1AD2Ev |
220 | Type: STT_FUNC |
221 | Section: .text |
222 | Size: 0x000000000000000D |
223 | Binding: STB_GLOBAL |
224 | - Name: _ZN1A3barEv |
225 | Type: STT_FUNC |
226 | Section: .text |
227 | Size: 0x000000000000000D |
228 | Binding: STB_GLOBAL |
229 | - Name: _ZGVZN4llvm4dbgsEvE7thestrm |
230 | Type: STT_FUNC |
231 | Section: .text |
232 | Size: 0x000000000000000D |
233 | Binding: STB_GLOBAL |
234 | - Name: _ZZN4llvm4dbgsEvE7thestrm |
235 | Type: STT_FUNC |
236 | Section: .text |
237 | Size: 0x000000000000000D |
238 | Binding: STB_GLOBAL |
239 | - Name: _ZTVN5clang4DeclE |
240 | Type: STT_FUNC |
241 | Section: .text |
242 | Size: 0x000000000000000D |
243 | Binding: STB_GLOBAL |
244 | - Name: -[ObjCfoo] |
245 | Type: STT_FUNC |
246 | Section: .text |
247 | Size: 0x000000000000000D |
248 | Binding: STB_GLOBAL |
249 | - Name: +[B ObjCbar(WithCategory)] |
250 | Type: STT_FUNC |
251 | Section: .text |
252 | Size: 0x000000000000000D |
253 | Binding: STB_GLOBAL |
254 | - Name: _Z12undemangableEvx42 |
255 | Type: STT_FUNC |
256 | Section: .text |
257 | Size: 0x000000000000000D |
258 | Binding: STB_GLOBAL |
259 | ... |
260 | )" ); |
261 | ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded()); |
262 | |
263 | auto M = std::make_shared<Module>(args: ExpectedFile->moduleSpec()); |
264 | |
265 | auto Count = [M](const char *Name, FunctionNameType Type) -> int { |
266 | SymbolContextList SymList; |
267 | M->FindFunctionSymbols(name: ConstString(Name), name_type_mask: Type, sc_list&: SymList); |
268 | return SymList.GetSize(); |
269 | }; |
270 | |
271 | // Unmangled |
272 | EXPECT_EQ(1, Count("main" , eFunctionNameTypeFull)); |
273 | EXPECT_EQ(1, Count("main" , eFunctionNameTypeBase)); |
274 | EXPECT_EQ(0, Count("main" , eFunctionNameTypeMethod)); |
275 | |
276 | // Itanium mangled |
277 | EXPECT_EQ(1, Count("_Z3foov" , eFunctionNameTypeFull)); |
278 | EXPECT_EQ(1, Count("_Z3foov" , eFunctionNameTypeBase)); |
279 | EXPECT_EQ(1, Count("foo" , eFunctionNameTypeBase)); |
280 | EXPECT_EQ(0, Count("foo" , eFunctionNameTypeMethod)); |
281 | |
282 | // Unmangled with linker annotation |
283 | EXPECT_EQ(1, Count("puts@GLIBC_2.5" , eFunctionNameTypeFull)); |
284 | EXPECT_EQ(1, Count("puts@GLIBC_2.6" , eFunctionNameTypeFull)); |
285 | EXPECT_EQ(2, Count("puts" , eFunctionNameTypeFull)); |
286 | EXPECT_EQ(2, Count("puts" , eFunctionNameTypeBase)); |
287 | EXPECT_EQ(0, Count("puts" , eFunctionNameTypeMethod)); |
288 | |
289 | // Itanium mangled with linker annotation |
290 | EXPECT_EQ(1, Count("_Z5annotv@VERSION3" , eFunctionNameTypeFull)); |
291 | EXPECT_EQ(1, Count("_Z5annotv" , eFunctionNameTypeFull)); |
292 | EXPECT_EQ(1, Count("_Z5annotv" , eFunctionNameTypeBase)); |
293 | EXPECT_EQ(0, Count("annot" , eFunctionNameTypeBase)); |
294 | EXPECT_EQ(0, Count("annot" , eFunctionNameTypeMethod)); |
295 | |
296 | // Itanium mangled ctor A::A() |
297 | EXPECT_EQ(1, Count("_ZN1AC2Ev" , eFunctionNameTypeFull)); |
298 | EXPECT_EQ(1, Count("_ZN1AC2Ev" , eFunctionNameTypeBase)); |
299 | EXPECT_EQ(1, Count("A" , eFunctionNameTypeMethod)); |
300 | EXPECT_EQ(0, Count("A" , eFunctionNameTypeBase)); |
301 | |
302 | // Itanium mangled dtor A::~A() |
303 | EXPECT_EQ(1, Count("_ZN1AD2Ev" , eFunctionNameTypeFull)); |
304 | EXPECT_EQ(1, Count("_ZN1AD2Ev" , eFunctionNameTypeBase)); |
305 | EXPECT_EQ(1, Count("~A" , eFunctionNameTypeMethod)); |
306 | EXPECT_EQ(0, Count("~A" , eFunctionNameTypeBase)); |
307 | |
308 | // Itanium mangled method A::bar() |
309 | EXPECT_EQ(1, Count("_ZN1A3barEv" , eFunctionNameTypeFull)); |
310 | EXPECT_EQ(1, Count("_ZN1A3barEv" , eFunctionNameTypeBase)); |
311 | EXPECT_EQ(1, Count("bar" , eFunctionNameTypeMethod)); |
312 | EXPECT_EQ(0, Count("bar" , eFunctionNameTypeBase)); |
313 | |
314 | // Itanium mangled names that are explicitly excluded from parsing |
315 | EXPECT_EQ(1, Count("_ZGVZN4llvm4dbgsEvE7thestrm" , eFunctionNameTypeFull)); |
316 | EXPECT_EQ(1, Count("_ZGVZN4llvm4dbgsEvE7thestrm" , eFunctionNameTypeBase)); |
317 | EXPECT_EQ(0, Count("dbgs" , eFunctionNameTypeMethod)); |
318 | EXPECT_EQ(0, Count("dbgs" , eFunctionNameTypeBase)); |
319 | EXPECT_EQ(1, Count("_ZZN4llvm4dbgsEvE7thestrm" , eFunctionNameTypeFull)); |
320 | EXPECT_EQ(1, Count("_ZZN4llvm4dbgsEvE7thestrm" , eFunctionNameTypeBase)); |
321 | EXPECT_EQ(0, Count("dbgs" , eFunctionNameTypeMethod)); |
322 | EXPECT_EQ(0, Count("dbgs" , eFunctionNameTypeBase)); |
323 | EXPECT_EQ(1, Count("_ZTVN5clang4DeclE" , eFunctionNameTypeFull)); |
324 | EXPECT_EQ(1, Count("_ZTVN5clang4DeclE" , eFunctionNameTypeBase)); |
325 | EXPECT_EQ(0, Count("Decl" , eFunctionNameTypeMethod)); |
326 | EXPECT_EQ(0, Count("Decl" , eFunctionNameTypeBase)); |
327 | |
328 | // ObjC mangled static |
329 | EXPECT_EQ(1, Count("-[ObjCfoo]" , eFunctionNameTypeFull)); |
330 | EXPECT_EQ(1, Count("-[ObjCfoo]" , eFunctionNameTypeBase)); |
331 | EXPECT_EQ(0, Count("ObjCfoo" , eFunctionNameTypeMethod)); |
332 | |
333 | // ObjC mangled method with category |
334 | EXPECT_EQ(1, Count("+[B ObjCbar(WithCategory)]" , eFunctionNameTypeFull)); |
335 | EXPECT_EQ(1, Count("+[B ObjCbar(WithCategory)]" , eFunctionNameTypeBase)); |
336 | EXPECT_EQ(0, Count("ObjCbar" , eFunctionNameTypeMethod)); |
337 | |
338 | // Invalid things: unable to decode but still possible to find by full name |
339 | EXPECT_EQ(1, Count("_Z12undemangableEvx42" , eFunctionNameTypeFull)); |
340 | EXPECT_EQ(1, Count("_Z12undemangableEvx42" , eFunctionNameTypeBase)); |
341 | EXPECT_EQ(0, Count("_Z12undemangableEvx42" , eFunctionNameTypeMethod)); |
342 | EXPECT_EQ(0, Count("undemangable" , eFunctionNameTypeBase)); |
343 | EXPECT_EQ(0, Count("undemangable" , eFunctionNameTypeMethod)); |
344 | } |
345 | |
346 | static bool NameInfoEquals(const DemangledNameInfo &lhs, |
347 | const DemangledNameInfo &rhs) { |
348 | return std::tie(args: lhs.BasenameRange, args: lhs.ArgumentsRange, args: lhs.ScopeRange, |
349 | args: lhs.QualifiersRange) == |
350 | std::tie(args: rhs.BasenameRange, args: rhs.ArgumentsRange, args: rhs.ScopeRange, |
351 | args: rhs.QualifiersRange); |
352 | } |
353 | |
354 | TEST(MangledTest, DemangledNameInfo_SetMangledResets) { |
355 | Mangled mangled; |
356 | EXPECT_EQ(mangled.GetDemangledInfo(), std::nullopt); |
357 | |
358 | mangled.SetMangledName(ConstString("_Z3foov" )); |
359 | ASSERT_TRUE(mangled); |
360 | |
361 | auto info1 = mangled.GetDemangledInfo(); |
362 | EXPECT_NE(info1, std::nullopt); |
363 | EXPECT_TRUE(info1->hasBasename()); |
364 | |
365 | mangled.SetMangledName(ConstString("_Z4funcv" )); |
366 | |
367 | // Should have re-calculated demangled-info since mangled name changed. |
368 | auto info2 = mangled.GetDemangledInfo(); |
369 | ASSERT_NE(info2, std::nullopt); |
370 | EXPECT_TRUE(info2->hasBasename()); |
371 | |
372 | EXPECT_FALSE(NameInfoEquals(info1.value(), info2.value())); |
373 | EXPECT_EQ(mangled.GetDemangledName(), "func()" ); |
374 | } |
375 | |
376 | TEST(MangledTest, DemangledNameInfo_SetDemangledResets) { |
377 | Mangled mangled("_Z3foov" ); |
378 | ASSERT_TRUE(mangled); |
379 | |
380 | mangled.SetDemangledName(ConstString("" )); |
381 | |
382 | // Mangled name hasn't changed, so GetDemangledInfo causes re-demangling |
383 | // of previously set mangled name. |
384 | EXPECT_NE(mangled.GetDemangledInfo(), std::nullopt); |
385 | EXPECT_EQ(mangled.GetDemangledName(), "foo()" ); |
386 | } |
387 | |
388 | TEST(MangledTest, DemangledNameInfo_Clear) { |
389 | Mangled mangled("_Z3foov" ); |
390 | ASSERT_TRUE(mangled); |
391 | EXPECT_NE(mangled.GetDemangledInfo(), std::nullopt); |
392 | |
393 | mangled.Clear(); |
394 | |
395 | EXPECT_EQ(mangled.GetDemangledInfo(), std::nullopt); |
396 | } |
397 | |
398 | TEST(MangledTest, DemangledNameInfo_SetValue) { |
399 | Mangled mangled("_Z4funcv" ); |
400 | ASSERT_TRUE(mangled); |
401 | |
402 | auto demangled_func = mangled.GetDemangledInfo(); |
403 | |
404 | // SetValue(mangled) resets demangled-info |
405 | mangled.SetValue(ConstString("_Z3foov" )); |
406 | auto demangled_foo = mangled.GetDemangledInfo(); |
407 | EXPECT_NE(demangled_foo, std::nullopt); |
408 | EXPECT_FALSE(NameInfoEquals(demangled_foo.value(), demangled_func.value())); |
409 | |
410 | // SetValue(demangled) resets demangled-info |
411 | mangled.SetValue(ConstString("_Z4funcv" )); |
412 | EXPECT_TRUE(NameInfoEquals(mangled.GetDemangledInfo().value(), |
413 | demangled_func.value())); |
414 | |
415 | // SetValue(empty) resets demangled-info |
416 | mangled.SetValue(ConstString()); |
417 | EXPECT_EQ(mangled.GetDemangledInfo(), std::nullopt); |
418 | |
419 | // Demangling invalid mangled name will set demangled-info |
420 | // (without a valid basename). |
421 | mangled.SetValue(ConstString("_Zinvalid" )); |
422 | ASSERT_NE(mangled.GetDemangledInfo(), std::nullopt); |
423 | EXPECT_FALSE(mangled.GetDemangledInfo()->hasBasename()); |
424 | } |
425 | |
426 | struct DemanglingPartsTestCase { |
427 | const char *mangled; |
428 | DemangledNameInfo expected_info; |
429 | std::string_view basename; |
430 | std::string_view scope; |
431 | std::string_view qualifiers; |
432 | bool valid_basename = true; |
433 | }; |
434 | |
435 | DemanglingPartsTestCase g_demangling_parts_test_cases[] = { |
436 | // clang-format off |
437 | { .mangled: "_ZNVKO3BarIN2ns3QuxIiEEE1CIPFi3FooIS_IiES6_EEE6methodIS6_EENS5_IT_SC_E5InnerIiEESD_SD_" , |
438 | .expected_info: { /*.BasenameRange=*/{92, 98}, /*.ScopeRange=*/{36, 92}, /*.ArgumentsRange=*/{ 108, 158 }, |
439 | /*.QualifiersRange=*/{158, 176}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, |
440 | /*.basename=*/"method" , |
441 | /*.scope=*/"Bar<ns::Qux<int>>::C<int (*)(Foo<Bar<int>, Bar<int>>)>::" , |
442 | /*.qualifiers=*/" const volatile &&" |
443 | }, |
444 | { .mangled: "_Z7getFuncIfEPFiiiET_" , |
445 | .expected_info: { /*.BasenameRange=*/{6, 13}, /*.ScopeRange=*/{6, 6}, /*.ArgumentsRange=*/{ 20, 27 }, |
446 | /*.QualifiersRange=*/{38, 38}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, |
447 | /*.basename=*/"getFunc" , |
448 | /*.scope=*/"" , |
449 | /*.qualifiers=*/"" |
450 | }, |
451 | { .mangled: "_ZN1f1b1c1gEv" , |
452 | .expected_info: { /*.BasenameRange=*/{9, 10}, /*.ScopeRange=*/{0, 9}, /*.ArgumentsRange=*/{ 10, 12 }, |
453 | /*.QualifiersRange=*/{12, 12}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, |
454 | /*.basename=*/"g" , |
455 | /*.scope=*/"f::b::c::" , |
456 | /*.qualifiers=*/"" |
457 | }, |
458 | { .mangled: "_ZN5test73fD1IiEEDTcmtlNS_1DEL_ZNS_1bEEEcvT__EES2_" , |
459 | .expected_info: { /*.BasenameRange=*/{45, 48}, /*.ScopeRange=*/{38, 45}, /*.ArgumentsRange=*/{ 53, 58 }, |
460 | /*.QualifiersRange=*/{58, 58}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, |
461 | /*.basename=*/"fD1" , |
462 | /*.scope=*/"test7::" , |
463 | /*.qualifiers=*/"" |
464 | }, |
465 | { .mangled: "_ZN5test73fD1IiEEDTcmtlNS_1DEL_ZNS_1bINDT1cE1dEEEEEcvT__EES2_" , |
466 | .expected_info: { /*.BasenameRange=*/{61, 64}, /*.ScopeRange=*/{54, 61}, /*.ArgumentsRange=*/{ 69, 79 }, |
467 | /*.QualifiersRange=*/{79, 79}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, |
468 | /*.basename=*/"fD1" , |
469 | /*.scope=*/"test7::" , |
470 | /*.qualifiers=*/"" |
471 | }, |
472 | { .mangled: "_ZN5test7INDT1cE1dINDT1cE1dEEEE3fD1INDT1cE1dINDT1cE1dEEEEEDTcmtlNS_1DEL_ZNS_1bINDT1cE1dEEEEEcvT__EES2_" , |
473 | .expected_info: { /*.BasenameRange=*/{120, 123}, /*.ScopeRange=*/{81, 120}, /*.ArgumentsRange=*/{ 155, 168 }, |
474 | /*.QualifiersRange=*/{168, 168}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, |
475 | /*.basename=*/"fD1" , |
476 | /*.scope=*/"test7<decltype(c)::d<decltype(c)::d>>::" , |
477 | /*.qualifiers=*/"" |
478 | }, |
479 | { .mangled: "_ZN8nlohmann16json_abi_v3_11_310basic_jsonINSt3__13mapENS2_6vectorENS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEbxydS8_NS0_14adl_serializerENS4_IhNS8_IhEEEEvE5parseIRA29_KcEESE_OT_NS2_8functionIFbiNS0_6detail13parse_event_tERSE_EEEbb" , |
480 | .expected_info: { /*.BasenameRange=*/{687, 692}, /*.ScopeRange=*/{343, 687}, /*.ArgumentsRange=*/{ 713, 1174 }, |
481 | /*.QualifiersRange=*/{1174, 1174}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, |
482 | /*.basename=*/"parse" , |
483 | /*.scope=*/"nlohmann::json_abi_v3_11_3::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::json_abi_v3_11_3::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char>>, void>::" , |
484 | /*.qualifiers=*/"" |
485 | }, |
486 | { .mangled: "_ZN8nlohmann16json_abi_v3_11_310basic_jsonINSt3__13mapENS2_6vectorENS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEbxydS8_NS0_14adl_serializerENS4_IhNS8_IhEEEEvEC1EDn" , |
487 | .expected_info: { /*.BasenameRange=*/{344, 354}, /*.ScopeRange=*/{0, 344}, /*.ArgumentsRange=*/{ 354, 370 }, |
488 | /*.QualifiersRange=*/{370, 370}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, |
489 | /*.basename=*/"basic_json" , |
490 | /*.scope=*/"nlohmann::json_abi_v3_11_3::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, bool, long long, unsigned long long, double, std::__1::allocator, nlohmann::json_abi_v3_11_3::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char>>, void>::" , |
491 | /*.qualifiers=*/"" |
492 | }, |
493 | { .mangled: "_Z3fppIiEPFPFvvEiEf" , |
494 | .expected_info: { /*.BasenameRange=*/{10, 13}, /*.ScopeRange=*/{10, 10}, /*.ArgumentsRange=*/{ 18, 25 }, |
495 | /*.QualifiersRange=*/{34,34}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, |
496 | /*.basename=*/"fpp" , |
497 | /*.scope=*/"" , |
498 | /*.qualifiers=*/"" |
499 | }, |
500 | { .mangled: "_Z3fppIiEPFPFvvEN2ns3FooIiEEEf" , |
501 | .expected_info: { /*.BasenameRange=*/{10, 13}, /*.ScopeRange=*/{10, 10}, /*.ArgumentsRange=*/{ 18, 25 }, |
502 | /*.QualifiersRange=*/{43, 43}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, |
503 | /*.basename=*/"fpp" , |
504 | /*.scope=*/"" , |
505 | /*.qualifiers=*/"" |
506 | }, |
507 | { .mangled: "_Z3fppIiEPFPFvPFN2ns3FooIiEENS2_3BarIfE3QuxEEEPFS2_S2_EEf" , |
508 | .expected_info: { /*.BasenameRange=*/{10, 13}, /*.ScopeRange=*/{10, 10}, /*.ArgumentsRange=*/{ 18, 25 }, |
509 | /*.QualifiersRange=*/{108, 108}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, |
510 | /*.basename=*/"fpp" , |
511 | /*.scope=*/"" , |
512 | /*.qualifiers=*/"" |
513 | }, |
514 | { .mangled: "_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvvEiEf" , |
515 | .expected_info: { /*.BasenameRange=*/{64, 67}, /*.ScopeRange=*/{10, 64}, /*.ArgumentsRange=*/{ 72, 79 }, |
516 | /*.QualifiersRange=*/{88, 88}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, |
517 | /*.basename=*/"fpp" , |
518 | /*.scope=*/"ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::" , |
519 | /*.qualifiers=*/"" |
520 | }, |
521 | { .mangled: "_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvvES2_Ef" , |
522 | .expected_info: { /*.BasenameRange=*/{64, 67}, /*.ScopeRange=*/{10, 64}, /*.ArgumentsRange=*/{ 72, 79 }, |
523 | /*.QualifiersRange=*/{97, 97}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, |
524 | /*.basename=*/"fpp" , |
525 | /*.scope=*/"ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::" , |
526 | /*.qualifiers=*/"" , |
527 | }, |
528 | { .mangled: "_ZN2ns8HasFuncsINS_3FooINS1_IiE3BarIfE3QuxEEEE3fppIiEEPFPFvPFS2_S5_EEPFS2_S2_EEf" , |
529 | .expected_info: { /*.BasenameRange=*/{64, 67}, /*.ScopeRange=*/{10, 64}, /*.ArgumentsRange=*/{ 72, 79 }, |
530 | /*.QualifiersRange=*/{162, 162}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, |
531 | /*.basename=*/"fpp" , |
532 | /*.scope=*/"ns::HasFuncs<ns::Foo<ns::Foo<int>::Bar<float>::Qux>>::" , |
533 | /*.qualifiers=*/"" , |
534 | }, |
535 | { .mangled: "_ZNKO2ns3ns23Bar3fooIiEEPFPFNS0_3FooIiEEiENS3_IfEEEi" , |
536 | .expected_info: { /*.BasenameRange=*/{37, 40}, /*.ScopeRange=*/{23, 37}, /*.ArgumentsRange=*/{ 45, 50 }, |
537 | /*.QualifiersRange=*/{78, 87}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, |
538 | /*.basename=*/"foo" , |
539 | /*.scope=*/"ns::ns2::Bar::" , |
540 | /*.qualifiers=*/" const &&" , |
541 | }, |
542 | { .mangled: "_ZTV11ImageLoader" , |
543 | .expected_info: { /*.BasenameRange=*/{0, 0}, /*.ScopeRange=*/{0, 0}, /*.ArgumentsRange=*/{ 0, 0 }, |
544 | /*.QualifiersRange=*/{0, 0}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, |
545 | /*.basename=*/"" , |
546 | /*.scope=*/"" , |
547 | /*.qualifiers=*/"" , |
548 | /*.valid_basename=*/false |
549 | }, |
550 | { .mangled: "___ZNK5dyld313MachOAnalyzer18forEachInitializerER11DiagnosticsRKNS0_15VMAddrConverterEU13block_pointerFvjEPKv_block_invoke.204" , |
551 | .expected_info: { /*.BasenameRange=*/{55, 73}, /*.ScopeRange=*/{33, 55}, /*.ArgumentsRange=*/{ 73, 181 }, |
552 | /*.QualifiersRange=*/{181, 187}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, |
553 | /*.basename=*/"forEachInitializer" , |
554 | /*.scope=*/"dyld3::MachOAnalyzer::" , |
555 | /*.qualifiers=*/" const" , |
556 | }, |
557 | { .mangled: "_ZZN5dyld45startEPNS_10KernelArgsEPvS2_ENK3$_1clEv" , |
558 | .expected_info: { /*.BasenameRange=*/{53, 63}, /*.ScopeRange=*/{0, 53}, /*.ArgumentsRange=*/{ 63, 65 }, |
559 | /*.QualifiersRange=*/{65, 71}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, |
560 | /*.basename=*/"operator()" , |
561 | /*.scope=*/"dyld4::start(dyld4::KernelArgs*, void*, void*)::$_1::" , |
562 | /*.qualifiers=*/" const" , |
563 | }, |
564 | { .mangled: "_ZZNK5dyld46Loader38runInitializersBottomUpPlusUpwardLinksERNS_12RuntimeStateEENK3$_0clEv" , |
565 | .expected_info: { /*.BasenameRange=*/{88, 98}, /*.ScopeRange=*/{0, 88}, /*.ArgumentsRange=*/{ 98, 100 }, |
566 | /*.QualifiersRange=*/{100, 106}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, |
567 | /*.basename=*/"operator()" , |
568 | /*.scope=*/"dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const::$_0::" , |
569 | /*.qualifiers=*/" const" , |
570 | }, |
571 | { .mangled: "_ZZNK5dyld46Loader38runInitializersBottomUpPlusUpwardLinksERNS_12RuntimeStateEENK3$_0clEv.cold" , |
572 | .expected_info: { /*.BasenameRange=*/{88, 98}, /*.ScopeRange=*/{0, 88}, /*.ArgumentsRange=*/{ 98, 100 }, |
573 | /*.QualifiersRange=*/{100, 106}, /*.PrefixRange=*/{0, 0}, /*.SuffixRange=*/{0, 0} }, |
574 | /*.basename=*/"operator()" , |
575 | /*.scope=*/"dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const::$_0::" , |
576 | /*.qualifiers=*/" const" , |
577 | } |
578 | // clang-format on |
579 | }; |
580 | |
581 | struct DemanglingPartsTestFixture |
582 | : public ::testing::TestWithParam<DemanglingPartsTestCase> {}; |
583 | |
584 | namespace { |
585 | class TestAllocator { |
586 | llvm::BumpPtrAllocator Alloc; |
587 | |
588 | public: |
589 | void reset() { Alloc.Reset(); } |
590 | |
591 | template <typename T, typename... Args> T *makeNode(Args &&...args) { |
592 | return new (Alloc.Allocate(Size: sizeof(T), Alignment: alignof(T))) |
593 | T(std::forward<Args>(args)...); |
594 | } |
595 | |
596 | void *allocateNodeArray(size_t sz) { |
597 | return Alloc.Allocate(Size: sizeof(llvm::itanium_demangle::Node *) * sz, |
598 | Alignment: alignof(llvm::itanium_demangle::Node *)); |
599 | } |
600 | }; |
601 | } // namespace |
602 | |
603 | TEST_P(DemanglingPartsTestFixture, DemanglingParts) { |
604 | const auto &[mangled, info, basename, scope, qualifiers, valid_basename] = |
605 | GetParam(); |
606 | |
607 | llvm::itanium_demangle::ManglingParser<TestAllocator> Parser( |
608 | mangled, mangled + ::strlen(s: mangled)); |
609 | |
610 | const auto *Root = Parser.parse(); |
611 | |
612 | ASSERT_NE(nullptr, Root); |
613 | |
614 | auto OB = std::unique_ptr<TrackingOutputBuffer, TrackingOutputBufferDeleter>( |
615 | new TrackingOutputBuffer()); |
616 | Root->print(OB&: *OB); |
617 | auto demangled = std::string_view(*OB); |
618 | |
619 | ASSERT_EQ(OB->NameInfo.hasBasename(), valid_basename); |
620 | |
621 | EXPECT_EQ(OB->NameInfo.BasenameRange, info.BasenameRange); |
622 | EXPECT_EQ(OB->NameInfo.ScopeRange, info.ScopeRange); |
623 | EXPECT_EQ(OB->NameInfo.ArgumentsRange, info.ArgumentsRange); |
624 | EXPECT_EQ(OB->NameInfo.QualifiersRange, info.QualifiersRange); |
625 | |
626 | auto get_part = [&](const std::pair<size_t, size_t> &loc) { |
627 | return demangled.substr(pos: loc.first, n: loc.second - loc.first); |
628 | }; |
629 | |
630 | EXPECT_EQ(get_part(OB->NameInfo.BasenameRange), basename); |
631 | EXPECT_EQ(get_part(OB->NameInfo.ScopeRange), scope); |
632 | EXPECT_EQ(get_part(OB->NameInfo.QualifiersRange), qualifiers); |
633 | } |
634 | |
635 | INSTANTIATE_TEST_SUITE_P(DemanglingPartsTests, DemanglingPartsTestFixture, |
636 | ::testing::ValuesIn(g_demangling_parts_test_cases)); |
637 | |
638 | struct DemanglingInfoCorrectnessTestCase { |
639 | const char *mangled; |
640 | const char *demangled; |
641 | }; |
642 | |
643 | DemanglingInfoCorrectnessTestCase g_demangling_correctness_test_cases[] = { |
644 | #include "llvm/Testing/Demangle/DemangleTestCases.inc" |
645 | }; |
646 | |
647 | struct DemanglingInfoCorrectnessTestFixutre |
648 | : public ::testing::TestWithParam<DemanglingInfoCorrectnessTestCase> {}; |
649 | |
650 | TEST_P(DemanglingInfoCorrectnessTestFixutre, Correctness) { |
651 | auto [mangled, demangled] = GetParam(); |
652 | |
653 | llvm::itanium_demangle::ManglingParser<TestAllocator> Parser( |
654 | mangled, mangled + ::strlen(s: mangled)); |
655 | |
656 | const auto *Root = Parser.parse(); |
657 | |
658 | ASSERT_NE(nullptr, Root); |
659 | |
660 | auto OB = std::unique_ptr<TrackingOutputBuffer, TrackingOutputBufferDeleter>( |
661 | new TrackingOutputBuffer()); |
662 | Root->print(OB&: *OB); |
663 | |
664 | // Filter out cases which would never show up in frames. We only care about |
665 | // function names. |
666 | if (Root->getKind() != |
667 | llvm::itanium_demangle::Node::Kind::KFunctionEncoding && |
668 | Root->getKind() != llvm::itanium_demangle::Node::Kind::KDotSuffix) |
669 | return; |
670 | |
671 | ASSERT_TRUE(OB->NameInfo.hasBasename()); |
672 | |
673 | auto tracked_name = llvm::StringRef(*OB); |
674 | |
675 | auto return_left = tracked_name.slice(Start: 0, End: OB->NameInfo.ScopeRange.first); |
676 | auto scope = tracked_name.slice(Start: OB->NameInfo.ScopeRange.first, |
677 | End: OB->NameInfo.ScopeRange.second); |
678 | auto basename = tracked_name.slice(Start: OB->NameInfo.BasenameRange.first, |
679 | End: OB->NameInfo.BasenameRange.second); |
680 | auto template_args = tracked_name.slice(Start: OB->NameInfo.BasenameRange.second, |
681 | End: OB->NameInfo.ArgumentsRange.first); |
682 | auto args = tracked_name.slice(Start: OB->NameInfo.ArgumentsRange.first, |
683 | End: OB->NameInfo.ArgumentsRange.second); |
684 | auto return_right = tracked_name.slice(Start: OB->NameInfo.ArgumentsRange.second, |
685 | End: OB->NameInfo.QualifiersRange.first); |
686 | auto qualifiers = tracked_name.slice(Start: OB->NameInfo.QualifiersRange.first, |
687 | End: OB->NameInfo.QualifiersRange.second); |
688 | auto suffix = tracked_name.slice(Start: OB->NameInfo.QualifiersRange.second, |
689 | End: llvm::StringRef::npos); |
690 | |
691 | auto reconstructed_name = |
692 | llvm::join_items(Separator: "" , Items&: return_left, Items&: scope, Items&: basename, Items&: template_args, Items&: args, |
693 | Items&: return_right, Items&: qualifiers, Items&: suffix); |
694 | |
695 | EXPECT_EQ(reconstructed_name, demangled); |
696 | } |
697 | |
698 | INSTANTIATE_TEST_SUITE_P( |
699 | DemanglingInfoCorrectnessTests, DemanglingInfoCorrectnessTestFixutre, |
700 | ::testing::ValuesIn(g_demangling_correctness_test_cases)); |
701 | |