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