| 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 | |