summaryrefslogtreecommitdiffstats
path: root/llvm/lib
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib')
-rw-r--r--llvm/lib/XRay/FDRRecordProducer.cpp117
-rw-r--r--llvm/lib/XRay/FDRRecords.cpp34
-rw-r--r--llvm/lib/XRay/FDRTraceWriter.cpp6
-rw-r--r--llvm/lib/XRay/RecordInitializer.cpp54
4 files changed, 188 insertions, 23 deletions
diff --git a/llvm/lib/XRay/FDRRecordProducer.cpp b/llvm/lib/XRay/FDRRecordProducer.cpp
index 122578010c4..25b3ee8af21 100644
--- a/llvm/lib/XRay/FDRRecordProducer.cpp
+++ b/llvm/lib/XRay/FDRRecordProducer.cpp
@@ -9,29 +9,32 @@
#include "llvm/XRay/FDRRecordProducer.h"
#include "llvm/Support/DataExtractor.h"
+#include <cstdint>
+
namespace llvm {
namespace xray {
namespace {
+// Keep this in sync with the values written in the XRay FDR mode runtime in
+// compiler-rt.
+enum MetadataRecordKinds : uint8_t {
+ NewBufferKind,
+ EndOfBufferKind,
+ NewCPUIdKind,
+ TSCWrapKind,
+ WalltimeMarkerKind,
+ CustomEventMarkerKind,
+ CallArgumentKind,
+ BufferExtentsKind,
+ TypedEventMarkerKind,
+ PidKind,
+ // This is an end marker, used to identify the upper bound for this enum.
+ EnumEndMarker,
+};
+
Expected<std::unique_ptr<Record>>
metadataRecordType(const XRayFileHeader &Header, uint8_t T) {
- // Keep this in sync with the values written in the XRay FDR mode runtime in
- // compiler-rt.
- enum MetadataRecordKinds : uint8_t {
- NewBufferKind,
- EndOfBufferKind,
- NewCPUIdKind,
- TSCWrapKind,
- WalltimeMarkerKind,
- CustomEventMarkerKind,
- CallArgumentKind,
- BufferExtentsKind,
- TypedEventMarkerKind,
- PidKind,
- // This is an end marker, used to identify the upper bound for this enum.
- EnumEndMarker,
- };
if (T >= static_cast<uint8_t>(MetadataRecordKinds::EnumEndMarker))
return createStringError(std::make_error_code(std::errc::invalid_argument),
@@ -70,9 +73,70 @@ metadataRecordType(const XRayFileHeader &Header, uint8_t T) {
llvm_unreachable("Unhandled MetadataRecordKinds enum value");
}
+constexpr bool isMetadataIntroducer(uint8_t FirstByte) {
+ return FirstByte & 0x01u;
+}
+
} // namespace
+Expected<std::unique_ptr<Record>>
+FileBasedRecordProducer::findNextBufferExtent() {
+ // We seek one byte at a time until we find a suitable buffer extents metadata
+ // record introducer.
+ std::unique_ptr<Record> R;
+ while (!R) {
+ auto PreReadOffset = OffsetPtr;
+ uint8_t FirstByte = E.getU8(&OffsetPtr);
+ if (OffsetPtr == PreReadOffset)
+ return createStringError(
+ std::make_error_code(std::errc::executable_format_error),
+ "Failed reading one byte from offset %d.", OffsetPtr);
+
+ if (isMetadataIntroducer(FirstByte)) {
+ auto LoadedType = FirstByte >> 1;
+ if (LoadedType == MetadataRecordKinds::BufferExtentsKind) {
+ auto MetadataRecordOrErr = metadataRecordType(Header, LoadedType);
+ if (!MetadataRecordOrErr)
+ return MetadataRecordOrErr.takeError();
+
+ R = std::move(MetadataRecordOrErr.get());
+ RecordInitializer RI(E, OffsetPtr);
+ if (auto Err = R->apply(RI))
+ return std::move(Err);
+ return std::move(R);
+ }
+ }
+ }
+ llvm_unreachable("Must always terminate with either an error or a record.");
+}
+
Expected<std::unique_ptr<Record>> FileBasedRecordProducer::produce() {
+ // First, we set up our result record.
+ std::unique_ptr<Record> R;
+
+ // Before we do any further reading, we should check whether we're at the end
+ // of the current buffer we're been consuming. In FDR logs version >= 3, we
+ // rely on the buffer extents record to determine how many bytes we should be
+ // considering as valid records.
+ if (Header.Version >= 3 && CurrentBufferBytes == 0) {
+ // Find the next buffer extents record.
+ auto BufferExtentsOrError = findNextBufferExtent();
+ if (!BufferExtentsOrError)
+ return joinErrors(
+ BufferExtentsOrError.takeError(),
+ createStringError(
+ std::make_error_code(std::errc::executable_format_error),
+ "Failed to find the next BufferExtents record."));
+
+ R = std::move(BufferExtentsOrError.get());
+ assert(R != nullptr);
+ assert(isa<BufferExtents>(R.get()));
+ auto BE = dyn_cast<BufferExtents>(R.get());
+ CurrentBufferBytes = BE->size();
+ return std::move(R);
+ }
+
+ //
// At the top level, we read one byte to determine the type of the record to
// create. This byte will comprise of the following bits:
//
@@ -90,11 +154,8 @@ Expected<std::unique_ptr<Record>> FileBasedRecordProducer::produce() {
std::make_error_code(std::errc::executable_format_error),
"Failed reading one byte from offset %d.", OffsetPtr);
- // Set up our result record.
- std::unique_ptr<Record> R;
-
// For metadata records, handle especially here.
- if (FirstByte & 0x01) {
+ if (isMetadataIntroducer(FirstByte)) {
auto LoadedType = FirstByte >> 1;
auto MetadataRecordOrErr = metadataRecordType(Header, LoadedType);
if (!MetadataRecordOrErr)
@@ -113,6 +174,22 @@ Expected<std::unique_ptr<Record>> FileBasedRecordProducer::produce() {
if (auto Err = R->apply(RI))
return std::move(Err);
+ // If we encountered a BufferExtents record, we should record the remaining
+ // bytes for the current buffer, to determine when we should start ignoring
+ // potentially malformed data and looking for buffer extents records.
+ if (auto BE = dyn_cast<BufferExtents>(R.get())) {
+ CurrentBufferBytes = BE->size();
+ } else if (Header.Version >= 3) {
+ if (OffsetPtr - PreReadOffset > CurrentBufferBytes)
+ return createStringError(
+ std::make_error_code(std::errc::executable_format_error),
+ "Buffer over-read at offset %d (over-read by %d bytes); Record Type "
+ "= %s.",
+ OffsetPtr, (OffsetPtr - PreReadOffset) - CurrentBufferBytes,
+ Record::kindToString(R->getRecordType()).data());
+
+ CurrentBufferBytes -= OffsetPtr - PreReadOffset;
+ }
assert(R != nullptr);
return std::move(R);
}
diff --git a/llvm/lib/XRay/FDRRecords.cpp b/llvm/lib/XRay/FDRRecords.cpp
index 2b68a73686f..2a40d5e0622 100644
--- a/llvm/lib/XRay/FDRRecords.cpp
+++ b/llvm/lib/XRay/FDRRecords.cpp
@@ -29,5 +29,39 @@ Error FunctionRecord::apply(RecordVisitor &V) { return V.visit(*this); }
Error CustomEventRecordV5::apply(RecordVisitor &V) { return V.visit(*this); }
Error TypedEventRecord::apply(RecordVisitor &V) { return V.visit(*this); }
+StringRef Record::kindToString(RecordKind K) {
+ switch (K) {
+ case RecordKind::RK_Metadata:
+ return "Metadata";
+ case RecordKind::RK_Metadata_BufferExtents:
+ return "Metadata:BufferExtents";
+ case RecordKind::RK_Metadata_WallClockTime:
+ return "Metadata:WallClockTime";
+ case RecordKind::RK_Metadata_NewCPUId:
+ return "Metadata:NewCPUId";
+ case RecordKind::RK_Metadata_TSCWrap:
+ return "Metadata:TSCWrap";
+ case RecordKind::RK_Metadata_CustomEvent:
+ return "Metadata:CustomEvent";
+ case RecordKind::RK_Metadata_CustomEventV5:
+ return "Metadata:CustomEventV5";
+ case RecordKind::RK_Metadata_CallArg:
+ return "Metadata:CallArg";
+ case RecordKind::RK_Metadata_PIDEntry:
+ return "Metadata:PIDEntry";
+ case RecordKind::RK_Metadata_NewBuffer:
+ return "Metadata:NewBuffer";
+ case RecordKind::RK_Metadata_EndOfBuffer:
+ return "Metadata:EndOfBuffer";
+ case RecordKind::RK_Metadata_TypedEvent:
+ return "Metadata:TypedEvent";
+ case RecordKind::RK_Metadata_LastMetadata:
+ return "Metadata:LastMetadata";
+ case RecordKind::RK_Function:
+ return "Function";
+ }
+ return "Unknown";
+}
+
} // namespace xray
} // namespace llvm
diff --git a/llvm/lib/XRay/FDRTraceWriter.cpp b/llvm/lib/XRay/FDRTraceWriter.cpp
index d5f96979986..c5224f4be09 100644
--- a/llvm/lib/XRay/FDRTraceWriter.cpp
+++ b/llvm/lib/XRay/FDRTraceWriter.cpp
@@ -43,7 +43,9 @@ template <size_t Index> struct IndexedWriter {
template <uint8_t Kind, class... Values>
Error writeMetadata(support::endian::Writer &OS, Values &&... Ds) {
- uint8_t FirstByte = (Kind << 1) | uint8_t{0x01};
+ // The first bit in the first byte of metadata records is always set to 1, so
+ // we ensure this is the case when we write out the first byte of the record.
+ uint8_t FirstByte = (static_cast<uint8_t>(Kind) << 1) | uint8_t{0x01u};
auto T = std::make_tuple(std::forward<Values>(std::move(Ds))...);
// Write in field order.
OS.write(FirstByte);
@@ -112,7 +114,7 @@ Error FDRTraceWriter::visit(CustomEventRecordV5 &R) {
}
Error FDRTraceWriter::visit(TypedEventRecord &R) {
- if (auto E = writeMetadata<7u>(OS, R.size(), R.delta(), R.eventType()))
+ if (auto E = writeMetadata<8u>(OS, R.size(), R.delta(), R.eventType()))
return E;
auto D = R.data();
ArrayRef<char> Bytes(D.data(), D.size());
diff --git a/llvm/lib/XRay/RecordInitializer.cpp b/llvm/lib/XRay/RecordInitializer.cpp
index cc9dd460949..f136a1e456b 100644
--- a/llvm/lib/XRay/RecordInitializer.cpp
+++ b/llvm/lib/XRay/RecordInitializer.cpp
@@ -111,6 +111,12 @@ Error RecordInitializer::visit(CustomEventRecord &R) {
std::make_error_code(std::errc::invalid_argument),
"Cannot read a custom event record size field offset %d.", OffsetPtr);
+ if (R.Size <= 0)
+ return createStringError(
+ std::make_error_code(std::errc::bad_address),
+ "Invalid size for custom event (size = %d) at offset %d.", R.Size,
+ OffsetPtr);
+
PreReadOffset = OffsetPtr;
R.TSC = E.getU64(&OffsetPtr);
if (PreReadOffset == OffsetPtr)
@@ -142,11 +148,21 @@ Error RecordInitializer::visit(CustomEventRecord &R) {
std::vector<uint8_t> Buffer;
Buffer.resize(R.Size);
+ PreReadOffset = OffsetPtr;
if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data())
return createStringError(
std::make_error_code(std::errc::invalid_argument),
"Failed reading data into buffer of size %d at offset %d.", R.Size,
OffsetPtr);
+
+ assert(OffsetPtr >= PreReadOffset);
+ if (OffsetPtr - PreReadOffset != static_cast<uint32_t>(R.Size))
+ return createStringError(
+ std::make_error_code(std::errc::invalid_argument),
+ "Failed reading enough bytes for the custom event payload -- read %d "
+ "expecting %d bytes at offset %d.",
+ OffsetPtr - PreReadOffset, R.Size, PreReadOffset);
+
R.Data.assign(Buffer.begin(), Buffer.end());
return Error::success();
}
@@ -167,6 +183,12 @@ Error RecordInitializer::visit(CustomEventRecordV5 &R) {
std::make_error_code(std::errc::invalid_argument),
"Cannot read a custom event record size field offset %d.", OffsetPtr);
+ if (R.Size <= 0)
+ return createStringError(
+ std::make_error_code(std::errc::bad_address),
+ "Invalid size for custom event (size = %d) at offset %d.", R.Size,
+ OffsetPtr);
+
PreReadOffset = OffsetPtr;
R.Delta = E.getSigned(&OffsetPtr, sizeof(int32_t));
if (PreReadOffset == OffsetPtr)
@@ -188,11 +210,21 @@ Error RecordInitializer::visit(CustomEventRecordV5 &R) {
std::vector<uint8_t> Buffer;
Buffer.resize(R.Size);
+ PreReadOffset = OffsetPtr;
if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data())
return createStringError(
std::make_error_code(std::errc::invalid_argument),
"Failed reading data into buffer of size %d at offset %d.", R.Size,
OffsetPtr);
+
+ assert(OffsetPtr >= PreReadOffset);
+ if (OffsetPtr - PreReadOffset != static_cast<uint32_t>(R.Size))
+ return createStringError(
+ std::make_error_code(std::errc::invalid_argument),
+ "Failed reading enough bytes for the custom event payload -- read %d "
+ "expecting %d bytes at offset %d.",
+ OffsetPtr - PreReadOffset, R.Size, PreReadOffset);
+
R.Data.assign(Buffer.begin(), Buffer.end());
return Error::success();
}
@@ -213,6 +245,12 @@ Error RecordInitializer::visit(TypedEventRecord &R) {
std::make_error_code(std::errc::invalid_argument),
"Cannot read a typed event record size field offset %d.", OffsetPtr);
+ if (R.Size <= 0)
+ return createStringError(
+ std::make_error_code(std::errc::bad_address),
+ "Invalid size for typed event (size = %d) at offset %d.", R.Size,
+ OffsetPtr);
+
PreReadOffset = OffsetPtr;
R.Delta = E.getSigned(&OffsetPtr, sizeof(int32_t));
if (PreReadOffset == OffsetPtr)
@@ -241,11 +279,21 @@ Error RecordInitializer::visit(TypedEventRecord &R) {
std::vector<uint8_t> Buffer;
Buffer.resize(R.Size);
+ PreReadOffset = OffsetPtr;
if (E.getU8(&OffsetPtr, Buffer.data(), R.Size) != Buffer.data())
return createStringError(
std::make_error_code(std::errc::invalid_argument),
"Failed reading data into buffer of size %d at offset %d.", R.Size,
OffsetPtr);
+
+ assert(OffsetPtr >= PreReadOffset);
+ if (OffsetPtr - PreReadOffset != static_cast<uint32_t>(R.Size))
+ return createStringError(
+ std::make_error_code(std::errc::invalid_argument),
+ "Failed reading enough bytes for the typed event payload -- read %d "
+ "expecting %d bytes at offset %d.",
+ OffsetPtr - PreReadOffset, R.Size, PreReadOffset);
+
R.Data.assign(Buffer.begin(), Buffer.end());
return Error::success();
}
@@ -337,7 +385,11 @@ Error RecordInitializer::visit(FunctionRecord &R) {
return createStringError(std::make_error_code(std::errc::bad_address),
"Cannot read function id field from offset %d.",
OffsetPtr);
- unsigned FunctionType = (Buffer >> 1) & 0x07;
+
+ // To get the function record type, we shift the buffer one to the right
+ // (truncating the function record indicator) then take the three bits
+ // (0b0111) to get the record type as an unsigned value.
+ unsigned FunctionType = (Buffer >> 1) & 0x07u;
switch (FunctionType) {
case static_cast<unsigned>(RecordTypes::ENTER):
case static_cast<unsigned>(RecordTypes::ENTER_ARG):
OpenPOWER on IntegriCloud