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