1*0b57cec5SDimitry Andric //===- DebugSubsectionRecord.cpp ------------------------------------------===//
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 
9*0b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
10*0b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/CodeView.h"
11*0b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugSubsection.h"
12*0b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamReader.h"
13*0b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamWriter.h"
14*0b57cec5SDimitry Andric #include "llvm/Support/Error.h"
15*0b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
16*0b57cec5SDimitry Andric #include <algorithm>
17*0b57cec5SDimitry Andric #include <cassert>
18*0b57cec5SDimitry Andric #include <cstdint>
19*0b57cec5SDimitry Andric 
20*0b57cec5SDimitry Andric using namespace llvm;
21*0b57cec5SDimitry Andric using namespace llvm::codeview;
22*0b57cec5SDimitry Andric 
23*0b57cec5SDimitry Andric DebugSubsectionRecord::DebugSubsectionRecord() = default;
24*0b57cec5SDimitry Andric 
DebugSubsectionRecord(DebugSubsectionKind Kind,BinaryStreamRef Data)25*0b57cec5SDimitry Andric DebugSubsectionRecord::DebugSubsectionRecord(DebugSubsectionKind Kind,
26*0b57cec5SDimitry Andric                                              BinaryStreamRef Data)
27*0b57cec5SDimitry Andric     : Kind(Kind), Data(Data) {}
28*0b57cec5SDimitry Andric 
initialize(BinaryStreamRef Stream,DebugSubsectionRecord & Info)29*0b57cec5SDimitry Andric Error DebugSubsectionRecord::initialize(BinaryStreamRef Stream,
30*0b57cec5SDimitry Andric                                         DebugSubsectionRecord &Info) {
31*0b57cec5SDimitry Andric   const DebugSubsectionHeader *Header;
32*0b57cec5SDimitry Andric   BinaryStreamReader Reader(Stream);
33*0b57cec5SDimitry Andric   if (auto EC = Reader.readObject(Header))
34*0b57cec5SDimitry Andric     return EC;
35*0b57cec5SDimitry Andric 
36*0b57cec5SDimitry Andric   DebugSubsectionKind Kind =
37*0b57cec5SDimitry Andric       static_cast<DebugSubsectionKind>(uint32_t(Header->Kind));
38*0b57cec5SDimitry Andric   if (auto EC = Reader.readStreamRef(Info.Data, Header->Length))
39*0b57cec5SDimitry Andric     return EC;
40*0b57cec5SDimitry Andric   Info.Kind = Kind;
41*0b57cec5SDimitry Andric   return Error::success();
42*0b57cec5SDimitry Andric }
43*0b57cec5SDimitry Andric 
getRecordLength() const44*0b57cec5SDimitry Andric uint32_t DebugSubsectionRecord::getRecordLength() const {
45*0b57cec5SDimitry Andric   return sizeof(DebugSubsectionHeader) + Data.getLength();
46*0b57cec5SDimitry Andric }
47*0b57cec5SDimitry Andric 
kind() const48*0b57cec5SDimitry Andric DebugSubsectionKind DebugSubsectionRecord::kind() const { return Kind; }
49*0b57cec5SDimitry Andric 
getRecordData() const50*0b57cec5SDimitry Andric BinaryStreamRef DebugSubsectionRecord::getRecordData() const { return Data; }
51*0b57cec5SDimitry Andric 
DebugSubsectionRecordBuilder(std::shared_ptr<DebugSubsection> Subsection)52*0b57cec5SDimitry Andric DebugSubsectionRecordBuilder::DebugSubsectionRecordBuilder(
53*0b57cec5SDimitry Andric     std::shared_ptr<DebugSubsection> Subsection)
54*0b57cec5SDimitry Andric     : Subsection(std::move(Subsection)) {}
55*0b57cec5SDimitry Andric 
DebugSubsectionRecordBuilder(const DebugSubsectionRecord & Contents)56*0b57cec5SDimitry Andric DebugSubsectionRecordBuilder::DebugSubsectionRecordBuilder(
57*0b57cec5SDimitry Andric     const DebugSubsectionRecord &Contents)
58*0b57cec5SDimitry Andric     : Contents(Contents) {}
59*0b57cec5SDimitry Andric 
calculateSerializedLength() const60*0b57cec5SDimitry Andric uint32_t DebugSubsectionRecordBuilder::calculateSerializedLength() const {
61*0b57cec5SDimitry Andric   uint32_t DataSize = Subsection ? Subsection->calculateSerializedSize()
62*0b57cec5SDimitry Andric                                  : Contents.getRecordData().getLength();
63*0b57cec5SDimitry Andric   // The length of the entire subsection is always padded to 4 bytes,
64*0b57cec5SDimitry Andric   // regardless of the container kind.
65*0b57cec5SDimitry Andric   return sizeof(DebugSubsectionHeader) + alignTo(DataSize, 4);
66*0b57cec5SDimitry Andric }
67*0b57cec5SDimitry Andric 
commit(BinaryStreamWriter & Writer,CodeViewContainer Container) const68*0b57cec5SDimitry Andric Error DebugSubsectionRecordBuilder::commit(BinaryStreamWriter &Writer,
69*0b57cec5SDimitry Andric                                            CodeViewContainer Container) const {
70*0b57cec5SDimitry Andric   assert(Writer.getOffset() % alignOf(Container) == 0 &&
71*0b57cec5SDimitry Andric          "Debug Subsection not properly aligned");
72*0b57cec5SDimitry Andric 
73*0b57cec5SDimitry Andric   DebugSubsectionHeader Header;
74*0b57cec5SDimitry Andric   Header.Kind = uint32_t(Subsection ? Subsection->kind() : Contents.kind());
75*0b57cec5SDimitry Andric   // The value written into the Header's Length field is only padded to the
76*0b57cec5SDimitry Andric   // container's alignment
77*0b57cec5SDimitry Andric   uint32_t DataSize = Subsection ? Subsection->calculateSerializedSize()
78*0b57cec5SDimitry Andric                                  : Contents.getRecordData().getLength();
79*0b57cec5SDimitry Andric   Header.Length = alignTo(DataSize, alignOf(Container));
80*0b57cec5SDimitry Andric 
81*0b57cec5SDimitry Andric   if (auto EC = Writer.writeObject(Header))
82*0b57cec5SDimitry Andric     return EC;
83*0b57cec5SDimitry Andric   if (Subsection) {
84*0b57cec5SDimitry Andric     if (auto EC = Subsection->commit(Writer))
85*0b57cec5SDimitry Andric       return EC;
86*0b57cec5SDimitry Andric   } else {
87*0b57cec5SDimitry Andric     if (auto EC = Writer.writeStreamRef(Contents.getRecordData()))
88*0b57cec5SDimitry Andric       return EC;
89*0b57cec5SDimitry Andric   }
90*0b57cec5SDimitry Andric   if (auto EC = Writer.padToAlignment(4))
91*0b57cec5SDimitry Andric     return EC;
92*0b57cec5SDimitry Andric 
93*0b57cec5SDimitry Andric   return Error::success();
94*0b57cec5SDimitry Andric }
95*0b57cec5SDimitry Andric