LLVM  14.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 (Error E = I->getContents().moveInto(Contents))
90  return E;
91 
92  RelocMap Relocs;
93  if (ObjFile.getBinary()->isELF()) {
94  uint32_t RelativeRelocation = [](object::ObjectFile *ObjFile) {
95  if (const auto *ELFObj = dyn_cast<object::ELF32LEObjectFile>(ObjFile))
96  return ELFObj->getELFFile().getRelativeRelocationType();
97  else if (const auto *ELFObj =
98  dyn_cast<object::ELF32BEObjectFile>(ObjFile))
99  return ELFObj->getELFFile().getRelativeRelocationType();
100  else if (const auto *ELFObj =
101  dyn_cast<object::ELF64LEObjectFile>(ObjFile))
102  return ELFObj->getELFFile().getRelativeRelocationType();
103  else if (const auto *ELFObj =
104  dyn_cast<object::ELF64BEObjectFile>(ObjFile))
105  return ELFObj->getELFFile().getRelativeRelocationType();
106  else
107  return static_cast<uint32_t>(0);
108  }(ObjFile.getBinary());
109 
112  std::tie(Supports, Resolver) =
114 
115  for (const object::SectionRef &Section : Sections) {
116  for (const object::RelocationRef &Reloc : Section.relocations()) {
117  if (ObjFile.getBinary()->getArch() == Triple::arm) {
118  if (Supports && Supports(Reloc.getType())) {
119  Expected<uint64_t> ValueOrErr = Reloc.getSymbol()->getValue();
120  if (!ValueOrErr)
121  return ValueOrErr.takeError();
122  Relocs.insert(
123  {Reloc.getOffset(),
124  object::resolveRelocation(Resolver, Reloc, *ValueOrErr, 0)});
125  }
126  } else if (Supports && Supports(Reloc.getType())) {
127  auto AddendOrErr = object::ELFRelocationRef(Reloc).getAddend();
128  auto A = AddendOrErr ? *AddendOrErr : 0;
129  Expected<uint64_t> ValueOrErr = Reloc.getSymbol()->getValue();
130  if (!ValueOrErr)
131  // TODO: Test this error.
132  return ValueOrErr.takeError();
133  Relocs.insert(
134  {Reloc.getOffset(),
135  object::resolveRelocation(Resolver, Reloc, *ValueOrErr, A)});
136  } else if (Reloc.getType() == RelativeRelocation) {
137  if (auto AddendOrErr = object::ELFRelocationRef(Reloc).getAddend())
138  Relocs.insert({Reloc.getOffset(), *AddendOrErr});
139  }
140  }
141  }
142  }
143 
144  // Copy the instrumentation map data into the Sleds data structure.
145  auto C = Contents.bytes_begin();
146  bool Is32Bit = ObjFile.getBinary()->makeTriple().isArch32Bit();
147  size_t ELFSledEntrySize = Is32Bit ? 16 : 32;
148 
149  if ((C - Contents.bytes_end()) % ELFSledEntrySize != 0)
150  return make_error<StringError>(
151  Twine("Instrumentation map entries not evenly divisible by size of "
152  "an XRay sled entry."),
153  std::make_error_code(std::errc::executable_format_error));
154 
155  auto RelocateOrElse = [&](uint64_t Offset, uint64_t Address) {
156  if (!Address) {
157  uint64_t A = I->getAddress() + C - Contents.bytes_begin() + Offset;
158  RelocMap::const_iterator R = Relocs.find(A);
159  if (R != Relocs.end())
160  return R->second;
161  }
162  return Address;
163  };
164 
165  const int WordSize = Is32Bit ? 4 : 8;
166  int32_t FuncId = 1;
167  uint64_t CurFn = 0;
168  for (; C != Contents.bytes_end(); C += ELFSledEntrySize) {
169  DataExtractor Extractor(
170  StringRef(reinterpret_cast<const char *>(C), ELFSledEntrySize), true,
171  8);
172  Sleds.push_back({});
173  auto &Entry = Sleds.back();
174  uint64_t OffsetPtr = 0;
175  uint64_t AddrOff = OffsetPtr;
176  if (Is32Bit)
177  Entry.Address = RelocateOrElse(AddrOff, Extractor.getU32(&OffsetPtr));
178  else
179  Entry.Address = RelocateOrElse(AddrOff, Extractor.getU64(&OffsetPtr));
180  uint64_t FuncOff = OffsetPtr;
181  if (Is32Bit)
182  Entry.Function = RelocateOrElse(FuncOff, Extractor.getU32(&OffsetPtr));
183  else
184  Entry.Function = RelocateOrElse(FuncOff, Extractor.getU64(&OffsetPtr));
185  auto Kind = Extractor.getU8(&OffsetPtr);
186  static constexpr SledEntry::FunctionKinds Kinds[] = {
191  if (Kind >= sizeof(Kinds) / sizeof(Kinds[0]))
192  return errorCodeToError(
193  std::make_error_code(std::errc::executable_format_error));
194  Entry.Kind = Kinds[Kind];
195  Entry.AlwaysInstrument = Extractor.getU8(&OffsetPtr) != 0;
196  Entry.Version = Extractor.getU8(&OffsetPtr);
197  if (Entry.Version >= 2) {
198  Entry.Address += C - Contents.bytes_begin() + Address;
199  Entry.Function += C - Contents.bytes_begin() + WordSize + Address;
200  }
201 
202  // We do replicate the function id generation scheme implemented in the
203  // XRay runtime.
204  // FIXME: Figure out how to keep this consistent with the XRay runtime.
205  if (CurFn == 0) {
206  CurFn = Entry.Function;
207  FunctionAddresses[FuncId] = Entry.Function;
208  FunctionIds[Entry.Function] = FuncId;
209  }
210  if (Entry.Function != CurFn) {
211  ++FuncId;
212  CurFn = Entry.Function;
213  FunctionAddresses[FuncId] = Entry.Function;
214  FunctionIds[Entry.Function] = FuncId;
215  }
216  }
217  return Error::success();
218 }
219 
220 static Error
221 loadYAML(sys::fs::file_t Fd, size_t FileSize, StringRef Filename,
223  InstrumentationMap::FunctionAddressMap &FunctionAddresses,
225  std::error_code EC;
226  sys::fs::mapped_file_region MappedFile(
228  sys::fs::closeFile(Fd);
229  if (EC)
230  return make_error<StringError>(
231  Twine("Failed memory-mapping file '") + Filename + "'.", EC);
232 
233  std::vector<YAMLXRaySledEntry> YAMLSleds;
234  yaml::Input In(StringRef(MappedFile.data(), MappedFile.size()));
235  In >> YAMLSleds;
236  if (In.error())
237  return make_error<StringError>(
238  Twine("Failed loading YAML document from '") + Filename + "'.",
239  In.error());
240 
241  Sleds.reserve(YAMLSleds.size());
242  for (const auto &Y : YAMLSleds) {
243  FunctionAddresses[Y.FuncId] = Y.Function;
244  FunctionIds[Y.Function] = Y.FuncId;
245  Sleds.push_back(SledEntry{Y.Address, Y.Function, Y.Kind, Y.AlwaysInstrument,
246  Y.Version});
247  }
248  return Error::success();
249 }
250 
251 // FIXME: Create error types that encapsulate a bit more information than what
252 // StringError instances contain.
255  // At this point we assume the file is an object file -- and if that doesn't
256  // work, we treat it as YAML.
257  // FIXME: Extend to support non-ELF and non-x86_64 binaries.
258 
259  InstrumentationMap Map;
260  auto ObjectFileOrError = object::ObjectFile::createObjectFile(Filename);
261  if (!ObjectFileOrError) {
262  auto E = ObjectFileOrError.takeError();
263  // We try to load it as YAML if the ELF load didn't work.
264  Expected<sys::fs::file_t> FdOrErr =
266  if (!FdOrErr) {
267  // Report the ELF load error if YAML failed.
268  consumeError(FdOrErr.takeError());
269  return std::move(E);
270  }
271 
272  uint64_t FileSize;
273  if (sys::fs::file_size(Filename, FileSize))
274  return std::move(E);
275 
276  // If the file is empty, we return the original error.
277  if (FileSize == 0)
278  return std::move(E);
279 
280  // From this point on the errors will be only for the YAML parts, so we
281  // consume the errors at this point.
283  if (auto E = loadYAML(*FdOrErr, FileSize, Filename, Map.Sleds,
284  Map.FunctionAddresses, Map.FunctionIds))
285  return std::move(E);
286  } else if (auto E = loadObj(Filename, *ObjectFileOrError, Map.Sleds,
287  Map.FunctionAddresses, Map.FunctionIds)) {
288  return std::move(E);
289  }
290  return Map;
291 }
llvm::sys::fs::file_t
int file_t
Definition: FileSystem.h:60
llvm
This is an optimization pass for GlobalISel generic memory operations.
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:331
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:1045
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:254
llvm::Resolver
Interface for looking up the initializer for a variable name, used by Init::resolveReferences.
Definition: Record.h:2013
llvm::object::ELFRelocationRef
Definition: ELFObjectFile.h:195
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:90
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
uint64_t
Addr
uint64_t Addr
Definition: ELFObjHandler.cpp:80
llvm::Triple::isArch32Bit
bool isArch32Bit() const
Test whether the architecture is 32-bit.
Definition: Triple.cpp:1387
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:221
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:186
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:645
llvm::StringRef::bytes_begin
const unsigned char * bytes_begin() const
Definition: StringRef.h:131
llvm::object::ObjectFile::makeTriple
Triple makeTriple() const
Create a triple from the data in this object file.
Definition: ObjectFile.cpp:105
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:57
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:1608
llvm::Twine
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:83
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:599
llvm::sys::fs::mapped_file_region
This class represents a memory mapped file.
Definition: FileSystem.h:1250
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:205
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:736
llvm::StringRef::bytes_end
const unsigned char * bytes_end() const
Definition: StringRef.h:134