diff options
Diffstat (limited to 'contrib/llvm/lib/XRay/InstrumentationMap.cpp')
-rw-r--r-- | contrib/llvm/lib/XRay/InstrumentationMap.cpp | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/contrib/llvm/lib/XRay/InstrumentationMap.cpp b/contrib/llvm/lib/XRay/InstrumentationMap.cpp new file mode 100644 index 0000000..d9ce255 --- /dev/null +++ b/contrib/llvm/lib/XRay/InstrumentationMap.cpp @@ -0,0 +1,198 @@ +//===- InstrumentationMap.cpp - XRay Instrumentation Map ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implementation of the InstrumentationMap type for XRay sleds. +// +//===----------------------------------------------------------------------===// + +#include "llvm/XRay/InstrumentationMap.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Object/Binary.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/YAMLTraits.h" +#include <algorithm> +#include <cstddef> +#include <cstdint> +#include <system_error> +#include <vector> + +using namespace llvm; +using namespace xray; + +Optional<int32_t> InstrumentationMap::getFunctionId(uint64_t Addr) const { + auto I = FunctionIds.find(Addr); + if (I != FunctionIds.end()) + return I->second; + return None; +} + +Optional<uint64_t> InstrumentationMap::getFunctionAddr(int32_t FuncId) const { + auto I = FunctionAddresses.find(FuncId); + if (I != FunctionAddresses.end()) + return I->second; + return None; +} + +static Error +loadELF64(StringRef Filename, object::OwningBinary<object::ObjectFile> &ObjFile, + InstrumentationMap::SledContainer &Sleds, + InstrumentationMap::FunctionAddressMap &FunctionAddresses, + InstrumentationMap::FunctionAddressReverseMap &FunctionIds) { + InstrumentationMap Map; + + // Find the section named "xray_instr_map". + if (!ObjFile.getBinary()->isELF() || + !(ObjFile.getBinary()->getArch() == Triple::x86_64 || + ObjFile.getBinary()->getArch() == Triple::ppc64le)) + return make_error<StringError>( + "File format not supported (only does ELF little endian 64-bit).", + std::make_error_code(std::errc::not_supported)); + + StringRef Contents = ""; + const auto &Sections = ObjFile.getBinary()->sections(); + auto I = llvm::find_if(Sections, [&](object::SectionRef Section) { + StringRef Name = ""; + if (Section.getName(Name)) + return false; + return Name == "xray_instr_map"; + }); + + if (I == Sections.end()) + return make_error<StringError>( + "Failed to find XRay instrumentation map.", + std::make_error_code(std::errc::executable_format_error)); + + if (I->getContents(Contents)) + return errorCodeToError( + std::make_error_code(std::errc::executable_format_error)); + + // Copy the instrumentation map data into the Sleds data structure. + auto C = Contents.bytes_begin(); + static constexpr size_t ELF64SledEntrySize = 32; + + if ((C - Contents.bytes_end()) % ELF64SledEntrySize != 0) + return make_error<StringError>( + Twine("Instrumentation map entries not evenly divisible by size of " + "an XRay sled entry in ELF64."), + std::make_error_code(std::errc::executable_format_error)); + + int32_t FuncId = 1; + uint64_t CurFn = 0; + for (; C != Contents.bytes_end(); C += ELF64SledEntrySize) { + DataExtractor Extractor( + StringRef(reinterpret_cast<const char *>(C), ELF64SledEntrySize), true, + 8); + Sleds.push_back({}); + auto &Entry = Sleds.back(); + uint32_t OffsetPtr = 0; + Entry.Address = Extractor.getU64(&OffsetPtr); + Entry.Function = Extractor.getU64(&OffsetPtr); + auto Kind = Extractor.getU8(&OffsetPtr); + static constexpr SledEntry::FunctionKinds Kinds[] = { + SledEntry::FunctionKinds::ENTRY, SledEntry::FunctionKinds::EXIT, + SledEntry::FunctionKinds::TAIL, + }; + if (Kind >= sizeof(Kinds)) + return errorCodeToError( + std::make_error_code(std::errc::executable_format_error)); + Entry.Kind = Kinds[Kind]; + Entry.AlwaysInstrument = Extractor.getU8(&OffsetPtr) != 0; + + // We do replicate the function id generation scheme implemented in the + // XRay runtime. + // FIXME: Figure out how to keep this consistent with the XRay runtime. + if (CurFn == 0) { + CurFn = Entry.Function; + FunctionAddresses[FuncId] = Entry.Function; + FunctionIds[Entry.Function] = FuncId; + } + if (Entry.Function != CurFn) { + ++FuncId; + CurFn = Entry.Function; + FunctionAddresses[FuncId] = Entry.Function; + FunctionIds[Entry.Function] = FuncId; + } + } + return Error::success(); +} + +static Error +loadYAML(int Fd, size_t FileSize, StringRef Filename, + InstrumentationMap::SledContainer &Sleds, + InstrumentationMap::FunctionAddressMap &FunctionAddresses, + InstrumentationMap::FunctionAddressReverseMap &FunctionIds) { + std::error_code EC; + sys::fs::mapped_file_region MappedFile( + Fd, sys::fs::mapped_file_region::mapmode::readonly, FileSize, 0, EC); + if (EC) + return make_error<StringError>( + Twine("Failed memory-mapping file '") + Filename + "'.", EC); + + std::vector<YAMLXRaySledEntry> YAMLSleds; + yaml::Input In(StringRef(MappedFile.data(), MappedFile.size())); + In >> YAMLSleds; + if (In.error()) + return make_error<StringError>( + Twine("Failed loading YAML document from '") + Filename + "'.", + In.error()); + + Sleds.reserve(YAMLSleds.size()); + for (const auto &Y : YAMLSleds) { + FunctionAddresses[Y.FuncId] = Y.Function; + FunctionIds[Y.Function] = Y.FuncId; + Sleds.push_back( + SledEntry{Y.Address, Y.Function, Y.Kind, Y.AlwaysInstrument}); + } + return Error::success(); +} + +// FIXME: Create error types that encapsulate a bit more information than what +// StringError instances contain. +Expected<InstrumentationMap> +llvm::xray::loadInstrumentationMap(StringRef Filename) { + // At this point we assume the file is an object file -- and if that doesn't + // work, we treat it as YAML. + // FIXME: Extend to support non-ELF and non-x86_64 binaries. + + InstrumentationMap Map; + auto ObjectFileOrError = object::ObjectFile::createObjectFile(Filename); + if (!ObjectFileOrError) { + auto E = ObjectFileOrError.takeError(); + // We try to load it as YAML if the ELF load didn't work. + int Fd; + if (sys::fs::openFileForRead(Filename, Fd)) + return std::move(E); + + uint64_t FileSize; + if (sys::fs::file_size(Filename, FileSize)) + return std::move(E); + + // If the file is empty, we return the original error. + if (FileSize == 0) + return std::move(E); + + // From this point on the errors will be only for the YAML parts, so we + // consume the errors at this point. + consumeError(std::move(E)); + if (auto E = loadYAML(Fd, FileSize, Filename, Map.Sleds, + Map.FunctionAddresses, Map.FunctionIds)) + return std::move(E); + } else if (auto E = loadELF64(Filename, *ObjectFileOrError, Map.Sleds, + Map.FunctionAddresses, Map.FunctionIds)) { + return std::move(E); + } + return Map; +} |