[llvm] 5147e59 - [GSYM] Callsites: Add data format support and loading from YAML (#109781)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 26 16:07:43 PST 2024
Author: alx32
Date: 2024-11-26T16:07:40-08:00
New Revision: 5147e5941d40ae89b6ecab89aa36f8f5def28f1e
URL: https://github.com/llvm/llvm-project/commit/5147e5941d40ae89b6ecab89aa36f8f5def28f1e
DIFF: https://github.com/llvm/llvm-project/commit/5147e5941d40ae89b6ecab89aa36f8f5def28f1e.diff
LOG: [GSYM] Callsites: Add data format support and loading from YAML (#109781)
This PR adds support in the gSYM format for call site information and
adds support for loading call sites from a YAML file. The support for
YAML input is mostly for testing purposes - so we have a way to test the
functionality.
Note that this data is not currently used in the gSYM tooling - the
logic to use call sites will be added in a later PR.
The reason why we need call site information in gSYM files is so that we
can support better call stack function disambiguation in the case where
multiple functions have been merged due to optimization (linker ICF).
When resolving a merged function on the callstack, we can use the call
site information of the calling function to narrow down the actual
function that is being called, from the set of all merged functions.
See [this
RFC](https://discourse.llvm.org/t/rfc-extending-gsym-format-with-call-site-information-for-merged-function-disambiguation/80682)
for more details on this change.
Added:
llvm/include/llvm/DebugInfo/GSYM/CallSiteInfo.h
llvm/lib/DebugInfo/GSYM/CallSiteInfo.cpp
llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-callsite-info-dsym.yaml
llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-callsite-info-exe.yaml
llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-callsite-info-obj.test
Modified:
llvm/include/llvm/DebugInfo/GSYM/FunctionInfo.h
llvm/include/llvm/DebugInfo/GSYM/GsymCreator.h
llvm/include/llvm/DebugInfo/GSYM/GsymReader.h
llvm/lib/DebugInfo/GSYM/CMakeLists.txt
llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp
llvm/lib/DebugInfo/GSYM/GsymCreator.cpp
llvm/lib/DebugInfo/GSYM/GsymReader.cpp
llvm/tools/llvm-gsymutil/Opts.td
llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/DebugInfo/GSYM/CallSiteInfo.h b/llvm/include/llvm/DebugInfo/GSYM/CallSiteInfo.h
new file mode 100644
index 00000000000000..55f7322029d0fa
--- /dev/null
+++ b/llvm/include/llvm/DebugInfo/GSYM/CallSiteInfo.h
@@ -0,0 +1,136 @@
+//===- 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/BitmaskEnum.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/Error.h"
+#include <vector>
+
+namespace llvm {
+class DataExtractor;
+class raw_ostream;
+
+namespace yaml {
+struct FunctionsYAML;
+} // namespace yaml
+
+namespace gsym {
+class FileWriter;
+class GsymCreator;
+struct FunctionInfo;
+struct CallSiteInfo {
+ 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,
+
+ LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue*/ ExternalCall),
+ };
+
+ /// 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;
+
+ /// Bitwise OR of CallSiteInfo::Flags values
+ uint8_t Flags = CallSiteInfo::Flags::None;
+
+ /// 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.
+ /// \returns A CallSiteInfo or an error describing the issue.
+ static llvm::Expected<CallSiteInfo> decode(DataExtractor &Data,
+ uint64_t &Offset);
+
+ /// 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 {
+ std::vector<CallSiteInfo> CallSites;
+
+ /// Decode a CallSiteInfoCollection object from a binary data stream.
+ ///
+ /// \param Data The binary stream to read the data from.
+ /// \returns A CallSiteInfoCollection or an error describing the issue.
+ static llvm::Expected<CallSiteInfoCollection> decode(DataExtractor &Data);
+
+ /// 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;
+};
+
+class CallSiteInfoLoader {
+public:
+ /// Constructor that initializes the CallSiteInfoLoader with necessary data
+ /// structures.
+ ///
+ /// \param GCreator A reference to the GsymCreator.
+ CallSiteInfoLoader(GsymCreator &GCreator, std::vector<FunctionInfo> &Funcs)
+ : GCreator(GCreator), Funcs(Funcs) {}
+
+ /// 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(StringRef YAMLFile);
+
+private:
+ /// 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();
+
+ /// Processes the parsed YAML functions and updates the `FuncMap` accordingly.
+ ///
+ /// \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 &FuncYAMLs,
+ StringMap<FunctionInfo *> &FuncMap);
+
+ /// Reference to the parent Gsym Creator object.
+ GsymCreator &GCreator;
+
+ /// Reference to the vector of FunctionInfo objects to be populated.
+ std::vector<FunctionInfo> &Funcs;
+};
+
+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..0d098da96dd278 100644
--- a/llvm/include/llvm/DebugInfo/GSYM/GsymCreator.h
+++ b/llvm/include/llvm/DebugInfo/GSYM/GsymCreator.h
@@ -329,6 +329,16 @@ class GsymCreator {
/// \returns The unique 32 bit offset into the string table.
uint32_t insertString(StringRef S, bool Copy = true);
+ /// Retrieve a string from the 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
@@ -352,13 +362,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..cf4c64e5e85ca6
--- /dev/null
+++ b/llvm/lib/DebugInfo/GSYM/CallSiteInfo.cpp
@@ -0,0 +1,254 @@
+//===- 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/DebugInfo/GSYM/GsymCreator.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;
+
+Error CallSiteInfo::encode(FileWriter &O) const {
+ O.writeU64(ReturnOffset);
+ O.writeU8(Flags);
+ O.writeU32(MatchRegex.size());
+ for (uint32_t Entry : MatchRegex)
+ O.writeU32(Entry);
+ return Error::success();
+}
+
+Expected<CallSiteInfo> CallSiteInfo::decode(DataExtractor &Data,
+ uint64_t &Offset) {
+ CallSiteInfo CSI;
+
+ // Read ReturnOffset
+ if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(uint64_t)))
+ return createStringError(std::errc::io_error,
+ "0x%8.8" PRIx64 ": missing ReturnOffset", Offset);
+ CSI.ReturnOffset = 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;
+}
+
+Error CallSiteInfoCollection::encode(FileWriter &O) const {
+ O.writeU32(CallSites.size());
+ for (const CallSiteInfo &CSI : CallSites)
+ if (Error Err = CSI.encode(O))
+ return Err;
+
+ return Error::success();
+}
+
+Expected<CallSiteInfoCollection>
+CallSiteInfoCollection::decode(DataExtractor &Data) {
+ 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) {
+ Expected<CallSiteInfo> ECSI = CallSiteInfo::decode(Data, Offset);
+ 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.
+ 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 &FuncYAMLs) {
+ io.mapRequired("functions", FuncYAMLs.functions);
+ }
+};
+
+} // namespace yaml
+} // namespace llvm
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(CallSiteYAML)
+LLVM_YAML_IS_SEQUENCE_VECTOR(FunctionYAML)
+
+Error CallSiteInfoLoader::loadYAML(StringRef YAMLFile) {
+ // Step 1: Read YAML file
+ auto BufferOrError = MemoryBuffer::getFile(YAMLFile);
+ if (!BufferOrError)
+ return errorCodeToError(BufferOrError.getError());
+
+ std::unique_ptr<MemoryBuffer> Buffer = std::move(*BufferOrError);
+
+ // Step 2: Parse YAML content
+ yaml::FunctionsYAML FuncsYAML;
+ yaml::Input Yin(Buffer->getMemBufferRef());
+ Yin >> FuncsYAML;
+ 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();
+
+ // Step 4: Process parsed YAML functions and update FuncMap
+ return processYAMLFunctions(FuncsYAML, FuncMap);
+}
+
+StringMap<FunctionInfo *> CallSiteInfoLoader::buildFunctionMap() {
+ // 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.
+ StringMap<FunctionInfo *> FuncMap;
+ for (auto &Func : Funcs) {
+ FuncMap.try_emplace(GCreator.getString(Func.Name), &Func);
+ if (auto MFuncs = Func.MergedFunctions)
+ for (auto &MFunc : MFuncs->MergedFunctions)
+ FuncMap.try_emplace(GCreator.getString(MFunc.Name), &MFunc);
+ }
+ return FuncMap;
+}
+
+Error CallSiteInfoLoader::processYAMLFunctions(
+ const yaml::FunctionsYAML &FuncYAMLs, StringMap<FunctionInfo *> &FuncMap) {
+ // For each function in the YAML file
+ for (const auto &FuncYAML : FuncYAMLs.functions) {
+ 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;
+ // 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.ReturnOffset = CallSiteYAML.return_offset;
+ for (const auto &Regex : CallSiteYAML.match_regex) {
+ uint32_t StrOffset = GCreator.insertString(Regex);
+ CSI.MatchRegex.push_back(StrOffset);
+ }
+
+ // 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 createStringError(std::errc::invalid_argument,
+ "Unknown flag in callsite YAML: %s\n",
+ FlagStr.c_str());
+ }
+ }
+ FuncInfo->CallSites->CallSites.push_back(CSI);
+ }
+ }
+ return Error::success();
+}
+
+raw_ostream &gsym::operator<<(raw_ostream &OS, const CallSiteInfo &CSI) {
+ OS << " Return=" << HEX64(CSI.ReturnOffset);
+ 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 &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..dd754c701f6240 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))
+ 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();
+ 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..eb26c637a2ca36 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(*this, Funcs);
+ return Loader.loadYAML(YAMLFile);
+}
+
void GsymCreator::prepareMergedFunctions(OutputAggregator &Out) {
// Nothing to do if we have less than 2 functions.
if (Funcs.size() < 2)
@@ -379,6 +385,13 @@ uint32_t GsymCreator::insertString(StringRef S, bool Copy) {
return StrOff;
}
+StringRef GsymCreator::getString(uint32_t Offset) {
+ auto I = StringOffsetMap.find(Offset);
+ assert(I != StringOffsetMap.end() &&
+ "GsymCreator::getString expects a valid offset as parameter.");
+ return I->second.val();
+}
+
void GsymCreator::addFunctionInfo(FunctionInfo &&FI) {
std::lock_guard<std::mutex> Guard(Mutex);
Funcs.emplace_back(std::move(FI));
diff --git a/llvm/lib/DebugInfo/GSYM/GsymReader.cpp b/llvm/lib/DebugInfo/GSYM/GsymReader.cpp
index 2f3e6cf9b56a3a..7979f1f5d51928 100644
--- a/llvm/lib/DebugInfo/GSYM/GsymReader.cpp
+++ b/llvm/lib/DebugInfo/GSYM/GsymReader.cpp
@@ -410,6 +410,9 @@ 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) {
@@ -419,6 +422,47 @@ void GsymReader::dump(raw_ostream &OS, const MergedFunctionsInfo &MFI) {
}
}
+void GsymReader::dump(raw_ostream &OS, const CallSiteInfo &CSI) {
+ OS << HEX16(CSI.ReturnOffset);
+
+ 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 relative return offset):\n";
+ for (const auto &CS : CSIC.CallSites) {
+ OS.indent(2);
+ dump(OS, CS);
+ OS << "\n";
+ }
+}
+
void GsymReader::dump(raw_ostream &OS, const LineTable <, 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..c636afe5cb850f
--- /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-yaml-file=%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,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,ENTRY:]] {{.*}}/call_sites.cpp:16
+# // func_mainBin_dec_01();
+# CHECK-GSYM-NEXT: 0x[[#%x,ADDR_DEC_01_CALL:]] {{.*}}/call_sites.cpp:17
+# // func_mainBin_dec_02();
+# CHECK-GSYM-NEXT: 0x[[#%x,ADDR_DEC_02_CALL:]] {{.*}}/call_sites.cpp:18
+# // func_mainBin_dec_03();
+# CHECK-GSYM-NEXT: 0x[[#%x,ADDR_DEC_03_CALL:]] {{.*}}/call_sites.cpp:19
+# // func_mainBin_inc_01();
+# CHECK-GSYM-NEXT: 0x[[#%x,ADDR_INC_01_CALL:]] {{.*}}/call_sites.cpp:21
+# // func_mainBin_inc_02();
+# CHECK-GSYM-NEXT: 0x[[#%x,ADDR_INC_02_CALL:]] {{.*}}/call_sites.cpp:22
+# // func_mainBin_inc_03();
+# CHECK-GSYM-NEXT: 0x[[#%x,ADDR_INC_03_CALL:]] {{.*}}/call_sites.cpp:23
+# // g_func_ptr();
+# CHECK-GSYM-NEXT: 0x[[#%x,ADDR_FUNC_CALL:]] {{.*}}/call_sites.cpp:25
+# // g_extern_func_ptr();
+# CHECK-GSYM-NEXT: 0x[[#%x,ADDR_EXTERN_FUNC_CALL:]] {{.*}}/call_sites.cpp:26
+# // g_volatile_var = 0;
+# CHECK-GSYM-NEXT: 0x[[#%x,ADDR_VAR_ASSIGN:]] {{.*}}/call_sites.cpp:28
+# // }
+# 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
+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..557f43d778e582
--- /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-yaml-file=%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 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]
+# 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..2d082ed6477f1e
--- /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-yaml-file=%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,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,ENTRY:]] {{.*}}/call_sites.cpp:16
+ // func_mainBin_dec_01();
+// CHECK-GSYM-NEXT: 0x[[#%x,ADDR_DEC_01_CALL:]] {{.*}}/call_sites.cpp:17
+ // func_mainBin_dec_02();
+// CHECK-GSYM-NEXT: 0x[[#%x,ADDR_DEC_02_CALL:]] {{.*}}/call_sites.cpp:18
+ // func_mainBin_dec_03();
+// CHECK-GSYM-NEXT: 0x[[#%x,ADDR_DEC_03_CALL:]] {{.*}}/call_sites.cpp:19
+ // func_mainBin_inc_01();
+// CHECK-GSYM-NEXT: 0x[[#%x,ADDR_INC_01_CALL:]] {{.*}}/call_sites.cpp:21
+ // func_mainBin_inc_02();
+// CHECK-GSYM-NEXT: 0x[[#%x,ADDR_INC_02_CALL:]] {{.*}}/call_sites.cpp:22
+ // func_mainBin_inc_03();
+// CHECK-GSYM-NEXT: 0x[[#%x,ADDR_INC_03_CALL:]] {{.*}}/call_sites.cpp:23
+ // g_func_ptr();
+// CHECK-GSYM-NEXT: 0x[[#%x,ADDR_FUNC_CALL:]] {{.*}}/call_sites.cpp:25
+ // g_extern_func_ptr();
+// CHECK-GSYM-NEXT: 0x[[#%x,ADDR_EXTERN_FUNC_CALL:]] {{.*}}/call_sites.cpp:26
+ // g_volatile_var = 0;
+// CHECK-GSYM-NEXT: 0x[[#%x,ADDR_VAR_ASSIGN:]] {{.*}}/call_sites.cpp:28
+ // }
+// 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
+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..00f903c5211f39 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_yaml_file :
+ Eq<"callsites-yaml-file", "Load call site info from YAML file. Useful for testing.">, Flags<[HelpHidden]>;
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..4d441465c47fbf 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::string CallSiteYamlPath;
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);
+
+ if (Args.hasArg(OPT_callsites_yaml_file_EQ)) {
+ CallSiteYamlPath = Args.getLastArgValue(OPT_callsites_yaml_file_EQ);
+ if (CallSiteYamlPath.empty()) {
+ llvm::errs()
+ << ToolName
+ << ": --callsites-yaml-file option requires a non-empty argument.\n";
+ std::exit(1);
+ }
+ }
}
/// @}
@@ -370,6 +382,11 @@ 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.
+ 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
// 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,
More information about the llvm-commits
mailing list