LLVM  10.0.0svn
InstrumentationMap.cpp
Go to the documentation of this file.
1 //===- InstrumentationMap.cpp - XRay Instrumentation Map ------------------===//
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 //===----------------------------------------------------------------------===//
8 //
9 // Implementation of the InstrumentationMap type for XRay sleds.
10 //
11 //===----------------------------------------------------------------------===//
12 
14 #include "llvm/ADT/DenseMap.h"
15 #include "llvm/ADT/None.h"
16 #include "llvm/ADT/STLExtras.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/ADT/Triple.h"
19 #include "llvm/ADT/Twine.h"
20 #include "llvm/Object/Binary.h"
22 #include "llvm/Object/ObjectFile.h"
24 #include "llvm/Support/Error.h"
27 #include <algorithm>
28 #include <cstddef>
29 #include <cstdint>
30 #include <system_error>
31 #include <vector>
32 
33 using namespace llvm;
34 using namespace xray;
35 
37  auto I = FunctionIds.find(Addr);
38  if (I != FunctionIds.end())
39  return I->second;
40  return None;
41 }
42 
44  auto I = FunctionAddresses.find(FuncId);
45  if (I != FunctionAddresses.end())
46  return I->second;
47  return None;
48 }
49 
51 
52 static Error
55  InstrumentationMap::FunctionAddressMap &FunctionAddresses,
58 
59  // Find the section named "xray_instr_map".
60  if ((!ObjFile.getBinary()->isELF() && !ObjFile.getBinary()->isMachO()) ||
61  !(ObjFile.getBinary()->getArch() == Triple::x86_64 ||
62  ObjFile.getBinary()->getArch() == Triple::ppc64le))
63  return make_error<StringError>(
64  "File format not supported (only does ELF and Mach-O little endian 64-bit).",
65  std::make_error_code(std::errc::not_supported));
66 
67  StringRef Contents = "";
68  const auto &Sections = ObjFile.getBinary()->sections();
69  auto I = llvm::find_if(Sections, [&](object::SectionRef Section) {
70  StringRef Name = "";
71  if (Section.getName(Name))
72  return false;
73  return Name == "xray_instr_map";
74  });
75 
76  if (I == Sections.end())
77  return make_error<StringError>(
78  "Failed to find XRay instrumentation map.",
79  std::make_error_code(std::errc::executable_format_error));
80 
81  if (Expected<StringRef> E = I->getContents())
82  Contents = *E;
83  else
84  return E.takeError();
85 
86  RelocMap Relocs;
87  if (ObjFile.getBinary()->isELF()) {
88  uint32_t RelativeRelocation = [](object::ObjectFile *ObjFile) {
89  if (const auto *ELFObj = dyn_cast<object::ELF32LEObjectFile>(ObjFile))
90  return ELFObj->getELFFile()->getRelativeRelocationType();
91  else if (const auto *ELFObj = dyn_cast<object::ELF32BEObjectFile>(ObjFile))
92  return ELFObj->getELFFile()->getRelativeRelocationType();
93  else if (const auto *ELFObj = dyn_cast<object::ELF64LEObjectFile>(ObjFile))
94  return ELFObj->getELFFile()->getRelativeRelocationType();
95  else if (const auto *ELFObj = dyn_cast<object::ELF64BEObjectFile>(ObjFile))
96  return ELFObj->getELFFile()->getRelativeRelocationType();
97  else
98  return static_cast<uint32_t>(0);
99  }(ObjFile.getBinary());
100 
101  for (const object::SectionRef &Section : Sections) {
102  for (const object::RelocationRef &Reloc : Section.relocations()) {
103  if (Reloc.getType() != RelativeRelocation)
104  continue;
105  if (auto AddendOrErr = object::ELFRelocationRef(Reloc).getAddend())
106  Relocs.insert({Reloc.getOffset(), *AddendOrErr});
107  }
108  }
109  }
110 
111  // Copy the instrumentation map data into the Sleds data structure.
112  auto C = Contents.bytes_begin();
113  static constexpr size_t ELF64SledEntrySize = 32;
114 
115  if ((C - Contents.bytes_end()) % ELF64SledEntrySize != 0)
116  return make_error<StringError>(
117  Twine("Instrumentation map entries not evenly divisible by size of "
118  "an XRay sled entry in ELF64."),
119  std::make_error_code(std::errc::executable_format_error));
120 
121  auto RelocateOrElse = [&](uint32_t Offset, uint64_t Address) {
122  if (!Address) {
123  uint64_t A = I->getAddress() + C - Contents.bytes_begin() + Offset;
124  RelocMap::const_iterator R = Relocs.find(A);
125  if (R != Relocs.end())
126  return R->second;
127  }
128  return Address;
129  };
130 
131  int32_t FuncId = 1;
132  uint64_t CurFn = 0;
133  for (; C != Contents.bytes_end(); C += ELF64SledEntrySize) {
134  DataExtractor Extractor(
135  StringRef(reinterpret_cast<const char *>(C), ELF64SledEntrySize), true,
136  8);
137  Sleds.push_back({});
138  auto &Entry = Sleds.back();
139  uint32_t OffsetPtr = 0;
140  uint32_t AddrOff = OffsetPtr;
141  Entry.Address = RelocateOrElse(AddrOff, Extractor.getU64(&OffsetPtr));
142  uint32_t FuncOff = OffsetPtr;
143  Entry.Function = RelocateOrElse(FuncOff, Extractor.getU64(&OffsetPtr));
144  auto Kind = Extractor.getU8(&OffsetPtr);
145  static constexpr SledEntry::FunctionKinds Kinds[] = {
150  if (Kind >= sizeof(Kinds))
151  return errorCodeToError(
152  std::make_error_code(std::errc::executable_format_error));
153  Entry.Kind = Kinds[Kind];
154  Entry.AlwaysInstrument = Extractor.getU8(&OffsetPtr) != 0;
155 
156  // We do replicate the function id generation scheme implemented in the
157  // XRay runtime.
158  // FIXME: Figure out how to keep this consistent with the XRay runtime.
159  if (CurFn == 0) {
160  CurFn = Entry.Function;
161  FunctionAddresses[FuncId] = Entry.Function;
162  FunctionIds[Entry.Function] = FuncId;
163  }
164  if (Entry.Function != CurFn) {
165  ++FuncId;
166  CurFn = Entry.Function;
167  FunctionAddresses[FuncId] = Entry.Function;
168  FunctionIds[Entry.Function] = FuncId;
169  }
170  }
171  return Error::success();
172 }
173 
174 static Error
175 loadYAML(sys::fs::file_t Fd, size_t FileSize, StringRef Filename,
177  InstrumentationMap::FunctionAddressMap &FunctionAddresses,
179  std::error_code EC;
180  sys::fs::mapped_file_region MappedFile(
181  Fd, sys::fs::mapped_file_region::mapmode::readonly, FileSize, 0, EC);
182  sys::fs::closeFile(Fd);
183  if (EC)
184  return make_error<StringError>(
185  Twine("Failed memory-mapping file '") + Filename + "'.", EC);
186 
187  std::vector<YAMLXRaySledEntry> YAMLSleds;
188  yaml::Input In(StringRef(MappedFile.data(), MappedFile.size()));
189  In >> YAMLSleds;
190  if (In.error())
191  return make_error<StringError>(
192  Twine("Failed loading YAML document from '") + Filename + "'.",
193  In.error());
194 
195  Sleds.reserve(YAMLSleds.size());
196  for (const auto &Y : YAMLSleds) {
197  FunctionAddresses[Y.FuncId] = Y.Function;
198  FunctionIds[Y.Function] = Y.FuncId;
199  Sleds.push_back(
200  SledEntry{Y.Address, Y.Function, Y.Kind, Y.AlwaysInstrument});
201  }
202  return Error::success();
203 }
204 
205 // FIXME: Create error types that encapsulate a bit more information than what
206 // StringError instances contain.
209  // At this point we assume the file is an object file -- and if that doesn't
210  // work, we treat it as YAML.
211  // FIXME: Extend to support non-ELF and non-x86_64 binaries.
212 
213  InstrumentationMap Map;
214  auto ObjectFileOrError = object::ObjectFile::createObjectFile(Filename);
215  if (!ObjectFileOrError) {
216  auto E = ObjectFileOrError.takeError();
217  // We try to load it as YAML if the ELF load didn't work.
219  if (!FdOrErr) {
220  // Report the ELF load error if YAML failed.
221  consumeError(FdOrErr.takeError());
222  return std::move(E);
223  }
224 
225  uint64_t FileSize;
226  if (sys::fs::file_size(Filename, FileSize))
227  return std::move(E);
228 
229  // If the file is empty, we return the original error.
230  if (FileSize == 0)
231  return std::move(E);
232 
233  // From this point on the errors will be only for the YAML parts, so we
234  // consume the errors at this point.
235  consumeError(std::move(E));
236  if (auto E = loadYAML(*FdOrErr, FileSize, Filename, Map.Sleds,
237  Map.FunctionAddresses, Map.FunctionIds))
238  return std::move(E);
239  } else if (auto E = loadObj(Filename, *ObjectFileOrError, Map.Sleds,
240  Map.FunctionAddresses, Map.FunctionIds)) {
241  return std::move(E);
242  }
243  return Map;
244 }
const NoneType None
Definition: None.h:23
uint64_t CallInst * C
static Expected< OwningBinary< ObjectFile > > createObjectFile(StringRef ObjectPath)
Definition: ObjectFile.cpp:163
Profile::FuncID FuncId
Definition: Profile.cpp:321
Optional< uint64_t > getFunctionAddr(int32_t FuncId) const
Returns the function address for a function id.
This class represents lattice values for constants.
Definition: AllocatorList.h:23
FunctionKinds
Each entry here represents the kinds of supported instrumentation map entries.
amdgpu Simplify well known AMD library false FunctionCallee Value const Twine & Name
This class is the base class for all object file types.
Definition: ObjectFile.h:226
This class represents a memory mapped file.
Definition: FileSystem.h:1162
std::unordered_map< uint64_t, int32_t > FunctionAddressReverseMap
Error takeError()
Take ownership of the stored error.
Definition: Error.h:552
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition: DenseMap.h:221
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml", "ocaml 3.10-compatible collector")
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:80
std::vector< SledEntry > SledContainer
This is a value type class that represents a single relocation in the list of relocations in the obje...
Definition: ObjectFile.h:52
std::error_code make_error_code(BitcodeError E)
std::error_code file_size(const Twine &Path, uint64_t &Result)
Get file size.
Definition: FileSystem.h:696
Tagged union holding either a T or a Error.
Definition: CachePruning.h:22
Expected< InstrumentationMap > loadInstrumentationMap(StringRef Filename)
Loads the instrumentation map from |Filename|.
static Error loadYAML(sys::fs::file_t Fd, size_t FileSize, StringRef Filename, InstrumentationMap::SledContainer &Sleds, InstrumentationMap::FunctionAddressMap &FunctionAddresses, InstrumentationMap::FunctionAddressReverseMap &FunctionIds)
static Error loadObj(StringRef Filename, object::OwningBinary< object::ObjectFile > &ObjFile, InstrumentationMap::SledContainer &Sleds, InstrumentationMap::FunctionAddressMap &FunctionAddresses, InstrumentationMap::FunctionAddressReverseMap &FunctionIds)
Represents an XRay instrumentation sled entry from an object file.
section_iterator_range sections() const
Definition: ObjectFile.h:315
iterator find(const_arg_type_t< KeyT > Val)
Definition: DenseMap.h:176
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition: Error.cpp:87
Expected< int64_t > getAddend() const
uint8_t getU8(uint32_t *offset_ptr) const
Extract a uint8_t value from *offset_ptr.
auto find_if(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range))
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly...
Definition: STLExtras.h:1220
bool isELF() const
Definition: Binary.h:114
uint64_t getU64(uint32_t *offset_ptr) const
Extract a uint64_t value from *offset_ptr.
void consumeError(Error Err)
Consume a Error without doing anything.
Definition: Error.h:981
static ErrorSuccess success()
Create a success value.
Definition: Error.h:326
std::error_code getName(StringRef &Result) const
Definition: ObjectFile.h:437
virtual Triple::ArchType getArch() const =0
Expected< file_t > openNativeFileForRead(const Twine &Name, OpenFlags Flags=OF_None, SmallVectorImpl< char > *RealPath=nullptr)
Opens the file with the given name in a read-only mode, returning its open file descriptor.
std::error_code closeFile(file_t &F)
Close the file object.
Optional< int32_t > getFunctionId(uint64_t Addr) const
Returns an XRay computed function id, provided a function address.
iterator_range< relocation_iterator > relocations() const
Definition: ObjectFile.h:130
#define I(x, y, z)
Definition: MD5.cpp:58
iterator end()
Definition: DenseMap.h:108
std::unordered_map< int32_t, uint64_t > FunctionAddressMap
The InstrumentationMap represents the computed function id&#39;s and indicated function addresses from an...
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
bool isMachO() const
Definition: Binary.h:118
This is a value type class that represents a single section in the list of sections in the object fil...
Definition: ObjectFile.h:81