Coverage Report

Created: 2017-10-03 07:32

/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- NamedStreamMap.cpp - PDB Named Stream Map --------------------------===//
2
//
3
//                     The LLVM Compiler Infrastructure
4
//
5
// This file is distributed under the University of Illinois Open Source
6
// License. See LICENSE.TXT for details.
7
//
8
//===----------------------------------------------------------------------===//
9
10
#include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h"
11
#include "llvm/ADT/StringMap.h"
12
#include "llvm/ADT/StringRef.h"
13
#include "llvm/ADT/iterator_range.h"
14
#include "llvm/DebugInfo/PDB/Native/HashTable.h"
15
#include "llvm/DebugInfo/PDB/Native/RawError.h"
16
#include "llvm/Support/BinaryStreamReader.h"
17
#include "llvm/Support/BinaryStreamRef.h"
18
#include "llvm/Support/BinaryStreamWriter.h"
19
#include "llvm/Support/Endian.h"
20
#include "llvm/Support/Error.h"
21
#include <algorithm>
22
#include <cassert>
23
#include <cstdint>
24
#include <tuple>
25
26
using namespace llvm;
27
using namespace llvm::pdb;
28
29
// FIXME: This shouldn't be necessary, but if we insert the strings in any
30
// other order, cvdump cannot read the generated name map.  This suggests that
31
// we may be using the wrong hash function.  A closer inspection of the cvdump
32
// source code may reveal something, but for now this at least makes us work,
33
// even if only by accident.
34
static constexpr const char *OrderedStreamNames[] = {"/LinkInfo", "/names",
35
                                                     "/src/headerblock"};
36
37
128
NamedStreamMap::NamedStreamMap() = default;
38
39
68
Error NamedStreamMap::load(BinaryStreamReader &Stream) {
40
68
  Mapping.clear();
41
68
  FinalizedHashTable.clear();
42
68
  FinalizedInfo.reset();
43
68
44
68
  uint32_t StringBufferSize;
45
68
  if (auto EC = Stream.readInteger(StringBufferSize))
46
0
    return joinErrors(std::move(EC),
47
0
                      make_error<RawError>(raw_error_code::corrupt_file,
48
0
                                           "Expected string buffer size"));
49
68
50
68
  BinaryStreamRef StringsBuffer;
51
68
  if (auto EC = Stream.readStreamRef(StringsBuffer, StringBufferSize))
52
0
    return EC;
53
68
54
68
  HashTable OffsetIndexMap;
55
68
  if (auto EC = OffsetIndexMap.load(Stream))
56
0
    return EC;
57
68
58
68
  uint32_t NameOffset;
59
68
  uint32_t NameIndex;
60
165
  for (const auto &Entry : OffsetIndexMap) {
61
165
    std::tie(NameOffset, NameIndex) = Entry;
62
165
63
165
    // Compute the offset of the start of the string relative to the stream.
64
165
    BinaryStreamReader NameReader(StringsBuffer);
65
165
    NameReader.setOffset(NameOffset);
66
165
    // Pump out our c-string from the stream.
67
165
    StringRef Str;
68
165
    if (auto EC = NameReader.readCString(Str))
69
0
      return joinErrors(std::move(EC),
70
0
                        make_error<RawError>(raw_error_code::corrupt_file,
71
0
                                             "Expected name map name"));
72
165
73
165
    // Add this to a string-map from name to stream number.
74
165
    Mapping.insert({Str, NameIndex});
75
165
  }
76
68
77
68
  return Error::success();
78
68
}
79
80
60
Error NamedStreamMap::commit(BinaryStreamWriter &Writer) const {
81
60
  assert(FinalizedInfo.hasValue());
82
60
83
60
  // The first field is the number of bytes of string data.
84
60
  if (auto EC = Writer.writeInteger(FinalizedInfo->StringDataBytes))
85
0
    return EC;
86
60
87
60
  
for (const auto &Name : OrderedStreamNames) 60
{
88
180
    auto Item = Mapping.find(Name);
89
180
    if (Item == Mapping.end())
90
60
      continue;
91
120
    
if (auto 120
EC120
= Writer.writeCString(Item->getKey()))
92
0
      return EC;
93
60
  }
94
60
95
60
  // And finally the Offset Index map.
96
60
  
if (auto 60
EC60
= FinalizedHashTable.commit(Writer))
97
0
    return EC;
98
60
99
60
  return Error::success();
100
60
}
101
102
60
uint32_t NamedStreamMap::finalize() {
103
60
  if (FinalizedInfo.hasValue())
104
0
    return FinalizedInfo->SerializedLength;
105
60
106
60
  // Build the finalized hash table.
107
60
  FinalizedHashTable.clear();
108
60
  FinalizedInfo.emplace();
109
60
110
180
  for (const auto &Name : OrderedStreamNames) {
111
180
    auto Item = Mapping.find(Name);
112
180
    if (Item == Mapping.end())
113
60
      continue;
114
120
    FinalizedHashTable.set(FinalizedInfo->StringDataBytes, Item->getValue());
115
120
    FinalizedInfo->StringDataBytes += Item->getKeyLength() + 1;
116
120
  }
117
60
118
60
  // Number of bytes of string data.
119
60
  FinalizedInfo->SerializedLength += sizeof(support::ulittle32_t);
120
60
  // Followed by that many actual bytes of string data.
121
60
  FinalizedInfo->SerializedLength += FinalizedInfo->StringDataBytes;
122
60
  // Followed by the mapping from Offset to Index.
123
60
  FinalizedInfo->SerializedLength +=
124
60
      FinalizedHashTable.calculateSerializedLength();
125
60
  return FinalizedInfo->SerializedLength;
126
60
}
127
128
iterator_range<StringMapConstIterator<uint32_t>>
129
11
NamedStreamMap::entries() const {
130
11
  return make_range<StringMapConstIterator<uint32_t>>(Mapping.begin(),
131
11
                                                      Mapping.end());
132
11
}
133
134
0
uint32_t NamedStreamMap::size() const { return Mapping.size(); }
135
136
97
bool NamedStreamMap::get(StringRef Stream, uint32_t &StreamNo) const {
137
97
  auto Iter = Mapping.find(Stream);
138
97
  if (Iter == Mapping.end())
139
0
    return false;
140
97
  StreamNo = Iter->second;
141
97
  return true;
142
97
}
143
144
120
void NamedStreamMap::set(StringRef Stream, uint32_t StreamNo) {
145
120
  FinalizedInfo.reset();
146
120
  Mapping[Stream] = StreamNo;
147
120
}
148
149
0
void NamedStreamMap::remove(StringRef Stream) {
150
0
  FinalizedInfo.reset();
151
0
  Mapping.erase(Stream);
152
0
}