1 //===- FDRRecordProducer.cpp - XRay FDR Mode Record Producer --------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 #include "llvm/XRay/FDRRecordProducer.h"
10 #include "llvm/Support/DataExtractor.h"
11 
12 namespace llvm {
13 namespace xray {
14 
15 namespace {
16 
17 Expected<std::unique_ptr<Record>>
18 metadataRecordType(const XRayFileHeader &Header, uint8_t T) {
19   // Keep this in sync with the values written in the XRay FDR mode runtime in
20   // compiler-rt.
21   enum MetadataRecordKinds : uint8_t {
22     NewBufferKind,
23     EndOfBufferKind,
24     NewCPUIdKind,
25     TSCWrapKind,
26     WalltimeMarkerKind,
27     CustomEventMarkerKind,
28     CallArgumentKind,
29     BufferExtentsKind,
30     TypedEventMarkerKind,
31     PidKind,
32     // This is an end marker, used to identify the upper bound for this enum.
33     EnumEndMarker,
34   };
35 
36   if (T >= static_cast<uint8_t>(MetadataRecordKinds::EnumEndMarker))
37     return createStringError(std::make_error_code(std::errc::invalid_argument),
38                              "Invalid metadata record type: %d", T);
39   switch (T) {
40   case MetadataRecordKinds::NewBufferKind:
41     return make_unique<NewBufferRecord>();
42   case MetadataRecordKinds::EndOfBufferKind:
43     if (Header.Version >= 2)
44       return createStringError(
45           std::make_error_code(std::errc::executable_format_error),
46           "End of buffer records are no longer supported starting version "
47           "2 of the log.");
48     return make_unique<EndBufferRecord>();
49   case MetadataRecordKinds::NewCPUIdKind:
50     return make_unique<NewCPUIDRecord>();
51   case MetadataRecordKinds::TSCWrapKind:
52     return make_unique<TSCWrapRecord>();
53   case MetadataRecordKinds::WalltimeMarkerKind:
54     return make_unique<WallclockRecord>();
55   case MetadataRecordKinds::CustomEventMarkerKind:
56     return make_unique<CustomEventRecord>();
57   case MetadataRecordKinds::CallArgumentKind:
58     return make_unique<CallArgRecord>();
59   case MetadataRecordKinds::BufferExtentsKind:
60     return make_unique<BufferExtents>();
61   case MetadataRecordKinds::TypedEventMarkerKind:
62     return createStringError(std::make_error_code(std::errc::invalid_argument),
63                              "Encountered an unsupported TypedEventMarker.");
64   case MetadataRecordKinds::PidKind:
65     return make_unique<PIDRecord>();
66   case MetadataRecordKinds::EnumEndMarker:
67     llvm_unreachable("Invalid MetadataRecordKind");
68   }
69   llvm_unreachable("Unhandled MetadataRecordKinds enum value");
70 }
71 
72 } // namespace
73 
74 Expected<std::unique_ptr<Record>> FileBasedRecordProducer::produce() {
75   // At the top level, we read one byte to determine the type of the record to
76   // create. This byte will comprise of the following bits:
77   //
78   //   - offset 0: A '1' indicates a metadata record, a '0' indicates a function
79   //     record.
80   //   - offsets 1-7: For metadata records, this will indicate the kind of
81   //     metadata record should be loaded.
82   //
83   // We read first byte, then create the appropriate type of record to consume
84   // the rest of the bytes.
85   auto PreReadOffset = OffsetPtr;
86   uint8_t FirstByte = E.getU8(&OffsetPtr);
87   std::unique_ptr<Record> R;
88 
89   // For metadata records, handle especially here.
90   if (FirstByte & 0x01) {
91     auto LoadedType = FirstByte >> 1;
92     auto MetadataRecordOrErr = metadataRecordType(Header, LoadedType);
93     if (!MetadataRecordOrErr)
94       return joinErrors(
95           MetadataRecordOrErr.takeError(),
96           createStringError(
97               std::make_error_code(std::errc::executable_format_error),
98               "Encountered an unsupported metadata record (%d) at offset %d.",
99               LoadedType, PreReadOffset));
100     R = std::move(MetadataRecordOrErr.get());
101   } else {
102     R = llvm::make_unique<FunctionRecord>();
103   }
104   RecordInitializer RI(E, OffsetPtr);
105 
106   if (auto Err = R->apply(RI))
107     return std::move(Err);
108 
109   assert(R != nullptr);
110   return std::move(R);
111 }
112 
113 } // namespace xray
114 } // namespace llvm
115