137 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			137 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
//===- ModInfoBuilder.cpp - PDB Module Info Stream Creation -----*- C++ -*-===//
 | 
						|
//
 | 
						|
//                     The LLVM Compiler Infrastructure
 | 
						|
//
 | 
						|
// This file is distributed under the University of Illinois Open Source
 | 
						|
// License. See LICENSE.TXT for details.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "llvm/DebugInfo/PDB/Native/ModInfoBuilder.h"
 | 
						|
 | 
						|
#include "llvm/ADT/ArrayRef.h"
 | 
						|
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
 | 
						|
#include "llvm/DebugInfo/MSF/MSFCommon.h"
 | 
						|
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
 | 
						|
#include "llvm/DebugInfo/PDB/Native/ModInfo.h"
 | 
						|
#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
 | 
						|
#include "llvm/DebugInfo/PDB/Native/RawError.h"
 | 
						|
#include "llvm/Support/BinaryItemStream.h"
 | 
						|
#include "llvm/Support/BinaryStreamWriter.h"
 | 
						|
#include "llvm/Support/COFF.h"
 | 
						|
 | 
						|
using namespace llvm;
 | 
						|
using namespace llvm::codeview;
 | 
						|
using namespace llvm::msf;
 | 
						|
using namespace llvm::pdb;
 | 
						|
 | 
						|
namespace llvm {
 | 
						|
template <> struct BinaryItemTraits<CVSymbol> {
 | 
						|
  static size_t length(const CVSymbol &Item) { return Item.RecordData.size(); }
 | 
						|
 | 
						|
  static ArrayRef<uint8_t> bytes(const CVSymbol &Item) {
 | 
						|
    return Item.RecordData;
 | 
						|
  }
 | 
						|
};
 | 
						|
}
 | 
						|
 | 
						|
static uint32_t calculateDiSymbolStreamSize(uint32_t SymbolByteSize) {
 | 
						|
  uint32_t Size = sizeof(uint32_t); // Signature
 | 
						|
  Size += SymbolByteSize;           // Symbol Data
 | 
						|
  Size += 0;                        // TODO: Layout.LineBytes
 | 
						|
  Size += 0;                        // TODO: Layout.C13Bytes
 | 
						|
  Size += sizeof(uint32_t);         // GlobalRefs substream size (always 0)
 | 
						|
  Size += 0;                        // GlobalRefs substream bytes
 | 
						|
  return Size;
 | 
						|
}
 | 
						|
 | 
						|
ModInfoBuilder::ModInfoBuilder(StringRef ModuleName, uint32_t ModIndex,
 | 
						|
                               msf::MSFBuilder &Msf)
 | 
						|
    : MSF(Msf), ModuleName(ModuleName) {
 | 
						|
  Layout.Mod = ModIndex;
 | 
						|
}
 | 
						|
 | 
						|
uint16_t ModInfoBuilder::getStreamIndex() const { return Layout.ModDiStream; }
 | 
						|
 | 
						|
void ModInfoBuilder::setObjFileName(StringRef Name) { ObjFileName = Name; }
 | 
						|
 | 
						|
void ModInfoBuilder::addSymbol(CVSymbol Symbol) {
 | 
						|
  Symbols.push_back(Symbol);
 | 
						|
  SymbolByteSize += Symbol.data().size();
 | 
						|
}
 | 
						|
 | 
						|
void ModInfoBuilder::addSourceFile(StringRef Path) {
 | 
						|
  SourceFiles.push_back(Path);
 | 
						|
}
 | 
						|
 | 
						|
uint32_t ModInfoBuilder::calculateSerializedLength() const {
 | 
						|
  uint32_t L = sizeof(Layout);
 | 
						|
  uint32_t M = ModuleName.size() + 1;
 | 
						|
  uint32_t O = ObjFileName.size() + 1;
 | 
						|
  return alignTo(L + M + O, sizeof(uint32_t));
 | 
						|
}
 | 
						|
 | 
						|
void ModInfoBuilder::finalize() {
 | 
						|
  Layout.C13Bytes = 0;
 | 
						|
  Layout.FileNameOffs = 0; // TODO: Fix this
 | 
						|
  Layout.Flags = 0;        // TODO: Fix this
 | 
						|
  Layout.LineBytes = 0;
 | 
						|
  (void)Layout.Mod;         // Set in constructor
 | 
						|
  (void)Layout.ModDiStream; // Set in finalizeMsfLayout
 | 
						|
  Layout.NumFiles = SourceFiles.size();
 | 
						|
  Layout.PdbFilePathNI = 0;
 | 
						|
  Layout.SrcFileNameNI = 0;
 | 
						|
 | 
						|
  // This value includes both the signature field as well as the record bytes
 | 
						|
  // from the symbol stream.
 | 
						|
  Layout.SymBytes = SymbolByteSize + sizeof(uint32_t);
 | 
						|
}
 | 
						|
 | 
						|
Error ModInfoBuilder::finalizeMsfLayout() {
 | 
						|
  this->Layout.ModDiStream = kInvalidStreamIndex;
 | 
						|
  auto ExpectedSN = MSF.addStream(calculateDiSymbolStreamSize(SymbolByteSize));
 | 
						|
  if (!ExpectedSN)
 | 
						|
    return ExpectedSN.takeError();
 | 
						|
  Layout.ModDiStream = *ExpectedSN;
 | 
						|
  return Error::success();
 | 
						|
}
 | 
						|
 | 
						|
Error ModInfoBuilder::commit(BinaryStreamWriter &ModiWriter,
 | 
						|
                             const msf::MSFLayout &MsfLayout,
 | 
						|
                             WritableBinaryStreamRef MsfBuffer) {
 | 
						|
  // We write the Modi record to the `ModiWriter`, but we additionally write its
 | 
						|
  // symbol stream to a brand new stream.
 | 
						|
  if (auto EC = ModiWriter.writeObject(Layout))
 | 
						|
    return EC;
 | 
						|
  if (auto EC = ModiWriter.writeCString(ModuleName))
 | 
						|
    return EC;
 | 
						|
  if (auto EC = ModiWriter.writeCString(ObjFileName))
 | 
						|
    return EC;
 | 
						|
  if (auto EC = ModiWriter.padToAlignment(sizeof(uint32_t)))
 | 
						|
    return EC;
 | 
						|
 | 
						|
  if (Layout.ModDiStream != kInvalidStreamIndex) {
 | 
						|
    auto NS = WritableMappedBlockStream::createIndexedStream(
 | 
						|
        MsfLayout, MsfBuffer, Layout.ModDiStream);
 | 
						|
    WritableBinaryStreamRef Ref(*NS);
 | 
						|
    BinaryStreamWriter SymbolWriter(Ref);
 | 
						|
    // Write the symbols.
 | 
						|
    if (auto EC =
 | 
						|
            SymbolWriter.writeInteger<uint32_t>(COFF::DEBUG_SECTION_MAGIC))
 | 
						|
      return EC;
 | 
						|
    BinaryItemStream<CVSymbol> Records(llvm::support::endianness::little);
 | 
						|
    Records.setItems(Symbols);
 | 
						|
    BinaryStreamRef RecordsRef(Records);
 | 
						|
    if (auto EC = SymbolWriter.writeStreamRef(RecordsRef))
 | 
						|
      return EC;
 | 
						|
    // TODO: Write C11 Line data
 | 
						|
    // TODO: Write C13 Line data
 | 
						|
    // TODO: Figure out what GlobalRefs substream actually is and populate it.
 | 
						|
    if (auto EC = SymbolWriter.writeInteger<uint32_t>(0))
 | 
						|
      return EC;
 | 
						|
    if (SymbolWriter.bytesRemaining() > 0)
 | 
						|
      return make_error<RawError>(raw_error_code::stream_too_long);
 | 
						|
  }
 | 
						|
  return Error::success();
 | 
						|
}
 |