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