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