diff --git a/include/llvm/XRay/FileHeaderReader.h b/include/llvm/XRay/FileHeaderReader.h new file mode 100644 index 00000000000..3b8809bdbb3 --- /dev/null +++ b/include/llvm/XRay/FileHeaderReader.h @@ -0,0 +1,33 @@ +//===- FileHeaderReader.h - XRay Trace File Header Reading Function -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares functions that can load an XRay log header from various +// sources. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_LIB_XRAY_FILEHEADERREADER_H_ +#define LLVM_LIB_XRAY_FILEHEADERREADER_H_ + +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Error.h" +#include "llvm/XRay/XRayRecord.h" +#include + +namespace llvm { +namespace xray { + +/// Convenience function for loading the file header given a data extractor at a +/// specified offset. +Expected readBinaryFormatHeader(DataExtractor &HeaderExtractor, + uint32_t &OffsetPtr); + +} // namespace xray +} // namespace llvm + +#endif // LLVM_LIB_XRAY_FILEHEADERREADER_H_ diff --git a/lib/XRay/CMakeLists.txt b/lib/XRay/CMakeLists.txt index 8d558209d8e..3a8af28defe 100644 --- a/lib/XRay/CMakeLists.txt +++ b/lib/XRay/CMakeLists.txt @@ -1,4 +1,5 @@ add_llvm_library(LLVMXRay + FileHeaderReader.cpp InstrumentationMap.cpp Trace.cpp diff --git a/lib/XRay/FileHeaderReader.cpp b/lib/XRay/FileHeaderReader.cpp new file mode 100644 index 00000000000..967e85f30d2 --- /dev/null +++ b/lib/XRay/FileHeaderReader.cpp @@ -0,0 +1,75 @@ +//===- FileHeaderReader.cpp - XRay File Header Reader --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "llvm/XRay/FileHeaderReader.h" + +namespace llvm { +namespace xray { + +// Populates the FileHeader reference by reading the first 32 bytes of the file. +Expected readBinaryFormatHeader(DataExtractor &HeaderExtractor, + uint32_t &OffsetPtr) { + // FIXME: Maybe deduce whether the data is little or big-endian using some + // magic bytes in the beginning of the file? + + // First 32 bytes of the file will always be the header. We assume a certain + // format here: + // + // (2) uint16 : version + // (2) uint16 : type + // (4) uint32 : bitfield + // (8) uint64 : cycle frequency + // (16) - : padding + XRayFileHeader FileHeader; + auto PreReadOffset = OffsetPtr; + FileHeader.Version = HeaderExtractor.getU16(&OffsetPtr); + if (OffsetPtr == PreReadOffset) + return createStringError( + std::make_error_code(std::errc::invalid_argument), + "Failed reading version from file header at offset %d.", OffsetPtr); + + PreReadOffset = OffsetPtr; + FileHeader.Type = HeaderExtractor.getU16(&OffsetPtr); + if (OffsetPtr == PreReadOffset) + return createStringError( + std::make_error_code(std::errc::invalid_argument), + "Failed reading file type from file header at offset %d.", OffsetPtr); + + PreReadOffset = OffsetPtr; + uint32_t Bitfield = HeaderExtractor.getU32(&OffsetPtr); + if (OffsetPtr == PreReadOffset) + return createStringError( + std::make_error_code(std::errc::invalid_argument), + "Failed reading flag bits from file header at offset %d.", OffsetPtr); + + FileHeader.ConstantTSC = Bitfield & 1uL; + FileHeader.NonstopTSC = Bitfield & 1uL << 1; + PreReadOffset = OffsetPtr; + FileHeader.CycleFrequency = HeaderExtractor.getU64(&OffsetPtr); + if (OffsetPtr == PreReadOffset) + return createStringError( + std::make_error_code(std::errc::invalid_argument), + "Failed reading cycle frequency from file header at offset %d.", + OffsetPtr); + + std::memcpy(&FileHeader.FreeFormData, + HeaderExtractor.getData().bytes_begin() + OffsetPtr, 16); + + // Manually advance the offset pointer 16 bytes, after getting a raw memcpy + // from the underlying data. + OffsetPtr += 16; + if (FileHeader.Version != 1 && FileHeader.Version != 2 && + FileHeader.Version != 3) + return createStringError(std::make_error_code(std::errc::invalid_argument), + "Unsupported XRay file version: %d at offset %d", + FileHeader.Version, OffsetPtr); + return std::move(FileHeader); +} + +} // namespace xray +} // namespace llvm diff --git a/lib/XRay/Trace.cpp b/lib/XRay/Trace.cpp index 559d6a95a11..df86ebb73ea 100644 --- a/lib/XRay/Trace.cpp +++ b/lib/XRay/Trace.cpp @@ -15,6 +15,7 @@ #include "llvm/Support/DataExtractor.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" +#include "llvm/XRay/FileHeaderReader.h" #include "llvm/XRay/YAMLXRayRecord.h" using namespace llvm; @@ -30,66 +31,6 @@ using XRayRecordStorage = // record it is. constexpr auto kFDRMetadataBodySize = 15; -// Populates the FileHeader reference by reading the first 32 bytes of the file. -Error readBinaryFormatHeader(DataExtractor &HeaderExtractor, - uint32_t &OffsetPtr, XRayFileHeader &FileHeader) { - // FIXME: Maybe deduce whether the data is little or big-endian using some - // magic bytes in the beginning of the file? - - // First 32 bytes of the file will always be the header. We assume a certain - // format here: - // - // (2) uint16 : version - // (2) uint16 : type - // (4) uint32 : bitfield - // (8) uint64 : cycle frequency - // (16) - : padding - - auto PreReadOffset = OffsetPtr; - FileHeader.Version = HeaderExtractor.getU16(&OffsetPtr); - if (OffsetPtr == PreReadOffset) - return createStringError( - std::make_error_code(std::errc::invalid_argument), - "Failed reading version from file header at offset %d.", OffsetPtr); - - PreReadOffset = OffsetPtr; - FileHeader.Type = HeaderExtractor.getU16(&OffsetPtr); - if (OffsetPtr == PreReadOffset) - return createStringError( - std::make_error_code(std::errc::invalid_argument), - "Failed reading file type from file header at offset %d.", OffsetPtr); - - PreReadOffset = OffsetPtr; - uint32_t Bitfield = HeaderExtractor.getU32(&OffsetPtr); - if (OffsetPtr == PreReadOffset) - return createStringError( - std::make_error_code(std::errc::invalid_argument), - "Failed reading flag bits from file header at offset %d.", OffsetPtr); - - FileHeader.ConstantTSC = Bitfield & 1uL; - FileHeader.NonstopTSC = Bitfield & 1uL << 1; - PreReadOffset = OffsetPtr; - FileHeader.CycleFrequency = HeaderExtractor.getU64(&OffsetPtr); - if (OffsetPtr == PreReadOffset) - return createStringError( - std::make_error_code(std::errc::invalid_argument), - "Failed reading cycle frequency from file header at offset %d.", - OffsetPtr); - - std::memcpy(&FileHeader.FreeFormData, - HeaderExtractor.getData().bytes_begin() + OffsetPtr, 16); - - // Manually advance the offset pointer 16 bytes, after getting a raw memcpy - // from the underlying data. - OffsetPtr += 16; - if (FileHeader.Version != 1 && FileHeader.Version != 2 && - FileHeader.Version != 3) - return createStringError(std::make_error_code(std::errc::invalid_argument), - "Unsupported XRay file version: %d at offset %d", - FileHeader.Version, OffsetPtr); - return Error::success(); -} - Error loadNaiveFormatLog(StringRef Data, XRayFileHeader &FileHeader, std::vector &Records) { if (Data.size() < 32) @@ -104,8 +45,10 @@ Error loadNaiveFormatLog(StringRef Data, XRayFileHeader &FileHeader, DataExtractor Reader(Data, true, 8); uint32_t OffsetPtr = 0; - if (auto E = readBinaryFormatHeader(Reader, OffsetPtr, FileHeader)) - return E; + auto FileHeaderOrError = readBinaryFormatHeader(Reader, OffsetPtr); + if (!FileHeaderOrError) + return FileHeaderOrError.takeError(); + FileHeader = std::move(FileHeaderOrError.get()); // Each record after the header will be 32 bytes, in the following format: // @@ -762,6 +705,7 @@ Error processFDRFunctionRecord(FDRState &State, DataExtractor &RecordExtractor, /// EOB: *deprecated* Error loadFDRLog(StringRef Data, XRayFileHeader &FileHeader, std::vector &Records) { + if (Data.size() < 32) return make_error( "Not enough bytes for an XRay log.", @@ -770,8 +714,10 @@ Error loadFDRLog(StringRef Data, XRayFileHeader &FileHeader, DataExtractor Reader(Data, true, 8); uint32_t OffsetPtr = 0; - if (auto E = readBinaryFormatHeader(Reader, OffsetPtr, FileHeader)) - return E; + auto FileHeaderOrError = readBinaryFormatHeader(Reader, OffsetPtr); + if (!FileHeaderOrError) + return FileHeaderOrError.takeError(); + FileHeader = std::move(FileHeaderOrError.get()); uint64_t BufferSize = 0; {