LLVM  6.0.0svn
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/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"
21 #include "llvm/Object/ObjectFile.h"
23 #include "llvm/Support/Error.h"
26 #include <algorithm>
27 #include <cstddef>
28 #include <cstdint>
29 #include <system_error>
30 #include <vector>
31 
32 using namespace llvm;
33 using namespace xray;
34 
36  auto I = FunctionIds.find(Addr);
37  if (I != FunctionIds.end())
38  return I->second;
39  return None;
40 }
41 
43  auto I = FunctionAddresses.find(FuncId);
44  if (I != FunctionAddresses.end())
45  return I->second;
46  return None;
47 }
48 
49 static Error
52  InstrumentationMap::FunctionAddressMap &FunctionAddresses,
55 
56  // Find the section named "xray_instr_map".
57  if (!ObjFile.getBinary()->isELF() ||
58  !(ObjFile.getBinary()->getArch() == Triple::x86_64 ||
59  ObjFile.getBinary()->getArch() == Triple::ppc64le))
60  return make_error<StringError>(
61  "File format not supported (only does ELF little endian 64-bit).",
62  std::make_error_code(std::errc::not_supported));
63 
64  StringRef Contents = "";
65  const auto &Sections = ObjFile.getBinary()->sections();
66  auto I = llvm::find_if(Sections, [&](object::SectionRef Section) {
67  StringRef Name = "";
68  if (Section.getName(Name))
69  return false;
70  return Name == "xray_instr_map";
71  });
72 
73  if (I == Sections.end())
74  return make_error<StringError>(
75  "Failed to find XRay instrumentation map.",
76  std::make_error_code(std::errc::executable_format_error));
77 
78  if (I->getContents(Contents))
79  return errorCodeToError(
80  std::make_error_code(std::errc::executable_format_error));
81 
82  // Copy the instrumentation map data into the Sleds data structure.
83  auto C = Contents.bytes_begin();
84  static constexpr size_t ELF64SledEntrySize = 32;
85 
86  if ((C - Contents.bytes_end()) % ELF64SledEntrySize != 0)
87  return make_error<StringError>(
88  Twine("Instrumentation map entries not evenly divisible by size of "
89  "an XRay sled entry in ELF64."),
90  std::make_error_code(std::errc::executable_format_error));
91 
92  int32_t FuncId = 1;
93  uint64_t CurFn = 0;
94  for (; C != Contents.bytes_end(); C += ELF64SledEntrySize) {
95  DataExtractor Extractor(
96  StringRef(reinterpret_cast<const char *>(C), ELF64SledEntrySize), true,
97  8);
98  Sleds.push_back({});
99  auto &Entry = Sleds.back();
100  uint32_t OffsetPtr = 0;
101  Entry.Address = Extractor.getU64(&OffsetPtr);
102  Entry.Function = Extractor.getU64(&OffsetPtr);
103  auto Kind = Extractor.getU8(&OffsetPtr);
104  static constexpr SledEntry::FunctionKinds Kinds[] = {
109  if (Kind >= sizeof(Kinds))
110  return errorCodeToError(
111  std::make_error_code(std::errc::executable_format_error));
112  Entry.Kind = Kinds[Kind];
113  Entry.AlwaysInstrument = Extractor.getU8(&OffsetPtr) != 0;
114 
115  // We do replicate the function id generation scheme implemented in the
116  // XRay runtime.
117  // FIXME: Figure out how to keep this consistent with the XRay runtime.
118  if (CurFn == 0) {
119  CurFn = Entry.Function;
120  FunctionAddresses[FuncId] = Entry.Function;
121  FunctionIds[Entry.Function] = FuncId;
122  }
123  if (Entry.Function != CurFn) {
124  ++FuncId;
125  CurFn = Entry.Function;
126  FunctionAddresses[FuncId] = Entry.Function;
127  FunctionIds[Entry.Function] = FuncId;
128  }
129  }
130  return Error::success();
131 }
132 
133 static Error
134 loadYAML(int Fd, size_t FileSize, StringRef Filename,
136  InstrumentationMap::FunctionAddressMap &FunctionAddresses,
138  std::error_code EC;
139  sys::fs::mapped_file_region MappedFile(
140  Fd, sys::fs::mapped_file_region::mapmode::readonly, FileSize, 0, EC);
141  if (EC)
142  return make_error<StringError>(
143  Twine("Failed memory-mapping file '") + Filename + "'.", EC);
144 
145  std::vector<YAMLXRaySledEntry> YAMLSleds;
146  yaml::Input In(StringRef(MappedFile.data(), MappedFile.size()));
147  In >> YAMLSleds;
148  if (In.error())
149  return make_error<StringError>(
150  Twine("Failed loading YAML document from '") + Filename + "'.",
151  In.error());
152 
153  Sleds.reserve(YAMLSleds.size());
154  for (const auto &Y : YAMLSleds) {
155  FunctionAddresses[Y.FuncId] = Y.Function;
156  FunctionIds[Y.Function] = Y.FuncId;
157  Sleds.push_back(
158  SledEntry{Y.Address, Y.Function, Y.Kind, Y.AlwaysInstrument});
159  }
160  return Error::success();
161 }
162 
163 // FIXME: Create error types that encapsulate a bit more information than what
164 // StringError instances contain.
167  // At this point we assume the file is an object file -- and if that doesn't
168  // work, we treat it as YAML.
169  // FIXME: Extend to support non-ELF and non-x86_64 binaries.
170 
171  InstrumentationMap Map;
172  auto ObjectFileOrError = object::ObjectFile::createObjectFile(Filename);
173  if (!ObjectFileOrError) {
174  auto E = ObjectFileOrError.takeError();
175  // We try to load it as YAML if the ELF load didn't work.
176  int Fd;
177  if (sys::fs::openFileForRead(Filename, Fd))
178  return std::move(E);
179 
180  uint64_t FileSize;
181  if (sys::fs::file_size(Filename, FileSize))
182  return std::move(E);
183 
184  // If the file is empty, we return the original error.
185  if (FileSize == 0)
186  return std::move(E);
187 
188  // From this point on the errors will be only for the YAML parts, so we
189  // consume the errors at this point.
190  consumeError(std::move(E));
191  if (auto E = loadYAML(Fd, FileSize, Filename, Map.Sleds,
192  Map.FunctionAddresses, Map.FunctionIds))
193  return std::move(E);
194  } else if (auto E = loadELF64(Filename, *ObjectFileOrError, Map.Sleds,
195  Map.FunctionAddresses, Map.FunctionIds)) {
196  return std::move(E);
197  }
198  return Map;
199 }
const NoneType None
Definition: None.h:24
uint64_t CallInst * C
static Expected< OwningBinary< ObjectFile > > createObjectFile(StringRef ObjectPath)
Create ObjectFile from path.
Definition: ObjectFile.cpp:152
std::error_code error()
Definition: YAMLTraits.cpp:73
Optional< uint64_t > getFunctionAddr(int32_t FuncId) const
Returns the function address for a function id.
Compute iterated dominance frontiers using a linear time algorithm.
Definition: AllocatorList.h:24
FunctionKinds
Each entry here represents the kinds of supported instrumentation map entries.
std::error_code openFileForRead(const Twine &Name, int &ResultFD, SmallVectorImpl< char > *RealPath=nullptr)
This class represents a memory mapped file.
Definition: FileSystem.h:805
std::unordered_map< uint64_t, int32_t > FunctionAddressReverseMap
virtual unsigned getArch() const =0
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:81
std::vector< SledEntry > SledContainer
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:639
Tagged union holding either a T or a Error.
Definition: CachePruning.h:23
Expected< InstrumentationMap > loadInstrumentationMap(StringRef Filename)
Loads the instrumentation map from |Filename|.
The Input class is used to parse a yaml document into in-memory structs and vectors.
Definition: YAMLTraits.h:1108
Represents an XRay instrumentation sled entry from an object file.
section_iterator_range sections() const
Definition: ObjectFile.h:273
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:78
static Error loadELF64(StringRef Filename, object::OwningBinary< object::ObjectFile > &ObjFile, InstrumentationMap::SledContainer &Sleds, InstrumentationMap::FunctionAddressMap &FunctionAddresses, InstrumentationMap::FunctionAddressReverseMap &FunctionIds)
uint8_t getU8(uint32_t *offset_ptr) const
Extract a uint8_t value from *offset_ptr.
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:962
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:313
std::error_code getName(StringRef &Result) const
Definition: ObjectFile.h:398
Optional< int32_t > getFunctionId(uint64_t Addr) const
Returns an XRay computed function id, provided a function address.
#define I(x, y, z)
Definition: MD5.cpp:58
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:156
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:49
auto find_if(R &&Range, UnaryPredicate P) -> decltype(std::begin(Range))
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly...
Definition: STLExtras.h:795
This is a value type class that represents a single section in the list of sections in the object fil...
Definition: ObjectFile.h:80