1*d764c1b6SDean Michael Berris //===- FileHeaderReader.cpp - XRay File Header Reader  --------------------===//
2*d764c1b6SDean Michael Berris //
3*d764c1b6SDean Michael Berris //                     The LLVM Compiler Infrastructure
4*d764c1b6SDean Michael Berris //
5*d764c1b6SDean Michael Berris // This file is distributed under the University of Illinois Open Source
6*d764c1b6SDean Michael Berris // License. See LICENSE.TXT for details.
7*d764c1b6SDean Michael Berris //
8*d764c1b6SDean Michael Berris //===----------------------------------------------------------------------===//
9*d764c1b6SDean Michael Berris #include "llvm/XRay/FileHeaderReader.h"
10*d764c1b6SDean Michael Berris 
11*d764c1b6SDean Michael Berris namespace llvm {
12*d764c1b6SDean Michael Berris namespace xray {
13*d764c1b6SDean Michael Berris 
14*d764c1b6SDean Michael Berris // Populates the FileHeader reference by reading the first 32 bytes of the file.
15*d764c1b6SDean Michael Berris Expected<XRayFileHeader> readBinaryFormatHeader(DataExtractor &HeaderExtractor,
16*d764c1b6SDean Michael Berris                                                 uint32_t &OffsetPtr) {
17*d764c1b6SDean Michael Berris   // FIXME: Maybe deduce whether the data is little or big-endian using some
18*d764c1b6SDean Michael Berris   // magic bytes in the beginning of the file?
19*d764c1b6SDean Michael Berris 
20*d764c1b6SDean Michael Berris   // First 32 bytes of the file will always be the header. We assume a certain
21*d764c1b6SDean Michael Berris   // format here:
22*d764c1b6SDean Michael Berris   //
23*d764c1b6SDean Michael Berris   //   (2)   uint16 : version
24*d764c1b6SDean Michael Berris   //   (2)   uint16 : type
25*d764c1b6SDean Michael Berris   //   (4)   uint32 : bitfield
26*d764c1b6SDean Michael Berris   //   (8)   uint64 : cycle frequency
27*d764c1b6SDean Michael Berris   //   (16)  -      : padding
28*d764c1b6SDean Michael Berris   XRayFileHeader FileHeader;
29*d764c1b6SDean Michael Berris   auto PreReadOffset = OffsetPtr;
30*d764c1b6SDean Michael Berris   FileHeader.Version = HeaderExtractor.getU16(&OffsetPtr);
31*d764c1b6SDean Michael Berris   if (OffsetPtr == PreReadOffset)
32*d764c1b6SDean Michael Berris     return createStringError(
33*d764c1b6SDean Michael Berris         std::make_error_code(std::errc::invalid_argument),
34*d764c1b6SDean Michael Berris         "Failed reading version from file header at offset %d.", OffsetPtr);
35*d764c1b6SDean Michael Berris 
36*d764c1b6SDean Michael Berris   PreReadOffset = OffsetPtr;
37*d764c1b6SDean Michael Berris   FileHeader.Type = HeaderExtractor.getU16(&OffsetPtr);
38*d764c1b6SDean Michael Berris   if (OffsetPtr == PreReadOffset)
39*d764c1b6SDean Michael Berris     return createStringError(
40*d764c1b6SDean Michael Berris         std::make_error_code(std::errc::invalid_argument),
41*d764c1b6SDean Michael Berris         "Failed reading file type from file header at offset %d.", OffsetPtr);
42*d764c1b6SDean Michael Berris 
43*d764c1b6SDean Michael Berris   PreReadOffset = OffsetPtr;
44*d764c1b6SDean Michael Berris   uint32_t Bitfield = HeaderExtractor.getU32(&OffsetPtr);
45*d764c1b6SDean Michael Berris   if (OffsetPtr == PreReadOffset)
46*d764c1b6SDean Michael Berris     return createStringError(
47*d764c1b6SDean Michael Berris         std::make_error_code(std::errc::invalid_argument),
48*d764c1b6SDean Michael Berris         "Failed reading flag bits from file header at offset %d.", OffsetPtr);
49*d764c1b6SDean Michael Berris 
50*d764c1b6SDean Michael Berris   FileHeader.ConstantTSC = Bitfield & 1uL;
51*d764c1b6SDean Michael Berris   FileHeader.NonstopTSC = Bitfield & 1uL << 1;
52*d764c1b6SDean Michael Berris   PreReadOffset = OffsetPtr;
53*d764c1b6SDean Michael Berris   FileHeader.CycleFrequency = HeaderExtractor.getU64(&OffsetPtr);
54*d764c1b6SDean Michael Berris   if (OffsetPtr == PreReadOffset)
55*d764c1b6SDean Michael Berris     return createStringError(
56*d764c1b6SDean Michael Berris         std::make_error_code(std::errc::invalid_argument),
57*d764c1b6SDean Michael Berris         "Failed reading cycle frequency from file header at offset %d.",
58*d764c1b6SDean Michael Berris         OffsetPtr);
59*d764c1b6SDean Michael Berris 
60*d764c1b6SDean Michael Berris   std::memcpy(&FileHeader.FreeFormData,
61*d764c1b6SDean Michael Berris               HeaderExtractor.getData().bytes_begin() + OffsetPtr, 16);
62*d764c1b6SDean Michael Berris 
63*d764c1b6SDean Michael Berris   // Manually advance the offset pointer 16 bytes, after getting a raw memcpy
64*d764c1b6SDean Michael Berris   // from the underlying data.
65*d764c1b6SDean Michael Berris   OffsetPtr += 16;
66*d764c1b6SDean Michael Berris   if (FileHeader.Version != 1 && FileHeader.Version != 2 &&
67*d764c1b6SDean Michael Berris       FileHeader.Version != 3)
68*d764c1b6SDean Michael Berris     return createStringError(std::make_error_code(std::errc::invalid_argument),
69*d764c1b6SDean Michael Berris                              "Unsupported XRay file version: %d at offset %d",
70*d764c1b6SDean Michael Berris                              FileHeader.Version, OffsetPtr);
71*d764c1b6SDean Michael Berris   return std::move(FileHeader);
72*d764c1b6SDean Michael Berris }
73*d764c1b6SDean Michael Berris 
74*d764c1b6SDean Michael Berris } // namespace xray
75*d764c1b6SDean Michael Berris } // namespace llvm
76