1*0b57cec5SDimitry Andric //===- DebugLinesSubsection.cpp -------------------------------------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric 9*0b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" 10*0b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h" 11*0b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/CodeView.h" 12*0b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/CodeViewError.h" 13*0b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" 14*0b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamReader.h" 15*0b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamWriter.h" 16*0b57cec5SDimitry Andric #include "llvm/Support/Error.h" 17*0b57cec5SDimitry Andric #include <cassert> 18*0b57cec5SDimitry Andric #include <cstdint> 19*0b57cec5SDimitry Andric 20*0b57cec5SDimitry Andric using namespace llvm; 21*0b57cec5SDimitry Andric using namespace llvm::codeview; 22*0b57cec5SDimitry Andric 23*0b57cec5SDimitry Andric Error LineColumnExtractor::operator()(BinaryStreamRef Stream, uint32_t &Len, 24*0b57cec5SDimitry Andric LineColumnEntry &Item) { 25*0b57cec5SDimitry Andric const LineBlockFragmentHeader *BlockHeader; 26*0b57cec5SDimitry Andric BinaryStreamReader Reader(Stream); 27*0b57cec5SDimitry Andric if (auto EC = Reader.readObject(BlockHeader)) 28*0b57cec5SDimitry Andric return EC; 29*0b57cec5SDimitry Andric bool HasColumn = Header->Flags & uint16_t(LF_HaveColumns); 30*0b57cec5SDimitry Andric uint32_t LineInfoSize = 31*0b57cec5SDimitry Andric BlockHeader->NumLines * 32*0b57cec5SDimitry Andric (sizeof(LineNumberEntry) + (HasColumn ? sizeof(ColumnNumberEntry) : 0)); 33*0b57cec5SDimitry Andric if (BlockHeader->BlockSize < sizeof(LineBlockFragmentHeader)) 34*0b57cec5SDimitry Andric return make_error<CodeViewError>(cv_error_code::corrupt_record, 35*0b57cec5SDimitry Andric "Invalid line block record size"); 36*0b57cec5SDimitry Andric uint32_t Size = BlockHeader->BlockSize - sizeof(LineBlockFragmentHeader); 37*0b57cec5SDimitry Andric if (LineInfoSize > Size) 38*0b57cec5SDimitry Andric return make_error<CodeViewError>(cv_error_code::corrupt_record, 39*0b57cec5SDimitry Andric "Invalid line block record size"); 40*0b57cec5SDimitry Andric // The value recorded in BlockHeader->BlockSize includes the size of 41*0b57cec5SDimitry Andric // LineBlockFragmentHeader. 42*0b57cec5SDimitry Andric Len = BlockHeader->BlockSize; 43*0b57cec5SDimitry Andric Item.NameIndex = BlockHeader->NameIndex; 44*0b57cec5SDimitry Andric if (auto EC = Reader.readArray(Item.LineNumbers, BlockHeader->NumLines)) 45*0b57cec5SDimitry Andric return EC; 46*0b57cec5SDimitry Andric if (HasColumn) { 47*0b57cec5SDimitry Andric if (auto EC = Reader.readArray(Item.Columns, BlockHeader->NumLines)) 48*0b57cec5SDimitry Andric return EC; 49*0b57cec5SDimitry Andric } 50*0b57cec5SDimitry Andric return Error::success(); 51*0b57cec5SDimitry Andric } 52*0b57cec5SDimitry Andric 53*0b57cec5SDimitry Andric DebugLinesSubsectionRef::DebugLinesSubsectionRef() 54*0b57cec5SDimitry Andric : DebugSubsectionRef(DebugSubsectionKind::Lines) {} 55*0b57cec5SDimitry Andric 56*0b57cec5SDimitry Andric Error DebugLinesSubsectionRef::initialize(BinaryStreamReader Reader) { 57*0b57cec5SDimitry Andric if (auto EC = Reader.readObject(Header)) 58*0b57cec5SDimitry Andric return EC; 59*0b57cec5SDimitry Andric 60*0b57cec5SDimitry Andric LinesAndColumns.getExtractor().Header = Header; 61*0b57cec5SDimitry Andric if (auto EC = Reader.readArray(LinesAndColumns, Reader.bytesRemaining())) 62*0b57cec5SDimitry Andric return EC; 63*0b57cec5SDimitry Andric 64*0b57cec5SDimitry Andric return Error::success(); 65*0b57cec5SDimitry Andric } 66*0b57cec5SDimitry Andric 67*0b57cec5SDimitry Andric bool DebugLinesSubsectionRef::hasColumnInfo() const { 68*0b57cec5SDimitry Andric return !!(Header->Flags & LF_HaveColumns); 69*0b57cec5SDimitry Andric } 70*0b57cec5SDimitry Andric 71*0b57cec5SDimitry Andric DebugLinesSubsection::DebugLinesSubsection(DebugChecksumsSubsection &Checksums, 72*0b57cec5SDimitry Andric DebugStringTableSubsection &Strings) 73*0b57cec5SDimitry Andric : DebugSubsection(DebugSubsectionKind::Lines), Checksums(Checksums) {} 74*0b57cec5SDimitry Andric 75*0b57cec5SDimitry Andric void DebugLinesSubsection::createBlock(StringRef FileName) { 76*0b57cec5SDimitry Andric uint32_t Offset = Checksums.mapChecksumOffset(FileName); 77*0b57cec5SDimitry Andric 78*0b57cec5SDimitry Andric Blocks.emplace_back(Offset); 79*0b57cec5SDimitry Andric } 80*0b57cec5SDimitry Andric 81*0b57cec5SDimitry Andric void DebugLinesSubsection::addLineInfo(uint32_t Offset, const LineInfo &Line) { 82*0b57cec5SDimitry Andric Block &B = Blocks.back(); 83*0b57cec5SDimitry Andric LineNumberEntry LNE; 84*0b57cec5SDimitry Andric LNE.Flags = Line.getRawData(); 85*0b57cec5SDimitry Andric LNE.Offset = Offset; 86*0b57cec5SDimitry Andric B.Lines.push_back(LNE); 87*0b57cec5SDimitry Andric } 88*0b57cec5SDimitry Andric 89*0b57cec5SDimitry Andric void DebugLinesSubsection::addLineAndColumnInfo(uint32_t Offset, 90*0b57cec5SDimitry Andric const LineInfo &Line, 91*0b57cec5SDimitry Andric uint32_t ColStart, 92*0b57cec5SDimitry Andric uint32_t ColEnd) { 93*0b57cec5SDimitry Andric Block &B = Blocks.back(); 94*0b57cec5SDimitry Andric assert(B.Lines.size() == B.Columns.size()); 95*0b57cec5SDimitry Andric 96*0b57cec5SDimitry Andric addLineInfo(Offset, Line); 97*0b57cec5SDimitry Andric ColumnNumberEntry CNE; 98*0b57cec5SDimitry Andric CNE.StartColumn = ColStart; 99*0b57cec5SDimitry Andric CNE.EndColumn = ColEnd; 100*0b57cec5SDimitry Andric B.Columns.push_back(CNE); 101*0b57cec5SDimitry Andric } 102*0b57cec5SDimitry Andric 103*0b57cec5SDimitry Andric Error DebugLinesSubsection::commit(BinaryStreamWriter &Writer) const { 104*0b57cec5SDimitry Andric LineFragmentHeader Header; 105*0b57cec5SDimitry Andric Header.CodeSize = CodeSize; 106*0b57cec5SDimitry Andric Header.Flags = hasColumnInfo() ? LF_HaveColumns : 0; 107*0b57cec5SDimitry Andric Header.RelocOffset = RelocOffset; 108*0b57cec5SDimitry Andric Header.RelocSegment = RelocSegment; 109*0b57cec5SDimitry Andric 110*0b57cec5SDimitry Andric if (auto EC = Writer.writeObject(Header)) 111*0b57cec5SDimitry Andric return EC; 112*0b57cec5SDimitry Andric 113*0b57cec5SDimitry Andric for (const auto &B : Blocks) { 114*0b57cec5SDimitry Andric LineBlockFragmentHeader BlockHeader; 115*0b57cec5SDimitry Andric assert(B.Lines.size() == B.Columns.size() || B.Columns.empty()); 116*0b57cec5SDimitry Andric 117*0b57cec5SDimitry Andric BlockHeader.NumLines = B.Lines.size(); 118*0b57cec5SDimitry Andric BlockHeader.BlockSize = sizeof(LineBlockFragmentHeader); 119*0b57cec5SDimitry Andric BlockHeader.BlockSize += BlockHeader.NumLines * sizeof(LineNumberEntry); 120*0b57cec5SDimitry Andric if (hasColumnInfo()) 121*0b57cec5SDimitry Andric BlockHeader.BlockSize += BlockHeader.NumLines * sizeof(ColumnNumberEntry); 122*0b57cec5SDimitry Andric BlockHeader.NameIndex = B.ChecksumBufferOffset; 123*0b57cec5SDimitry Andric if (auto EC = Writer.writeObject(BlockHeader)) 124*0b57cec5SDimitry Andric return EC; 125*0b57cec5SDimitry Andric 126*0b57cec5SDimitry Andric if (auto EC = Writer.writeArray(makeArrayRef(B.Lines))) 127*0b57cec5SDimitry Andric return EC; 128*0b57cec5SDimitry Andric 129*0b57cec5SDimitry Andric if (hasColumnInfo()) { 130*0b57cec5SDimitry Andric if (auto EC = Writer.writeArray(makeArrayRef(B.Columns))) 131*0b57cec5SDimitry Andric return EC; 132*0b57cec5SDimitry Andric } 133*0b57cec5SDimitry Andric } 134*0b57cec5SDimitry Andric return Error::success(); 135*0b57cec5SDimitry Andric } 136*0b57cec5SDimitry Andric 137*0b57cec5SDimitry Andric uint32_t DebugLinesSubsection::calculateSerializedSize() const { 138*0b57cec5SDimitry Andric uint32_t Size = sizeof(LineFragmentHeader); 139*0b57cec5SDimitry Andric for (const auto &B : Blocks) { 140*0b57cec5SDimitry Andric Size += sizeof(LineBlockFragmentHeader); 141*0b57cec5SDimitry Andric Size += B.Lines.size() * sizeof(LineNumberEntry); 142*0b57cec5SDimitry Andric if (hasColumnInfo()) 143*0b57cec5SDimitry Andric Size += B.Columns.size() * sizeof(ColumnNumberEntry); 144*0b57cec5SDimitry Andric } 145*0b57cec5SDimitry Andric return Size; 146*0b57cec5SDimitry Andric } 147*0b57cec5SDimitry Andric 148*0b57cec5SDimitry Andric void DebugLinesSubsection::setRelocationAddress(uint16_t Segment, 149*0b57cec5SDimitry Andric uint32_t Offset) { 150*0b57cec5SDimitry Andric RelocOffset = Offset; 151*0b57cec5SDimitry Andric RelocSegment = Segment; 152*0b57cec5SDimitry Andric } 153*0b57cec5SDimitry Andric 154*0b57cec5SDimitry Andric void DebugLinesSubsection::setCodeSize(uint32_t Size) { CodeSize = Size; } 155*0b57cec5SDimitry Andric 156*0b57cec5SDimitry Andric void DebugLinesSubsection::setFlags(LineFlags Flags) { this->Flags = Flags; } 157*0b57cec5SDimitry Andric 158*0b57cec5SDimitry Andric bool DebugLinesSubsection::hasColumnInfo() const { 159*0b57cec5SDimitry Andric return Flags & LF_HaveColumns; 160*0b57cec5SDimitry Andric } 161