10b57cec5SDimitry Andric //===- DebugSubsectionRecord.cpp ------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
100b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/CodeView.h"
110b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugSubsection.h"
120b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamReader.h"
130b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamWriter.h"
140b57cec5SDimitry Andric #include "llvm/Support/Error.h"
150b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
160b57cec5SDimitry Andric #include <cassert>
170b57cec5SDimitry Andric #include <cstdint>
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric using namespace llvm;
200b57cec5SDimitry Andric using namespace llvm::codeview;
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric DebugSubsectionRecord::DebugSubsectionRecord() = default;
230b57cec5SDimitry Andric 
DebugSubsectionRecord(DebugSubsectionKind Kind,BinaryStreamRef Data)240b57cec5SDimitry Andric DebugSubsectionRecord::DebugSubsectionRecord(DebugSubsectionKind Kind,
255ffd83dbSDimitry Andric                                              BinaryStreamRef Data)
265ffd83dbSDimitry Andric     : Kind(Kind), Data(Data) {}
270b57cec5SDimitry Andric 
initialize(BinaryStreamRef Stream,DebugSubsectionRecord & Info)280b57cec5SDimitry Andric Error DebugSubsectionRecord::initialize(BinaryStreamRef Stream,
295ffd83dbSDimitry Andric                                         DebugSubsectionRecord &Info) {
300b57cec5SDimitry Andric   const DebugSubsectionHeader *Header;
310b57cec5SDimitry Andric   BinaryStreamReader Reader(Stream);
320b57cec5SDimitry Andric   if (auto EC = Reader.readObject(Header))
330b57cec5SDimitry Andric     return EC;
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric   DebugSubsectionKind Kind =
360b57cec5SDimitry Andric       static_cast<DebugSubsectionKind>(uint32_t(Header->Kind));
370b57cec5SDimitry Andric   if (auto EC = Reader.readStreamRef(Info.Data, Header->Length))
380b57cec5SDimitry Andric     return EC;
390b57cec5SDimitry Andric   Info.Kind = Kind;
400b57cec5SDimitry Andric   return Error::success();
410b57cec5SDimitry Andric }
420b57cec5SDimitry Andric 
getRecordLength() const430b57cec5SDimitry Andric uint32_t DebugSubsectionRecord::getRecordLength() const {
440b57cec5SDimitry Andric   return sizeof(DebugSubsectionHeader) + Data.getLength();
450b57cec5SDimitry Andric }
460b57cec5SDimitry Andric 
kind() const470b57cec5SDimitry Andric DebugSubsectionKind DebugSubsectionRecord::kind() const { return Kind; }
480b57cec5SDimitry Andric 
getRecordData() const490b57cec5SDimitry Andric BinaryStreamRef DebugSubsectionRecord::getRecordData() const { return Data; }
500b57cec5SDimitry Andric 
DebugSubsectionRecordBuilder(std::shared_ptr<DebugSubsection> Subsection)510b57cec5SDimitry Andric DebugSubsectionRecordBuilder::DebugSubsectionRecordBuilder(
525ffd83dbSDimitry Andric     std::shared_ptr<DebugSubsection> Subsection)
535ffd83dbSDimitry Andric     : Subsection(std::move(Subsection)) {}
540b57cec5SDimitry Andric 
DebugSubsectionRecordBuilder(const DebugSubsectionRecord & Contents)550b57cec5SDimitry Andric DebugSubsectionRecordBuilder::DebugSubsectionRecordBuilder(
565ffd83dbSDimitry Andric     const DebugSubsectionRecord &Contents)
575ffd83dbSDimitry Andric     : Contents(Contents) {}
580b57cec5SDimitry Andric 
calculateSerializedLength() const595ffd83dbSDimitry Andric uint32_t DebugSubsectionRecordBuilder::calculateSerializedLength() const {
600b57cec5SDimitry Andric   uint32_t DataSize = Subsection ? Subsection->calculateSerializedSize()
610b57cec5SDimitry Andric                                  : Contents.getRecordData().getLength();
620b57cec5SDimitry Andric   // The length of the entire subsection is always padded to 4 bytes,
630b57cec5SDimitry Andric   // regardless of the container kind.
640b57cec5SDimitry Andric   return sizeof(DebugSubsectionHeader) + alignTo(DataSize, 4);
650b57cec5SDimitry Andric }
660b57cec5SDimitry Andric 
commit(BinaryStreamWriter & Writer,CodeViewContainer Container) const675ffd83dbSDimitry Andric Error DebugSubsectionRecordBuilder::commit(BinaryStreamWriter &Writer,
685ffd83dbSDimitry Andric                                            CodeViewContainer Container) const {
690b57cec5SDimitry Andric   assert(Writer.getOffset() % alignOf(Container) == 0 &&
700b57cec5SDimitry Andric          "Debug Subsection not properly aligned");
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric   DebugSubsectionHeader Header;
730b57cec5SDimitry Andric   Header.Kind = uint32_t(Subsection ? Subsection->kind() : Contents.kind());
740b57cec5SDimitry Andric   // The value written into the Header's Length field is only padded to the
750b57cec5SDimitry Andric   // container's alignment
760b57cec5SDimitry Andric   uint32_t DataSize = Subsection ? Subsection->calculateSerializedSize()
770b57cec5SDimitry Andric                                  : Contents.getRecordData().getLength();
780b57cec5SDimitry Andric   Header.Length = alignTo(DataSize, alignOf(Container));
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric   if (auto EC = Writer.writeObject(Header))
810b57cec5SDimitry Andric     return EC;
820b57cec5SDimitry Andric   if (Subsection) {
830b57cec5SDimitry Andric     if (auto EC = Subsection->commit(Writer))
840b57cec5SDimitry Andric       return EC;
850b57cec5SDimitry Andric   } else {
860b57cec5SDimitry Andric     if (auto EC = Writer.writeStreamRef(Contents.getRecordData()))
870b57cec5SDimitry Andric       return EC;
880b57cec5SDimitry Andric   }
890b57cec5SDimitry Andric   if (auto EC = Writer.padToAlignment(4))
900b57cec5SDimitry Andric     return EC;
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric   return Error::success();
930b57cec5SDimitry Andric }
94