17251ede7SZachary Turner //===- CodeViewRecordIO.cpp -------------------------------------*- C++ -*-===// 27251ede7SZachary Turner // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 67251ede7SZachary Turner // 77251ede7SZachary Turner //===----------------------------------------------------------------------===// 87251ede7SZachary Turner 97251ede7SZachary Turner #include "llvm/DebugInfo/CodeView/CodeViewRecordIO.h" 107251ede7SZachary Turner #include "llvm/DebugInfo/CodeView/CodeView.h" 117251ede7SZachary Turner #include "llvm/DebugInfo/CodeView/RecordSerialization.h" 12d9dc2829SZachary Turner #include "llvm/Support/BinaryStreamReader.h" 13d9dc2829SZachary Turner #include "llvm/Support/BinaryStreamWriter.h" 147251ede7SZachary Turner 157251ede7SZachary Turner using namespace llvm; 167251ede7SZachary Turner using namespace llvm::codeview; 177251ede7SZachary Turner 184efa0a42SZachary Turner Error CodeViewRecordIO::beginRecord(Optional<uint32_t> MaxLength) { 194efa0a42SZachary Turner RecordLimit Limit; 204efa0a42SZachary Turner Limit.MaxLength = MaxLength; 214efa0a42SZachary Turner Limit.BeginOffset = getCurrentOffset(); 224efa0a42SZachary Turner Limits.push_back(Limit); 237251ede7SZachary Turner return Error::success(); 247251ede7SZachary Turner } 257251ede7SZachary Turner 267251ede7SZachary Turner Error CodeViewRecordIO::endRecord() { 274efa0a42SZachary Turner assert(!Limits.empty() && "Not in a record!"); 284efa0a42SZachary Turner Limits.pop_back(); 29ebd3ae83SZachary Turner // We would like to assert that we actually read / wrote all the bytes that we 30ebd3ae83SZachary Turner // expected to for this record, but unfortunately we can't do this. Some 31ebd3ae83SZachary Turner // producers such as MASM over-allocate for certain types of records and 32ebd3ae83SZachary Turner // commit the extraneous data, so when reading we can't be sure every byte 33ebd3ae83SZachary Turner // will have been read. And when writing we over-allocate temporarily since 34ebd3ae83SZachary Turner // we don't know how big the record is until we're finished writing it, so 35ebd3ae83SZachary Turner // even though we don't commit the extraneous data, we still can't guarantee 36ebd3ae83SZachary Turner // we're at the end of the allocated data. 37faed8516SNilanjana Basu 38faed8516SNilanjana Basu if (isStreaming()) { 39faed8516SNilanjana Basu // For streaming mode, add padding to align with 4 byte boundaries for each 40faed8516SNilanjana Basu // record 41faed8516SNilanjana Basu uint32_t Align = getStreamedLen() % 4; 42faed8516SNilanjana Basu if (Align == 0) 43faed8516SNilanjana Basu return Error::success(); 44faed8516SNilanjana Basu 45faed8516SNilanjana Basu int PaddingBytes = 4 - Align; 46faed8516SNilanjana Basu while (PaddingBytes > 0) { 47faed8516SNilanjana Basu char Pad = static_cast<uint8_t>(LF_PAD0 + PaddingBytes); 48faed8516SNilanjana Basu StringRef BytesSR = StringRef(&Pad, sizeof(Pad)); 49faed8516SNilanjana Basu Streamer->EmitBytes(BytesSR); 50faed8516SNilanjana Basu --PaddingBytes; 51faed8516SNilanjana Basu } 52*06b8fe8dSNilanjana Basu resetStreamedLen(); 53faed8516SNilanjana Basu } 547251ede7SZachary Turner return Error::success(); 557251ede7SZachary Turner } 567251ede7SZachary Turner 574efa0a42SZachary Turner uint32_t CodeViewRecordIO::maxFieldLength() const { 58faed8516SNilanjana Basu if (isStreaming()) 59faed8516SNilanjana Basu return 0; 60faed8516SNilanjana Basu 614efa0a42SZachary Turner assert(!Limits.empty() && "Not in a record!"); 624efa0a42SZachary Turner 634efa0a42SZachary Turner // The max length of the next field is the minimum of all lengths that would 644efa0a42SZachary Turner // be allowed by any of the sub-records we're in. In practice, we can only 654efa0a42SZachary Turner // ever be at most 1 sub-record deep (in a FieldList), but this works for 664efa0a42SZachary Turner // the general case. 674efa0a42SZachary Turner uint32_t Offset = getCurrentOffset(); 684efa0a42SZachary Turner Optional<uint32_t> Min = Limits.front().bytesRemaining(Offset); 694efa0a42SZachary Turner for (auto X : makeArrayRef(Limits).drop_front()) { 704efa0a42SZachary Turner Optional<uint32_t> ThisMin = X.bytesRemaining(Offset); 714efa0a42SZachary Turner if (ThisMin.hasValue()) 724efa0a42SZachary Turner Min = (Min.hasValue()) ? std::min(*Min, *ThisMin) : *ThisMin; 734efa0a42SZachary Turner } 744efa0a42SZachary Turner assert(Min.hasValue() && "Every field must have a maximum length!"); 754efa0a42SZachary Turner 764efa0a42SZachary Turner return *Min; 774efa0a42SZachary Turner } 784efa0a42SZachary Turner 79ebd3ae83SZachary Turner Error CodeViewRecordIO::padToAlignment(uint32_t Align) { 80ebd3ae83SZachary Turner if (isReading()) 81ebd3ae83SZachary Turner return Reader->padToAlignment(Align); 82ebd3ae83SZachary Turner return Writer->padToAlignment(Align); 83ebd3ae83SZachary Turner } 84ebd3ae83SZachary Turner 857251ede7SZachary Turner Error CodeViewRecordIO::skipPadding() { 867251ede7SZachary Turner assert(!isWriting() && "Cannot skip padding while writing!"); 877251ede7SZachary Turner 887251ede7SZachary Turner if (Reader->bytesRemaining() == 0) 897251ede7SZachary Turner return Error::success(); 907251ede7SZachary Turner 917251ede7SZachary Turner uint8_t Leaf = Reader->peek(); 927251ede7SZachary Turner if (Leaf < LF_PAD0) 937251ede7SZachary Turner return Error::success(); 947251ede7SZachary Turner // Leaf is greater than 0xf0. We should advance by the number of bytes in 957251ede7SZachary Turner // the low 4 bits. 967251ede7SZachary Turner unsigned BytesToAdvance = Leaf & 0x0F; 977251ede7SZachary Turner return Reader->skip(BytesToAdvance); 987251ede7SZachary Turner } 997251ede7SZachary Turner 1006e407669SNilanjana Basu Error CodeViewRecordIO::mapByteVectorTail(ArrayRef<uint8_t> &Bytes, 1016e407669SNilanjana Basu const Twine &Comment) { 102faed8516SNilanjana Basu if (isStreaming()) { 1036e407669SNilanjana Basu emitComment(Comment); 104faed8516SNilanjana Basu Streamer->EmitBinaryData(toStringRef(Bytes)); 105faed8516SNilanjana Basu incrStreamedLen(Bytes.size()); 106faed8516SNilanjana Basu } else if (isWriting()) { 1077251ede7SZachary Turner if (auto EC = Writer->writeBytes(Bytes)) 1087251ede7SZachary Turner return EC; 1097251ede7SZachary Turner } else { 1107251ede7SZachary Turner if (auto EC = Reader->readBytes(Bytes, Reader->bytesRemaining())) 1117251ede7SZachary Turner return EC; 1127251ede7SZachary Turner } 1137251ede7SZachary Turner return Error::success(); 1147251ede7SZachary Turner } 1157251ede7SZachary Turner 1166e407669SNilanjana Basu Error CodeViewRecordIO::mapByteVectorTail(std::vector<uint8_t> &Bytes, 1176e407669SNilanjana Basu const Twine &Comment) { 11846225b19SZachary Turner ArrayRef<uint8_t> BytesRef(Bytes); 1196e407669SNilanjana Basu if (auto EC = mapByteVectorTail(BytesRef, Comment)) 12046225b19SZachary Turner return EC; 12146225b19SZachary Turner if (!isWriting()) 12246225b19SZachary Turner Bytes.assign(BytesRef.begin(), BytesRef.end()); 12346225b19SZachary Turner 12446225b19SZachary Turner return Error::success(); 12546225b19SZachary Turner } 12646225b19SZachary Turner 1276e407669SNilanjana Basu Error CodeViewRecordIO::mapInteger(TypeIndex &TypeInd, const Twine &Comment) { 128faed8516SNilanjana Basu if (isStreaming()) { 1296e407669SNilanjana Basu emitComment(Comment); 130faed8516SNilanjana Basu Streamer->EmitIntValue(TypeInd.getIndex(), sizeof(TypeInd.getIndex())); 131faed8516SNilanjana Basu incrStreamedLen(sizeof(TypeInd.getIndex())); 132faed8516SNilanjana Basu } else if (isWriting()) { 133695ed56bSZachary Turner if (auto EC = Writer->writeInteger(TypeInd.getIndex())) 1347251ede7SZachary Turner return EC; 135faed8516SNilanjana Basu } else { 1367251ede7SZachary Turner uint32_t I; 137695ed56bSZachary Turner if (auto EC = Reader->readInteger(I)) 1387251ede7SZachary Turner return EC; 1397251ede7SZachary Turner TypeInd.setIndex(I); 140faed8516SNilanjana Basu } 1417251ede7SZachary Turner return Error::success(); 1427251ede7SZachary Turner } 1437251ede7SZachary Turner 1446e407669SNilanjana Basu Error CodeViewRecordIO::mapEncodedInteger(int64_t &Value, 1456e407669SNilanjana Basu const Twine &Comment) { 146faed8516SNilanjana Basu if (isStreaming()) { 147faed8516SNilanjana Basu if (Value >= 0) 1486e407669SNilanjana Basu emitEncodedUnsignedInteger(static_cast<uint64_t>(Value), Comment); 149faed8516SNilanjana Basu else 1506e407669SNilanjana Basu emitEncodedSignedInteger(Value, Comment); 151faed8516SNilanjana Basu } else if (isWriting()) { 1527251ede7SZachary Turner if (Value >= 0) { 1537251ede7SZachary Turner if (auto EC = writeEncodedUnsignedInteger(static_cast<uint64_t>(Value))) 1547251ede7SZachary Turner return EC; 1557251ede7SZachary Turner } else { 1567251ede7SZachary Turner if (auto EC = writeEncodedSignedInteger(Value)) 1577251ede7SZachary Turner return EC; 1587251ede7SZachary Turner } 1597251ede7SZachary Turner } else { 1607251ede7SZachary Turner APSInt N; 1617251ede7SZachary Turner if (auto EC = consume(*Reader, N)) 1627251ede7SZachary Turner return EC; 1637251ede7SZachary Turner Value = N.getExtValue(); 1647251ede7SZachary Turner } 1657251ede7SZachary Turner 1667251ede7SZachary Turner return Error::success(); 1677251ede7SZachary Turner } 1687251ede7SZachary Turner 1696e407669SNilanjana Basu Error CodeViewRecordIO::mapEncodedInteger(uint64_t &Value, 1706e407669SNilanjana Basu const Twine &Comment) { 171faed8516SNilanjana Basu if (isStreaming()) 1726e407669SNilanjana Basu emitEncodedUnsignedInteger(Value, Comment); 173faed8516SNilanjana Basu else if (isWriting()) { 1747251ede7SZachary Turner if (auto EC = writeEncodedUnsignedInteger(Value)) 1757251ede7SZachary Turner return EC; 1767251ede7SZachary Turner } else { 1777251ede7SZachary Turner APSInt N; 1787251ede7SZachary Turner if (auto EC = consume(*Reader, N)) 1797251ede7SZachary Turner return EC; 1807251ede7SZachary Turner Value = N.getZExtValue(); 1817251ede7SZachary Turner } 1827251ede7SZachary Turner return Error::success(); 1837251ede7SZachary Turner } 1847251ede7SZachary Turner 1856e407669SNilanjana Basu Error CodeViewRecordIO::mapEncodedInteger(APSInt &Value, const Twine &Comment) { 186faed8516SNilanjana Basu if (isStreaming()) { 187faed8516SNilanjana Basu if (Value.isSigned()) 1886e407669SNilanjana Basu emitEncodedSignedInteger(Value.getSExtValue(), Comment); 189faed8516SNilanjana Basu else 1906e407669SNilanjana Basu emitEncodedUnsignedInteger(Value.getZExtValue(), Comment); 191faed8516SNilanjana Basu } else if (isWriting()) { 1927251ede7SZachary Turner if (Value.isSigned()) 1937251ede7SZachary Turner return writeEncodedSignedInteger(Value.getSExtValue()); 1947251ede7SZachary Turner return writeEncodedUnsignedInteger(Value.getZExtValue()); 195faed8516SNilanjana Basu } else 1967251ede7SZachary Turner return consume(*Reader, Value); 197faed8516SNilanjana Basu return Error::success(); 1987251ede7SZachary Turner } 1997251ede7SZachary Turner 2006e407669SNilanjana Basu Error CodeViewRecordIO::mapStringZ(StringRef &Value, const Twine &Comment) { 201faed8516SNilanjana Basu if (isStreaming()) { 202faed8516SNilanjana Basu auto NullTerminatedString = StringRef(Value.data(), Value.size() + 1); 2036e407669SNilanjana Basu emitComment(Comment); 204faed8516SNilanjana Basu Streamer->EmitBytes(NullTerminatedString); 205faed8516SNilanjana Basu incrStreamedLen(NullTerminatedString.size()); 206faed8516SNilanjana Basu } else if (isWriting()) { 2074efa0a42SZachary Turner // Truncate if we attempt to write too much. 2084efa0a42SZachary Turner StringRef S = Value.take_front(maxFieldLength() - 1); 209120faca4SZachary Turner if (auto EC = Writer->writeCString(S)) 2107251ede7SZachary Turner return EC; 2117251ede7SZachary Turner } else { 212120faca4SZachary Turner if (auto EC = Reader->readCString(Value)) 2137251ede7SZachary Turner return EC; 2147251ede7SZachary Turner } 2157251ede7SZachary Turner return Error::success(); 2167251ede7SZachary Turner } 2177251ede7SZachary Turner 2186e407669SNilanjana Basu Error CodeViewRecordIO::mapGuid(GUID &Guid, const Twine &Comment) { 2194efa0a42SZachary Turner constexpr uint32_t GuidSize = 16; 220faed8516SNilanjana Basu 221faed8516SNilanjana Basu if (isStreaming()) { 222faed8516SNilanjana Basu StringRef GuidSR = 223faed8516SNilanjana Basu StringRef((reinterpret_cast<const char *>(&Guid)), GuidSize); 2246e407669SNilanjana Basu emitComment(Comment); 225faed8516SNilanjana Basu Streamer->EmitBytes(GuidSR); 226faed8516SNilanjana Basu incrStreamedLen(GuidSize); 227faed8516SNilanjana Basu return Error::success(); 228faed8516SNilanjana Basu } 229faed8516SNilanjana Basu 2304efa0a42SZachary Turner if (maxFieldLength() < GuidSize) 2314efa0a42SZachary Turner return make_error<CodeViewError>(cv_error_code::insufficient_buffer); 2324efa0a42SZachary Turner 2337251ede7SZachary Turner if (isWriting()) { 23467653ee0SReid Kleckner if (auto EC = Writer->writeBytes(Guid.Guid)) 2357251ede7SZachary Turner return EC; 2367251ede7SZachary Turner } else { 23767653ee0SReid Kleckner ArrayRef<uint8_t> GuidBytes; 23867653ee0SReid Kleckner if (auto EC = Reader->readBytes(GuidBytes, GuidSize)) 2397251ede7SZachary Turner return EC; 24067653ee0SReid Kleckner memcpy(Guid.Guid, GuidBytes.data(), GuidSize); 2417251ede7SZachary Turner } 2427251ede7SZachary Turner return Error::success(); 2437251ede7SZachary Turner } 2447251ede7SZachary Turner 2456e407669SNilanjana Basu Error CodeViewRecordIO::mapStringZVectorZ(std::vector<StringRef> &Value, 2466e407669SNilanjana Basu const Twine &Comment) { 247faed8516SNilanjana Basu 248faed8516SNilanjana Basu if (!isReading()) { 2496e407669SNilanjana Basu emitComment(Comment); 25046225b19SZachary Turner for (auto V : Value) { 25146225b19SZachary Turner if (auto EC = mapStringZ(V)) 25246225b19SZachary Turner return EC; 25346225b19SZachary Turner } 254faed8516SNilanjana Basu uint8_t FinalZero = 0; 255faed8516SNilanjana Basu if (auto EC = mapInteger(FinalZero)) 25646225b19SZachary Turner return EC; 25746225b19SZachary Turner } else { 25846225b19SZachary Turner StringRef S; 25946225b19SZachary Turner if (auto EC = mapStringZ(S)) 26046225b19SZachary Turner return EC; 26146225b19SZachary Turner while (!S.empty()) { 26246225b19SZachary Turner Value.push_back(S); 26346225b19SZachary Turner if (auto EC = mapStringZ(S)) 26446225b19SZachary Turner return EC; 26546225b19SZachary Turner }; 26646225b19SZachary Turner } 26746225b19SZachary Turner return Error::success(); 26846225b19SZachary Turner } 26946225b19SZachary Turner 2706e407669SNilanjana Basu void CodeViewRecordIO::emitEncodedSignedInteger(const int64_t &Value, 2716e407669SNilanjana Basu const Twine &Comment) { 272faed8516SNilanjana Basu assert(Value < 0 && "Encoded integer is not signed!"); 273faed8516SNilanjana Basu if (Value >= std::numeric_limits<int8_t>::min()) { 274faed8516SNilanjana Basu Streamer->EmitIntValue(LF_CHAR, 2); 2756e407669SNilanjana Basu emitComment(Comment); 276faed8516SNilanjana Basu Streamer->EmitIntValue(Value, 1); 277faed8516SNilanjana Basu incrStreamedLen(3); 278faed8516SNilanjana Basu } else if (Value >= std::numeric_limits<int16_t>::min()) { 279faed8516SNilanjana Basu Streamer->EmitIntValue(LF_SHORT, 2); 2806e407669SNilanjana Basu emitComment(Comment); 281faed8516SNilanjana Basu Streamer->EmitIntValue(Value, 2); 282faed8516SNilanjana Basu incrStreamedLen(4); 283faed8516SNilanjana Basu } else if (Value >= std::numeric_limits<int32_t>::min()) { 284faed8516SNilanjana Basu Streamer->EmitIntValue(LF_LONG, 2); 2856e407669SNilanjana Basu emitComment(Comment); 286faed8516SNilanjana Basu Streamer->EmitIntValue(Value, 4); 287faed8516SNilanjana Basu incrStreamedLen(6); 288faed8516SNilanjana Basu } else { 289faed8516SNilanjana Basu Streamer->EmitIntValue(LF_QUADWORD, 2); 2906e407669SNilanjana Basu emitComment(Comment); 291faed8516SNilanjana Basu Streamer->EmitIntValue(Value, 4); 292faed8516SNilanjana Basu incrStreamedLen(6); 293faed8516SNilanjana Basu } 294faed8516SNilanjana Basu } 295faed8516SNilanjana Basu 2966e407669SNilanjana Basu void CodeViewRecordIO::emitEncodedUnsignedInteger(const uint64_t &Value, 2976e407669SNilanjana Basu const Twine &Comment) { 298faed8516SNilanjana Basu if (Value < LF_NUMERIC) { 2996e407669SNilanjana Basu emitComment(Comment); 300faed8516SNilanjana Basu Streamer->EmitIntValue(Value, 2); 301faed8516SNilanjana Basu incrStreamedLen(2); 302faed8516SNilanjana Basu } else if (Value <= std::numeric_limits<uint16_t>::max()) { 303faed8516SNilanjana Basu Streamer->EmitIntValue(LF_USHORT, 2); 3046e407669SNilanjana Basu emitComment(Comment); 305faed8516SNilanjana Basu Streamer->EmitIntValue(Value, 2); 306faed8516SNilanjana Basu incrStreamedLen(4); 307faed8516SNilanjana Basu } else if (Value <= std::numeric_limits<uint32_t>::max()) { 308faed8516SNilanjana Basu Streamer->EmitIntValue(LF_ULONG, 2); 3096e407669SNilanjana Basu emitComment(Comment); 310faed8516SNilanjana Basu Streamer->EmitIntValue(Value, 4); 311faed8516SNilanjana Basu incrStreamedLen(6); 312faed8516SNilanjana Basu } else { 313faed8516SNilanjana Basu Streamer->EmitIntValue(LF_UQUADWORD, 2); 3146e407669SNilanjana Basu emitComment(Comment); 315faed8516SNilanjana Basu Streamer->EmitIntValue(Value, 8); 316faed8516SNilanjana Basu incrStreamedLen(6); 317faed8516SNilanjana Basu } 318faed8516SNilanjana Basu } 319faed8516SNilanjana Basu 3207251ede7SZachary Turner Error CodeViewRecordIO::writeEncodedSignedInteger(const int64_t &Value) { 3217251ede7SZachary Turner assert(Value < 0 && "Encoded integer is not signed!"); 3227251ede7SZachary Turner if (Value >= std::numeric_limits<int8_t>::min()) { 323695ed56bSZachary Turner if (auto EC = Writer->writeInteger<uint16_t>(LF_CHAR)) 3247251ede7SZachary Turner return EC; 325695ed56bSZachary Turner if (auto EC = Writer->writeInteger<int8_t>(Value)) 3267251ede7SZachary Turner return EC; 3277251ede7SZachary Turner } else if (Value >= std::numeric_limits<int16_t>::min()) { 328695ed56bSZachary Turner if (auto EC = Writer->writeInteger<uint16_t>(LF_SHORT)) 3297251ede7SZachary Turner return EC; 330695ed56bSZachary Turner if (auto EC = Writer->writeInteger<int16_t>(Value)) 3317251ede7SZachary Turner return EC; 3327251ede7SZachary Turner } else if (Value >= std::numeric_limits<int32_t>::min()) { 333695ed56bSZachary Turner if (auto EC = Writer->writeInteger<uint16_t>(LF_LONG)) 3347251ede7SZachary Turner return EC; 335695ed56bSZachary Turner if (auto EC = Writer->writeInteger<int32_t>(Value)) 3367251ede7SZachary Turner return EC; 3377251ede7SZachary Turner } else { 338695ed56bSZachary Turner if (auto EC = Writer->writeInteger<uint16_t>(LF_QUADWORD)) 3397251ede7SZachary Turner return EC; 340695ed56bSZachary Turner if (auto EC = Writer->writeInteger(Value)) 3417251ede7SZachary Turner return EC; 3427251ede7SZachary Turner } 3437251ede7SZachary Turner return Error::success(); 3447251ede7SZachary Turner } 3457251ede7SZachary Turner 3467251ede7SZachary Turner Error CodeViewRecordIO::writeEncodedUnsignedInteger(const uint64_t &Value) { 3477251ede7SZachary Turner if (Value < LF_NUMERIC) { 348695ed56bSZachary Turner if (auto EC = Writer->writeInteger<uint16_t>(Value)) 3497251ede7SZachary Turner return EC; 3507251ede7SZachary Turner } else if (Value <= std::numeric_limits<uint16_t>::max()) { 351695ed56bSZachary Turner if (auto EC = Writer->writeInteger<uint16_t>(LF_USHORT)) 3527251ede7SZachary Turner return EC; 353695ed56bSZachary Turner if (auto EC = Writer->writeInteger<uint16_t>(Value)) 3547251ede7SZachary Turner return EC; 3557251ede7SZachary Turner } else if (Value <= std::numeric_limits<uint32_t>::max()) { 356695ed56bSZachary Turner if (auto EC = Writer->writeInteger<uint16_t>(LF_ULONG)) 3577251ede7SZachary Turner return EC; 358695ed56bSZachary Turner if (auto EC = Writer->writeInteger<uint32_t>(Value)) 3597251ede7SZachary Turner return EC; 3607251ede7SZachary Turner } else { 361695ed56bSZachary Turner if (auto EC = Writer->writeInteger<uint16_t>(LF_UQUADWORD)) 3627251ede7SZachary Turner return EC; 363695ed56bSZachary Turner if (auto EC = Writer->writeInteger(Value)) 3647251ede7SZachary Turner return EC; 3657251ede7SZachary Turner } 3667251ede7SZachary Turner 3677251ede7SZachary Turner return Error::success(); 3687251ede7SZachary Turner } 369