[llvm] [GSYM] Callsites: Add data format support and loading from YAML (PR #109781)

via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 14 10:41:19 PST 2024


https://github.com/alx32 updated https://github.com/llvm/llvm-project/pull/109781

>From ac48f2c4d76cefd27ce40d39762ce54633fee3f4 Mon Sep 17 00:00:00 2001
From: Alex B <alexborcan at meta.com>
Date: Tue, 24 Sep 2024 03:16:47 -0700
Subject: [PATCH 1/7] [GSYM] Callsites: Add data format support and loading
 from YAML

---
 .../llvm/DebugInfo/GSYM/CallSiteInfo.h        | 224 +++++
 .../llvm/DebugInfo/GSYM/FunctionInfo.h        |  10 +-
 .../include/llvm/DebugInfo/GSYM/GsymCreator.h |  11 +-
 llvm/include/llvm/DebugInfo/GSYM/GsymReader.h |  20 +
 llvm/lib/DebugInfo/GSYM/CMakeLists.txt        |   1 +
 llvm/lib/DebugInfo/GSYM/CallSiteInfo.cpp      | 293 ++++++
 llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp      |  31 +-
 llvm/lib/DebugInfo/GSYM/GsymCreator.cpp       |   6 +
 llvm/lib/DebugInfo/GSYM/GsymReader.cpp        |  45 +
 .../macho-gsym-callsite-info-dsym.yaml        | 950 ++++++++++++++++++
 .../macho-gsym-callsite-info-exe.yaml         | 558 ++++++++++
 .../macho-gsym-callsite-info-obj.test         | 304 ++++++
 llvm/tools/llvm-gsymutil/Opts.td              |   2 +
 llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp    |  19 +
 llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp    |   4 +-
 15 files changed, 2471 insertions(+), 7 deletions(-)
 create mode 100644 llvm/include/llvm/DebugInfo/GSYM/CallSiteInfo.h
 create mode 100644 llvm/lib/DebugInfo/GSYM/CallSiteInfo.cpp
 create mode 100644 llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-callsite-info-dsym.yaml
 create mode 100644 llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-callsite-info-exe.yaml
 create mode 100644 llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-callsite-info-obj.test

diff --git a/llvm/include/llvm/DebugInfo/GSYM/CallSiteInfo.h b/llvm/include/llvm/DebugInfo/GSYM/CallSiteInfo.h
new file mode 100644
index 00000000000000..45257f0e11578e
--- /dev/null
+++ b/llvm/include/llvm/DebugInfo/GSYM/CallSiteInfo.h
@@ -0,0 +1,224 @@
+//===- CallSiteInfo.h -------------------------------------------*- C++ -*-===//
+//
+// 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_DEBUGINFO_GSYM_CALLSITEINFO_H
+#define LLVM_DEBUGINFO_GSYM_CALLSITEINFO_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/DebugInfo/GSYM/ExtractRanges.h"
+#include "llvm/Support/YAMLParser.h"
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace llvm {
+class DataExtractor;
+class raw_ostream;
+class StringTableBuilder;
+class CachedHashStringRef;
+
+namespace yaml {
+struct CallSiteYAML;
+struct FunctionYAML;
+struct FunctionsYAML;
+} // namespace yaml
+
+namespace gsym {
+class FileWriter;
+struct FunctionInfo;
+struct CallSiteInfo {
+public:
+  enum Flags : uint8_t {
+    None = 0,
+    // This flag specifies that the call site can only call a function within
+    // the same link unit as the call site.
+    InternalCall = 1 << 0,
+    // This flag specifies that the call site can only call a function outside
+    // the link unit that the call site is in.
+    ExternalCall = 1 << 1,
+  };
+
+  /// The return address of the call site.
+  uint64_t ReturnAddress;
+
+  /// Offsets into the string table for function names regex patterns.
+  std::vector<uint32_t> MatchRegex;
+
+  /// Bitwise OR of CallSiteInfo::Flags values
+  uint8_t Flags;
+
+  /// Decode a CallSiteInfo object from a binary data stream.
+  ///
+  /// \param Data The binary stream to read the data from.
+  /// \param Offset The current offset within the data stream.
+  /// \param BaseAddr The base address for decoding (unused here but included
+  /// for consistency).
+  ///
+  /// \returns A CallSiteInfo or an error describing the issue.
+  static llvm::Expected<CallSiteInfo>
+  decode(DataExtractor &Data, uint64_t &Offset, uint64_t BaseAddr);
+
+  /// Encode this CallSiteInfo object into a FileWriter stream.
+  ///
+  /// \param O The binary stream to write the data to.
+  /// \returns An error object that indicates success or failure.
+  llvm::Error encode(FileWriter &O) const;
+};
+
+struct CallSiteInfoCollection {
+public:
+  std::vector<CallSiteInfo> CallSites;
+
+  void clear() { CallSites.clear(); }
+
+  /// Query if a CallSiteInfoCollection object is valid.
+  ///
+  /// \returns True if the collection is not empty.
+  bool isValid() const { return !CallSites.empty(); }
+
+  /// Decode a CallSiteInfoCollection object from a binary data stream.
+  ///
+  /// \param Data The binary stream to read the data from.
+  /// \param BaseAddr The base address for decoding (unused here but included
+  /// for consistency).
+  ///
+  /// \returns A CallSiteInfoCollection or an error describing the issue.
+  static llvm::Expected<CallSiteInfoCollection> decode(DataExtractor &Data,
+                                                       uint64_t BaseAddr);
+
+  /// Encode this CallSiteInfoCollection object into a FileWriter stream.
+  ///
+  /// \param O The binary stream to write the data to.
+  /// \returns An error object that indicates success or failure.
+  llvm::Error encode(FileWriter &O) const;
+};
+
+bool operator==(const CallSiteInfoCollection &LHS,
+                const CallSiteInfoCollection &RHS);
+
+bool operator==(const CallSiteInfo &LHS, const CallSiteInfo &RHS);
+
+class CallSiteInfoLoader {
+public:
+  /// Constructor that initializes the CallSiteInfoLoader with necessary data
+  /// structures.
+  ///
+  /// \param StringOffsetMap A reference to a DenseMap that maps existing string
+  /// offsets to CachedHashStringRef. \param StrTab A reference to a
+  /// StringTableBuilder used for managing looking up and creating new strings.
+  /// \param StringStorage A reference to a StringSet for storing the data for
+  /// generated strings.
+  CallSiteInfoLoader(DenseMap<uint64_t, CachedHashStringRef> &StringOffsetMap,
+                     StringTableBuilder &StrTab, StringSet<> &StringStorage)
+      : StringOffsetMap(StringOffsetMap), StrTab(StrTab),
+        StringStorage(StringStorage) {}
+
+  /// Loads call site information from a YAML file and populates the provided
+  /// FunctionInfo vector.
+  ///
+  /// This method reads the specified YAML file, parses its content, and updates
+  /// the `Funcs` vector with call site information based on the YAML data.
+  ///
+  /// \param Funcs A reference to a vector of FunctionInfo objects to be
+  /// populated.
+  /// \param YAMLFile A StringRef representing the path to the YAML
+  /// file to be loaded.
+  ///
+  /// \returns An `llvm::Error` indicating success or describing any issues
+  /// encountered during the loading process.
+  llvm::Error loadYAML(std::vector<FunctionInfo> &Funcs, StringRef YAMLFile);
+
+private:
+  /// Retrieves an existing string from the StringOffsetMap using the provided
+  /// offset.
+  ///
+  /// \param offset A 32-bit unsigned integer representing the offset of the
+  /// string.
+  ///
+  /// \returns A StringRef corresponding to the string for the given offset.
+  ///
+  /// \note This method asserts that the offset exists in the StringOffsetMap.
+  StringRef stringFromOffset(uint32_t offset) const;
+
+  /// Obtains the offset corresponding to a given string in the StrTab. If the
+  /// string does not already exist, it is created.
+  ///
+  /// \param str A StringRef representing the string for which the offset is
+  /// requested.
+  ///
+  /// \returns A 32-bit unsigned integer representing the offset of the string.
+  uint32_t offsetFromString(StringRef str);
+
+  /// Reads the content of the YAML file specified by `YAMLFile` into
+  /// `yamlContent`.
+  ///
+  /// \param YAMLFile A StringRef representing the path to the YAML file.
+  /// \param Buffer The memory buffer containing the YAML content.
+  ///
+  /// \returns An `llvm::Error` indicating success or describing any issues
+  /// encountered while reading the file.
+  llvm::Error readYAMLFile(StringRef YAMLFile,
+                           std::unique_ptr<llvm::MemoryBuffer> &Buffer);
+
+  /// Parses the YAML content and populates `functionsYAML` with the parsed
+  /// data.
+  ///
+  /// \param Buffer The memory buffer containing the YAML content.
+  /// \param functionsYAML A reference to an llvm::yaml::FunctionsYAML object to
+  /// be populated.
+  ///
+  /// \returns An `llvm::Error` indicating success or describing any issues
+  /// encountered during parsing.
+  llvm::Error parseYAML(llvm::MemoryBuffer &Buffer,
+                        llvm::yaml::FunctionsYAML &functionsYAML);
+
+  /// Builds a map from function names to FunctionInfo pointers based on the
+  /// provided `Funcs` vector.
+  ///
+  /// \param Funcs A reference to a vector of FunctionInfo objects.
+  ///
+  /// \returns An unordered_map mapping function names (std::string) to their
+  /// corresponding FunctionInfo pointers.
+  std::unordered_map<std::string, FunctionInfo *>
+  buildFunctionMap(std::vector<FunctionInfo> &Funcs);
+
+  /// Processes the parsed YAML functions and updates the `FuncMap` accordingly.
+  ///
+  /// \param functionsYAML A constant reference to an llvm::yaml::FunctionsYAML
+  /// object containing parsed YAML data.
+  /// \param FuncMap A reference to an unordered_map mapping function names to
+  /// FunctionInfo pointers.
+  /// \param YAMLFile A StringRef representing the name of the YAML file (used
+  /// for error messages).
+  ///
+  /// \returns An `llvm::Error` indicating success or describing any issues
+  /// encountered during processing.
+  llvm::Error
+  processYAMLFunctions(const llvm::yaml::FunctionsYAML &functionsYAML,
+                       std::unordered_map<std::string, FunctionInfo *> &FuncMap,
+                       StringRef YAMLFile);
+
+  /// Map of existing string offsets to CachedHashStringRef.
+  DenseMap<uint64_t, CachedHashStringRef> &StringOffsetMap;
+
+  /// The gSYM string table builder.
+  StringTableBuilder &StrTab;
+
+  /// The gSYM string storage - we store generated strings here.
+  StringSet<> &StringStorage;
+};
+
+raw_ostream &operator<<(raw_ostream &OS, const CallSiteInfo &CSI);
+raw_ostream &operator<<(raw_ostream &OS, const CallSiteInfoCollection &CSIC);
+
+} // namespace gsym
+} // namespace llvm
+
+#endif // LLVM_DEBUGINFO_GSYM_CALLSITEINFO_H
diff --git a/llvm/include/llvm/DebugInfo/GSYM/FunctionInfo.h b/llvm/include/llvm/DebugInfo/GSYM/FunctionInfo.h
index 71209b6b5c9cd1..fd4ac3164c686d 100644
--- a/llvm/include/llvm/DebugInfo/GSYM/FunctionInfo.h
+++ b/llvm/include/llvm/DebugInfo/GSYM/FunctionInfo.h
@@ -10,6 +10,7 @@
 #define LLVM_DEBUGINFO_GSYM_FUNCTIONINFO_H
 
 #include "llvm/ADT/SmallString.h"
+#include "llvm/DebugInfo/GSYM/CallSiteInfo.h"
 #include "llvm/DebugInfo/GSYM/ExtractRanges.h"
 #include "llvm/DebugInfo/GSYM/InlineInfo.h"
 #include "llvm/DebugInfo/GSYM/LineTable.h"
@@ -63,7 +64,9 @@ class GsymReader;
 ///   enum InfoType {
 ///     EndOfList = 0u,
 ///     LineTableInfo = 1u,
-///     InlineInfo = 2u
+///     InlineInfo = 2u,
+///     MergedFunctionsInfo = 3u,
+///     CallSiteInfo = 4u
 ///   };
 ///
 /// This stream of tuples is terminated by a "InfoType" whose value is
@@ -73,7 +76,7 @@ class GsymReader;
 /// clients to still parse the format and skip over any data that they don't
 /// understand or want to parse.
 ///
-/// So the function information encoding essientially looks like:
+/// So the function information encoding essentially looks like:
 ///
 /// struct {
 ///   uint32_t Size;
@@ -92,6 +95,7 @@ struct FunctionInfo {
   std::optional<LineTable> OptLineTable;
   std::optional<InlineInfo> Inline;
   std::optional<MergedFunctionsInfo> MergedFunctions;
+  std::optional<CallSiteInfoCollection> CallSites;
   /// If we encode a FunctionInfo during segmenting so we know its size, we can
   /// cache that encoding here so we don't need to re-encode it when saving the
   /// GSYM file.
@@ -107,7 +111,7 @@ struct FunctionInfo {
   /// debug info, we might end up with multiple FunctionInfo objects for the
   /// same range and we need to be able to tell which one is the better object
   /// to use.
-  bool hasRichInfo() const { return OptLineTable || Inline; }
+  bool hasRichInfo() const { return OptLineTable || Inline || CallSites; }
 
   /// Query if a FunctionInfo object is valid.
   ///
diff --git a/llvm/include/llvm/DebugInfo/GSYM/GsymCreator.h b/llvm/include/llvm/DebugInfo/GSYM/GsymCreator.h
index 48808fb7b71e18..9e5b3c1f8d92de 100644
--- a/llvm/include/llvm/DebugInfo/GSYM/GsymCreator.h
+++ b/llvm/include/llvm/DebugInfo/GSYM/GsymCreator.h
@@ -352,13 +352,22 @@ class GsymCreator {
   /// \param   FI The function info object to emplace into our functions list.
   void addFunctionInfo(FunctionInfo &&FI);
 
+  /// Load call site information from a YAML file.
+  ///
+  /// This function reads call site information from a specified YAML file and
+  /// adds it to the GSYM data.
+  ///
+  /// \param YAMLFile The path to the YAML file containing call site
+  /// information.
+  llvm::Error loadCallSitesFromYAML(StringRef YAMLFile);
+
   /// Organize merged FunctionInfo's
   ///
   /// This method processes the list of function infos (Funcs) to identify and
   /// group functions with overlapping address ranges.
   ///
   /// \param  Out Output stream to report information about how merged
-  /// FunctionInfo's were handeled.
+  /// FunctionInfo's were handled.
   void prepareMergedFunctions(OutputAggregator &Out);
 
   /// Finalize the data in the GSYM creator prior to saving the data out.
diff --git a/llvm/include/llvm/DebugInfo/GSYM/GsymReader.h b/llvm/include/llvm/DebugInfo/GSYM/GsymReader.h
index 89f8c043b91519..72b7f3e7bfc42e 100644
--- a/llvm/include/llvm/DebugInfo/GSYM/GsymReader.h
+++ b/llvm/include/llvm/DebugInfo/GSYM/GsymReader.h
@@ -181,6 +181,26 @@ class GsymReader {
   /// \param MFI The object to dump.
   void dump(raw_ostream &OS, const MergedFunctionsInfo &MFI);
 
+  /// Dump a CallSiteInfo object.
+  ///
+  /// This function will output the details of a CallSiteInfo object in a
+  /// human-readable format.
+  ///
+  /// \param OS The output stream to dump to.
+  ///
+  /// \param CSI The CallSiteInfo object to dump.
+  void dump(raw_ostream &OS, const CallSiteInfo &CSI);
+
+  /// Dump a CallSiteInfoCollection object.
+  ///
+  /// This function will iterate over a collection of CallSiteInfo objects and
+  /// dump each one.
+  ///
+  /// \param OS The output stream to dump to.
+  ///
+  /// \param CSIC The CallSiteInfoCollection object to dump.
+  void dump(raw_ostream &OS, const CallSiteInfoCollection &CSIC);
+
   /// Dump a LineTable object.
   ///
   /// This function will convert any string table indexes and file indexes
diff --git a/llvm/lib/DebugInfo/GSYM/CMakeLists.txt b/llvm/lib/DebugInfo/GSYM/CMakeLists.txt
index be90bfdaa7fd2b..c27d648db62f61 100644
--- a/llvm/lib/DebugInfo/GSYM/CMakeLists.txt
+++ b/llvm/lib/DebugInfo/GSYM/CMakeLists.txt
@@ -8,6 +8,7 @@ add_llvm_component_library(LLVMDebugInfoGSYM
   InlineInfo.cpp
   LineTable.cpp
   LookupResult.cpp
+  CallSiteInfo.cpp
   MergedFunctionsInfo.cpp
   ObjectFileTransformer.cpp
   ExtractRanges.cpp
diff --git a/llvm/lib/DebugInfo/GSYM/CallSiteInfo.cpp b/llvm/lib/DebugInfo/GSYM/CallSiteInfo.cpp
new file mode 100644
index 00000000000000..4ed3d3f67a44fd
--- /dev/null
+++ b/llvm/lib/DebugInfo/GSYM/CallSiteInfo.cpp
@@ -0,0 +1,293 @@
+//===- CallSiteInfo.cpp ----------------------------------*- C++ -*-===//
+//
+// 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 "llvm/DebugInfo/GSYM/CallSiteInfo.h"
+#include "llvm/ADT/CachedHashString.h"
+#include "llvm/DebugInfo/GSYM/FileWriter.h"
+#include "llvm/DebugInfo/GSYM/FunctionInfo.h"
+#include "llvm/MC/StringTableBuilder.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/YAMLParser.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
+#include <fstream>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+using namespace llvm;
+using namespace gsym;
+
+llvm::Error CallSiteInfo::encode(FileWriter &O) const {
+  O.writeU64(ReturnAddress);
+  O.writeU8(Flags);
+  O.writeU32(MatchRegex.size());
+  for (uint32_t Entry : MatchRegex)
+    O.writeU32(Entry);
+  return llvm::Error::success();
+}
+
+llvm::Expected<CallSiteInfo>
+CallSiteInfo::decode(DataExtractor &Data, uint64_t &Offset, uint64_t BaseAddr) {
+  CallSiteInfo CSI;
+
+  // Read ReturnAddress
+  if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(uint64_t)))
+    return createStringError(std::errc::io_error,
+                             "0x%8.8" PRIx64 ": missing ReturnAddress", Offset);
+  CSI.ReturnAddress = Data.getU64(&Offset);
+
+  // Read Flags
+  if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(uint8_t)))
+    return createStringError(std::errc::io_error,
+                             "0x%8.8" PRIx64 ": missing Flags", Offset);
+  CSI.Flags = Data.getU8(&Offset);
+
+  // Read number of MatchRegex entries
+  if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(uint32_t)))
+    return createStringError(std::errc::io_error,
+                             "0x%8.8" PRIx64 ": missing MatchRegex count",
+                             Offset);
+  uint32_t NumEntries = Data.getU32(&Offset);
+
+  CSI.MatchRegex.reserve(NumEntries);
+  for (uint32_t i = 0; i < NumEntries; ++i) {
+    if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(uint32_t)))
+      return createStringError(std::errc::io_error,
+                               "0x%8.8" PRIx64 ": missing MatchRegex entry",
+                               Offset);
+    uint32_t Entry = Data.getU32(&Offset);
+    CSI.MatchRegex.push_back(Entry);
+  }
+
+  return CSI;
+}
+
+llvm::Error CallSiteInfoCollection::encode(FileWriter &O) const {
+  O.writeU32(CallSites.size());
+  for (const CallSiteInfo &CSI : CallSites) {
+    if (llvm::Error Err = CSI.encode(O))
+      return Err;
+  }
+  return llvm::Error::success();
+}
+
+llvm::Expected<CallSiteInfoCollection>
+CallSiteInfoCollection::decode(DataExtractor &Data, uint64_t BaseAddr) {
+  CallSiteInfoCollection CSC;
+  uint64_t Offset = 0;
+
+  // Read number of CallSiteInfo entries
+  if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(uint32_t)))
+    return createStringError(std::errc::io_error,
+                             "0x%8.8" PRIx64 ": missing CallSiteInfo count",
+                             Offset);
+  uint32_t NumCallSites = Data.getU32(&Offset);
+
+  CSC.CallSites.reserve(NumCallSites);
+  for (uint32_t i = 0; i < NumCallSites; ++i) {
+    llvm::Expected<CallSiteInfo> ECSI =
+        CallSiteInfo::decode(Data, Offset, BaseAddr);
+    if (!ECSI)
+      return ECSI.takeError();
+    CSC.CallSites.emplace_back(*ECSI);
+  }
+
+  return CSC;
+}
+
+/// Structures necessary for reading CallSiteInfo from YAML.
+namespace llvm {
+namespace yaml {
+
+struct CallSiteYAML {
+  // The offset of the return address of the call site - relative to the start
+  // of the function.
+  llvm::yaml::Hex64 return_offset;
+  std::vector<std::string> match_regex;
+  std::vector<std::string> flags;
+};
+
+struct FunctionYAML {
+  std::string name;
+  std::vector<CallSiteYAML> callsites;
+};
+
+struct FunctionsYAML {
+  std::vector<FunctionYAML> functions;
+};
+
+template <> struct MappingTraits<CallSiteYAML> {
+  static void mapping(IO &io, CallSiteYAML &callsite) {
+    io.mapRequired("return_offset", callsite.return_offset);
+    io.mapRequired("match_regex", callsite.match_regex);
+    io.mapOptional("flags", callsite.flags);
+  }
+};
+
+template <> struct MappingTraits<FunctionYAML> {
+  static void mapping(IO &io, FunctionYAML &func) {
+    io.mapRequired("name", func.name);
+    io.mapOptional("callsites", func.callsites);
+  }
+};
+
+template <> struct MappingTraits<FunctionsYAML> {
+  static void mapping(IO &io, FunctionsYAML &functionsYAML) {
+    io.mapRequired("functions", functionsYAML.functions);
+  }
+};
+
+} // namespace yaml
+} // namespace llvm
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(CallSiteYAML)
+LLVM_YAML_IS_SEQUENCE_VECTOR(FunctionYAML)
+
+// Implementation of CallSiteInfoLoader
+StringRef CallSiteInfoLoader::stringFromOffset(uint32_t offset) const {
+  assert(StringOffsetMap.count(offset) &&
+         "expected function name offset to already be in StringOffsetMap");
+  return StringOffsetMap.find(offset)->second.val();
+}
+
+uint32_t CallSiteInfoLoader::offsetFromString(StringRef str) {
+  return StrTab.add(StringStorage.insert(str).first->getKey());
+}
+
+llvm::Error CallSiteInfoLoader::loadYAML(std::vector<FunctionInfo> &Funcs,
+                                         StringRef YAMLFile) {
+  std::unique_ptr<llvm::MemoryBuffer> Buffer;
+  // Step 1: Read YAML file
+  if (auto Err = readYAMLFile(YAMLFile, Buffer))
+    return Err;
+
+  // Step 2: Parse YAML content
+  llvm::yaml::FunctionsYAML functionsYAML;
+  if (auto Err = parseYAML(*Buffer, functionsYAML))
+    return Err;
+
+  // Step 3: Build function map from Funcs
+  auto FuncMap = buildFunctionMap(Funcs);
+
+  // Step 4: Process parsed YAML functions and update FuncMap
+  return processYAMLFunctions(functionsYAML, FuncMap, YAMLFile);
+}
+
+llvm::Error
+CallSiteInfoLoader::readYAMLFile(StringRef YAMLFile,
+                                 std::unique_ptr<llvm::MemoryBuffer> &Buffer) {
+  auto BufferOrError = llvm::MemoryBuffer::getFile(YAMLFile);
+  if (!BufferOrError)
+    return errorCodeToError(BufferOrError.getError());
+  Buffer = std::move(*BufferOrError);
+  return llvm::Error::success();
+}
+
+llvm::Error
+CallSiteInfoLoader::parseYAML(llvm::MemoryBuffer &Buffer,
+                              llvm::yaml::FunctionsYAML &functionsYAML) {
+  // Use the MemoryBufferRef constructor
+  llvm::yaml::Input yin(Buffer.getMemBufferRef());
+  yin >> functionsYAML;
+  if (yin.error()) {
+    return llvm::createStringError(yin.error(), "Error parsing YAML file: %s\n",
+                                   Buffer.getBufferIdentifier().str().c_str());
+  }
+  return llvm::Error::success();
+}
+
+std::unordered_map<std::string, FunctionInfo *>
+CallSiteInfoLoader::buildFunctionMap(std::vector<FunctionInfo> &Funcs) {
+  std::unordered_map<std::string, FunctionInfo *> FuncMap;
+  auto insertFunc = [&](auto &Function) {
+    std::string FuncName = stringFromOffset(Function.Name).str();
+    // If the function name is already in the map, don't update it. This way we
+    // preferentially use the first encountered function. Since symbols are
+    // loaded from dSYM first, we end up preferring keeping track of symbols
+    // from dSYM rather than from the symbol table - which is what we want to
+    // do.
+    if (FuncMap.count(FuncName))
+      return;
+    FuncMap[FuncName] = &Function;
+  };
+  for (auto &Func : Funcs) {
+    insertFunc(Func);
+    if (Func.MergedFunctions.has_value())
+      for (auto &MFunc : Func.MergedFunctions->MergedFunctions)
+        insertFunc(MFunc);
+  }
+  return FuncMap;
+}
+
+llvm::Error CallSiteInfoLoader::processYAMLFunctions(
+    const llvm::yaml::FunctionsYAML &functionsYAML,
+    std::unordered_map<std::string, FunctionInfo *> &FuncMap,
+    StringRef YAMLFile) {
+  // For each function in the YAML file
+  for (const auto &FuncYAML : functionsYAML.functions) {
+    auto it = FuncMap.find(FuncYAML.name);
+    if (it == FuncMap.end()) {
+      return llvm::createStringError(
+          std::errc::invalid_argument,
+          "Can't find function '%s' specified in callsite YAML\n",
+          FuncYAML.name.c_str());
+    }
+    FunctionInfo *FuncInfo = it->second;
+    // Create a CallSiteInfoCollection if not already present
+    if (!FuncInfo->CallSites)
+      FuncInfo->CallSites = CallSiteInfoCollection();
+    for (const auto &CallSiteYAML : FuncYAML.callsites) {
+      CallSiteInfo CSI;
+      // Since YAML has specifies relative return offsets, add the function
+      // start address to make the offset absolute.
+      CSI.ReturnAddress = FuncInfo->Range.start() + CallSiteYAML.return_offset;
+      for (const auto &regex : CallSiteYAML.match_regex) {
+        CSI.MatchRegex.push_back(offsetFromString(regex));
+      }
+      // Initialize flags to None
+      CSI.Flags = CallSiteInfo::None;
+      // Parse flags and combine them
+      for (const auto &FlagStr : CallSiteYAML.flags) {
+        if (FlagStr == "InternalCall") {
+          CSI.Flags |= static_cast<uint8_t>(CallSiteInfo::InternalCall);
+        } else if (FlagStr == "ExternalCall") {
+          CSI.Flags |= static_cast<uint8_t>(CallSiteInfo::ExternalCall);
+        } else {
+          return llvm::createStringError(std::errc::invalid_argument,
+                                         "Unknown flag in callsite YAML: %s\n",
+                                         FlagStr.c_str());
+        }
+      }
+      FuncInfo->CallSites->CallSites.push_back(CSI);
+    }
+  }
+  return llvm::Error::success();
+}
+
+raw_ostream &llvm::gsym::operator<<(raw_ostream &OS, const CallSiteInfo &CSI) {
+  OS << "  Return=" << HEX64(CSI.ReturnAddress);
+  OS << "  Flags=" << HEX8(CSI.Flags);
+
+  OS << "  RegEx=";
+  for (uint32_t i = 0; i < CSI.MatchRegex.size(); ++i) {
+    if (i > 0)
+      OS << ",";
+    OS << CSI.MatchRegex[i];
+  }
+  return OS;
+}
+
+raw_ostream &llvm::gsym::operator<<(raw_ostream &OS,
+                                    const CallSiteInfoCollection &CSIC) {
+  for (const auto &CS : CSIC.CallSites) {
+    OS << CS;
+    OS << "\n";
+  }
+  return OS;
+}
diff --git a/llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp b/llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp
index 2cd85ef2398f91..9dc9c241168b26 100644
--- a/llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp
+++ b/llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp
@@ -24,6 +24,7 @@ enum InfoType : uint32_t {
   LineTableInfo = 1u,
   InlineInfo = 2u,
   MergedFunctionsInfo = 3u,
+  CallSiteInfo = 4u,
 };
 
 raw_ostream &llvm::gsym::operator<<(raw_ostream &OS, const FunctionInfo &FI) {
@@ -32,6 +33,8 @@ raw_ostream &llvm::gsym::operator<<(raw_ostream &OS, const FunctionInfo &FI) {
     OS << FI.OptLineTable << '\n';
   if (FI.Inline)
     OS << FI.Inline << '\n';
+  if (FI.CallSites)
+    OS << *FI.CallSites << '\n';
   return OS;
 }
 
@@ -95,6 +98,14 @@ llvm::Expected<FunctionInfo> FunctionInfo::decode(DataExtractor &Data,
           return MI.takeError();
         break;
 
+      case InfoType::CallSiteInfo:
+        if (Expected<llvm::gsym::CallSiteInfoCollection> CI =
+                llvm::gsym::CallSiteInfoCollection::decode(InfoData, BaseAddr))
+          FI.CallSites = std::move(CI.get());
+        else
+          return CI.takeError();
+        break;
+
       default:
         return createStringError(std::errc::io_error,
                                  "0x%8.8" PRIx64 ": unsupported InfoType %u",
@@ -200,7 +211,25 @@ llvm::Expected<uint64_t> FunctionInfo::encode(FileWriter &Out,
     Out.fixup32(static_cast<uint32_t>(Length), StartOffset - 4);
   }
 
-  // Terminate the data chunks with and end of list with zero size
+  // Write out the call sites if we have any and if they are valid.
+  if (CallSites) {
+    Out.writeU32(InfoType::CallSiteInfo);
+    // Write a uint32_t length as zero for now, we will fix this up after
+    // writing the CallSites out with the number of bytes that were written.
+    Out.writeU32(0);
+    const auto StartOffset = Out.tell();
+    llvm::Error err = CallSites->encode(Out);
+    if (err)
+      return std::move(err);
+    const auto Length = Out.tell() - StartOffset;
+    if (Length > UINT32_MAX)
+      return createStringError(std::errc::invalid_argument,
+                               "CallSites length is greater than UINT32_MAX");
+    // Fixup the size of the CallSites data with the correct size.
+    Out.fixup32(static_cast<uint32_t>(Length), StartOffset - 4);
+  }
+
+  // Terminate the data chunks with an end of list with zero size.
   Out.writeU32(InfoType::EndOfList);
   Out.writeU32(0);
   return FuncInfoOffset;
diff --git a/llvm/lib/DebugInfo/GSYM/GsymCreator.cpp b/llvm/lib/DebugInfo/GSYM/GsymCreator.cpp
index 3227fa5400fb5c..0df84ee256aef9 100644
--- a/llvm/lib/DebugInfo/GSYM/GsymCreator.cpp
+++ b/llvm/lib/DebugInfo/GSYM/GsymCreator.cpp
@@ -189,6 +189,12 @@ llvm::Error GsymCreator::encode(FileWriter &O) const {
   return ErrorSuccess();
 }
 
+llvm::Error GsymCreator::loadCallSitesFromYAML(StringRef YAMLFile) {
+  // Use the loader to load call site information from the YAML file.
+  CallSiteInfoLoader Loader(StringOffsetMap, StrTab, StringStorage);
+  return Loader.loadYAML(Funcs, YAMLFile);
+}
+
 void GsymCreator::prepareMergedFunctions(OutputAggregator &Out) {
   // Nothing to do if we have less than 2 functions.
   if (Funcs.size() < 2)
diff --git a/llvm/lib/DebugInfo/GSYM/GsymReader.cpp b/llvm/lib/DebugInfo/GSYM/GsymReader.cpp
index ddfc92e1a8a403..4f645714480e6d 100644
--- a/llvm/lib/DebugInfo/GSYM/GsymReader.cpp
+++ b/llvm/lib/DebugInfo/GSYM/GsymReader.cpp
@@ -411,6 +411,10 @@ void GsymReader::dump(raw_ostream &OS, const FunctionInfo &FI,
     assert(Indent == 0 && "MergedFunctionsInfo should only exist at top level");
     dump(OS, *FI.MergedFunctions);
   }
+
+  if (FI.CallSites) {
+    dump(OS, *FI.CallSites);
+  }
 }
 
 void GsymReader::dump(raw_ostream &OS, const MergedFunctionsInfo &MFI) {
@@ -420,6 +424,47 @@ void GsymReader::dump(raw_ostream &OS, const MergedFunctionsInfo &MFI) {
   }
 }
 
+void GsymReader::dump(raw_ostream &OS, const CallSiteInfo &CSI) {
+  OS << HEX64(CSI.ReturnAddress);
+
+  std::string Flags;
+  auto addFlag = [&](const char *Flag) {
+    if (!Flags.empty())
+      Flags += " | ";
+    Flags += Flag;
+  };
+
+  if (CSI.Flags == CallSiteInfo::Flags::None)
+    Flags = "None";
+  else {
+    if (CSI.Flags & CallSiteInfo::Flags::InternalCall)
+      addFlag("InternalCall");
+
+    if (CSI.Flags & CallSiteInfo::Flags::ExternalCall)
+      addFlag("ExternalCall");
+  }
+  OS << " Flags[" << Flags << "]";
+
+  if (!CSI.MatchRegex.empty()) {
+    OS << " MatchRegex[";
+    for (uint32_t i = 0; i < CSI.MatchRegex.size(); ++i) {
+      if (i > 0)
+        OS << ";";
+      OS << getString(CSI.MatchRegex[i]);
+    }
+    OS << "]";
+  }
+}
+
+void GsymReader::dump(raw_ostream &OS, const CallSiteInfoCollection &CSIC) {
+  OS << "CallSites (by return address):\n";
+  for (const auto &CS : CSIC.CallSites) {
+    OS.indent(2);
+    dump(OS, CS);
+    OS << "\n";
+  }
+}
+
 void GsymReader::dump(raw_ostream &OS, const LineTable &LT, uint32_t Indent) {
   OS.indent(Indent);
   OS << "LineTable:\n";
diff --git a/llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-callsite-info-dsym.yaml b/llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-callsite-info-dsym.yaml
new file mode 100644
index 00000000000000..5c31d609626694
--- /dev/null
+++ b/llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-callsite-info-dsym.yaml
@@ -0,0 +1,950 @@
+## Test that reconstructs a dSYM file from YAML and generates a callsite-enabled gsym from it - and then verifies the gsym.
+## See llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-callsite-info.test for the script to generate this yaml file
+
+# RUN: split-file %s %t
+# RUN: yaml2obj %t/call_sites.dSYM.yaml -o %t/call_sites.dSYM
+
+# RUN: llvm-gsymutil --convert=%t/call_sites.dSYM --callsites-from-yaml=%t/callsites.yaml -o %t/call_sites_dSYM.gsym
+
+# Dump the GSYM file and check the output for callsite information
+# RUN: llvm-gsymutil %t/call_sites_dSYM.gsym | FileCheck --check-prefix=CHECK-GSYM %s
+
+
+# CHECK-GSYM:      FunctionInfo @ 0x[[#%x,]]: [0x[[#%x,]] - 0x[[#%x,]]) "func_mainBin_dec_call_everything"
+# CHECK-GSYM-NEXT: LineTable:
+#                    // func_mainBin_dec_call_everything() {
+# CHECK-GSYM-NEXT:   0x[[#%x,]] {{.*}}/call_sites.cpp:16
+#                    // func_mainBin_dec_01();
+# CHECK-GSYM-NEXT:   0x[[ADDR_dec_01_call:[0-9a-f]+]] {{.*}}/call_sites.cpp:17
+#                    // func_mainBin_dec_02();
+# CHECK-GSYM-NEXT:   0x[[ADDR_dec_02_call:[0-9a-f]+]] {{.*}}/call_sites.cpp:18
+#                    // func_mainBin_dec_03();
+# CHECK-GSYM-NEXT:   [[ADDR_dec_03_call:0x[0-9a-f]+]] {{.*}}/call_sites.cpp:19
+#                    // func_mainBin_inc_01();
+# CHECK-GSYM-NEXT:   [[ADDR_inc_01_call:0x[0-9a-f]+]] {{.*}}/call_sites.cpp:21
+#                    // func_mainBin_inc_02();
+# CHECK-GSYM-NEXT:   [[ADDR_inc_02_call:0x[0-9a-f]+]] {{.*}}/call_sites.cpp:22
+#                    // func_mainBin_inc_03();
+# CHECK-GSYM-NEXT:   [[ADDR_inc_03_call:0x[0-9a-f]+]] {{.*}}/call_sites.cpp:23
+#                    // g_func_ptr();
+# CHECK-GSYM-NEXT:   [[ADDR_func_call:0x[0-9a-f]+]] {{.*}}/call_sites.cpp:25
+#                    // g_extern_func_ptr();
+# CHECK-GSYM-NEXT:   [[ADDR_extern_func_call:0x[0-9a-f]+]] {{.*}}/call_sites.cpp:26
+#                    // g_volatile_var = 0;
+# CHECK-GSYM-NEXT:   [[ADDR_var_assign:0x[0-9a-f]+]] {{.*}}/call_sites.cpp:28
+#                    // }
+# CHECK-GSYM-NEXT:   [[#%x,]] {{.*}}/call_sites.cpp:29
+# CHECK-GSYM-NEXT: CallSites (by return address):
+# CHECK-GSYM-NEXT:   [[ADDR_dec_02_call]] Flags[InternalCall] MatchRegex[func_mainBin_dec_01]
+# CHECK-GSYM-NEXT:   [[ADDR_dec_03_call]] Flags[InternalCall] MatchRegex[func_mainBin_dec_02]
+# CHECK-GSYM-NEXT:   [[ADDR_inc_01_call]] Flags[InternalCall] MatchRegex[func_mainBin_dec_03]
+# CHECK-GSYM-NEXT:   [[ADDR_inc_02_call]] Flags[InternalCall] MatchRegex[func_mainBin_inc_01]
+# CHECK-GSYM-NEXT:   [[ADDR_inc_03_call]] Flags[InternalCall] MatchRegex[func_mainBin_inc_02]
+# CHECK-GSYM-NEXT:   [[ADDR_func_call]] Flags[InternalCall] MatchRegex[func_mainBin_inc_03]
+# CHECK-GSYM-NEXT:   [[ADDR_extern_func_call]] Flags[None] MatchRegex[.*func.*]
+# CHECK-GSYM-NEXT:   [[ADDR_var_assign]] Flags[ExternalCall] MatchRegex[.*extern_func.*]
+
+
+#--- callsites.yaml
+functions:
+  - name: func_mainBin_dec_call_everything
+    callsites:
+      - return_offset: 0x0C
+        match_regex: ["func_mainBin_dec_01"]
+        flags:
+          - "InternalCall"
+      - return_offset: 0x10
+        match_regex: ["func_mainBin_dec_02"]
+        flags:
+          - "InternalCall"
+      - return_offset: 0x14
+        match_regex: ["func_mainBin_dec_03"]
+        flags:
+          - "InternalCall"
+      - return_offset: 24
+        match_regex: ["func_mainBin_inc_01"]
+        flags:
+          - "InternalCall"
+      - return_offset: 28
+        match_regex: ["func_mainBin_inc_02"]
+        flags:
+          - "InternalCall"
+      - return_offset: 32
+        match_regex: ["func_mainBin_inc_03"]
+        flags:
+          - "InternalCall"
+      - return_offset: 44
+        match_regex: [".*func.*"]
+      - return_offset: 56
+        match_regex: [".*extern_func.*"]
+        flags:
+          - "ExternalCall"
+
+
+#--- call_sites.dSYM.yaml
+--- !mach-o
+FileHeader:
+  magic:           0xFEEDFACF
+  cputype:         0x100000C
+  cpusubtype:      0x0
+  filetype:        0xA
+  ncmds:           8
+  sizeofcmds:      1392
+  flags:           0x0
+  reserved:        0x0
+LoadCommands:
+  - cmd:             LC_UUID
+    cmdsize:         24
+    uuid:            4C4C44E9-5555-3144-A1D3-328233D00078
+  - cmd:             LC_BUILD_VERSION
+    cmdsize:         24
+    platform:        1
+    minos:           720896
+    sdk:             720896
+    ntools:          0
+  - cmd:             LC_SYMTAB
+    cmdsize:         24
+    symoff:          4096
+    nsyms:           12
+    stroff:          4288
+    strsize:         235
+  - 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:         152
+    segname:         __TEXT
+    vmaddr:          4294967296
+    vmsize:          16384
+    fileoff:         0
+    filesize:        0
+    maxprot:         5
+    initprot:        5
+    nsects:          1
+    flags:           0
+    Sections:
+      - sectname:        __text
+        segname:         __TEXT
+        addr:            0x100000338
+        size:            216
+        offset:          0x0
+        align:           2
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x80000400
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         CFFAEDFE0C000001000000000A000000080000007005000000000000000000001B000000180000004C4C44E955553144A1D3328233D0007832000000180000000100000000000B0000000B00000000000200000018000000001000000C000000C0100000EB00000019000000480000005F5F504147455A45524F00000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000019000000980000005F5F544558540000000000000000000000000000010000000040000000000000
+  - cmd:             LC_SEGMENT_64
+    cmdsize:         152
+    segname:         __DATA
+    vmaddr:          4294983680
+    vmsize:          16384
+    fileoff:         0
+    filesize:        0
+    maxprot:         3
+    initprot:        3
+    nsects:          1
+    flags:           0
+    Sections:
+      - sectname:        __common
+        segname:         __DATA
+        addr:            0x100004000
+        size:            24
+        offset:          0x0
+        align:           3
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x1
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+  - cmd:             LC_SEGMENT_64
+    cmdsize:         72
+    segname:         __LINKEDIT
+    vmaddr:          4295000064
+    vmsize:          4096
+    fileoff:         4096
+    filesize:        427
+    maxprot:         1
+    initprot:        1
+    nsects:          0
+    flags:           0
+  - cmd:             LC_SEGMENT_64
+    cmdsize:         872
+    segname:         __DWARF
+    vmaddr:          4295004160
+    vmsize:          4096
+    fileoff:         8192
+    filesize:        1894
+    maxprot:         7
+    initprot:        3
+    nsects:          10
+    flags:           0
+    Sections:
+      - sectname:        __debug_line
+        segname:         __DWARF
+        addr:            0x100009000
+        size:            150
+        offset:          0x2000
+        align:           0
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x0
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+      - sectname:        __debug_aranges
+        segname:         __DWARF
+        addr:            0x100009096
+        size:            48
+        offset:          0x2096
+        align:           0
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x0
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+      - sectname:        __debug_info
+        segname:         __DWARF
+        addr:            0x1000090C6
+        size:            424
+        offset:          0x20C6
+        align:           0
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x0
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+      - sectname:        __debug_frame
+        segname:         __DWARF
+        addr:            0x10000926E
+        size:            232
+        offset:          0x226E
+        align:           0
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x0
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         14000000FFFFFFFF0400080001781E0C1F0000000000000014000000000000003803000001000000140000000000000014000000000000004C03000001000000140000000000000014000000000000006003000001000000140000000000000014000000000000007403000001000000140000000000000014000000000000008803000001000000140000000000000014000000000000009C0300000100000014000000000000001C00000000000000B0030000010000004800000000000000480C1D109E019D021C00000000000000F8030000010000001800000000000000480C1D109E019D02
+      - sectname:        __debug_abbrev
+        segname:         __DWARF
+        addr:            0x100009356
+        size:            171
+        offset:          0x2356
+        align:           0
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x0
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+      - sectname:        __debug_str
+        segname:         __DWARF
+        addr:            0x100009401
+        size:            378
+        offset:          0x2401
+        align:           0
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x0
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+      - sectname:        __apple_namespac
+        segname:         __DWARF
+        addr:            0x10000957B
+        size:            36
+        offset:          0x257B
+        align:           0
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x0
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         485341480100000001000000000000000C000000000000000100000001000600FFFFFFFF
+      - sectname:        __apple_names
+        segname:         __DWARF
+        addr:            0x10000959F
+        size:            340
+        offset:          0x259F
+        align:           0
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x0
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         48534148010000000B0000000B0000000C000000000000000100000001000600FFFFFFFF00000000FFFFFFFFFFFFFFFFFFFFFFFF01000000FFFFFFFF0300000004000000060000000900000073A83B36215E623FACBB81686A7F9A7C1939EE6AC7E03A771A39EE6AC8E03A773856D6801B39EE6AC9E03A77A4000000B4000000C4000000D4000000E4000000F40000000401000014010000240100003401000044010000AC000000010000002E00000000000000CA000000010000007300000000000000BF000000010000004F0000000000000075010000010000008001000000000000DC0000000100000088000000000000001801000001000000C700000000000000F0000000010000009D000000000000002C01000001000000DC00000000000000540100000100000006010000000000000401000001000000B2000000000000004001000001000000F100000000000000
+      - sectname:        __apple_types
+        segname:         __DWARF
+        addr:            0x1000096F3
+        size:            79
+        offset:          0x26F3
+        align:           0
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x0
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         48534148010000000100000001000000180000000000000004000000010006000300050005000B0006000600000000003080880B38000000BB0000000100000048000000240000A4283A0C00000000
+      - sectname:        __apple_objc
+        segname:         __DWARF
+        addr:            0x100009742
+        size:            36
+        offset:          0x2742
+        align:           0
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x0
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         485341480100000001000000000000000C000000000000000100000001000600FFFFFFFF
+LinkEditData:
+  NameList:
+    - n_strx:          2
+      n_type:          0xF
+      n_sect:          1
+      n_desc:          0
+      n_value:         4294968312
+    - n_strx:          8
+      n_type:          0xF
+      n_sect:          1
+      n_desc:          0
+      n_value:         4294968120
+    - n_strx:          29
+      n_type:          0xF
+      n_sect:          1
+      n_desc:          0
+      n_value:         4294968140
+    - n_strx:          50
+      n_type:          0xF
+      n_sect:          1
+      n_desc:          0
+      n_value:         4294968160
+    - n_strx:          71
+      n_type:          0xF
+      n_sect:          1
+      n_desc:          0
+      n_value:         4294968180
+    - n_strx:          92
+      n_type:          0xF
+      n_sect:          1
+      n_desc:          0
+      n_value:         4294968200
+    - n_strx:          113
+      n_type:          0xF
+      n_sect:          1
+      n_desc:          0
+      n_value:         4294968220
+    - n_strx:          134
+      n_type:          0xF
+      n_sect:          1
+      n_desc:          0
+      n_value:         4294968240
+    - n_strx:          168
+      n_type:          0xF
+      n_sect:          2
+      n_desc:          0
+      n_value:         4294983680
+    - n_strx:          184
+      n_type:          0xF
+      n_sect:          2
+      n_desc:          0
+      n_value:         4294983688
+    - n_strx:          196
+      n_type:          0xF
+      n_sect:          2
+      n_desc:          0
+      n_value:         4294983696
+    - n_strx:          215
+      n_type:          0xF
+      n_sect:          1
+      n_desc:          16
+      n_value:         4294967296
+  StringTable:
+    - ''
+    - ''
+    - _main
+    - _func_mainBin_dec_01
+    - _func_mainBin_dec_02
+    - _func_mainBin_dec_03
+    - _func_mainBin_inc_01
+    - _func_mainBin_inc_02
+    - _func_mainBin_inc_03
+    - _func_mainBin_dec_call_everything
+    - _g_volatile_var
+    - _g_func_ptr
+    - _g_extern_func_ptr
+    - __mh_execute_header
+DWARF:
+  debug_str:
+    - ''
+    - 'clang version 20.0.0git (https://github.com/alx32/llvm-project.git f41f6ea1f33c4f5e7c94f3d155e44292d1809c50)'
+    - call_sites.cpp
+    - '/'
+    - '/tmp/___________________________________/tst'
+    - g_volatile_var
+    - int
+    - g_func_ptr
+    - g_extern_func_ptr
+    - func_mainBin_dec_01
+    - func_mainBin_dec_02
+    - func_mainBin_dec_03
+    - func_mainBin_inc_01
+    - func_mainBin_inc_02
+    - func_mainBin_inc_03
+    - func_mainBin_dec_call_everything
+    - main
+  debug_abbrev:
+    - ID:              0
+      Table:
+        - Code:            0x1
+          Tag:             DW_TAG_compile_unit
+          Children:        DW_CHILDREN_yes
+          Attributes:
+            - Attribute:       DW_AT_producer
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_language
+              Form:            DW_FORM_data2
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_LLVM_sysroot
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_stmt_list
+              Form:            DW_FORM_sec_offset
+            - Attribute:       DW_AT_comp_dir
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_APPLE_optimized
+              Form:            DW_FORM_flag_present
+            - Attribute:       DW_AT_low_pc
+              Form:            DW_FORM_addr
+            - Attribute:       DW_AT_high_pc
+              Form:            DW_FORM_data4
+        - Code:            0x2
+          Tag:             DW_TAG_variable
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_type
+              Form:            DW_FORM_ref_addr
+            - Attribute:       DW_AT_external
+              Form:            DW_FORM_flag_present
+            - Attribute:       DW_AT_decl_file
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_decl_line
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_location
+              Form:            DW_FORM_exprloc
+        - Code:            0x3
+          Tag:             DW_TAG_volatile_type
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_type
+              Form:            DW_FORM_ref_addr
+        - Code:            0x4
+          Tag:             DW_TAG_base_type
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_encoding
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_byte_size
+              Form:            DW_FORM_data1
+        - Code:            0x5
+          Tag:             DW_TAG_pointer_type
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_type
+              Form:            DW_FORM_ref_addr
+        - Code:            0x6
+          Tag:             DW_TAG_subroutine_type
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_type
+              Form:            DW_FORM_ref_addr
+        - Code:            0x7
+          Tag:             DW_TAG_subprogram
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_low_pc
+              Form:            DW_FORM_addr
+            - Attribute:       DW_AT_high_pc
+              Form:            DW_FORM_data4
+            - Attribute:       DW_AT_APPLE_omit_frame_ptr
+              Form:            DW_FORM_flag_present
+            - Attribute:       DW_AT_frame_base
+              Form:            DW_FORM_exprloc
+            - Attribute:       DW_AT_call_all_calls
+              Form:            DW_FORM_flag_present
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_decl_file
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_decl_line
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_external
+              Form:            DW_FORM_flag_present
+            - Attribute:       DW_AT_APPLE_optimized
+              Form:            DW_FORM_flag_present
+        - Code:            0x8
+          Tag:             DW_TAG_subprogram
+          Children:        DW_CHILDREN_yes
+          Attributes:
+            - Attribute:       DW_AT_low_pc
+              Form:            DW_FORM_addr
+            - Attribute:       DW_AT_high_pc
+              Form:            DW_FORM_data4
+            - Attribute:       DW_AT_frame_base
+              Form:            DW_FORM_exprloc
+            - Attribute:       DW_AT_call_all_calls
+              Form:            DW_FORM_flag_present
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_decl_file
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_decl_line
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_external
+              Form:            DW_FORM_flag_present
+            - Attribute:       DW_AT_APPLE_optimized
+              Form:            DW_FORM_flag_present
+        - Code:            0x9
+          Tag:             DW_TAG_call_site
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_call_origin
+              Form:            DW_FORM_ref4
+            - Attribute:       DW_AT_call_return_pc
+              Form:            DW_FORM_addr
+        - Code:            0xA
+          Tag:             DW_TAG_call_site
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_call_target
+              Form:            DW_FORM_exprloc
+            - Attribute:       DW_AT_call_return_pc
+              Form:            DW_FORM_addr
+        - Code:            0xB
+          Tag:             DW_TAG_subprogram
+          Children:        DW_CHILDREN_yes
+          Attributes:
+            - Attribute:       DW_AT_low_pc
+              Form:            DW_FORM_addr
+            - Attribute:       DW_AT_high_pc
+              Form:            DW_FORM_data4
+            - Attribute:       DW_AT_frame_base
+              Form:            DW_FORM_exprloc
+            - Attribute:       DW_AT_call_all_calls
+              Form:            DW_FORM_flag_present
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_decl_file
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_decl_line
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_type
+              Form:            DW_FORM_ref_addr
+            - Attribute:       DW_AT_external
+              Form:            DW_FORM_flag_present
+            - Attribute:       DW_AT_APPLE_optimized
+              Form:            DW_FORM_flag_present
+  debug_aranges:
+    - Length:          0x2C
+      Version:         2
+      CuOffset:        0x0
+      AddressSize:     0x8
+      Descriptors:
+        - Address:         0x100000338
+          Length:          0xD8
+  debug_info:
+    - Length:          0x1A4
+      Version:         4
+      AbbrevTableID:   0
+      AbbrOffset:      0x0
+      AddrSize:        8
+      Entries:
+        - AbbrCode:        0x1
+          Values:
+            - Value:           0x1
+            - Value:           0x21
+            - Value:           0x6E
+            - Value:           0x7D
+            - Value:           0x0
+            - Value:           0x7F
+            - Value:           0x1
+            - Value:           0x100000338
+            - Value:           0xD8
+        - AbbrCode:        0x2
+          Values:
+            - Value:           0xAC
+            - Value:           0x43
+            - Value:           0x1
+            - Value:           0x1
+            - Value:           0x4
+            - Value:           0x9
+              BlockData:       [ 0x3, 0x0, 0x40, 0x0, 0x0, 0x1, 0x0, 0x0,
+                                 0x0 ]
+        - AbbrCode:        0x3
+          Values:
+            - Value:           0x48
+        - AbbrCode:        0x4
+          Values:
+            - Value:           0xBB
+            - Value:           0x5
+            - Value:           0x4
+        - AbbrCode:        0x2
+          Values:
+            - Value:           0xBF
+            - Value:           0x64
+            - Value:           0x1
+            - Value:           0x1
+            - Value:           0x5
+            - Value:           0x9
+              BlockData:       [ 0x3, 0x8, 0x40, 0x0, 0x0, 0x1, 0x0, 0x0,
+                                 0x0 ]
+        - AbbrCode:        0x3
+          Values:
+            - Value:           0x69
+        - AbbrCode:        0x5
+          Values:
+            - Value:           0x6E
+        - AbbrCode:        0x6
+          Values:
+            - Value:           0x48
+        - AbbrCode:        0x2
+          Values:
+            - Value:           0xCA
+            - Value:           0x64
+            - Value:           0x1
+            - Value:           0x1
+            - Value:           0x6
+            - Value:           0x9
+              BlockData:       [ 0x3, 0x10, 0x40, 0x0, 0x0, 0x1, 0x0, 0x0,
+                                 0x0 ]
+        - AbbrCode:        0x7
+          Values:
+            - Value:           0x100000338
+            - Value:           0x14
+            - Value:           0x1
+            - Value:           0x1
+              BlockData:       [ 0x6F ]
+            - Value:           0x1
+            - Value:           0xDC
+            - Value:           0x1
+            - Value:           0x8
+            - Value:           0x1
+            - Value:           0x1
+        - AbbrCode:        0x7
+          Values:
+            - Value:           0x10000034C
+            - Value:           0x14
+            - Value:           0x1
+            - Value:           0x1
+              BlockData:       [ 0x6F ]
+            - Value:           0x1
+            - Value:           0xF0
+            - Value:           0x1
+            - Value:           0x9
+            - Value:           0x1
+            - Value:           0x1
+        - AbbrCode:        0x7
+          Values:
+            - Value:           0x100000360
+            - Value:           0x14
+            - Value:           0x1
+            - Value:           0x1
+              BlockData:       [ 0x6F ]
+            - Value:           0x1
+            - Value:           0x104
+            - Value:           0x1
+            - Value:           0xA
+            - Value:           0x1
+            - Value:           0x1
+        - AbbrCode:        0x7
+          Values:
+            - Value:           0x100000374
+            - Value:           0x14
+            - Value:           0x1
+            - Value:           0x1
+              BlockData:       [ 0x6F ]
+            - Value:           0x1
+            - Value:           0x118
+            - Value:           0x1
+            - Value:           0xC
+            - Value:           0x1
+            - Value:           0x1
+        - AbbrCode:        0x7
+          Values:
+            - Value:           0x100000388
+            - Value:           0x14
+            - Value:           0x1
+            - Value:           0x1
+              BlockData:       [ 0x6F ]
+            - Value:           0x1
+            - Value:           0x12C
+            - Value:           0x1
+            - Value:           0xD
+            - Value:           0x1
+            - Value:           0x1
+        - AbbrCode:        0x7
+          Values:
+            - Value:           0x10000039C
+            - Value:           0x14
+            - Value:           0x1
+            - Value:           0x1
+              BlockData:       [ 0x6F ]
+            - Value:           0x1
+            - Value:           0x140
+            - Value:           0x1
+            - Value:           0xE
+            - Value:           0x1
+            - Value:           0x1
+        - AbbrCode:        0x8
+          Values:
+            - Value:           0x1000003B0
+            - Value:           0x48
+            - Value:           0x1
+              BlockData:       [ 0x6D ]
+            - Value:           0x1
+            - Value:           0x154
+            - Value:           0x1
+            - Value:           0x10
+            - Value:           0x1
+            - Value:           0x1
+        - AbbrCode:        0x9
+          Values:
+            - Value:           0x88
+            - Value:           0x1000003BC
+        - AbbrCode:        0x9
+          Values:
+            - Value:           0x9D
+            - Value:           0x1000003C0
+        - AbbrCode:        0x9
+          Values:
+            - Value:           0xB2
+            - Value:           0x1000003C4
+        - AbbrCode:        0x9
+          Values:
+            - Value:           0xC7
+            - Value:           0x1000003C8
+        - AbbrCode:        0x9
+          Values:
+            - Value:           0xDC
+            - Value:           0x1000003CC
+        - AbbrCode:        0x9
+          Values:
+            - Value:           0xF1
+            - Value:           0x1000003D0
+        - AbbrCode:        0xA
+          Values:
+            - Value:           0x1
+              BlockData:       [ 0x58 ]
+            - Value:           0x1000003DC
+        - AbbrCode:        0xA
+          Values:
+            - Value:           0x1
+              BlockData:       [ 0x58 ]
+            - Value:           0x1000003E8
+        - AbbrCode:        0x0
+        - AbbrCode:        0xB
+          Values:
+            - Value:           0x1000003F8
+            - Value:           0x18
+            - Value:           0x1
+              BlockData:       [ 0x6D ]
+            - Value:           0x1
+            - Value:           0x175
+            - Value:           0x1
+            - Value:           0x1F
+            - Value:           0x48
+            - Value:           0x1
+            - Value:           0x1
+        - AbbrCode:        0x9
+          Values:
+            - Value:           0x106
+            - Value:           0x100000404
+        - AbbrCode:        0x0
+        - AbbrCode:        0x0
+  debug_line:
+    - Length:          146
+      Version:         4
+      PrologueLength:  38
+      MinInstLength:   1
+      MaxOpsPerInst:   1
+      DefaultIsStmt:   1
+      LineBase:        251
+      LineRange:       14
+      OpcodeBase:      13
+      StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]
+      Files:
+        - Name:            call_sites.cpp
+          DirIdx:          0
+          ModTime:         0
+          Length:          0
+      Opcodes:
+        - Opcode:          DW_LNS_extended_op
+          ExtLen:          9
+          SubOpcode:       DW_LNE_set_address
+          Data:            4294968120
+        - Opcode:          DW_LNS_set_column
+          Data:            54
+        - Opcode:          DW_LNS_set_prologue_end
+          Data:            0
+        - Opcode:          0x19
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            58
+        - Opcode:          DW_LNS_negate_stmt
+          Data:            0
+        - Opcode:          0xF2
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            54
+        - Opcode:          DW_LNS_negate_stmt
+          Data:            0
+        - Opcode:          DW_LNS_set_prologue_end
+          Data:            0
+        - Opcode:          0x4B
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            58
+        - Opcode:          DW_LNS_negate_stmt
+          Data:            0
+        - Opcode:          0xF2
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            54
+        - Opcode:          DW_LNS_negate_stmt
+          Data:            0
+        - Opcode:          DW_LNS_set_prologue_end
+          Data:            0
+        - Opcode:          0x4B
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            58
+        - Opcode:          DW_LNS_negate_stmt
+          Data:            0
+        - Opcode:          0xF2
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            54
+        - Opcode:          DW_LNS_negate_stmt
+          Data:            0
+        - Opcode:          DW_LNS_set_prologue_end
+          Data:            0
+        - Opcode:          0x4C
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            58
+        - Opcode:          DW_LNS_negate_stmt
+          Data:            0
+        - Opcode:          0xF2
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            54
+        - Opcode:          DW_LNS_negate_stmt
+          Data:            0
+        - Opcode:          DW_LNS_set_prologue_end
+          Data:            0
+        - Opcode:          0x4B
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            58
+        - Opcode:          DW_LNS_negate_stmt
+          Data:            0
+        - Opcode:          0xF2
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            54
+        - Opcode:          DW_LNS_negate_stmt
+          Data:            0
+        - Opcode:          DW_LNS_set_prologue_end
+          Data:            0
+        - Opcode:          0x4B
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            58
+        - Opcode:          DW_LNS_negate_stmt
+          Data:            0
+        - Opcode:          0xF2
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            0
+        - Opcode:          DW_LNS_negate_stmt
+          Data:            0
+        - Opcode:          0x4C
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            5
+        - Opcode:          DW_LNS_set_prologue_end
+          Data:            0
+        - Opcode:          0x83
+          Data:            0
+        - Opcode:          0x4B
+          Data:            0
+        - Opcode:          0x4B
+          Data:            0
+        - Opcode:          0x4C
+          Data:            0
+        - Opcode:          0x4B
+          Data:            0
+        - Opcode:          0x4B
+          Data:            0
+        - Opcode:          0x4C
+          Data:            0
+        - Opcode:          0xBB
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            20
+        - Opcode:          0xBC
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            1
+        - Opcode:          DW_LNS_set_epilogue_begin
+          Data:            0
+        - Opcode:          0x83
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            0
+        - Opcode:          0x84
+          Data:            0
+        - Opcode:          DW_LNS_set_column
+          Data:            3
+        - Opcode:          DW_LNS_set_prologue_end
+          Data:            0
+        - Opcode:          0x83
+          Data:            0
+        - Opcode:          0x4B
+          Data:            0
+        - Opcode:          DW_LNS_negate_stmt
+          Data:            0
+        - Opcode:          DW_LNS_set_epilogue_begin
+          Data:            0
+        - Opcode:          0x4A
+          Data:            0
+        - Opcode:          DW_LNS_advance_pc
+          Data:            8
+        - Opcode:          DW_LNS_extended_op
+          ExtLen:          1
+          SubOpcode:       DW_LNE_end_sequence
+          Data:            0
+...
diff --git a/llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-callsite-info-exe.yaml b/llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-callsite-info-exe.yaml
new file mode 100644
index 00000000000000..b454a9e14699a9
--- /dev/null
+++ b/llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-callsite-info-exe.yaml
@@ -0,0 +1,558 @@
+## Test that reconstructs a MachO binary from YAML and generates a callsite-enabled gsym from it - and then verifies the gsym.
+## See llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-callsite-info.test for the script to generate this yaml file
+
+# RUN: split-file %s %t
+# RUN: yaml2obj %t/call_sites.exe.yaml -o %t/call_sites.exe
+
+# RUN: llvm-gsymutil --convert=%t/call_sites.exe --callsites-from-yaml=%t/callsites.yaml -o %t/call_sites_exe.gsym
+
+# Dump the GSYM file and check the output for callsite information
+# RUN: llvm-gsymutil %t/call_sites_exe.gsym | FileCheck --check-prefix=CHECK-GSYM %s
+
+
+# CHECK-GSYM:      FunctionInfo @ 0x[[#%x,]]: [0x[[#%x,]] - 0x[[#%x,]]) "func_mainBin_dec_call_everything"
+# CHECK-GSYM-NEXT: CallSites (by return address):
+# CHECK-GSYM-NEXT:   0x[[#%x,]] Flags[InternalCall] MatchRegex[func_mainBin_dec_01]
+# CHECK-GSYM-NEXT:   0x[[#%x,]] Flags[InternalCall] MatchRegex[func_mainBin_dec_02]
+# CHECK-GSYM-NEXT:   0x[[#%x,]] Flags[InternalCall] MatchRegex[func_mainBin_dec_03]
+# CHECK-GSYM-NEXT:   0x[[#%x,]] Flags[InternalCall] MatchRegex[func_mainBin_inc_01]
+# CHECK-GSYM-NEXT:   0x[[#%x,]] Flags[InternalCall] MatchRegex[func_mainBin_inc_02]
+# CHECK-GSYM-NEXT:   0x[[#%x,]] Flags[InternalCall] MatchRegex[func_mainBin_inc_03]
+# CHECK-GSYM-NEXT:   0x[[#%x,]] Flags[None] MatchRegex[.*func.*]
+# CHECK-GSYM-NEXT:   0x[[#%x,]] Flags[ExternalCall] MatchRegex[.*extern_func.*]
+
+
+#--- callsites.yaml
+functions:
+  - name: func_mainBin_dec_call_everything
+    callsites:
+      - return_offset: 0x0C
+        match_regex: ["func_mainBin_dec_01"]
+        flags:
+          - "InternalCall"
+      - return_offset: 0x10
+        match_regex: ["func_mainBin_dec_02"]
+        flags:
+          - "InternalCall"
+      - return_offset: 0x14
+        match_regex: ["func_mainBin_dec_03"]
+        flags:
+          - "InternalCall"
+      - return_offset: 24
+        match_regex: ["func_mainBin_inc_01"]
+        flags:
+          - "InternalCall"
+      - return_offset: 28
+        match_regex: ["func_mainBin_inc_02"]
+        flags:
+          - "InternalCall"
+      - return_offset: 32
+        match_regex: ["func_mainBin_inc_03"]
+        flags:
+          - "InternalCall"
+      - return_offset: 44
+        match_regex: [".*func.*"]
+      - return_offset: 56
+        match_regex: [".*extern_func.*"]
+        flags:
+          - "ExternalCall"
+
+
+#--- call_sites.exe.yaml
+--- !mach-o
+FileHeader:
+  magic:           0xFEEDFACF
+  cputype:         0x100000C
+  cpusubtype:      0x0
+  filetype:        0x2
+  ncmds:           14
+  sizeofcmds:      760
+  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:         152
+    segname:         __TEXT
+    vmaddr:          4294967296
+    vmsize:          16384
+    fileoff:         0
+    filesize:        16384
+    maxprot:         5
+    initprot:        5
+    nsects:          1
+    flags:           0
+    Sections:
+      - sectname:        __text
+        segname:         __TEXT
+        addr:            0x100000338
+        size:            216
+        offset:          0x338
+        align:           2
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x80000400
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         28000090090140B929050051090100B9C0035FD628000090090140B929050051090100B9C0035FD628000090090140B929050051090100B9C0035FD628000090090140B929050011090100B9C0035FD628000090090140B929050011090100B9C0035FD628000090090140B929050011090100B9C0035FD6FD7BBFA9FD030091E0FFFF97E4FFFF97E8FFFF97ECFFFF97F0FFFF97F4FFFF971F2003D5A8E1015800013FD61F2003D588E1015800013FD6280000901F0100B9FD7BC1A8C0035FD6FD7BBFA9FD030091ECFFFF9700008052FD7BC1A8C0035FD6
+  - cmd:             LC_SEGMENT_64
+    cmdsize:         152
+    segname:         __DATA
+    vmaddr:          4294983680
+    vmsize:          16384
+    fileoff:         16384
+    filesize:        0
+    maxprot:         3
+    initprot:        3
+    nsects:          1
+    flags:           0
+    Sections:
+      - sectname:        __common
+        segname:         __DATA
+        addr:            0x100004000
+        size:            24
+        offset:          0x0
+        align:           3
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x1
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+  - cmd:             LC_SEGMENT_64
+    cmdsize:         72
+    segname:         __LINKEDIT
+    vmaddr:          4295000064
+    vmsize:          1648
+    fileoff:         16384
+    filesize:        1648
+    maxprot:         1
+    initprot:        1
+    nsects:          0
+    flags:           0
+  - cmd:             LC_DYLD_INFO_ONLY
+    cmdsize:         48
+    rebase_off:      0
+    rebase_size:     0
+    bind_off:        0
+    bind_size:       0
+    weak_bind_off:   0
+    weak_bind_size:  0
+    lazy_bind_off:   0
+    lazy_bind_size:  0
+    export_off:      16384
+    export_size:     232
+  - cmd:             LC_SYMTAB
+    cmdsize:         24
+    symoff:          16632
+    nsyms:           34
+    stroff:          17176
+    strsize:         568
+  - cmd:             LC_DYSYMTAB
+    cmdsize:         80
+    ilocalsym:       0
+    nlocalsym:       22
+    iextdefsym:      22
+    nextdefsym:      12
+    iundefsym:       34
+    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:            4C4C44E9-5555-3144-A1D3-328233D00078
+  - cmd:             LC_BUILD_VERSION
+    cmdsize:         32
+    platform:        1
+    minos:           720896
+    sdk:             720896
+    ntools:          1
+    Tools:
+      - tool:            4
+        version:         1310720
+  - cmd:             LC_MAIN
+    cmdsize:         24
+    entryoff:        1016
+    stacksize:       0
+  - cmd:             LC_FUNCTION_STARTS
+    cmdsize:         16
+    dataoff:         16616
+    datasize:        16
+  - cmd:             LC_DATA_IN_CODE
+    cmdsize:         16
+    dataoff:         16632
+    datasize:        0
+  - cmd:             LC_CODE_SIGNATURE
+    cmdsize:         16
+    dataoff:         17744
+    datasize:        288
+LinkEditData:
+  ExportTrie:
+    TerminalSize:    0
+    NodeOffset:      0
+    Name:            ''
+    Flags:           0x0
+    Address:         0x0
+    Other:           0x0
+    ImportName:      ''
+    Children:
+      - TerminalSize:    0
+        NodeOffset:      5
+        Name:            _
+        Flags:           0x0
+        Address:         0x0
+        Other:           0x0
+        ImportName:      ''
+        Children:
+          - TerminalSize:    2
+            NodeOffset:      52
+            Name:            _mh_execute_header
+            Flags:           0x0
+            Address:         0x0
+            Other:           0x0
+            ImportName:      ''
+          - TerminalSize:    3
+            NodeOffset:      56
+            Name:            main
+            Flags:           0x0
+            Address:         0x3F8
+            Other:           0x0
+            ImportName:      ''
+          - TerminalSize:    0
+            NodeOffset:      61
+            Name:            g_
+            Flags:           0x0
+            Address:         0x0
+            Other:           0x0
+            ImportName:      ''
+            Children:
+              - TerminalSize:    4
+                NodeOffset:      104
+                Name:            volatile_var
+                Flags:           0x0
+                Address:         0x4000
+                Other:           0x0
+                ImportName:      ''
+              - TerminalSize:    4
+                NodeOffset:      110
+                Name:            func_ptr
+                Flags:           0x0
+                Address:         0x4008
+                Other:           0x0
+                ImportName:      ''
+              - TerminalSize:    4
+                NodeOffset:      116
+                Name:            extern_func_ptr
+                Flags:           0x0
+                Address:         0x4010
+                Other:           0x0
+                ImportName:      ''
+          - TerminalSize:    0
+            NodeOffset:      122
+            Name:            func_mainBin_
+            Flags:           0x0
+            Address:         0x0
+            Other:           0x0
+            ImportName:      ''
+            Children:
+              - TerminalSize:    0
+                NodeOffset:      139
+                Name:            dec_
+                Flags:           0x0
+                Address:         0x0
+                Other:           0x0
+                ImportName:      ''
+                Children:
+                  - TerminalSize:    3
+                    NodeOffset:      163
+                    Name:            call_everything
+                    Flags:           0x0
+                    Address:         0x3B0
+                    Other:           0x0
+                    ImportName:      ''
+                  - TerminalSize:    0
+                    NodeOffset:      168
+                    Name:            '0'
+                    Flags:           0x0
+                    Address:         0x0
+                    Other:           0x0
+                    ImportName:      ''
+                    Children:
+                      - TerminalSize:    3
+                        NodeOffset:      182
+                        Name:            '1'
+                        Flags:           0x0
+                        Address:         0x338
+                        Other:           0x0
+                        ImportName:      ''
+                      - TerminalSize:    3
+                        NodeOffset:      187
+                        Name:            '3'
+                        Flags:           0x0
+                        Address:         0x360
+                        Other:           0x0
+                        ImportName:      ''
+                      - TerminalSize:    3
+                        NodeOffset:      192
+                        Name:            '2'
+                        Flags:           0x0
+                        Address:         0x34C
+                        Other:           0x0
+                        ImportName:      ''
+              - TerminalSize:    0
+                NodeOffset:      197
+                Name:            inc_0
+                Flags:           0x0
+                Address:         0x0
+                Other:           0x0
+                ImportName:      ''
+                Children:
+                  - TerminalSize:    3
+                    NodeOffset:      211
+                    Name:            '2'
+                    Flags:           0x0
+                    Address:         0x388
+                    Other:           0x0
+                    ImportName:      ''
+                  - TerminalSize:    3
+                    NodeOffset:      216
+                    Name:            '1'
+                    Flags:           0x0
+                    Address:         0x374
+                    Other:           0x0
+                    ImportName:      ''
+                  - TerminalSize:    3
+                    NodeOffset:      221
+                    Name:            '3'
+                    Flags:           0x0
+                    Address:         0x39C
+                    Other:           0x0
+                    ImportName:      ''
+  NameList:
+    - n_strx:          235
+      n_type:          0x64
+      n_sect:          0
+      n_desc:          0
+      n_value:         0
+    - n_strx:          295
+      n_type:          0x66
+      n_sect:          0
+      n_desc:          1
+      n_value:         0
+    - n_strx:          353
+      n_type:          0x24
+      n_sect:          1
+      n_desc:          0
+      n_value:         4294968312
+    - n_strx:          1
+      n_type:          0x24
+      n_sect:          0
+      n_desc:          0
+      n_value:         24
+    - n_strx:          359
+      n_type:          0x24
+      n_sect:          1
+      n_desc:          0
+      n_value:         4294968120
+    - n_strx:          1
+      n_type:          0x24
+      n_sect:          0
+      n_desc:          0
+      n_value:         20
+    - n_strx:          380
+      n_type:          0x24
+      n_sect:          1
+      n_desc:          0
+      n_value:         4294968140
+    - n_strx:          1
+      n_type:          0x24
+      n_sect:          0
+      n_desc:          0
+      n_value:         20
+    - n_strx:          401
+      n_type:          0x24
+      n_sect:          1
+      n_desc:          0
+      n_value:         4294968160
+    - n_strx:          1
+      n_type:          0x24
+      n_sect:          0
+      n_desc:          0
+      n_value:         20
+    - n_strx:          422
+      n_type:          0x24
+      n_sect:          1
+      n_desc:          0
+      n_value:         4294968180
+    - n_strx:          1
+      n_type:          0x24
+      n_sect:          0
+      n_desc:          0
+      n_value:         20
+    - n_strx:          443
+      n_type:          0x24
+      n_sect:          1
+      n_desc:          0
+      n_value:         4294968200
+    - n_strx:          1
+      n_type:          0x24
+      n_sect:          0
+      n_desc:          0
+      n_value:         20
+    - n_strx:          464
+      n_type:          0x24
+      n_sect:          1
+      n_desc:          0
+      n_value:         4294968220
+    - n_strx:          1
+      n_type:          0x24
+      n_sect:          0
+      n_desc:          0
+      n_value:         20
+    - n_strx:          485
+      n_type:          0x24
+      n_sect:          1
+      n_desc:          0
+      n_value:         4294968240
+    - n_strx:          1
+      n_type:          0x24
+      n_sect:          0
+      n_desc:          0
+      n_value:         72
+    - n_strx:          519
+      n_type:          0x20
+      n_sect:          2
+      n_desc:          0
+      n_value:         4294983680
+    - n_strx:          535
+      n_type:          0x20
+      n_sect:          2
+      n_desc:          0
+      n_value:         4294983688
+    - n_strx:          547
+      n_type:          0x20
+      n_sect:          2
+      n_desc:          0
+      n_value:         4294983696
+    - n_strx:          1
+      n_type:          0x64
+      n_sect:          1
+      n_desc:          0
+      n_value:         0
+    - n_strx:          2
+      n_type:          0xF
+      n_sect:          1
+      n_desc:          0
+      n_value:         4294968312
+    - n_strx:          8
+      n_type:          0xF
+      n_sect:          1
+      n_desc:          0
+      n_value:         4294968120
+    - n_strx:          29
+      n_type:          0xF
+      n_sect:          1
+      n_desc:          0
+      n_value:         4294968140
+    - n_strx:          50
+      n_type:          0xF
+      n_sect:          1
+      n_desc:          0
+      n_value:         4294968160
+    - n_strx:          71
+      n_type:          0xF
+      n_sect:          1
+      n_desc:          0
+      n_value:         4294968180
+    - n_strx:          92
+      n_type:          0xF
+      n_sect:          1
+      n_desc:          0
+      n_value:         4294968200
+    - n_strx:          113
+      n_type:          0xF
+      n_sect:          1
+      n_desc:          0
+      n_value:         4294968220
+    - n_strx:          134
+      n_type:          0xF
+      n_sect:          1
+      n_desc:          0
+      n_value:         4294968240
+    - n_strx:          168
+      n_type:          0xF
+      n_sect:          2
+      n_desc:          0
+      n_value:         4294983680
+    - n_strx:          184
+      n_type:          0xF
+      n_sect:          2
+      n_desc:          0
+      n_value:         4294983688
+    - n_strx:          196
+      n_type:          0xF
+      n_sect:          2
+      n_desc:          0
+      n_value:         4294983696
+    - n_strx:          215
+      n_type:          0xF
+      n_sect:          1
+      n_desc:          16
+      n_value:         4294967296
+  StringTable:
+    - ' '
+    - _main
+    - _func_mainBin_dec_01
+    - _func_mainBin_dec_02
+    - _func_mainBin_dec_03
+    - _func_mainBin_inc_01
+    - _func_mainBin_inc_02
+    - _func_mainBin_inc_03
+    - _func_mainBin_dec_call_everything
+    - _g_volatile_var
+    - _g_func_ptr
+    - _g_extern_func_ptr
+    - __mh_execute_header
+    - '/tmp/_______________________________________/call_sites.cpp'
+    - '/tmp/_______________________________________/call_sites.o'
+    - _main
+    - _func_mainBin_dec_01
+    - _func_mainBin_dec_02
+    - _func_mainBin_dec_03
+    - _func_mainBin_inc_01
+    - _func_mainBin_inc_02
+    - _func_mainBin_inc_03
+    - _func_mainBin_dec_call_everything
+    - _g_volatile_var
+    - _g_func_ptr
+    - _g_extern_func_ptr
+    - ''
+    - ''
+  FunctionStarts:  [ 0x338, 0x34C, 0x360, 0x374, 0x388, 0x39C, 0x3B0, 0x3F8 ]
+...
diff --git a/llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-callsite-info-obj.test b/llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-callsite-info-obj.test
new file mode 100644
index 00000000000000..255b68a343b8db
--- /dev/null
+++ b/llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-callsite-info-obj.test
@@ -0,0 +1,304 @@
+// RUN: split-file %s %t
+
+// Assemble the input assembly code into an object file
+// RUN: llc -enable-machine-outliner=never -mtriple arm64-apple-darwin -filetype=obj %t/call_sites.ll -o %t/call_sites.o
+// RUN: llvm-gsymutil --convert=%t/call_sites.o --callsites-from-yaml=%t/callsites.yaml -o %t/call_sites_obj.gsym
+
+// Dump the GSYM file and check the output for callsite information
+// RUN: llvm-gsymutil %t/call_sites_obj.gsym | FileCheck --check-prefix=CHECK-GSYM %s
+
+
+// CHECK-GSYM:      FunctionInfo @ 0x[[#%x,]]: [0x[[#%x,]] - 0x[[#%x,]]) "func_mainBin_dec_call_everything"
+// CHECK-GSYM-NEXT: LineTable:
+                      // func_mainBin_dec_call_everything() {
+// CHECK-GSYM-NEXT:   0x[[#%x,]] {{.*}}/call_sites.cpp:16
+                      // func_mainBin_dec_01();
+// CHECK-GSYM-NEXT:   0x[[ADDR_dec_01_call:[0-9a-f]+]] {{.*}}/call_sites.cpp:17
+                      // func_mainBin_dec_02();
+// CHECK-GSYM-NEXT:   0x[[ADDR_dec_02_call:[0-9a-f]+]] {{.*}}/call_sites.cpp:18
+                      // func_mainBin_dec_03();
+// CHECK-GSYM-NEXT:   [[ADDR_dec_03_call:0x[0-9a-f]+]] {{.*}}/call_sites.cpp:19
+                      // func_mainBin_inc_01();
+// CHECK-GSYM-NEXT:   [[ADDR_inc_01_call:0x[0-9a-f]+]] {{.*}}/call_sites.cpp:21
+                      // func_mainBin_inc_02();
+// CHECK-GSYM-NEXT:   [[ADDR_inc_02_call:0x[0-9a-f]+]] {{.*}}/call_sites.cpp:22
+                      // func_mainBin_inc_03();
+// CHECK-GSYM-NEXT:   [[ADDR_inc_03_call:0x[0-9a-f]+]] {{.*}}/call_sites.cpp:23
+                      // g_func_ptr();
+// CHECK-GSYM-NEXT:   [[ADDR_func_call:0x[0-9a-f]+]] {{.*}}/call_sites.cpp:25
+                      // g_extern_func_ptr();
+// CHECK-GSYM-NEXT:   [[ADDR_extern_func_call:0x[0-9a-f]+]] {{.*}}/call_sites.cpp:26
+                      // g_volatile_var = 0;
+// CHECK-GSYM-NEXT:   [[ADDR_var_assign:0x[0-9a-f]+]] {{.*}}/call_sites.cpp:28
+                      // }
+// CHECK-GSYM-NEXT:   [[#%x,]] {{.*}}/call_sites.cpp:29
+// CHECK-GSYM-NEXT: CallSites (by return address):
+// CHECK-GSYM-NEXT:   [[ADDR_dec_02_call]] Flags[InternalCall] MatchRegex[func_mainBin_dec_01]
+// CHECK-GSYM-NEXT:   [[ADDR_dec_03_call]] Flags[InternalCall] MatchRegex[func_mainBin_dec_02]
+// CHECK-GSYM-NEXT:   [[ADDR_inc_01_call]] Flags[InternalCall] MatchRegex[func_mainBin_dec_03]
+// CHECK-GSYM-NEXT:   [[ADDR_inc_02_call]] Flags[InternalCall] MatchRegex[func_mainBin_inc_01]
+// CHECK-GSYM-NEXT:   [[ADDR_inc_03_call]] Flags[InternalCall] MatchRegex[func_mainBin_inc_02]
+// CHECK-GSYM-NEXT:   [[ADDR_func_call]] Flags[InternalCall] MatchRegex[func_mainBin_inc_03]
+// CHECK-GSYM-NEXT:   [[ADDR_extern_func_call]] Flags[None] MatchRegex[.*func.*]
+// CHECK-GSYM-NEXT:   [[ADDR_var_assign]] Flags[ExternalCall] MatchRegex[.*extern_func.*]
+
+
+//--- callsites.yaml
+functions:
+  - name: func_mainBin_dec_call_everything
+    callsites:
+      - return_offset: 0x0C
+        match_regex: ["func_mainBin_dec_01"]
+        flags:
+          - "InternalCall"
+      - return_offset: 0x10
+        match_regex: ["func_mainBin_dec_02"]
+        flags:
+          - "InternalCall"
+      - return_offset: 0x14
+        match_regex: ["func_mainBin_dec_03"]
+        flags:
+          - "InternalCall"
+      - return_offset: 24
+        match_regex: ["func_mainBin_inc_01"]
+        flags:
+          - "InternalCall"
+      - return_offset: 28
+        match_regex: ["func_mainBin_inc_02"]
+        flags:
+          - "InternalCall"
+      - return_offset: 32
+        match_regex: ["func_mainBin_inc_03"]
+        flags:
+          - "InternalCall"
+      - return_offset: 44
+        match_regex: [".*func.*"]
+      - return_offset: 56
+        match_regex: [".*extern_func.*"]
+        flags:
+          - "ExternalCall"
+
+
+//--- call_sites.ll
+; ModuleID = 'call_sites.cpp'
+source_filename = "call_sites.cpp"
+target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128-Fn32"
+target triple = "arm64-unknown-macosx10.4.0"
+
+ at g_volatile_var = global i32 0, align 4, !dbg !0
+ at g_func_ptr = global ptr null, align 8, !dbg !5
+ at g_extern_func_ptr = global ptr null, align 8, !dbg !12
+
+; Function Attrs: minsize mustprogress nofree noinline norecurse nounwind optsize ssp memory(readwrite, argmem: none)
+define void @func_mainBin_dec_01() local_unnamed_addr #0 !dbg !21 {
+entry:
+  %0 = load volatile i32, ptr @g_volatile_var, align 4, !dbg !24, !tbaa !25
+  %dec = add nsw i32 %0, -1, !dbg !24
+  store volatile i32 %dec, ptr @g_volatile_var, align 4, !dbg !24, !tbaa !25
+  ret void, !dbg !29
+}
+
+; Function Attrs: minsize mustprogress nofree noinline norecurse nounwind optsize ssp memory(readwrite, argmem: none)
+define void @func_mainBin_dec_02() local_unnamed_addr #0 !dbg !30 {
+entry:
+  %0 = load volatile i32, ptr @g_volatile_var, align 4, !dbg !31, !tbaa !25
+  %dec = add nsw i32 %0, -1, !dbg !31
+  store volatile i32 %dec, ptr @g_volatile_var, align 4, !dbg !31, !tbaa !25
+  ret void, !dbg !32
+}
+
+; Function Attrs: minsize mustprogress nofree noinline norecurse nounwind optsize ssp memory(readwrite, argmem: none)
+define void @func_mainBin_dec_03() local_unnamed_addr #0 !dbg !33 {
+entry:
+  %0 = load volatile i32, ptr @g_volatile_var, align 4, !dbg !34, !tbaa !25
+  %dec = add nsw i32 %0, -1, !dbg !34
+  store volatile i32 %dec, ptr @g_volatile_var, align 4, !dbg !34, !tbaa !25
+  ret void, !dbg !35
+}
+
+; Function Attrs: minsize mustprogress nofree noinline norecurse nounwind optsize ssp memory(readwrite, argmem: none)
+define void @func_mainBin_inc_01() local_unnamed_addr #0 !dbg !36 {
+entry:
+  %0 = load volatile i32, ptr @g_volatile_var, align 4, !dbg !37, !tbaa !25
+  %inc = add nsw i32 %0, 1, !dbg !37
+  store volatile i32 %inc, ptr @g_volatile_var, align 4, !dbg !37, !tbaa !25
+  ret void, !dbg !38
+}
+
+; Function Attrs: minsize mustprogress nofree noinline norecurse nounwind optsize ssp memory(readwrite, argmem: none)
+define void @func_mainBin_inc_02() local_unnamed_addr #0 !dbg !39 {
+entry:
+  %0 = load volatile i32, ptr @g_volatile_var, align 4, !dbg !40, !tbaa !25
+  %inc = add nsw i32 %0, 1, !dbg !40
+  store volatile i32 %inc, ptr @g_volatile_var, align 4, !dbg !40, !tbaa !25
+  ret void, !dbg !41
+}
+
+; Function Attrs: minsize mustprogress nofree noinline norecurse nounwind optsize ssp memory(readwrite, argmem: none)
+define void @func_mainBin_inc_03() local_unnamed_addr #0 !dbg !42 {
+entry:
+  %0 = load volatile i32, ptr @g_volatile_var, align 4, !dbg !43, !tbaa !25
+  %inc = add nsw i32 %0, 1, !dbg !43
+  store volatile i32 %inc, ptr @g_volatile_var, align 4, !dbg !43, !tbaa !25
+  ret void, !dbg !44
+}
+
+; Function Attrs: minsize mustprogress noinline nounwind optsize ssp
+define void @func_mainBin_dec_call_everything() local_unnamed_addr #1 !dbg !45 {
+entry:
+  tail call void @func_mainBin_dec_01() #3, !dbg !46
+  tail call void @func_mainBin_dec_02() #3, !dbg !47
+  tail call void @func_mainBin_dec_03() #3, !dbg !48
+  tail call void @func_mainBin_inc_01() #3, !dbg !49
+  tail call void @func_mainBin_inc_02() #3, !dbg !50
+  tail call void @func_mainBin_inc_03() #3, !dbg !51
+  %0 = load volatile ptr, ptr @g_func_ptr, align 8, !dbg !52, !tbaa !53
+  %call = tail call noundef i32 %0() #4, !dbg !52
+  %1 = load volatile ptr, ptr @g_extern_func_ptr, align 8, !dbg !55, !tbaa !53
+  %call1 = tail call noundef i32 %1() #4, !dbg !55
+  store volatile i32 0, ptr @g_volatile_var, align 4, !dbg !56, !tbaa !25
+  ret void, !dbg !57
+}
+
+; Function Attrs: minsize mustprogress norecurse nounwind optsize ssp
+define noundef i32 @main() local_unnamed_addr #2 !dbg !58 {
+entry:
+  tail call void @func_mainBin_dec_call_everything() #3, !dbg !59
+  ret i32 0, !dbg !60
+}
+
+attributes #0 = { minsize mustprogress nofree noinline norecurse nounwind optsize ssp memory(readwrite, argmem: none) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+altnzcv,+ccdp,+ccidx,+complxnum,+crc,+dit,+dotprod,+flagm,+fp-armv8,+fp16fml,+fptoint,+fullfp16,+jsconv,+lse,+neon,+pauth,+perfmon,+predres,+ras,+rcpc,+rdm,+sb,+sha2,+sha3,+specrestrict,+ssbs,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8a,+zcm,+zcz" }
+attributes #1 = { minsize mustprogress noinline nounwind optsize ssp "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+altnzcv,+ccdp,+ccidx,+complxnum,+crc,+dit,+dotprod,+flagm,+fp-armv8,+fp16fml,+fptoint,+fullfp16,+jsconv,+lse,+neon,+pauth,+perfmon,+predres,+ras,+rcpc,+rdm,+sb,+sha2,+sha3,+specrestrict,+ssbs,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8a,+zcm,+zcz" }
+attributes #2 = { minsize mustprogress norecurse nounwind optsize ssp "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+altnzcv,+ccdp,+ccidx,+complxnum,+crc,+dit,+dotprod,+flagm,+fp-armv8,+fp16fml,+fptoint,+fullfp16,+jsconv,+lse,+neon,+pauth,+perfmon,+predres,+ras,+rcpc,+rdm,+sb,+sha2,+sha3,+specrestrict,+ssbs,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8a,+zcm,+zcz" }
+attributes #3 = { minsize optsize }
+attributes #4 = { minsize nounwind optsize }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!15, !16, !17, !18, !19}
+!llvm.ident = !{!20}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "g_volatile_var", scope: !2, file: !3, line: 4, type: !14, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 20.0.0git (https://github.com/alx32/llvm-project.git f41f6ea1f33c4f5e7c94f3d155e44292d1809c50)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None, sysroot: "/")
+!3 = !DIFile(filename: "call_sites.cpp", directory: "/tmp/tst")
+!4 = !{!0, !5, !12}
+!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression())
+!6 = distinct !DIGlobalVariable(name: "g_func_ptr", scope: !2, file: !3, line: 5, type: !7, isLocal: false, isDefinition: true)
+!7 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !8)
+!8 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !9, size: 64)
+!9 = !DISubroutineType(types: !10)
+!10 = !{!11}
+!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!12 = !DIGlobalVariableExpression(var: !13, expr: !DIExpression())
+!13 = distinct !DIGlobalVariable(name: "g_extern_func_ptr", scope: !2, file: !3, line: 6, type: !7, isLocal: false, isDefinition: true)
+!14 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !11)
+!15 = !{i32 7, !"Dwarf Version", i32 4}
+!16 = !{i32 2, !"Debug Info Version", i32 3}
+!17 = !{i32 1, !"wchar_size", i32 4}
+!18 = !{i32 8, !"PIC Level", i32 2}
+!19 = !{i32 7, !"frame-pointer", i32 1}
+!20 = !{!"clang version 20.0.0git (https://github.com/alx32/llvm-project.git f41f6ea1f33c4f5e7c94f3d155e44292d1809c50)"}
+!21 = distinct !DISubprogram(name: "func_mainBin_dec_01", scope: !3, file: !3, line: 8, type: !22, scopeLine: 8, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2)
+!22 = !DISubroutineType(types: !23)
+!23 = !{null}
+!24 = !DILocation(line: 8, column: 54, scope: !21)
+!25 = !{!26, !26, i64 0}
+!26 = !{!"int", !27, i64 0}
+!27 = !{!"omnipotent char", !28, i64 0}
+!28 = !{!"Simple C++ TBAA"}
+!29 = !DILocation(line: 8, column: 58, scope: !21)
+!30 = distinct !DISubprogram(name: "func_mainBin_dec_02", scope: !3, file: !3, line: 9, type: !22, scopeLine: 9, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2)
+!31 = !DILocation(line: 9, column: 54, scope: !30)
+!32 = !DILocation(line: 9, column: 58, scope: !30)
+!33 = distinct !DISubprogram(name: "func_mainBin_dec_03", scope: !3, file: !3, line: 10, type: !22, scopeLine: 10, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2)
+!34 = !DILocation(line: 10, column: 54, scope: !33)
+!35 = !DILocation(line: 10, column: 58, scope: !33)
+!36 = distinct !DISubprogram(name: "func_mainBin_inc_01", scope: !3, file: !3, line: 12, type: !22, scopeLine: 12, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2)
+!37 = !DILocation(line: 12, column: 54, scope: !36)
+!38 = !DILocation(line: 12, column: 58, scope: !36)
+!39 = distinct !DISubprogram(name: "func_mainBin_inc_02", scope: !3, file: !3, line: 13, type: !22, scopeLine: 13, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2)
+!40 = !DILocation(line: 13, column: 54, scope: !39)
+!41 = !DILocation(line: 13, column: 58, scope: !39)
+!42 = distinct !DISubprogram(name: "func_mainBin_inc_03", scope: !3, file: !3, line: 14, type: !22, scopeLine: 14, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2)
+!43 = !DILocation(line: 14, column: 54, scope: !42)
+!44 = !DILocation(line: 14, column: 58, scope: !42)
+!45 = distinct !DISubprogram(name: "func_mainBin_dec_call_everything", scope: !3, file: !3, line: 16, type: !22, scopeLine: 16, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2)
+!46 = !DILocation(line: 17, column: 5, scope: !45)
+!47 = !DILocation(line: 18, column: 5, scope: !45)
+!48 = !DILocation(line: 19, column: 5, scope: !45)
+!49 = !DILocation(line: 21, column: 5, scope: !45)
+!50 = !DILocation(line: 22, column: 5, scope: !45)
+!51 = !DILocation(line: 23, column: 5, scope: !45)
+!52 = !DILocation(line: 25, column: 5, scope: !45)
+!53 = !{!54, !54, i64 0}
+!54 = !{!"any pointer", !27, i64 0}
+!55 = !DILocation(line: 26, column: 5, scope: !45)
+!56 = !DILocation(line: 28, column: 20, scope: !45)
+!57 = !DILocation(line: 29, column: 1, scope: !45)
+!58 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 31, type: !9, scopeLine: 31, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2)
+!59 = !DILocation(line: 32, column: 3, scope: !58)
+!60 = !DILocation(line: 33, column: 3, scope: !58)
+
+
+//--- generate-callsite-test-data.sh
+#!/bin/bash
+## This is provided for reference only, if we need to modify the file and regenerate the assembly code
+set -ex
+
+TOOLCHAIN_DIR="llvm-project/build/Debug/bin"
+
+# Create call_sites.cpp
+cat > call_sites.cpp <<EOF
+
+#define FUNC_ATTR extern "C" __attribute__((noinline))
+
+volatile int g_volatile_var;
+int (*volatile g_func_ptr)();
+int (*volatile g_extern_func_ptr)();
+
+FUNC_ATTR void func_mainBin_dec_01() { g_volatile_var--; }
+FUNC_ATTR void func_mainBin_dec_02() { g_volatile_var--; }
+FUNC_ATTR void func_mainBin_dec_03() { g_volatile_var--; }
+
+FUNC_ATTR void func_mainBin_inc_01() { g_volatile_var++; }
+FUNC_ATTR void func_mainBin_inc_02() { g_volatile_var++; }
+FUNC_ATTR void func_mainBin_inc_03() { g_volatile_var++; }
+
+FUNC_ATTR void func_mainBin_dec_call_everything() {
+    func_mainBin_dec_01();
+    func_mainBin_dec_02();
+    func_mainBin_dec_03();
+
+    func_mainBin_inc_01();
+    func_mainBin_inc_02();
+    func_mainBin_inc_03();
+
+    g_func_ptr();
+    g_extern_func_ptr();
+
+    g_volatile_var = 0;
+}
+
+int main() {
+  func_mainBin_dec_call_everything();
+  return 0;
+}
+EOF
+
+# Generate IR from call_sites.cpp
+"$TOOLCHAIN_DIR"/clang++ -mno-outline -target arm64-apple-macos -g -Oz -fno-exceptions -S -emit-llvm call_sites.cpp -o call_sites.ll
+
+# Compile the assembly into an object file
+"$TOOLCHAIN_DIR"/llc -filetype=obj call_sites.ll -o call_sites.o
+
+# Link the object file into an executable using lld directly
+"$TOOLCHAIN_DIR"/ld64.lld -arch arm64 -platform_version macos 11.0.0 11.0.0 -o call_sites call_sites.o -lSystem
+
+# Create a dSYM file
+"$TOOLCHAIN_DIR"/dsymutil call_sites -o call_sites.dSYM
+
+# Dump the binary to YAML
+"$TOOLCHAIN_DIR"/obj2yaml call_sites > call_sites_binary.yaml
+
+# Dump the dSYM to YAML
+"$TOOLCHAIN_DIR"/obj2yaml call_sites.dSYM/Contents/Resources/DWARF/call_sites > call_sites_dsym.yaml
diff --git a/llvm/tools/llvm-gsymutil/Opts.td b/llvm/tools/llvm-gsymutil/Opts.td
index e3001f3fe53f1d..8dcce1f7388750 100644
--- a/llvm/tools/llvm-gsymutil/Opts.td
+++ b/llvm/tools/llvm-gsymutil/Opts.td
@@ -18,6 +18,8 @@ defm convert :
      "Convert the specified file to the GSYM format.\nSupported files include ELF and mach-o files that will have their debug info (DWARF) and symbol table converted">;
 def merged_functions :
   FF<"merged-functions", "Encode merged function information for functions in debug info that have matching address ranges.\nWithout this option one function per unique address range will be emitted.">;
+defm callsites_from_yaml :
+  Eq<"callsites-from-yaml", "Load call site info from YAML file.">;
 defm arch :
   Eq<"arch",
      "Process debug information for the specified CPU architecture only.\nArchitectures may be specified by name or by number.\nThis option can be specified multiple times, once for each desired architecture">;
diff --git a/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp b/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
index 10bbdf215736d8..59350157463252 100644
--- a/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
+++ b/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
@@ -9,6 +9,7 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/DebugInfo/DIContext.h"
 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/GSYM/CallSiteInfo.h"
 #include "llvm/Object/Archive.h"
 #include "llvm/Object/ELFObjectFile.h"
 #include "llvm/Object/MachOUniversal.h"
@@ -96,6 +97,7 @@ static bool Quiet;
 static std::vector<uint64_t> LookupAddresses;
 static bool LookupAddressesFromStdin;
 static bool StoreMergedFunctionInfo = false;
+static std::vector<std::string> CallSiteYamlPaths;
 
 static void parseArgs(int argc, char **argv) {
   GSYMUtilOptTable Tbl;
@@ -177,6 +179,16 @@ static void parseArgs(int argc, char **argv) {
 
   LookupAddressesFromStdin = Args.hasArg(OPT_addresses_from_stdin);
   StoreMergedFunctionInfo = Args.hasArg(OPT_merged_functions);
+
+  for (const llvm::opt::Arg *A : Args.filtered(OPT_callsites_from_yaml_EQ))
+    if (A->getValue() && A->getValue()[0] != '\0')
+      CallSiteYamlPaths.emplace_back(A->getValue());
+    else {
+      llvm::errs()
+          << ToolName
+          << ": --callsites-from-yaml option requires a non-empty argument.\n";
+      std::exit(1);
+    }
 }
 
 /// @}
@@ -370,6 +382,13 @@ static llvm::Error handleObjectFile(ObjectFile &Obj, const std::string &OutFile,
   if (auto Err = ObjectFileTransformer::convert(Obj, Out, Gsym))
     return Err;
 
+  // If any call site YAML files were specified, load them now.
+  for (const auto &yamlPath : CallSiteYamlPaths) {
+    if (auto Err = Gsym.loadCallSitesFromYAML(yamlPath)) {
+      return Err;
+    }
+  }
+
   // Finalize the GSYM to make it ready to save to disk. This will remove
   // duplicate FunctionInfo entries where we might have found an entry from
   // debug info and also a symbol table entry from the object file.
diff --git a/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp b/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp
index c6218e5004d178..33f53de2e77bcd 100644
--- a/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp
+++ b/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp
@@ -214,10 +214,10 @@ TEST(GSYMTest, TestFunctionInfoDecodeErrors) {
   FW.writeU32(1); // InfoType::LineTableInfo.
   TestFunctionInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
       "0x0000000c: missing FunctionInfo InfoType length");
-  FW.fixup32(4, FixupOffset); // Write an invalid InfoType enumeration value
+  FW.fixup32(7, FixupOffset); // Write an invalid InfoType enumeration value
   FW.writeU32(0); // LineTableInfo InfoType data length.
   TestFunctionInfoDecodeError(ByteOrder, OutStrm.str(), BaseAddr,
-      "0x00000008: unsupported InfoType 4");
+                              "0x00000008: unsupported InfoType 7");
 }
 
 static void TestFunctionInfoEncodeError(llvm::endianness ByteOrder,

>From fe23779dd6ecb7acd835577d68824001a2dcc608 Mon Sep 17 00:00:00 2001
From: Alex B <alexborcan at meta.com>
Date: Thu, 26 Sep 2024 16:10:23 -0700
Subject: [PATCH 2/7] Address Feedback nr.1

---
 .../llvm/DebugInfo/GSYM/CallSiteInfo.h        | 46 ++--------------
 llvm/lib/DebugInfo/GSYM/CallSiteInfo.cpp      | 54 +++++++------------
 llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp    |  3 +-
 3 files changed, 25 insertions(+), 78 deletions(-)

diff --git a/llvm/include/llvm/DebugInfo/GSYM/CallSiteInfo.h b/llvm/include/llvm/DebugInfo/GSYM/CallSiteInfo.h
index 45257f0e11578e..c4e97a599e9889 100644
--- a/llvm/include/llvm/DebugInfo/GSYM/CallSiteInfo.h
+++ b/llvm/include/llvm/DebugInfo/GSYM/CallSiteInfo.h
@@ -34,7 +34,6 @@ namespace gsym {
 class FileWriter;
 struct FunctionInfo;
 struct CallSiteInfo {
-public:
   enum Flags : uint8_t {
     None = 0,
     // This flag specifies that the call site can only call a function within
@@ -52,7 +51,7 @@ struct CallSiteInfo {
   std::vector<uint32_t> MatchRegex;
 
   /// Bitwise OR of CallSiteInfo::Flags values
-  uint8_t Flags;
+  uint8_t Flags = CallSiteInfo::Flags::None;
 
   /// Decode a CallSiteInfo object from a binary data stream.
   ///
@@ -73,16 +72,8 @@ struct CallSiteInfo {
 };
 
 struct CallSiteInfoCollection {
-public:
   std::vector<CallSiteInfo> CallSites;
 
-  void clear() { CallSites.clear(); }
-
-  /// Query if a CallSiteInfoCollection object is valid.
-  ///
-  /// \returns True if the collection is not empty.
-  bool isValid() const { return !CallSites.empty(); }
-
   /// Decode a CallSiteInfoCollection object from a binary data stream.
   ///
   /// \param Data The binary stream to read the data from.
@@ -156,54 +147,27 @@ class CallSiteInfoLoader {
   /// \returns A 32-bit unsigned integer representing the offset of the string.
   uint32_t offsetFromString(StringRef str);
 
-  /// Reads the content of the YAML file specified by `YAMLFile` into
-  /// `yamlContent`.
-  ///
-  /// \param YAMLFile A StringRef representing the path to the YAML file.
-  /// \param Buffer The memory buffer containing the YAML content.
-  ///
-  /// \returns An `llvm::Error` indicating success or describing any issues
-  /// encountered while reading the file.
-  llvm::Error readYAMLFile(StringRef YAMLFile,
-                           std::unique_ptr<llvm::MemoryBuffer> &Buffer);
-
-  /// Parses the YAML content and populates `functionsYAML` with the parsed
-  /// data.
-  ///
-  /// \param Buffer The memory buffer containing the YAML content.
-  /// \param functionsYAML A reference to an llvm::yaml::FunctionsYAML object to
-  /// be populated.
-  ///
-  /// \returns An `llvm::Error` indicating success or describing any issues
-  /// encountered during parsing.
-  llvm::Error parseYAML(llvm::MemoryBuffer &Buffer,
-                        llvm::yaml::FunctionsYAML &functionsYAML);
-
   /// Builds a map from function names to FunctionInfo pointers based on the
   /// provided `Funcs` vector.
   ///
   /// \param Funcs A reference to a vector of FunctionInfo objects.
   ///
-  /// \returns An unordered_map mapping function names (std::string) to their
+  /// \returns A StringMap mapping function names (StringRef) to their
   /// corresponding FunctionInfo pointers.
-  std::unordered_map<std::string, FunctionInfo *>
-  buildFunctionMap(std::vector<FunctionInfo> &Funcs);
+  StringMap<FunctionInfo *> buildFunctionMap(std::vector<FunctionInfo> &Funcs);
 
   /// Processes the parsed YAML functions and updates the `FuncMap` accordingly.
   ///
   /// \param functionsYAML A constant reference to an llvm::yaml::FunctionsYAML
   /// object containing parsed YAML data.
-  /// \param FuncMap A reference to an unordered_map mapping function names to
+  /// \param FuncMap A reference to a StringMap mapping function names to
   /// FunctionInfo pointers.
-  /// \param YAMLFile A StringRef representing the name of the YAML file (used
-  /// for error messages).
   ///
   /// \returns An `llvm::Error` indicating success or describing any issues
   /// encountered during processing.
   llvm::Error
   processYAMLFunctions(const llvm::yaml::FunctionsYAML &functionsYAML,
-                       std::unordered_map<std::string, FunctionInfo *> &FuncMap,
-                       StringRef YAMLFile);
+                       StringMap<FunctionInfo *> &FuncMap);
 
   /// Map of existing string offsets to CachedHashStringRef.
   DenseMap<uint64_t, CachedHashStringRef> &StringOffsetMap;
diff --git a/llvm/lib/DebugInfo/GSYM/CallSiteInfo.cpp b/llvm/lib/DebugInfo/GSYM/CallSiteInfo.cpp
index 4ed3d3f67a44fd..3fe7fb48cb0de3 100644
--- a/llvm/lib/DebugInfo/GSYM/CallSiteInfo.cpp
+++ b/llvm/lib/DebugInfo/GSYM/CallSiteInfo.cpp
@@ -162,49 +162,32 @@ uint32_t CallSiteInfoLoader::offsetFromString(StringRef str) {
 
 llvm::Error CallSiteInfoLoader::loadYAML(std::vector<FunctionInfo> &Funcs,
                                          StringRef YAMLFile) {
-  std::unique_ptr<llvm::MemoryBuffer> Buffer;
   // Step 1: Read YAML file
-  if (auto Err = readYAMLFile(YAMLFile, Buffer))
-    return Err;
-
-  // Step 2: Parse YAML content
-  llvm::yaml::FunctionsYAML functionsYAML;
-  if (auto Err = parseYAML(*Buffer, functionsYAML))
-    return Err;
-
-  // Step 3: Build function map from Funcs
-  auto FuncMap = buildFunctionMap(Funcs);
-
-  // Step 4: Process parsed YAML functions and update FuncMap
-  return processYAMLFunctions(functionsYAML, FuncMap, YAMLFile);
-}
-
-llvm::Error
-CallSiteInfoLoader::readYAMLFile(StringRef YAMLFile,
-                                 std::unique_ptr<llvm::MemoryBuffer> &Buffer) {
   auto BufferOrError = llvm::MemoryBuffer::getFile(YAMLFile);
   if (!BufferOrError)
     return errorCodeToError(BufferOrError.getError());
-  Buffer = std::move(*BufferOrError);
-  return llvm::Error::success();
-}
 
-llvm::Error
-CallSiteInfoLoader::parseYAML(llvm::MemoryBuffer &Buffer,
-                              llvm::yaml::FunctionsYAML &functionsYAML) {
-  // Use the MemoryBufferRef constructor
-  llvm::yaml::Input yin(Buffer.getMemBufferRef());
+  std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(*BufferOrError);
+
+  // Step 2: Parse YAML content
+  llvm::yaml::FunctionsYAML functionsYAML;
+  llvm::yaml::Input yin(Buffer->getMemBufferRef());
   yin >> functionsYAML;
   if (yin.error()) {
     return llvm::createStringError(yin.error(), "Error parsing YAML file: %s\n",
-                                   Buffer.getBufferIdentifier().str().c_str());
+                                   Buffer->getBufferIdentifier().str().c_str());
   }
-  return llvm::Error::success();
+
+  // Step 3: Build function map from Funcs
+  auto FuncMap = buildFunctionMap(Funcs);
+
+  // Step 4: Process parsed YAML functions and update FuncMap
+  return processYAMLFunctions(functionsYAML, FuncMap);
 }
 
-std::unordered_map<std::string, FunctionInfo *>
+StringMap<FunctionInfo *>
 CallSiteInfoLoader::buildFunctionMap(std::vector<FunctionInfo> &Funcs) {
-  std::unordered_map<std::string, FunctionInfo *> FuncMap;
+  StringMap<FunctionInfo *> FuncMap;
   auto insertFunc = [&](auto &Function) {
     std::string FuncName = stringFromOffset(Function.Name).str();
     // If the function name is already in the map, don't update it. This way we
@@ -227,8 +210,7 @@ CallSiteInfoLoader::buildFunctionMap(std::vector<FunctionInfo> &Funcs) {
 
 llvm::Error CallSiteInfoLoader::processYAMLFunctions(
     const llvm::yaml::FunctionsYAML &functionsYAML,
-    std::unordered_map<std::string, FunctionInfo *> &FuncMap,
-    StringRef YAMLFile) {
+    StringMap<FunctionInfo *> &FuncMap) {
   // For each function in the YAML file
   for (const auto &FuncYAML : functionsYAML.functions) {
     auto it = FuncMap.find(FuncYAML.name);
@@ -247,9 +229,9 @@ llvm::Error CallSiteInfoLoader::processYAMLFunctions(
       // Since YAML has specifies relative return offsets, add the function
       // start address to make the offset absolute.
       CSI.ReturnAddress = FuncInfo->Range.start() + CallSiteYAML.return_offset;
-      for (const auto &regex : CallSiteYAML.match_regex) {
-        CSI.MatchRegex.push_back(offsetFromString(regex));
-      }
+      for (const auto &Regex : CallSiteYAML.match_regex)
+        CSI.MatchRegex.push_back(offsetFromString(Regex));
+
       // Initialize flags to None
       CSI.Flags = CallSiteInfo::None;
       // Parse flags and combine them
diff --git a/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp b/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
index 59350157463252..bb107c17f6f96c 100644
--- a/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
+++ b/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
@@ -180,7 +180,7 @@ static void parseArgs(int argc, char **argv) {
   LookupAddressesFromStdin = Args.hasArg(OPT_addresses_from_stdin);
   StoreMergedFunctionInfo = Args.hasArg(OPT_merged_functions);
 
-  for (const llvm::opt::Arg *A : Args.filtered(OPT_callsites_from_yaml_EQ))
+  if (const llvm::opt::Arg *A = Args.getLastArg(OPT_callsites_from_yaml_EQ)) {
     if (A->getValue() && A->getValue()[0] != '\0')
       CallSiteYamlPaths.emplace_back(A->getValue());
     else {
@@ -189,6 +189,7 @@ static void parseArgs(int argc, char **argv) {
           << ": --callsites-from-yaml option requires a non-empty argument.\n";
       std::exit(1);
     }
+  }
 }
 
 /// @}

>From cd7c30ab8cac2b2be6446c74c4542dd8321d7439 Mon Sep 17 00:00:00 2001
From: Alex B <alexborcan at meta.com>
Date: Fri, 27 Sep 2024 14:00:36 -0700
Subject: [PATCH 3/7] Address feedback nr.2

---
 .../llvm/DebugInfo/GSYM/CallSiteInfo.h        | 72 +++------------
 .../include/llvm/DebugInfo/GSYM/GsymCreator.h |  9 ++
 llvm/lib/DebugInfo/GSYM/CallSiteInfo.cpp      | 92 ++++++++-----------
 llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp      |  2 +-
 llvm/lib/DebugInfo/GSYM/GsymCreator.cpp       |  8 +-
 llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp    | 15 ++-
 6 files changed, 76 insertions(+), 122 deletions(-)

diff --git a/llvm/include/llvm/DebugInfo/GSYM/CallSiteInfo.h b/llvm/include/llvm/DebugInfo/GSYM/CallSiteInfo.h
index c4e97a599e9889..496679fdf9bc8f 100644
--- a/llvm/include/llvm/DebugInfo/GSYM/CallSiteInfo.h
+++ b/llvm/include/llvm/DebugInfo/GSYM/CallSiteInfo.h
@@ -32,6 +32,7 @@ struct FunctionsYAML;
 
 namespace gsym {
 class FileWriter;
+class GsymCreator;
 struct FunctionInfo;
 struct CallSiteInfo {
   enum Flags : uint8_t {
@@ -45,7 +46,7 @@ struct CallSiteInfo {
   };
 
   /// The return address of the call site.
-  uint64_t ReturnAddress;
+  uint64_t ReturnAddress = 0;
 
   /// Offsets into the string table for function names regex patterns.
   std::vector<uint32_t> MatchRegex;
@@ -57,12 +58,9 @@ struct CallSiteInfo {
   ///
   /// \param Data The binary stream to read the data from.
   /// \param Offset The current offset within the data stream.
-  /// \param BaseAddr The base address for decoding (unused here but included
-  /// for consistency).
-  ///
   /// \returns A CallSiteInfo or an error describing the issue.
-  static llvm::Expected<CallSiteInfo>
-  decode(DataExtractor &Data, uint64_t &Offset, uint64_t BaseAddr);
+  static llvm::Expected<CallSiteInfo> decode(DataExtractor &Data,
+                                             uint64_t &Offset);
 
   /// Encode this CallSiteInfo object into a FileWriter stream.
   ///
@@ -77,12 +75,8 @@ struct CallSiteInfoCollection {
   /// Decode a CallSiteInfoCollection object from a binary data stream.
   ///
   /// \param Data The binary stream to read the data from.
-  /// \param BaseAddr The base address for decoding (unused here but included
-  /// for consistency).
-  ///
   /// \returns A CallSiteInfoCollection or an error describing the issue.
-  static llvm::Expected<CallSiteInfoCollection> decode(DataExtractor &Data,
-                                                       uint64_t BaseAddr);
+  static llvm::Expected<CallSiteInfoCollection> decode(DataExtractor &Data);
 
   /// Encode this CallSiteInfoCollection object into a FileWriter stream.
   ///
@@ -91,29 +85,18 @@ struct CallSiteInfoCollection {
   llvm::Error encode(FileWriter &O) const;
 };
 
-bool operator==(const CallSiteInfoCollection &LHS,
-                const CallSiteInfoCollection &RHS);
-
-bool operator==(const CallSiteInfo &LHS, const CallSiteInfo &RHS);
-
 class CallSiteInfoLoader {
 public:
   /// Constructor that initializes the CallSiteInfoLoader with necessary data
   /// structures.
   ///
   /// \param StringOffsetMap A reference to a DenseMap that maps existing string
-  /// offsets to CachedHashStringRef. \param StrTab A reference to a
-  /// StringTableBuilder used for managing looking up and creating new strings.
-  /// \param StringStorage A reference to a StringSet for storing the data for
-  /// generated strings.
-  CallSiteInfoLoader(DenseMap<uint64_t, CachedHashStringRef> &StringOffsetMap,
-                     StringTableBuilder &StrTab, StringSet<> &StringStorage)
-      : StringOffsetMap(StringOffsetMap), StrTab(StrTab),
-        StringStorage(StringStorage) {}
-
-  /// Loads call site information from a YAML file and populates the provided
-  /// FunctionInfo vector.
-  ///
+  /// offsets to CachedHashStringRef.
+  /// \param StrTab A reference to a StringTableBuilder used for managing
+  /// looking up and creating new strings. \param StringStorage A reference to a
+  /// StringSet for storing the data for generated strings.
+  CallSiteInfoLoader(GsymCreator &GCreator) : GCreator(GCreator) {}
+
   /// This method reads the specified YAML file, parses its content, and updates
   /// the `Funcs` vector with call site information based on the YAML data.
   ///
@@ -121,37 +104,15 @@ class CallSiteInfoLoader {
   /// populated.
   /// \param YAMLFile A StringRef representing the path to the YAML
   /// file to be loaded.
-  ///
   /// \returns An `llvm::Error` indicating success or describing any issues
   /// encountered during the loading process.
   llvm::Error loadYAML(std::vector<FunctionInfo> &Funcs, StringRef YAMLFile);
 
 private:
-  /// Retrieves an existing string from the StringOffsetMap using the provided
-  /// offset.
-  ///
-  /// \param offset A 32-bit unsigned integer representing the offset of the
-  /// string.
-  ///
-  /// \returns A StringRef corresponding to the string for the given offset.
-  ///
-  /// \note This method asserts that the offset exists in the StringOffsetMap.
-  StringRef stringFromOffset(uint32_t offset) const;
-
-  /// Obtains the offset corresponding to a given string in the StrTab. If the
-  /// string does not already exist, it is created.
-  ///
-  /// \param str A StringRef representing the string for which the offset is
-  /// requested.
-  ///
-  /// \returns A 32-bit unsigned integer representing the offset of the string.
-  uint32_t offsetFromString(StringRef str);
-
   /// Builds a map from function names to FunctionInfo pointers based on the
   /// provided `Funcs` vector.
   ///
   /// \param Funcs A reference to a vector of FunctionInfo objects.
-  ///
   /// \returns A StringMap mapping function names (StringRef) to their
   /// corresponding FunctionInfo pointers.
   StringMap<FunctionInfo *> buildFunctionMap(std::vector<FunctionInfo> &Funcs);
@@ -162,21 +123,14 @@ class CallSiteInfoLoader {
   /// object containing parsed YAML data.
   /// \param FuncMap A reference to a StringMap mapping function names to
   /// FunctionInfo pointers.
-  ///
   /// \returns An `llvm::Error` indicating success or describing any issues
   /// encountered during processing.
   llvm::Error
   processYAMLFunctions(const llvm::yaml::FunctionsYAML &functionsYAML,
                        StringMap<FunctionInfo *> &FuncMap);
 
-  /// Map of existing string offsets to CachedHashStringRef.
-  DenseMap<uint64_t, CachedHashStringRef> &StringOffsetMap;
-
-  /// The gSYM string table builder.
-  StringTableBuilder &StrTab;
-
-  /// The gSYM string storage - we store generated strings here.
-  StringSet<> &StringStorage;
+  /// Reference to the parent Gsym Creator object.
+  GsymCreator &GCreator;
 };
 
 raw_ostream &operator<<(raw_ostream &OS, const CallSiteInfo &CSI);
diff --git a/llvm/include/llvm/DebugInfo/GSYM/GsymCreator.h b/llvm/include/llvm/DebugInfo/GSYM/GsymCreator.h
index 9e5b3c1f8d92de..8e9e500f267c1f 100644
--- a/llvm/include/llvm/DebugInfo/GSYM/GsymCreator.h
+++ b/llvm/include/llvm/DebugInfo/GSYM/GsymCreator.h
@@ -329,6 +329,15 @@ class GsymCreator {
   /// \returns The unique 32 bit offset into the string table.
   uint32_t insertString(StringRef S, bool Copy = true);
 
+  /// Retrieve a string fromt he GSYM string table given its offset.
+  ///
+  /// The offset is assumed to be a valid offset into the string table.
+  /// otherwise an assert will be triggered.
+  ///
+  /// \param offset The offset of the string to retrieve, previously returned by
+  /// insertString. \returns The string at the given offset in the string table.
+  StringRef getString(uint32_t offset);
+
   /// Insert a file into this GSYM creator.
   ///
   /// Inserts a file by adding a FileEntry into the "Files" member variable if
diff --git a/llvm/lib/DebugInfo/GSYM/CallSiteInfo.cpp b/llvm/lib/DebugInfo/GSYM/CallSiteInfo.cpp
index 3fe7fb48cb0de3..5f8f622043bd8b 100644
--- a/llvm/lib/DebugInfo/GSYM/CallSiteInfo.cpp
+++ b/llvm/lib/DebugInfo/GSYM/CallSiteInfo.cpp
@@ -10,6 +10,7 @@
 #include "llvm/ADT/CachedHashString.h"
 #include "llvm/DebugInfo/GSYM/FileWriter.h"
 #include "llvm/DebugInfo/GSYM/FunctionInfo.h"
+#include "llvm/DebugInfo/GSYM/GsymCreator.h"
 #include "llvm/MC/StringTableBuilder.h"
 #include "llvm/Support/DataExtractor.h"
 #include "llvm/Support/YAMLParser.h"
@@ -23,17 +24,17 @@
 using namespace llvm;
 using namespace gsym;
 
-llvm::Error CallSiteInfo::encode(FileWriter &O) const {
+Error CallSiteInfo::encode(FileWriter &O) const {
   O.writeU64(ReturnAddress);
   O.writeU8(Flags);
   O.writeU32(MatchRegex.size());
   for (uint32_t Entry : MatchRegex)
     O.writeU32(Entry);
-  return llvm::Error::success();
+  return Error::success();
 }
 
-llvm::Expected<CallSiteInfo>
-CallSiteInfo::decode(DataExtractor &Data, uint64_t &Offset, uint64_t BaseAddr) {
+Expected<CallSiteInfo> CallSiteInfo::decode(DataExtractor &Data,
+                                            uint64_t &Offset) {
   CallSiteInfo CSI;
 
   // Read ReturnAddress
@@ -68,17 +69,17 @@ CallSiteInfo::decode(DataExtractor &Data, uint64_t &Offset, uint64_t BaseAddr) {
   return CSI;
 }
 
-llvm::Error CallSiteInfoCollection::encode(FileWriter &O) const {
+Error CallSiteInfoCollection::encode(FileWriter &O) const {
   O.writeU32(CallSites.size());
   for (const CallSiteInfo &CSI : CallSites) {
-    if (llvm::Error Err = CSI.encode(O))
+    if (Error Err = CSI.encode(O))
       return Err;
   }
-  return llvm::Error::success();
+  return Error::success();
 }
 
-llvm::Expected<CallSiteInfoCollection>
-CallSiteInfoCollection::decode(DataExtractor &Data, uint64_t BaseAddr) {
+Expected<CallSiteInfoCollection>
+CallSiteInfoCollection::decode(DataExtractor &Data) {
   CallSiteInfoCollection CSC;
   uint64_t Offset = 0;
 
@@ -91,8 +92,7 @@ CallSiteInfoCollection::decode(DataExtractor &Data, uint64_t BaseAddr) {
 
   CSC.CallSites.reserve(NumCallSites);
   for (uint32_t i = 0; i < NumCallSites; ++i) {
-    llvm::Expected<CallSiteInfo> ECSI =
-        CallSiteInfo::decode(Data, Offset, BaseAddr);
+    Expected<CallSiteInfo> ECSI = CallSiteInfo::decode(Data, Offset);
     if (!ECSI)
       return ECSI.takeError();
     CSC.CallSites.emplace_back(*ECSI);
@@ -108,7 +108,7 @@ namespace yaml {
 struct CallSiteYAML {
   // The offset of the return address of the call site - relative to the start
   // of the function.
-  llvm::yaml::Hex64 return_offset;
+  Hex64 return_offset;
   std::vector<std::string> match_regex;
   std::vector<std::string> flags;
 };
@@ -149,34 +149,22 @@ template <> struct MappingTraits<FunctionsYAML> {
 LLVM_YAML_IS_SEQUENCE_VECTOR(CallSiteYAML)
 LLVM_YAML_IS_SEQUENCE_VECTOR(FunctionYAML)
 
-// Implementation of CallSiteInfoLoader
-StringRef CallSiteInfoLoader::stringFromOffset(uint32_t offset) const {
-  assert(StringOffsetMap.count(offset) &&
-         "expected function name offset to already be in StringOffsetMap");
-  return StringOffsetMap.find(offset)->second.val();
-}
-
-uint32_t CallSiteInfoLoader::offsetFromString(StringRef str) {
-  return StrTab.add(StringStorage.insert(str).first->getKey());
-}
-
-llvm::Error CallSiteInfoLoader::loadYAML(std::vector<FunctionInfo> &Funcs,
-                                         StringRef YAMLFile) {
+Error CallSiteInfoLoader::loadYAML(std::vector<FunctionInfo> &Funcs,
+                                   StringRef YAMLFile) {
   // Step 1: Read YAML file
-  auto BufferOrError = llvm::MemoryBuffer::getFile(YAMLFile);
+  auto BufferOrError = MemoryBuffer::getFile(YAMLFile);
   if (!BufferOrError)
     return errorCodeToError(BufferOrError.getError());
 
-  std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(*BufferOrError);
+  std::unique_ptr<MemoryBuffer> Buffer = std::move(*BufferOrError);
 
   // Step 2: Parse YAML content
-  llvm::yaml::FunctionsYAML functionsYAML;
-  llvm::yaml::Input yin(Buffer->getMemBufferRef());
+  yaml::FunctionsYAML functionsYAML;
+  yaml::Input yin(Buffer->getMemBufferRef());
   yin >> functionsYAML;
-  if (yin.error()) {
-    return llvm::createStringError(yin.error(), "Error parsing YAML file: %s\n",
-                                   Buffer->getBufferIdentifier().str().c_str());
-  }
+  if (yin.error())
+    return createStringError(yin.error(), "Error parsing YAML file: %s\n",
+                             Buffer->getBufferIdentifier().str().c_str());
 
   // Step 3: Build function map from Funcs
   auto FuncMap = buildFunctionMap(Funcs);
@@ -189,7 +177,7 @@ StringMap<FunctionInfo *>
 CallSiteInfoLoader::buildFunctionMap(std::vector<FunctionInfo> &Funcs) {
   StringMap<FunctionInfo *> FuncMap;
   auto insertFunc = [&](auto &Function) {
-    std::string FuncName = stringFromOffset(Function.Name).str();
+    StringRef FuncName = GCreator.getString(Function.Name);
     // If the function name is already in the map, don't update it. This way we
     // preferentially use the first encountered function. Since symbols are
     // loaded from dSYM first, we end up preferring keeping track of symbols
@@ -208,19 +196,19 @@ CallSiteInfoLoader::buildFunctionMap(std::vector<FunctionInfo> &Funcs) {
   return FuncMap;
 }
 
-llvm::Error CallSiteInfoLoader::processYAMLFunctions(
-    const llvm::yaml::FunctionsYAML &functionsYAML,
+Error CallSiteInfoLoader::processYAMLFunctions(
+    const yaml::FunctionsYAML &functionsYAML,
     StringMap<FunctionInfo *> &FuncMap) {
   // For each function in the YAML file
   for (const auto &FuncYAML : functionsYAML.functions) {
-    auto it = FuncMap.find(FuncYAML.name);
-    if (it == FuncMap.end()) {
-      return llvm::createStringError(
+    auto It = FuncMap.find(FuncYAML.name);
+    if (It == FuncMap.end())
+      return createStringError(
           std::errc::invalid_argument,
           "Can't find function '%s' specified in callsite YAML\n",
           FuncYAML.name.c_str());
-    }
-    FunctionInfo *FuncInfo = it->second;
+
+    FunctionInfo *FuncInfo = It->second;
     // Create a CallSiteInfoCollection if not already present
     if (!FuncInfo->CallSites)
       FuncInfo->CallSites = CallSiteInfoCollection();
@@ -229,11 +217,11 @@ llvm::Error CallSiteInfoLoader::processYAMLFunctions(
       // Since YAML has specifies relative return offsets, add the function
       // start address to make the offset absolute.
       CSI.ReturnAddress = FuncInfo->Range.start() + CallSiteYAML.return_offset;
-      for (const auto &Regex : CallSiteYAML.match_regex)
-        CSI.MatchRegex.push_back(offsetFromString(Regex));
+      for (const auto &Regex : CallSiteYAML.match_regex) {
+        uint32_t StrOffset = GCreator.insertString(Regex);
+        CSI.MatchRegex.push_back(StrOffset);
+      }
 
-      // Initialize flags to None
-      CSI.Flags = CallSiteInfo::None;
       // Parse flags and combine them
       for (const auto &FlagStr : CallSiteYAML.flags) {
         if (FlagStr == "InternalCall") {
@@ -241,18 +229,18 @@ llvm::Error CallSiteInfoLoader::processYAMLFunctions(
         } else if (FlagStr == "ExternalCall") {
           CSI.Flags |= static_cast<uint8_t>(CallSiteInfo::ExternalCall);
         } else {
-          return llvm::createStringError(std::errc::invalid_argument,
-                                         "Unknown flag in callsite YAML: %s\n",
-                                         FlagStr.c_str());
+          return createStringError(std::errc::invalid_argument,
+                                   "Unknown flag in callsite YAML: %s\n",
+                                   FlagStr.c_str());
         }
       }
       FuncInfo->CallSites->CallSites.push_back(CSI);
     }
   }
-  return llvm::Error::success();
+  return Error::success();
 }
 
-raw_ostream &llvm::gsym::operator<<(raw_ostream &OS, const CallSiteInfo &CSI) {
+raw_ostream &gsym::operator<<(raw_ostream &OS, const CallSiteInfo &CSI) {
   OS << "  Return=" << HEX64(CSI.ReturnAddress);
   OS << "  Flags=" << HEX8(CSI.Flags);
 
@@ -265,8 +253,8 @@ raw_ostream &llvm::gsym::operator<<(raw_ostream &OS, const CallSiteInfo &CSI) {
   return OS;
 }
 
-raw_ostream &llvm::gsym::operator<<(raw_ostream &OS,
-                                    const CallSiteInfoCollection &CSIC) {
+raw_ostream &gsym::operator<<(raw_ostream &OS,
+                              const CallSiteInfoCollection &CSIC) {
   for (const auto &CS : CSIC.CallSites) {
     OS << CS;
     OS << "\n";
diff --git a/llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp b/llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp
index 9dc9c241168b26..facad95f8fdebc 100644
--- a/llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp
+++ b/llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp
@@ -100,7 +100,7 @@ llvm::Expected<FunctionInfo> FunctionInfo::decode(DataExtractor &Data,
 
       case InfoType::CallSiteInfo:
         if (Expected<llvm::gsym::CallSiteInfoCollection> CI =
-                llvm::gsym::CallSiteInfoCollection::decode(InfoData, BaseAddr))
+                llvm::gsym::CallSiteInfoCollection::decode(InfoData))
           FI.CallSites = std::move(CI.get());
         else
           return CI.takeError();
diff --git a/llvm/lib/DebugInfo/GSYM/GsymCreator.cpp b/llvm/lib/DebugInfo/GSYM/GsymCreator.cpp
index 0df84ee256aef9..3cabb27053a5c5 100644
--- a/llvm/lib/DebugInfo/GSYM/GsymCreator.cpp
+++ b/llvm/lib/DebugInfo/GSYM/GsymCreator.cpp
@@ -191,7 +191,7 @@ llvm::Error GsymCreator::encode(FileWriter &O) const {
 
 llvm::Error GsymCreator::loadCallSitesFromYAML(StringRef YAMLFile) {
   // Use the loader to load call site information from the YAML file.
-  CallSiteInfoLoader Loader(StringOffsetMap, StrTab, StringStorage);
+  CallSiteInfoLoader Loader(*this);
   return Loader.loadYAML(Funcs, YAMLFile);
 }
 
@@ -385,6 +385,12 @@ uint32_t GsymCreator::insertString(StringRef S, bool Copy) {
   return StrOff;
 }
 
+StringRef GsymCreator::getString(uint32_t offset) {
+  assert(StringOffsetMap.count(offset) &&
+         "GsymCreator::getString expects a valid offset as parameter.");
+  return StringOffsetMap.find(offset)->second.val();
+}
+
 void GsymCreator::addFunctionInfo(FunctionInfo &&FI) {
   std::lock_guard<std::mutex> Guard(Mutex);
   Funcs.emplace_back(std::move(FI));
diff --git a/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp b/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
index bb107c17f6f96c..6c7506e51e649e 100644
--- a/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
+++ b/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
@@ -97,7 +97,7 @@ static bool Quiet;
 static std::vector<uint64_t> LookupAddresses;
 static bool LookupAddressesFromStdin;
 static bool StoreMergedFunctionInfo = false;
-static std::vector<std::string> CallSiteYamlPaths;
+static std::string CallSiteYamlPath;
 
 static void parseArgs(int argc, char **argv) {
   GSYMUtilOptTable Tbl;
@@ -180,10 +180,9 @@ static void parseArgs(int argc, char **argv) {
   LookupAddressesFromStdin = Args.hasArg(OPT_addresses_from_stdin);
   StoreMergedFunctionInfo = Args.hasArg(OPT_merged_functions);
 
-  if (const llvm::opt::Arg *A = Args.getLastArg(OPT_callsites_from_yaml_EQ)) {
-    if (A->getValue() && A->getValue()[0] != '\0')
-      CallSiteYamlPaths.emplace_back(A->getValue());
-    else {
+  if (Args.hasArg(OPT_callsites_from_yaml_EQ)) {
+    CallSiteYamlPath = Args.getLastArgValue(OPT_callsites_from_yaml_EQ);
+    if (CallSiteYamlPath.empty()) {
       llvm::errs()
           << ToolName
           << ": --callsites-from-yaml option requires a non-empty argument.\n";
@@ -384,11 +383,9 @@ static llvm::Error handleObjectFile(ObjectFile &Obj, const std::string &OutFile,
     return Err;
 
   // If any call site YAML files were specified, load them now.
-  for (const auto &yamlPath : CallSiteYamlPaths) {
-    if (auto Err = Gsym.loadCallSitesFromYAML(yamlPath)) {
+  if (!CallSiteYamlPath.empty())
+    if (auto Err = Gsym.loadCallSitesFromYAML(CallSiteYamlPath))
       return Err;
-    }
-  }
 
   // Finalize the GSYM to make it ready to save to disk. This will remove
   // duplicate FunctionInfo entries where we might have found an entry from

>From 087cdea260ddcaec7b952ff523b5b662b49e18cb Mon Sep 17 00:00:00 2001
From: Alex B <alexborcan at meta.com>
Date: Fri, 27 Sep 2024 14:04:16 -0700
Subject: [PATCH 4/7] Address Feedback Nr 2.1

---
 llvm/lib/DebugInfo/GSYM/GsymReader.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/lib/DebugInfo/GSYM/GsymReader.cpp b/llvm/lib/DebugInfo/GSYM/GsymReader.cpp
index 4f645714480e6d..786633adc51202 100644
--- a/llvm/lib/DebugInfo/GSYM/GsymReader.cpp
+++ b/llvm/lib/DebugInfo/GSYM/GsymReader.cpp
@@ -412,9 +412,8 @@ void GsymReader::dump(raw_ostream &OS, const FunctionInfo &FI,
     dump(OS, *FI.MergedFunctions);
   }
 
-  if (FI.CallSites) {
+  if (FI.CallSites)
     dump(OS, *FI.CallSites);
-  }
 }
 
 void GsymReader::dump(raw_ostream &OS, const MergedFunctionsInfo &MFI) {

>From d7cff1b16cb3edb26208b6cf6d5d2f53f01e34ef Mon Sep 17 00:00:00 2001
From: Alex B <alexborcan at meta.com>
Date: Thu, 17 Oct 2024 12:49:04 -0700
Subject: [PATCH 5/7] Address [Some] Feedback Nr 3 - Rest pending YAML format

---
 .../llvm/DebugInfo/GSYM/CallSiteInfo.h        | 19 +++++--------------
 llvm/lib/DebugInfo/GSYM/CallSiteInfo.cpp      |  6 +++---
 llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp      |  6 +++---
 3 files changed, 11 insertions(+), 20 deletions(-)

diff --git a/llvm/include/llvm/DebugInfo/GSYM/CallSiteInfo.h b/llvm/include/llvm/DebugInfo/GSYM/CallSiteInfo.h
index 496679fdf9bc8f..8043779f31724c 100644
--- a/llvm/include/llvm/DebugInfo/GSYM/CallSiteInfo.h
+++ b/llvm/include/llvm/DebugInfo/GSYM/CallSiteInfo.h
@@ -9,24 +9,17 @@
 #ifndef LLVM_DEBUGINFO_GSYM_CALLSITEINFO_H
 #define LLVM_DEBUGINFO_GSYM_CALLSITEINFO_H
 
-#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/BitmaskEnum.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/StringSet.h"
-#include "llvm/DebugInfo/GSYM/ExtractRanges.h"
-#include "llvm/Support/YAMLParser.h"
-#include <string>
-#include <unordered_map>
+#include "llvm/Support/Error.h"
 #include <vector>
 
 namespace llvm {
 class DataExtractor;
 class raw_ostream;
-class StringTableBuilder;
-class CachedHashStringRef;
 
 namespace yaml {
-struct CallSiteYAML;
-struct FunctionYAML;
 struct FunctionsYAML;
 } // namespace yaml
 
@@ -43,6 +36,8 @@ struct CallSiteInfo {
     // This flag specifies that the call site can only call a function outside
     // the link unit that the call site is in.
     ExternalCall = 1 << 1,
+
+    LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue*/ ExternalCall),
   };
 
   /// The return address of the call site.
@@ -90,11 +85,7 @@ class CallSiteInfoLoader {
   /// Constructor that initializes the CallSiteInfoLoader with necessary data
   /// structures.
   ///
-  /// \param StringOffsetMap A reference to a DenseMap that maps existing string
-  /// offsets to CachedHashStringRef.
-  /// \param StrTab A reference to a StringTableBuilder used for managing
-  /// looking up and creating new strings. \param StringStorage A reference to a
-  /// StringSet for storing the data for generated strings.
+  /// \param GCreator A reference to the GsymCreator.
   CallSiteInfoLoader(GsymCreator &GCreator) : GCreator(GCreator) {}
 
   /// This method reads the specified YAML file, parses its content, and updates
diff --git a/llvm/lib/DebugInfo/GSYM/CallSiteInfo.cpp b/llvm/lib/DebugInfo/GSYM/CallSiteInfo.cpp
index 5f8f622043bd8b..6439aad4814f54 100644
--- a/llvm/lib/DebugInfo/GSYM/CallSiteInfo.cpp
+++ b/llvm/lib/DebugInfo/GSYM/CallSiteInfo.cpp
@@ -159,9 +159,9 @@ Error CallSiteInfoLoader::loadYAML(std::vector<FunctionInfo> &Funcs,
   std::unique_ptr<MemoryBuffer> Buffer = std::move(*BufferOrError);
 
   // Step 2: Parse YAML content
-  yaml::FunctionsYAML functionsYAML;
+  yaml::FunctionsYAML FuncsYAML;
   yaml::Input yin(Buffer->getMemBufferRef());
-  yin >> functionsYAML;
+  yin >> FuncsYAML;
   if (yin.error())
     return createStringError(yin.error(), "Error parsing YAML file: %s\n",
                              Buffer->getBufferIdentifier().str().c_str());
@@ -170,7 +170,7 @@ Error CallSiteInfoLoader::loadYAML(std::vector<FunctionInfo> &Funcs,
   auto FuncMap = buildFunctionMap(Funcs);
 
   // Step 4: Process parsed YAML functions and update FuncMap
-  return processYAMLFunctions(functionsYAML, FuncMap);
+  return processYAMLFunctions(FuncsYAML, FuncMap);
 }
 
 StringMap<FunctionInfo *>
diff --git a/llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp b/llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp
index facad95f8fdebc..dd754c701f6240 100644
--- a/llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp
+++ b/llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp
@@ -218,9 +218,9 @@ llvm::Expected<uint64_t> FunctionInfo::encode(FileWriter &Out,
     // writing the CallSites out with the number of bytes that were written.
     Out.writeU32(0);
     const auto StartOffset = Out.tell();
-    llvm::Error err = CallSites->encode(Out);
-    if (err)
-      return std::move(err);
+    Error Err = CallSites->encode(Out);
+    if (Err)
+      return std::move(Err);
     const auto Length = Out.tell() - StartOffset;
     if (Length > UINT32_MAX)
       return createStringError(std::errc::invalid_argument,

>From cc1d3144e48788b7466a4e7a6869bb984c298568 Mon Sep 17 00:00:00 2001
From: Alex B <alexborcan at meta.com>
Date: Wed, 13 Nov 2024 12:37:04 -0800
Subject: [PATCH 6/7] Switch to relative return offsets

---
 .../llvm/DebugInfo/GSYM/CallSiteInfo.h        | 11 +++--
 llvm/lib/DebugInfo/GSYM/CallSiteInfo.cpp      | 21 +++++-----
 llvm/lib/DebugInfo/GSYM/GsymReader.cpp        |  4 +-
 .../macho-gsym-callsite-info-obj.test         | 42 +++++++++----------
 4 files changed, 38 insertions(+), 40 deletions(-)

diff --git a/llvm/include/llvm/DebugInfo/GSYM/CallSiteInfo.h b/llvm/include/llvm/DebugInfo/GSYM/CallSiteInfo.h
index 8043779f31724c..8a9b3e55531216 100644
--- a/llvm/include/llvm/DebugInfo/GSYM/CallSiteInfo.h
+++ b/llvm/include/llvm/DebugInfo/GSYM/CallSiteInfo.h
@@ -40,8 +40,8 @@ struct CallSiteInfo {
     LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue*/ ExternalCall),
   };
 
-  /// The return address of the call site.
-  uint64_t ReturnAddress = 0;
+  /// The return offset of the call site - relative to the function start.
+  uint64_t ReturnOffset = 0;
 
   /// Offsets into the string table for function names regex patterns.
   std::vector<uint32_t> MatchRegex;
@@ -110,15 +110,14 @@ class CallSiteInfoLoader {
 
   /// Processes the parsed YAML functions and updates the `FuncMap` accordingly.
   ///
-  /// \param functionsYAML A constant reference to an llvm::yaml::FunctionsYAML
+  /// \param FuncYAMLs A constant reference to an llvm::yaml::FunctionsYAML
   /// object containing parsed YAML data.
   /// \param FuncMap A reference to a StringMap mapping function names to
   /// FunctionInfo pointers.
   /// \returns An `llvm::Error` indicating success or describing any issues
   /// encountered during processing.
-  llvm::Error
-  processYAMLFunctions(const llvm::yaml::FunctionsYAML &functionsYAML,
-                       StringMap<FunctionInfo *> &FuncMap);
+  llvm::Error processYAMLFunctions(const llvm::yaml::FunctionsYAML &FuncYAMLs,
+                                   StringMap<FunctionInfo *> &FuncMap);
 
   /// Reference to the parent Gsym Creator object.
   GsymCreator &GCreator;
diff --git a/llvm/lib/DebugInfo/GSYM/CallSiteInfo.cpp b/llvm/lib/DebugInfo/GSYM/CallSiteInfo.cpp
index 6439aad4814f54..af2a374c908bc8 100644
--- a/llvm/lib/DebugInfo/GSYM/CallSiteInfo.cpp
+++ b/llvm/lib/DebugInfo/GSYM/CallSiteInfo.cpp
@@ -25,7 +25,7 @@ using namespace llvm;
 using namespace gsym;
 
 Error CallSiteInfo::encode(FileWriter &O) const {
-  O.writeU64(ReturnAddress);
+  O.writeU64(ReturnOffset);
   O.writeU8(Flags);
   O.writeU32(MatchRegex.size());
   for (uint32_t Entry : MatchRegex)
@@ -37,11 +37,11 @@ Expected<CallSiteInfo> CallSiteInfo::decode(DataExtractor &Data,
                                             uint64_t &Offset) {
   CallSiteInfo CSI;
 
-  // Read ReturnAddress
+  // Read ReturnOffset
   if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(uint64_t)))
     return createStringError(std::errc::io_error,
-                             "0x%8.8" PRIx64 ": missing ReturnAddress", Offset);
-  CSI.ReturnAddress = Data.getU64(&Offset);
+                             "0x%8.8" PRIx64 ": missing ReturnOffset", Offset);
+  CSI.ReturnOffset = Data.getU64(&Offset);
 
   // Read Flags
   if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(uint8_t)))
@@ -138,8 +138,8 @@ template <> struct MappingTraits<FunctionYAML> {
 };
 
 template <> struct MappingTraits<FunctionsYAML> {
-  static void mapping(IO &io, FunctionsYAML &functionsYAML) {
-    io.mapRequired("functions", functionsYAML.functions);
+  static void mapping(IO &io, FunctionsYAML &FuncYAMLs) {
+    io.mapRequired("functions", FuncYAMLs.functions);
   }
 };
 
@@ -197,10 +197,9 @@ CallSiteInfoLoader::buildFunctionMap(std::vector<FunctionInfo> &Funcs) {
 }
 
 Error CallSiteInfoLoader::processYAMLFunctions(
-    const yaml::FunctionsYAML &functionsYAML,
-    StringMap<FunctionInfo *> &FuncMap) {
+    const yaml::FunctionsYAML &FuncYAMLs, StringMap<FunctionInfo *> &FuncMap) {
   // For each function in the YAML file
-  for (const auto &FuncYAML : functionsYAML.functions) {
+  for (const auto &FuncYAML : FuncYAMLs.functions) {
     auto It = FuncMap.find(FuncYAML.name);
     if (It == FuncMap.end())
       return createStringError(
@@ -216,7 +215,7 @@ Error CallSiteInfoLoader::processYAMLFunctions(
       CallSiteInfo CSI;
       // Since YAML has specifies relative return offsets, add the function
       // start address to make the offset absolute.
-      CSI.ReturnAddress = FuncInfo->Range.start() + CallSiteYAML.return_offset;
+      CSI.ReturnOffset = CallSiteYAML.return_offset;
       for (const auto &Regex : CallSiteYAML.match_regex) {
         uint32_t StrOffset = GCreator.insertString(Regex);
         CSI.MatchRegex.push_back(StrOffset);
@@ -241,7 +240,7 @@ Error CallSiteInfoLoader::processYAMLFunctions(
 }
 
 raw_ostream &gsym::operator<<(raw_ostream &OS, const CallSiteInfo &CSI) {
-  OS << "  Return=" << HEX64(CSI.ReturnAddress);
+  OS << "  Return=" << HEX64(CSI.ReturnOffset);
   OS << "  Flags=" << HEX8(CSI.Flags);
 
   OS << "  RegEx=";
diff --git a/llvm/lib/DebugInfo/GSYM/GsymReader.cpp b/llvm/lib/DebugInfo/GSYM/GsymReader.cpp
index 786633adc51202..cd92488e8b9cbd 100644
--- a/llvm/lib/DebugInfo/GSYM/GsymReader.cpp
+++ b/llvm/lib/DebugInfo/GSYM/GsymReader.cpp
@@ -424,7 +424,7 @@ void GsymReader::dump(raw_ostream &OS, const MergedFunctionsInfo &MFI) {
 }
 
 void GsymReader::dump(raw_ostream &OS, const CallSiteInfo &CSI) {
-  OS << HEX64(CSI.ReturnAddress);
+  OS << HEX16(CSI.ReturnOffset);
 
   std::string Flags;
   auto addFlag = [&](const char *Flag) {
@@ -456,7 +456,7 @@ void GsymReader::dump(raw_ostream &OS, const CallSiteInfo &CSI) {
 }
 
 void GsymReader::dump(raw_ostream &OS, const CallSiteInfoCollection &CSIC) {
-  OS << "CallSites (by return address):\n";
+  OS << "CallSites (by relative return offset):\n";
   for (const auto &CS : CSIC.CallSites) {
     OS.indent(2);
     dump(OS, CS);
diff --git a/llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-callsite-info-obj.test b/llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-callsite-info-obj.test
index 255b68a343b8db..61304558ba63f3 100644
--- a/llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-callsite-info-obj.test
+++ b/llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-callsite-info-obj.test
@@ -8,39 +8,39 @@
 // RUN: llvm-gsymutil %t/call_sites_obj.gsym | FileCheck --check-prefix=CHECK-GSYM %s
 
 
-// CHECK-GSYM:      FunctionInfo @ 0x[[#%x,]]: [0x[[#%x,]] - 0x[[#%x,]]) "func_mainBin_dec_call_everything"
+// CHECK-GSYM:      FunctionInfo @ 0x[[#%x,FUNC_INFO:]]: [0x[[#%x,FUNC_START:]] - 0x[[#%x,FUNC_END:]]) "func_mainBin_dec_call_everything"
 // CHECK-GSYM-NEXT: LineTable:
                       // func_mainBin_dec_call_everything() {
-// CHECK-GSYM-NEXT:   0x[[#%x,]] {{.*}}/call_sites.cpp:16
+// CHECK-GSYM-NEXT:   0x[[#%x,ENTRY:]] {{.*}}/call_sites.cpp:16
                       // func_mainBin_dec_01();
-// CHECK-GSYM-NEXT:   0x[[ADDR_dec_01_call:[0-9a-f]+]] {{.*}}/call_sites.cpp:17
+// CHECK-GSYM-NEXT:   0x[[#%x,ADDR_DEC_01_CALL:]] {{.*}}/call_sites.cpp:17
                       // func_mainBin_dec_02();
-// CHECK-GSYM-NEXT:   0x[[ADDR_dec_02_call:[0-9a-f]+]] {{.*}}/call_sites.cpp:18
+// CHECK-GSYM-NEXT:   0x[[#%x,ADDR_DEC_02_CALL:]] {{.*}}/call_sites.cpp:18
                       // func_mainBin_dec_03();
-// CHECK-GSYM-NEXT:   [[ADDR_dec_03_call:0x[0-9a-f]+]] {{.*}}/call_sites.cpp:19
+// CHECK-GSYM-NEXT:   0x[[#%x,ADDR_DEC_03_CALL:]] {{.*}}/call_sites.cpp:19
                       // func_mainBin_inc_01();
-// CHECK-GSYM-NEXT:   [[ADDR_inc_01_call:0x[0-9a-f]+]] {{.*}}/call_sites.cpp:21
+// CHECK-GSYM-NEXT:   0x[[#%x,ADDR_INC_01_CALL:]] {{.*}}/call_sites.cpp:21
                       // func_mainBin_inc_02();
-// CHECK-GSYM-NEXT:   [[ADDR_inc_02_call:0x[0-9a-f]+]] {{.*}}/call_sites.cpp:22
+// CHECK-GSYM-NEXT:   0x[[#%x,ADDR_INC_02_CALL:]] {{.*}}/call_sites.cpp:22
                       // func_mainBin_inc_03();
-// CHECK-GSYM-NEXT:   [[ADDR_inc_03_call:0x[0-9a-f]+]] {{.*}}/call_sites.cpp:23
+// CHECK-GSYM-NEXT:   0x[[#%x,ADDR_INC_03_CALL:]] {{.*}}/call_sites.cpp:23
                       // g_func_ptr();
-// CHECK-GSYM-NEXT:   [[ADDR_func_call:0x[0-9a-f]+]] {{.*}}/call_sites.cpp:25
+// CHECK-GSYM-NEXT:   0x[[#%x,ADDR_FUNC_CALL:]] {{.*}}/call_sites.cpp:25
                       // g_extern_func_ptr();
-// CHECK-GSYM-NEXT:   [[ADDR_extern_func_call:0x[0-9a-f]+]] {{.*}}/call_sites.cpp:26
+// CHECK-GSYM-NEXT:   0x[[#%x,ADDR_EXTERN_FUNC_CALL:]] {{.*}}/call_sites.cpp:26
                       // g_volatile_var = 0;
-// CHECK-GSYM-NEXT:   [[ADDR_var_assign:0x[0-9a-f]+]] {{.*}}/call_sites.cpp:28
+// CHECK-GSYM-NEXT:   0x[[#%x,ADDR_VAR_ASSIGN:]] {{.*}}/call_sites.cpp:28
                       // }
-// CHECK-GSYM-NEXT:   [[#%x,]] {{.*}}/call_sites.cpp:29
-// CHECK-GSYM-NEXT: CallSites (by return address):
-// CHECK-GSYM-NEXT:   [[ADDR_dec_02_call]] Flags[InternalCall] MatchRegex[func_mainBin_dec_01]
-// CHECK-GSYM-NEXT:   [[ADDR_dec_03_call]] Flags[InternalCall] MatchRegex[func_mainBin_dec_02]
-// CHECK-GSYM-NEXT:   [[ADDR_inc_01_call]] Flags[InternalCall] MatchRegex[func_mainBin_dec_03]
-// CHECK-GSYM-NEXT:   [[ADDR_inc_02_call]] Flags[InternalCall] MatchRegex[func_mainBin_inc_01]
-// CHECK-GSYM-NEXT:   [[ADDR_inc_03_call]] Flags[InternalCall] MatchRegex[func_mainBin_inc_02]
-// CHECK-GSYM-NEXT:   [[ADDR_func_call]] Flags[InternalCall] MatchRegex[func_mainBin_inc_03]
-// CHECK-GSYM-NEXT:   [[ADDR_extern_func_call]] Flags[None] MatchRegex[.*func.*]
-// CHECK-GSYM-NEXT:   [[ADDR_var_assign]] Flags[ExternalCall] MatchRegex[.*extern_func.*]
+// CHECK-GSYM-NEXT:   0x[[#%x,]] {{.*}}/call_sites.cpp:29
+// CHECK-GSYM-NEXT: CallSites (by relative return offset):
+// CHECK-GSYM-NEXT:   0x[[#%.4x,sub(ADDR_DEC_02_CALL,FUNC_START)]] Flags[InternalCall] MatchRegex[func_mainBin_dec_01]
+// CHECK-GSYM-NEXT:   0x[[#%.4x,sub(ADDR_DEC_03_CALL,FUNC_START)]] Flags[InternalCall] MatchRegex[func_mainBin_dec_02]
+// CHECK-GSYM-NEXT:   0x[[#%.4x,sub(ADDR_INC_01_CALL,FUNC_START)]] Flags[InternalCall] MatchRegex[func_mainBin_dec_03]
+// CHECK-GSYM-NEXT:   0x[[#%.4x,sub(ADDR_INC_02_CALL,FUNC_START)]] Flags[InternalCall] MatchRegex[func_mainBin_inc_01]
+// CHECK-GSYM-NEXT:   0x[[#%.4x,sub(ADDR_INC_03_CALL,FUNC_START)]] Flags[InternalCall] MatchRegex[func_mainBin_inc_02]
+// CHECK-GSYM-NEXT:   0x[[#%.4x,sub(ADDR_FUNC_CALL,FUNC_START)]] Flags[InternalCall] MatchRegex[func_mainBin_inc_03]
+// CHECK-GSYM-NEXT:   0x[[#%.4x,sub(ADDR_EXTERN_FUNC_CALL,FUNC_START)]] Flags[None] MatchRegex[.*func.*]
+// CHECK-GSYM-NEXT:   0x[[#%.4x,sub(ADDR_VAR_ASSIGN,FUNC_START)]] Flags[ExternalCall] MatchRegex[.*extern_func.*]
 
 
 //--- callsites.yaml

>From 32f798791e36d7c6f70fa91e8ed5998856607478 Mon Sep 17 00:00:00 2001
From: Alex B <alexborcan at meta.com>
Date: Thu, 14 Nov 2024 10:36:07 -0800
Subject: [PATCH 7/7] Fix lit test

---
 .../macho-gsym-callsite-info-dsym.yaml        | 42 +++++++++----------
 .../macho-gsym-callsite-info-exe.yaml         |  2 +-
 2 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-callsite-info-dsym.yaml b/llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-callsite-info-dsym.yaml
index 5c31d609626694..2ea53f5e1ce0bc 100644
--- a/llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-callsite-info-dsym.yaml
+++ b/llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-callsite-info-dsym.yaml
@@ -10,39 +10,39 @@
 # RUN: llvm-gsymutil %t/call_sites_dSYM.gsym | FileCheck --check-prefix=CHECK-GSYM %s
 
 
-# CHECK-GSYM:      FunctionInfo @ 0x[[#%x,]]: [0x[[#%x,]] - 0x[[#%x,]]) "func_mainBin_dec_call_everything"
+# CHECK-GSYM:      FunctionInfo @ 0x[[#%x,FUNC_INFO:]]: [0x[[#%x,FUNC_START:]] - 0x[[#%x,FUNC_END:]]) "func_mainBin_dec_call_everything"
 # CHECK-GSYM-NEXT: LineTable:
 #                    // func_mainBin_dec_call_everything() {
-# CHECK-GSYM-NEXT:   0x[[#%x,]] {{.*}}/call_sites.cpp:16
+# CHECK-GSYM-NEXT:   0x[[#%x,ENTRY:]] {{.*}}/call_sites.cpp:16
 #                    // func_mainBin_dec_01();
-# CHECK-GSYM-NEXT:   0x[[ADDR_dec_01_call:[0-9a-f]+]] {{.*}}/call_sites.cpp:17
+# CHECK-GSYM-NEXT:   0x[[#%x,ADDR_DEC_01_CALL:]] {{.*}}/call_sites.cpp:17
 #                    // func_mainBin_dec_02();
-# CHECK-GSYM-NEXT:   0x[[ADDR_dec_02_call:[0-9a-f]+]] {{.*}}/call_sites.cpp:18
+# CHECK-GSYM-NEXT:   0x[[#%x,ADDR_DEC_02_CALL:]] {{.*}}/call_sites.cpp:18
 #                    // func_mainBin_dec_03();
-# CHECK-GSYM-NEXT:   [[ADDR_dec_03_call:0x[0-9a-f]+]] {{.*}}/call_sites.cpp:19
+# CHECK-GSYM-NEXT:   0x[[#%x,ADDR_DEC_03_CALL:]] {{.*}}/call_sites.cpp:19
 #                    // func_mainBin_inc_01();
-# CHECK-GSYM-NEXT:   [[ADDR_inc_01_call:0x[0-9a-f]+]] {{.*}}/call_sites.cpp:21
+# CHECK-GSYM-NEXT:   0x[[#%x,ADDR_INC_01_CALL:]] {{.*}}/call_sites.cpp:21
 #                    // func_mainBin_inc_02();
-# CHECK-GSYM-NEXT:   [[ADDR_inc_02_call:0x[0-9a-f]+]] {{.*}}/call_sites.cpp:22
+# CHECK-GSYM-NEXT:   0x[[#%x,ADDR_INC_02_CALL:]] {{.*}}/call_sites.cpp:22
 #                    // func_mainBin_inc_03();
-# CHECK-GSYM-NEXT:   [[ADDR_inc_03_call:0x[0-9a-f]+]] {{.*}}/call_sites.cpp:23
+# CHECK-GSYM-NEXT:   0x[[#%x,ADDR_INC_03_CALL:]] {{.*}}/call_sites.cpp:23
 #                    // g_func_ptr();
-# CHECK-GSYM-NEXT:   [[ADDR_func_call:0x[0-9a-f]+]] {{.*}}/call_sites.cpp:25
+# CHECK-GSYM-NEXT:   0x[[#%x,ADDR_FUNC_CALL:]] {{.*}}/call_sites.cpp:25
 #                    // g_extern_func_ptr();
-# CHECK-GSYM-NEXT:   [[ADDR_extern_func_call:0x[0-9a-f]+]] {{.*}}/call_sites.cpp:26
+# CHECK-GSYM-NEXT:   0x[[#%x,ADDR_EXTERN_FUNC_CALL:]] {{.*}}/call_sites.cpp:26
 #                    // g_volatile_var = 0;
-# CHECK-GSYM-NEXT:   [[ADDR_var_assign:0x[0-9a-f]+]] {{.*}}/call_sites.cpp:28
+# CHECK-GSYM-NEXT:   0x[[#%x,ADDR_VAR_ASSIGN:]] {{.*}}/call_sites.cpp:28
 #                    // }
-# CHECK-GSYM-NEXT:   [[#%x,]] {{.*}}/call_sites.cpp:29
-# CHECK-GSYM-NEXT: CallSites (by return address):
-# CHECK-GSYM-NEXT:   [[ADDR_dec_02_call]] Flags[InternalCall] MatchRegex[func_mainBin_dec_01]
-# CHECK-GSYM-NEXT:   [[ADDR_dec_03_call]] Flags[InternalCall] MatchRegex[func_mainBin_dec_02]
-# CHECK-GSYM-NEXT:   [[ADDR_inc_01_call]] Flags[InternalCall] MatchRegex[func_mainBin_dec_03]
-# CHECK-GSYM-NEXT:   [[ADDR_inc_02_call]] Flags[InternalCall] MatchRegex[func_mainBin_inc_01]
-# CHECK-GSYM-NEXT:   [[ADDR_inc_03_call]] Flags[InternalCall] MatchRegex[func_mainBin_inc_02]
-# CHECK-GSYM-NEXT:   [[ADDR_func_call]] Flags[InternalCall] MatchRegex[func_mainBin_inc_03]
-# CHECK-GSYM-NEXT:   [[ADDR_extern_func_call]] Flags[None] MatchRegex[.*func.*]
-# CHECK-GSYM-NEXT:   [[ADDR_var_assign]] Flags[ExternalCall] MatchRegex[.*extern_func.*]
+# CHECK-GSYM-NEXT:   0x[[#%x,]] {{.*}}/call_sites.cpp:29
+# CHECK-GSYM-NEXT: CallSites (by relative return offset):
+# CHECK-GSYM-NEXT:   0x[[#%.4x,sub(ADDR_DEC_02_CALL,FUNC_START)]] Flags[InternalCall] MatchRegex[func_mainBin_dec_01]
+# CHECK-GSYM-NEXT:   0x[[#%.4x,sub(ADDR_DEC_03_CALL,FUNC_START)]] Flags[InternalCall] MatchRegex[func_mainBin_dec_02]
+# CHECK-GSYM-NEXT:   0x[[#%.4x,sub(ADDR_INC_01_CALL,FUNC_START)]] Flags[InternalCall] MatchRegex[func_mainBin_dec_03]
+# CHECK-GSYM-NEXT:   0x[[#%.4x,sub(ADDR_INC_02_CALL,FUNC_START)]] Flags[InternalCall] MatchRegex[func_mainBin_inc_01]
+# CHECK-GSYM-NEXT:   0x[[#%.4x,sub(ADDR_INC_03_CALL,FUNC_START)]] Flags[InternalCall] MatchRegex[func_mainBin_inc_02]
+# CHECK-GSYM-NEXT:   0x[[#%.4x,sub(ADDR_FUNC_CALL,FUNC_START)]] Flags[InternalCall] MatchRegex[func_mainBin_inc_03]
+# CHECK-GSYM-NEXT:   0x[[#%.4x,sub(ADDR_EXTERN_FUNC_CALL,FUNC_START)]] Flags[None] MatchRegex[.*func.*]
+# CHECK-GSYM-NEXT:   0x[[#%.4x,sub(ADDR_VAR_ASSIGN,FUNC_START)]] Flags[ExternalCall] MatchRegex[.*extern_func.*]
 
 
 #--- callsites.yaml
diff --git a/llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-callsite-info-exe.yaml b/llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-callsite-info-exe.yaml
index b454a9e14699a9..4a5324f68d2c63 100644
--- a/llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-callsite-info-exe.yaml
+++ b/llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-callsite-info-exe.yaml
@@ -11,7 +11,7 @@
 
 
 # CHECK-GSYM:      FunctionInfo @ 0x[[#%x,]]: [0x[[#%x,]] - 0x[[#%x,]]) "func_mainBin_dec_call_everything"
-# CHECK-GSYM-NEXT: CallSites (by return address):
+# CHECK-GSYM-NEXT: CallSites (by relative return offset):
 # CHECK-GSYM-NEXT:   0x[[#%x,]] Flags[InternalCall] MatchRegex[func_mainBin_dec_01]
 # CHECK-GSYM-NEXT:   0x[[#%x,]] Flags[InternalCall] MatchRegex[func_mainBin_dec_02]
 # CHECK-GSYM-NEXT:   0x[[#%x,]] Flags[InternalCall] MatchRegex[func_mainBin_dec_03]



More information about the llvm-commits mailing list