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