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