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