reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
//===- CVRecord.h -----------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_DEBUGINFO_CODEVIEW_RECORDITERATOR_H
#define LLVM_DEBUGINFO_CODEVIEW_RECORDITERATOR_H

#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
#include "llvm/DebugInfo/CodeView/CodeViewError.h"
#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
#include "llvm/Support/BinaryStreamReader.h"
#include "llvm/Support/BinaryStreamRef.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
#include <cstdint>

namespace llvm {

namespace codeview {

/// CVRecord is a fat pointer (base + size pair) to a symbol or type record.
/// Carrying the size separately instead of trusting the size stored in the
/// record prefix provides some extra safety and flexibility.
template <typename Kind> class CVRecord {
public:
  CVRecord() = default;

  CVRecord(ArrayRef<uint8_t> Data) : RecordData(Data) {}

  CVRecord(const RecordPrefix *P, size_t Size)
      : RecordData(reinterpret_cast<const uint8_t *>(P), Size) {}

  bool valid() const { return kind() != Kind(0); }

  uint32_t length() const { return RecordData.size(); }

  Kind kind() const {
    if (RecordData.size() < sizeof(RecordPrefix))
      return Kind(0);
    return static_cast<Kind>(static_cast<uint16_t>(
        reinterpret_cast<const RecordPrefix *>(RecordData.data())->RecordKind));
  }

  ArrayRef<uint8_t> data() const { return RecordData; }

  StringRef str_data() const {
    return StringRef(reinterpret_cast<const char *>(RecordData.data()),
                     RecordData.size());
  }

  ArrayRef<uint8_t> content() const {
    return RecordData.drop_front(sizeof(RecordPrefix));
  }

  ArrayRef<uint8_t> RecordData;
};

template <typename Kind> struct RemappedRecord {
  explicit RemappedRecord(const CVRecord<Kind> &R) : OriginalRecord(R) {}

  CVRecord<Kind> OriginalRecord;
  SmallVector<std::pair<uint32_t, TypeIndex>, 8> Mappings;
};

template <typename Record, typename Func>
Error forEachCodeViewRecord(ArrayRef<uint8_t> StreamBuffer, Func F) {
  while (!StreamBuffer.empty()) {
    if (StreamBuffer.size() < sizeof(RecordPrefix))
      return make_error<CodeViewError>(cv_error_code::corrupt_record);

    const RecordPrefix *Prefix =
        reinterpret_cast<const RecordPrefix *>(StreamBuffer.data());

    size_t RealLen = Prefix->RecordLen + 2;
    if (StreamBuffer.size() < RealLen)
      return make_error<CodeViewError>(cv_error_code::corrupt_record);

    ArrayRef<uint8_t> Data = StreamBuffer.take_front(RealLen);
    StreamBuffer = StreamBuffer.drop_front(RealLen);

    Record R(Data);
    if (auto EC = F(R))
      return EC;
  }
  return Error::success();
}

/// Read a complete record from a stream at a random offset.
template <typename Kind>
inline Expected<CVRecord<Kind>> readCVRecordFromStream(BinaryStreamRef Stream,
                                                       uint32_t Offset) {
  const RecordPrefix *Prefix = nullptr;
  BinaryStreamReader Reader(Stream);
  Reader.setOffset(Offset);

  if (auto EC = Reader.readObject(Prefix))
    return std::move(EC);
  if (Prefix->RecordLen < 2)
    return make_error<CodeViewError>(cv_error_code::corrupt_record);

  Reader.setOffset(Offset);
  ArrayRef<uint8_t> RawData;
  if (auto EC = Reader.readBytes(RawData, Prefix->RecordLen + sizeof(uint16_t)))
    return std::move(EC);
  return codeview::CVRecord<Kind>(RawData);
}

} // end namespace codeview

template <typename Kind>
struct VarStreamArrayExtractor<codeview::CVRecord<Kind>> {
  Error operator()(BinaryStreamRef Stream, uint32_t &Len,
                   codeview::CVRecord<Kind> &Item) {
    auto ExpectedRec = codeview::readCVRecordFromStream<Kind>(Stream, 0);
    if (!ExpectedRec)
      return ExpectedRec.takeError();
    Item = *ExpectedRec;
    Len = ExpectedRec->length();
    return Error::success();
  }
};

} // end namespace llvm

#endif // LLVM_DEBUGINFO_CODEVIEW_RECORDITERATOR_H