[llvm] [dsymutil] collect pseudoprobe sections from debug map into __LLVM segment (PR #206817)

Henry Jiang via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 7 23:48:54 PDT 2026


https://github.com/mustartt updated https://github.com/llvm/llvm-project/pull/206817

>From a88400d2f74ee75500683c7465dc3bd4ed506551 Mon Sep 17 00:00:00 2001
From: Henry Jiang <henry_jiang2 at apple.com>
Date: Tue, 7 Jul 2026 13:18:11 -0700
Subject: [PATCH 1/2] Revert "[dsymutil] Add support for pseudo probes
 (#186877)"

This reverts commit bc3386c1b9a5bff82ce4baaf4254fc4268f69ff4.

The companion-copy approach (transferring the __PSEUDO_PROBE segment into
the dSYM companion binary) is superseded by gathering the pseudo-probe
sections from the debug-map objects into a sidecar, added in the following
commit.
---
 .../tools/dsymutil/AArch64/pseudo-probe.test  | 319 ------------------
 llvm/tools/dsymutil/MachOUtils.cpp            |  72 +---
 2 files changed, 7 insertions(+), 384 deletions(-)
 delete mode 100644 llvm/test/tools/dsymutil/AArch64/pseudo-probe.test

diff --git a/llvm/test/tools/dsymutil/AArch64/pseudo-probe.test b/llvm/test/tools/dsymutil/AArch64/pseudo-probe.test
deleted file mode 100644
index 0bc97eb574eae..0000000000000
--- a/llvm/test/tools/dsymutil/AArch64/pseudo-probe.test
+++ /dev/null
@@ -1,319 +0,0 @@
-## Test that dsymutil correctly copies pseudoprobe sections and segments
-
-# https://github.com/llvm/llvm-project/issues/190481
-# REQUIRES: host-byteorder-little-endian
-
-# RUN: rm -rf %t && mkdir -p %t
-# RUN: yaml2obj %s -o %t/main.o
-# RUN: dsymutil --linker classic %t/main.o -o %t/main.dSYM
-# RUN: obj2yaml %t/main.dSYM/Contents/Resources/DWARF/main.o -o %t/out.yaml
-# RUN: FileCheck %s < %t/out.yaml
-# RUN: dsymutil --linker parallel %t/main.o -o %t/main.dSYM
-# RUN: obj2yaml %t/main.dSYM/Contents/Resources/DWARF/main.o -o %t/out.yaml
-# RUN: FileCheck %s < %t/out.yaml
-
-# CHECK:        segname:         __PSEUDO_PROBE
-# CHECK:        Sections:
-# CHECK-NEXT:     - sectname:        __probe_descs
-# CHECK-NEXT:       segname:         __PSEUDO_PROBE
-# CHECK:            content:         ACBD18DB4CC2F85CFFFFFFFF0000000003666F6F37B51D194A7513E4FFFFFFFF000000000362617273FEFFA4B7F6BB68FFFFFFFF000002000362617AFAD58DE7366495DBFFFFFFFF00000100046D61696E
-# CHECK-NEXT:     - sectname:        __probes
-# CHECK-NEXT:       segname:         __PSEUDO_PROBE
-# CHECK:            content:         37B51D194A7513E402000020A9A7418A5E3E02B5018000FAD58DE7366495DB0200002001411FAE90F5722601800073FEFFA4B7F6BB6802000020DEDF76EC3AE9F50501800037B51D194A7513E402000020DEDF76EC3AE9F505018000ACBD18DB4CC2F85C020000208774C18D504B6E28018000
-
---- !mach-o
-FileHeader:
-  magic:           0xFEEDFACF
-  cputype:         0x100000C
-  cpusubtype:      0x0
-  filetype:        0x2
-  ncmds:           17
-  sizeofcmds:      976
-  flags:           0x200085
-  reserved:        0x0
-LoadCommands:
-  - cmd:             LC_SEGMENT_64
-    cmdsize:         72
-    segname:         __PAGEZERO
-    vmaddr:          0
-    vmsize:          4294967296
-    fileoff:         0
-    filesize:        0
-    maxprot:         0
-    initprot:        0
-    nsects:          0
-    flags:           0
-  - cmd:             LC_SEGMENT_64
-    cmdsize:         232
-    segname:         __TEXT
-    vmaddr:          4294967296
-    vmsize:          16384
-    fileoff:         0
-    filesize:        16384
-    maxprot:         5
-    initprot:        5
-    nsects:          2
-    flags:           0
-    Sections:
-      - sectname:        __text
-        segname:         __TEXT
-        addr:            0x100000410
-        size:            20
-        offset:          0x410
-        align:           2
-        reloff:          0x0
-        nreloc:          0
-        flags:           0x80000400
-        reserved1:       0x0
-        reserved2:       0x0
-        reserved3:       0x0
-        content:         C0035FD6C0035FD6C0035FD600008052C0035FD6
-      - sectname:        __unwind_info
-        segname:         __TEXT
-        addr:            0x100000424
-        size:            88
-        offset:          0x424
-        align:           2
-        reloff:          0x0
-        nreloc:          0
-        flags:           0x0
-        reserved1:       0x0
-        reserved2:       0x0
-        reserved3:       0x0
-        content:         010000001C000000000000001C000000000000001C00000002000000100400004000000040000000250400000000000040000000000000000000000000000000030000000C00010010000100000000000000000200000000
-  - cmd:             LC_SEGMENT_64
-    cmdsize:         232
-    segname:         __PSEUDO_PROBE
-    vmaddr:          4294983680
-    vmsize:          16384
-    fileoff:         16384
-    filesize:        16384
-    maxprot:         3
-    initprot:        3
-    nsects:          2
-    flags:           0
-    Sections:
-      - sectname:        __probe_descs
-        segname:         __PSEUDO_PROBE
-        addr:            0x100004000
-        size:            81
-        offset:          0x4000
-        align:           0
-        reloff:          0x0
-        nreloc:          0
-        flags:           0x0
-        reserved1:       0x0
-        reserved2:       0x0
-        reserved3:       0x0
-        content:         ACBD18DB4CC2F85CFFFFFFFF0000000003666F6F37B51D194A7513E4FFFFFFFF000000000362617273FEFFA4B7F6BB68FFFFFFFF000002000362617AFAD58DE7366495DBFFFFFFFF00000100046D61696E
-      - sectname:        __probes
-        segname:         __PSEUDO_PROBE
-        addr:            0x100004051
-        size:            115
-        offset:          0x4051
-        align:           0
-        reloff:          0x0
-        nreloc:          0
-        flags:           0x0
-        reserved1:       0x0
-        reserved2:       0x0
-        reserved3:       0x0
-        content:         37B51D194A7513E402000020A9A7418A5E3E02B5018000FAD58DE7366495DB0200002001411FAE90F5722601800073FEFFA4B7F6BB6802000020DEDF76EC3AE9F50501800037B51D194A7513E402000020DEDF76EC3AE9F505018000ACBD18DB4CC2F85C020000208774C18D504B6E28018000
-  - cmd:             LC_SEGMENT_64
-    cmdsize:         72
-    segname:         __LINKEDIT
-    vmaddr:          4295000064
-    vmsize:          16384
-    fileoff:         32768
-    filesize:        680
-    maxprot:         1
-    initprot:        1
-    nsects:          0
-    flags:           0
-  - cmd:             LC_DYLD_CHAINED_FIXUPS
-    cmdsize:         16
-    dataoff:         32768
-    datasize:        56
-  - cmd:             LC_DYLD_EXPORTS_TRIE
-    cmdsize:         16
-    dataoff:         32824
-    datasize:        80
-  - cmd:             LC_SYMTAB
-    cmdsize:         24
-    symoff:          32912
-    nsyms:           5
-    stroff:          32992
-    strsize:         48
-  - cmd:             LC_DYSYMTAB
-    cmdsize:         80
-    ilocalsym:       0
-    nlocalsym:       0
-    iextdefsym:      0
-    nextdefsym:      5
-    iundefsym:       5
-    nundefsym:       0
-    tocoff:          0
-    ntoc:            0
-    modtaboff:       0
-    nmodtab:         0
-    extrefsymoff:    0
-    nextrefsyms:     0
-    indirectsymoff:  0
-    nindirectsyms:   0
-    extreloff:       0
-    nextrel:         0
-    locreloff:       0
-    nlocrel:         0
-  - cmd:             LC_LOAD_DYLINKER
-    cmdsize:         32
-    name:            12
-    Content:         '/usr/lib/dyld'
-    ZeroPadBytes:    7
-  - cmd:             LC_UUID
-    cmdsize:         24
-    uuid:            B95C17E1-7B8C-362B-B402-C636C09BB979
-  - cmd:             LC_BUILD_VERSION
-    cmdsize:         32
-    platform:        1
-    minos:           1703936
-    sdk:             1704448
-    ntools:          1
-    Tools:
-      - tool:            3
-        version:         86573312
-  - cmd:             LC_SOURCE_VERSION
-    cmdsize:         16
-    version:         0
-  - cmd:             LC_MAIN
-    cmdsize:         24
-    entryoff:        1052
-    stacksize:       0
-  - cmd:             LC_LOAD_DYLIB
-    cmdsize:         56
-    dylib:
-      name:            24
-      timestamp:       2
-      current_version: 88866816
-      compatibility_version: 65536
-    Content:         '/usr/lib/libSystem.B.dylib'
-    ZeroPadBytes:    6
-  - cmd:             LC_FUNCTION_STARTS
-    cmdsize:         16
-    dataoff:         32904
-    datasize:        8
-  - cmd:             LC_DATA_IN_CODE
-    cmdsize:         16
-    dataoff:         32912
-    datasize:        0
-  - cmd:             LC_CODE_SIGNATURE
-    cmdsize:         16
-    dataoff:         33040
-    datasize:        408
-LinkEditData:
-  ExportTrie:
-    TerminalSize:    0
-    NodeOffset:      0
-    Name:            ''
-    Flags:           0x0
-    Address:         0x0
-    Other:           0x0
-    ImportName:      ''
-    Children:
-      - TerminalSize:    0
-        NodeOffset:      41
-        Name:            _
-        Flags:           0x0
-        Address:         0x0
-        Other:           0x0
-        ImportName:      ''
-        Children:
-          - TerminalSize:    2
-            NodeOffset:      9
-            Name:            _mh_execute_header
-            Flags:           0x0
-            Address:         0x0
-            Other:           0x0
-            ImportName:      ''
-          - TerminalSize:    0
-            NodeOffset:      23
-            Name:            ba
-            Flags:           0x0
-            Address:         0x0
-            Other:           0x0
-            ImportName:      ''
-            Children:
-              - TerminalSize:    3
-                NodeOffset:      13
-                Name:            r
-                Flags:           0x0
-                Address:         0x414
-                Other:           0x0
-                ImportName:      ''
-              - TerminalSize:    3
-                NodeOffset:      18
-                Name:            z
-                Flags:           0x0
-                Address:         0x418
-                Other:           0x0
-                ImportName:      ''
-          - TerminalSize:    3
-            NodeOffset:      31
-            Name:            foo
-            Flags:           0x0
-            Address:         0x410
-            Other:           0x0
-            ImportName:      ''
-          - TerminalSize:    3
-            NodeOffset:      36
-            Name:            main
-            Flags:           0x0
-            Address:         0x41C
-            Other:           0x0
-            ImportName:      ''
-  NameList:
-    - n_strx:          2
-      n_type:          0xF
-      n_sect:          1
-      n_desc:          16
-      n_value:         4294967296
-    - n_strx:          22
-      n_type:          0xF
-      n_sect:          1
-      n_desc:          0
-      n_value:         4294968340
-    - n_strx:          27
-      n_type:          0xF
-      n_sect:          1
-      n_desc:          0
-      n_value:         4294968344
-    - n_strx:          32
-      n_type:          0xF
-      n_sect:          1
-      n_desc:          0
-      n_value:         4294968336
-    - n_strx:          37
-      n_type:          0xF
-      n_sect:          1
-      n_desc:          0
-      n_value:         4294968348
-  StringTable:
-    - ' '
-    - __mh_execute_header
-    - _bar
-    - _baz
-    - _foo
-    - _main
-    - ''
-    - ''
-    - ''
-    - ''
-    - ''
-  FunctionStarts:  [ 0x410, 0x414, 0x418, 0x41C ]
-  ChainedFixups:   [ 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x34, 0x0, 
-                     0x0, 0x0, 0x34, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
-                     0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
-                     0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
-                     0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
-                     0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]
-...
-
diff --git a/llvm/tools/dsymutil/MachOUtils.cpp b/llvm/tools/dsymutil/MachOUtils.cpp
index a6dd3afa223e7..9b143157ac773 100644
--- a/llvm/tools/dsymutil/MachOUtils.cpp
+++ b/llvm/tools/dsymutil/MachOUtils.cpp
@@ -269,19 +269,13 @@ getSection(const object::MachOObjectFile &Obj,
 //
 // When the eh_frame section is transferred, its offset and size are set resp.
 // to \a EHFrameOffset and \a EHFrameSize.
-//
-// When the __PSEUDO_PROBE segment is transferred, its offset and size are set
-// resp. to \a PseudoProbeOffset and \a PseudoProbeSize, and its sections'
-// offsets are updated using \a PseudoProbeProbesOffset for __probes and
-// \a PseudoProbeDescsOffset for __probe_descs.
 template <typename SegmentTy>
 static void transferSegmentAndSections(
     const object::MachOObjectFile::LoadCommandInfo &LCI, SegmentTy Segment,
     const object::MachOObjectFile &Obj, MachObjectWriter &Writer,
     uint64_t LinkeditOffset, uint64_t LinkeditSize, uint64_t EHFrameOffset,
-    uint64_t EHFrameSize, uint64_t PseudoProbeOffset, uint64_t PseudoProbeSize,
-    uint64_t PseudoProbeProbesOffset, uint64_t PseudoProbeDescsOffset,
-    uint64_t DwarfSegmentSize, uint64_t &GapForDwarf, uint64_t &EndAddress) {
+    uint64_t EHFrameSize, uint64_t DwarfSegmentSize, uint64_t &GapForDwarf,
+    uint64_t &EndAddress) {
   if (StringRef("__DWARF") == Segment.segname)
     return;
 
@@ -293,10 +287,6 @@ static void transferSegmentAndSections(
     Segment.filesize = LinkeditSize;
     // Resize vmsize by rounding to the page size.
     Segment.vmsize = alignTo(LinkeditSize, 0x1000);
-  } else if (StringRef("__PSEUDO_PROBE") == Segment.segname &&
-             PseudoProbeSize > 0) {
-    Segment.fileoff = PseudoProbeOffset;
-    Segment.filesize = PseudoProbeSize;
   } else {
     Segment.fileoff = Segment.filesize = 0;
   }
@@ -322,14 +312,6 @@ static void transferSegmentAndSections(
     if (StringRef("__eh_frame") == Sect.sectname) {
       Sect.offset = EHFrameOffset;
       Sect.reloff = Sect.nreloc = 0;
-    } else if (StringRef("__probes") == Sect.sectname &&
-               PseudoProbeProbesOffset > 0) {
-      Sect.offset = PseudoProbeProbesOffset;
-      Sect.reloff = Sect.nreloc = 0;
-    } else if (StringRef("__probe_descs") == Sect.sectname &&
-               PseudoProbeDescsOffset > 0) {
-      Sect.offset = PseudoProbeDescsOffset;
-      Sect.reloff = Sect.nreloc = 0;
     } else {
       Sect.offset = Sect.reloff = Sect.nreloc = 0;
     }
@@ -481,10 +463,6 @@ bool generateDsymCompanion(
   // If we have a valid eh_frame to copy, do it.
   uint64_t EHFrameSize = 0;
   StringRef EHFrameData;
-  StringRef PseudoProbeProbesData;
-  uint64_t PseudoProbeProbesSize = 0;
-  StringRef PseudoProbeDescsData;
-  uint64_t PseudoProbeDescsSize = 0;
   for (const object::SectionRef &Section : InputBinary.sections()) {
     Expected<StringRef> NameOrErr = Section.getName();
     if (!NameOrErr) {
@@ -500,23 +478,8 @@ bool generateDsymCompanion(
       } else {
         consumeError(ContentsOrErr.takeError());
       }
-    } else if (SectionName == "probes") {
-      if (Expected<StringRef> ContentsOrErr = Section.getContents()) {
-        PseudoProbeProbesData = *ContentsOrErr;
-        PseudoProbeProbesSize = Section.getSize();
-      } else {
-        consumeError(ContentsOrErr.takeError());
-      }
-    } else if (SectionName == "probe_descs") {
-      if (Expected<StringRef> ContentsOrErr = Section.getContents()) {
-        PseudoProbeDescsData = *ContentsOrErr;
-        PseudoProbeDescsSize = Section.getSize();
-      } else {
-        consumeError(ContentsOrErr.takeError());
-      }
     }
   }
-  uint64_t PseudoProbeSize = PseudoProbeProbesSize + PseudoProbeDescsSize;
 
   unsigned HeaderSize =
       Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
@@ -598,16 +561,8 @@ bool generateDsymCompanion(
   uint64_t EHFrameStart = StringStart + NewStringsSize;
   EHFrameStart = alignTo(EHFrameStart, 0x1000);
 
-  // Place pseudo probe data after the EH frame.
-  uint64_t PseudoProbeStart = PseudoProbeSize > 0
-                                  ? alignTo(EHFrameStart + EHFrameSize, 0x1000)
-                                  : EHFrameStart + EHFrameSize;
-
-  uint64_t PseudoProbeProbesStart = PseudoProbeStart;
-  uint64_t PseudoProbeDescsStart = PseudoProbeStart + PseudoProbeProbesSize;
-
-  uint64_t DwarfSegmentStart =
-      alignTo(PseudoProbeStart + PseudoProbeSize, 0x1000);
+  uint64_t DwarfSegmentStart = EHFrameStart + EHFrameSize;
+  DwarfSegmentStart = alignTo(DwarfSegmentStart, 0x1000);
 
   // Write the load commands for the segments and sections we 'import' from
   // the original binary.
@@ -618,16 +573,12 @@ bool generateDsymCompanion(
       transferSegmentAndSections(
           LCI, InputBinary.getSegmentLoadCommand(LCI), InputBinary, Writer,
           SymtabStart, StringStart + NewStringsSize - SymtabStart, EHFrameStart,
-          EHFrameSize, PseudoProbeStart, PseudoProbeSize,
-          PseudoProbeProbesStart, PseudoProbeDescsStart, DwarfSegmentSize,
-          GapForDwarf, EndAddress);
+          EHFrameSize, DwarfSegmentSize, GapForDwarf, EndAddress);
     else if (LCI.C.cmd == MachO::LC_SEGMENT_64)
       transferSegmentAndSections(
           LCI, InputBinary.getSegment64LoadCommand(LCI), InputBinary, Writer,
           SymtabStart, StringStart + NewStringsSize - SymtabStart, EHFrameStart,
-          EHFrameSize, PseudoProbeStart, PseudoProbeSize,
-          PseudoProbeProbesStart, PseudoProbeDescsStart, DwarfSegmentSize,
-          GapForDwarf, EndAddress);
+          EHFrameSize, DwarfSegmentSize, GapForDwarf, EndAddress);
   }
 
   uint64_t DwarfVMAddr = alignTo(EndAddress, 0x1000);
@@ -681,17 +632,8 @@ bool generateDsymCompanion(
     OutFile << EHFrameData;
   assert(OutFile.tell() == EHFrameStart + EHFrameSize);
 
-  // Transfer pseudo probe.
-  if (PseudoProbeSize > 0) {
-    OutFile.write_zeros(PseudoProbeStart - (EHFrameStart + EHFrameSize));
-    assert(OutFile.tell() == PseudoProbeStart);
-    OutFile << PseudoProbeProbesData;
-    OutFile << PseudoProbeDescsData;
-    assert(OutFile.tell() == PseudoProbeStart + PseudoProbeSize);
-  }
-
   // Pad till the Dwarf segment start.
-  OutFile.write_zeros(DwarfSegmentStart - OutFile.tell());
+  OutFile.write_zeros(DwarfSegmentStart - (EHFrameStart + EHFrameSize));
   assert(OutFile.tell() == DwarfSegmentStart);
 
   // Emit the Dwarf sections contents.

>From 23983c5c8c8713f94e56f2683eadb182776019ae Mon Sep 17 00:00:00 2001
From: Henry Jiang <henry_jiang2 at apple.com>
Date: Tue, 7 Jul 2026 13:41:14 -0700
Subject: [PATCH 2/2] [dsymutil] Collect MachO pseudo-probe sections into dSYM
 companion file

---
 .../AArch64/pseudo-probe-universal.test       | 439 ++++++++++++++++++
 .../tools/dsymutil/AArch64/pseudo-probe.test  | 366 +++++++++++++++
 llvm/tools/dsymutil/CMakeLists.txt            |   1 +
 llvm/tools/dsymutil/PseudoProbeLinker.cpp     | 184 ++++++++
 llvm/tools/dsymutil/PseudoProbeLinker.h       |  55 +++
 llvm/tools/dsymutil/dsymutil.cpp              |   5 +
 6 files changed, 1050 insertions(+)
 create mode 100644 llvm/test/tools/dsymutil/AArch64/pseudo-probe-universal.test
 create mode 100644 llvm/test/tools/dsymutil/AArch64/pseudo-probe.test
 create mode 100644 llvm/tools/dsymutil/PseudoProbeLinker.cpp
 create mode 100644 llvm/tools/dsymutil/PseudoProbeLinker.h

diff --git a/llvm/test/tools/dsymutil/AArch64/pseudo-probe-universal.test b/llvm/test/tools/dsymutil/AArch64/pseudo-probe-universal.test
new file mode 100644
index 0000000000000..6ff9caadf3449
--- /dev/null
+++ b/llvm/test/tools/dsymutil/AArch64/pseudo-probe-universal.test
@@ -0,0 +1,439 @@
+# REQUIRES: aarch64-registered-target
+# REQUIRES: host-byteorder-little-endian
+
+# RUN: rm -rf %t && split-file %s %t
+# RUN: yaml2obj %t/fat.dylib.yaml -o %t/fat.dylib
+# RUN: yaml2obj %t/a.o.yaml -o %t/a.o
+# RUN: yaml2obj %t/e.o.yaml -o %t/e.o
+
+# RUN: dsymutil --linker classic --no-object-timestamp %t/fat.dylib -oso-prepend-path=%t -o %t/classic.dSYM
+# RUN: llvm-readobj --file-headers --sections %t/classic.dSYM/Contents/Resources/Profiling/pseudo_probes-arm64 \
+# RUN:    | FileCheck %s --check-prefix=ARM64
+# RUN: llvm-readobj --file-headers --sections %t/classic.dSYM/Contents/Resources/Profiling/pseudo_probes-arm64e \
+# RUN:    | FileCheck %s --check-prefix=ARM64E
+# RUN: llvm-objdump -s --section=__probes --section=__probe_descs %t/classic.dSYM/Contents/Resources/Profiling/pseudo_probes-arm64 \
+# RUN:    | FileCheck %s --check-prefix=DATA
+
+# RUN: dsymutil --linker parallel --no-object-timestamp %t/fat.dylib -oso-prepend-path=%t -o %t/parallel.dSYM
+# RUN: llvm-readobj --file-headers --sections %t/parallel.dSYM/Contents/Resources/Profiling/pseudo_probes-arm64 \
+# RUN:    | FileCheck %s --check-prefix=ARM64
+# RUN: llvm-readobj --file-headers --sections %t/parallel.dSYM/Contents/Resources/Profiling/pseudo_probes-arm64e \
+# RUN:    | FileCheck %s --check-prefix=ARM64E
+# RUN: llvm-objdump -s --section=__probes --section=__probe_descs %t/parallel.dSYM/Contents/Resources/Profiling/pseudo_probes-arm64 \
+# RUN:    | FileCheck %s --check-prefix=DATA
+
+# ARM64:      CpuType: Arm64
+# ARM64:      CpuSubType: CPU_SUBTYPE_ARM64_ALL
+# ARM64:      Name: __probes
+# ARM64-NEXT: Segment: __LLVM
+# ARM64-NEXT: Address: 0x0
+# ARM64-NEXT: Size: 0x3C
+# ARM64-NEXT: Offset: 368
+# ARM64:      Name: __probe_descs
+# ARM64-NEXT: Segment: __LLVM
+# ARM64-NEXT: Address: 0x3C
+# ARM64-NEXT: Size: 0x27
+# ARM64-NEXT: Offset: 428
+
+# ARM64E:      CpuType: Arm64
+# ARM64E:      CpuSubType: CPU_SUBTYPE_ARM64E
+# ARM64E:      Name: __probes
+# ARM64E-NEXT: Segment: __LLVM
+# ARM64E-NEXT: Address: 0x0
+# ARM64E-NEXT: Size: 0x3C
+# ARM64E-NEXT: Offset: 368
+# ARM64E:      Name: __probe_descs
+# ARM64E-NEXT: Segment: __LLVM
+# ARM64E-NEXT: Address: 0x3C
+# ARM64E-NEXT: Size: 0x27
+# ARM64E-NEXT: Offset: 428
+
+# DATA:      Contents of section __LLVM,__probes:
+# DATA-NEXT: 0000 fad58de7 366495db
+# DATA:      Contents of section __LLVM,__probe_descs:
+# DATA-NEXT: 003c 8fa14cdd 754f91cc
+# DATA:      046d 61696e
+
+
+#--- fat.dylib.yaml
+--- !fat-mach-o
+FatHeader:
+  magic:           0xCAFEBABE
+  nfat_arch:       2
+FatArchs:
+  - cputype:         0x100000C
+    cpusubtype:      0x0
+    offset:          0x4000
+    size:            181
+    align:           14
+  - cputype:         0x100000C
+    cpusubtype:      0x2
+    offset:          0x8000
+    size:            181
+    align:           14
+Slices:
+  - !mach-o
+    FileHeader:
+      magic:           0xFEEDFACF
+      cputype:         0x100000C
+      cpusubtype:      0x0
+      filetype:        0x6
+      ncmds:           3
+      sizeofcmds:      128
+      flags:           0x100085
+      reserved:        0x0
+    LoadCommands:
+      - cmd:             LC_SEGMENT_64
+        cmdsize:         72
+        segname:         __LINKEDIT
+        vmaddr:          16384
+        vmsize:          4096
+        fileoff:         160
+        filesize:        21
+        maxprot:         1
+        initprot:        1
+        nsects:          0
+        flags:           0
+      - cmd:             LC_ID_DYLIB
+        cmdsize:         32
+        dylib:
+          name:            24
+          timestamp:       0
+          current_version: 0
+          compatibility_version: 0
+        Content:         probe
+        ZeroPadBytes:    3
+      - cmd:             LC_SYMTAB
+        cmdsize:         24
+        symoff:          160
+        nsyms:           1
+        stroff:          176
+        strsize:         5
+    LinkEditData:
+      NameList:
+        - n_strx:          1
+          n_type:          0x66
+          n_sect:          0
+          n_desc:          1
+          n_value:         0
+      StringTable:
+        - ''
+        - a.o
+  - !mach-o
+    FileHeader:
+      magic:           0xFEEDFACF
+      cputype:         0x100000C
+      cpusubtype:      0x2
+      filetype:        0x6
+      ncmds:           3
+      sizeofcmds:      128
+      flags:           0x100085
+      reserved:        0x0
+    LoadCommands:
+      - cmd:             LC_SEGMENT_64
+        cmdsize:         72
+        segname:         __LINKEDIT
+        vmaddr:          16384
+        vmsize:          4096
+        fileoff:         160
+        filesize:        21
+        maxprot:         1
+        initprot:        1
+        nsects:          0
+        flags:           0
+      - cmd:             LC_ID_DYLIB
+        cmdsize:         32
+        dylib:
+          name:            24
+          timestamp:       0
+          current_version: 0
+          compatibility_version: 0
+        Content:         probe
+        ZeroPadBytes:    3
+      - cmd:             LC_SYMTAB
+        cmdsize:         24
+        symoff:          160
+        nsyms:           1
+        stroff:          176
+        strsize:         5
+    LinkEditData:
+      NameList:
+        - n_strx:          1
+          n_type:          0x66
+          n_sect:          0
+          n_desc:          1
+          n_value:         0
+      StringTable:
+        - ''
+        - e.o
+...
+
+#--- a.o.yaml
+--- !mach-o
+FileHeader:
+  magic:           0xFEEDFACF
+  cputype:         0x100000C
+  cpusubtype:      0x0
+  filetype:        0x1
+  ncmds:           4
+  sizeofcmds:      440
+  flags:           0x2000
+  reserved:        0x0
+LoadCommands:
+  - cmd:             LC_SEGMENT_64
+    cmdsize:         312
+    segname:         ''
+    vmaddr:          0
+    vmsize:          813
+    fileoff:         472
+    filesize:        115
+    maxprot:         7
+    initprot:        7
+    nsects:          3
+    flags:           0
+    Sections:
+      - sectname:        __text
+        segname:         __TEXT
+        addr:            0x0
+        size:            16
+        offset:          0x1D8
+        align:           2
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x80000400
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         00040011C0035FD640008052C0035FD6
+      - sectname:        __probe_descs
+        segname:         __PSEUDO_PROBE
+        addr:            0x10
+        size:            39
+        offset:          0x1E8
+        align:           0
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x12000000
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         8FA14CDD754F91CCFFFFFFFF000000000166FAD58DE7366495DBFFFFFFFF00000100046D61696E
+      - sectname:        __probes
+        segname:         __PSEUDO_PROBE
+        addr:            0x2F1
+        size:            60
+        offset:          0x20F
+        align:           0
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x12000000
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         FAD58DE7366495DB0201002001411FAE90F57226018000028FA14CDD754F91CC01000180008FA14CDD754F91CC02000020E99036E91302D08B018000
+  - cmd:             LC_BUILD_VERSION
+    cmdsize:         24
+    platform:        1
+    minos:           1703936
+    sdk:             1704960
+    ntools:          0
+  - cmd:             LC_SYMTAB
+    cmdsize:         24
+    symoff:          587
+    nsyms:           5
+    stroff:          667
+    strsize:         32
+  - cmd:             LC_DYSYMTAB
+    cmdsize:         80
+    ilocalsym:       0
+    nlocalsym:       3
+    iextdefsym:      3
+    nextdefsym:      2
+    iundefsym:       5
+    nundefsym:       0
+    tocoff:          0
+    ntoc:            0
+    modtaboff:       0
+    nmodtab:         0
+    extrefsymoff:    0
+    nextrefsyms:     0
+    indirectsymoff:  0
+    nindirectsyms:   0
+    extreloff:       0
+    nextrel:         0
+    locreloff:       0
+    nlocrel:         0
+LinkEditData:
+  NameList:
+    - n_strx:          22
+      n_type:          0xE
+      n_sect:          1
+      n_desc:          0
+      n_value:         0
+    - n_strx:          16
+      n_type:          0xE
+      n_sect:          2
+      n_desc:          0
+      n_value:         16
+    - n_strx:          10
+      n_type:          0xE
+      n_sect:          3
+      n_desc:          0
+      n_value:         753
+    - n_strx:          7
+      n_type:          0xF
+      n_sect:          1
+      n_desc:          0
+      n_value:         0
+    - n_strx:          1
+      n_type:          0xF
+      n_sect:          1
+      n_desc:          0
+      n_value:         8
+  StringTable:
+    - ''
+    - _main
+    - _f
+    - ltmp2
+    - ltmp1
+    - ltmp0
+    - ''
+    - ''
+    - ''
+    - ''
+...
+
+#--- e.o.yaml
+--- !mach-o
+FileHeader:
+  magic:           0xFEEDFACF
+  cputype:         0x100000C
+  cpusubtype:      0x80000002
+  filetype:        0x1
+  ncmds:           4
+  sizeofcmds:      440
+  flags:           0x2000
+  reserved:        0x0
+LoadCommands:
+  - cmd:             LC_SEGMENT_64
+    cmdsize:         312
+    segname:         ''
+    vmaddr:          0
+    vmsize:          813
+    fileoff:         472
+    filesize:        115
+    maxprot:         7
+    initprot:        7
+    nsects:          3
+    flags:           0
+    Sections:
+      - sectname:        __text
+        segname:         __TEXT
+        addr:            0x0
+        size:            16
+        offset:          0x1D8
+        align:           2
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x80000400
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         00040011C0035FD640008052C0035FD6
+      - sectname:        __probe_descs
+        segname:         __PSEUDO_PROBE
+        addr:            0x10
+        size:            39
+        offset:          0x1E8
+        align:           0
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x12000000
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         8FA14CDD754F91CCFFFFFFFF000000000166FAD58DE7366495DBFFFFFFFF00000100046D61696E
+      - sectname:        __probes
+        segname:         __PSEUDO_PROBE
+        addr:            0x2F1
+        size:            60
+        offset:          0x20F
+        align:           0
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x12000000
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         FAD58DE7366495DB0201002001411FAE90F57226018000028FA14CDD754F91CC01000180008FA14CDD754F91CC02000020E99036E91302D08B018000
+  - cmd:             LC_BUILD_VERSION
+    cmdsize:         24
+    platform:        1
+    minos:           1703936
+    sdk:             1704960
+    ntools:          0
+  - cmd:             LC_SYMTAB
+    cmdsize:         24
+    symoff:          587
+    nsyms:           5
+    stroff:          667
+    strsize:         32
+  - cmd:             LC_DYSYMTAB
+    cmdsize:         80
+    ilocalsym:       0
+    nlocalsym:       3
+    iextdefsym:      3
+    nextdefsym:      2
+    iundefsym:       5
+    nundefsym:       0
+    tocoff:          0
+    ntoc:            0
+    modtaboff:       0
+    nmodtab:         0
+    extrefsymoff:    0
+    nextrefsyms:     0
+    indirectsymoff:  0
+    nindirectsyms:   0
+    extreloff:       0
+    nextrel:         0
+    locreloff:       0
+    nlocrel:         0
+LinkEditData:
+  NameList:
+    - n_strx:          22
+      n_type:          0xE
+      n_sect:          1
+      n_desc:          0
+      n_value:         0
+    - n_strx:          16
+      n_type:          0xE
+      n_sect:          2
+      n_desc:          0
+      n_value:         16
+    - n_strx:          10
+      n_type:          0xE
+      n_sect:          3
+      n_desc:          0
+      n_value:         753
+    - n_strx:          7
+      n_type:          0xF
+      n_sect:          1
+      n_desc:          0
+      n_value:         0
+    - n_strx:          1
+      n_type:          0xF
+      n_sect:          1
+      n_desc:          0
+      n_value:         8
+  StringTable:
+    - ''
+    - _main
+    - _f
+    - ltmp2
+    - ltmp1
+    - ltmp0
+    - ''
+    - ''
+    - ''
+    - ''
+...
diff --git a/llvm/test/tools/dsymutil/AArch64/pseudo-probe.test b/llvm/test/tools/dsymutil/AArch64/pseudo-probe.test
new file mode 100644
index 0000000000000..bf676af963c81
--- /dev/null
+++ b/llvm/test/tools/dsymutil/AArch64/pseudo-probe.test
@@ -0,0 +1,366 @@
+# REQUIRES: aarch64-registered-target
+# REQUIRES: host-byteorder-little-endian
+
+# RUN: rm -rf %t
+# RUN: split-file %s %t
+# RUN: mkdir -p %t
+# RUN: yaml2obj %t/a.yaml -o %t/a.o
+# RUN: yaml2obj %t/b.yaml -o %t/b.o
+
+# RUN: dsymutil --linker classic -y %t/debug.map -oso-prepend-path=%t -o %t/classic.dSYM
+# RUN: llvm-objdump --section-headers %t/classic.dSYM/Contents/Resources/Profiling/pseudo_probes \
+# RUN:    | FileCheck %s --check-prefix=SIZE
+# RUN: llvm-readobj --sections %t/classic.dSYM/Contents/Resources/Profiling/pseudo_probes \
+# RUN:    | FileCheck %s --check-prefix=SEG
+# RUN: llvm-objdump -s --section=__probes --section=__probe_descs \
+# RUN:    %t/classic.dSYM/Contents/Resources/Profiling/pseudo_probes | FileCheck %s --check-prefix=DATA
+
+# RUN: dsymutil --linker parallel -y %t/debug.map -oso-prepend-path=%t -o %t/parallel.dSYM
+# RUN: llvm-objdump --section-headers %t/parallel.dSYM/Contents/Resources/Profiling/pseudo_probes \
+# RUN:    | FileCheck %s --check-prefix=SIZE
+# RUN: llvm-readobj --sections %t/parallel.dSYM/Contents/Resources/Profiling/pseudo_probes \
+# RUN:    | FileCheck %s --check-prefix=SEG
+# RUN: llvm-objdump -s --section=__probes --section=__probe_descs \
+# RUN:    %t/parallel.dSYM/Contents/Resources/Profiling/pseudo_probes | FileCheck %s --check-prefix=DATA
+
+# SEG:      Name: __probes
+# SEG-NEXT: Segment: __LLVM
+# SEG:      Name: __probe_descs
+# SEG-NEXT: Segment: __LLVM
+
+# SIZE: __probes      00000040
+# SIZE: __probe_descs 00000024
+
+# DATA:      Contents of section __LLVM,__probes:
+# DATA-NEXT: {{[0-9a-f]+}} 0cc175b9 c0f1b6a8 05000020 5c855e09
+# DATA-NEXT: {{[0-9a-f]+}} 4bdf284e 01800c02 80140380 0c048008
+# DATA-NEXT: {{[0-9a-f]+}} 92eb5ffe e6ae2fec 05000020 c716fb29
+# DATA-NEXT: {{[0-9a-f]+}} 298ad96a 01800c02 80140380 0c048008
+# DATA:      Contents of section __LLVM,__probe_descs:
+# DATA-NEXT: {{[0-9a-f]+}} 0cc175b9 c0f1b6a8 94da52e8 10000000
+# DATA-NEXT: {{[0-9a-f]+}} 016192eb 5ffee6ae 2fec94da 52e81000
+# DATA-NEXT: {{[0-9a-f]+}} 00000162
+
+#--- debug.map
+---
+triple:          'arm64-apple-darwin'
+objects:
+  - filename: a.o
+    symbols:         []
+  - filename: b.o
+    symbols:         []
+...
+
+#--- a.yaml
+--- !mach-o
+FileHeader:
+  magic:           0xFEEDFACF
+  cputype:         0x100000C
+  cpusubtype:      0x0
+  filetype:        0x1
+  ncmds:           4
+  sizeofcmds:      520
+  flags:           0x2000
+  reserved:        0x0
+LoadCommands:
+  - cmd:             LC_SEGMENT_64
+    cmdsize:         392
+    segname:         ''
+    vmaddr:          0
+    vmsize:          144
+    fileoff:         552
+    filesize:        144
+    maxprot:         7
+    initprot:        7
+    nsects:          4
+    flags:           0
+    Sections:
+      - sectname:        __text
+        segname:         __TEXT
+        addr:            0x0
+        size:            60
+        offset:          0x228
+        align:           2
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x80000400
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         FF4300D1E00B00B9E80B40B9C800003401000014E80B40B908050011E80F00B90400001408008052E80F00B901000014E00F40B9FF430091C0035FD6
+      - sectname:        __probe_descs
+        segname:         __LLVM
+        addr:            0x3C
+        size:            18
+        offset:          0x264
+        align:           0
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x12000000
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         0CC175B9C0F1B6A894DA52E8100000000161
+      - sectname:        __compact_unwind
+        segname:         __LD
+        addr:            0x50
+        size:            32
+        offset:          0x278
+        align:           3
+        reloff:          0x2B8
+        nreloc:          1
+        flags:           0x2000000
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         00000000000000003C0000000010000200000000000000000000000000000000
+        relocations:
+          - address:         0x0
+            symbolnum:       1
+            pcrel:           false
+            length:          3
+            extern:          false
+            type:            0
+            scattered:       false
+            value:           0
+      - sectname:        __probes
+        segname:         __LLVM
+        addr:            0x70
+        size:            32
+        offset:          0x298
+        align:           0
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x12000000
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         0CC175B9C0F1B6A8050000205C855E094BDF284E01800C02801403800C048008
+  - cmd:             LC_BUILD_VERSION
+    cmdsize:         24
+    platform:        1
+    minos:           1703936
+    sdk:             1704960
+    ntools:          0
+  - cmd:             LC_SYMTAB
+    cmdsize:         24
+    symoff:          704
+    nsyms:           5
+    stroff:          784
+    strsize:         32
+  - cmd:             LC_DYSYMTAB
+    cmdsize:         80
+    ilocalsym:       0
+    nlocalsym:       4
+    iextdefsym:      4
+    nextdefsym:      1
+    iundefsym:       5
+    nundefsym:       0
+    tocoff:          0
+    ntoc:            0
+    modtaboff:       0
+    nmodtab:         0
+    extrefsymoff:    0
+    nextrefsyms:     0
+    indirectsymoff:  0
+    nindirectsyms:   0
+    extreloff:       0
+    nextrel:         0
+    locreloff:       0
+    nlocrel:         0
+LinkEditData:
+  NameList:
+    - n_strx:          22
+      n_type:          0xE
+      n_sect:          1
+      n_desc:          0
+      n_value:         0
+    - n_strx:          16
+      n_type:          0xE
+      n_sect:          2
+      n_desc:          0
+      n_value:         60
+    - n_strx:          10
+      n_type:          0xE
+      n_sect:          3
+      n_desc:          0
+      n_value:         80
+    - n_strx:          4
+      n_type:          0xE
+      n_sect:          4
+      n_desc:          0
+      n_value:         112
+    - n_strx:          1
+      n_type:          0xF
+      n_sect:          1
+      n_desc:          0
+      n_value:         0
+  StringTable:
+    - ''
+    - _a
+    - ltmp3
+    - ltmp2
+    - ltmp1
+    - ltmp0
+    - ''
+    - ''
+    - ''
+    - ''
+...
+
+#--- b.yaml
+--- !mach-o
+FileHeader:
+  magic:           0xFEEDFACF
+  cputype:         0x100000C
+  cpusubtype:      0x0
+  filetype:        0x1
+  ncmds:           4
+  sizeofcmds:      520
+  flags:           0x2000
+  reserved:        0x0
+LoadCommands:
+  - cmd:             LC_SEGMENT_64
+    cmdsize:         392
+    segname:         ''
+    vmaddr:          0
+    vmsize:          144
+    fileoff:         552
+    filesize:        144
+    maxprot:         7
+    initprot:        7
+    nsects:          4
+    flags:           0
+    Sections:
+      - sectname:        __text
+        segname:         __TEXT
+        addr:            0x0
+        size:            60
+        offset:          0x228
+        align:           2
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x80000400
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         FF4300D1E00B00B9E80B40B9C800003401000014E80B40B908791F53E80F00B90400001428008052E80F00B901000014E00F40B9FF430091C0035FD6
+      - sectname:        __probe_descs
+        segname:         __LLVM
+        addr:            0x3C
+        size:            18
+        offset:          0x264
+        align:           0
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x12000000
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         92EB5FFEE6AE2FEC94DA52E8100000000162
+      - sectname:        __compact_unwind
+        segname:         __LD
+        addr:            0x50
+        size:            32
+        offset:          0x278
+        align:           3
+        reloff:          0x2B8
+        nreloc:          1
+        flags:           0x2000000
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         00000000000000003C0000000010000200000000000000000000000000000000
+        relocations:
+          - address:         0x0
+            symbolnum:       1
+            pcrel:           false
+            length:          3
+            extern:          false
+            type:            0
+            scattered:       false
+            value:           0
+      - sectname:        __probes
+        segname:         __LLVM
+        addr:            0x70
+        size:            32
+        offset:          0x298
+        align:           0
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x12000000
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         92EB5FFEE6AE2FEC05000020C716FB29298AD96A01800C02801403800C048008
+  - cmd:             LC_BUILD_VERSION
+    cmdsize:         24
+    platform:        1
+    minos:           1703936
+    sdk:             1704960
+    ntools:          0
+  - cmd:             LC_SYMTAB
+    cmdsize:         24
+    symoff:          704
+    nsyms:           5
+    stroff:          784
+    strsize:         32
+  - cmd:             LC_DYSYMTAB
+    cmdsize:         80
+    ilocalsym:       0
+    nlocalsym:       4
+    iextdefsym:      4
+    nextdefsym:      1
+    iundefsym:       5
+    nundefsym:       0
+    tocoff:          0
+    ntoc:            0
+    modtaboff:       0
+    nmodtab:         0
+    extrefsymoff:    0
+    nextrefsyms:     0
+    indirectsymoff:  0
+    nindirectsyms:   0
+    extreloff:       0
+    nextrel:         0
+    locreloff:       0
+    nlocrel:         0
+LinkEditData:
+  NameList:
+    - n_strx:          22
+      n_type:          0xE
+      n_sect:          1
+      n_desc:          0
+      n_value:         0
+    - n_strx:          16
+      n_type:          0xE
+      n_sect:          2
+      n_desc:          0
+      n_value:         60
+    - n_strx:          10
+      n_type:          0xE
+      n_sect:          3
+      n_desc:          0
+      n_value:         80
+    - n_strx:          4
+      n_type:          0xE
+      n_sect:          4
+      n_desc:          0
+      n_value:         112
+    - n_strx:          1
+      n_type:          0xF
+      n_sect:          1
+      n_desc:          0
+      n_value:         0
+  StringTable:
+    - ''
+    - _b
+    - ltmp3
+    - ltmp2
+    - ltmp1
+    - ltmp0
+    - ''
+    - ''
+    - ''
+    - ''
+...
diff --git a/llvm/tools/dsymutil/CMakeLists.txt b/llvm/tools/dsymutil/CMakeLists.txt
index d3cdbe466de08..eeff3986fef88 100644
--- a/llvm/tools/dsymutil/CMakeLists.txt
+++ b/llvm/tools/dsymutil/CMakeLists.txt
@@ -33,6 +33,7 @@ add_llvm_tool(dsymutil
   DwarfLinkerForBinary.cpp
   MachODebugMapParser.cpp
   MachOUtils.cpp
+  PseudoProbeLinker.cpp
   Reproducer.cpp
   RelocationMap.cpp
   SwiftModule.cpp
diff --git a/llvm/tools/dsymutil/PseudoProbeLinker.cpp b/llvm/tools/dsymutil/PseudoProbeLinker.cpp
new file mode 100644
index 0000000000000..9848dc65e6bd4
--- /dev/null
+++ b/llvm/tools/dsymutil/PseudoProbeLinker.cpp
@@ -0,0 +1,184 @@
+//===- tools/dsymutil/PseudoProbeLinker.cpp -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "PseudoProbeLinker.h"
+#include "BinaryHolder.h"
+#include "DebugMap.h"
+#include "LinkUtils.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSectionMachO.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCTargetOptions.h"
+#include "llvm/MC/SectionKind.h"
+#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/TargetParser/Triple.h"
+
+namespace llvm {
+namespace dsymutil {
+
+Error PseudoProbeLinker::emit(const Triple &TheTriple) const {
+  // Don't create the directory and the file if there is nothing to write.
+  if (empty())
+    return Error::success();
+
+  // Without a resource directory (e.g. --flat) there is no dSYM bundle to place
+  // the content. Nothing to do in this case.
+  if (!Options.ResourceDir)
+    return Error::success();
+
+  SmallString<128> Path;
+  sys::path::append(Path, *Options.ResourceDir, "Profiling");
+  if (std::error_code EC = sys::fs::create_directories(Path.str(), true,
+                                                       sys::fs::perms::all_all))
+    return errorCodeToError(EC);
+
+  // For fat binaries, also append a dash and the architecture name.
+  sys::path::append(Path, "pseudo_probes");
+  if (Options.NumDebugMaps > 1) {
+    Path += '-';
+    Path += TheTriple.getArchName();
+  }
+
+  // Build the minimal MC machinery needed to write a MachO object holding the
+  // probe sections. All targets and their MC layers are registered by
+  // dsymutil_main.
+  std::string TripleName = TheTriple.getTriple();
+  std::string ErrorStr;
+  const Target *TheTarget = TargetRegistry::lookupTarget(TheTriple, ErrorStr);
+  if (!TheTarget)
+    return createStringError(inconvertibleErrorCode(), ErrorStr);
+
+  std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TheTriple));
+  if (!MRI)
+    return createStringError(inconvertibleErrorCode(),
+                             "no register info for target " + TripleName);
+
+  MCTargetOptions MCOptions;
+  std::unique_ptr<MCAsmInfo> MAI(
+      TheTarget->createMCAsmInfo(*MRI, TheTriple, MCOptions));
+  if (!MAI)
+    return createStringError(inconvertibleErrorCode(),
+                             "no asm info for target " + TripleName);
+
+  std::unique_ptr<MCSubtargetInfo> MSTI(
+      TheTarget->createMCSubtargetInfo(TheTriple, "", ""));
+  if (!MSTI)
+    return createStringError(inconvertibleErrorCode(),
+                             "no subtarget info for target " + TripleName);
+
+  MCContext Ctx(TheTriple, *MAI, *MRI, *MSTI);
+  std::unique_ptr<MCObjectFileInfo> MOFI(
+      TheTarget->createMCObjectFileInfo(Ctx, /*PIC=*/false));
+  Ctx.setObjectFileInfo(MOFI.get());
+
+  std::unique_ptr<MCInstrInfo> MII(TheTarget->createMCInstrInfo());
+  std::unique_ptr<MCCodeEmitter> MCE(TheTarget->createMCCodeEmitter(*MII, Ctx));
+  std::unique_ptr<MCAsmBackend> MAB(
+      TheTarget->createMCAsmBackend(*MSTI, *MRI, MCOptions));
+  if (!MCE || !MAB)
+    return createStringError(inconvertibleErrorCode(),
+                             "no code emitter/asm backend for target " +
+                                 TripleName);
+
+  std::error_code EC;
+  raw_fd_ostream OS(Options.NoOutput ? "-" : Path.str(), EC, sys::fs::OF_None);
+  if (EC)
+    return errorCodeToError(EC);
+
+  std::unique_ptr<MCObjectWriter> OW = MAB->createObjectWriter(OS);
+  std::unique_ptr<MCStreamer> MS(TheTarget->createMCObjectStreamer(
+      TheTriple, Ctx, std::move(MAB), std::move(OW), std::move(MCE), *MSTI));
+  if (!MS)
+    return createStringError(inconvertibleErrorCode(),
+                             "no object streamer for target " + TripleName);
+
+  auto emitSection = [&](StringRef Name, StringRef Data) {
+    if (Data.empty())
+      return;
+    MCSectionMachO *Sec = Ctx.getMachOSection(
+        "__LLVM", Name, /*TypeAndAttributes=*/0, SectionKind::getMetadata());
+    MS->switchSection(Sec);
+    MS->emitBytes(Data);
+  };
+  emitSection("__probes", getProbes());
+  emitSection("__probe_descs", getProbeDescs());
+  MS->finish();
+
+  return Error::success();
+}
+
+bool PseudoProbeLinker::link(const DebugMap &Map) {
+  for (const auto &Obj : Map.objects()) {
+    // Load the object. Any load error is reported by the DWARF link; skip
+    // silently here to avoid duplicate diagnostics.
+    auto ObjectEntry =
+        BinHolder.getObjectEntry(Obj->getObjectFilename(), Obj->getTimestamp());
+    if (!ObjectEntry) {
+      consumeError(ObjectEntry.takeError());
+      continue;
+    }
+    auto Object = ObjectEntry->getObject(Map.getTriple());
+    if (!Object) {
+      consumeError(Object.takeError());
+      continue;
+    }
+
+    collect(*Object);
+  }
+
+  if (Error E = emit(Map.getTriple())) {
+    handleAllErrors(std::move(E), [](const ErrorInfoBase &EI) {
+      WithColor::error() << EI.message() << '\n';
+    });
+    return false;
+  }
+  return true;
+}
+
+void PseudoProbeLinker::collect(const object::ObjectFile &Obj) {
+  const auto *MO = dyn_cast<object::MachOObjectFile>(&Obj);
+  if (!MO)
+    return;
+
+  for (const object::SectionRef &Section : MO->sections()) {
+    Expected<StringRef> NameOrErr = Section.getName();
+    if (!NameOrErr) {
+      consumeError(NameOrErr.takeError());
+      continue;
+    }
+    std::string *Dest = nullptr;
+    if (*NameOrErr == "__probes")
+      Dest = &Probes;
+    else if (*NameOrErr == "__probe_descs")
+      Dest = &ProbeDescs;
+    else
+      continue;
+
+    Expected<StringRef> ContentsOrErr = Section.getContents();
+    if (!ContentsOrErr) {
+      consumeError(ContentsOrErr.takeError());
+      continue;
+    }
+    *Dest += *ContentsOrErr;
+  }
+}
+} // end namespace dsymutil
+} // end namespace llvm
diff --git a/llvm/tools/dsymutil/PseudoProbeLinker.h b/llvm/tools/dsymutil/PseudoProbeLinker.h
new file mode 100644
index 0000000000000..dbe2dab6ac765
--- /dev/null
+++ b/llvm/tools/dsymutil/PseudoProbeLinker.h
@@ -0,0 +1,55 @@
+//===- tools/dsymutil/PseudoProbeLinker.h ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_DSYMUTIL_PSEUDOPROBELINKER_H
+#define LLVM_TOOLS_DSYMUTIL_PSEUDOPROBELINKER_H
+
+#include "LinkUtils.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/Error.h"
+#include <string>
+
+namespace llvm {
+class Triple;
+namespace dsymutil {
+
+class BinaryHolder;
+class DebugMap;
+
+/// Collect and merge the __probes and __probe_descs sections from the debug map
+/// object into the companion Contents/Resources/Profiling/pseudo_probes-<arch>.
+/// Note: the probe sections contain no relocations.
+class PseudoProbeLinker {
+  BinaryHolder &BinHolder;
+  const LinkOptions &Options;
+  std::string Probes;
+  std::string ProbeDescs;
+
+  Error emit(const Triple &TheTriple) const;
+
+public:
+  PseudoProbeLinker(BinaryHolder &BinHolder, const LinkOptions &Options)
+      : BinHolder(BinHolder), Options(Options) {}
+
+  /// Emit the collected probe sections as a single MachO object sidecar for the
+  /// \p TheTriple architecture. No-op if nothing was collected.
+  bool link(const DebugMap &Map);
+
+  /// Append the pseudo-probe sections found in \p Obj, if any.
+  void collect(const object::ObjectFile &Obj);
+
+  bool empty() const { return Probes.empty() && ProbeDescs.empty(); }
+  StringRef getProbes() const { return Probes; }
+  StringRef getProbeDescs() const { return ProbeDescs; }
+};
+
+} // end namespace dsymutil
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_DSYMUTIL_PSEUDOPROBELINKER_H
diff --git a/llvm/tools/dsymutil/dsymutil.cpp b/llvm/tools/dsymutil/dsymutil.cpp
index 45b9d68a03f16..78ce54ac95b7c 100644
--- a/llvm/tools/dsymutil/dsymutil.cpp
+++ b/llvm/tools/dsymutil/dsymutil.cpp
@@ -17,6 +17,7 @@
 #include "DwarfLinkerForBinary.h"
 #include "LinkUtils.h"
 #include "MachOUtils.h"
+#include "PseudoProbeLinker.h"
 #include "Reproducer.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallString.h"
@@ -953,6 +954,10 @@ int dsymutil_main(int argc, char **argv, const llvm::ToolContext &) {
           DwarfLinkerForBinary Linker(*Stream, BinHolder, Options.LinkOpts,
                                       ErrorHandlerMutex);
           AllOK.fetch_and(Linker.link(*Map));
+
+          PseudoProbeLinker ProbeLinker(BinHolder, Options.LinkOpts);
+          AllOK.fetch_and(ProbeLinker.link(*Map));
+
           Stream->flush();
           if (flagIsSet(Options.Verify, DWARFVerify::Output) ||
               (flagIsSet(Options.Verify, DWARFVerify::OutputOnValidInput) &&



More information about the llvm-commits mailing list