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