LLVM  9.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 (I->getContents(Contents))
82  return errorCodeToError(
83  std::make_error_code(std::errc::executable_format_error));
84 
85  RelocMap Relocs;
86  if (ObjFile.getBinary()->isELF()) {
87  uint32_t RelativeRelocation = [](object::ObjectFile *ObjFile) {
88  if (const auto *ELFObj = dyn_cast<object::ELF32LEObjectFile>(ObjFile))
89  return ELFObj->getELFFile()->getRelativeRelocationType();
90  else if (const auto *ELFObj = dyn_cast<object::ELF32BEObjectFile>(ObjFile))
91  return ELFObj->getELFFile()->getRelativeRelocationType();
92  else if (const auto *ELFObj = dyn_cast<object::ELF64LEObjectFile>(ObjFile))
93  return ELFObj->getELFFile()->getRelativeRelocationType();
94  else if (const auto *ELFObj = dyn_cast<object::ELF64BEObjectFile>(ObjFile))
95  return ELFObj->getELFFile()->getRelativeRelocationType();
96  else
97  return static_cast<uint32_t>(0);
98  }(ObjFile.getBinary());
99 
100  for (const object::SectionRef &Section : Sections) {
101  for (const object::RelocationRef &Reloc : Section.relocations()) {
102  if (Reloc.getType() != RelativeRelocation)
103  continue;
104  if (auto AddendOrErr = object::ELFRelocationRef(Reloc).getAddend())
105  Relocs.insert({Reloc.getOffset(), *AddendOrErr});
106  }
107  }
108  }
109 
110  // Copy the instrumentation map data into the Sleds data structure.
111  auto C = Contents.bytes_begin();
112  static constexpr size_t ELF64SledEntrySize = 32;
113 
114  if ((C - Contents.bytes_end()) % ELF64SledEntrySize != 0)
115  return make_error<StringError>(
116  Twine("Instrumentation map entries not evenly divisible by size of "
117  "an XRay sled entry in ELF64."),
118  std::make_error_code(std::errc::executable_format_error));
119 
120  auto RelocateOrElse = [&](uint32_t Offset, uint64_t Address) {
121  if (!Address) {
122  uint64_t A = I->getAddress() + C - Contents.bytes_begin() + Offset;
123  RelocMap::const_iterator R = Relocs.find(A);
124  if (R != Relocs.end())
125  return R->second;
126  }
127  return Address;
128  };
129 
130  int32_t FuncId = 1;
131  uint64_t CurFn = 0;
132  for (; C != Contents.bytes_end(); C += ELF64SledEntrySize) {
133  DataExtractor Extractor(
134  StringRef(reinterpret_cast<const char *>(C), ELF64SledEntrySize), true,
135  8);
136  Sleds.push_back({});
137  auto &Entry = Sleds.back();
138  uint32_t OffsetPtr = 0;
139  uint32_t AddrOff = OffsetPtr;
140  Entry.Address = RelocateOrElse(AddrOff, Extractor.getU64(&OffsetPtr));
141  uint32_t FuncOff = OffsetPtr;
142  Entry.Function = RelocateOrElse(FuncOff, Extractor.getU64(&OffsetPtr));
143  auto Kind = Extractor.getU8(&OffsetPtr);
144  static constexpr SledEntry::FunctionKinds Kinds[] = {
149  if (Kind >= sizeof(Kinds))
150  return errorCodeToError(
151  std::make_error_code(std::errc::executable_format_error));
152  Entry.Kind = Kinds[Kind];
153  Entry.AlwaysInstrument = Extractor.getU8(&OffsetPtr) != 0;
154 
155  // We do replicate the function id generation scheme implemented in the
156  // XRay runtime.
157  // FIXME: Figure out how to keep this consistent with the XRay runtime.
158  if (CurFn == 0) {
159  CurFn = Entry.Function;
160  FunctionAddresses[FuncId] = Entry.Function;
161  FunctionIds[Entry.Function] = FuncId;
162  }
163  if (Entry.Function != CurFn) {
164  ++FuncId;
165  CurFn = Entry.Function;
166  FunctionAddresses[FuncId] = Entry.Function;
167  FunctionIds[Entry.Function] = FuncId;
168  }
169  }
170  return Error::success();
171 }
172 
173 static Error
174 loadYAML(int Fd, size_t FileSize, StringRef Filename,
176  InstrumentationMap::FunctionAddressMap &FunctionAddresses,
178  std::error_code EC;
179  sys::fs::mapped_file_region MappedFile(
180  Fd, sys::fs::mapped_file_region::mapmode::readonly, FileSize, 0, EC);
181  if (EC)
182  return make_error<StringError>(
183  Twine("Failed memory-mapping file '") + Filename + "'.", EC);
184 
185  std::vector<YAMLXRaySledEntry> YAMLSleds;
186  yaml::Input In(StringRef(MappedFile.data(), MappedFile.size()));
187  In >> YAMLSleds;
188  if (In.error())
189  return make_error<StringError>(
190  Twine("Failed loading YAML document from '") + Filename + "'.",
191  In.error());
192 
193  Sleds.reserve(YAMLSleds.size());
194  for (const auto &Y : YAMLSleds) {
195  FunctionAddresses[Y.FuncId] = Y.Function;
196  FunctionIds[Y.Function] = Y.FuncId;
197  Sleds.push_back(
198  SledEntry{Y.Address, Y.Function, Y.Kind, Y.AlwaysInstrument});
199  }
200  return Error::success();
201 }
202 
203 // FIXME: Create error types that encapsulate a bit more information than what
204 // StringError instances contain.
207  // At this point we assume the file is an object file -- and if that doesn't
208  // work, we treat it as YAML.
209  // FIXME: Extend to support non-ELF and non-x86_64 binaries.
210 
211  InstrumentationMap Map;
212  auto ObjectFileOrError = object::ObjectFile::createObjectFile(Filename);
213  if (!ObjectFileOrError) {
214  auto E = ObjectFileOrError.takeError();
215  // We try to load it as YAML if the ELF load didn't work.
216  int Fd;
217  if (sys::fs::openFileForRead(Filename, Fd))
218  return std::move(E);
219 
220  uint64_t FileSize;
221  if (sys::fs::file_size(Filename, FileSize))
222  return std::move(E);
223 
224  // If the file is empty, we return the original error.
225  if (FileSize == 0)
226  return std::move(E);
227 
228  // From this point on the errors will be only for the YAML parts, so we
229  // consume the errors at this point.
230  consumeError(std::move(E));
231  if (auto E = loadYAML(Fd, FileSize, Filename, Map.Sleds,
232  Map.FunctionAddresses, Map.FunctionIds))
233  return std::move(E);
234  } else if (auto E = loadObj(Filename, *ObjectFileOrError, Map.Sleds,
235  Map.FunctionAddresses, Map.FunctionIds)) {
236  return std::move(E);
237  }
238  return Map;
239 }
const NoneType None
Definition: None.h:23
uint64_t CallInst * C
static Expected< OwningBinary< ObjectFile > > createObjectFile(StringRef ObjectPath)
Definition: ObjectFile.cpp:160
Profile::FuncID FuncId
Definition: Profile.cpp:320
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
std::error_code openFileForRead(const Twine &Name, int &ResultFD, 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.
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:201
This class represents a memory mapped file.
Definition: FileSystem.h:1074
std::unordered_map< uint64_t, int32_t > FunctionAddressReverseMap
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:51
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:678
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 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:291
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:1213
bool isELF() const
Definition: Binary.h:108
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 Error loadYAML(int Fd, size_t FileSize, StringRef Filename, InstrumentationMap::SledContainer &Sleds, InstrumentationMap::FunctionAddressMap &FunctionAddresses, InstrumentationMap::FunctionAddressReverseMap &FunctionIds)
static ErrorSuccess success()
Create a success value.
Definition: Error.h:326
std::error_code getName(StringRef &Result) const
Definition: ObjectFile.h:413
virtual Triple::ArchType getArch() const =0
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:129
#define I(x, y, z)
Definition: MD5.cpp:58
iterator end()
Definition: DenseMap.h:108
std::unordered_map< int32_t, uint64_t > FunctionAddressMap
const unsigned Kind
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:112
This is a value type class that represents a single section in the list of sections in the object fil...
Definition: ObjectFile.h:80