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