Home | History | Annotate | Line # | Download | only in CodeView
      1 //===- DebugChecksumsSubsection.cpp ---------------------------------------===//
      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 #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
     10 #include "llvm/ADT/ArrayRef.h"
     11 #include "llvm/DebugInfo/CodeView/CodeView.h"
     12 #include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
     13 #include "llvm/Support/BinaryStreamReader.h"
     14 #include "llvm/Support/BinaryStreamWriter.h"
     15 #include "llvm/Support/Endian.h"
     16 #include "llvm/Support/Error.h"
     17 #include "llvm/Support/MathExtras.h"
     18 #include <cassert>
     19 #include <cstdint>
     20 #include <cstring>
     21 
     22 using namespace llvm;
     23 using namespace llvm::codeview;
     24 
     25 struct FileChecksumEntryHeader {
     26   using ulittle32_t = support::ulittle32_t;
     27 
     28   ulittle32_t FileNameOffset; // Byte offset of filename in global string table.
     29   uint8_t ChecksumSize;       // Number of bytes of checksum.
     30   uint8_t ChecksumKind;       // FileChecksumKind
     31                               // Checksum bytes follow.
     32 };
     33 
     34 Error VarStreamArrayExtractor<FileChecksumEntry>::
     35 operator()(BinaryStreamRef Stream, uint32_t &Len, FileChecksumEntry &Item) {
     36   BinaryStreamReader Reader(Stream);
     37 
     38   const FileChecksumEntryHeader *Header;
     39   if (auto EC = Reader.readObject(Header))
     40     return EC;
     41 
     42   Item.FileNameOffset = Header->FileNameOffset;
     43   Item.Kind = static_cast<FileChecksumKind>(Header->ChecksumKind);
     44   if (auto EC = Reader.readBytes(Item.Checksum, Header->ChecksumSize))
     45     return EC;
     46 
     47   Len = alignTo(Header->ChecksumSize + sizeof(FileChecksumEntryHeader), 4);
     48   return Error::success();
     49 }
     50 
     51 Error DebugChecksumsSubsectionRef::initialize(BinaryStreamReader Reader) {
     52   if (auto EC = Reader.readArray(Checksums, Reader.bytesRemaining()))
     53     return EC;
     54 
     55   return Error::success();
     56 }
     57 
     58 Error DebugChecksumsSubsectionRef::initialize(BinaryStreamRef Section) {
     59   BinaryStreamReader Reader(Section);
     60   return initialize(Reader);
     61 }
     62 
     63 DebugChecksumsSubsection::DebugChecksumsSubsection(
     64     DebugStringTableSubsection &Strings)
     65     : DebugSubsection(DebugSubsectionKind::FileChecksums), Strings(Strings) {}
     66 
     67 void DebugChecksumsSubsection::addChecksum(StringRef FileName,
     68                                            FileChecksumKind Kind,
     69                                            ArrayRef<uint8_t> Bytes) {
     70   FileChecksumEntry Entry;
     71   if (!Bytes.empty()) {
     72     uint8_t *Copy = Storage.Allocate<uint8_t>(Bytes.size());
     73     ::memcpy(Copy, Bytes.data(), Bytes.size());
     74     Entry.Checksum = makeArrayRef(Copy, Bytes.size());
     75   }
     76 
     77   Entry.FileNameOffset = Strings.insert(FileName);
     78   Entry.Kind = Kind;
     79   Checksums.push_back(Entry);
     80 
     81   // This maps the offset of this string in the string table to the offset
     82   // of this checksum entry in the checksum buffer.
     83   OffsetMap[Entry.FileNameOffset] = SerializedSize;
     84   assert(SerializedSize % 4 == 0);
     85 
     86   uint32_t Len = alignTo(sizeof(FileChecksumEntryHeader) + Bytes.size(), 4);
     87   SerializedSize += Len;
     88 }
     89 
     90 uint32_t DebugChecksumsSubsection::calculateSerializedSize() const {
     91   return SerializedSize;
     92 }
     93 
     94 Error DebugChecksumsSubsection::commit(BinaryStreamWriter &Writer) const {
     95   for (const auto &FC : Checksums) {
     96     FileChecksumEntryHeader Header;
     97     Header.ChecksumKind = uint8_t(FC.Kind);
     98     Header.ChecksumSize = FC.Checksum.size();
     99     Header.FileNameOffset = FC.FileNameOffset;
    100     if (auto EC = Writer.writeObject(Header))
    101       return EC;
    102     if (auto EC = Writer.writeArray(makeArrayRef(FC.Checksum)))
    103       return EC;
    104     if (auto EC = Writer.padToAlignment(4))
    105       return EC;
    106   }
    107   return Error::success();
    108 }
    109 
    110 uint32_t DebugChecksumsSubsection::mapChecksumOffset(StringRef FileName) const {
    111   uint32_t Offset = Strings.getIdForString(FileName);
    112   auto Iter = OffsetMap.find(Offset);
    113   assert(Iter != OffsetMap.end());
    114   return Iter->second;
    115 }
    116