Home | History | Annotate | Line # | Download | only in CodeView
      1 //===- CVRecord.h -----------------------------------------------*- 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 
      9 #ifndef LLVM_DEBUGINFO_CODEVIEW_CVRECORD_H
     10 #define LLVM_DEBUGINFO_CODEVIEW_CVRECORD_H
     11 
     12 #include "llvm/ADT/ArrayRef.h"
     13 #include "llvm/ADT/Optional.h"
     14 #include "llvm/DebugInfo/CodeView/CodeView.h"
     15 #include "llvm/DebugInfo/CodeView/CodeViewError.h"
     16 #include "llvm/DebugInfo/CodeView/RecordSerialization.h"
     17 #include "llvm/Support/BinaryStreamReader.h"
     18 #include "llvm/Support/BinaryStreamRef.h"
     19 #include "llvm/Support/Endian.h"
     20 #include "llvm/Support/Error.h"
     21 #include <cstdint>
     22 
     23 namespace llvm {
     24 
     25 namespace codeview {
     26 
     27 /// CVRecord is a fat pointer (base + size pair) to a symbol or type record.
     28 /// Carrying the size separately instead of trusting the size stored in the
     29 /// record prefix provides some extra safety and flexibility.
     30 template <typename Kind> class CVRecord {
     31 public:
     32   CVRecord() = default;
     33 
     34   CVRecord(ArrayRef<uint8_t> Data) : RecordData(Data) {}
     35 
     36   CVRecord(const RecordPrefix *P, size_t Size)
     37       : RecordData(reinterpret_cast<const uint8_t *>(P), Size) {}
     38 
     39   bool valid() const { return kind() != Kind(0); }
     40 
     41   uint32_t length() const { return RecordData.size(); }
     42 
     43   Kind kind() const {
     44     if (RecordData.size() < sizeof(RecordPrefix))
     45       return Kind(0);
     46     return static_cast<Kind>(static_cast<uint16_t>(
     47         reinterpret_cast<const RecordPrefix *>(RecordData.data())->RecordKind));
     48   }
     49 
     50   ArrayRef<uint8_t> data() const { return RecordData; }
     51 
     52   StringRef str_data() const {
     53     return StringRef(reinterpret_cast<const char *>(RecordData.data()),
     54                      RecordData.size());
     55   }
     56 
     57   ArrayRef<uint8_t> content() const {
     58     return RecordData.drop_front(sizeof(RecordPrefix));
     59   }
     60 
     61   ArrayRef<uint8_t> RecordData;
     62 };
     63 
     64 // There are two kinds of codeview records: type and symbol records.
     65 using CVType = CVRecord<TypeLeafKind>;
     66 using CVSymbol = CVRecord<SymbolKind>;
     67 
     68 template <typename Record, typename Func>
     69 Error forEachCodeViewRecord(ArrayRef<uint8_t> StreamBuffer, Func F) {
     70   while (!StreamBuffer.empty()) {
     71     if (StreamBuffer.size() < sizeof(RecordPrefix))
     72       return make_error<CodeViewError>(cv_error_code::corrupt_record);
     73 
     74     const RecordPrefix *Prefix =
     75         reinterpret_cast<const RecordPrefix *>(StreamBuffer.data());
     76 
     77     size_t RealLen = Prefix->RecordLen + 2;
     78     if (StreamBuffer.size() < RealLen)
     79       return make_error<CodeViewError>(cv_error_code::corrupt_record);
     80 
     81     ArrayRef<uint8_t> Data = StreamBuffer.take_front(RealLen);
     82     StreamBuffer = StreamBuffer.drop_front(RealLen);
     83 
     84     Record R(Data);
     85     if (auto EC = F(R))
     86       return EC;
     87   }
     88   return Error::success();
     89 }
     90 
     91 /// Read a complete record from a stream at a random offset.
     92 template <typename Kind>
     93 inline Expected<CVRecord<Kind>> readCVRecordFromStream(BinaryStreamRef Stream,
     94                                                        uint32_t Offset) {
     95   const RecordPrefix *Prefix = nullptr;
     96   BinaryStreamReader Reader(Stream);
     97   Reader.setOffset(Offset);
     98 
     99   if (auto EC = Reader.readObject(Prefix))
    100     return std::move(EC);
    101   if (Prefix->RecordLen < 2)
    102     return make_error<CodeViewError>(cv_error_code::corrupt_record);
    103 
    104   Reader.setOffset(Offset);
    105   ArrayRef<uint8_t> RawData;
    106   if (auto EC = Reader.readBytes(RawData, Prefix->RecordLen + sizeof(uint16_t)))
    107     return std::move(EC);
    108   return codeview::CVRecord<Kind>(RawData);
    109 }
    110 
    111 } // end namespace codeview
    112 
    113 template <typename Kind>
    114 struct VarStreamArrayExtractor<codeview::CVRecord<Kind>> {
    115   Error operator()(BinaryStreamRef Stream, uint32_t &Len,
    116                    codeview::CVRecord<Kind> &Item) {
    117     auto ExpectedRec = codeview::readCVRecordFromStream<Kind>(Stream, 0);
    118     if (!ExpectedRec)
    119       return ExpectedRec.takeError();
    120     Item = *ExpectedRec;
    121     Len = ExpectedRec->length();
    122     return Error::success();
    123   }
    124 };
    125 
    126 namespace codeview {
    127 using CVSymbolArray = VarStreamArray<CVSymbol>;
    128 using CVTypeArray = VarStreamArray<CVType>;
    129 using CVTypeRange = iterator_range<CVTypeArray::Iterator>;
    130 } // namespace codeview
    131 
    132 } // end namespace llvm
    133 
    134 #endif // LLVM_DEBUGINFO_CODEVIEW_CVRECORD_H
    135