LLVM  13.0.0git
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"
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  ObjFile.getBinary()->getArch() == Triple::arm ||
65  ObjFile.getBinary()->getArch() == Triple::aarch64))
66  return make_error<StringError>(
67  "File format not supported (only does ELF and Mach-O little endian "
68  "64-bit).",
69  std::make_error_code(std::errc::not_supported));
70 
71  StringRef Contents = "";
72  const auto &Sections = ObjFile.getBinary()->sections();
73  uint64_t Address = 0;
74  auto I = llvm::find_if(Sections, [&](object::SectionRef Section) {
75  Expected<StringRef> NameOrErr = Section.getName();
76  if (NameOrErr) {
77  Address = Section.getAddress();
78  return *NameOrErr == "xray_instr_map";
79  }
80  consumeError(NameOrErr.takeError());
81  return false;
82  });
83 
84  if (I == Sections.end())
85  return make_error<StringError>(
86  "Failed to find XRay instrumentation map.",
87  std::make_error_code(std::errc::executable_format_error));
88 
89  if (Expected<StringRef> E = I->getContents())
90  Contents = *E;
91  else
92  return E.takeError();
93 
94  RelocMap Relocs;
95  if (ObjFile.getBinary()->isELF()) {
96  uint32_t RelativeRelocation = [](object::ObjectFile *ObjFile) {
97  if (const auto *ELFObj = dyn_cast<object::ELF32LEObjectFile>(ObjFile))
98  return ELFObj->getELFFile().getRelativeRelocationType();
99  else if (const auto *ELFObj =
100  dyn_cast<object::ELF32BEObjectFile>(ObjFile))
101  return ELFObj->getELFFile().getRelativeRelocationType();
102  else if (const auto *ELFObj =
103  dyn_cast<object::ELF64LEObjectFile>(ObjFile))
104  return ELFObj->getELFFile().getRelativeRelocationType();
105  else if (const auto *ELFObj =
106  dyn_cast<object::ELF64BEObjectFile>(ObjFile))
107  return ELFObj->getELFFile().getRelativeRelocationType();
108  else
109  return static_cast<uint32_t>(0);
110  }(ObjFile.getBinary());
111 
114  std::tie(Supports, Resolver) =
116 
117  for (const object::SectionRef &Section : Sections) {
118  for (const object::RelocationRef &Reloc : Section.relocations()) {
119  if (ObjFile.getBinary()->getArch() == Triple::arm) {
120  if (Supports && Supports(Reloc.getType())) {
121  Expected<uint64_t> ValueOrErr = Reloc.getSymbol()->getValue();
122  if (!ValueOrErr)
123  return ValueOrErr.takeError();
124  Relocs.insert(
125  {Reloc.getOffset(),
126  object::resolveRelocation(Resolver, Reloc, *ValueOrErr, 0)});
127  }
128  } else if (Supports && Supports(Reloc.getType())) {
129  auto AddendOrErr = object::ELFRelocationRef(Reloc).getAddend();
130  auto A = AddendOrErr ? *AddendOrErr : 0;
131  Expected<uint64_t> ValueOrErr = Reloc.getSymbol()->getValue();
132  if (!ValueOrErr)
133  // TODO: Test this error.
134  return ValueOrErr.takeError();
135  Relocs.insert(
136  {Reloc.getOffset(),
137  object::resolveRelocation(Resolver, Reloc, *ValueOrErr, A)});
138  } else if (Reloc.getType() == RelativeRelocation) {
139  if (auto AddendOrErr = object::ELFRelocationRef(Reloc).getAddend())
140  Relocs.insert({Reloc.getOffset(), *AddendOrErr});
141  }
142  }
143  }
144  }
145 
146  // Copy the instrumentation map data into the Sleds data structure.
147  auto C = Contents.bytes_begin();
148  bool Is32Bit = ObjFile.getBinary()->makeTriple().isArch32Bit();
149  size_t ELFSledEntrySize = Is32Bit ? 16 : 32;
150 
151  if ((C - Contents.bytes_end()) % ELFSledEntrySize != 0)
152  return make_error<StringError>(
153  Twine("Instrumentation map entries not evenly divisible by size of "
154  "an XRay sled entry."),
155  std::make_error_code(std::errc::executable_format_error));
156 
157  auto RelocateOrElse = [&](uint64_t Offset, uint64_t Address) {
158  if (!Address) {
159  uint64_t A = I->getAddress() + C - Contents.bytes_begin() + Offset;
160  RelocMap::const_iterator R = Relocs.find(A);
161  if (R != Relocs.end())
162  return R->second;
163  }
164  return Address;
165  };
166 
167  const int WordSize = Is32Bit ? 4 : 8;
168  int32_t FuncId = 1;
169  uint64_t CurFn = 0;
170  for (; C != Contents.bytes_end(); C += ELFSledEntrySize) {
171  DataExtractor Extractor(
172  StringRef(reinterpret_cast<const char *>(C), ELFSledEntrySize), true,
173  8);
174  Sleds.push_back({});
175  auto &Entry = Sleds.back();
176  uint64_t OffsetPtr = 0;
177  uint64_t AddrOff = OffsetPtr;
178  if (Is32Bit)
179  Entry.Address = RelocateOrElse(AddrOff, Extractor.getU32(&OffsetPtr));
180  else
181  Entry.Address = RelocateOrElse(AddrOff, Extractor.getU64(&OffsetPtr));
182  uint64_t FuncOff = OffsetPtr;
183  if (Is32Bit)
184  Entry.Function = RelocateOrElse(FuncOff, Extractor.getU32(&OffsetPtr));
185  else
186  Entry.Function = RelocateOrElse(FuncOff, Extractor.getU64(&OffsetPtr));
187  auto Kind = Extractor.getU8(&OffsetPtr);
188  static constexpr SledEntry::FunctionKinds Kinds[] = {
193  if (Kind >= sizeof(Kinds))
194  return errorCodeToError(
195  std::make_error_code(std::errc::executable_format_error));
196  Entry.Kind = Kinds[Kind];
197  Entry.AlwaysInstrument = Extractor.getU8(&OffsetPtr) != 0;
198  Entry.Version = Extractor.getU8(&OffsetPtr);
199  if (Entry.Version >= 2) {
200  Entry.Address += C - Contents.bytes_begin() + Address;
201  Entry.Function += C - Contents.bytes_begin() + WordSize + Address;
202  }
203 
204  // We do replicate the function id generation scheme implemented in the
205  // XRay runtime.
206  // FIXME: Figure out how to keep this consistent with the XRay runtime.
207  if (CurFn == 0) {
208  CurFn = Entry.Function;
209  FunctionAddresses[FuncId] = Entry.Function;
210  FunctionIds[Entry.Function] = FuncId;
211  }
212  if (Entry.Function != CurFn) {
213  ++FuncId;
214  CurFn = Entry.Function;
215  FunctionAddresses[FuncId] = Entry.Function;
216  FunctionIds[Entry.Function] = FuncId;
217  }
218  }
219  return Error::success();
220 }
221 
222 static Error
223 loadYAML(sys::fs::file_t Fd, size_t FileSize, StringRef Filename,
225  InstrumentationMap::FunctionAddressMap &FunctionAddresses,
227  std::error_code EC;
228  sys::fs::mapped_file_region MappedFile(
230  sys::fs::closeFile(Fd);
231  if (EC)
232  return make_error<StringError>(
233  Twine("Failed memory-mapping file '") + Filename + "'.", EC);
234 
235  std::vector<YAMLXRaySledEntry> YAMLSleds;
236  yaml::Input In(StringRef(MappedFile.data(), MappedFile.size()));
237  In >> YAMLSleds;
238  if (In.error())
239  return make_error<StringError>(
240  Twine("Failed loading YAML document from '") + Filename + "'.",
241  In.error());
242 
243  Sleds.reserve(YAMLSleds.size());
244  for (const auto &Y : YAMLSleds) {
245  FunctionAddresses[Y.FuncId] = Y.Function;
246  FunctionIds[Y.Function] = Y.FuncId;
247  Sleds.push_back(SledEntry{Y.Address, Y.Function, Y.Kind, Y.AlwaysInstrument,
248  Y.Version});
249  }
250  return Error::success();
251 }
252 
253 // FIXME: Create error types that encapsulate a bit more information than what
254 // StringError instances contain.
257  // At this point we assume the file is an object file -- and if that doesn't
258  // work, we treat it as YAML.
259  // FIXME: Extend to support non-ELF and non-x86_64 binaries.
260 
261  InstrumentationMap Map;
262  auto ObjectFileOrError = object::ObjectFile::createObjectFile(Filename);
263  if (!ObjectFileOrError) {
264  auto E = ObjectFileOrError.takeError();
265  // We try to load it as YAML if the ELF load didn't work.
266  Expected<sys::fs::file_t> FdOrErr =
268  if (!FdOrErr) {
269  // Report the ELF load error if YAML failed.
270  consumeError(FdOrErr.takeError());
271  return std::move(E);
272  }
273 
274  uint64_t FileSize;
275  if (sys::fs::file_size(Filename, FileSize))
276  return std::move(E);
277 
278  // If the file is empty, we return the original error.
279  if (FileSize == 0)
280  return std::move(E);
281 
282  // From this point on the errors will be only for the YAML parts, so we
283  // consume the errors at this point.
285  if (auto E = loadYAML(*FdOrErr, FileSize, Filename, Map.Sleds,
286  Map.FunctionAddresses, Map.FunctionIds))
287  return std::move(E);
288  } else if (auto E = loadObj(Filename, *ObjectFileOrError, Map.Sleds,
289  Map.FunctionAddresses, Map.FunctionIds)) {
290  return std::move(E);
291  }
292  return Map;
293 }
llvm::sys::fs::file_t
int file_t
Definition: FileSystem.h:60
llvm
Definition: AllocatorList.h:23
FileSystem.h
llvm::xray::InstrumentationMap::getFunctionAddr
Optional< uint64_t > getFunctionAddr(int32_t FuncId) const
Returns the function address for a function id.
Definition: InstrumentationMap.cpp:44
llvm::xray::InstrumentationMap
The InstrumentationMap represents the computed function id's and indicated function addresses from an...
Definition: InstrumentationMap.h:75
llvm::object::RelocationResolver
uint64_t(*)(uint64_t Type, uint64_t Offset, uint64_t S, uint64_t LocData, int64_t Addend) RelocationResolver
Definition: RelocationResolver.h:37
StringRef.h
llvm::Error::success
static ErrorSuccess success()
Create a success value.
Definition: Error.h:332
llvm::object::OwningBinary::getBinary
T * getBinary()
Definition: Binary.h:227
Error.h
llvm::DenseMapIterator
Definition: DenseMap.h:56
DenseMap.h
llvm::Triple::x86_64
@ x86_64
Definition: Triple.h:84
llvm::object::ObjectFile::getArch
virtual Triple::ArchType getArch() const =0
llvm::Optional
Definition: APInt.h:33
Offset
uint64_t Offset
Definition: ELFObjHandler.cpp:81
llvm::xray::SledEntry::FunctionKinds
FunctionKinds
Each entry here represents the kinds of supported instrumentation map entries.
Definition: InstrumentationMap.h:40
llvm::Expected
Tagged union holding either a T or a Error.
Definition: APFloat.h:42
STLExtras.h
llvm::DataExtractor::getU64
uint64_t getU64(uint64_t *offset_ptr, Error *Err=nullptr) const
Extract a uint64_t value from *offset_ptr.
Definition: DataExtractor.cpp:117
llvm::xray::InstrumentationMap::getFunctionId
Optional< int32_t > getFunctionId(uint64_t Addr) const
Returns an XRay computed function id, provided a function address.
Definition: InstrumentationMap.cpp:37
llvm::consumeError
void consumeError(Error Err)
Consume a Error without doing anything.
Definition: Error.h:1006
llvm::ARMBuildAttrs::Section
@ Section
Legacy Tags.
Definition: ARMBuildAttributes.h:78
llvm::xray::loadInstrumentationMap
Expected< InstrumentationMap > loadInstrumentationMap(StringRef Filename)
Loads the instrumentation map from |Filename|.
Definition: InstrumentationMap.cpp:256
llvm::Resolver
Interface for looking up the initializer for a variable name, used by Init::resolveReferences.
Definition: Record.h:2000
llvm::object::ELFRelocationRef
Definition: ELFObjectFile.h:191
E
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
llvm::xray::SledEntry::FunctionKinds::EXIT
@ EXIT
C
(vector float) vec_cmpeq(*A, *B) C
Definition: README_ALTIVEC.txt:86
Twine.h
llvm::errorCodeToError
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition: Error.cpp:87
Y
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml", "ocaml 3.10-compatible collector")
llvm::sys::fs::openNativeFileForRead
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.
llvm::None
const NoneType None
Definition: None.h:23
llvm::lltok::Kind
Kind
Definition: LLToken.h:18
llvm::xray::InstrumentationMap::SledContainer
std::vector< SledEntry > SledContainer
Definition: InstrumentationMap.h:79
llvm::object::SectionRef
This is a value type class that represents a single section in the list of sections in the object fil...
Definition: ObjectFile.h:80
llvm::object::SupportsRelocation
bool(*)(uint64_t) SupportsRelocation
Definition: RelocationResolver.h:34
llvm::Triple::ppc64le
@ ppc64le
Definition: Triple.h:70
llvm::tgtok::In
@ In
Definition: TGLexer.h:51
readonly
This currently compiles esp xmm0 movsd esp eax eax esp ret We should use not the dag combiner This is because dagcombine2 needs to be able to see through the X86ISD::Wrapper which DAGCombine can t really do The code for turning x load into a single vector load is target independent and should be moved to the dag combiner The code for turning x load into a vector load can only handle a direct load from a global or a direct load from the stack It should be generalized to handle any load from where P can be anything The alignment inference code cannot handle loads from globals in static non mode because it doesn t look through the extra dyld stub load If you try vec_align ll without relocation you ll see what I mean We should lower which eliminates a constant pool load For float z nounwind readonly
Definition: README-SSE.txt:421
Addr
uint64_t Addr
Definition: ELFObjHandler.cpp:80
llvm::Triple::isArch32Bit
bool isArch32Bit() const
Test whether the architecture is 32-bit.
Definition: Triple.cpp:1340
move
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
Definition: README.txt:546
llvm::xray::SledEntry::FunctionKinds::CUSTOM_EVENT
@ CUSTOM_EVENT
llvm::DenseMap
Definition: DenseMap.h:714
I
#define I(x, y, z)
Definition: MD5.cpp:59
FuncId
Profile::FuncID FuncId
Definition: Profile.cpp:321
loadYAML
static Error loadYAML(sys::fs::file_t Fd, size_t FileSize, StringRef Filename, InstrumentationMap::SledContainer &Sleds, InstrumentationMap::FunctionAddressMap &FunctionAddresses, InstrumentationMap::FunctionAddressReverseMap &FunctionIds)
Definition: InstrumentationMap.cpp:223
llvm::HighlightColor::Address
@ Address
llvm::DenseMapBase::find
iterator find(const_arg_type_t< KeyT > Val)
Definition: DenseMap.h:150
llvm::object::ObjectFile::createObjectFile
static Expected< OwningBinary< ObjectFile > > createObjectFile(StringRef ObjectPath)
Definition: ObjectFile.cpp:184
ObjectFile.h
llvm::object::Binary::isELF
bool isELF() const
Definition: Binary.h:120
llvm::sys::fs::closeFile
std::error_code closeFile(file_t &F)
Close the file object.
llvm::object::getRelocationResolver
std::pair< SupportsRelocation, RelocationResolver > getRelocationResolver(const ObjectFile &Obj)
Definition: RelocationResolver.cpp:640
llvm::StringRef::bytes_begin
const unsigned char * bytes_begin() const
Definition: StringRef.h:132
llvm::object::ObjectFile::makeTriple
Triple makeTriple() const
Create a triple from the data in this object file.
Definition: ObjectFile.cpp:104
Triple.h
YAMLTraits.h
llvm::DataExtractor::getU32
uint32_t getU32(uint64_t *offset_ptr, Error *Err=nullptr) const
Extract a uint32_t value from *offset_ptr.
Definition: DataExtractor.cpp:108
RelocationResolver.h
llvm::sys::fs::mapped_file_region::data
char * data() const
Definition: Path.cpp:1160
None.h
llvm::Triple::arm
@ arm
Definition: Triple.h:50
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:58
llvm::object::ObjectFile
This class is the base class for all object file types.
Definition: ObjectFile.h:228
llvm::xray::SledEntry::FunctionKinds::ENTRY
@ ENTRY
uint32_t
llvm::xray::SledEntry::FunctionKinds::TAIL
@ TAIL
llvm::DenseMapBase::insert
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition: DenseMap.h:207
llvm::DataExtractor::getU8
uint8_t getU8(uint64_t *offset_ptr, Error *Err=nullptr) const
Extract a uint8_t value from *offset_ptr.
Definition: DataExtractor.cpp:80
ELFObjectFile.h
llvm::make_error_code
std::error_code make_error_code(BitcodeError E)
Definition: BitcodeReader.h:270
llvm::find_if
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1509
llvm::Twine
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:80
llvm::xray::SledEntry::FunctionKinds::LOG_ARGS_ENTER
@ LOG_ARGS_ENTER
llvm::object::OwningBinary
Definition: RuntimeDyld.h:36
llvm::DenseMapBase::end
iterator end()
Definition: DenseMap.h:83
llvm::Error
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
DataExtractor.h
llvm::sys::fs::mapped_file_region::size
size_t size() const
Definition: Path.cpp:1155
llvm::xray::SledEntry
Represents an XRay instrumentation sled entry from an object file.
Definition: InstrumentationMap.h:37
llvm::object::Binary::isMachO
bool isMachO() const
Definition: Binary.h:124
loadObj
static Error loadObj(StringRef Filename, object::OwningBinary< object::ObjectFile > &ObjFile, InstrumentationMap::SledContainer &Sleds, InstrumentationMap::FunctionAddressMap &FunctionAddresses, InstrumentationMap::FunctionAddressReverseMap &FunctionIds)
Definition: InstrumentationMap.cpp:54
llvm::Expected::takeError
Error takeError()
Take ownership of the stored error.
Definition: Error.h:557
llvm::sys::fs::mapped_file_region
This class represents a memory mapped file.
Definition: FileSystem.h:1246
Binary.h
llvm::sys::fs::file_size
std::error_code file_size(const Twine &Path, uint64_t &Result)
Get file size.
Definition: FileSystem.h:691
llvm::DataExtractor
Definition: DataExtractor.h:41
llvm::object::ObjectFile::sections
section_iterator_range sections() const
Definition: ObjectFile.h:322
llvm::object::RelocationRef
This is a value type class that represents a single relocation in the list of relocations in the obje...
Definition: ObjectFile.h:51
llvm::object::ELFRelocationRef::getAddend
Expected< int64_t > getAddend() const
Definition: ELFObjectFile.h:201
llvm::xray::InstrumentationMap::FunctionAddressMap
std::unordered_map< int32_t, uint64_t > FunctionAddressMap
Definition: InstrumentationMap.h:77
InstrumentationMap.h
llvm::Triple::aarch64
@ aarch64
Definition: Triple.h:52
llvm::xray::InstrumentationMap::FunctionAddressReverseMap
std::unordered_map< uint64_t, int32_t > FunctionAddressReverseMap
Definition: InstrumentationMap.h:78
llvm::object::resolveRelocation
uint64_t resolveRelocation(RelocationResolver Resolver, const RelocationRef &R, uint64_t S, uint64_t LocData)
Definition: RelocationResolver.cpp:731
llvm::StringRef::bytes_end
const unsigned char * bytes_end() const
Definition: StringRef.h:135