1*a580b014SDimitry Andric //===- DebugLinesSubsection.cpp -------------------------------------------===//
289cb50c9SDimitry Andric //
389cb50c9SDimitry Andric //                     The LLVM Compiler Infrastructure
489cb50c9SDimitry Andric //
589cb50c9SDimitry Andric // This file is distributed under the University of Illinois Open Source
689cb50c9SDimitry Andric // License. See LICENSE.TXT for details.
789cb50c9SDimitry Andric //
889cb50c9SDimitry Andric //===----------------------------------------------------------------------===//
989cb50c9SDimitry Andric 
1089cb50c9SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
11*a580b014SDimitry Andric #include "llvm/ADT/ArrayRef.h"
12*a580b014SDimitry Andric #include "llvm/DebugInfo/CodeView/CodeView.h"
1389cb50c9SDimitry Andric #include "llvm/DebugInfo/CodeView/CodeViewError.h"
1489cb50c9SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
15*a580b014SDimitry Andric #include "llvm/Support/BinaryStreamReader.h"
16*a580b014SDimitry Andric #include "llvm/Support/BinaryStreamWriter.h"
17*a580b014SDimitry Andric #include "llvm/Support/Error.h"
18*a580b014SDimitry Andric #include <cassert>
19*a580b014SDimitry Andric #include <cstdint>
2089cb50c9SDimitry Andric 
2189cb50c9SDimitry Andric using namespace llvm;
2289cb50c9SDimitry Andric using namespace llvm::codeview;
2389cb50c9SDimitry Andric 
operator ()(BinaryStreamRef Stream,uint32_t & Len,LineColumnEntry & Item)24db17bf38SDimitry Andric Error LineColumnExtractor::operator()(BinaryStreamRef Stream, uint32_t &Len,
25db17bf38SDimitry Andric                                       LineColumnEntry &Item) {
2689cb50c9SDimitry Andric   const LineBlockFragmentHeader *BlockHeader;
2789cb50c9SDimitry Andric   BinaryStreamReader Reader(Stream);
2889cb50c9SDimitry Andric   if (auto EC = Reader.readObject(BlockHeader))
2989cb50c9SDimitry Andric     return EC;
3089cb50c9SDimitry Andric   bool HasColumn = Header->Flags & uint16_t(LF_HaveColumns);
3189cb50c9SDimitry Andric   uint32_t LineInfoSize =
3289cb50c9SDimitry Andric       BlockHeader->NumLines *
3389cb50c9SDimitry Andric       (sizeof(LineNumberEntry) + (HasColumn ? sizeof(ColumnNumberEntry) : 0));
3489cb50c9SDimitry Andric   if (BlockHeader->BlockSize < sizeof(LineBlockFragmentHeader))
3589cb50c9SDimitry Andric     return make_error<CodeViewError>(cv_error_code::corrupt_record,
3689cb50c9SDimitry Andric                                      "Invalid line block record size");
3789cb50c9SDimitry Andric   uint32_t Size = BlockHeader->BlockSize - sizeof(LineBlockFragmentHeader);
3889cb50c9SDimitry Andric   if (LineInfoSize > Size)
3989cb50c9SDimitry Andric     return make_error<CodeViewError>(cv_error_code::corrupt_record,
4089cb50c9SDimitry Andric                                      "Invalid line block record size");
4189cb50c9SDimitry Andric   // The value recorded in BlockHeader->BlockSize includes the size of
4289cb50c9SDimitry Andric   // LineBlockFragmentHeader.
4389cb50c9SDimitry Andric   Len = BlockHeader->BlockSize;
4489cb50c9SDimitry Andric   Item.NameIndex = BlockHeader->NameIndex;
4589cb50c9SDimitry Andric   if (auto EC = Reader.readArray(Item.LineNumbers, BlockHeader->NumLines))
4689cb50c9SDimitry Andric     return EC;
4789cb50c9SDimitry Andric   if (HasColumn) {
4889cb50c9SDimitry Andric     if (auto EC = Reader.readArray(Item.Columns, BlockHeader->NumLines))
4989cb50c9SDimitry Andric       return EC;
5089cb50c9SDimitry Andric   }
5189cb50c9SDimitry Andric   return Error::success();
5289cb50c9SDimitry Andric }
5389cb50c9SDimitry Andric 
DebugLinesSubsectionRef()5489cb50c9SDimitry Andric DebugLinesSubsectionRef::DebugLinesSubsectionRef()
5589cb50c9SDimitry Andric     : DebugSubsectionRef(DebugSubsectionKind::Lines) {}
5689cb50c9SDimitry Andric 
initialize(BinaryStreamReader Reader)5789cb50c9SDimitry Andric Error DebugLinesSubsectionRef::initialize(BinaryStreamReader Reader) {
5889cb50c9SDimitry Andric   if (auto EC = Reader.readObject(Header))
5989cb50c9SDimitry Andric     return EC;
6089cb50c9SDimitry Andric 
61db17bf38SDimitry Andric   LinesAndColumns.getExtractor().Header = Header;
62db17bf38SDimitry Andric   if (auto EC = Reader.readArray(LinesAndColumns, Reader.bytesRemaining()))
6389cb50c9SDimitry Andric     return EC;
6489cb50c9SDimitry Andric 
6589cb50c9SDimitry Andric   return Error::success();
6689cb50c9SDimitry Andric }
6789cb50c9SDimitry Andric 
hasColumnInfo() const6889cb50c9SDimitry Andric bool DebugLinesSubsectionRef::hasColumnInfo() const {
6989cb50c9SDimitry Andric   return !!(Header->Flags & LF_HaveColumns);
7089cb50c9SDimitry Andric }
7189cb50c9SDimitry Andric 
DebugLinesSubsection(DebugChecksumsSubsection & Checksums,DebugStringTableSubsection & Strings)7289cb50c9SDimitry Andric DebugLinesSubsection::DebugLinesSubsection(DebugChecksumsSubsection &Checksums,
7389cb50c9SDimitry Andric                                            DebugStringTableSubsection &Strings)
7489cb50c9SDimitry Andric     : DebugSubsection(DebugSubsectionKind::Lines), Checksums(Checksums) {}
7589cb50c9SDimitry Andric 
createBlock(StringRef FileName)7689cb50c9SDimitry Andric void DebugLinesSubsection::createBlock(StringRef FileName) {
7789cb50c9SDimitry Andric   uint32_t Offset = Checksums.mapChecksumOffset(FileName);
7889cb50c9SDimitry Andric 
7989cb50c9SDimitry Andric   Blocks.emplace_back(Offset);
8089cb50c9SDimitry Andric }
8189cb50c9SDimitry Andric 
addLineInfo(uint32_t Offset,const LineInfo & Line)8289cb50c9SDimitry Andric void DebugLinesSubsection::addLineInfo(uint32_t Offset, const LineInfo &Line) {
8389cb50c9SDimitry Andric   Block &B = Blocks.back();
8489cb50c9SDimitry Andric   LineNumberEntry LNE;
8589cb50c9SDimitry Andric   LNE.Flags = Line.getRawData();
8689cb50c9SDimitry Andric   LNE.Offset = Offset;
8789cb50c9SDimitry Andric   B.Lines.push_back(LNE);
8889cb50c9SDimitry Andric }
8989cb50c9SDimitry Andric 
addLineAndColumnInfo(uint32_t Offset,const LineInfo & Line,uint32_t ColStart,uint32_t ColEnd)9089cb50c9SDimitry Andric void DebugLinesSubsection::addLineAndColumnInfo(uint32_t Offset,
9189cb50c9SDimitry Andric                                                 const LineInfo &Line,
9289cb50c9SDimitry Andric                                                 uint32_t ColStart,
9389cb50c9SDimitry Andric                                                 uint32_t ColEnd) {
9489cb50c9SDimitry Andric   Block &B = Blocks.back();
9589cb50c9SDimitry Andric   assert(B.Lines.size() == B.Columns.size());
9689cb50c9SDimitry Andric 
9789cb50c9SDimitry Andric   addLineInfo(Offset, Line);
9889cb50c9SDimitry Andric   ColumnNumberEntry CNE;
9989cb50c9SDimitry Andric   CNE.StartColumn = ColStart;
10089cb50c9SDimitry Andric   CNE.EndColumn = ColEnd;
10189cb50c9SDimitry Andric   B.Columns.push_back(CNE);
10289cb50c9SDimitry Andric }
10389cb50c9SDimitry Andric 
commit(BinaryStreamWriter & Writer) const10489cb50c9SDimitry Andric Error DebugLinesSubsection::commit(BinaryStreamWriter &Writer) const {
10589cb50c9SDimitry Andric   LineFragmentHeader Header;
10689cb50c9SDimitry Andric   Header.CodeSize = CodeSize;
10789cb50c9SDimitry Andric   Header.Flags = hasColumnInfo() ? LF_HaveColumns : 0;
10889cb50c9SDimitry Andric   Header.RelocOffset = RelocOffset;
10989cb50c9SDimitry Andric   Header.RelocSegment = RelocSegment;
11089cb50c9SDimitry Andric 
11189cb50c9SDimitry Andric   if (auto EC = Writer.writeObject(Header))
11289cb50c9SDimitry Andric     return EC;
11389cb50c9SDimitry Andric 
11489cb50c9SDimitry Andric   for (const auto &B : Blocks) {
11589cb50c9SDimitry Andric     LineBlockFragmentHeader BlockHeader;
11689cb50c9SDimitry Andric     assert(B.Lines.size() == B.Columns.size() || B.Columns.empty());
11789cb50c9SDimitry Andric 
11889cb50c9SDimitry Andric     BlockHeader.NumLines = B.Lines.size();
11989cb50c9SDimitry Andric     BlockHeader.BlockSize = sizeof(LineBlockFragmentHeader);
12089cb50c9SDimitry Andric     BlockHeader.BlockSize += BlockHeader.NumLines * sizeof(LineNumberEntry);
12189cb50c9SDimitry Andric     if (hasColumnInfo())
12289cb50c9SDimitry Andric       BlockHeader.BlockSize += BlockHeader.NumLines * sizeof(ColumnNumberEntry);
12389cb50c9SDimitry Andric     BlockHeader.NameIndex = B.ChecksumBufferOffset;
12489cb50c9SDimitry Andric     if (auto EC = Writer.writeObject(BlockHeader))
12589cb50c9SDimitry Andric       return EC;
12689cb50c9SDimitry Andric 
12789cb50c9SDimitry Andric     if (auto EC = Writer.writeArray(makeArrayRef(B.Lines)))
12889cb50c9SDimitry Andric       return EC;
12989cb50c9SDimitry Andric 
13089cb50c9SDimitry Andric     if (hasColumnInfo()) {
13189cb50c9SDimitry Andric       if (auto EC = Writer.writeArray(makeArrayRef(B.Columns)))
13289cb50c9SDimitry Andric         return EC;
13389cb50c9SDimitry Andric     }
13489cb50c9SDimitry Andric   }
13589cb50c9SDimitry Andric   return Error::success();
13689cb50c9SDimitry Andric }
13789cb50c9SDimitry Andric 
calculateSerializedSize() const13889cb50c9SDimitry Andric uint32_t DebugLinesSubsection::calculateSerializedSize() const {
13989cb50c9SDimitry Andric   uint32_t Size = sizeof(LineFragmentHeader);
14089cb50c9SDimitry Andric   for (const auto &B : Blocks) {
14189cb50c9SDimitry Andric     Size += sizeof(LineBlockFragmentHeader);
14289cb50c9SDimitry Andric     Size += B.Lines.size() * sizeof(LineNumberEntry);
14389cb50c9SDimitry Andric     if (hasColumnInfo())
14489cb50c9SDimitry Andric       Size += B.Columns.size() * sizeof(ColumnNumberEntry);
14589cb50c9SDimitry Andric   }
14689cb50c9SDimitry Andric   return Size;
14789cb50c9SDimitry Andric }
14889cb50c9SDimitry Andric 
setRelocationAddress(uint16_t Segment,uint32_t Offset)14989cb50c9SDimitry Andric void DebugLinesSubsection::setRelocationAddress(uint16_t Segment,
150db17bf38SDimitry Andric                                                 uint32_t Offset) {
15189cb50c9SDimitry Andric   RelocOffset = Offset;
15289cb50c9SDimitry Andric   RelocSegment = Segment;
15389cb50c9SDimitry Andric }
15489cb50c9SDimitry Andric 
setCodeSize(uint32_t Size)15589cb50c9SDimitry Andric void DebugLinesSubsection::setCodeSize(uint32_t Size) { CodeSize = Size; }
15689cb50c9SDimitry Andric 
setFlags(LineFlags Flags)15789cb50c9SDimitry Andric void DebugLinesSubsection::setFlags(LineFlags Flags) { this->Flags = Flags; }
15889cb50c9SDimitry Andric 
hasColumnInfo() const15989cb50c9SDimitry Andric bool DebugLinesSubsection::hasColumnInfo() const {
16089cb50c9SDimitry Andric   return Flags & LF_HaveColumns;
16189cb50c9SDimitry Andric }
162