LLVM  15.0.0git
CodeViewRecordIO.cpp
Go to the documentation of this file.
1 //===- CodeViewRecordIO.cpp -------------------------------------*- C++ -*-===//
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 
16 
17 using namespace llvm;
18 using namespace llvm::codeview;
19 
21  RecordLimit Limit;
22  Limit.MaxLength = MaxLength;
23  Limit.BeginOffset = getCurrentOffset();
24  Limits.push_back(Limit);
25  return Error::success();
26 }
27 
29  assert(!Limits.empty() && "Not in a record!");
30  Limits.pop_back();
31  // We would like to assert that we actually read / wrote all the bytes that we
32  // expected to for this record, but unfortunately we can't do this. Some
33  // producers such as MASM over-allocate for certain types of records and
34  // commit the extraneous data, so when reading we can't be sure every byte
35  // will have been read. And when writing we over-allocate temporarily since
36  // we don't know how big the record is until we're finished writing it, so
37  // even though we don't commit the extraneous data, we still can't guarantee
38  // we're at the end of the allocated data.
39 
40  if (isStreaming()) {
41  // For streaming mode, add padding to align with 4 byte boundaries for each
42  // record
44  if (Align == 0)
45  return Error::success();
46 
47  int PaddingBytes = 4 - Align;
48  while (PaddingBytes > 0) {
49  char Pad = static_cast<uint8_t>(LF_PAD0 + PaddingBytes);
50  StringRef BytesSR = StringRef(&Pad, sizeof(Pad));
51  Streamer->emitBytes(BytesSR);
52  --PaddingBytes;
53  }
54  resetStreamedLen();
55  }
56  return Error::success();
57 }
58 
60  if (isStreaming())
61  return 0;
62 
63  assert(!Limits.empty() && "Not in a record!");
64 
65  // The max length of the next field is the minimum of all lengths that would
66  // be allowed by any of the sub-records we're in. In practice, we can only
67  // ever be at most 1 sub-record deep (in a FieldList), but this works for
68  // the general case.
69  uint32_t Offset = getCurrentOffset();
70  Optional<uint32_t> Min = Limits.front().bytesRemaining(Offset);
71  for (auto X : makeArrayRef(Limits).drop_front()) {
72  Optional<uint32_t> ThisMin = X.bytesRemaining(Offset);
73  if (ThisMin.hasValue())
74  Min = (Min.hasValue()) ? std::min(*Min, *ThisMin) : *ThisMin;
75  }
76  assert(Min.hasValue() && "Every field must have a maximum length!");
77 
78  return *Min;
79 }
80 
82  if (isReading())
83  return Reader->padToAlignment(Align);
84  return Writer->padToAlignment(Align);
85 }
86 
88  assert(!isWriting() && "Cannot skip padding while writing!");
89 
90  if (Reader->bytesRemaining() == 0)
91  return Error::success();
92 
93  uint8_t Leaf = Reader->peek();
94  if (Leaf < LF_PAD0)
95  return Error::success();
96  // Leaf is greater than 0xf0. We should advance by the number of bytes in
97  // the low 4 bits.
98  unsigned BytesToAdvance = Leaf & 0x0F;
99  return Reader->skip(BytesToAdvance);
100 }
101 
103  const Twine &Comment) {
104  if (isStreaming()) {
105  emitComment(Comment);
106  Streamer->emitBinaryData(toStringRef(Bytes));
107  incrStreamedLen(Bytes.size());
108  } else if (isWriting()) {
109  if (auto EC = Writer->writeBytes(Bytes))
110  return EC;
111  } else {
112  if (auto EC = Reader->readBytes(Bytes, Reader->bytesRemaining()))
113  return EC;
114  }
115  return Error::success();
116 }
117 
118 Error CodeViewRecordIO::mapByteVectorTail(std::vector<uint8_t> &Bytes,
119  const Twine &Comment) {
120  ArrayRef<uint8_t> BytesRef(Bytes);
121  if (auto EC = mapByteVectorTail(BytesRef, Comment))
122  return EC;
123  if (!isWriting())
124  Bytes.assign(BytesRef.begin(), BytesRef.end());
125 
126  return Error::success();
127 }
128 
130  if (isStreaming()) {
131  std::string TypeNameStr = Streamer->getTypeName(TypeInd);
132  if (!TypeNameStr.empty())
133  emitComment(Comment + ": " + TypeNameStr);
134  else
135  emitComment(Comment);
136  Streamer->emitIntValue(TypeInd.getIndex(), sizeof(TypeInd.getIndex()));
137  incrStreamedLen(sizeof(TypeInd.getIndex()));
138  } else if (isWriting()) {
139  if (auto EC = Writer->writeInteger(TypeInd.getIndex()))
140  return EC;
141  } else {
142  uint32_t I;
143  if (auto EC = Reader->readInteger(I))
144  return EC;
145  TypeInd.setIndex(I);
146  }
147  return Error::success();
148 }
149 
151  const Twine &Comment) {
152  if (isStreaming()) {
153  if (Value >= 0)
154  emitEncodedUnsignedInteger(static_cast<uint64_t>(Value), Comment);
155  else
156  emitEncodedSignedInteger(Value, Comment);
157  } else if (isWriting()) {
158  if (Value >= 0) {
159  if (auto EC = writeEncodedUnsignedInteger(static_cast<uint64_t>(Value)))
160  return EC;
161  } else {
162  if (auto EC = writeEncodedSignedInteger(Value))
163  return EC;
164  }
165  } else {
166  APSInt N;
167  if (auto EC = consume(*Reader, N))
168  return EC;
169  Value = N.getExtValue();
170  }
171 
172  return Error::success();
173 }
174 
176  const Twine &Comment) {
177  if (isStreaming())
178  emitEncodedUnsignedInteger(Value, Comment);
179  else if (isWriting()) {
180  if (auto EC = writeEncodedUnsignedInteger(Value))
181  return EC;
182  } else {
183  APSInt N;
184  if (auto EC = consume(*Reader, N))
185  return EC;
186  Value = N.getZExtValue();
187  }
188  return Error::success();
189 }
190 
192  if (isStreaming()) {
193  // FIXME: We also need to handle big values here, but it's
194  // not clear how we can excercise this code path yet.
195  if (Value.isSigned())
196  emitEncodedSignedInteger(Value.getSExtValue(), Comment);
197  else
198  emitEncodedUnsignedInteger(Value.getZExtValue(), Comment);
199  } else if (isWriting()) {
200  if (Value.isSigned())
201  return writeEncodedSignedInteger(
202  Value.isSingleWord() ? Value.getSExtValue() : INT64_MIN);
203  return writeEncodedUnsignedInteger(Value.getLimitedValue());
204  } else
205  return consume(*Reader, Value);
206  return Error::success();
207 }
208 
210  if (isStreaming()) {
211  auto NullTerminatedString = StringRef(Value.data(), Value.size() + 1);
212  emitComment(Comment);
213  Streamer->emitBytes(NullTerminatedString);
214  incrStreamedLen(NullTerminatedString.size());
215  } else if (isWriting()) {
216  // Truncate if we attempt to write too much.
217  StringRef S = Value.take_front(maxFieldLength() - 1);
218  if (auto EC = Writer->writeCString(S))
219  return EC;
220  } else {
221  if (auto EC = Reader->readCString(Value))
222  return EC;
223  }
224  return Error::success();
225 }
226 
227 Error CodeViewRecordIO::mapGuid(GUID &Guid, const Twine &Comment) {
228  constexpr uint32_t GuidSize = 16;
229 
230  if (isStreaming()) {
231  StringRef GuidSR =
232  StringRef((reinterpret_cast<const char *>(&Guid)), GuidSize);
233  emitComment(Comment);
234  Streamer->emitBytes(GuidSR);
235  incrStreamedLen(GuidSize);
236  return Error::success();
237  }
238 
239  if (maxFieldLength() < GuidSize)
240  return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
241 
242  if (isWriting()) {
243  if (auto EC = Writer->writeBytes(Guid.Guid))
244  return EC;
245  } else {
246  ArrayRef<uint8_t> GuidBytes;
247  if (auto EC = Reader->readBytes(GuidBytes, GuidSize))
248  return EC;
249  memcpy(Guid.Guid, GuidBytes.data(), GuidSize);
250  }
251  return Error::success();
252 }
253 
255  const Twine &Comment) {
256 
257  if (!isReading()) {
258  emitComment(Comment);
259  for (auto V : Value) {
260  if (auto EC = mapStringZ(V))
261  return EC;
262  }
263  uint8_t FinalZero = 0;
264  if (auto EC = mapInteger(FinalZero))
265  return EC;
266  } else {
267  StringRef S;
268  if (auto EC = mapStringZ(S))
269  return EC;
270  while (!S.empty()) {
271  Value.push_back(S);
272  if (auto EC = mapStringZ(S))
273  return EC;
274  };
275  }
276  return Error::success();
277 }
278 
279 void CodeViewRecordIO::emitEncodedSignedInteger(const int64_t &Value,
280  const Twine &Comment) {
281  // FIXME: There are no test cases covering this function.
282  // This may be because we always consider enumerators to be unsigned.
283  // See FIXME at CodeViewDebug.cpp : CodeViewDebug::lowerTypeEnum.
285  Streamer->emitIntValue(LF_CHAR, 2);
286  emitComment(Comment);
287  Streamer->emitIntValue(Value, 1);
288  incrStreamedLen(3);
289  } else if (Value >= std::numeric_limits<int16_t>::min()) {
290  Streamer->emitIntValue(LF_SHORT, 2);
291  emitComment(Comment);
292  Streamer->emitIntValue(Value, 2);
293  incrStreamedLen(4);
294  } else if (Value >= std::numeric_limits<int32_t>::min()) {
295  Streamer->emitIntValue(LF_LONG, 2);
296  emitComment(Comment);
297  Streamer->emitIntValue(Value, 4);
298  incrStreamedLen(6);
299  } else {
300  Streamer->emitIntValue(LF_QUADWORD, 2);
301  emitComment(Comment);
302  Streamer->emitIntValue(Value, 4); // FIXME: Why not 8 (size of quadword)?
303  incrStreamedLen(6); // FIXME: Why not 10 (8 + 2)?
304  }
305 }
306 
307 void CodeViewRecordIO::emitEncodedUnsignedInteger(const uint64_t &Value,
308  const Twine &Comment) {
309  if (Value < LF_NUMERIC) {
310  emitComment(Comment);
311  Streamer->emitIntValue(Value, 2);
312  incrStreamedLen(2);
313  } else if (Value <= std::numeric_limits<uint16_t>::max()) {
314  Streamer->emitIntValue(LF_USHORT, 2);
315  emitComment(Comment);
316  Streamer->emitIntValue(Value, 2);
317  incrStreamedLen(4);
318  } else if (Value <= std::numeric_limits<uint32_t>::max()) {
319  Streamer->emitIntValue(LF_ULONG, 2);
320  emitComment(Comment);
321  Streamer->emitIntValue(Value, 4);
322  incrStreamedLen(6);
323  } else {
324  // FIXME: There are no test cases covering this block.
325  Streamer->emitIntValue(LF_UQUADWORD, 2);
326  emitComment(Comment);
327  Streamer->emitIntValue(Value, 8);
328  incrStreamedLen(6); // FIXME: Why not 10 (8 + 2)?
329  }
330 }
331 
332 Error CodeViewRecordIO::writeEncodedSignedInteger(const int64_t &Value) {
334  if (auto EC = Writer->writeInteger<uint16_t>(LF_CHAR))
335  return EC;
336  if (auto EC = Writer->writeInteger<int8_t>(Value))
337  return EC;
338  } else if (Value >= std::numeric_limits<int16_t>::min()) {
339  if (auto EC = Writer->writeInteger<uint16_t>(LF_SHORT))
340  return EC;
341  if (auto EC = Writer->writeInteger<int16_t>(Value))
342  return EC;
343  } else if (Value >= std::numeric_limits<int32_t>::min()) {
344  if (auto EC = Writer->writeInteger<uint16_t>(LF_LONG))
345  return EC;
346  if (auto EC = Writer->writeInteger<int32_t>(Value))
347  return EC;
348  } else {
349  if (auto EC = Writer->writeInteger<uint16_t>(LF_QUADWORD))
350  return EC;
351  if (auto EC = Writer->writeInteger(Value))
352  return EC;
353  }
354  return Error::success();
355 }
356 
357 Error CodeViewRecordIO::writeEncodedUnsignedInteger(const uint64_t &Value) {
358  if (Value < LF_NUMERIC) {
359  if (auto EC = Writer->writeInteger<uint16_t>(Value))
360  return EC;
361  } else if (Value <= std::numeric_limits<uint16_t>::max()) {
362  if (auto EC = Writer->writeInteger<uint16_t>(LF_USHORT))
363  return EC;
364  if (auto EC = Writer->writeInteger<uint16_t>(Value))
365  return EC;
366  } else if (Value <= std::numeric_limits<uint32_t>::max()) {
367  if (auto EC = Writer->writeInteger<uint16_t>(LF_ULONG))
368  return EC;
369  if (auto EC = Writer->writeInteger<uint32_t>(Value))
370  return EC;
371  } else {
372  if (auto EC = Writer->writeInteger<uint16_t>(LF_UQUADWORD))
373  return EC;
374  if (auto EC = Writer->writeInteger(Value))
375  return EC;
376  }
377 
378  return Error::success();
379 }
llvm::codeview::CodeViewRecordIO::getStreamedLen
uint64_t getStreamedLen()
Definition: CodeViewRecordIO.h:209
BinaryStreamReader.h
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:17
GUID.h
llvm::BinaryStreamWriter::writeInteger
Error writeInteger(T Value)
Write the integer Value to the underlying stream in the specified endianness.
Definition: BinaryStreamWriter.h:58
RecordSerialization.h
llvm::BinaryStreamReader::readBytes
Error readBytes(ArrayRef< uint8_t > &Buffer, uint32_t Size)
Read Size bytes from the underlying stream at the current offset and and set Buffer to the resulting ...
Definition: BinaryStreamReader.cpp:37
llvm::codeview::TypeIndex::setIndex
void setIndex(uint32_t I)
Definition: TypeIndex.h:112
llvm::codeview::CodeViewRecordIO::isWriting
bool isWriting() const
Definition: CodeViewRecordIO.h:77
llvm::codeview::CodeViewRecordIO::mapByteVectorTail
Error mapByteVectorTail(ArrayRef< uint8_t > &Bytes, const Twine &Comment="")
Definition: CodeViewRecordIO.cpp:102
llvm::BinaryStreamReader::skip
Error skip(uint64_t Amount)
Advance the stream's offset by Amount bytes.
Definition: BinaryStreamReader.cpp:148
llvm::Error::success
static ErrorSuccess success()
Create a success value.
Definition: Error.h:329
llvm::codeview::GUID
This represents the 'GUID' type from windows.h.
Definition: GUID.h:21
llvm::codeview::CodeViewRecordIO::mapStringZ
Error mapStringZ(StringRef &Value, const Twine &Comment="")
Definition: CodeViewRecordIO.cpp:209
llvm::BinaryStreamReader::bytesRemaining
uint64_t bytesRemaining() const
Definition: BinaryStreamReader.h:250
llvm::Optional< uint32_t >
llvm::codeview::CodeViewRecordIO::padToAlignment
Error padToAlignment(uint32_t Align)
Definition: CodeViewRecordIO.cpp:81
llvm::codeview::cv_error_code::insufficient_buffer
@ insufficient_buffer
llvm::ArrayRef::data
const T * data() const
Definition: ArrayRef.h:161
llvm::Optional::hasValue
constexpr bool hasValue() const
Definition: Optional.h:283
llvm::codeview::CodeViewRecordIO::beginRecord
Error beginRecord(Optional< uint32_t > MaxLength)
Definition: CodeViewRecordIO.cpp:20
llvm::dwarf::toStringRef
StringRef toStringRef(const Optional< DWARFFormValue > &V, StringRef Default={})
Take an optional DWARFFormValue and try to extract a string value from it.
Definition: DWARFFormValue.h:193
llvm::BinaryStreamReader::readInteger
Error readInteger(T &Dest)
Read an integer of the specified endianness into Dest and update the stream's offset.
Definition: BinaryStreamReader.h:68
llvm::APSInt
An arbitrary precision integer that knows its signedness.
Definition: APSInt.h:23
Align
uint64_t Align
Definition: ELFObjHandler.cpp:81
llvm::Align
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39
CodeView.h
llvm::BinaryStreamReader::padToAlignment
Error padToAlignment(uint32_t Align)
Definition: BinaryStreamReader.cpp:155
X
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
llvm::codeview::CodeViewRecordIO::mapStringZVectorZ
Error mapStringZVectorZ(std::vector< StringRef > &Value, const Twine &Comment="")
Definition: CodeViewRecordIO.cpp:254
llvm::codeview::CodeViewRecordIO::skipPadding
Error skipPadding()
Definition: CodeViewRecordIO.cpp:87
uint64_t
llvm::codeview::CodeViewRecordStreamer::getTypeName
virtual std::string getTypeName(TypeIndex TI)=0
llvm::BinaryStreamReader::readCString
Error readCString(StringRef &Dest)
Read a null terminated string from Dest.
Definition: BinaryStreamReader.cpp:74
I
#define I(x, y, z)
Definition: MD5.cpp:58
CodeViewRecordIO.h
llvm::codeview::CodeViewRecordStreamer::emitBinaryData
virtual void emitBinaryData(StringRef Data)=0
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::BinaryStreamWriter::writeCString
Error writeCString(StringRef Str)
Write the string Str to the underlying stream followed by a null terminator.
Definition: BinaryStreamWriter.cpp:47
memcpy
<%struct.s * > cast struct s *S to sbyte *< sbyte * > sbyte uint cast struct s *agg result to sbyte *< sbyte * > sbyte uint cast struct s *memtmp to sbyte *< sbyte * > sbyte uint ret void llc ends up issuing two memcpy or custom lower memcpy(of small size) to be ldmia/stmia. I think option 2 is better but the current register allocator cannot allocate a chunk of registers at a time. A feasible temporary solution is to use specific physical registers at the lowering time for small(<
llvm::codeview::CompileSym2Flags::EC
@ EC
llvm::codeview::consume
Error consume(BinaryStreamReader &Reader)
Definition: RecordSerialization.h:45
llvm::ArrayRef< uint8_t >
llvm::min
Expected< ExpressionValue > min(const ExpressionValue &Lhs, const ExpressionValue &Rhs)
Definition: FileCheck.cpp:357
llvm::BinaryStreamWriter::writeBytes
Error writeBytes(ArrayRef< uint8_t > Buffer)
Write the bytes specified in Buffer to the underlying stream.
Definition: BinaryStreamWriter.cpp:28
llvm::codeview::CodeViewRecordIO::isStreaming
bool isStreaming() const
Definition: CodeViewRecordIO.h:71
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:58
uint32_t
llvm::codeview::CodeViewRecordIO::mapInteger
Error mapInteger(TypeIndex &TypeInd, const Twine &Comment="")
Definition: CodeViewRecordIO.cpp:129
llvm::codeview::CodeViewRecordIO::maxFieldLength
uint32_t maxFieldLength() const
Definition: CodeViewRecordIO.cpp:59
S
add sub stmia L5 ldr r0 bl L_printf $stub Instead of a and a wouldn t it be better to do three moves *Return an aggregate type is even return S
Definition: README.txt:210
llvm::Twine
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:83
llvm::codeview::CodeViewRecordIO::mapEncodedInteger
Error mapEncodedInteger(int64_t &Value, const Twine &Comment="")
Definition: CodeViewRecordIO.cpp:150
uint16_t
llvm::codeview::CodeViewRecordIO::endRecord
Error endRecord()
Definition: CodeViewRecordIO.cpp:28
llvm::ArrayRef::begin
iterator begin() const
Definition: ArrayRef.h:152
llvm::BinaryStreamWriter::padToAlignment
Error padToAlignment(uint32_t Align)
Definition: BinaryStreamWriter.cpp:95
llvm::Error
Lightweight error class with error context and mandatory checking.
Definition: Error.h:155
llvm::codeview::GUID::Guid
uint8_t Guid[16]
Definition: GUID.h:22
llvm::codeview::TypeIndex::getIndex
uint32_t getIndex() const
Definition: TypeIndex.h:111
TypeIndex.h
llvm::codeview
Definition: AppendingTypeTableBuilder.h:22
llvm::makeArrayRef
ArrayRef< T > makeArrayRef(const T &OneElt)
Construct an ArrayRef from a single element.
Definition: ArrayRef.h:475
llvm::codeview::CodeViewRecordStreamer::emitIntValue
virtual void emitIntValue(uint64_t Value, unsigned Size)=0
llvm::codeview::CodeViewRecordIO::isReading
bool isReading() const
Definition: CodeViewRecordIO.h:74
N
#define N
llvm::BinaryStreamReader::peek
uint8_t peek() const
Examine the next byte of the underlying stream without advancing the stream's offset.
Definition: BinaryStreamReader.cpp:160
llvm::ArrayRef::size
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:164
llvm::max
Align max(MaybeAlign Lhs, Align Rhs)
Definition: Alignment.h:340
llvm::codeview::TypeIndex
A 32-bit type reference.
Definition: TypeIndex.h:96
llvm::codeview::CodeViewRecordIO::mapGuid
Error mapGuid(GUID &Guid, const Twine &Comment="")
Definition: CodeViewRecordIO.cpp:227
BinaryStreamWriter.h
llvm::Value
LLVM Value Representation.
Definition: Value.h:74
llvm::codeview::CodeViewRecordStreamer::emitBytes
virtual void emitBytes(StringRef Data)=0
llvm::ArrayRef::end
iterator end() const
Definition: ArrayRef.h:153
INT64_MIN
#define INT64_MIN
Definition: DataTypes.h:74