Index: llvm/trunk/include/llvm/XRay/InstrumentationMap.h =================================================================== --- llvm/trunk/include/llvm/XRay/InstrumentationMap.h +++ llvm/trunk/include/llvm/XRay/InstrumentationMap.h @@ -0,0 +1,131 @@ +//===- InstrumentationMap.h - XRay Instrumentation Map --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines the interface for extracting the instrumentation map from an +// XRay-instrumented binary. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_XRAY_INSTRUMENTATION_MAP_H +#define LLVM_XRAY_INSTRUMENTATION_MAP_H + +#include +#include +#include + +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/YAMLTraits.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { +namespace xray { + +// Forward declare to make a friend. +class InstrumentationMap; + +/// Loads the instrumentation map from |Filename|. This auto-deduces the type of +/// the instrumentation map. +Expected loadInstrumentationMap(StringRef Filename); + +/// Represents an XRay instrumentation sled entry from an object file. +struct SledEntry { + + /// Each entry here represents the kinds of supported instrumentation map + /// entries. + enum class FunctionKinds { ENTRY, EXIT, TAIL }; + + /// The address of the sled. + uint64_t Address; + + /// The address of the function. + uint64_t Function; + + /// The kind of sled. + FunctionKinds Kind; + + /// Whether the sled was annotated to always be instrumented. + bool AlwaysInstrument; +}; + +struct YAMLXRaySledEntry { + int32_t FuncId; + yaml::Hex64 Address; + yaml::Hex64 Function; + SledEntry::FunctionKinds Kind; + bool AlwaysInstrument; +}; + +/// The InstrumentationMap represents the computed function id's and indicated +/// function addresses from an object file (or a YAML file). This provides an +/// interface to just the mapping between the function id, and the function +/// address. +/// +/// We also provide raw access to the actual instrumentation map entries we find +/// associated with a particular object file. +/// +class InstrumentationMap { +public: + using FunctionAddressMap = std::unordered_map; + using FunctionAddressReverseMap = std::unordered_map; + using SledContainer = std::vector; + +private: + SledContainer Sleds; + FunctionAddressMap FunctionAddresses; + FunctionAddressReverseMap FunctionIds; + + friend Expected loadInstrumentationMap(StringRef); + +public: + /// Provides a raw accessor to the unordered map of function addresses. + const FunctionAddressMap &getFunctionAddresses() { return FunctionAddresses; } + + /// Returns an XRay computed function id, provided a function address. + Optional getFunctionId(uint64_t Addr) const; + + /// Returns the function address for a function id. + Optional getFunctionAddr(int32_t FuncId) const; + + /// Provide read-only access to the entries of the instrumentation map. + const SledContainer &sleds() const { return Sleds; }; +}; + +} // namespace xray +} // namespace llvm + +namespace llvm { +namespace yaml { + +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &IO, xray::SledEntry::FunctionKinds &Kind) { + IO.enumCase(Kind, "function-enter", xray::SledEntry::FunctionKinds::ENTRY); + IO.enumCase(Kind, "function-exit", xray::SledEntry::FunctionKinds::EXIT); + IO.enumCase(Kind, "tail-exit", xray::SledEntry::FunctionKinds::TAIL); + } +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, xray::YAMLXRaySledEntry &Entry) { + IO.mapRequired("id", Entry.FuncId); + IO.mapRequired("address", Entry.Address); + IO.mapRequired("function", Entry.Function); + IO.mapRequired("kind", Entry.Kind); + IO.mapRequired("always-instrument", Entry.AlwaysInstrument); + } + + static constexpr bool flow = true; +}; +} // namespace yaml +} // namespace llvm + +LLVM_YAML_IS_SEQUENCE_VECTOR(xray::YAMLXRaySledEntry) + +#endif // LLVM_XRAY_INSTRUMENTATION_MAP_H Index: llvm/trunk/lib/XRay/CMakeLists.txt =================================================================== --- llvm/trunk/lib/XRay/CMakeLists.txt +++ llvm/trunk/lib/XRay/CMakeLists.txt @@ -1,4 +1,5 @@ add_llvm_library(LLVMXRay + InstrumentationMap.cpp Trace.cpp ADDITIONAL_HEADER_DIRS @@ -7,7 +8,9 @@ DEPENDS LLVMSupport + LLVMObject LINK_LIBS LLVMSupport + LLVMObject ) Index: llvm/trunk/lib/XRay/InstrumentationMap.cpp =================================================================== --- llvm/trunk/lib/XRay/InstrumentationMap.cpp +++ llvm/trunk/lib/XRay/InstrumentationMap.cpp @@ -0,0 +1,194 @@ +//===- 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. +// +//===----------------------------------------------------------------------===// + +#ifndef XRAY_INSTRUMENTATIONMAP_H +#define XRAY_INSTRUMENTATIONMAP_H + +#include "llvm/XRay/InstrumentationMap.h" + +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/XRay/XRayRecord.h" +#include + +namespace llvm { +namespace xray { + +Optional InstrumentationMap::getFunctionId(uint64_t Addr) const { + auto I = FunctionIds.find(Addr); + if (I != FunctionIds.end()) + return I->second; + return None; +} + +Optional InstrumentationMap::getFunctionAddr(int32_t FuncId) const { + auto I = FunctionAddresses.find(FuncId); + if (I != FunctionAddresses.end()) + return I->second; + return None; +} + +namespace { +Error loadELF64(StringRef Filename, + object::OwningBinary &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) + return make_error( + "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 = 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( + "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( + 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(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(); +} + +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( + Twine("Failed memory-mapping file '") + Filename + "'.", EC); + + std::vector YAMLSleds; + yaml::Input In(StringRef(MappedFile.data(), MappedFile.size())); + In >> YAMLSleds; + if (In.error()) + return make_error( + 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(); +} +} // namespace + +// FIXME: Create error types that encapsulate a bit more information than what +// StringError instances contain. +Expected 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; +} +} +} + +#endif // XRAY_INSTRUMENTATIONMAP_H Index: llvm/trunk/test/tools/llvm-xray/X86/account-deduce-tail-call.yaml =================================================================== --- llvm/trunk/test/tools/llvm-xray/X86/account-deduce-tail-call.yaml +++ llvm/trunk/test/tools/llvm-xray/X86/account-deduce-tail-call.yaml @@ -1,4 +1,4 @@ -#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -d | FileCheck %s +#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -d | FileCheck %s --- header: version: 1 Index: llvm/trunk/test/tools/llvm-xray/X86/account-keep-going.yaml =================================================================== --- llvm/trunk/test/tools/llvm-xray/X86/account-keep-going.yaml +++ llvm/trunk/test/tools/llvm-xray/X86/account-keep-going.yaml @@ -1,4 +1,4 @@ -#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -k | FileCheck %s +#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -k | FileCheck %s --- header: version: 1 Index: llvm/trunk/test/tools/llvm-xray/X86/account-simple-case.yaml =================================================================== --- llvm/trunk/test/tools/llvm-xray/X86/account-simple-case.yaml +++ llvm/trunk/test/tools/llvm-xray/X86/account-simple-case.yaml @@ -1,4 +1,4 @@ -#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml | FileCheck %s +#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml | FileCheck %s --- header: version: 1 Index: llvm/trunk/test/tools/llvm-xray/X86/account-simple-sorting.yaml =================================================================== --- llvm/trunk/test/tools/llvm-xray/X86/account-simple-sorting.yaml +++ llvm/trunk/test/tools/llvm-xray/X86/account-simple-sorting.yaml @@ -1,13 +1,13 @@ -#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml | FileCheck --check-prefix DEFAULT %s -#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -s count | FileCheck --check-prefix COUNT-ASC %s -#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -s min | FileCheck --check-prefix MIN-ASC %s -#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -s max | FileCheck --check-prefix MAX-ASC %s -#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -s sum | FileCheck --check-prefix SUM-ASC %s - -#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -s count -r dsc | FileCheck --check-prefix COUNT-DSC %s -#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -s min -r dsc | FileCheck --check-prefix MIN-DSC %s -#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -s max -r dsc | FileCheck --check-prefix MAX-DSC %s -#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -s sum -r dsc | FileCheck --check-prefix SUM-DSC %s +#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml | FileCheck --check-prefix DEFAULT %s +#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -s count | FileCheck --check-prefix COUNT-ASC %s +#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -s min | FileCheck --check-prefix MIN-ASC %s +#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -s max | FileCheck --check-prefix MAX-ASC %s +#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -s sum | FileCheck --check-prefix SUM-ASC %s + +#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -s count -r dsc | FileCheck --check-prefix COUNT-DSC %s +#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -s min -r dsc | FileCheck --check-prefix MIN-DSC %s +#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -s max -r dsc | FileCheck --check-prefix MAX-DSC %s +#RUN: llvm-xray account %s -o - -m %S/Inputs/simple-instrmap.yaml -s sum -r dsc | FileCheck --check-prefix SUM-DSC %s --- header: version: 1 Index: llvm/trunk/test/tools/llvm-xray/X86/convert-with-yaml-instrmap.txt =================================================================== --- llvm/trunk/test/tools/llvm-xray/X86/convert-with-yaml-instrmap.txt +++ llvm/trunk/test/tools/llvm-xray/X86/convert-with-yaml-instrmap.txt @@ -1,4 +1,4 @@ -; RUN: llvm-xray convert -m %S/Inputs/simple-xray-instrmap.yaml -t yaml %S/Inputs/naive-log-simple.xray -f=yaml -o - | FileCheck %s +; RUN: llvm-xray convert -m %S/Inputs/simple-xray-instrmap.yaml %S/Inputs/naive-log-simple.xray -f=yaml -o - | FileCheck %s ; CHECK: --- ; CHECK-NEXT: header: Index: llvm/trunk/test/tools/llvm-xray/X86/graph-color-simple-case.yaml =================================================================== --- llvm/trunk/test/tools/llvm-xray/X86/graph-color-simple-case.yaml +++ llvm/trunk/test/tools/llvm-xray/X86/graph-color-simple-case.yaml @@ -1,6 +1,6 @@ -#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -e sum -c sum \ +#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -e sum -c sum \ #RUN: | FileCheck %s -check-prefix=EDGE -#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -v sum -b sum \ +#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -v sum -b sum \ #RUN: | FileCheck %s -check-prefix=VERTEX --- header: Index: llvm/trunk/test/tools/llvm-xray/X86/graph-deduce-tail-call.yaml =================================================================== --- llvm/trunk/test/tools/llvm-xray/X86/graph-deduce-tail-call.yaml +++ llvm/trunk/test/tools/llvm-xray/X86/graph-deduce-tail-call.yaml @@ -1,19 +1,19 @@ -#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -d \ +#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -d \ #RUN: | FileCheck %s -check-prefix=EMPTY -#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -d -e count \ +#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -d -e count \ #RUN: | FileCheck %s -check-prefix=COUNT # -#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -d -e min \ +#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -d -e min \ #RUN: | FileCheck %s -check-prefix=TIME -#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -d -e med \ +#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -d -e med \ #RUN: | FileCheck %s -check-prefix=TIME -#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -d -e 90p \ +#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -d -e 90p \ #RUN: | FileCheck %s -check-prefix=TIME -#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -d -e 99p \ +#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -d -e 99p \ #RUN: | FileCheck %s -check-prefix=TIME -#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -d -e max \ +#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -d -e max \ #RUN: | FileCheck %s -check-prefix=TIME -#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -d -e sum \ +#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -d -e sum \ #RUN: | FileCheck %s -check-prefix=TIME # --- Index: llvm/trunk/test/tools/llvm-xray/X86/graph-simple-case.yaml =================================================================== --- llvm/trunk/test/tools/llvm-xray/X86/graph-simple-case.yaml +++ llvm/trunk/test/tools/llvm-xray/X86/graph-simple-case.yaml @@ -1,19 +1,19 @@ -#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml \ +#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml \ #RUN: | FileCheck %s -check-prefix=EMPTY -#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -e count \ +#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -e count \ #RUN: | FileCheck %s -check-prefix=COUNT # -#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -e min \ +#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -e min \ #RUN: | FileCheck %s -check-prefix=TIME -#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -e med \ +#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -e med \ #RUN: | FileCheck %s -check-prefix=TIME -#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -e 90p \ +#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -e 90p \ #RUN: | FileCheck %s -check-prefix=TIME -#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -e 99p \ +#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -e 99p \ #RUN: | FileCheck %s -check-prefix=TIME -#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -e max \ +#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -e max \ #RUN: | FileCheck %s -check-prefix=TIME -#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -t yaml -e sum \ +#RUN: llvm-xray graph %s -o - -m %S/Inputs/simple-instrmap.yaml -e sum \ #RUN: | FileCheck %s -check-prefix=TIME --- header: Index: llvm/trunk/tools/llvm-xray/xray-account.cc =================================================================== --- llvm/trunk/tools/llvm-xray/xray-account.cc +++ llvm/trunk/tools/llvm-xray/xray-account.cc @@ -18,10 +18,10 @@ #include #include "xray-account.h" -#include "xray-extract.h" #include "xray-registry.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormatVariadic.h" +#include "llvm/XRay/InstrumentationMap.h" #include "llvm/XRay/Trace.h" using namespace llvm; @@ -120,16 +120,6 @@ static cl::alias AccountInstrMap2("m", cl::aliasopt(AccountInstrMap), cl::desc("Alias for -instr_map"), cl::sub(Account)); -static cl::opt InstrMapFormat( - "instr-map-format", cl::desc("format of instrumentation map"), - cl::values(clEnumValN(InstrumentationMapExtractor::InputFormats::ELF, "elf", - "instrumentation map in an ELF header"), - clEnumValN(InstrumentationMapExtractor::InputFormats::YAML, - "yaml", "instrumentation map in YAML")), - cl::sub(Account), cl::init(InstrumentationMapExtractor::InputFormats::ELF)); -static cl::alias InstrMapFormat2("t", cl::aliasopt(InstrMapFormat), - cl::desc("Alias for -instr-map-format"), - cl::sub(Account)); namespace { @@ -418,67 +408,63 @@ using namespace llvm::xray; static CommandRegistration Unused(&Account, []() -> Error { - int Fd; - auto EC = sys::fs::openFileForRead(AccountInput, Fd); - if (EC) - return make_error( - Twine("Cannot open file '") + AccountInput + "'", EC); - - Error Err = Error::success(); - xray::InstrumentationMapExtractor Extractor(AccountInstrMap, InstrMapFormat, - Err); - if (auto E = handleErrors( - std::move(Err), [&](std::unique_ptr SE) -> Error { - if (SE->convertToErrorCode() == std::errc::no_such_file_or_directory) - return Error::success(); - return Error(std::move(SE)); - })) - return E; + InstrumentationMap Map; + if (!AccountInstrMap.empty()) { + auto InstrumentationMapOrError = loadInstrumentationMap(AccountInstrMap); + if (!InstrumentationMapOrError) + return joinErrors(make_error( + Twine("Cannot open instrumentation map '") + + AccountInstrMap + "'", + std::make_error_code(std::errc::invalid_argument)), + InstrumentationMapOrError.takeError()); + Map = std::move(*InstrumentationMapOrError); + } + std::error_code EC; raw_fd_ostream OS(AccountOutput, EC, sys::fs::OpenFlags::F_Text); if (EC) return make_error( Twine("Cannot open file '") + AccountOutput + "' for writing.", EC); - const auto &FunctionAddresses = Extractor.getFunctionAddresses(); + const auto &FunctionAddresses = Map.getFunctionAddresses(); symbolize::LLVMSymbolizer::Options Opts( symbolize::FunctionNameKind::LinkageName, true, true, false, ""); symbolize::LLVMSymbolizer Symbolizer(Opts); llvm::xray::FuncIdConversionHelper FuncIdHelper(AccountInstrMap, Symbolizer, FunctionAddresses); xray::LatencyAccountant FCA(FuncIdHelper, AccountDeduceSiblingCalls); - if (auto TraceOrErr = loadTraceFile(AccountInput)) { - auto &T = *TraceOrErr; - for (const auto &Record : T) { - if (FCA.accountRecord(Record)) - continue; - for (const auto &ThreadStack : FCA.getPerThreadFunctionStack()) { - errs() << "Thread ID: " << ThreadStack.first << "\n"; - auto Level = ThreadStack.second.size(); - for (const auto &Entry : llvm::reverse(ThreadStack.second)) - errs() << "#" << Level-- << "\t" - << FuncIdHelper.SymbolOrNumber(Entry.first) << '\n'; - } - if (!AccountKeepGoing) - return make_error( - Twine("Failed accounting function calls in file '") + AccountInput + - "'.", - std::make_error_code(std::errc::executable_format_error)); - } - switch (AccountOutputFormat) { - case AccountOutputFormats::TEXT: - FCA.exportStatsAsText(OS, T.getFileHeader()); - break; - case AccountOutputFormats::CSV: - FCA.exportStatsAsCSV(OS, T.getFileHeader()); - break; - } - } else { + auto TraceOrErr = loadTraceFile(AccountInput); + if (!TraceOrErr) return joinErrors( make_error( Twine("Failed loading input file '") + AccountInput + "'", std::make_error_code(std::errc::executable_format_error)), TraceOrErr.takeError()); + + auto &T = *TraceOrErr; + for (const auto &Record : T) { + if (FCA.accountRecord(Record)) + continue; + for (const auto &ThreadStack : FCA.getPerThreadFunctionStack()) { + errs() << "Thread ID: " << ThreadStack.first << "\n"; + auto Level = ThreadStack.second.size(); + for (const auto &Entry : llvm::reverse(ThreadStack.second)) + errs() << "#" << Level-- << "\t" + << FuncIdHelper.SymbolOrNumber(Entry.first) << '\n'; + } + if (!AccountKeepGoing) + return make_error( + Twine("Failed accounting function calls in file '") + AccountInput + + "'.", + std::make_error_code(std::errc::executable_format_error)); + } + switch (AccountOutputFormat) { + case AccountOutputFormats::TEXT: + FCA.exportStatsAsText(OS, T.getFileHeader()); + break; + case AccountOutputFormats::CSV: + FCA.exportStatsAsCSV(OS, T.getFileHeader()); + break; } return Error::success(); Index: llvm/trunk/tools/llvm-xray/xray-converter.cc =================================================================== --- llvm/trunk/tools/llvm-xray/xray-converter.cc +++ llvm/trunk/tools/llvm-xray/xray-converter.cc @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "xray-converter.h" -#include "xray-extract.h" #include "xray-registry.h" #include "llvm/DebugInfo/Symbolize/Symbolize.h" #include "llvm/Support/EndianStream.h" @@ -20,6 +19,7 @@ #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/XRay/InstrumentationMap.h" #include "llvm/XRay/Trace.h" #include "llvm/XRay/YAMLXRayRecord.h" @@ -73,16 +73,6 @@ static cl::alias ConvertSortInput2("s", cl::aliasopt(ConvertSortInput), cl::desc("Alias for -sort"), cl::sub(Convert)); -static cl::opt InstrMapFormat( - "instr-map-format", cl::desc("format of instrumentation map"), - cl::values(clEnumValN(InstrumentationMapExtractor::InputFormats::ELF, "elf", - "instrumentation map in an ELF header"), - clEnumValN(InstrumentationMapExtractor::InputFormats::YAML, - "yaml", "instrumentation map in YAML")), - cl::sub(Convert), cl::init(InstrumentationMapExtractor::InputFormats::ELF)); -static cl::alias InstrMapFormat2("t", cl::aliasopt(InstrMapFormat), - cl::desc("Alias for -instr-map-format"), - cl::sub(Convert)); using llvm::yaml::Output; @@ -151,25 +141,26 @@ static CommandRegistration Unused(&Convert, []() -> Error { // FIXME: Support conversion to BINARY when upgrading XRay trace versions. - int Fd; - auto EC = sys::fs::openFileForRead(ConvertInput, Fd); - if (EC) - return make_error( - Twine("Cannot open file '") + ConvertInput + "'", EC); - - Error Err = Error::success(); - xray::InstrumentationMapExtractor Extractor(ConvertInstrMap, InstrMapFormat, - Err); - handleAllErrors(std::move(Err), - [&](const ErrorInfoBase &E) { E.log(errs()); }); + InstrumentationMap Map; + if (!ConvertInstrMap.empty()) { + auto InstrumentationMapOrError = loadInstrumentationMap(ConvertInstrMap); + if (!InstrumentationMapOrError) + return joinErrors(make_error( + Twine("Cannot open instrumentation map '") + + ConvertInstrMap + "'", + std::make_error_code(std::errc::invalid_argument)), + InstrumentationMapOrError.takeError()); + Map = std::move(*InstrumentationMapOrError); + } - const auto &FunctionAddresses = Extractor.getFunctionAddresses(); + const auto &FunctionAddresses = Map.getFunctionAddresses(); symbolize::LLVMSymbolizer::Options Opts( symbolize::FunctionNameKind::LinkageName, true, true, false, ""); symbolize::LLVMSymbolizer Symbolizer(Opts); llvm::xray::FuncIdConversionHelper FuncIdHelper(ConvertInstrMap, Symbolizer, FunctionAddresses); llvm::xray::TraceConverter TC(FuncIdHelper, ConvertSymbolize); + std::error_code EC; raw_fd_ostream OS(ConvertOutput, EC, ConvertOutputFormat == ConvertFormats::BINARY ? sys::fs::OpenFlags::F_None @@ -178,22 +169,22 @@ return make_error( Twine("Cannot open file '") + ConvertOutput + "' for writing.", EC); - if (auto TraceOrErr = loadTraceFile(ConvertInput, ConvertSortInput)) { - auto &T = *TraceOrErr; - switch (ConvertOutputFormat) { - case ConvertFormats::YAML: - TC.exportAsYAML(T, OS); - break; - case ConvertFormats::BINARY: - TC.exportAsRAWv1(T, OS); - break; - } - } else { + auto TraceOrErr = loadTraceFile(ConvertInput, ConvertSortInput); + if (!TraceOrErr) return joinErrors( make_error( Twine("Failed loading input file '") + ConvertInput + "'.", std::make_error_code(std::errc::executable_format_error)), TraceOrErr.takeError()); + + auto &T = *TraceOrErr; + switch (ConvertOutputFormat) { + case ConvertFormats::YAML: + TC.exportAsYAML(T, OS); + break; + case ConvertFormats::BINARY: + TC.exportAsRAWv1(T, OS); + break; } return Error::success(); }); Index: llvm/trunk/tools/llvm-xray/xray-extract.h =================================================================== --- llvm/trunk/tools/llvm-xray/xray-extract.h +++ llvm/trunk/tools/llvm-xray/xray-extract.h @@ -1,58 +0,0 @@ -//===- xray-extract.h - XRay Instrumentation Map Extraction ---------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Defines the interface for extracting the instrumentation map from an -// XRay-instrumented binary. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_XRAY_EXTRACT_H -#define LLVM_TOOLS_XRAY_EXTRACT_H - -#include -#include -#include -#include - -#include "xray-sleds.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/raw_ostream.h" - -namespace llvm { -namespace xray { - -class InstrumentationMapExtractor { -public: - typedef std::unordered_map FunctionAddressMap; - typedef std::unordered_map FunctionAddressReverseMap; - - enum class InputFormats { ELF, YAML }; - -private: - std::deque Sleds; - FunctionAddressMap FunctionAddresses; - FunctionAddressReverseMap FunctionIds; - -public: - /// Loads the instrumentation map from |Filename|. Updates |EC| in case there - /// were errors encountered opening the file. |Format| defines what the input - /// instrumentation map is in. - InstrumentationMapExtractor(std::string Filename, InputFormats Format, - Error &EC); - - const FunctionAddressMap &getFunctionAddresses() { return FunctionAddresses; } - - /// Exports the loaded function address map as YAML through |OS|. - void exportAsYAML(raw_ostream &OS); -}; - -} // namespace xray -} // namespace llvm - -#endif // LLVM_TOOLS_XRAY_EXTRACT_H Index: llvm/trunk/tools/llvm-xray/xray-extract.cc =================================================================== --- llvm/trunk/tools/llvm-xray/xray-extract.cc +++ llvm/trunk/tools/llvm-xray/xray-extract.cc @@ -16,10 +16,7 @@ #include #include -#include "xray-extract.h" - #include "xray-registry.h" -#include "xray-sleds.h" #include "llvm/Object/ELF.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/CommandLine.h" @@ -28,8 +25,8 @@ #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" -#include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/XRay/InstrumentationMap.h" using namespace llvm; using namespace llvm::xray; @@ -49,243 +46,40 @@ cl::desc("Alias for -output"), cl::sub(Extract)); -struct YAMLXRaySledEntry { - int32_t FuncId; - Hex64 Address; - Hex64 Function; - SledEntry::FunctionKinds Kind; - bool AlwaysInstrument; -}; - -namespace llvm { -namespace yaml { - -template <> struct ScalarEnumerationTraits { - static void enumeration(IO &IO, SledEntry::FunctionKinds &Kind) { - IO.enumCase(Kind, "function-enter", SledEntry::FunctionKinds::ENTRY); - IO.enumCase(Kind, "function-exit", SledEntry::FunctionKinds::EXIT); - IO.enumCase(Kind, "tail-exit", SledEntry::FunctionKinds::TAIL); - } -}; - -template <> struct MappingTraits { - static void mapping(IO &IO, YAMLXRaySledEntry &Entry) { - IO.mapRequired("id", Entry.FuncId); - IO.mapRequired("address", Entry.Address); - IO.mapRequired("function", Entry.Function); - IO.mapRequired("kind", Entry.Kind); - IO.mapRequired("always-instrument", Entry.AlwaysInstrument); - } - - static constexpr bool flow = true; -}; -} -} - -LLVM_YAML_IS_SEQUENCE_VECTOR(YAMLXRaySledEntry) - namespace { -llvm::Error LoadBinaryInstrELF( - StringRef Filename, std::deque &OutputSleds, - InstrumentationMapExtractor::FunctionAddressMap &InstrMap, - InstrumentationMapExtractor::FunctionAddressReverseMap &FunctionIds) { - auto ObjectFile = object::ObjectFile::createObjectFile(Filename); - - if (!ObjectFile) - return ObjectFile.takeError(); - - // FIXME: Maybe support other ELF formats. For now, 64-bit Little Endian only. - if (!ObjectFile->getBinary()->isELF()) - return make_error( - "File format not supported (only does ELF).", - std::make_error_code(std::errc::not_supported)); - if (ObjectFile->getBinary()->getArch() != Triple::x86_64) - return make_error( - "File format not supported (only does ELF little endian 64-bit).", - std::make_error_code(std::errc::not_supported)); - - // Find the section named "xray_instr_map". - StringRef Contents = ""; - const auto &Sections = ObjectFile->getBinary()->sections(); - auto I = 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( - "Failed to find XRay instrumentation map.", - std::make_error_code(std::errc::not_supported)); - if (I->getContents(Contents)) - return make_error( - "Failed to get contents of 'xray_instr_map' section.", - 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( - "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; - std::deque Sleds; - for (; C != Contents.bytes_end(); C += ELF64SledEntrySize) { - DataExtractor Extractor( - StringRef(reinterpret_cast(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); - switch (Kind) { - case 0: // ENTRY - Entry.Kind = SledEntry::FunctionKinds::ENTRY; - break; - case 1: // EXIT - Entry.Kind = SledEntry::FunctionKinds::EXIT; - break; - case 2: // TAIL - Entry.Kind = SledEntry::FunctionKinds::TAIL; - break; - default: - return make_error( - Twine("Encountered unknown sled type ") + "'" + Twine(int32_t{Kind}) + - "'.", - std::make_error_code(std::errc::executable_format_error)); - } - Entry.AlwaysInstrument = Extractor.getU8(&OffsetPtr) != 0; - - // We replicate the function id generation scheme implemented in the runtime - // here. Ideally we should be able to break it out, or output this map from - // the runtime, but that's a design point we can discuss later on. For now, - // we replicate the logic and move on. - if (CurFn == 0) { - CurFn = Entry.Function; - InstrMap[FuncId] = Entry.Function; - FunctionIds[Entry.Function] = FuncId; - } - if (Entry.Function != CurFn) { - ++FuncId; - CurFn = Entry.Function; - InstrMap[FuncId] = Entry.Function; - FunctionIds[Entry.Function] = FuncId; - } - } - OutputSleds = std::move(Sleds); - return llvm::Error::success(); -} - -Error LoadYAMLInstrMap( - StringRef Filename, std::deque &Sleds, - InstrumentationMapExtractor::FunctionAddressMap &InstrMap, - InstrumentationMapExtractor::FunctionAddressReverseMap &FunctionIds) { - int Fd; - if (auto EC = sys::fs::openFileForRead(Filename, Fd)) - return make_error( - Twine("Failed opening file '") + Filename + "' for reading.", EC); - - uint64_t FileSize; - if (auto EC = sys::fs::file_size(Filename, FileSize)) - return make_error( - Twine("Failed getting size of file '") + Filename + "'.", EC); - - 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( - Twine("Failed memory-mapping file '") + Filename + "'.", EC); - - std::vector YAMLSleds; - Input In(StringRef(MappedFile.data(), MappedFile.size())); - In >> YAMLSleds; - if (In.error()) - return make_error( - Twine("Failed loading YAML document from '") + Filename + "'.", - In.error()); - - for (const auto &Y : YAMLSleds) { - InstrMap[Y.FuncId] = Y.Function; - FunctionIds[Y.Function] = Y.FuncId; - Sleds.push_back( - SledEntry{Y.Address, Y.Function, Y.Kind, Y.AlwaysInstrument}); - } - return Error::success(); -} - -} // namespace - -InstrumentationMapExtractor::InstrumentationMapExtractor(std::string Filename, - InputFormats Format, - Error &EC) { - ErrorAsOutParameter ErrAsOutputParam(&EC); - if (Filename.empty()) { - EC = Error::success(); - return; - } - switch (Format) { - case InputFormats::ELF: { - EC = handleErrors( - LoadBinaryInstrELF(Filename, Sleds, FunctionAddresses, FunctionIds), - [&](std::unique_ptr E) { - return joinErrors( - make_error( - Twine("Cannot extract instrumentation map from '") + - Filename + "'.", - std::make_error_code(std::errc::executable_format_error)), - std::move(E)); - }); - break; - } - case InputFormats::YAML: { - EC = handleErrors( - LoadYAMLInstrMap(Filename, Sleds, FunctionAddresses, FunctionIds), - [&](std::unique_ptr E) { - return joinErrors( - make_error( - Twine("Cannot load YAML instrumentation map from '") + - Filename + "'.", - std::make_error_code(std::errc::executable_format_error)), - std::move(E)); - }); - break; - } - } -} - -void InstrumentationMapExtractor::exportAsYAML(raw_ostream &OS) { +void exportAsYAML(const InstrumentationMap &Map, raw_ostream &OS) { // First we translate the sleds into the YAMLXRaySledEntry objects in a deque. std::vector YAMLSleds; - YAMLSleds.reserve(Sleds.size()); + auto Sleds = Map.sleds(); + YAMLSleds.reserve(std::distance(Sleds.begin(), Sleds.end())); for (const auto &Sled : Sleds) { - YAMLSleds.push_back({FunctionIds[Sled.Function], Sled.Address, - Sled.Function, Sled.Kind, Sled.AlwaysInstrument}); + auto FuncId = Map.getFunctionId(Sled.Function); + if (!FuncId) + return; + YAMLSleds.push_back({*FuncId, Sled.Address, Sled.Function, Sled.Kind, + Sled.AlwaysInstrument}); } Output Out(OS); Out << YAMLSleds; } +} // namespace + static CommandRegistration Unused(&Extract, []() -> Error { - Error Err = Error::success(); - xray::InstrumentationMapExtractor Extractor( - ExtractInput, InstrumentationMapExtractor::InputFormats::ELF, Err); - if (Err) - return Err; + auto InstrumentationMapOrError = loadInstrumentationMap(ExtractInput); + if (!InstrumentationMapOrError) + return joinErrors(make_error( + Twine("Cannot extract instrumentation map from '") + + ExtractInput + "'.", + std::make_error_code(std::errc::invalid_argument)), + InstrumentationMapOrError.takeError()); std::error_code EC; raw_fd_ostream OS(ExtractOutput, EC, sys::fs::OpenFlags::F_Text); if (EC) return make_error( Twine("Cannot open file '") + ExtractOutput + "' for writing.", EC); - Extractor.exportAsYAML(OS); + exportAsYAML(*InstrumentationMapOrError, OS); return Error::success(); }); Index: llvm/trunk/tools/llvm-xray/xray-graph.cc =================================================================== --- llvm/trunk/tools/llvm-xray/xray-graph.cc +++ llvm/trunk/tools/llvm-xray/xray-graph.cc @@ -17,17 +17,17 @@ #include #include -#include "xray-extract.h" #include "xray-graph.h" #include "xray-registry.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormatVariadic.h" +#include "llvm/XRay/InstrumentationMap.h" #include "llvm/XRay/Trace.h" #include "llvm/XRay/YAMLXRayRecord.h" using namespace llvm; -using namespace xray; +using namespace llvm::xray; // Setup llvm-xray graph subcommand and its options. static cl::SubCommand Graph("graph", "Generate function-call graph"); @@ -48,27 +48,14 @@ static cl::alias GraphOutput2("o", cl::aliasopt(GraphOutput), cl::desc("Alias for -output"), cl::sub(Graph)); -static cl::opt - GraphInstrMap("instr_map", - cl::desc("binary with the instrumrntation map, or " - "a separate instrumentation map"), - cl::value_desc("binary with xray_instr_map"), cl::sub(Graph), - cl::init("")); +static cl::opt GraphInstrMap( + "instr_map", cl::desc("binary with the instrumrntation map, or " + "a separate instrumentation map"), + cl::value_desc("binary with xray_instr_map"), cl::sub(Graph), cl::init("")); static cl::alias GraphInstrMap2("m", cl::aliasopt(GraphInstrMap), cl::desc("alias for -instr_map"), cl::sub(Graph)); -static cl::opt InstrMapFormat( - "instr-map-format", cl::desc("format of instrumentation map"), - cl::values(clEnumValN(InstrumentationMapExtractor::InputFormats::ELF, "elf", - "instrumentation map in an ELF header"), - clEnumValN(InstrumentationMapExtractor::InputFormats::YAML, - "yaml", "instrumentation map in YAML")), - cl::sub(Graph), cl::init(InstrumentationMapExtractor::InputFormats::ELF)); -static cl::alias InstrMapFormat2("t", cl::aliasopt(InstrMapFormat), - cl::desc("Alias for -instr-map-format"), - cl::sub(Graph)); - static cl::opt GraphDeduceSiblingCalls( "deduce-sibling-calls", cl::desc("Deduce sibling calls when unrolling function call stacks"), @@ -535,50 +522,44 @@ // FIXME: include additional filtering and annalysis passes to provide more // specific useful information. static CommandRegistration Unused(&Graph, []() -> Error { - int Fd; - auto EC = sys::fs::openFileForRead(GraphInput, Fd); - if (EC) - return make_error( - Twine("Cannot open file '") + GraphInput + "'", EC); - - Error Err = Error::success(); - xray::InstrumentationMapExtractor Extractor(GraphInstrMap, InstrMapFormat, - Err); - handleAllErrors(std::move(Err), - [&](const ErrorInfoBase &E) { E.log(errs()); }); - - const auto &FunctionAddresses = Extractor.getFunctionAddresses(); + InstrumentationMap Map; + if (!GraphInstrMap.empty()) { + auto InstrumentationMapOrError = loadInstrumentationMap(GraphInstrMap); + if (!InstrumentationMapOrError) + return joinErrors( + make_error( + Twine("Cannot open instrumentation map '") + GraphInstrMap + "'", + std::make_error_code(std::errc::invalid_argument)), + InstrumentationMapOrError.takeError()); + Map = std::move(*InstrumentationMapOrError); + } + const auto &FunctionAddresses = Map.getFunctionAddresses(); symbolize::LLVMSymbolizer::Options Opts( symbolize::FunctionNameKind::LinkageName, true, true, false, ""); - symbolize::LLVMSymbolizer Symbolizer(Opts); - llvm::xray::FuncIdConversionHelper FuncIdHelper(GraphInstrMap, Symbolizer, FunctionAddresses); - xray::GraphRenderer GR(FuncIdHelper, GraphDeduceSiblingCalls); - + std::error_code EC; raw_fd_ostream OS(GraphOutput, EC, sys::fs::OpenFlags::F_Text); - if (EC) return make_error( Twine("Cannot open file '") + GraphOutput + "' for writing.", EC); auto TraceOrErr = loadTraceFile(GraphInput, true); - - if (!TraceOrErr) { + if (!TraceOrErr) return joinErrors( make_error(Twine("Failed loading input file '") + GraphInput + "'", make_error_code(llvm::errc::invalid_argument)), - std::move(Err)); - } + TraceOrErr.takeError()); auto &Trace = *TraceOrErr; const auto &Header = Trace.getFileHeader(); + + // Here we generate the call graph from entries we find in the trace. for (const auto &Record : Trace) { - // Generate graph. auto E = GR.accountRecord(Record); if (!E) continue; @@ -592,12 +573,16 @@ } if (!GraphKeepGoing) - return joinErrors(std::move(E), std::move(Err)); + return joinErrors(make_error( + "Error encountered generating the call graph.", + std::make_error_code(std::errc::bad_message)), + std::move(E)); + handleAllErrors(std::move(E), [&](const ErrorInfoBase &E) { E.log(errs()); }); } GR.exportGraphAsDOT(OS, Header, GraphEdgeLabel, GraphEdgeColorType, GraphVertexLabel, GraphVertexColorType); - return Err; + return Error::success(); }); Index: llvm/trunk/tools/llvm-xray/xray-sleds.h =================================================================== --- llvm/trunk/tools/llvm-xray/xray-sleds.h +++ llvm/trunk/tools/llvm-xray/xray-sleds.h @@ -1,32 +0,0 @@ -//===- xray-sleds.h - XRay Sleds Data Structure ---------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Defines the structure used to represent XRay instrumentation map entries. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVM_XRAY_XRAY_SLEDS_H -#define LLVM_TOOLS_LLVM_XRAY_XRAY_SLEDS_H - -namespace llvm { -namespace xray { - -struct SledEntry { - enum class FunctionKinds { ENTRY, EXIT, TAIL }; - - uint64_t Address; - uint64_t Function; - FunctionKinds Kind; - bool AlwaysInstrument; -}; - -} // namespace xray -} // namespace llvm - -#endif // LLVM_TOOLS_LLVM_XRAY_XRAY_SLEDS_H