1 //===- DebugInlineeLinesSubsection.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/DebugInlineeLinesSubsection.h"
10 #include "llvm/ADT/ArrayRef.h"
11 #include "llvm/DebugInfo/CodeView/CodeView.h"
12 #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
13 #include "llvm/Support/BinaryStreamReader.h"
14 #include "llvm/Support/BinaryStreamWriter.h"
15 #include "llvm/Support/Endian.h"
16 #include "llvm/Support/Error.h"
17 #include <cassert>
18 #include <cstdint>
19 
20 using namespace llvm;
21 using namespace llvm::codeview;
22 
23 Error VarStreamArrayExtractor<InlineeSourceLine>::
24 operator()(BinaryStreamRef Stream, uint32_t &Len, InlineeSourceLine &Item) {
25   BinaryStreamReader Reader(Stream);
26 
27   if (auto EC = Reader.readObject(Item.Header))
28     return EC;
29 
30   if (HasExtraFiles) {
31     uint32_t ExtraFileCount;
32     if (auto EC = Reader.readInteger(ExtraFileCount))
33       return EC;
34     if (auto EC = Reader.readArray(Item.ExtraFiles, ExtraFileCount))
35       return EC;
36   }
37 
38   Len = Reader.getOffset();
39   return Error::success();
40 }
41 
42 DebugInlineeLinesSubsectionRef::DebugInlineeLinesSubsectionRef()
43     : DebugSubsectionRef(DebugSubsectionKind::InlineeLines) {}
44 
45 Error DebugInlineeLinesSubsectionRef::initialize(BinaryStreamReader Reader) {
46   if (auto EC = Reader.readEnum(Signature))
47     return EC;
48 
49   Lines.getExtractor().HasExtraFiles = hasExtraFiles();
50   if (auto EC = Reader.readArray(Lines, Reader.bytesRemaining()))
51     return EC;
52 
53   assert(Reader.bytesRemaining() == 0);
54   return Error::success();
55 }
56 
57 bool DebugInlineeLinesSubsectionRef::hasExtraFiles() const {
58   return Signature == InlineeLinesSignature::ExtraFiles;
59 }
60 
61 DebugInlineeLinesSubsection::DebugInlineeLinesSubsection(
62     DebugChecksumsSubsection &Checksums, bool HasExtraFiles)
63     : DebugSubsection(DebugSubsectionKind::InlineeLines), Checksums(Checksums),
64       HasExtraFiles(HasExtraFiles) {}
65 
66 uint32_t DebugInlineeLinesSubsection::calculateSerializedSize() const {
67   // 4 bytes for the signature
68   uint32_t Size = sizeof(InlineeLinesSignature);
69 
70   // one header for each entry.
71   Size += Entries.size() * sizeof(InlineeSourceLineHeader);
72   if (HasExtraFiles) {
73     // If extra files are enabled, one count for each entry.
74     Size += Entries.size() * sizeof(uint32_t);
75 
76     // And one file id for each file.
77     Size += ExtraFileCount * sizeof(uint32_t);
78   }
79   assert(Size % 4 == 0);
80   return Size;
81 }
82 
83 Error DebugInlineeLinesSubsection::commit(BinaryStreamWriter &Writer) const {
84   InlineeLinesSignature Sig = InlineeLinesSignature::Normal;
85   if (HasExtraFiles)
86     Sig = InlineeLinesSignature::ExtraFiles;
87 
88   if (auto EC = Writer.writeEnum(Sig))
89     return EC;
90 
91   for (const auto &E : Entries) {
92     if (auto EC = Writer.writeObject(E.Header))
93       return EC;
94 
95     if (!HasExtraFiles)
96       continue;
97 
98     if (auto EC = Writer.writeInteger<uint32_t>(E.ExtraFiles.size()))
99       return EC;
100     if (auto EC = Writer.writeArray(makeArrayRef(E.ExtraFiles)))
101       return EC;
102   }
103 
104   return Error::success();
105 }
106 
107 void DebugInlineeLinesSubsection::addExtraFile(StringRef FileName) {
108   uint32_t Offset = Checksums.mapChecksumOffset(FileName);
109 
110   auto &Entry = Entries.back();
111   Entry.ExtraFiles.push_back(ulittle32_t(Offset));
112   ++ExtraFileCount;
113 }
114 
115 void DebugInlineeLinesSubsection::addInlineSite(TypeIndex FuncId,
116                                                 StringRef FileName,
117                                                 uint32_t SourceLine) {
118   uint32_t Offset = Checksums.mapChecksumOffset(FileName);
119 
120   Entries.emplace_back();
121   auto &Entry = Entries.back();
122   Entry.Header.FileID = Offset;
123   Entry.Header.SourceLineNum = SourceLine;
124   Entry.Header.Inlinee = FuncId;
125 }
126