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_reader.h"
22 : #include "syzygy/pdb/pdb_writer.h"
23 :
24 : namespace pdb {
25 :
26 : namespace {
27 :
28 : // Sets the stream associated with a given entry in the DBI DBG header.
29 : // Gets the index at position @p index_offset of the DBI DBG header. If invalid,
30 : // adds a new stream to the PDB and updates the index to point to it. If a valid
31 : // stream already exists, replaces it with the new @p stream.
32 : // @param index_offset the offset of the int16 stream index within the DBI DBG
33 : // header.
34 : // @param stream the stream to be associated with the given DBI DBG entry.
35 : // @param pdb_file the PDB file to be updated.
36 : bool SetDbiDbgStream(size_t index_offset,
37 : PdbStream* stream,
38 E : PdbFile* pdb_file) {
39 E : DCHECK(pdb_file != NULL);
40 :
41 E : if (!EnsureStreamWritable(kDbiStream, pdb_file)) {
42 i : LOG(ERROR) << "Failed to make DBI stream writable.";
43 i : return false;
44 : }
45 :
46 E : scoped_refptr<PdbStream> dbi_reader(pdb_file->GetStream(kDbiStream));
47 : scoped_refptr<WritablePdbStream> dbi_writer(
48 E : dbi_reader->GetWritablePdbStream());
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(out != NULL);
261 :
262 E : std::string result;
263 E : char c = 0;
264 E : while (stream->Read(&c, 1)) {
265 E : if (c == '\0') {
266 E : out->swap(result);
267 E : return true;
268 : }
269 E : result.push_back(c);
270 E : }
271 :
272 i : return false;
273 E : }
274 :
275 E : bool ReadStringAt(PdbStream* stream, size_t pos, std::string* out) {
276 E : size_t save = stream->pos();
277 E : bool read = stream->Seek(pos) && ReadString(stream, out);
278 E : stream->Seek(save);
279 E : return read;
280 E : }
281 :
282 E : uint32 GetDbiDbgHeaderOffset(const DbiHeader& dbi_header) {
283 E : uint32 offset = sizeof(DbiHeader);
284 E : offset += dbi_header.gp_modi_size;
285 E : offset += dbi_header.section_contribution_size;
286 E : offset += dbi_header.section_map_size;
287 E : offset += dbi_header.file_info_size;
288 E : offset += dbi_header.ts_map_size;
289 E : offset += dbi_header.ec_info_size; // Unexpected, but necessary.
290 E : return offset;
291 E : }
292 :
293 E : bool EnsureStreamWritable(uint32 index, PdbFile* pdb_file) {
294 E : DCHECK(pdb_file != NULL);
295 :
296 : // Bail if the index is to a non-existent stream.
297 E : if (index >= pdb_file->StreamCount()) {
298 E : LOG(ERROR) << "Invalid PDB stream index.";
299 E : return false;
300 : }
301 :
302 : // Get the reader. If it doesn't actually exist, create a new one.
303 E : scoped_refptr<PdbStream> reader(pdb_file->GetStream(index));
304 E : if (reader.get() == NULL)
305 E : reader = new PdbByteStream();
306 :
307 : // Try and get a writer.
308 E : scoped_refptr<WritablePdbStream> writer(reader->GetWritablePdbStream());
309 E : if (writer.get() == NULL) {
310 : // If not possible, copy the existing reader to a PdbByteStream which will
311 : // be able to give us a writer.
312 E : scoped_refptr<PdbByteStream> new_stream = new PdbByteStream();
313 E : if (!new_stream->Init(reader.get())) {
314 i : LOG(ERROR) << "Failed to initialize writable stream.";
315 i : return false;
316 : }
317 E : reader = new_stream.get();
318 E : }
319 :
320 E : DCHECK(reader->GetWritablePdbStream() != NULL);
321 :
322 : // Be sure to replace the stream at this index with the new one. This is a
323 : // no-op if the stream hasn't changed.
324 E : pdb_file->ReplaceStream(index, reader.get());
325 :
326 E : return true;
327 E : }
328 :
329 : bool SetOmapToStream(const std::vector<OMAP>& omap_to_list,
330 E : PdbFile* pdb_file) {
331 E : DCHECK(pdb_file != NULL);
332 : return SetOmapStream(offsetof(DbiDbgHeader, omap_to_src),
333 : omap_to_list,
334 E : pdb_file);
335 E : }
336 :
337 : bool SetOmapFromStream(const std::vector<OMAP>& omap_from_list,
338 E : PdbFile* pdb_file) {
339 E : DCHECK(pdb_file != NULL);
340 : return SetOmapStream(offsetof(DbiDbgHeader, omap_from_src),
341 : omap_from_list,
342 E : pdb_file);
343 E : }
344 :
345 E : bool SetGuid(const GUID& guid, PdbFile* pdb_file) {
346 E : DCHECK(pdb_file != NULL);
347 :
348 : // Make sure the Pdb header and the Dbi streams are writable.
349 E : if (!EnsureStreamWritable(kPdbHeaderInfoStream, pdb_file)) {
350 i : LOG(ERROR) << "Failed to make PDB Header Info stream writable.";
351 i : return false;
352 : }
353 E : if (!EnsureStreamWritable(kDbiStream, pdb_file)) {
354 i : LOG(ERROR) << "Failed to make DBI Info stream writable.";
355 i : return false;
356 : }
357 :
358 : // Get the reader and writer for the header info stream.
359 E : scoped_refptr<PdbStream> reader(pdb_file->GetStream(kPdbHeaderInfoStream));
360 E : scoped_refptr<WritablePdbStream> writer(reader->GetWritablePdbStream());
361 E : DCHECK(writer.get() != NULL);
362 :
363 : // Read the header.
364 E : PdbInfoHeader70 info_header = {};
365 E : if (!reader->Seek(0) || !reader->Read(&info_header, 1)) {
366 E : LOG(ERROR) << "Failed to read PdbInfoHeader70.";
367 E : return false;
368 : }
369 :
370 : // Update it.
371 E : info_header.timestamp = static_cast<uint32>(time(NULL));
372 E : info_header.pdb_age = 1; // Reset age to 1, as this is a new generation.
373 E : info_header.signature = guid;
374 :
375 : // And write it back.
376 E : writer->set_pos(0);
377 E : if (!writer->Write(info_header)) {
378 i : LOG(ERROR) << "Failed to write PdbInfoHeader70.";
379 i : return false;
380 : }
381 :
382 : // Now update the age in the DBI stream to match the age we set above.
383 E : reader = pdb_file->GetStream(kDbiStream);
384 E : if (reader.get() == NULL) {
385 i : LOG(ERROR) << "No DBI stream in PDB.";
386 i : return false;
387 : }
388 E : writer = reader->GetWritablePdbStream();
389 :
390 E : DCHECK(writer.get() != NULL);
391 :
392 : // Read the header.
393 E : DbiHeader dbi_header = {};
394 E : if (!reader->Seek(0) || !reader->Read(&dbi_header, 1)) {
395 E : LOG(ERROR) << "Failed to read DbiHeader.";
396 E : return false;
397 : }
398 :
399 E : dbi_header.age = 1;
400 E : writer->set_pos(0);
401 E : if (!writer->Write(dbi_header)) {
402 i : LOG(ERROR) << "Failed to write DbiHeader";
403 i : return false;
404 : }
405 :
406 E : return true;
407 E : }
408 :
409 : bool ReadPdbHeader(const base::FilePath& pdb_path,
410 E : PdbInfoHeader70* pdb_header) {
411 E : DCHECK(!pdb_path.empty());
412 E : DCHECK(pdb_header != NULL);
413 :
414 E : PdbReader pdb_reader;
415 E : PdbFile pdb_file;
416 E : if (!pdb_reader.Read(pdb_path, &pdb_file)) {
417 E : LOG(ERROR) << "Unable to process PDB file: " << pdb_path.value();
418 E : return false;
419 : }
420 :
421 E : PdbStream* header_stream = pdb_file.GetStream(kPdbHeaderInfoStream);
422 E : if (header_stream == NULL) {
423 i : LOG(ERROR) << "PDB file contains no header stream: " << pdb_path.value();
424 i : return false;
425 : }
426 :
427 E : if (!header_stream->Read(pdb_header, 1)) {
428 i : LOG(ERROR) << "Failure reading PDB header: " << pdb_path.value();
429 i : return false;
430 : }
431 :
432 : // We only know how to deal with PDB files of the current version.
433 E : if (pdb_header->version != kPdbCurrentVersion) {
434 i : LOG(ERROR) << "PDB header has unsupported version (got "
435 : << pdb_header->version << ", expected " << kPdbCurrentVersion
436 : << ").";
437 i : return false;
438 : }
439 :
440 E : return true;
441 E : }
442 :
443 : bool ReadHeaderInfoStream(const PdbFile& pdb_file,
444 : PdbInfoHeader70* pdb_header,
445 E : NameStreamMap* name_stream_map) {
446 E : DCHECK(pdb_header != NULL);
447 E : DCHECK(name_stream_map != NULL);
448 :
449 : // Get the stream reader.
450 E : if (kPdbHeaderInfoStream >= pdb_file.StreamCount()) {
451 E : LOG(ERROR) << "No header info stream found.";
452 E : return false;
453 : }
454 : scoped_refptr<PdbStream> header_reader(
455 E : pdb_file.GetStream(kPdbHeaderInfoStream));
456 E : if (header_reader.get() == NULL) {
457 i : LOG(ERROR) << "No header info stream found.";
458 i : return false;
459 : }
460 :
461 : // Read the header.
462 : if (!pdb::ReadHeaderInfoStream(header_reader.get(), pdb_header,
463 E : name_stream_map)) {
464 i : LOG(ERROR) << "Failed to read header info stream.";
465 i : return false;
466 : }
467 :
468 E : return true;
469 E : }
470 :
471 : bool ReadHeaderInfoStream(PdbStream* pdb_stream,
472 : PdbInfoHeader70* pdb_header,
473 E : NameStreamMap* name_stream_map) {
474 E : VLOG(1) << "Header Info Stream size: " << pdb_stream->length();
475 :
476 E : if (!pdb_stream->Seek(0)) {
477 i : LOG(ERROR) << "Unable to seek to start of PDB header info stream.";
478 i : return false;
479 : }
480 :
481 : // The header stream starts with the fixed-size header pdb_header record.
482 E : if (!pdb_stream->Read(pdb_header, 1)) {
483 E : LOG(ERROR) << "Unable to read PDB pdb_header header.";
484 E : return false;
485 : }
486 :
487 E : uint32 string_len = 0;
488 E : if (!pdb_stream->Read(&string_len, 1)) {
489 E : LOG(ERROR) << "Unable to read string table length.";
490 E : return false;
491 : }
492 :
493 : // The fixed-size record is followed by information on named streams, which
494 : // is essentially a string->id mapping. This starts with the strings
495 : // themselves, which have been observed to be a packed run of zero-terminated
496 : // strings.
497 : // We store the start of the string list, as the string positions we read
498 : // later are relative to that position.
499 E : size_t string_start = pdb_stream->pos();
500 :
501 : // Seek past the strings.
502 E : if (!pdb_stream->Seek(string_start + string_len)) {
503 i : LOG(ERROR) << "Unable to seek past string list";
504 i : return false;
505 : }
506 :
507 : // Next there's a pair of integers. The first one of those is the number of
508 : // items in the string->id mapping. The purpose of the second one is not
509 : // clear, but has been observed as larger or equal to the first one.
510 E : uint32 size = 0;
511 E : uint32 max = 0;
512 E : if (!pdb_stream->Read(&size, 1) || !pdb_stream->Read(&max, 1)) {
513 i : LOG(ERROR) << "Unable to read name pdb_stream size/max";
514 i : return false;
515 : }
516 E : DCHECK(max >= size);
517 :
518 : // After the counts, there's a pair of bitsets. Each bitset has a 32 bit
519 : // length, followed by that number of 32 bit words that contain the bits.
520 : // The purpose of those is again not clear, though the first set will have
521 : // "size" bits of the bits in the range 0-max set.
522 E : PdbBitSet used;
523 E : PdbBitSet deleted;
524 E : if (!used.Read(pdb_stream) || !deleted.Read(pdb_stream)) {
525 i : LOG(ERROR) << "Unable to read name pdb_stream bitsets.";
526 i : return false;
527 : }
528 :
529 : #ifndef NDEBUG
530 : // The first bitset has "size" bits set of the first "max" bits.
531 E : size_t set_bits = 0;
532 E : for (size_t i = 0; i < max; ++i) {
533 E : if (used.IsSet(i))
534 E : ++set_bits;
535 E : }
536 :
537 : // The second bitset has always been observed to be empty.
538 E : DCHECK(deleted.IsEmpty());
539 :
540 E : DCHECK_EQ(size, set_bits);
541 : #endif
542 :
543 : // Read the mapping proper, this is simply a run of {string offset, id} pairs.
544 E : for (size_t i = 0; i < size; ++i) {
545 E : uint32 str_offs = 0;
546 E : uint32 stream_no = 0;
547 : // Read the offset and pdb_stream number.
548 E : if (!pdb_stream->Read(&str_offs, 1) || !pdb_stream->Read(&stream_no, 1)) {
549 i : LOG(ERROR) << "Unable to read pdb_stream data.";
550 i : return false;
551 : }
552 :
553 : // Read the string itself from the table.
554 E : std::string name;
555 E : if (!ReadStringAt(pdb_stream, string_start + str_offs, &name)) {
556 i : LOG(ERROR) << "Failed to read pdb_stream name.";
557 i : return false;
558 : }
559 :
560 E : (*name_stream_map)[name] = stream_no;
561 E : }
562 :
563 E : return true;
564 E : }
565 :
566 : bool WriteHeaderInfoStream(const PdbInfoHeader70& header,
567 : const NameStreamMap& name_stream_map,
568 E : PdbFile* pdb_file) {
569 E : DCHECK(pdb_file != NULL);
570 :
571 E : if (!pdb::EnsureStreamWritable(pdb::kPdbHeaderInfoStream, pdb_file)) {
572 i : LOG(ERROR) << "Failed to make PDB Header Info stream writable.";
573 i : return false;
574 : }
575 :
576 : // Get the stream reader.
577 : scoped_refptr<PdbStream> header_reader(
578 E : pdb_file->GetStream(pdb::kPdbHeaderInfoStream));
579 E : DCHECK(header_reader.get() != NULL);
580 :
581 : // Get the stream writer.
582 : scoped_refptr<WritablePdbStream> header_writer(
583 E : header_reader->GetWritablePdbStream());
584 E : DCHECK(header_writer.get() != NULL);
585 :
586 : // Write the new header.
587 E : if (!WriteHeaderInfoStream(header, name_stream_map, header_writer.get())) {
588 i : LOG(ERROR) << "Failed to write PDB Header Info stream.";
589 i : return false;
590 : }
591 :
592 E : return true;
593 E : }
594 :
595 : bool WriteHeaderInfoStream(const PdbInfoHeader70& pdb_header,
596 : const NameStreamMap& name_stream_map,
597 E : WritablePdbStream* pdb_stream) {
598 E : DCHECK(pdb_stream != NULL);
599 :
600 E : if (!pdb_stream->Write(pdb_header)) {
601 i : LOG(ERROR) << "Failed to write PDB header.";
602 i : return false;
603 : }
604 :
605 : // Calculate the hash table entry count and size.
606 E : uint32 string_count = name_stream_map.size();
607 E : uint32 table_size = GetNamedStreamsHashTableSize(string_count);
608 :
609 : // Initialize the 'used' bitset.
610 E : PdbBitSet used;
611 E : used.Resize(table_size);
612 :
613 : // Get the string table length. We also calculate hashes for each name,
614 : // populating the 'used' bitset and determining the order in which to output
615 : // the stream names.
616 E : std::vector<NamedStreamInfo> name_infos;
617 E : name_infos.reserve(string_count);
618 E : uint32 string_length = 0;
619 E : NameStreamMap::const_iterator name_it = name_stream_map.begin();
620 E : for (; name_it != name_stream_map.end(); ++name_it) {
621 E : uint16 hash = HashString(name_it->first);
622 E : size_t bucket = hash % table_size;
623 E : bucket = SetNamedStreamsHashTableBit(bucket, table_size, &used);
624 E : name_infos.push_back(NamedStreamInfo(name_it, 0, bucket));
625 E : string_length += name_it->first.size() + 1; // Include the trailing zero.
626 E : }
627 :
628 : // Sort the strings in the order in which they will be output.
629 E : std::sort(name_infos.begin(), name_infos.end());
630 :
631 : // Dump the string table.
632 E : if (!pdb_stream->Write(string_length)) {
633 i : LOG(ERROR) << "Failed to write stream name table length.";
634 i : return false;
635 : }
636 E : string_length = 0;
637 E : for (size_t i = 0; i < name_infos.size(); ++i) {
638 E : name_infos[i].offset = string_length;
639 E : name_it = name_infos[i].it;
640 E : string_length += name_it->first.size() + 1;
641 E : if (!pdb_stream->Write(name_it->first.size() + 1, name_it->first.c_str())) {
642 i : LOG(ERROR) << "Failed to write stream name.";
643 i : return false;
644 : }
645 E : }
646 :
647 : // Write the string hash table size.
648 E : if (!pdb_stream->Write(string_count) || !pdb_stream->Write(table_size)) {
649 i : LOG(ERROR) << "Failed to write string table size.";
650 i : return false;
651 : }
652 :
653 : // Write the 'used' bitset.
654 E : if (!used.Write(pdb_stream, true)) {
655 i : LOG(ERROR) << "Failed to write 'used' bitset.";
656 i : return false;
657 : }
658 :
659 : // The 'deleted' bitset is always empty.
660 E : PdbBitSet deleted;
661 E : DCHECK(deleted.IsEmpty());
662 E : if (!deleted.Write(pdb_stream, true)) {
663 i : LOG(ERROR) << "Failed to write 'deleted' bitset.";
664 i : return false;
665 : }
666 :
667 : // Now output the actual mapping, a run of (string table offset, stream id)
668 : // pairs. We output these in order of hash table buckets of each name,
669 : // mimicking the output produced by pdbstr.exe.
670 E : for (size_t i = 0; i < name_infos.size(); ++i) {
671 : if (!pdb_stream->Write(name_infos[i].offset) ||
672 E : !pdb_stream->Write(name_infos[i].it->second)) {
673 i : LOG(ERROR) << "Failed to write stream name mapping.";
674 i : return false;
675 : }
676 E : }
677 :
678 : // The run of pairs must be terminated with a single NULL entry.
679 E : if (!pdb_stream->Write(static_cast<uint32>(0))) {
680 i : LOG(ERROR) << "Failed to write terminating NULL.";
681 i : return false;
682 : }
683 :
684 E : return true;
685 E : }
686 :
687 : bool ReadStringTable(PdbStream* stream,
688 : const char* table_name,
689 : size_t table_start,
690 : size_t table_end,
691 E : OffsetStringMap* string_map) {
692 E : DCHECK(stream != NULL);
693 E : DCHECK(table_name != NULL);
694 E : DCHECK(string_map != NULL);
695 :
696 E : uint32 string_table_signature = 0;
697 E : uint32 string_table_version = 0;
698 :
699 : if (!stream->Seek(table_start) ||
700 : !stream->Read(&string_table_signature, 1) ||
701 E : !stream->Read(&string_table_version, 1)) {
702 i : LOG(ERROR) << "Unable to seek to " << table_name << " stream.";
703 i : return false;
704 : }
705 :
706 : if (string_table_signature != kPdbStringTableSignature ||
707 E : string_table_version != kPdbStringTableVersion) {
708 i : LOG(ERROR) << "Unexpected " << table_name << " header. Expected "
709 : << "signature/version "
710 : << base::StringPrintf("0x%08X", kPdbStringTableSignature) << "/"
711 : << kPdbStringTableVersion << ", read "
712 : << base::StringPrintf("0x%08X", string_table_signature) << "/"
713 : << string_table_version << ".";
714 i : return false;
715 : }
716 :
717 E : size_t string_table_size = 0;
718 E : if (!stream->Read(&string_table_size, 1)) {
719 i : LOG(ERROR) << "Unable to read the size of the " << table_name << " string "
720 : << "table.";
721 i : return false;
722 : }
723 :
724 E : size_t string_table_start = stream->pos();
725 E : size_t offset_table_start = stream->pos() + string_table_size;
726 :
727 : // Skip the string table and seek to the offset table.
728 E : if (!stream->Seek(offset_table_start)) {
729 i : LOG(ERROR) << "Unable to seek to the " << table_name << " offset table.";
730 i : return false;
731 : }
732 :
733 E : size_t entries_count = 0;
734 E : if (!stream->Read(&entries_count, 1)) {
735 i : LOG(ERROR) << "Unable to read the number of entries in the " << table_name
736 : << " offset table.";
737 i : return false;
738 : }
739 :
740 : // Some of the offsets present in the offset table have the value 0, which
741 : // refers to an empty string present at the beginning of the string table.
742 E : for (size_t i = 0; i < entries_count; ++i) {
743 E : size_t string_offset = 0;
744 E : std::string temp_string;
745 : if (!stream->Read(&string_offset, 1) ||
746 : !ReadStringAt(stream, string_table_start + string_offset,
747 E : &temp_string)) {
748 i : LOG(ERROR) << "Unable to read the " << table_name << " name table.";
749 i : return false;
750 : }
751 :
752 E : string_map->insert(std::make_pair(string_offset, temp_string));
753 E : }
754 :
755 E : uint32 string_count = 0;
756 : // Sometimes the string_count field matches the number of non-empty strings
757 : // in the string_map and sometimes it doesn't.
758 : // TODO(sebmarchand) : understand what's this value once the compiland streams
759 : // are deciphered.
760 E : if (!stream->Read(&string_count, 1)) {
761 i : LOG(ERROR) << "Unable to read the number of files present in the "
762 : << table_name << " stream.";
763 i : return false;
764 : }
765 :
766 E : if (stream->pos() != table_end) {
767 i : LOG(ERROR) << table_name << " stream is not valid.";
768 i : return false;
769 : }
770 :
771 E : return true;
772 E : }
773 :
774 : bool LoadNamedStreamFromPdbFile(
775 : const base::StringPiece& stream_name,
776 : PdbFile* pdb_file,
777 E : scoped_refptr<PdbStream>* stream) {
778 E : DCHECK(pdb_file != NULL);
779 E : DCHECK(stream != NULL);
780 E : DCHECK(stream->get() == NULL);
781 :
782 : // Get the PDB header and try to get the named stream ID from it.
783 E : pdb::PdbInfoHeader70 pdb_header = {0};
784 E : pdb::NameStreamMap name_stream_map;
785 : if (!ReadHeaderInfoStream(pdb_file->GetStream(pdb::kPdbHeaderInfoStream),
786 : &pdb_header,
787 E : &name_stream_map)) {
788 i : LOG(ERROR) << "Failed to read header info stream.";
789 i : return false;
790 : }
791 :
792 : // The stream with the given name does not exist.
793 : pdb::NameStreamMap::const_iterator name_it = name_stream_map.find(
794 E : stream_name.as_string());
795 E : if (name_it == name_stream_map.end())
796 E : return true;
797 :
798 : // Get the named stream and ensure that it's not empty.
799 E : *stream = pdb_file->GetStream(name_it->second);
800 E : if (stream->get() == NULL) {
801 i : LOG(ERROR) << "Failed to read the \"" << stream_name.as_string()
802 : << "\" stream from the PDB.";
803 i : return false;
804 : }
805 :
806 E : return true;
807 E : }
808 :
809 : } // namespace pdb
|