[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.
This commit is contained in:
alx32
2024-11-26 16:07:40 -08:00
committed by GitHub
parent 06514c5501
commit 5147e5941d
15 changed files with 2358 additions and 7 deletions

View File

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

View File

@@ -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.
///

View File

@@ -329,6 +329,16 @@ public:
/// \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 @@ public:
/// \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.

View File

@@ -181,6 +181,26 @@ public:
/// \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

View File

@@ -8,6 +8,7 @@ add_llvm_component_library(LLVMDebugInfoGSYM
InlineInfo.cpp
LineTable.cpp
LookupResult.cpp
CallSiteInfo.cpp
MergedFunctionsInfo.cpp
ObjectFileTransformer.cpp
ExtractRanges.cpp

View File

@@ -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;
}

View File

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

View File

@@ -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));

View File

@@ -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 &LT, uint32_t Indent) {
OS.indent(Indent);
OS << "LineTable:\n";

View File

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

View File

@@ -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 ]
...

View File

@@ -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"
@g_volatile_var = global i32 0, align 4, !dbg !0
@g_func_ptr = global ptr null, align 8, !dbg !5
@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

View File

@@ -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">;

View File

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

View File

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