1 : // Copyright 2012 Google Inc.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 : #include "syzygy/pdb/pdb_util.h"
15 :
16 : #include <algorithm>
17 : #include <string>
18 :
19 : #include "base/stringprintf.h"
20 : #include "sawbuck/common/buffer_parser.h"
21 : #include "syzygy/pdb/pdb_byte_stream.h"
22 : #include "syzygy/pdb/pdb_reader.h"
23 : #include "syzygy/pdb/pdb_writer.h"
24 :
25 : namespace pdb {
26 :
27 : namespace {
28 :
29 : // Sets the stream associated with a given entry in the DBI DBG header.
30 : // Gets the index at position @p index_offset of the DBI DBG header. If invalid,
31 : // adds a new stream to the PDB and updates the index to point to it. If a valid
32 : // stream already exists, replaces it with the new @p stream.
33 : // @param index_offset the offset of the int16 stream index within the DBI DBG
34 : // header.
35 : // @param stream the stream to be associated with the given DBI DBG entry.
36 : // @param pdb_file the PDB file to be updated.
37 : bool SetDbiDbgStream(size_t index_offset,
38 : PdbStream* stream,
39 E : PdbFile* pdb_file) {
40 E : DCHECK(pdb_file != NULL);
41 :
42 E : if (!EnsureStreamWritable(kDbiStream, pdb_file)) {
43 i : LOG(ERROR) << "Failed to make DBI stream writable.";
44 i : return false;
45 : }
46 :
47 E : scoped_refptr<PdbStream> dbi_reader(pdb_file->GetStream(kDbiStream));
48 : scoped_refptr<WritablePdbStream> dbi_writer(
49 E : dbi_reader->GetWritablePdbStream());
50 E : DCHECK(dbi_writer.get() != NULL);
51 :
52 : // Read the DBI header.
53 E : DbiHeader dbi_header = {};
54 E : if (!dbi_reader->Seek(0) || !dbi_reader->Read(&dbi_header, 1)) {
55 i : LOG(ERROR) << "Failed to read DBI header.";
56 i : return false;
57 : }
58 :
59 : // Get the stream index at the provided offset.
60 E : uint32 dbi_dbg_offset = GetDbiDbgHeaderOffset(dbi_header);
61 E : int16 existing_index = -1;
62 : if (!dbi_reader->Seek(dbi_dbg_offset + index_offset) ||
63 E : !dbi_reader->Read(&existing_index, 1)) {
64 i : LOG(ERROR) << "Failed to read stream index at offset " << dbi_dbg_offset
65 : << " of DBI DBG header.";
66 i : return false;
67 : }
68 :
69 : // If the stream is an invalid index, we create a new one.
70 E : int16 new_index = existing_index;
71 : if (existing_index < 0 ||
72 E : existing_index >= static_cast<int16>(pdb_file->StreamCount())) {
73 E : new_index = static_cast<int16>(pdb_file->AppendStream(stream));
74 E : } else {
75 i : pdb_file->ReplaceStream(new_index, stream);
76 : }
77 :
78 : // Update the index in the header if we need to.
79 E : if (new_index != existing_index) {
80 E : dbi_writer->set_pos(dbi_dbg_offset + index_offset);
81 E : if (!dbi_writer->Write(new_index)) {
82 i : LOG(ERROR) << "Failed to write stream index at offset " << dbi_dbg_offset
83 : << " of DBI DBG header.";
84 i : return false;
85 : }
86 : }
87 :
88 E : return true;
89 E : }
90 :
91 : bool SetOmapStream(size_t dbi_dbg_index_offset,
92 : const std::vector<OMAP>& omap_list,
93 E : PdbFile* pdb_file) {
94 E : DCHECK(pdb_file != NULL);
95 :
96 E : scoped_refptr<PdbByteStream> stream = new PdbByteStream();
97 E : if (!omap_list.empty()) {
98 : if (!stream->Init(reinterpret_cast<const uint8*>(&omap_list.at(0)),
99 E : omap_list.size() * sizeof(OMAP))) {
100 i : LOG(ERROR) << "Failed to initialize OMAP stream.";
101 i : return false;
102 : }
103 : }
104 :
105 E : return SetDbiDbgStream(dbi_dbg_index_offset, stream.get(), pdb_file);
106 E : }
107 :
108 : // Calculates the size of the hash table required to represent a named stream
109 : // hash containing the given number of entries. This has been determined from
110 : // inspection of the output produced by pdbstr.exe.
111 E : size_t GetNamedStreamsHashTableSize(size_t entries) {
112 : // This produces the sequence of sizes: 6, 10, 14, 20, 28, 38, 52, etc.
113 E : size_t size = 3;
114 E : while (true) {
115 E : size_t threshold = 2 * size / 3;
116 E : if (entries <= threshold)
117 E : return size;
118 E : size = 2 * (threshold + 1);
119 E : }
120 E : }
121 :
122 : // Calculates the hash value associated with a stream name, as used by the
123 : // named streams hash table. This is required for interoperability with
124 : // dbghelp and srcsrv tools.
125 E : uint16 NamedStreamsHash(const base::StringPiece& name) {
126 E : size_t length = name.size();
127 E : const char* data = name.data();
128 :
129 E : uint32 hash = 0;
130 E : while (length >= 4) {
131 E : hash ^= *reinterpret_cast<const uint32*>(data);
132 E : data += 4;
133 E : length -= 4;
134 E : }
135 :
136 E : if (length >= 2) {
137 E : hash ^= *reinterpret_cast<const uint16*>(data);
138 E : data += 2;
139 E : length -= 2;
140 : }
141 :
142 E : if (length >= 1)
143 E : hash ^= *data;
144 :
145 E : hash |= 0x20202020;
146 E : hash ^= hash >> 11;
147 E : hash ^= hash >> 16;
148 :
149 E : return hash & 0xFFFF;
150 E : }
151 :
152 : // Sets the bit at the given index, with collision semantics. Returns the index
153 : // of the bit that was set. Note that there must be at least one bit that is not
154 : // already set, otherwise this will loop forever.
155 : size_t SetNamedStreamsHashTableBit(
156 E : size_t index, size_t max, PdbBitSet* bitset) {
157 E : DCHECK(bitset != NULL);
158 :
159 E : while (bitset->IsSet(index)) {
160 E : ++index;
161 E : if (index > max)
162 i : index = 0;
163 E : }
164 :
165 E : bitset->Set(index);
166 E : return index;
167 E : }
168 :
169 : // A small struct that is used for storing information regarding the name-stream
170 : // map, and the associated hash table. The (string table offset, stream id)
171 : // pairs need to be output in order of the hash value, which is the default sort
172 : // order of this object.
173 : struct NamedStreamInfo {
174 E : NamedStreamInfo(NameStreamMap::const_iterator it,
175 : uint32 offset,
176 : uint32 bucket)
177 : : it(it), offset(offset), bucket(bucket) {
178 E : }
179 :
180 E : bool operator<(const NamedStreamInfo& rhs) const {
181 E : return bucket < rhs.bucket;
182 E : }
183 :
184 : // An iterator into the (name, stream_id) map.
185 : NameStreamMap::const_iterator it;
186 : // The offset of the name in the string table.
187 : uint32 offset;
188 : // The bucket that this name occupies in the hash map, after collision
189 : // resolution. This is the sort key.
190 : uint32 bucket;
191 : };
192 :
193 : } // namespace
194 :
195 E : bool PdbBitSet::Read(PdbStream* stream) {
196 E : DCHECK(stream != NULL);
197 E : uint32 size = 0;
198 E : if (!stream->Read(&size, 1)) {
199 E : LOG(ERROR) << "Failed to read bitset size.";
200 E : return false;
201 : }
202 E : if (!stream->Read(&bits_, size)) {
203 i : LOG(ERROR) << "Failed to read bitset bits.";
204 i : return false;
205 : }
206 :
207 E : return true;
208 E : }
209 :
210 E : bool PdbBitSet::Write(WritablePdbStream* stream) {
211 E : DCHECK(stream != NULL);
212 E : if (!stream->Write(static_cast<uint32>(bits_.size()))) {
213 i : LOG(ERROR) << "Failed to write bitset size.";
214 i : return false;
215 : }
216 E : if (bits_.size() == 0)
217 E : return true;
218 E : if (!stream->Write(bits_.size(), &bits_[0])) {
219 i : LOG(ERROR) << "Failed to write bitset bits.";
220 i : return false;
221 : }
222 :
223 E : return true;
224 E : }
225 :
226 E : void PdbBitSet::Resize(size_t bits) {
227 E : bits_.resize((bits + 31) / 32);
228 E : }
229 :
230 E : void PdbBitSet::Set(size_t bit) {
231 E : size_t index = bit / 32;
232 E : if (index >= bits_.size())
233 i : return;
234 E : bits_[index] |= (1 << (bit % 32));
235 E : }
236 :
237 E : void PdbBitSet::Clear(size_t bit) {
238 E : size_t index = bit / 32;
239 E : if (index >= bits_.size())
240 i : return;
241 E : bits_[index] &= ~(1 << (bit % 32));
242 E : }
243 :
244 E : void PdbBitSet::Toggle(size_t bit) {
245 E : size_t index = bit / 32;
246 E : if (index >= bits_.size())
247 i : return;
248 E : bits_[index] ^= (1 << (bit % 32));
249 E : }
250 :
251 E : bool PdbBitSet::IsSet(size_t bit) const {
252 E : size_t index = bit / 32;
253 E : if (index >= bits_.size())
254 i : return false;
255 :
256 E : return (bits_[index] & (1 << (bit % 32))) != 0;
257 E : }
258 :
259 E : bool PdbBitSet::IsEmpty() const {
260 E : return bits_.size() == 0;
261 E : }
262 :
263 E : bool ReadString(PdbStream* stream, std::string* out) {
264 E : DCHECK(out != NULL);
265 :
266 E : std::string result;
267 E : char c = 0;
268 E : while (stream->Read(&c, 1)) {
269 E : if (c == '\0') {
270 E : out->swap(result);
271 E : return true;
272 : }
273 E : result.push_back(c);
274 E : }
275 :
276 i : return false;
277 E : }
278 :
279 E : bool ReadStringAt(PdbStream* stream, size_t pos, std::string* out) {
280 E : size_t save = stream->pos();
281 E : bool read = stream->Seek(pos) && ReadString(stream, out);
282 E : stream->Seek(save);
283 E : return read;
284 E : }
285 :
286 E : uint32 GetDbiDbgHeaderOffset(const DbiHeader& dbi_header) {
287 E : uint32 offset = sizeof(DbiHeader);
288 E : offset += dbi_header.gp_modi_size;
289 E : offset += dbi_header.section_contribution_size;
290 E : offset += dbi_header.section_map_size;
291 E : offset += dbi_header.file_info_size;
292 E : offset += dbi_header.ts_map_size;
293 E : offset += dbi_header.ec_info_size; // Unexpected, but necessary.
294 E : return offset;
295 E : }
296 :
297 E : bool EnsureStreamWritable(uint32 index, PdbFile* pdb_file) {
298 E : DCHECK(pdb_file != NULL);
299 :
300 : // Bail if the index is to a non-existent stream.
301 E : if (index >= pdb_file->StreamCount()) {
302 E : LOG(ERROR) << "Invalid PDB stream index.";
303 E : return false;
304 : }
305 :
306 : // Get the reader. If it doesn't actually exist, create a new one.
307 E : scoped_refptr<PdbStream> reader(pdb_file->GetStream(index));
308 E : if (reader.get() == NULL)
309 E : reader = new PdbByteStream();
310 :
311 : // Try and get a writer.
312 E : scoped_refptr<WritablePdbStream> writer(reader->GetWritablePdbStream());
313 E : if (writer.get() == NULL) {
314 : // If not possible, copy the existing reader to a PdbByteStream which will
315 : // be able to give us a writer.
316 E : scoped_refptr<PdbByteStream> new_stream = new PdbByteStream();
317 E : if (!new_stream->Init(reader.get())) {
318 i : LOG(ERROR) << "Failed to initialize writable stream.";
319 i : return false;
320 : }
321 E : reader = new_stream.get();
322 E : }
323 :
324 E : DCHECK(reader->GetWritablePdbStream() != NULL);
325 :
326 : // Be sure to replace the stream at this index with the new one. This is a
327 : // no-op if the stream hasn't changed.
328 E : pdb_file->ReplaceStream(index, reader.get());
329 :
330 E : return true;
331 E : }
332 :
333 : bool SetOmapToStream(const std::vector<OMAP>& omap_to_list,
334 E : PdbFile* pdb_file) {
335 E : DCHECK(pdb_file != NULL);
336 : return SetOmapStream(offsetof(DbiDbgHeader, omap_to_src),
337 : omap_to_list,
338 E : pdb_file);
339 E : }
340 :
341 : bool SetOmapFromStream(const std::vector<OMAP>& omap_from_list,
342 E : PdbFile* pdb_file) {
343 E : DCHECK(pdb_file != NULL);
344 : return SetOmapStream(offsetof(DbiDbgHeader, omap_from_src),
345 : omap_from_list,
346 E : pdb_file);
347 E : }
348 :
349 E : bool SetGuid(const GUID& guid, PdbFile* pdb_file) {
350 E : DCHECK(pdb_file != NULL);
351 :
352 : // Make sure the Pdb header and the Dbi streams are writable.
353 E : if (!EnsureStreamWritable(kPdbHeaderInfoStream, pdb_file)) {
354 i : LOG(ERROR) << "Failed to make PDB Header Info stream writable.";
355 i : return false;
356 : }
357 E : if (!EnsureStreamWritable(kDbiStream, pdb_file)) {
358 i : LOG(ERROR) << "Failed to make DBI Info stream writable.";
359 i : return false;
360 : }
361 :
362 : // Get the reader and writer for the header info stream.
363 E : scoped_refptr<PdbStream> reader(pdb_file->GetStream(kPdbHeaderInfoStream));
364 E : scoped_refptr<WritablePdbStream> writer(reader->GetWritablePdbStream());
365 E : DCHECK(writer.get() != NULL);
366 :
367 : // Read the header.
368 E : PdbInfoHeader70 info_header = {};
369 E : if (!reader->Seek(0) || !reader->Read(&info_header, 1)) {
370 E : LOG(ERROR) << "Failed to read PdbInfoHeader70.";
371 E : return false;
372 : }
373 :
374 : // Update it.
375 E : info_header.timestamp = static_cast<uint32>(time(NULL));
376 E : info_header.pdb_age = 1; // Reset age to 1, as this is a new generation.
377 E : info_header.signature = guid;
378 :
379 : // And write it back.
380 E : writer->set_pos(0);
381 E : if (!writer->Write(info_header)) {
382 i : LOG(ERROR) << "Failed to write PdbInfoHeader70.";
383 i : return false;
384 : }
385 :
386 : // Now update the age in the DBI stream to match the age we set above.
387 E : reader = pdb_file->GetStream(kDbiStream);
388 E : if (reader.get() == NULL) {
389 i : LOG(ERROR) << "No DBI stream in PDB.";
390 i : return false;
391 : }
392 E : writer = reader->GetWritablePdbStream();
393 :
394 E : DCHECK(writer.get() != NULL);
395 :
396 : // Read the header.
397 E : DbiHeader dbi_header = {};
398 E : if (!reader->Seek(0) || !reader->Read(&dbi_header, 1)) {
399 E : LOG(ERROR) << "Failed to read DbiHeader.";
400 E : return false;
401 : }
402 :
403 E : dbi_header.age = 1;
404 E : writer->set_pos(0);
405 E : if (!writer->Write(dbi_header)) {
406 i : LOG(ERROR) << "Failed to write DbiHeader";
407 i : return false;
408 : }
409 :
410 E : return true;
411 E : }
412 :
413 E : bool ReadPdbHeader(const FilePath& pdb_path, PdbInfoHeader70* pdb_header) {
414 E : DCHECK(!pdb_path.empty());
415 E : DCHECK(pdb_header != NULL);
416 :
417 E : PdbReader pdb_reader;
418 E : PdbFile pdb_file;
419 E : if (!pdb_reader.Read(pdb_path, &pdb_file)) {
420 i : LOG(ERROR) << "Unable to process PDB file: " << pdb_path.value();
421 i : return false;
422 : }
423 :
424 E : PdbStream* header_stream = pdb_file.GetStream(kPdbHeaderInfoStream);
425 E : if (header_stream == NULL) {
426 i : LOG(ERROR) << "PDB file contains no header stream: " << pdb_path.value();
427 i : return false;
428 : }
429 :
430 E : if (!header_stream->Read(pdb_header, 1)) {
431 i : LOG(ERROR) << "Failure reading PDB header: " << pdb_path.value();
432 i : return false;
433 : }
434 :
435 : // We only know how to deal with PDB files of the current version.
436 E : if (pdb_header->version != kPdbCurrentVersion) {
437 i : LOG(ERROR) << "PDB header has unsupported version (got "
438 : << pdb_header->version << ", expected " << kPdbCurrentVersion
439 : << ").";
440 i : return false;
441 : }
442 :
443 E : return true;
444 E : }
445 :
446 : bool ReadHeaderInfoStream(const PdbFile& pdb_file,
447 : PdbInfoHeader70* pdb_header,
448 E : NameStreamMap* name_stream_map) {
449 E : DCHECK(pdb_header != NULL);
450 E : DCHECK(name_stream_map != NULL);
451 :
452 : // Get the stream reader.
453 E : if (kPdbHeaderInfoStream >= pdb_file.StreamCount()) {
454 E : LOG(ERROR) << "No header info stream found.";
455 E : return false;
456 : }
457 : scoped_refptr<PdbStream> header_reader(
458 E : pdb_file.GetStream(kPdbHeaderInfoStream));
459 E : if (header_reader.get() == NULL) {
460 i : LOG(ERROR) << "No header info stream found.";
461 i : return false;
462 : }
463 :
464 : // Read the header.
465 : if (!pdb::ReadHeaderInfoStream(header_reader.get(), pdb_header,
466 E : name_stream_map)) {
467 i : LOG(ERROR) << "Failed to read header info stream.";
468 i : return false;
469 : }
470 :
471 E : return true;
472 E : }
473 :
474 : bool ReadHeaderInfoStream(PdbStream* pdb_stream,
475 : PdbInfoHeader70* pdb_header,
476 E : NameStreamMap* name_stream_map) {
477 E : VLOG(1) << "Header Info Stream size: " << pdb_stream->length();
478 :
479 E : if (!pdb_stream->Seek(0)) {
480 i : LOG(ERROR) << "Unable to seek to start of PDB header info stream.";
481 i : return false;
482 : }
483 :
484 : // The header stream starts with the fixed-size header pdb_header record.
485 E : if (!pdb_stream->Read(pdb_header, 1)) {
486 E : LOG(ERROR) << "Unable to read PDB pdb_header header.";
487 E : return false;
488 : }
489 :
490 E : uint32 string_len = 0;
491 E : if (!pdb_stream->Read(&string_len, 1)) {
492 E : LOG(ERROR) << "Unable to read string table length.";
493 E : return false;
494 : }
495 :
496 : // The fixed-size record is followed by information on named streams, which
497 : // is essentially a string->id mapping. This starts with the strings
498 : // themselves, which have been observed to be a packed run of zero-terminated
499 : // strings.
500 : // We store the start of the string list, as the string positions we read
501 : // later are relative to that position.
502 E : size_t string_start = pdb_stream->pos();
503 :
504 : // Seek past the strings.
505 E : if (!pdb_stream->Seek(string_start + string_len)) {
506 i : LOG(ERROR) << "Unable to seek past string list";
507 i : return false;
508 : }
509 :
510 : // Next there's a pair of integers. The first one of those is the number of
511 : // items in the string->id mapping. The purpose of the second one is not
512 : // clear, but has been observed as larger or equal to the first one.
513 E : uint32 size = 0;
514 E : uint32 max = 0;
515 E : if (!pdb_stream->Read(&size, 1) || !pdb_stream->Read(&max, 1)) {
516 i : LOG(ERROR) << "Unable to read name pdb_stream size/max";
517 i : return false;
518 : }
519 E : DCHECK(max >= size);
520 :
521 : // After the counts, there's a pair of bitsets. Each bitset has a 32 bit
522 : // length, followed by that number of 32 bit words that contain the bits.
523 : // The purpose of those is again not clear, though the first set will have
524 : // "size" bits of the bits in the range 0-max set.
525 E : PdbBitSet used;
526 E : PdbBitSet deleted;
527 E : if (!used.Read(pdb_stream) || !deleted.Read(pdb_stream)) {
528 i : LOG(ERROR) << "Unable to read name pdb_stream bitsets.";
529 i : return false;
530 : }
531 :
532 : #ifndef NDEBUG
533 : // The first bitset has "size" bits set of the first "max" bits.
534 E : size_t set_bits = 0;
535 E : for (size_t i = 0; i < max; ++i) {
536 E : if (used.IsSet(i))
537 E : ++set_bits;
538 E : }
539 :
540 : // The second bitset has always been observed to be empty.
541 E : DCHECK(deleted.IsEmpty());
542 :
543 E : DCHECK_EQ(size, set_bits);
544 : #endif
545 :
546 : // Read the mapping proper, this is simply a run of {string offset, id} pairs.
547 E : for (size_t i = 0; i < size; ++i) {
548 E : uint32 str_offs = 0;
549 E : uint32 stream_no = 0;
550 : // Read the offset and pdb_stream number.
551 E : if (!pdb_stream->Read(&str_offs, 1) || !pdb_stream->Read(&stream_no, 1)) {
552 i : LOG(ERROR) << "Unable to read pdb_stream data.";
553 i : return false;
554 : }
555 :
556 : // Read the string itself from the table.
557 E : std::string name;
558 E : if (!ReadStringAt(pdb_stream, string_start + str_offs, &name)) {
559 i : LOG(ERROR) << "Failed to read pdb_stream name.";
560 i : return false;
561 : }
562 :
563 E : (*name_stream_map)[name] = stream_no;
564 E : }
565 :
566 E : return true;
567 E : }
568 :
569 : bool WriteHeaderInfoStream(const PdbInfoHeader70& header,
570 : const NameStreamMap& name_stream_map,
571 E : PdbFile* pdb_file) {
572 E : DCHECK(pdb_file != NULL);
573 :
574 E : if (!pdb::EnsureStreamWritable(pdb::kPdbHeaderInfoStream, pdb_file)) {
575 i : LOG(ERROR) << "Failed to make PDB Header Info stream writable.";
576 i : return false;
577 : }
578 :
579 : // Get the stream reader.
580 : scoped_refptr<PdbStream> header_reader(
581 E : pdb_file->GetStream(pdb::kPdbHeaderInfoStream));
582 E : DCHECK(header_reader.get() != NULL);
583 :
584 : // Get the stream writer.
585 : scoped_refptr<WritablePdbStream> header_writer(
586 E : header_reader->GetWritablePdbStream());
587 E : DCHECK(header_writer.get() != NULL);
588 :
589 : // Write the new header.
590 E : if (!WriteHeaderInfoStream(header, name_stream_map, header_writer.get())) {
591 i : LOG(ERROR) << "Failed to write PDB Header Info stream.";
592 i : return false;
593 : }
594 :
595 E : return true;
596 E : }
597 :
598 : bool WriteHeaderInfoStream(const PdbInfoHeader70& pdb_header,
599 : const NameStreamMap& name_stream_map,
600 E : WritablePdbStream* pdb_stream) {
601 E : DCHECK(pdb_stream != NULL);
602 :
603 E : if (!pdb_stream->Write(pdb_header)) {
604 i : LOG(ERROR) << "Failed to write PDB header.";
605 i : return false;
606 : }
607 :
608 : // Calculate the hash table entry count and size.
609 E : uint32 string_count = name_stream_map.size();
610 E : uint32 table_size = GetNamedStreamsHashTableSize(string_count);
611 :
612 : // Initialize the 'used' bitset.
613 E : PdbBitSet used;
614 E : used.Resize(table_size);
615 :
616 : // Get the string table length. We also calculate hashes for each name,
617 : // populating the 'used' bitset and determining the order in which to output
618 : // the stream names.
619 E : std::vector<NamedStreamInfo> name_infos;
620 E : name_infos.reserve(string_count);
621 E : uint32 string_length = 0;
622 E : NameStreamMap::const_iterator name_it = name_stream_map.begin();
623 E : for (; name_it != name_stream_map.end(); ++name_it) {
624 E : uint16 hash = NamedStreamsHash(name_it->first);
625 E : size_t bucket = hash % table_size;
626 E : bucket = SetNamedStreamsHashTableBit(bucket, table_size, &used);
627 E : name_infos.push_back(NamedStreamInfo(name_it, 0, bucket));
628 E : string_length += name_it->first.size() + 1; // Include the trailing zero.
629 E : }
630 :
631 : // Sort the strings in the order in which they will be output.
632 E : std::sort(name_infos.begin(), name_infos.end());
633 :
634 : // Dump the string table.
635 E : if (!pdb_stream->Write(string_length)) {
636 i : LOG(ERROR) << "Failed to write stream name table length.";
637 i : return false;
638 : }
639 E : string_length = 0;
640 E : for (size_t i = 0; i < name_infos.size(); ++i) {
641 E : name_infos[i].offset = string_length;
642 E : name_it = name_infos[i].it;
643 E : string_length += name_it->first.size() + 1;
644 E : if (!pdb_stream->Write(name_it->first.size() + 1, name_it->first.c_str())) {
645 i : LOG(ERROR) << "Failed to write stream name.";
646 i : return false;
647 : }
648 E : }
649 :
650 : // Write the string hash table size.
651 E : if (!pdb_stream->Write(string_count) || !pdb_stream->Write(table_size)) {
652 i : LOG(ERROR) << "Failed to write string table size.";
653 i : return false;
654 : }
655 :
656 : // Write the 'used' bitset.
657 E : if (!used.Write(pdb_stream)) {
658 i : LOG(ERROR) << "Failed to write 'used' bitset.";
659 i : return false;
660 : }
661 :
662 : // The 'deleted' bitset is always empty.
663 E : PdbBitSet deleted;
664 E : DCHECK(deleted.IsEmpty());
665 E : if (!deleted.Write(pdb_stream)) {
666 i : LOG(ERROR) << "Failed to write 'deleted' bitset.";
667 i : return false;
668 : }
669 :
670 : // Now output the actual mapping, a run of (string table offset, stream id)
671 : // pairs. We output these in order of hash table buckets of each name,
672 : // mimicking the output produced by pdbstr.exe.
673 E : for (size_t i = 0; i < name_infos.size(); ++i) {
674 : if (!pdb_stream->Write(name_infos[i].offset) ||
675 E : !pdb_stream->Write(name_infos[i].it->second)) {
676 i : LOG(ERROR) << "Failed to write stream name mapping.";
677 i : return false;
678 : }
679 E : }
680 :
681 : // The run of pairs must be terminated with a single NULL entry.
682 E : if (!pdb_stream->Write(static_cast<uint32>(0))) {
683 i : LOG(ERROR) << "Failed to write terminating NULL.";
684 i : return false;
685 : }
686 :
687 E : return true;
688 E : }
689 :
690 : bool ReadStringTable(PdbStream* stream,
691 : const char* table_name,
692 : size_t table_start,
693 : size_t table_end,
694 E : OffsetStringMap* string_map) {
695 E : DCHECK(stream != NULL);
696 E : DCHECK(table_name != NULL);
697 E : DCHECK(string_map != NULL);
698 :
699 E : uint32 string_table_signature = 0;
700 E : uint32 string_table_version = 0;
701 :
702 : if (!stream->Seek(table_start) ||
703 : !stream->Read(&string_table_signature, 1) ||
704 E : !stream->Read(&string_table_version, 1)) {
705 i : LOG(ERROR) << "Unable to seek to " << table_name << " stream.";
706 i : return false;
707 : }
708 :
709 : if (string_table_signature != kPdbNameTableSignature ||
710 E : string_table_version != kPdbNameTableVersion) {
711 i : LOG(ERROR) << "Unexpected " << table_name << " header. Expected "
712 : << "signature/version "
713 : << StringPrintf("0x%08X", kPdbNameTableSignature) << "/"
714 : << kPdbNameTableVersion << ", read "
715 : << StringPrintf("0x%08X", string_table_signature) << "/"
716 : << string_table_version << ".";
717 i : return false;
718 : }
719 :
720 E : size_t string_table_size = 0;
721 E : if (!stream->Read(&string_table_size, 1)) {
722 i : LOG(ERROR) << "Unable to read the size of the " << table_name << " string "
723 : << "table.";
724 i : return false;
725 : }
726 :
727 E : size_t string_table_start = stream->pos();
728 E : size_t offset_table_start = stream->pos() + string_table_size;
729 :
730 : // Skip the string table and seek to the offset table.
731 E : if (!stream->Seek(offset_table_start)) {
732 i : LOG(ERROR) << "Unable to seek to the " << table_name << " offset table.";
733 i : return false;
734 : }
735 :
736 E : size_t entries_count = 0;
737 E : if (!stream->Read(&entries_count, 1)) {
738 i : LOG(ERROR) << "Unable to read the number of entries in the " << table_name
739 : << " offset table.";
740 i : return false;
741 : }
742 :
743 : // Some of the offsets present in the offset table have the value 0, which
744 : // refers to an empty string present at the beginning of the string table.
745 E : for (size_t i = 0; i < entries_count; ++i) {
746 E : size_t string_offset = 0;
747 E : std::string temp_string;
748 : if (!stream->Read(&string_offset, 1) ||
749 : !ReadStringAt(stream, string_table_start + string_offset,
750 E : &temp_string)) {
751 i : LOG(ERROR) << "Unable to read the " << table_name << " name table.";
752 i : return false;
753 : }
754 :
755 E : string_map->insert(std::make_pair(string_offset, temp_string));
756 E : }
757 :
758 E : uint32 string_count = 0;
759 : // Sometimes the string_count field matches the number of non-empty strings
760 : // in the string_map and sometimes it doesn't.
761 : // TODO(sebmarchand) : understand what's this value once the compiland streams
762 : // are deciphered.
763 E : if (!stream->Read(&string_count, 1)) {
764 i : LOG(ERROR) << "Unable to read the number of files present in the "
765 : << table_name << " stream.";
766 i : return false;
767 : }
768 :
769 E : if (stream->pos() != table_end) {
770 i : LOG(ERROR) << table_name << " stream is not valid.";
771 i : return false;
772 : }
773 :
774 E : return true;
775 E : }
776 :
777 : } // namespace pdb
|