10b57cec5SDimitry Andric //===- CodeViewRecordIO.cpp -------------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/CodeViewRecordIO.h"
10*fe013be4SDimitry Andric #include "llvm/ADT/StringExtras.h"
110b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/CodeView.h"
1281ad6265SDimitry Andric #include "llvm/DebugInfo/CodeView/GUID.h"
130b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/RecordSerialization.h"
1481ad6265SDimitry Andric #include "llvm/DebugInfo/CodeView/TypeIndex.h"
150b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamReader.h"
160b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamWriter.h"
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric using namespace llvm;
190b57cec5SDimitry Andric using namespace llvm::codeview;
200b57cec5SDimitry Andric 
beginRecord(std::optional<uint32_t> MaxLength)21bdd1243dSDimitry Andric Error CodeViewRecordIO::beginRecord(std::optional<uint32_t> MaxLength) {
220b57cec5SDimitry Andric   RecordLimit Limit;
230b57cec5SDimitry Andric   Limit.MaxLength = MaxLength;
240b57cec5SDimitry Andric   Limit.BeginOffset = getCurrentOffset();
250b57cec5SDimitry Andric   Limits.push_back(Limit);
260b57cec5SDimitry Andric   return Error::success();
270b57cec5SDimitry Andric }
280b57cec5SDimitry Andric 
endRecord()290b57cec5SDimitry Andric Error CodeViewRecordIO::endRecord() {
300b57cec5SDimitry Andric   assert(!Limits.empty() && "Not in a record!");
310b57cec5SDimitry Andric   Limits.pop_back();
320b57cec5SDimitry Andric   // We would like to assert that we actually read / wrote all the bytes that we
330b57cec5SDimitry Andric   // expected to for this record, but unfortunately we can't do this.  Some
340b57cec5SDimitry Andric   // producers such as MASM over-allocate for certain types of records and
350b57cec5SDimitry Andric   // commit the extraneous data, so when reading we can't be sure every byte
360b57cec5SDimitry Andric   // will have been read.  And when writing we over-allocate temporarily since
370b57cec5SDimitry Andric   // we don't know how big the record is until we're finished writing it, so
380b57cec5SDimitry Andric   // even though we don't commit the extraneous data, we still can't guarantee
390b57cec5SDimitry Andric   // we're at the end of the allocated data.
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric   if (isStreaming()) {
420b57cec5SDimitry Andric     // For streaming mode, add padding to align with 4 byte boundaries for each
430b57cec5SDimitry Andric     // record
440b57cec5SDimitry Andric     uint32_t Align = getStreamedLen() % 4;
450b57cec5SDimitry Andric     if (Align == 0)
460b57cec5SDimitry Andric       return Error::success();
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric     int PaddingBytes = 4 - Align;
490b57cec5SDimitry Andric     while (PaddingBytes > 0) {
500b57cec5SDimitry Andric       char Pad = static_cast<uint8_t>(LF_PAD0 + PaddingBytes);
510b57cec5SDimitry Andric       StringRef BytesSR = StringRef(&Pad, sizeof(Pad));
525ffd83dbSDimitry Andric       Streamer->emitBytes(BytesSR);
530b57cec5SDimitry Andric       --PaddingBytes;
540b57cec5SDimitry Andric     }
558bcb0991SDimitry Andric     resetStreamedLen();
560b57cec5SDimitry Andric   }
570b57cec5SDimitry Andric   return Error::success();
580b57cec5SDimitry Andric }
590b57cec5SDimitry Andric 
maxFieldLength() const600b57cec5SDimitry Andric uint32_t CodeViewRecordIO::maxFieldLength() const {
610b57cec5SDimitry Andric   if (isStreaming())
620b57cec5SDimitry Andric     return 0;
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric   assert(!Limits.empty() && "Not in a record!");
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric   // The max length of the next field is the minimum of all lengths that would
670b57cec5SDimitry Andric   // be allowed by any of the sub-records we're in.  In practice, we can only
680b57cec5SDimitry Andric   // ever be at most 1 sub-record deep (in a FieldList), but this works for
690b57cec5SDimitry Andric   // the general case.
700b57cec5SDimitry Andric   uint32_t Offset = getCurrentOffset();
71bdd1243dSDimitry Andric   std::optional<uint32_t> Min = Limits.front().bytesRemaining(Offset);
72bdd1243dSDimitry Andric   for (auto X : ArrayRef(Limits).drop_front()) {
73bdd1243dSDimitry Andric     std::optional<uint32_t> ThisMin = X.bytesRemaining(Offset);
7481ad6265SDimitry Andric     if (ThisMin)
7581ad6265SDimitry Andric       Min = Min ? std::min(*Min, *ThisMin) : *ThisMin;
760b57cec5SDimitry Andric   }
7781ad6265SDimitry Andric   assert(Min && "Every field must have a maximum length!");
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric   return *Min;
800b57cec5SDimitry Andric }
810b57cec5SDimitry Andric 
padToAlignment(uint32_t Align)820b57cec5SDimitry Andric Error CodeViewRecordIO::padToAlignment(uint32_t Align) {
830b57cec5SDimitry Andric   if (isReading())
840b57cec5SDimitry Andric     return Reader->padToAlignment(Align);
850b57cec5SDimitry Andric   return Writer->padToAlignment(Align);
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric 
skipPadding()880b57cec5SDimitry Andric Error CodeViewRecordIO::skipPadding() {
890b57cec5SDimitry Andric   assert(!isWriting() && "Cannot skip padding while writing!");
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric   if (Reader->bytesRemaining() == 0)
920b57cec5SDimitry Andric     return Error::success();
930b57cec5SDimitry Andric 
940b57cec5SDimitry Andric   uint8_t Leaf = Reader->peek();
950b57cec5SDimitry Andric   if (Leaf < LF_PAD0)
960b57cec5SDimitry Andric     return Error::success();
970b57cec5SDimitry Andric   // Leaf is greater than 0xf0. We should advance by the number of bytes in
980b57cec5SDimitry Andric   // the low 4 bits.
990b57cec5SDimitry Andric   unsigned BytesToAdvance = Leaf & 0x0F;
1000b57cec5SDimitry Andric   return Reader->skip(BytesToAdvance);
1010b57cec5SDimitry Andric }
1020b57cec5SDimitry Andric 
mapByteVectorTail(ArrayRef<uint8_t> & Bytes,const Twine & Comment)1030b57cec5SDimitry Andric Error CodeViewRecordIO::mapByteVectorTail(ArrayRef<uint8_t> &Bytes,
1040b57cec5SDimitry Andric                                           const Twine &Comment) {
1050b57cec5SDimitry Andric   if (isStreaming()) {
1060b57cec5SDimitry Andric     emitComment(Comment);
1075ffd83dbSDimitry Andric     Streamer->emitBinaryData(toStringRef(Bytes));
1080b57cec5SDimitry Andric     incrStreamedLen(Bytes.size());
1090b57cec5SDimitry Andric   } else if (isWriting()) {
1100b57cec5SDimitry Andric     if (auto EC = Writer->writeBytes(Bytes))
1110b57cec5SDimitry Andric       return EC;
1120b57cec5SDimitry Andric   } else {
1130b57cec5SDimitry Andric     if (auto EC = Reader->readBytes(Bytes, Reader->bytesRemaining()))
1140b57cec5SDimitry Andric       return EC;
1150b57cec5SDimitry Andric   }
1160b57cec5SDimitry Andric   return Error::success();
1170b57cec5SDimitry Andric }
1180b57cec5SDimitry Andric 
mapByteVectorTail(std::vector<uint8_t> & Bytes,const Twine & Comment)1190b57cec5SDimitry Andric Error CodeViewRecordIO::mapByteVectorTail(std::vector<uint8_t> &Bytes,
1200b57cec5SDimitry Andric                                           const Twine &Comment) {
1210b57cec5SDimitry Andric   ArrayRef<uint8_t> BytesRef(Bytes);
1220b57cec5SDimitry Andric   if (auto EC = mapByteVectorTail(BytesRef, Comment))
1230b57cec5SDimitry Andric     return EC;
1240b57cec5SDimitry Andric   if (!isWriting())
1250b57cec5SDimitry Andric     Bytes.assign(BytesRef.begin(), BytesRef.end());
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric   return Error::success();
1280b57cec5SDimitry Andric }
1290b57cec5SDimitry Andric 
mapInteger(TypeIndex & TypeInd,const Twine & Comment)1300b57cec5SDimitry Andric Error CodeViewRecordIO::mapInteger(TypeIndex &TypeInd, const Twine &Comment) {
1310b57cec5SDimitry Andric   if (isStreaming()) {
1328bcb0991SDimitry Andric     std::string TypeNameStr = Streamer->getTypeName(TypeInd);
1338bcb0991SDimitry Andric     if (!TypeNameStr.empty())
1348bcb0991SDimitry Andric       emitComment(Comment + ": " + TypeNameStr);
1358bcb0991SDimitry Andric     else
1360b57cec5SDimitry Andric       emitComment(Comment);
1375ffd83dbSDimitry Andric     Streamer->emitIntValue(TypeInd.getIndex(), sizeof(TypeInd.getIndex()));
1380b57cec5SDimitry Andric     incrStreamedLen(sizeof(TypeInd.getIndex()));
1390b57cec5SDimitry Andric   } else if (isWriting()) {
1400b57cec5SDimitry Andric     if (auto EC = Writer->writeInteger(TypeInd.getIndex()))
1410b57cec5SDimitry Andric       return EC;
1420b57cec5SDimitry Andric   } else {
1430b57cec5SDimitry Andric     uint32_t I;
1440b57cec5SDimitry Andric     if (auto EC = Reader->readInteger(I))
1450b57cec5SDimitry Andric       return EC;
1460b57cec5SDimitry Andric     TypeInd.setIndex(I);
1470b57cec5SDimitry Andric   }
1480b57cec5SDimitry Andric   return Error::success();
1490b57cec5SDimitry Andric }
1500b57cec5SDimitry Andric 
mapEncodedInteger(int64_t & Value,const Twine & Comment)1510b57cec5SDimitry Andric Error CodeViewRecordIO::mapEncodedInteger(int64_t &Value,
1520b57cec5SDimitry Andric                                           const Twine &Comment) {
1530b57cec5SDimitry Andric   if (isStreaming()) {
1540b57cec5SDimitry Andric     if (Value >= 0)
1550b57cec5SDimitry Andric       emitEncodedUnsignedInteger(static_cast<uint64_t>(Value), Comment);
1560b57cec5SDimitry Andric     else
1570b57cec5SDimitry Andric       emitEncodedSignedInteger(Value, Comment);
1580b57cec5SDimitry Andric   } else if (isWriting()) {
1590b57cec5SDimitry Andric     if (Value >= 0) {
1600b57cec5SDimitry Andric       if (auto EC = writeEncodedUnsignedInteger(static_cast<uint64_t>(Value)))
1610b57cec5SDimitry Andric         return EC;
1620b57cec5SDimitry Andric     } else {
1630b57cec5SDimitry Andric       if (auto EC = writeEncodedSignedInteger(Value))
1640b57cec5SDimitry Andric         return EC;
1650b57cec5SDimitry Andric     }
1660b57cec5SDimitry Andric   } else {
1670b57cec5SDimitry Andric     APSInt N;
1680b57cec5SDimitry Andric     if (auto EC = consume(*Reader, N))
1690b57cec5SDimitry Andric       return EC;
1700b57cec5SDimitry Andric     Value = N.getExtValue();
1710b57cec5SDimitry Andric   }
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric   return Error::success();
1740b57cec5SDimitry Andric }
1750b57cec5SDimitry Andric 
mapEncodedInteger(uint64_t & Value,const Twine & Comment)1760b57cec5SDimitry Andric Error CodeViewRecordIO::mapEncodedInteger(uint64_t &Value,
1770b57cec5SDimitry Andric                                           const Twine &Comment) {
1780b57cec5SDimitry Andric   if (isStreaming())
1790b57cec5SDimitry Andric     emitEncodedUnsignedInteger(Value, Comment);
1800b57cec5SDimitry Andric   else if (isWriting()) {
1810b57cec5SDimitry Andric     if (auto EC = writeEncodedUnsignedInteger(Value))
1820b57cec5SDimitry Andric       return EC;
1830b57cec5SDimitry Andric   } else {
1840b57cec5SDimitry Andric     APSInt N;
1850b57cec5SDimitry Andric     if (auto EC = consume(*Reader, N))
1860b57cec5SDimitry Andric       return EC;
1870b57cec5SDimitry Andric     Value = N.getZExtValue();
1880b57cec5SDimitry Andric   }
1890b57cec5SDimitry Andric   return Error::success();
1900b57cec5SDimitry Andric }
1910b57cec5SDimitry Andric 
mapEncodedInteger(APSInt & Value,const Twine & Comment)1920b57cec5SDimitry Andric Error CodeViewRecordIO::mapEncodedInteger(APSInt &Value, const Twine &Comment) {
1930b57cec5SDimitry Andric   if (isStreaming()) {
194fe6060f1SDimitry Andric     // FIXME: We also need to handle big values here, but it's
195fe6060f1SDimitry Andric     //        not clear how we can excercise this code path yet.
1960b57cec5SDimitry Andric     if (Value.isSigned())
1970b57cec5SDimitry Andric       emitEncodedSignedInteger(Value.getSExtValue(), Comment);
1980b57cec5SDimitry Andric     else
1990b57cec5SDimitry Andric       emitEncodedUnsignedInteger(Value.getZExtValue(), Comment);
2000b57cec5SDimitry Andric   } else if (isWriting()) {
2010b57cec5SDimitry Andric     if (Value.isSigned())
202fe6060f1SDimitry Andric       return writeEncodedSignedInteger(
203fe6060f1SDimitry Andric           Value.isSingleWord() ? Value.getSExtValue() : INT64_MIN);
204fe6060f1SDimitry Andric     return writeEncodedUnsignedInteger(Value.getLimitedValue());
2050b57cec5SDimitry Andric   } else
2060b57cec5SDimitry Andric     return consume(*Reader, Value);
2070b57cec5SDimitry Andric   return Error::success();
2080b57cec5SDimitry Andric }
2090b57cec5SDimitry Andric 
mapStringZ(StringRef & Value,const Twine & Comment)2100b57cec5SDimitry Andric Error CodeViewRecordIO::mapStringZ(StringRef &Value, const Twine &Comment) {
2110b57cec5SDimitry Andric   if (isStreaming()) {
2120b57cec5SDimitry Andric     auto NullTerminatedString = StringRef(Value.data(), Value.size() + 1);
2130b57cec5SDimitry Andric     emitComment(Comment);
2145ffd83dbSDimitry Andric     Streamer->emitBytes(NullTerminatedString);
2150b57cec5SDimitry Andric     incrStreamedLen(NullTerminatedString.size());
2160b57cec5SDimitry Andric   } else if (isWriting()) {
2170b57cec5SDimitry Andric     // Truncate if we attempt to write too much.
2180b57cec5SDimitry Andric     StringRef S = Value.take_front(maxFieldLength() - 1);
2190b57cec5SDimitry Andric     if (auto EC = Writer->writeCString(S))
2200b57cec5SDimitry Andric       return EC;
2210b57cec5SDimitry Andric   } else {
2220b57cec5SDimitry Andric     if (auto EC = Reader->readCString(Value))
2230b57cec5SDimitry Andric       return EC;
2240b57cec5SDimitry Andric   }
2250b57cec5SDimitry Andric   return Error::success();
2260b57cec5SDimitry Andric }
2270b57cec5SDimitry Andric 
mapGuid(GUID & Guid,const Twine & Comment)2280b57cec5SDimitry Andric Error CodeViewRecordIO::mapGuid(GUID &Guid, const Twine &Comment) {
2290b57cec5SDimitry Andric   constexpr uint32_t GuidSize = 16;
2300b57cec5SDimitry Andric 
2310b57cec5SDimitry Andric   if (isStreaming()) {
2320b57cec5SDimitry Andric     StringRef GuidSR =
2330b57cec5SDimitry Andric         StringRef((reinterpret_cast<const char *>(&Guid)), GuidSize);
2340b57cec5SDimitry Andric     emitComment(Comment);
2355ffd83dbSDimitry Andric     Streamer->emitBytes(GuidSR);
2360b57cec5SDimitry Andric     incrStreamedLen(GuidSize);
2370b57cec5SDimitry Andric     return Error::success();
2380b57cec5SDimitry Andric   }
2390b57cec5SDimitry Andric 
2400b57cec5SDimitry Andric   if (maxFieldLength() < GuidSize)
2410b57cec5SDimitry Andric     return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
2420b57cec5SDimitry Andric 
2430b57cec5SDimitry Andric   if (isWriting()) {
2440b57cec5SDimitry Andric     if (auto EC = Writer->writeBytes(Guid.Guid))
2450b57cec5SDimitry Andric       return EC;
2460b57cec5SDimitry Andric   } else {
2470b57cec5SDimitry Andric     ArrayRef<uint8_t> GuidBytes;
2480b57cec5SDimitry Andric     if (auto EC = Reader->readBytes(GuidBytes, GuidSize))
2490b57cec5SDimitry Andric       return EC;
2500b57cec5SDimitry Andric     memcpy(Guid.Guid, GuidBytes.data(), GuidSize);
2510b57cec5SDimitry Andric   }
2520b57cec5SDimitry Andric   return Error::success();
2530b57cec5SDimitry Andric }
2540b57cec5SDimitry Andric 
mapStringZVectorZ(std::vector<StringRef> & Value,const Twine & Comment)2550b57cec5SDimitry Andric Error CodeViewRecordIO::mapStringZVectorZ(std::vector<StringRef> &Value,
2560b57cec5SDimitry Andric                                           const Twine &Comment) {
2570b57cec5SDimitry Andric 
2580b57cec5SDimitry Andric   if (!isReading()) {
2590b57cec5SDimitry Andric     emitComment(Comment);
2600b57cec5SDimitry Andric     for (auto V : Value) {
2610b57cec5SDimitry Andric       if (auto EC = mapStringZ(V))
2620b57cec5SDimitry Andric         return EC;
2630b57cec5SDimitry Andric     }
2640b57cec5SDimitry Andric     uint8_t FinalZero = 0;
2650b57cec5SDimitry Andric     if (auto EC = mapInteger(FinalZero))
2660b57cec5SDimitry Andric       return EC;
2670b57cec5SDimitry Andric   } else {
2680b57cec5SDimitry Andric     StringRef S;
2690b57cec5SDimitry Andric     if (auto EC = mapStringZ(S))
2700b57cec5SDimitry Andric       return EC;
2710b57cec5SDimitry Andric     while (!S.empty()) {
2720b57cec5SDimitry Andric       Value.push_back(S);
2730b57cec5SDimitry Andric       if (auto EC = mapStringZ(S))
2740b57cec5SDimitry Andric         return EC;
2750b57cec5SDimitry Andric     };
2760b57cec5SDimitry Andric   }
2770b57cec5SDimitry Andric   return Error::success();
2780b57cec5SDimitry Andric }
2790b57cec5SDimitry Andric 
emitEncodedSignedInteger(const int64_t & Value,const Twine & Comment)2800b57cec5SDimitry Andric void CodeViewRecordIO::emitEncodedSignedInteger(const int64_t &Value,
2810b57cec5SDimitry Andric                                                 const Twine &Comment) {
282fe6060f1SDimitry Andric   // FIXME: There are no test cases covering this function.
283fe6060f1SDimitry Andric   // This may be because we always consider enumerators to be unsigned.
284fe6060f1SDimitry Andric   // See FIXME at CodeViewDebug.cpp : CodeViewDebug::lowerTypeEnum.
28581ad6265SDimitry Andric   if (Value < LF_NUMERIC && Value >= 0) {
28681ad6265SDimitry Andric     emitComment(Comment);
28781ad6265SDimitry Andric     Streamer->emitIntValue(Value, 2);
28881ad6265SDimitry Andric     incrStreamedLen(2);
28981ad6265SDimitry Andric   } else if (Value >= std::numeric_limits<int8_t>::min() &&
29081ad6265SDimitry Andric              Value <= std::numeric_limits<int8_t>::max()) {
2915ffd83dbSDimitry Andric     Streamer->emitIntValue(LF_CHAR, 2);
2920b57cec5SDimitry Andric     emitComment(Comment);
2935ffd83dbSDimitry Andric     Streamer->emitIntValue(Value, 1);
2940b57cec5SDimitry Andric     incrStreamedLen(3);
29581ad6265SDimitry Andric   } else if (Value >= std::numeric_limits<int16_t>::min() &&
29681ad6265SDimitry Andric              Value <= std::numeric_limits<int16_t>::max()) {
2975ffd83dbSDimitry Andric     Streamer->emitIntValue(LF_SHORT, 2);
2980b57cec5SDimitry Andric     emitComment(Comment);
2995ffd83dbSDimitry Andric     Streamer->emitIntValue(Value, 2);
3000b57cec5SDimitry Andric     incrStreamedLen(4);
30181ad6265SDimitry Andric   } else if (Value >= std::numeric_limits<int32_t>::min() &&
30281ad6265SDimitry Andric              Value <= std::numeric_limits<int32_t>::max()) {
3035ffd83dbSDimitry Andric     Streamer->emitIntValue(LF_LONG, 2);
3040b57cec5SDimitry Andric     emitComment(Comment);
3055ffd83dbSDimitry Andric     Streamer->emitIntValue(Value, 4);
3060b57cec5SDimitry Andric     incrStreamedLen(6);
3070b57cec5SDimitry Andric   } else {
3085ffd83dbSDimitry Andric     Streamer->emitIntValue(LF_QUADWORD, 2);
3090b57cec5SDimitry Andric     emitComment(Comment);
310fe6060f1SDimitry Andric     Streamer->emitIntValue(Value, 4); // FIXME: Why not 8 (size of quadword)?
311fe6060f1SDimitry Andric     incrStreamedLen(6);               // FIXME: Why not 10 (8 + 2)?
3120b57cec5SDimitry Andric   }
3130b57cec5SDimitry Andric }
3140b57cec5SDimitry Andric 
emitEncodedUnsignedInteger(const uint64_t & Value,const Twine & Comment)3150b57cec5SDimitry Andric void CodeViewRecordIO::emitEncodedUnsignedInteger(const uint64_t &Value,
3160b57cec5SDimitry Andric                                                   const Twine &Comment) {
3170b57cec5SDimitry Andric   if (Value < LF_NUMERIC) {
3180b57cec5SDimitry Andric     emitComment(Comment);
3195ffd83dbSDimitry Andric     Streamer->emitIntValue(Value, 2);
3200b57cec5SDimitry Andric     incrStreamedLen(2);
3210b57cec5SDimitry Andric   } else if (Value <= std::numeric_limits<uint16_t>::max()) {
3225ffd83dbSDimitry Andric     Streamer->emitIntValue(LF_USHORT, 2);
3230b57cec5SDimitry Andric     emitComment(Comment);
3245ffd83dbSDimitry Andric     Streamer->emitIntValue(Value, 2);
3250b57cec5SDimitry Andric     incrStreamedLen(4);
3260b57cec5SDimitry Andric   } else if (Value <= std::numeric_limits<uint32_t>::max()) {
3275ffd83dbSDimitry Andric     Streamer->emitIntValue(LF_ULONG, 2);
3280b57cec5SDimitry Andric     emitComment(Comment);
3295ffd83dbSDimitry Andric     Streamer->emitIntValue(Value, 4);
3300b57cec5SDimitry Andric     incrStreamedLen(6);
3310b57cec5SDimitry Andric   } else {
332fe6060f1SDimitry Andric     // FIXME: There are no test cases covering this block.
3335ffd83dbSDimitry Andric     Streamer->emitIntValue(LF_UQUADWORD, 2);
3340b57cec5SDimitry Andric     emitComment(Comment);
3355ffd83dbSDimitry Andric     Streamer->emitIntValue(Value, 8);
336fe6060f1SDimitry Andric     incrStreamedLen(6); // FIXME: Why not 10 (8 + 2)?
3370b57cec5SDimitry Andric   }
3380b57cec5SDimitry Andric }
3390b57cec5SDimitry Andric 
writeEncodedSignedInteger(const int64_t & Value)3400b57cec5SDimitry Andric Error CodeViewRecordIO::writeEncodedSignedInteger(const int64_t &Value) {
34181ad6265SDimitry Andric   if (Value < LF_NUMERIC && Value >= 0) {
34281ad6265SDimitry Andric     if (auto EC = Writer->writeInteger<int16_t>(Value))
34381ad6265SDimitry Andric       return EC;
34481ad6265SDimitry Andric   } else if (Value >= std::numeric_limits<int8_t>::min() &&
34581ad6265SDimitry Andric              Value <= std::numeric_limits<int8_t>::max()) {
3460b57cec5SDimitry Andric     if (auto EC = Writer->writeInteger<uint16_t>(LF_CHAR))
3470b57cec5SDimitry Andric       return EC;
3480b57cec5SDimitry Andric     if (auto EC = Writer->writeInteger<int8_t>(Value))
3490b57cec5SDimitry Andric       return EC;
35081ad6265SDimitry Andric   } else if (Value >= std::numeric_limits<int16_t>::min() &&
35181ad6265SDimitry Andric              Value <= std::numeric_limits<int16_t>::max()) {
3520b57cec5SDimitry Andric     if (auto EC = Writer->writeInteger<uint16_t>(LF_SHORT))
3530b57cec5SDimitry Andric       return EC;
3540b57cec5SDimitry Andric     if (auto EC = Writer->writeInteger<int16_t>(Value))
3550b57cec5SDimitry Andric       return EC;
35681ad6265SDimitry Andric   } else if (Value >= std::numeric_limits<int32_t>::min() &&
35781ad6265SDimitry Andric              Value <= std::numeric_limits<int32_t>::max()) {
3580b57cec5SDimitry Andric     if (auto EC = Writer->writeInteger<uint16_t>(LF_LONG))
3590b57cec5SDimitry Andric       return EC;
3600b57cec5SDimitry Andric     if (auto EC = Writer->writeInteger<int32_t>(Value))
3610b57cec5SDimitry Andric       return EC;
3620b57cec5SDimitry Andric   } else {
3630b57cec5SDimitry Andric     if (auto EC = Writer->writeInteger<uint16_t>(LF_QUADWORD))
3640b57cec5SDimitry Andric       return EC;
3650b57cec5SDimitry Andric     if (auto EC = Writer->writeInteger(Value))
3660b57cec5SDimitry Andric       return EC;
3670b57cec5SDimitry Andric   }
3680b57cec5SDimitry Andric   return Error::success();
3690b57cec5SDimitry Andric }
3700b57cec5SDimitry Andric 
writeEncodedUnsignedInteger(const uint64_t & Value)3710b57cec5SDimitry Andric Error CodeViewRecordIO::writeEncodedUnsignedInteger(const uint64_t &Value) {
3720b57cec5SDimitry Andric   if (Value < LF_NUMERIC) {
3730b57cec5SDimitry Andric     if (auto EC = Writer->writeInteger<uint16_t>(Value))
3740b57cec5SDimitry Andric       return EC;
3750b57cec5SDimitry Andric   } else if (Value <= std::numeric_limits<uint16_t>::max()) {
3760b57cec5SDimitry Andric     if (auto EC = Writer->writeInteger<uint16_t>(LF_USHORT))
3770b57cec5SDimitry Andric       return EC;
3780b57cec5SDimitry Andric     if (auto EC = Writer->writeInteger<uint16_t>(Value))
3790b57cec5SDimitry Andric       return EC;
3800b57cec5SDimitry Andric   } else if (Value <= std::numeric_limits<uint32_t>::max()) {
3810b57cec5SDimitry Andric     if (auto EC = Writer->writeInteger<uint16_t>(LF_ULONG))
3820b57cec5SDimitry Andric       return EC;
3830b57cec5SDimitry Andric     if (auto EC = Writer->writeInteger<uint32_t>(Value))
3840b57cec5SDimitry Andric       return EC;
3850b57cec5SDimitry Andric   } else {
3860b57cec5SDimitry Andric     if (auto EC = Writer->writeInteger<uint16_t>(LF_UQUADWORD))
3870b57cec5SDimitry Andric       return EC;
3880b57cec5SDimitry Andric     if (auto EC = Writer->writeInteger(Value))
3890b57cec5SDimitry Andric       return EC;
3900b57cec5SDimitry Andric   }
3910b57cec5SDimitry Andric 
3920b57cec5SDimitry Andric   return Error::success();
3930b57cec5SDimitry Andric }
394