[Clang] Disable failing offload test on darwin
[llvm-project.git] / llvm / lib / DebugInfo / GSYM / CallSiteInfo.cpp
blobc112c0bc3ddc9df6ed82c3cec13d58f730a0f1e2
1 //===- CallSiteInfo.cpp -----------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "llvm/DebugInfo/GSYM/CallSiteInfo.h"
10 #include "llvm/ADT/CachedHashString.h"
11 #include "llvm/DebugInfo/GSYM/FileWriter.h"
12 #include "llvm/DebugInfo/GSYM/FunctionInfo.h"
13 #include "llvm/DebugInfo/GSYM/GsymCreator.h"
14 #include "llvm/MC/StringTableBuilder.h"
15 #include "llvm/Support/DataExtractor.h"
16 #include "llvm/Support/YAMLParser.h"
17 #include "llvm/Support/YAMLTraits.h"
18 #include "llvm/Support/raw_ostream.h"
19 #include <fstream>
20 #include <string>
21 #include <unordered_map>
22 #include <vector>
24 using namespace llvm;
25 using namespace gsym;
27 Error CallSiteInfo::encode(FileWriter &O) const {
28 O.writeU64(ReturnOffset);
29 O.writeU8(Flags);
30 O.writeU32(MatchRegex.size());
31 for (uint32_t Entry : MatchRegex)
32 O.writeU32(Entry);
33 return Error::success();
36 Expected<CallSiteInfo> CallSiteInfo::decode(DataExtractor &Data,
37 uint64_t &Offset) {
38 CallSiteInfo CSI;
40 // Read ReturnOffset
41 if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(uint64_t)))
42 return createStringError(std::errc::io_error,
43 "0x%8.8" PRIx64 ": missing ReturnOffset", Offset);
44 CSI.ReturnOffset = Data.getU64(&Offset);
46 // Read Flags
47 if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(uint8_t)))
48 return createStringError(std::errc::io_error,
49 "0x%8.8" PRIx64 ": missing Flags", Offset);
50 CSI.Flags = Data.getU8(&Offset);
52 // Read number of MatchRegex entries
53 if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(uint32_t)))
54 return createStringError(std::errc::io_error,
55 "0x%8.8" PRIx64 ": missing MatchRegex count",
56 Offset);
57 uint32_t NumEntries = Data.getU32(&Offset);
59 CSI.MatchRegex.reserve(NumEntries);
60 for (uint32_t i = 0; i < NumEntries; ++i) {
61 if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(uint32_t)))
62 return createStringError(std::errc::io_error,
63 "0x%8.8" PRIx64 ": missing MatchRegex entry",
64 Offset);
65 uint32_t Entry = Data.getU32(&Offset);
66 CSI.MatchRegex.push_back(Entry);
69 return CSI;
72 Error CallSiteInfoCollection::encode(FileWriter &O) const {
73 O.writeU32(CallSites.size());
74 for (const CallSiteInfo &CSI : CallSites)
75 if (Error Err = CSI.encode(O))
76 return Err;
78 return Error::success();
81 Expected<CallSiteInfoCollection>
82 CallSiteInfoCollection::decode(DataExtractor &Data) {
83 CallSiteInfoCollection CSC;
84 uint64_t Offset = 0;
86 // Read number of CallSiteInfo entries
87 if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(uint32_t)))
88 return createStringError(std::errc::io_error,
89 "0x%8.8" PRIx64 ": missing CallSiteInfo count",
90 Offset);
91 uint32_t NumCallSites = Data.getU32(&Offset);
93 CSC.CallSites.reserve(NumCallSites);
94 for (uint32_t i = 0; i < NumCallSites; ++i) {
95 Expected<CallSiteInfo> ECSI = CallSiteInfo::decode(Data, Offset);
96 if (!ECSI)
97 return ECSI.takeError();
98 CSC.CallSites.emplace_back(*ECSI);
101 return CSC;
104 /// Structures necessary for reading CallSiteInfo from YAML.
105 namespace llvm {
106 namespace yaml {
108 struct CallSiteYAML {
109 // The offset of the return address of the call site - relative to the start
110 // of the function.
111 Hex64 return_offset;
112 std::vector<std::string> match_regex;
113 std::vector<std::string> flags;
116 struct FunctionYAML {
117 std::string name;
118 std::vector<CallSiteYAML> callsites;
121 struct FunctionsYAML {
122 std::vector<FunctionYAML> functions;
125 template <> struct MappingTraits<CallSiteYAML> {
126 static void mapping(IO &io, CallSiteYAML &callsite) {
127 io.mapRequired("return_offset", callsite.return_offset);
128 io.mapRequired("match_regex", callsite.match_regex);
129 io.mapOptional("flags", callsite.flags);
133 template <> struct MappingTraits<FunctionYAML> {
134 static void mapping(IO &io, FunctionYAML &func) {
135 io.mapRequired("name", func.name);
136 io.mapOptional("callsites", func.callsites);
140 template <> struct MappingTraits<FunctionsYAML> {
141 static void mapping(IO &io, FunctionsYAML &FuncYAMLs) {
142 io.mapRequired("functions", FuncYAMLs.functions);
146 } // namespace yaml
147 } // namespace llvm
149 LLVM_YAML_IS_SEQUENCE_VECTOR(CallSiteYAML)
150 LLVM_YAML_IS_SEQUENCE_VECTOR(FunctionYAML)
152 Error CallSiteInfoLoader::loadYAML(StringRef YAMLFile) {
153 // Step 1: Read YAML file
154 auto BufferOrError = MemoryBuffer::getFile(YAMLFile, /*IsText=*/true);
155 if (!BufferOrError)
156 return errorCodeToError(BufferOrError.getError());
158 std::unique_ptr<MemoryBuffer> Buffer = std::move(*BufferOrError);
160 // Step 2: Parse YAML content
161 yaml::FunctionsYAML FuncsYAML;
162 yaml::Input Yin(Buffer->getMemBufferRef());
163 Yin >> FuncsYAML;
164 if (Yin.error())
165 return createStringError(Yin.error(), "Error parsing YAML file: %s\n",
166 Buffer->getBufferIdentifier().str().c_str());
168 // Step 3: Build function map from Funcs
169 auto FuncMap = buildFunctionMap();
171 // Step 4: Process parsed YAML functions and update FuncMap
172 return processYAMLFunctions(FuncsYAML, FuncMap);
175 StringMap<FunctionInfo *> CallSiteInfoLoader::buildFunctionMap() {
176 // If the function name is already in the map, don't update it. This way we
177 // preferentially use the first encountered function. Since symbols are
178 // loaded from dSYM first, we end up preferring keeping track of symbols
179 // from dSYM rather than from the symbol table - which is what we want to
180 // do.
181 StringMap<FunctionInfo *> FuncMap;
182 for (auto &Func : Funcs) {
183 FuncMap.try_emplace(GCreator.getString(Func.Name), &Func);
184 if (auto &MFuncs = Func.MergedFunctions)
185 for (auto &MFunc : MFuncs->MergedFunctions)
186 FuncMap.try_emplace(GCreator.getString(MFunc.Name), &MFunc);
188 return FuncMap;
191 Error CallSiteInfoLoader::processYAMLFunctions(
192 const yaml::FunctionsYAML &FuncYAMLs, StringMap<FunctionInfo *> &FuncMap) {
193 // For each function in the YAML file
194 for (const auto &FuncYAML : FuncYAMLs.functions) {
195 auto It = FuncMap.find(FuncYAML.name);
196 if (It == FuncMap.end())
197 return createStringError(
198 std::errc::invalid_argument,
199 "Can't find function '%s' specified in callsite YAML\n",
200 FuncYAML.name.c_str());
202 FunctionInfo *FuncInfo = It->second;
203 // Create a CallSiteInfoCollection if not already present
204 if (!FuncInfo->CallSites)
205 FuncInfo->CallSites = CallSiteInfoCollection();
206 for (const auto &CallSiteYAML : FuncYAML.callsites) {
207 CallSiteInfo CSI;
208 // Since YAML has specifies relative return offsets, add the function
209 // start address to make the offset absolute.
210 CSI.ReturnOffset = CallSiteYAML.return_offset;
211 for (const auto &Regex : CallSiteYAML.match_regex) {
212 uint32_t StrOffset = GCreator.insertString(Regex);
213 CSI.MatchRegex.push_back(StrOffset);
216 // Parse flags and combine them
217 for (const auto &FlagStr : CallSiteYAML.flags) {
218 if (FlagStr == "InternalCall") {
219 CSI.Flags |= static_cast<uint8_t>(CallSiteInfo::InternalCall);
220 } else if (FlagStr == "ExternalCall") {
221 CSI.Flags |= static_cast<uint8_t>(CallSiteInfo::ExternalCall);
222 } else {
223 return createStringError(std::errc::invalid_argument,
224 "Unknown flag in callsite YAML: %s\n",
225 FlagStr.c_str());
228 FuncInfo->CallSites->CallSites.push_back(CSI);
231 return Error::success();
234 raw_ostream &gsym::operator<<(raw_ostream &OS, const CallSiteInfo &CSI) {
235 OS << " Return=" << HEX64(CSI.ReturnOffset);
236 OS << " Flags=" << HEX8(CSI.Flags);
238 OS << " RegEx=";
239 for (uint32_t i = 0; i < CSI.MatchRegex.size(); ++i) {
240 if (i > 0)
241 OS << ",";
242 OS << CSI.MatchRegex[i];
244 return OS;
247 raw_ostream &gsym::operator<<(raw_ostream &OS,
248 const CallSiteInfoCollection &CSIC) {
249 for (const auto &CS : CSIC.CallSites) {
250 OS << CS;
251 OS << "\n";
253 return OS;