10b57cec5SDimitry Andric //===- DebugSubsectionRecord.h ----------------------------------*- C++ -*-===//
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 #ifndef LLVM_DEBUGINFO_CODEVIEW_DEBUGSUBSECTIONRECORD_H
100b57cec5SDimitry Andric #define LLVM_DEBUGINFO_CODEVIEW_DEBUGSUBSECTIONRECORD_H
110b57cec5SDimitry Andric 
120b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/CodeView.h"
130b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamArray.h"
140b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamRef.h"
150b57cec5SDimitry Andric #include "llvm/Support/Endian.h"
160b57cec5SDimitry Andric #include "llvm/Support/Error.h"
170b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
180b57cec5SDimitry Andric #include <cstdint>
190b57cec5SDimitry Andric #include <memory>
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric namespace llvm {
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric class BinaryStreamWriter;
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric namespace codeview {
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric class DebugSubsection;
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric // Corresponds to the `CV_DebugSSubsectionHeader_t` structure.
300b57cec5SDimitry Andric struct DebugSubsectionHeader {
310b57cec5SDimitry Andric   support::ulittle32_t Kind;   // codeview::DebugSubsectionKind enum
320b57cec5SDimitry Andric   support::ulittle32_t Length; // number of bytes occupied by this record.
330b57cec5SDimitry Andric };
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric class DebugSubsectionRecord {
360b57cec5SDimitry Andric public:
370b57cec5SDimitry Andric   DebugSubsectionRecord();
380b57cec5SDimitry Andric   DebugSubsectionRecord(DebugSubsectionKind Kind, BinaryStreamRef Data);
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric   static Error initialize(BinaryStreamRef Stream, DebugSubsectionRecord &Info);
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric   uint32_t getRecordLength() const;
430b57cec5SDimitry Andric   DebugSubsectionKind kind() const;
440b57cec5SDimitry Andric   BinaryStreamRef getRecordData() const;
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric private:
470b57cec5SDimitry Andric   DebugSubsectionKind Kind = DebugSubsectionKind::None;
480b57cec5SDimitry Andric   BinaryStreamRef Data;
490b57cec5SDimitry Andric };
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric class DebugSubsectionRecordBuilder {
520b57cec5SDimitry Andric public:
530b57cec5SDimitry Andric   DebugSubsectionRecordBuilder(std::shared_ptr<DebugSubsection> Subsection);
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric   /// Use this to copy existing subsections directly from source to destination.
560b57cec5SDimitry Andric   /// For example, line table subsections in an object file only need to be
570b57cec5SDimitry Andric   /// relocated before being copied into the PDB.
580b57cec5SDimitry Andric   DebugSubsectionRecordBuilder(const DebugSubsectionRecord &Contents);
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric   uint32_t calculateSerializedLength() const;
610b57cec5SDimitry Andric   Error commit(BinaryStreamWriter &Writer, CodeViewContainer Container) const;
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric private:
640b57cec5SDimitry Andric   /// The subsection to build. Will be null if Contents is non-empty.
650b57cec5SDimitry Andric   std::shared_ptr<DebugSubsection> Subsection;
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric   /// The bytes of the subsection. Only non-empty if Subsection is null.
680b57cec5SDimitry Andric   /// FIXME: Reduce the size of this.
690b57cec5SDimitry Andric   DebugSubsectionRecord Contents;
700b57cec5SDimitry Andric };
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric } // end namespace codeview
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric template <> struct VarStreamArrayExtractor<codeview::DebugSubsectionRecord> {
750b57cec5SDimitry Andric   Error operator()(BinaryStreamRef Stream, uint32_t &Length,
760b57cec5SDimitry Andric                    codeview::DebugSubsectionRecord &Info) {
770b57cec5SDimitry Andric     // FIXME: We need to pass the container type through to this function.  In
780b57cec5SDimitry Andric     // practice this isn't super important since the subsection header describes
790b57cec5SDimitry Andric     // its length and we can just skip it.  It's more important when writing.
800b57cec5SDimitry Andric     if (auto EC = codeview::DebugSubsectionRecord::initialize(Stream, Info))
810b57cec5SDimitry Andric       return EC;
820b57cec5SDimitry Andric     Length = alignTo(Info.getRecordLength(), 4);
830b57cec5SDimitry Andric     return Error::success();
840b57cec5SDimitry Andric   }
850b57cec5SDimitry Andric };
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric namespace codeview {
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric using DebugSubsectionArray = VarStreamArray<DebugSubsectionRecord>;
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric } // end namespace codeview
920b57cec5SDimitry Andric 
930b57cec5SDimitry Andric } // end namespace llvm
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric #endif // LLVM_DEBUGINFO_CODEVIEW_DEBUGSUBSECTIONRECORD_H
960b57cec5SDimitry Andric