LLVM  8.0.1
InstrumentationMap.cpp
Go to the documentation of this file.
1 //===- InstrumentationMap.cpp - XRay Instrumentation Map ------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // Implementation of the InstrumentationMap type for XRay sleds.
11 //
12 //===----------------------------------------------------------------------===//
13 
15 #include "llvm/ADT/DenseMap.h"
16 #include "llvm/ADT/None.h"
17 #include "llvm/ADT/STLExtras.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/ADT/Triple.h"
20 #include "llvm/ADT/Twine.h"
21 #include "llvm/Object/Binary.h"
23 #include "llvm/Object/ObjectFile.h"
25 #include "llvm/Support/Error.h"
28 #include <algorithm>
29 #include <cstddef>
30 #include <cstdint>
31 #include <system_error>
32 #include <vector>
33 
34 using namespace llvm;
35 using namespace xray;
36 
38  auto I = FunctionIds.find(Addr);
39  if (I != FunctionIds.end())
40  return I->second;
41  return None;
42 }
43 
45  auto I = FunctionAddresses.find(FuncId);
46  if (I != FunctionAddresses.end())
47  return I->second;
48  return None;
49 }
50 
52 
53 static Error
56  InstrumentationMap::FunctionAddressMap &FunctionAddresses,
59 
60  // Find the section named "xray_instr_map".
61  if ((!ObjFile.getBinary()->isELF() && !ObjFile.getBinary()->isMachO()) ||
62  !(ObjFile.getBinary()->getArch() == Triple::x86_64 ||
63  ObjFile.getBinary()->getArch() == Triple::ppc64le))
64  return make_error<StringError>(
65  "File format not supported (only does ELF and Mach-O little endian 64-bit).",
66  std::make_error_code(std::errc::not_supported));
67 
68  StringRef Contents = "";
69  const auto &Sections = ObjFile.getBinary()->sections();
70  auto I = llvm::find_if(Sections, [&](object::SectionRef Section) {
71  StringRef Name = "";
72  if (Section.getName(Name))
73  return false;
74  return Name == "xray_instr_map";
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 (I->getContents(Contents))
83  return errorCodeToError(
84  std::make_error_code(std::errc::executable_format_error));
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(int 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  if (EC)
183  return make_error<StringError>(
184  Twine("Failed memory-mapping file '") + Filename + "'.", EC);
185 
186  std::vector<YAMLXRaySledEntry> YAMLSleds;
187  yaml::Input In(StringRef(MappedFile.data(), MappedFile.size()));
188  In >> YAMLSleds;
189  if (In.error())
190  return make_error<StringError>(
191  Twine("Failed loading YAML document from '") + Filename + "'.",
192  In.error());
193 
194  Sleds.reserve(YAMLSleds.size());
195  for (const auto &Y : YAMLSleds) {
196  FunctionAddresses[Y.FuncId] = Y.Function;
197  FunctionIds[Y.Function] = Y.FuncId;
198  Sleds.push_back(
199  SledEntry{Y.Address, Y.Function, Y.Kind, Y.AlwaysInstrument});
200  }
201  return Error::success();
202 }
203 
204 // FIXME: Create error types that encapsulate a bit more information than what
205 // StringError instances contain.
208  // At this point we assume the file is an object file -- and if that doesn't
209  // work, we treat it as YAML.
210  // FIXME: Extend to support non-ELF and non-x86_64 binaries.
211 
212  InstrumentationMap Map;
213  auto ObjectFileOrError = object::ObjectFile::createObjectFile(Filename);
214  if (!ObjectFileOrError) {
215  auto E = ObjectFileOrError.takeError();
216  // We try to load it as YAML if the ELF load didn't work.
217  int Fd;
218  if (sys::fs::openFileForRead(Filename, Fd))
219  return std::move(E);
220 
221  uint64_t FileSize;
222  if (sys::fs::file_size(Filename, FileSize))
223  return std::move(E);
224 
225  // If the file is empty, we return the original error.
226  if (FileSize == 0)
227  return std::move(E);
228 
229  // From this point on the errors will be only for the YAML parts, so we
230  // consume the errors at this point.
231  consumeError(std::move(E));
232  if (auto E = loadYAML(Fd, FileSize, Filename, Map.Sleds,
233  Map.FunctionAddresses, Map.FunctionIds))
234  return std::move(E);
235  } else if (auto E = loadObj(Filename, *ObjectFileOrError, Map.Sleds,
236  Map.FunctionAddresses, Map.FunctionIds)) {
237  return std::move(E);
238  }
239  return Map;
240 }
const NoneType None
Definition: None.h:24
uint64_t CallInst * C
static Expected< OwningBinary< ObjectFile > > createObjectFile(StringRef ObjectPath)
Definition: ObjectFile.cpp:161
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:24
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.
This class is the base class for all object file types.
Definition: ObjectFile.h:202
This class represents a memory mapped file.
Definition: FileSystem.h:1075
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")
amdgpu Simplify well known AMD library false Value Value const Twine & Name
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
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:679
Tagged union holding either a T or a Error.
Definition: CachePruning.h:23
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:292
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:88
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:1214
bool isELF() const
Definition: Binary.h:109
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:982
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:327
std::error_code getName(StringRef &Result) const
Definition: ObjectFile.h:414
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:130
#define I(x, y, z)
Definition: MD5.cpp:58
iterator end()
Definition: DenseMap.h:109
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:158
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:49
bool isMachO() const
Definition: Binary.h:113
This is a value type class that represents a single section in the list of sections in the object fil...
Definition: ObjectFile.h:81