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