[llvm] [llvm-gsymutil] Replace truncated DWARF names with mangled names from symbol table (PR #184221)

Chen Li via llvm-commits llvm-commits at lists.llvm.org
Fri May 8 13:47:30 PDT 2026


https://github.com/thechenli updated https://github.com/llvm/llvm-project/pull/184221

>From c4da0d41deb6aae2bda64b3b57aef037a3088b1d Mon Sep 17 00:00:00 2001
From: Chen Li <chenlii at fb.com>
Date: Thu, 23 Apr 2026 16:44:58 -0700
Subject: [PATCH] [llvm-gsymutil] Replace truncated DWARF names with mangled
 names from symbol table

---
 .../llvm/DebugInfo/GSYM/CallSiteInfo.h        |   7 +
 .../llvm/DebugInfo/GSYM/FunctionInfo.h        |   3 +-
 llvm/lib/DebugInfo/GSYM/GsymCreator.cpp       |  60 ++++++--
 .../X86/elf-mangled-name-replacement.yaml     | 128 ++++++++++++++++
 .../elf-swift-mangled-name-replacement.yaml   | 128 ++++++++++++++++
 llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp    | 139 ++++++++++++++++++
 6 files changed, 452 insertions(+), 13 deletions(-)
 create mode 100644 llvm/test/tools/llvm-gsymutil/X86/elf-mangled-name-replacement.yaml
 create mode 100644 llvm/test/tools/llvm-gsymutil/X86/elf-swift-mangled-name-replacement.yaml

diff --git a/llvm/include/llvm/DebugInfo/GSYM/CallSiteInfo.h b/llvm/include/llvm/DebugInfo/GSYM/CallSiteInfo.h
index 2b72d901f2330..96e4c9adf99ad 100644
--- a/llvm/include/llvm/DebugInfo/GSYM/CallSiteInfo.h
+++ b/llvm/include/llvm/DebugInfo/GSYM/CallSiteInfo.h
@@ -78,6 +78,13 @@ struct CallSiteInfo {
 struct CallSiteInfoCollection {
   std::vector<CallSiteInfo> CallSites;
 
+  bool operator==(const CallSiteInfoCollection &RHS) const {
+    return CallSites == RHS.CallSites;
+  }
+  bool operator!=(const CallSiteInfoCollection &RHS) const {
+    return !(*this == RHS);
+  }
+
   /// Decode a CallSiteInfoCollection object from a binary data stream.
   ///
   /// \param Data The binary stream to read the data from.
diff --git a/llvm/include/llvm/DebugInfo/GSYM/FunctionInfo.h b/llvm/include/llvm/DebugInfo/GSYM/FunctionInfo.h
index bd836e6783a97..ef074a6309788 100644
--- a/llvm/include/llvm/DebugInfo/GSYM/FunctionInfo.h
+++ b/llvm/include/llvm/DebugInfo/GSYM/FunctionInfo.h
@@ -217,7 +217,8 @@ struct FunctionInfo {
 
 inline bool operator==(const FunctionInfo &LHS, const FunctionInfo &RHS) {
   return LHS.Range == RHS.Range && LHS.Name == RHS.Name &&
-         LHS.OptLineTable == RHS.OptLineTable && LHS.Inline == RHS.Inline;
+         LHS.OptLineTable == RHS.OptLineTable && LHS.Inline == RHS.Inline &&
+         LHS.CallSites == RHS.CallSites;
 }
 inline bool operator!=(const FunctionInfo &LHS, const FunctionInfo &RHS) {
   return !(LHS == RHS);
diff --git a/llvm/lib/DebugInfo/GSYM/GsymCreator.cpp b/llvm/lib/DebugInfo/GSYM/GsymCreator.cpp
index 4b3929a532489..36e939cb647b0 100644
--- a/llvm/lib/DebugInfo/GSYM/GsymCreator.cpp
+++ b/llvm/lib/DebugInfo/GSYM/GsymCreator.cpp
@@ -6,6 +6,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/DebugInfo/GSYM/GsymCreator.h"
+#include "llvm/ADT/SmallString.h"
 #include "llvm/DebugInfo/GSYM/FileWriter.h"
 #include "llvm/DebugInfo/GSYM/Header.h"
 #include "llvm/DebugInfo/GSYM/LineTable.h"
@@ -21,6 +22,34 @@
 using namespace llvm;
 using namespace gsym;
 
+// Keep this matching cheap: Itanium and Swift both encode identifiers as
+// <length><identifier> in the raw mangled name. Look for that token instead of
+// demangling during finalize().
+static bool isSupportedMangledPrefix(StringRef Name) {
+  return Name.starts_with("_Z") || Name.starts_with("$s") ||
+         Name.starts_with("$S");
+}
+
+static bool shouldReplaceWithMangledName(StringRef AlternateName,
+                                         StringRef CurrentName) {
+  // Any name is better than no name.
+  if (CurrentName.empty() && !AlternateName.empty())
+    return true;
+
+  // Keep the current name if it's already mangled, or if the alternate name
+  // is not a supported mangled name.
+  if (isSupportedMangledPrefix(CurrentName) ||
+      !isSupportedMangledPrefix(AlternateName))
+    return false;
+
+  // Confirm the alternate mangled name actually contains the current name as
+  // an Itanium/Swift identifier token (<length><identifier>).
+  SmallString<64> LengthAndName;
+  raw_svector_ostream OS(LengthAndName);
+  OS << CurrentName.size() << CurrentName;
+  return AlternateName.contains(StringRef(LengthAndName));
+}
+
 GsymCreator::GsymCreator(bool Quiet)
     : StrTab(StringTableBuilder::ELF), Quiet(Quiet) {
   insertFile(StringRef());
@@ -180,14 +209,25 @@ llvm::Error GsymCreator::finalize(OutputAggregator &Out) {
         if (ranges_equal || Prev.Range.intersects(Curr.Range)) {
           // Overlapping ranges or empty identical ranges.
           if (ranges_equal) {
-            // Same address range. Check if one is from debug
-            // info and the other is from a symbol table. If
-            // so, then keep the one with debug info. Our
-            // sorting guarantees that entries with matching
-            // address ranges that have debug info are last in
-            // the sort.
-            if (!(Prev == Curr)) {
-              if (Prev.hasRichInfo() && Curr.hasRichInfo())
+            // Same address range. When exactly one entry has rich info (line
+            // table, inline info, or call sites), keep that entry. DWARF often
+            // truncates a function's linkage name to its short form, so before
+            // dropping the non-rich symbol-table entry, check whether its name
+            // is a more complete mangled (Itanium or Swift) form of the rich
+            // entry's name and, if so, copy it onto the rich entry. This lets
+            // downstream tools demangle the full signature.
+            const bool PrevRich = Prev.hasRichInfo();
+            const bool CurrRich = Curr.hasRichInfo();
+            if (PrevRich != CurrRich) {
+              FunctionInfo &RichFI = PrevRich ? Prev : Curr;
+              FunctionInfo &NonRichFI = PrevRich ? Curr : Prev;
+              if (shouldReplaceWithMangledName(getString(NonRichFI.Name),
+                                               getString(RichFI.Name)))
+                RichFI.Name = NonRichFI.Name;
+              if (!PrevRich)
+                std::swap(Prev, Curr);
+            } else if (Prev != Curr) {
+              if (PrevRich)
                 Out.Report(
                     "Duplicate address ranges with different debug info.",
                     [&](raw_ostream &OS) {
@@ -197,10 +237,6 @@ llvm::Error GsymCreator::finalize(OutputAggregator &Out) {
                          << Prev << "\nIn favor of this one:\n"
                          << Curr << "\n";
                     });
-
-              // We want to swap the current entry with the previous since
-              // later entries with the same range always have more debug info
-              // or different debug info.
               std::swap(Prev, Curr);
             }
           } else {
diff --git a/llvm/test/tools/llvm-gsymutil/X86/elf-mangled-name-replacement.yaml b/llvm/test/tools/llvm-gsymutil/X86/elf-mangled-name-replacement.yaml
new file mode 100644
index 0000000000000..0ad50e2e3e218
--- /dev/null
+++ b/llvm/test/tools/llvm-gsymutil/X86/elf-mangled-name-replacement.yaml
@@ -0,0 +1,128 @@
+## Test that same-range dedup keeps the DWARF line table while replacing a
+## shortened DWARF function name with the full Itanium symbol-table name.
+
+# RUN: yaml2obj %s -o %t
+# RUN: llvm-gsymutil --convert %t -o %t.gsym 2>&1 | FileCheck %s --check-prefix=CONVERT
+# RUN: llvm-gsymutil %t.gsym 2>&1 | FileCheck %s --check-prefix=DUMP
+
+# CONVERT: Loaded 1 functions from DWARF.
+# CONVERT: Loaded 1 functions from symbol table.
+# CONVERT: Pruned 1 functions, ended with 1 total
+
+# DUMP: "_Z10make_ftypePci"
+# DUMP: LineTable:
+# DUMP: main.cpp:10
+# DUMP: main.cpp:11
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+Sections:
+  - Name:    .text
+    Type:    SHT_PROGBITS
+    Flags:   [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address: 0x0000000000401000
+    AddressAlign: 0x10
+    Content: 554889E531C05DC3554889E531C05DC3
+DWARF:
+  debug_str:
+    - ''
+    - main.cpp
+    - make_ftype
+  debug_abbrev:
+    - ID:              0
+      Table:
+        - Code:            0x1
+          Tag:             DW_TAG_compile_unit
+          Children:        DW_CHILDREN_yes
+          Attributes:
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_language
+              Form:            DW_FORM_udata
+            - Attribute:       DW_AT_stmt_list
+              Form:            DW_FORM_sec_offset
+        - Code:            0x2
+          Tag:             DW_TAG_subprogram
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_low_pc
+              Form:            DW_FORM_addr
+            - Attribute:       DW_AT_high_pc
+              Form:            DW_FORM_addr
+  debug_info:
+    - Length:          0x27
+      Version:         4
+      AbbrevTableID:   0
+      AbbrOffset:      0x0
+      AddrSize:        8
+      Entries:
+        - AbbrCode:        0x1
+          Values:
+            - Value:           0x1
+            - Value:           0x2
+            - Value:           0x0
+        - AbbrCode:        0x2
+          Values:
+            - Value:           0xA
+            - Value:           0x401000
+            - Value:           0x401010
+        - AbbrCode:        0x0
+  debug_line:
+    - Length:          61
+      Version:         2
+      PrologueLength:  31
+      MinInstLength:   1
+      DefaultIsStmt:   1
+      LineBase:        251
+      LineRange:       14
+      OpcodeBase:      13
+      StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]
+      Files:
+        - Name:            main.cpp
+          DirIdx:          0
+          ModTime:         0
+          Length:          0
+      Opcodes:
+        - Opcode:          DW_LNS_extended_op
+          ExtLen:          9
+          SubOpcode:       DW_LNE_set_address
+          Data:            4198400
+        - Opcode:          DW_LNS_advance_line
+          SData:           9
+          Data:            0
+        - Opcode:          DW_LNS_copy
+          Data:            0
+        - Opcode:          DW_LNS_advance_pc
+          Data:            8
+        - Opcode:          DW_LNS_advance_line
+          SData:           1
+          Data:            0
+        - Opcode:          DW_LNS_copy
+          Data:            0
+        - Opcode:          DW_LNS_advance_pc
+          Data:            8
+        - Opcode:          DW_LNS_extended_op
+          ExtLen:          1
+          SubOpcode:       DW_LNE_end_sequence
+          Data:            0
+ProgramHeaders:
+  - Type:  PT_LOAD
+    Flags: [ PF_X, PF_R ]
+    VAddr: 0x0000000000400000
+    Align: 0x1000
+    FirstSec: .text
+    LastSec:  .text
+Symbols:
+  - Name:    _Z10make_ftypePci
+    Type:    STT_FUNC
+    Section: .text
+    Binding: STB_GLOBAL
+    Value:   0x0000000000401000
+    Size:    0x0000000000000010
+...
diff --git a/llvm/test/tools/llvm-gsymutil/X86/elf-swift-mangled-name-replacement.yaml b/llvm/test/tools/llvm-gsymutil/X86/elf-swift-mangled-name-replacement.yaml
new file mode 100644
index 0000000000000..b706f890c6c35
--- /dev/null
+++ b/llvm/test/tools/llvm-gsymutil/X86/elf-swift-mangled-name-replacement.yaml
@@ -0,0 +1,128 @@
+## Test that same-range dedup keeps the DWARF line table while replacing a
+## shortened Swift DWARF function name with the full Swift symbol-table name.
+
+# RUN: yaml2obj %s -o %t
+# RUN: llvm-gsymutil --convert %t -o %t.gsym 2>&1 | FileCheck %s --check-prefix=CONVERT
+# RUN: llvm-gsymutil %t.gsym 2>&1 | FileCheck %s --check-prefix=DUMP
+
+# CONVERT: Loaded 1 functions from DWARF.
+# CONVERT: Loaded 1 functions from symbol table.
+# CONVERT: Pruned 1 functions, ended with 1 total
+
+# DUMP: "$s4main10make_ftypeyyF"
+# DUMP: LineTable:
+# DUMP: main.swift:10
+# DUMP: main.swift:11
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+Sections:
+  - Name:    .text
+    Type:    SHT_PROGBITS
+    Flags:   [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address: 0x0000000000401000
+    AddressAlign: 0x10
+    Content: 554889E531C05DC3554889E531C05DC3
+DWARF:
+  debug_str:
+    - ''
+    - main.swift
+    - make_ftype
+  debug_abbrev:
+    - ID:              0
+      Table:
+        - Code:            0x1
+          Tag:             DW_TAG_compile_unit
+          Children:        DW_CHILDREN_yes
+          Attributes:
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_language
+              Form:            DW_FORM_udata
+            - Attribute:       DW_AT_stmt_list
+              Form:            DW_FORM_sec_offset
+        - Code:            0x2
+          Tag:             DW_TAG_subprogram
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_low_pc
+              Form:            DW_FORM_addr
+            - Attribute:       DW_AT_high_pc
+              Form:            DW_FORM_addr
+  debug_info:
+    - Length:          0x27
+      Version:         4
+      AbbrevTableID:   0
+      AbbrOffset:      0x0
+      AddrSize:        8
+      Entries:
+        - AbbrCode:        0x1
+          Values:
+            - Value:           0x1
+            - Value:           0x1E
+            - Value:           0x0
+        - AbbrCode:        0x2
+          Values:
+            - Value:           0xC
+            - Value:           0x401000
+            - Value:           0x401010
+        - AbbrCode:        0x0
+  debug_line:
+    - Length:          63
+      Version:         2
+      PrologueLength:  33
+      MinInstLength:   1
+      DefaultIsStmt:   1
+      LineBase:        251
+      LineRange:       14
+      OpcodeBase:      13
+      StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]
+      Files:
+        - Name:            main.swift
+          DirIdx:          0
+          ModTime:         0
+          Length:          0
+      Opcodes:
+        - Opcode:          DW_LNS_extended_op
+          ExtLen:          9
+          SubOpcode:       DW_LNE_set_address
+          Data:            4198400
+        - Opcode:          DW_LNS_advance_line
+          SData:           9
+          Data:            0
+        - Opcode:          DW_LNS_copy
+          Data:            0
+        - Opcode:          DW_LNS_advance_pc
+          Data:            8
+        - Opcode:          DW_LNS_advance_line
+          SData:           1
+          Data:            0
+        - Opcode:          DW_LNS_copy
+          Data:            0
+        - Opcode:          DW_LNS_advance_pc
+          Data:            8
+        - Opcode:          DW_LNS_extended_op
+          ExtLen:          1
+          SubOpcode:       DW_LNE_end_sequence
+          Data:            0
+ProgramHeaders:
+  - Type:  PT_LOAD
+    Flags: [ PF_X, PF_R ]
+    VAddr: 0x0000000000400000
+    Align: 0x1000
+    FirstSec: .text
+    LastSec:  .text
+Symbols:
+  - Name:    '$s4main10make_ftypeyyF'
+    Type:    STT_FUNC
+    Section: .text
+    Binding: STB_GLOBAL
+    Value:   0x0000000000401000
+    Size:    0x0000000000000010
+...
diff --git a/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp b/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp
index 299e19e3c896e..b937dabd927aa 100644
--- a/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp
+++ b/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp
@@ -2813,6 +2813,145 @@ FinalizeEncodeAndDecode(GsymCreator &GC) {
   return GsymReader::copyBuffer(OutStrm.str());
 }
 
+template <typename CreatorT>
+static void AddDuplicateRangePair(CreatorT &GC, uint64_t Addr,
+                                  gsym_strp_t RichName, gsym_strp_t NonRichName,
+                                  bool AddRichFirst, uint32_t FileIdx,
+                                  uint32_t FirstLine) {
+  FunctionInfo RichFI(Addr, 0x20, RichName);
+  RichFI.OptLineTable = LineTable();
+  RichFI.OptLineTable->push(LineEntry(Addr, FileIdx, FirstLine));
+  RichFI.OptLineTable->push(LineEntry(Addr + 0x10, FileIdx, FirstLine + 1));
+
+  FunctionInfo NonRichFI(Addr, 0x20, NonRichName);
+  if (AddRichFirst) {
+    GC.addFunctionInfo(std::move(RichFI));
+    GC.addFunctionInfo(std::move(NonRichFI));
+  } else {
+    GC.addFunctionInfo(std::move(NonRichFI));
+    GC.addFunctionInfo(std::move(RichFI));
+  }
+}
+
+static void VerifyDuplicateRangeResult(const GsymReader &GR, uint64_t Addr,
+                                       StringRef ExpectedName,
+                                       uint32_t ExpectedFileIdx,
+                                       uint32_t FirstLine) {
+  auto ExpFI = GR.getFunctionInfo(Addr);
+  ASSERT_THAT_EXPECTED(ExpFI, Succeeded());
+  EXPECT_EQ(GR.getString(ExpFI->Name), ExpectedName);
+  ASSERT_TRUE(ExpFI->OptLineTable.has_value());
+  ASSERT_EQ(ExpFI->OptLineTable->size(), 2u);
+  EXPECT_EQ((*ExpFI->OptLineTable)[0],
+            LineEntry(Addr, ExpectedFileIdx, FirstLine));
+  EXPECT_EQ((*ExpFI->OptLineTable)[1],
+            LineEntry(Addr + 0x10, ExpectedFileIdx, FirstLine + 1));
+}
+
+template <typename CreatorT> static void TestMangledNameReplacement() {
+  CreatorT GC;
+  const uint32_t FileIdx = GC.insertFile("/tmp/main.cpp");
+  const gsym_strp_t ShortName = GC.insertString("make_ftype");
+  const gsym_strp_t MangledName = GC.insertString("_Z10make_ftypePci");
+  const gsym_strp_t SwiftMangledName =
+      GC.insertString("$s4main10make_ftypeyyF");
+
+  AddDuplicateRangePair(GC, 0x1000, ShortName, MangledName,
+                        /*AddRichFirst=*/false, FileIdx, 10);
+  AddDuplicateRangePair(GC, 0x2000, ShortName, MangledName,
+                        /*AddRichFirst=*/true, FileIdx, 20);
+  AddDuplicateRangePair(GC, 0x3000, ShortName, SwiftMangledName,
+                        /*AddRichFirst=*/false, FileIdx, 30);
+
+  auto GROrErr = FinalizeEncodeAndDecode(GC);
+  ASSERT_THAT_EXPECTED(GROrErr, Succeeded());
+  const std::unique_ptr<GsymReader> &GR = *GROrErr;
+
+  EXPECT_EQ(GR->getNumAddresses(), 3u);
+  VerifyDuplicateRangeResult(*GR, 0x1000, "_Z10make_ftypePci", FileIdx, 10);
+  VerifyDuplicateRangeResult(*GR, 0x2000, "_Z10make_ftypePci", FileIdx, 20);
+  VerifyDuplicateRangeResult(*GR, 0x3000, "$s4main10make_ftypeyyF", FileIdx,
+                             30);
+}
+
+TEST(GSYMTest, TestMangledNameReplacement) {
+  TestMangledNameReplacement<GsymCreatorV1>();
+}
+TEST(GSYMTest, TestMangledNameReplacementV2) {
+  TestMangledNameReplacement<GsymCreatorV2>();
+}
+
+template <typename CreatorT> static void TestMangledNameReplacementNegative() {
+  CreatorT GC;
+  const uint32_t FileIdx = GC.insertFile("/tmp/test.cpp");
+  const gsym_strp_t MangledA = GC.insertString("_Z3foov");
+  const gsym_strp_t MangledB = GC.insertString("_Z3barv");
+  const gsym_strp_t MangledName = GC.insertString("_Z10make_ftypePci");
+  const gsym_strp_t UnrelatedName = GC.insertString("some_other_func");
+  const gsym_strp_t SwiftShortName = GC.insertString("foo");
+  const gsym_strp_t SwiftLongerName = GC.insertString("$s5fooBaryyF");
+
+  AddDuplicateRangePair(GC, 0x3000, MangledB, MangledA,
+                        /*AddRichFirst=*/false, FileIdx, 5);
+  AddDuplicateRangePair(GC, 0x4000, UnrelatedName, MangledName,
+                        /*AddRichFirst=*/false, FileIdx, 15);
+  AddDuplicateRangePair(GC, 0x5000, SwiftShortName, SwiftLongerName,
+                        /*AddRichFirst=*/false, FileIdx, 25);
+
+  auto GROrErr = FinalizeEncodeAndDecode(GC);
+  ASSERT_THAT_EXPECTED(GROrErr, Succeeded());
+  const std::unique_ptr<GsymReader> &GR = *GROrErr;
+
+  EXPECT_EQ(GR->getNumAddresses(), 3u);
+  VerifyDuplicateRangeResult(*GR, 0x3000, "_Z3barv", FileIdx, 5);
+  VerifyDuplicateRangeResult(*GR, 0x4000, "some_other_func", FileIdx, 15);
+  VerifyDuplicateRangeResult(*GR, 0x5000, "foo", FileIdx, 25);
+}
+
+TEST(GSYMTest, TestMangledNameReplacementNegative) {
+  TestMangledNameReplacementNegative<GsymCreatorV1>();
+}
+TEST(GSYMTest, TestMangledNameReplacementNegativeV2) {
+  TestMangledNameReplacementNegative<GsymCreatorV2>();
+}
+
+template <typename CreatorT> static void TestDuplicateRangeKeepsCallSites() {
+  CreatorT GC;
+  const gsym_strp_t FuncName = GC.insertString("foo");
+  const gsym_strp_t MatchRegex = GC.insertString("callee");
+
+  FunctionInfo NonRichFI(0x5000, 0x20, FuncName);
+  FunctionInfo RichFI(0x5000, 0x20, FuncName);
+  RichFI.CallSites = CallSiteInfoCollection();
+  CallSiteInfo CSI;
+  CSI.ReturnOffset = 0x10;
+  CSI.MatchRegex.push_back(MatchRegex);
+  RichFI.CallSites->CallSites.push_back(CSI);
+
+  GC.addFunctionInfo(std::move(NonRichFI));
+  GC.addFunctionInfo(std::move(RichFI));
+
+  auto GROrErr = FinalizeEncodeAndDecode(GC);
+  ASSERT_THAT_EXPECTED(GROrErr, Succeeded());
+  const std::unique_ptr<GsymReader> &GR = *GROrErr;
+
+  auto ExpFI = GR->getFunctionInfo(0x5000);
+  ASSERT_THAT_EXPECTED(ExpFI, Succeeded());
+  ASSERT_TRUE(ExpFI->CallSites.has_value());
+  ASSERT_EQ(ExpFI->CallSites->CallSites.size(), 1u);
+  EXPECT_EQ(ExpFI->CallSites->CallSites[0].ReturnOffset, 0x10u);
+  ASSERT_EQ(ExpFI->CallSites->CallSites[0].MatchRegex.size(), 1u);
+  EXPECT_EQ(GR->getString(ExpFI->CallSites->CallSites[0].MatchRegex[0]),
+            "callee");
+}
+
+TEST(GSYMTest, TestDuplicateRangeKeepsCallSites) {
+  TestDuplicateRangeKeepsCallSites<GsymCreatorV1>();
+}
+TEST(GSYMTest, TestDuplicateRangeKeepsCallSitesV2) {
+  TestDuplicateRangeKeepsCallSites<GsymCreatorV2>();
+}
+
 template <typename CreatorT>
 static void TestGsymSegmenting(uint64_t SegmentSize) {
   // Test creating a GSYM file with function infos and segment the information.



More information about the llvm-commits mailing list