diff --git a/llvm/include/llvm/XRay/FDRTraceWriter.h b/llvm/include/llvm/XRay/FDRTraceWriter.h index e1c7540a0f11..91488f89ecc5 100644 --- a/llvm/include/llvm/XRay/FDRTraceWriter.h +++ b/llvm/include/llvm/XRay/FDRTraceWriter.h @@ -14,6 +14,7 @@ #define LLVM_INCLUDE_LLVM_XRAY_FDRTRACEWRITER_H_ #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/EndianStream.h" #include "llvm/XRay/FDRRecords.h" #include "llvm/XRay/XRayRecord.h" @@ -44,7 +45,7 @@ public: Error visit(FunctionRecord &) override; private: - raw_ostream &OS; + support::endian::Writer OS; }; } // namespace xray diff --git a/llvm/lib/XRay/FDRTraceWriter.cpp b/llvm/lib/XRay/FDRTraceWriter.cpp index b9b71eb14a88..c68e915bbb5b 100644 --- a/llvm/lib/XRay/FDRTraceWriter.cpp +++ b/llvm/lib/XRay/FDRTraceWriter.cpp @@ -39,19 +39,16 @@ struct FunctionDeltaBlob { uint32_t TSCDelta; }; -template struct IndexedMemcpy { +template struct IndexedWriter { template < class Tuple, typename std::enable_if< (Index < std::tuple_size::type>::value), int>::type = 0> - static void Copy(char *Dest, Tuple &&T) { - auto Next = static_cast(std::memcpy( - Dest, reinterpret_cast(&std::get(T)), - sizeof(std::get(T)))) + - sizeof(std::get(T)); - IndexedMemcpy::Copy(Next, T); + static size_t write(support::endian::Writer &OS, Tuple &&T) { + OS.write(std::get(T)); + return sizeof(std::get(T)) + IndexedWriter::write(OS, T); } template < @@ -60,34 +57,43 @@ template struct IndexedMemcpy { (Index >= std::tuple_size::type>::value), int>::type = 0> - static void Copy(char *, Tuple &&) {} + static size_t write(support::endian::Writer &OS, Tuple &&) { + return 0; + } }; template -Error writeMetadata(raw_ostream &OS, Values &&... Ds) { - MetadataBlob B; - B.Type = 1; - B.RecordKind = Kind; - std::memset(B.Data, 0, 15); +Error writeMetadata(support::endian::Writer &OS, Values &&... Ds) { + uint8_t FirstByte = (Kind << 1) | uint8_t{0x01}; auto T = std::make_tuple(std::forward(std::move(Ds))...); - IndexedMemcpy<0>::Copy(B.Data, T); - OS.write(reinterpret_cast(&B), sizeof(MetadataBlob)); + // Write in field order. + OS.write(FirstByte); + auto Bytes = IndexedWriter<0>::write(OS, T); + assert(Bytes <= 15 && "Must only ever write at most 16 byte metadata!"); + // Pad out with appropriate numbers of zero's. + for (; Bytes < 15; ++Bytes) + OS.write('\0'); return Error::success(); } } // namespace FDRTraceWriter::FDRTraceWriter(raw_ostream &O, const XRayFileHeader &H) - : OS(O) { + : OS(O, support::endianness::native) { // We need to re-construct a header, by writing the fields we care about for // traces, in the format that the runtime would have written. - FileHeader Raw; - Raw.Version = H.Version; - Raw.Type = H.Type; - Raw.BitField = (H.ConstantTSC ? 0x01 : 0x0) | (H.NonstopTSC ? 0x02 : 0x0); - Raw.CycleFrequency = H.CycleFrequency; - memcpy(&Raw.FreeForm, H.FreeFormData, 16); - OS.write(reinterpret_cast(&Raw), sizeof(XRayFileHeader)); + uint32_t BitField = + (H.ConstantTSC ? 0x01 : 0x0) | (H.NonstopTSC ? 0x02 : 0x0); + + // For endian-correctness, we need to write these fields in the order they + // appear and that we expect, instead of blasting bytes of the struct through. + OS.write(H.Version); + OS.write(H.Type); + OS.write(BitField); + OS.write(H.CycleFrequency); + ArrayRef FreeFormBytes(H.FreeFormData, + sizeof(XRayFileHeader::FreeFormData)); + OS.write(FreeFormBytes); } FDRTraceWriter::~FDRTraceWriter() {} @@ -111,7 +117,8 @@ Error FDRTraceWriter::visit(TSCWrapRecord &R) { Error FDRTraceWriter::visit(CustomEventRecord &R) { if (auto E = writeMetadata<5u>(OS, R.size(), R.tsc())) return E; - OS.write(R.data().data(), R.data().size()); + ArrayRef Bytes(R.data().data(), R.data().size()); + OS.write(Bytes); return Error::success(); } @@ -137,7 +144,9 @@ Error FDRTraceWriter::visit(FunctionRecord &R) { B.RecordKind = static_cast(R.recordType()); B.FuncId = R.functionId(); B.TSCDelta = R.delta(); - OS.write(reinterpret_cast(&B), sizeof(FunctionDeltaBlob)); + ArrayRef Bytes(reinterpret_cast(&B), + sizeof(FunctionDeltaBlob)); + OS.write(Bytes); return Error::success(); } diff --git a/llvm/unittests/XRay/FDRProducerConsumerTest.cpp b/llvm/unittests/XRay/FDRProducerConsumerTest.cpp index 8d6f0d955150..58e252dd25b9 100644 --- a/llvm/unittests/XRay/FDRProducerConsumerTest.cpp +++ b/llvm/unittests/XRay/FDRProducerConsumerTest.cpp @@ -99,7 +99,7 @@ TYPED_TEST_P(RoundTripTest, RoundTripsSingleValue) { ASSERT_FALSE(errorToBool(R->apply(*this->Writer))); this->OS.flush(); - DataExtractor DE(this->Data, true, 8); + DataExtractor DE(this->Data, sys::IsLittleEndianHost, 8); uint32_t OffsetPtr = 0; auto HeaderOrErr = readBinaryFormatHeader(DE, OffsetPtr); if (!HeaderOrErr) diff --git a/llvm/unittests/XRay/FDRTraceWriterTest.cpp b/llvm/unittests/XRay/FDRTraceWriterTest.cpp index 97a011977b17..cbe6346eaf58 100644 --- a/llvm/unittests/XRay/FDRTraceWriterTest.cpp +++ b/llvm/unittests/XRay/FDRTraceWriterTest.cpp @@ -56,7 +56,7 @@ TEST(FDRTraceWriterTest, WriteToStringBufferVersion3) { OS.flush(); // Then from here we load the Trace file. - DataExtractor DE(Data, true, 8); + DataExtractor DE(Data, sys::IsLittleEndianHost, 8); auto TraceOrErr = loadTrace(DE, true); if (!TraceOrErr) FAIL() << TraceOrErr.takeError(); @@ -100,7 +100,7 @@ TEST(FDRTraceWriterTest, WriteToStringBufferVersion2) { OS.flush(); // Then from here we load the Trace file. - DataExtractor DE(Data, true, 8); + DataExtractor DE(Data, sys::IsLittleEndianHost, 8); auto TraceOrErr = loadTrace(DE, true); if (!TraceOrErr) FAIL() << TraceOrErr.takeError(); @@ -160,7 +160,7 @@ TEST(FDRTraceWriterTest, WriteToStringBufferVersion1) { ASSERT_THAT(Data.size(), Eq(BufferSize + 32)); // Then from here we load the Trace file. - DataExtractor DE(Data, true, 8); + DataExtractor DE(Data, sys::IsLittleEndianHost, 8); auto TraceOrErr = loadTrace(DE, true); if (!TraceOrErr) FAIL() << TraceOrErr.takeError();