153 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			153 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			C++
		
	
	
	
//===- NamedStreamMap.cpp - PDB Named Stream Map --------------------------===//
 | 
						|
//
 | 
						|
//                     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/NamedStreamMap.h"
 | 
						|
#include "llvm/ADT/StringMap.h"
 | 
						|
#include "llvm/ADT/StringRef.h"
 | 
						|
#include "llvm/ADT/iterator_range.h"
 | 
						|
#include "llvm/DebugInfo/PDB/Native/HashTable.h"
 | 
						|
#include "llvm/DebugInfo/PDB/Native/RawError.h"
 | 
						|
#include "llvm/Support/BinaryStreamReader.h"
 | 
						|
#include "llvm/Support/BinaryStreamRef.h"
 | 
						|
#include "llvm/Support/BinaryStreamWriter.h"
 | 
						|
#include "llvm/Support/Endian.h"
 | 
						|
#include "llvm/Support/Error.h"
 | 
						|
#include <algorithm>
 | 
						|
#include <cassert>
 | 
						|
#include <cstdint>
 | 
						|
#include <tuple>
 | 
						|
 | 
						|
using namespace llvm;
 | 
						|
using namespace llvm::pdb;
 | 
						|
 | 
						|
// FIXME: This shouldn't be necessary, but if we insert the strings in any
 | 
						|
// other order, cvdump cannot read the generated name map.  This suggests that
 | 
						|
// we may be using the wrong hash function.  A closer inspection of the cvdump
 | 
						|
// source code may reveal something, but for now this at least makes us work,
 | 
						|
// even if only by accident.
 | 
						|
static constexpr const char *OrderedStreamNames[] = {"/LinkInfo", "/names",
 | 
						|
                                                     "/src/headerblock"};
 | 
						|
 | 
						|
NamedStreamMap::NamedStreamMap() = default;
 | 
						|
 | 
						|
Error NamedStreamMap::load(BinaryStreamReader &Stream) {
 | 
						|
  Mapping.clear();
 | 
						|
  FinalizedHashTable.clear();
 | 
						|
  FinalizedInfo.reset();
 | 
						|
 | 
						|
  uint32_t StringBufferSize;
 | 
						|
  if (auto EC = Stream.readInteger(StringBufferSize))
 | 
						|
    return joinErrors(std::move(EC),
 | 
						|
                      make_error<RawError>(raw_error_code::corrupt_file,
 | 
						|
                                           "Expected string buffer size"));
 | 
						|
 | 
						|
  BinaryStreamRef StringsBuffer;
 | 
						|
  if (auto EC = Stream.readStreamRef(StringsBuffer, StringBufferSize))
 | 
						|
    return EC;
 | 
						|
 | 
						|
  HashTable OffsetIndexMap;
 | 
						|
  if (auto EC = OffsetIndexMap.load(Stream))
 | 
						|
    return EC;
 | 
						|
 | 
						|
  uint32_t NameOffset;
 | 
						|
  uint32_t NameIndex;
 | 
						|
  for (const auto &Entry : OffsetIndexMap) {
 | 
						|
    std::tie(NameOffset, NameIndex) = Entry;
 | 
						|
 | 
						|
    // Compute the offset of the start of the string relative to the stream.
 | 
						|
    BinaryStreamReader NameReader(StringsBuffer);
 | 
						|
    NameReader.setOffset(NameOffset);
 | 
						|
    // Pump out our c-string from the stream.
 | 
						|
    StringRef Str;
 | 
						|
    if (auto EC = NameReader.readCString(Str))
 | 
						|
      return joinErrors(std::move(EC),
 | 
						|
                        make_error<RawError>(raw_error_code::corrupt_file,
 | 
						|
                                             "Expected name map name"));
 | 
						|
 | 
						|
    // Add this to a string-map from name to stream number.
 | 
						|
    Mapping.insert({Str, NameIndex});
 | 
						|
  }
 | 
						|
 | 
						|
  return Error::success();
 | 
						|
}
 | 
						|
 | 
						|
Error NamedStreamMap::commit(BinaryStreamWriter &Writer) const {
 | 
						|
  assert(FinalizedInfo.hasValue());
 | 
						|
 | 
						|
  // The first field is the number of bytes of string data.
 | 
						|
  if (auto EC = Writer.writeInteger(FinalizedInfo->StringDataBytes))
 | 
						|
    return EC;
 | 
						|
 | 
						|
  for (const auto &Name : OrderedStreamNames) {
 | 
						|
    auto Item = Mapping.find(Name);
 | 
						|
    if (Item == Mapping.end())
 | 
						|
      continue;
 | 
						|
    if (auto EC = Writer.writeCString(Item->getKey()))
 | 
						|
      return EC;
 | 
						|
  }
 | 
						|
 | 
						|
  // And finally the Offset Index map.
 | 
						|
  if (auto EC = FinalizedHashTable.commit(Writer))
 | 
						|
    return EC;
 | 
						|
 | 
						|
  return Error::success();
 | 
						|
}
 | 
						|
 | 
						|
uint32_t NamedStreamMap::finalize() {
 | 
						|
  if (FinalizedInfo.hasValue())
 | 
						|
    return FinalizedInfo->SerializedLength;
 | 
						|
 | 
						|
  // Build the finalized hash table.
 | 
						|
  FinalizedHashTable.clear();
 | 
						|
  FinalizedInfo.emplace();
 | 
						|
 | 
						|
  for (const auto &Name : OrderedStreamNames) {
 | 
						|
    auto Item = Mapping.find(Name);
 | 
						|
    if (Item == Mapping.end())
 | 
						|
      continue;
 | 
						|
    FinalizedHashTable.set(FinalizedInfo->StringDataBytes, Item->getValue());
 | 
						|
    FinalizedInfo->StringDataBytes += Item->getKeyLength() + 1;
 | 
						|
  }
 | 
						|
 | 
						|
  // Number of bytes of string data.
 | 
						|
  FinalizedInfo->SerializedLength += sizeof(support::ulittle32_t);
 | 
						|
  // Followed by that many actual bytes of string data.
 | 
						|
  FinalizedInfo->SerializedLength += FinalizedInfo->StringDataBytes;
 | 
						|
  // Followed by the mapping from Offset to Index.
 | 
						|
  FinalizedInfo->SerializedLength +=
 | 
						|
      FinalizedHashTable.calculateSerializedLength();
 | 
						|
  return FinalizedInfo->SerializedLength;
 | 
						|
}
 | 
						|
 | 
						|
iterator_range<StringMapConstIterator<uint32_t>>
 | 
						|
NamedStreamMap::entries() const {
 | 
						|
  return make_range<StringMapConstIterator<uint32_t>>(Mapping.begin(),
 | 
						|
                                                      Mapping.end());
 | 
						|
}
 | 
						|
 | 
						|
uint32_t NamedStreamMap::size() const { return Mapping.size(); }
 | 
						|
 | 
						|
bool NamedStreamMap::get(StringRef Stream, uint32_t &StreamNo) const {
 | 
						|
  auto Iter = Mapping.find(Stream);
 | 
						|
  if (Iter == Mapping.end())
 | 
						|
    return false;
 | 
						|
  StreamNo = Iter->second;
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
void NamedStreamMap::set(StringRef Stream, uint32_t StreamNo) {
 | 
						|
  FinalizedInfo.reset();
 | 
						|
  Mapping[Stream] = StreamNo;
 | 
						|
}
 | 
						|
 | 
						|
void NamedStreamMap::remove(StringRef Stream) {
 | 
						|
  FinalizedInfo.reset();
 | 
						|
  Mapping.erase(Stream);
 | 
						|
}
 |