brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.9 KiB · 0d0a357 Raw
394 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/DebugInfo/CodeView/CodeViewRecordIO.h"10#include "llvm/ADT/StringExtras.h"11#include "llvm/DebugInfo/CodeView/CodeView.h"12#include "llvm/DebugInfo/CodeView/GUID.h"13#include "llvm/DebugInfo/CodeView/RecordSerialization.h"14#include "llvm/DebugInfo/CodeView/TypeIndex.h"15#include "llvm/Support/BinaryStreamReader.h"16#include "llvm/Support/BinaryStreamWriter.h"17 18using namespace llvm;19using namespace llvm::codeview;20 21Error CodeViewRecordIO::beginRecord(std::optional<uint32_t> MaxLength) {22  RecordLimit Limit;23  Limit.MaxLength = MaxLength;24  Limit.BeginOffset = getCurrentOffset();25  Limits.push_back(Limit);26  return Error::success();27}28 29Error CodeViewRecordIO::endRecord() {30  assert(!Limits.empty() && "Not in a record!");31  Limits.pop_back();32  // We would like to assert that we actually read / wrote all the bytes that we33  // expected to for this record, but unfortunately we can't do this.  Some34  // producers such as MASM over-allocate for certain types of records and35  // commit the extraneous data, so when reading we can't be sure every byte36  // will have been read.  And when writing we over-allocate temporarily since37  // we don't know how big the record is until we're finished writing it, so38  // even though we don't commit the extraneous data, we still can't guarantee39  // we're at the end of the allocated data.40 41  if (isStreaming()) {42    // For streaming mode, add padding to align with 4 byte boundaries for each43    // record44    uint32_t Align = getStreamedLen() % 4;45    if (Align == 0)46      return Error::success();47 48    int PaddingBytes = 4 - Align;49    while (PaddingBytes > 0) {50      char Pad = static_cast<uint8_t>(LF_PAD0 + PaddingBytes);51      StringRef BytesSR = StringRef(&Pad, sizeof(Pad));52      Streamer->emitBytes(BytesSR);53      --PaddingBytes;54    }55    resetStreamedLen();56  }57  return Error::success();58}59 60uint32_t CodeViewRecordIO::maxFieldLength() const {61  if (isStreaming())62    return 0;63 64  assert(!Limits.empty() && "Not in a record!");65 66  // The max length of the next field is the minimum of all lengths that would67  // be allowed by any of the sub-records we're in.  In practice, we can only68  // ever be at most 1 sub-record deep (in a FieldList), but this works for69  // the general case.70  uint32_t Offset = getCurrentOffset();71  std::optional<uint32_t> Min = Limits.front().bytesRemaining(Offset);72  for (auto X : ArrayRef(Limits).drop_front()) {73    std::optional<uint32_t> ThisMin = X.bytesRemaining(Offset);74    if (ThisMin)75      Min = Min ? std::min(*Min, *ThisMin) : *ThisMin;76  }77  assert(Min && "Every field must have a maximum length!");78 79  return *Min;80}81 82Error CodeViewRecordIO::padToAlignment(uint32_t Align) {83  if (isReading())84    return Reader->padToAlignment(Align);85  return Writer->padToAlignment(Align);86}87 88Error CodeViewRecordIO::skipPadding() {89  assert(!isWriting() && "Cannot skip padding while writing!");90 91  if (Reader->bytesRemaining() == 0)92    return Error::success();93 94  uint8_t Leaf = Reader->peek();95  if (Leaf < LF_PAD0)96    return Error::success();97  // Leaf is greater than 0xf0. We should advance by the number of bytes in98  // the low 4 bits.99  unsigned BytesToAdvance = Leaf & 0x0F;100  return Reader->skip(BytesToAdvance);101}102 103Error CodeViewRecordIO::mapByteVectorTail(ArrayRef<uint8_t> &Bytes,104                                          const Twine &Comment) {105  if (isStreaming()) {106    emitComment(Comment);107    Streamer->emitBinaryData(toStringRef(Bytes));108    incrStreamedLen(Bytes.size());109  } else if (isWriting()) {110    if (auto EC = Writer->writeBytes(Bytes))111      return EC;112  } else {113    if (auto EC = Reader->readBytes(Bytes, Reader->bytesRemaining()))114      return EC;115  }116  return Error::success();117}118 119Error CodeViewRecordIO::mapByteVectorTail(std::vector<uint8_t> &Bytes,120                                          const Twine &Comment) {121  ArrayRef<uint8_t> BytesRef(Bytes);122  if (auto EC = mapByteVectorTail(BytesRef, Comment))123    return EC;124  if (!isWriting())125    Bytes.assign(BytesRef.begin(), BytesRef.end());126 127  return Error::success();128}129 130Error CodeViewRecordIO::mapInteger(TypeIndex &TypeInd, const Twine &Comment) {131  if (isStreaming()) {132    std::string TypeNameStr = Streamer->getTypeName(TypeInd);133    if (!TypeNameStr.empty())134      emitComment(Comment + ": " + TypeNameStr);135    else136      emitComment(Comment);137    Streamer->emitIntValue(TypeInd.getIndex(), sizeof(TypeInd.getIndex()));138    incrStreamedLen(sizeof(TypeInd.getIndex()));139  } else if (isWriting()) {140    if (auto EC = Writer->writeInteger(TypeInd.getIndex()))141      return EC;142  } else {143    uint32_t I;144    if (auto EC = Reader->readInteger(I))145      return EC;146    TypeInd.setIndex(I);147  }148  return Error::success();149}150 151Error CodeViewRecordIO::mapEncodedInteger(int64_t &Value,152                                          const Twine &Comment) {153  if (isStreaming()) {154    if (Value >= 0)155      emitEncodedUnsignedInteger(static_cast<uint64_t>(Value), Comment);156    else157      emitEncodedSignedInteger(Value, Comment);158  } else if (isWriting()) {159    if (Value >= 0) {160      if (auto EC = writeEncodedUnsignedInteger(static_cast<uint64_t>(Value)))161        return EC;162    } else {163      if (auto EC = writeEncodedSignedInteger(Value))164        return EC;165    }166  } else {167    APSInt N;168    if (auto EC = consume(*Reader, N))169      return EC;170    Value = N.getExtValue();171  }172 173  return Error::success();174}175 176Error CodeViewRecordIO::mapEncodedInteger(uint64_t &Value,177                                          const Twine &Comment) {178  if (isStreaming())179    emitEncodedUnsignedInteger(Value, Comment);180  else if (isWriting()) {181    if (auto EC = writeEncodedUnsignedInteger(Value))182      return EC;183  } else {184    APSInt N;185    if (auto EC = consume(*Reader, N))186      return EC;187    Value = N.getZExtValue();188  }189  return Error::success();190}191 192Error CodeViewRecordIO::mapEncodedInteger(APSInt &Value, const Twine &Comment) {193  if (isStreaming()) {194    // FIXME: We also need to handle big values here, but it's195    //        not clear how we can excercise this code path yet.196    if (Value.isSigned())197      emitEncodedSignedInteger(Value.getSExtValue(), Comment);198    else199      emitEncodedUnsignedInteger(Value.getZExtValue(), Comment);200  } else if (isWriting()) {201    if (Value.isSigned())202      return writeEncodedSignedInteger(203          Value.isSingleWord() ? Value.getSExtValue() : INT64_MIN);204    return writeEncodedUnsignedInteger(Value.getLimitedValue());205  } else206    return consume(*Reader, Value);207  return Error::success();208}209 210Error CodeViewRecordIO::mapStringZ(StringRef &Value, const Twine &Comment) {211  if (isStreaming()) {212    auto NullTerminatedString = StringRef(Value.data(), Value.size() + 1);213    emitComment(Comment);214    Streamer->emitBytes(NullTerminatedString);215    incrStreamedLen(NullTerminatedString.size());216  } else if (isWriting()) {217    // Truncate if we attempt to write too much.218    StringRef S = Value.take_front(maxFieldLength() - 1);219    if (auto EC = Writer->writeCString(S))220      return EC;221  } else {222    if (auto EC = Reader->readCString(Value))223      return EC;224  }225  return Error::success();226}227 228Error CodeViewRecordIO::mapGuid(GUID &Guid, const Twine &Comment) {229  constexpr uint32_t GuidSize = 16;230 231  if (isStreaming()) {232    StringRef GuidSR =233        StringRef((reinterpret_cast<const char *>(&Guid)), GuidSize);234    emitComment(Comment);235    Streamer->emitBytes(GuidSR);236    incrStreamedLen(GuidSize);237    return Error::success();238  }239 240  if (maxFieldLength() < GuidSize)241    return make_error<CodeViewError>(cv_error_code::insufficient_buffer);242 243  if (isWriting()) {244    if (auto EC = Writer->writeBytes(Guid.Guid))245      return EC;246  } else {247    ArrayRef<uint8_t> GuidBytes;248    if (auto EC = Reader->readBytes(GuidBytes, GuidSize))249      return EC;250    memcpy(Guid.Guid, GuidBytes.data(), GuidSize);251  }252  return Error::success();253}254 255Error CodeViewRecordIO::mapStringZVectorZ(std::vector<StringRef> &Value,256                                          const Twine &Comment) {257 258  if (!isReading()) {259    emitComment(Comment);260    for (auto V : Value) {261      if (auto EC = mapStringZ(V))262        return EC;263    }264    uint8_t FinalZero = 0;265    if (auto EC = mapInteger(FinalZero))266      return EC;267  } else {268    StringRef S;269    if (auto EC = mapStringZ(S))270      return EC;271    while (!S.empty()) {272      Value.push_back(S);273      if (auto EC = mapStringZ(S))274        return EC;275    };276  }277  return Error::success();278}279 280void CodeViewRecordIO::emitEncodedSignedInteger(const int64_t &Value,281                                                const Twine &Comment) {282  // FIXME: There are no test cases covering this function.283  // This may be because we always consider enumerators to be unsigned.284  // See FIXME at CodeViewDebug.cpp : CodeViewDebug::lowerTypeEnum.285  if (Value < LF_NUMERIC && Value >= 0) {286    emitComment(Comment);287    Streamer->emitIntValue(Value, 2);288    incrStreamedLen(2);289  } else if (Value >= std::numeric_limits<int8_t>::min() &&290             Value <= std::numeric_limits<int8_t>::max()) {291    Streamer->emitIntValue(LF_CHAR, 2);292    emitComment(Comment);293    Streamer->emitIntValue(Value, 1);294    incrStreamedLen(3);295  } else if (Value >= std::numeric_limits<int16_t>::min() &&296             Value <= std::numeric_limits<int16_t>::max()) {297    Streamer->emitIntValue(LF_SHORT, 2);298    emitComment(Comment);299    Streamer->emitIntValue(Value, 2);300    incrStreamedLen(4);301  } else if (Value >= std::numeric_limits<int32_t>::min() &&302             Value <= std::numeric_limits<int32_t>::max()) {303    Streamer->emitIntValue(LF_LONG, 2);304    emitComment(Comment);305    Streamer->emitIntValue(Value, 4);306    incrStreamedLen(6);307  } else {308    Streamer->emitIntValue(LF_QUADWORD, 2);309    emitComment(Comment);310    Streamer->emitIntValue(Value, 4); // FIXME: Why not 8 (size of quadword)?311    incrStreamedLen(6);               // FIXME: Why not 10 (8 + 2)?312  }313}314 315void CodeViewRecordIO::emitEncodedUnsignedInteger(const uint64_t &Value,316                                                  const Twine &Comment) {317  if (Value < LF_NUMERIC) {318    emitComment(Comment);319    Streamer->emitIntValue(Value, 2);320    incrStreamedLen(2);321  } else if (Value <= std::numeric_limits<uint16_t>::max()) {322    Streamer->emitIntValue(LF_USHORT, 2);323    emitComment(Comment);324    Streamer->emitIntValue(Value, 2);325    incrStreamedLen(4);326  } else if (Value <= std::numeric_limits<uint32_t>::max()) {327    Streamer->emitIntValue(LF_ULONG, 2);328    emitComment(Comment);329    Streamer->emitIntValue(Value, 4);330    incrStreamedLen(6);331  } else {332    // FIXME: There are no test cases covering this block.333    Streamer->emitIntValue(LF_UQUADWORD, 2);334    emitComment(Comment);335    Streamer->emitIntValue(Value, 8);336    incrStreamedLen(6); // FIXME: Why not 10 (8 + 2)?337  }338}339 340Error CodeViewRecordIO::writeEncodedSignedInteger(const int64_t &Value) {341  if (Value < LF_NUMERIC && Value >= 0) {342    if (auto EC = Writer->writeInteger<int16_t>(Value))343      return EC;344  } else if (Value >= std::numeric_limits<int8_t>::min() &&345             Value <= std::numeric_limits<int8_t>::max()) {346    if (auto EC = Writer->writeInteger<uint16_t>(LF_CHAR))347      return EC;348    if (auto EC = Writer->writeInteger<int8_t>(Value))349      return EC;350  } else if (Value >= std::numeric_limits<int16_t>::min() &&351             Value <= std::numeric_limits<int16_t>::max()) {352    if (auto EC = Writer->writeInteger<uint16_t>(LF_SHORT))353      return EC;354    if (auto EC = Writer->writeInteger<int16_t>(Value))355      return EC;356  } else if (Value >= std::numeric_limits<int32_t>::min() &&357             Value <= std::numeric_limits<int32_t>::max()) {358    if (auto EC = Writer->writeInteger<uint16_t>(LF_LONG))359      return EC;360    if (auto EC = Writer->writeInteger<int32_t>(Value))361      return EC;362  } else {363    if (auto EC = Writer->writeInteger<uint16_t>(LF_QUADWORD))364      return EC;365    if (auto EC = Writer->writeInteger(Value))366      return EC;367  }368  return Error::success();369}370 371Error CodeViewRecordIO::writeEncodedUnsignedInteger(const uint64_t &Value) {372  if (Value < LF_NUMERIC) {373    if (auto EC = Writer->writeInteger<uint16_t>(Value))374      return EC;375  } else if (Value <= std::numeric_limits<uint16_t>::max()) {376    if (auto EC = Writer->writeInteger<uint16_t>(LF_USHORT))377      return EC;378    if (auto EC = Writer->writeInteger<uint16_t>(Value))379      return EC;380  } else if (Value <= std::numeric_limits<uint32_t>::max()) {381    if (auto EC = Writer->writeInteger<uint16_t>(LF_ULONG))382      return EC;383    if (auto EC = Writer->writeInteger<uint32_t>(Value))384      return EC;385  } else {386    if (auto EC = Writer->writeInteger<uint16_t>(LF_UQUADWORD))387      return EC;388    if (auto EC = Writer->writeInteger(Value))389      return EC;390  }391 392  return Error::success();393}394