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 :
15 : #include "syzygy/pdb/pdb_util.h"
16 :
17 : #include <objbase.h>
18 :
19 : #include "base/command_line.h"
20 : #include "base/path_service.h"
21 : #include "base/process_util.h"
22 : #include "base/scoped_native_library.h"
23 : #include "base/utf_string_conversions.h"
24 : #include "base/files/scoped_temp_dir.h"
25 : #include "base/win/pe_image.h"
26 : #include "gmock/gmock.h"
27 : #include "gtest/gtest.h"
28 : #include "syzygy/core/unittest_util.h"
29 : #include "syzygy/pdb/pdb_byte_stream.h"
30 : #include "syzygy/pdb/pdb_reader.h"
31 : #include "syzygy/pdb/pdb_writer.h"
32 : #include "syzygy/pdb/unittest_util.h"
33 : #include "syzygy/pe/pe_data.h"
34 : #include "syzygy/pe/unittest_util.h"
35 :
36 : namespace pdb {
37 :
38 : namespace {
39 :
40 : const wchar_t* kTempPdbFileName = L"temp.pdb";
41 : const wchar_t* kTempPdbFileName2 = L"temp2.pdb";
42 :
43 : const GUID kSampleGuid = {0xACDC900D, 0x9009, 0xFEED, {7, 6, 5, 4, 3, 2, 1, 0}};
44 :
45 : const PdbInfoHeader70 kSamplePdbHeader = {
46 : kPdbCurrentVersion,
47 : 1336402486, // 7 May 2012, 14:54:00 GMT.
48 : 999,
49 : {0xDEADBEEF, 0x900D, 0xF00D, {0, 1, 2, 3, 4, 5, 6, 7}}
50 : };
51 :
52 : const DbiHeader kSampleDbiHeader = {
53 : -1, // signature.
54 : 19990903, // version.
55 : 999, // age.
56 : };
57 :
58 : const OMAP kOmapToData[] = {
59 : {4096, 4096},
60 : {5012, 5012},
61 : {6064, 6064},
62 : {7048, 240504}
63 : };
64 :
65 : const OMAP kOmapFromData[] = {
66 : {4096, 4096},
67 : {5012, 5012},
68 : {240504, 7048}
69 : };
70 :
71 : class PdbUtilTest : public testing::Test {
72 : public:
73 E : PdbUtilTest() : process_(this) {
74 E : }
75 :
76 E : void SetUp() {
77 E : ASSERT_TRUE(::SymInitialize(process_, NULL, FALSE));
78 :
79 E : ASSERT_HRESULT_SUCCEEDED(::CoCreateGuid(&new_guid_));
80 E : ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
81 :
82 E : temp_pdb_file_path_ = temp_dir_.path().Append(kTempPdbFileName);
83 E : temp_pdb_file_path2_ = temp_dir_.path().Append(kTempPdbFileName2);
84 E : }
85 :
86 E : void TearDown() {
87 E : ASSERT_TRUE(::SymCleanup(process_));
88 E : }
89 :
90 : void VerifyGuidData(const base::FilePath& pdb_path,
91 : const GUID& guid) {
92 : DWORD64 base_address =
93 : ::SymLoadModuleExW(process_,
94 : NULL,
95 : pdb_path.value().c_str(),
96 : NULL,
97 : 1,
98 : 1,
99 : NULL,
100 : 0);
101 : EXPECT_NE(0, base_address);
102 :
103 : // Get the module info to verify that the new PDB has the GUID we specified.
104 : IMAGEHLP_MODULEW64 module_info = { sizeof(module_info) };
105 : EXPECT_TRUE(::SymGetModuleInfoW64(process_, base_address, &module_info));
106 : EXPECT_EQ(new_guid_, module_info.PdbSig70);
107 :
108 : EXPECT_TRUE(::SymUnloadModule64(process_, base_address));
109 : }
110 :
111 : void VerifyOmapData(const base::FilePath& pdb_path,
112 : const std::vector<OMAP>& omap_to_list,
113 E : const std::vector<OMAP>& omap_from_list) {
114 : DWORD64 base_address =
115 : ::SymLoadModuleExW(process_,
116 : NULL,
117 : pdb_path.value().c_str(),
118 : NULL,
119 : 1,
120 : 1,
121 : NULL,
122 E : 0);
123 E : ASSERT_NE(0, base_address);
124 :
125 E : OMAP* omap_to = NULL;
126 E : DWORD64 omap_to_length = 0;
127 E : OMAP* omap_from = NULL;
128 E : DWORD64 omap_from_length = 0;
129 E : ASSERT_TRUE(::SymGetOmaps(process_,
130 : base_address,
131 : &omap_to,
132 : &omap_to_length,
133 : &omap_from,
134 : &omap_from_length));
135 :
136 E : ASSERT_EQ(omap_to_list.size(), omap_to_length);
137 E : EXPECT_EQ(0, memcmp(&omap_to_list[0], omap_to,
138 : omap_to_list.size() * sizeof(OMAP)));
139 E : ASSERT_EQ(omap_from_list.size(), omap_from_length);
140 E : EXPECT_EQ(0, memcmp(&omap_from_list[0], omap_from,
141 : omap_from_list.size() * sizeof(OMAP)));
142 :
143 E : EXPECT_TRUE(::SymUnloadModule64(process_, base_address));
144 E : }
145 :
146 : protected:
147 : HANDLE process_;
148 : GUID new_guid_;
149 : base::ScopedTempDir temp_dir_;
150 : base::FilePath temp_pdb_file_path_;
151 : base::FilePath temp_pdb_file_path2_;
152 : };
153 :
154 : class TestPdbStream : public PdbStream {
155 : public:
156 E : TestPdbStream() : PdbStream(0), bytes_(NULL) {
157 E : }
158 :
159 : template<typename T> TestPdbStream(const T& t)
160 : : PdbStream(sizeof(T)),
161 E : bytes_(reinterpret_cast<const uint8*>(&t)) {
162 E : }
163 :
164 : virtual bool ReadBytes(void* dest,
165 : size_t count,
166 E : size_t* bytes_read) OVERRIDE {
167 E : if (pos() >= length())
168 i : return false;
169 E : size_t max_count = length() - pos();
170 E : *bytes_read = max_count < count ? max_count : count;
171 E : ::memcpy(dest, bytes_ + pos(), *bytes_read);
172 E : Seek(pos() + *bytes_read);
173 E : return *bytes_read == count;
174 E : }
175 :
176 : private:
177 : const uint8* const bytes_;
178 : };
179 :
180 : // Comparison operator for PdbInfoHeader70 objects.
181 : bool AreEqual(const PdbInfoHeader70& header1,
182 E : const PdbInfoHeader70& header2) {
183 E : return ::memcmp(&header1, &header2, sizeof(header1)) == 0;
184 E : }
185 :
186 : } // namespace
187 :
188 E : TEST(PdbBitSetTest, ReadEmptyStream) {
189 E : scoped_refptr<PdbStream> stream(new TestPdbStream());
190 E : PdbBitSet bs;
191 E : EXPECT_FALSE(bs.Read(stream.get()));
192 E : }
193 :
194 E : TEST(PdbBitSetTest, SimpleMutators) {
195 E : PdbBitSet bs;
196 E : EXPECT_TRUE(bs.IsEmpty());
197 E : EXPECT_EQ(bs.size(), 0u);
198 E : bs.Resize(43);
199 E : EXPECT_EQ(bs.size(), 64u);
200 :
201 E : for (size_t i = 0; i < 64; ++i)
202 E : EXPECT_FALSE(bs.IsSet(i));
203 :
204 E : bs.Toggle(15);
205 E : EXPECT_TRUE(bs.IsSet(15));
206 E : bs.Toggle(15);
207 E : EXPECT_FALSE(bs.IsSet(15));
208 :
209 E : bs.Set(25);
210 E : EXPECT_TRUE(bs.IsSet(25));
211 E : bs.Clear(25);
212 E : EXPECT_FALSE(bs.IsSet(25));
213 :
214 E : for (size_t i = 0; i < 64; i += 10)
215 E : bs.Set(i);
216 :
217 E : for (size_t i = 0; i < 64; ++i)
218 E : EXPECT_EQ((i % 10) == 0, bs.IsSet(i));
219 E : }
220 :
221 E : TEST(PdbBitSetTest, ReadEmptyBitSet) {
222 E : const uint32 kSize = 0;
223 E : scoped_refptr<PdbStream> stream(new TestPdbStream(kSize));
224 E : PdbBitSet bs;
225 E : EXPECT_TRUE(bs.Read(stream.get()));
226 E : EXPECT_TRUE(bs.IsEmpty());
227 E : EXPECT_EQ(bs.size(), 0u);
228 E : }
229 :
230 E : TEST(PdbBitSetTest, ReadSingleDwordBitSet) {
231 E : const uint32 kData[] = { 1, (1<<0) | (1<<5) | (1<<13) };
232 E : scoped_refptr<PdbStream> stream(new TestPdbStream(kData));
233 E : PdbBitSet bs;
234 E : EXPECT_TRUE(bs.Read(stream.get()));
235 E : EXPECT_FALSE(bs.IsEmpty());
236 E : EXPECT_EQ(bs.size(), 32u);
237 E : for (size_t i = 0; i < bs.size(); ++i)
238 E : EXPECT_EQ(i == 0 || i == 5 || i == 13, bs.IsSet(i));
239 E : }
240 :
241 E : TEST(PdbBitSetTest, ReadMultiDwordBitSet) {
242 E : const uint32 kData[] = { 2, (1<<0) | (1<<5) | (1<<13), (1<<5) };
243 E : scoped_refptr<PdbStream> stream(new TestPdbStream(kData));
244 E : PdbBitSet bs;
245 E : EXPECT_TRUE(bs.Read(stream.get()));
246 E : EXPECT_FALSE(bs.IsEmpty());
247 E : EXPECT_EQ(bs.size(), 64u);
248 E : for (size_t i = 0; i < bs.size(); ++i)
249 E : EXPECT_EQ(i == 0 || i == 5 || i == 13 || i == (32 + 5), bs.IsSet(i));
250 E : }
251 :
252 E : TEST(PdbBitSetTest, WriteEmptyBitSet) {
253 E : const uint32 kData[] = { 0 };
254 E : scoped_refptr<PdbStream> stream(new TestPdbStream(kData));
255 E : PdbBitSet bs;
256 E : EXPECT_TRUE(bs.Read(stream.get()));
257 :
258 E : scoped_refptr<PdbByteStream> reader(new PdbByteStream());
259 E : scoped_refptr<WritablePdbStream> writer(reader->GetWritablePdbStream());
260 E : EXPECT_TRUE(bs.Write(writer.get()));
261 :
262 E : std::vector<uint32> data;
263 E : EXPECT_TRUE(reader->Read(&data, arraysize(kData)));
264 E : EXPECT_THAT(data, testing::ElementsAreArray(kData));
265 E : }
266 :
267 E : TEST(PdbBitSetTest, WriteBitSet) {
268 E : const uint32 kData[] = { 2, (1<<0) | (1<<5) | (1<<13), (1<<5) };
269 E : scoped_refptr<PdbStream> stream(new TestPdbStream(kData));
270 E : PdbBitSet bs;
271 E : EXPECT_TRUE(bs.Read(stream.get()));
272 :
273 E : scoped_refptr<PdbByteStream> reader(new PdbByteStream());
274 E : scoped_refptr<WritablePdbStream> writer(reader->GetWritablePdbStream());
275 E : EXPECT_TRUE(bs.Write(writer.get()));
276 E : EXPECT_EQ(sizeof(kData), reader->length());
277 :
278 E : std::vector<uint32> data;
279 E : EXPECT_TRUE(reader->Read(&data, arraysize(kData)));
280 E : EXPECT_THAT(data, testing::ElementsAreArray(kData));
281 E : }
282 :
283 E : TEST_F(PdbUtilTest, GetDbiDbgHeaderOffsetTestDll) {
284 : // Test the test_dll.dll.pdb doesn't have Omap information.
285 E : PdbReader reader;
286 E : PdbFile pdb_file;
287 : EXPECT_TRUE(reader.Read(
288 : testing::GetSrcRelativePath(testing::kTestPdbFilePath),
289 E : &pdb_file));
290 :
291 E : PdbStream* dbi_stream = pdb_file.GetStream(kDbiStream);
292 : DbiHeader dbi_header;
293 E : EXPECT_TRUE(dbi_stream->Read(&dbi_header, 1));
294 :
295 E : uint32 offset = GetDbiDbgHeaderOffset(dbi_header);
296 E : EXPECT_LE(offset, dbi_stream->length() - sizeof(DbiDbgHeader));
297 :
298 E : EXPECT_TRUE(dbi_stream->Seek(offset));
299 : DbiDbgHeader dbi_dbg_header;
300 E : EXPECT_TRUE(dbi_stream->Read(&dbi_dbg_header, 1));
301 :
302 E : EXPECT_EQ(-1, dbi_dbg_header.omap_to_src);
303 E : EXPECT_EQ(-1, dbi_dbg_header.omap_from_src);
304 E : }
305 :
306 E : TEST_F(PdbUtilTest, GetDbiDbgHeaderOffsetOmappedTestDll) {
307 : // Test that omapped_test_dll.dll.pdb does have Omap information.
308 E : PdbReader reader;
309 E : PdbFile pdb_file;
310 : EXPECT_TRUE(reader.Read(
311 : testing::GetSrcRelativePath(testing::kOmappedTestPdbFilePath),
312 E : &pdb_file));
313 :
314 E : PdbStream* dbi_stream = pdb_file.GetStream(kDbiStream);
315 : DbiHeader dbi_header;
316 E : EXPECT_TRUE(dbi_stream->Read(&dbi_header, 1));
317 :
318 E : uint32 offset = GetDbiDbgHeaderOffset(dbi_header);
319 E : EXPECT_LE(offset, dbi_stream->length() - sizeof(DbiDbgHeader));
320 :
321 E : EXPECT_TRUE(dbi_stream->Seek(offset));
322 : DbiDbgHeader dbi_dbg_header;
323 E : EXPECT_TRUE(dbi_stream->Read(&dbi_dbg_header, 1));
324 :
325 E : EXPECT_NE(-1, dbi_dbg_header.omap_to_src);
326 E : EXPECT_NE(-1, dbi_dbg_header.omap_from_src);
327 E : }
328 :
329 E : TEST_F(PdbUtilTest, TestDllHasNoOmap) {
330 : // Test that test_dll.dll.pdb has no Omap information.
331 : base::FilePath test_pdb_file_path = testing::GetSrcRelativePath(
332 E : testing::kTestPdbFilePath);
333 : DWORD64 base_address =
334 : ::SymLoadModuleExW(process_,
335 : NULL,
336 : test_pdb_file_path.value().c_str(),
337 : NULL,
338 : 1,
339 : 1,
340 : NULL,
341 E : 0);
342 E : EXPECT_NE(0, base_address);
343 :
344 E : OMAP* omap_to = NULL;
345 E : DWORD64 omap_to_length = 0;
346 E : OMAP* omap_from = NULL;
347 E : DWORD64 omap_from_length = 0;
348 : EXPECT_FALSE(::SymGetOmaps(process_,
349 : base_address,
350 : &omap_to,
351 : &omap_to_length,
352 : &omap_from,
353 E : &omap_from_length));
354 :
355 E : EXPECT_TRUE(::SymUnloadModule64(process_, base_address));
356 E : }
357 :
358 E : TEST_F(PdbUtilTest, SetOmapToAndFromStream) {
359 : // Add Omap information to test_dll.pdb and test that the output file
360 : // has Omap information.
361 : std::vector<OMAP> omap_to_list(kOmapToData,
362 E : kOmapToData + arraysize(kOmapToData));
363 : std::vector<OMAP> omap_from_list(kOmapFromData,
364 E : kOmapFromData + arraysize(kOmapFromData));
365 :
366 : base::FilePath test_pdb_file_path = testing::GetSrcRelativePath(
367 E : testing::kTestPdbFilePath);
368 E : PdbReader pdb_reader;
369 E : PdbFile pdb_file;
370 E : ASSERT_TRUE(pdb_reader.Read(test_pdb_file_path, &pdb_file));
371 :
372 E : EXPECT_TRUE(SetOmapToStream(omap_to_list, &pdb_file));
373 E : EXPECT_TRUE(SetOmapFromStream(omap_from_list, &pdb_file));
374 :
375 E : PdbWriter pdb_writer;
376 E : ASSERT_TRUE(pdb_writer.Write(temp_pdb_file_path_, pdb_file));
377 :
378 : VerifyOmapData(temp_pdb_file_path_,
379 : omap_to_list,
380 E : omap_from_list);
381 E : }
382 :
383 E : TEST_F(PdbUtilTest, PdbHeaderMatchesImageDebugDirectory) {
384 E : PdbReader reader;
385 E : PdbFile pdb_file;
386 : EXPECT_TRUE(reader.Read(
387 : testing::GetSrcRelativePath(testing::kTestPdbFilePath),
388 E : &pdb_file));
389 :
390 E : PdbInfoHeader70 header = { 0 };
391 E : ASSERT_GE(pdb_file.StreamCount(), kPdbHeaderInfoStream);
392 E : ASSERT_TRUE(pdb_file.GetStream(kPdbHeaderInfoStream) != NULL);
393 E : EXPECT_TRUE(pdb_file.GetStream(kPdbHeaderInfoStream)->Read(&header, 1));
394 E : EXPECT_EQ(header.version, kPdbCurrentVersion);
395 :
396 E : std::string error;
397 : base::NativeLibrary test_dll =
398 : base::LoadNativeLibrary(
399 : testing::GetSrcRelativePath(testing::kTestDllFilePath),
400 E : &error);
401 E : ASSERT_TRUE(test_dll != NULL);
402 :
403 : // Make sure the DLL is unloaded on exit.
404 E : base::ScopedNativeLibrary test_dll_keeper(test_dll);
405 E : base::win::PEImage image(test_dll);
406 :
407 : // Retrieve the NT headers to make it easy to look at them in debugger.
408 E : const IMAGE_NT_HEADERS* nt_headers = image.GetNTHeaders();
409 :
410 : ASSERT_EQ(sizeof(IMAGE_DEBUG_DIRECTORY),
411 E : image.GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_DEBUG));
412 : const IMAGE_DEBUG_DIRECTORY* debug_directory =
413 : reinterpret_cast<const IMAGE_DEBUG_DIRECTORY*>(
414 E : image.GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_DEBUG));
415 :
416 E : ASSERT_EQ(IMAGE_DEBUG_TYPE_CODEVIEW, debug_directory->Type);
417 E : ASSERT_GE(debug_directory->SizeOfData, sizeof(pe::CvInfoPdb70));
418 :
419 : const pe::CvInfoPdb70* cv_info =
420 : reinterpret_cast<const pe::CvInfoPdb70*>(
421 E : image.RVAToAddr(debug_directory->AddressOfRawData));
422 :
423 E : ASSERT_EQ(pe::kPdb70Signature, cv_info->cv_signature);
424 E : ASSERT_EQ(header.signature, cv_info->signature);
425 E : ASSERT_EQ(header.pdb_age, cv_info->pdb_age);
426 E : }
427 :
428 E : TEST_F(PdbUtilTest, ReadPdbHeader) {
429 : const base::FilePath pdb_path = testing::GetSrcRelativePath(
430 E : testing::kTestPdbFilePath);
431 E : PdbInfoHeader70 pdb_header = {};
432 E : EXPECT_TRUE(ReadPdbHeader(pdb_path, &pdb_header));
433 E : }
434 :
435 E : TEST(EnsureStreamWritableTest, DoesNothingWhenAlreadyWritable) {
436 E : PdbFile pdb_file;
437 E : scoped_refptr<PdbStream> stream = new PdbByteStream();
438 E : size_t index = pdb_file.AppendStream(stream.get());
439 E : EXPECT_TRUE(EnsureStreamWritable(index, &pdb_file));
440 E : scoped_refptr<PdbStream> stream2 = pdb_file.GetStream(index);
441 E : EXPECT_EQ(stream.get(), stream2.get());
442 E : }
443 :
444 E : TEST(EnsureStreamWritableTest, WorksWhenReadOnly) {
445 E : PdbFile pdb_file;
446 E : scoped_refptr<PdbStream> stream = new TestPdbStream();
447 E : size_t index = pdb_file.AppendStream(stream.get());
448 E : EXPECT_TRUE(EnsureStreamWritable(index, &pdb_file));
449 E : scoped_refptr<PdbStream> stream2 = pdb_file.GetStream(index);
450 E : EXPECT_TRUE(stream2.get() != NULL);
451 E : EXPECT_NE(stream.get(), stream2.get());
452 E : EXPECT_TRUE(stream2->GetWritablePdbStream() != NULL);
453 E : }
454 :
455 E : TEST(EnsureStreamWritableTest, FailsWhenNonExistent) {
456 E : PdbFile pdb_file;
457 E : EXPECT_FALSE(EnsureStreamWritable(45, &pdb_file));
458 E : }
459 :
460 E : TEST(SetGuidTest, FailsWhenStreamsDoNotExist) {
461 E : PdbFile pdb_file;
462 :
463 : // Leave the Pdb header missing.
464 E : pdb_file.SetStream(kPdbHeaderInfoStream, NULL);
465 E : pdb_file.SetStream(kDbiStream, new TestPdbStream(kSampleDbiHeader));
466 E : EXPECT_FALSE(SetGuid(kSampleGuid, &pdb_file));
467 :
468 : // Add the header stream, but leave the Dbi header missing.
469 E : pdb_file.SetStream(kPdbHeaderInfoStream, new TestPdbStream(kSamplePdbHeader));
470 E : pdb_file.SetStream(kDbiStream, NULL);
471 E : EXPECT_FALSE(SetGuid(kSampleGuid, &pdb_file));
472 E : }
473 :
474 E : TEST(SetGuidTest, FailsWhenStreamsAreTooShort) {
475 E : PdbFile pdb_file;
476 :
477 E : const uint8 kByte = 6;
478 E : pdb_file.SetStream(kPdbHeaderInfoStream, new TestPdbStream(kByte));
479 E : pdb_file.SetStream(kDbiStream, new TestPdbStream(kSampleDbiHeader));
480 E : EXPECT_FALSE(SetGuid(kSampleGuid, &pdb_file));
481 :
482 E : pdb_file.SetStream(kPdbHeaderInfoStream, new TestPdbStream(kSamplePdbHeader));
483 E : pdb_file.SetStream(kDbiStream, new TestPdbStream(kByte));
484 E : EXPECT_FALSE(SetGuid(kSampleGuid, &pdb_file));
485 E : }
486 :
487 E : TEST(SetGuidTest, Succeeds) {
488 E : PdbFile pdb_file;
489 :
490 E : pdb_file.SetStream(kPdbHeaderInfoStream, new TestPdbStream(kSamplePdbHeader));
491 E : pdb_file.SetStream(kDbiStream, new TestPdbStream(kSampleDbiHeader));
492 :
493 : scoped_refptr<PdbStream> stream =
494 E : pdb_file.GetStream(kPdbHeaderInfoStream);
495 E : ASSERT_TRUE(stream.get() != NULL);
496 E : ASSERT_EQ(stream->length(), sizeof(PdbInfoHeader70));
497 :
498 E : uint32 time1 = static_cast<uint32>(time(NULL));
499 E : EXPECT_TRUE(SetGuid(kSampleGuid, &pdb_file));
500 E : uint32 time2 = static_cast<uint32>(time(NULL));
501 :
502 : // Read the new header.
503 E : PdbInfoHeader70 pdb_header = {};
504 E : stream = pdb_file.GetStream(kPdbHeaderInfoStream);
505 E : EXPECT_TRUE(stream->Seek(0));
506 E : EXPECT_TRUE(stream->Read(&pdb_header, 1));
507 :
508 : // Validate that the fields are as expected.
509 E : EXPECT_LE(time1, pdb_header.timestamp);
510 E : EXPECT_LE(pdb_header.timestamp, time2);
511 E : EXPECT_EQ(1u, pdb_header.pdb_age);
512 E : EXPECT_EQ(kSampleGuid, pdb_header.signature);
513 :
514 E : DbiHeader dbi_header = {};
515 E : stream = pdb_file.GetStream(kDbiStream);
516 E : ASSERT_TRUE(stream.get() != NULL);
517 E : ASSERT_EQ(stream->length(), sizeof(dbi_header));
518 :
519 E : EXPECT_TRUE(stream->Seek(0));
520 E : EXPECT_TRUE(stream->Read(&dbi_header, 1));
521 E : EXPECT_EQ(1u, dbi_header.age);
522 E : }
523 :
524 E : TEST(ReadHeaderInfoStreamTest, ReadFromPdbFile) {
525 : const base::FilePath pdb_path = testing::GetSrcRelativePath(
526 E : testing::kTestPdbFilePath);
527 :
528 E : PdbFile pdb_file;
529 E : PdbReader pdb_reader;
530 E : ASSERT_TRUE(pdb_reader.Read(pdb_path, &pdb_file));
531 :
532 E : PdbInfoHeader70 pdb_header = {};
533 E : NameStreamMap name_stream_map;
534 E : EXPECT_TRUE(ReadHeaderInfoStream(pdb_file, &pdb_header, &name_stream_map));
535 E : }
536 :
537 E : TEST(ReadHeaderInfoStreamTest, ReadEmptyStream) {
538 E : scoped_refptr<PdbStream> stream(new TestPdbStream());
539 E : PdbInfoHeader70 pdb_header = {};
540 E : NameStreamMap name_stream_map;
541 E : EXPECT_FALSE(ReadHeaderInfoStream(stream, &pdb_header, &name_stream_map));
542 E : }
543 :
544 E : TEST(ReadHeaderInfoStreamTest, ReadStreamWithOnlyHeader) {
545 E : scoped_refptr<PdbStream> reader(new PdbByteStream());
546 E : scoped_refptr<WritablePdbStream> writer(reader->GetWritablePdbStream());
547 :
548 E : PdbInfoHeader70 pdb_header = {};
549 E : ASSERT_TRUE(writer->Write(pdb_header));
550 :
551 E : NameStreamMap name_stream_map;
552 E : EXPECT_FALSE(ReadHeaderInfoStream(reader, &pdb_header, &name_stream_map));
553 E : }
554 :
555 E : TEST(ReadHeaderInfoStreamTest, ReadStreamWithEmptyNameStreamMap) {
556 E : scoped_refptr<PdbStream> reader(new PdbByteStream());
557 E : scoped_refptr<WritablePdbStream> writer(reader->GetWritablePdbStream());
558 :
559 E : PdbInfoHeader70 pdb_header = {};
560 E : ASSERT_TRUE(writer->Write(pdb_header));
561 E : ASSERT_TRUE(writer->Write(static_cast<uint32>(0))); // total string length.
562 E : ASSERT_TRUE(writer->Write(static_cast<uint32>(0))); // number of names.
563 E : ASSERT_TRUE(writer->Write(static_cast<uint32>(0))); // size of bitsets.
564 E : ASSERT_TRUE(writer->Write(static_cast<uint32>(0))); // first bitset.
565 E : ASSERT_TRUE(writer->Write(static_cast<uint32>(0))); // second bitset.
566 :
567 E : NameStreamMap name_stream_map;
568 E : EXPECT_TRUE(ReadHeaderInfoStream(reader, &pdb_header, &name_stream_map));
569 E : EXPECT_EQ(name_stream_map.size(), 0u);
570 E : }
571 :
572 E : TEST(ReadHeaderInfoStreamTest, ReadStreamWithNameStreamMap) {
573 E : scoped_refptr<PdbStream> reader(new PdbByteStream());
574 E : scoped_refptr<WritablePdbStream> writer(reader->GetWritablePdbStream());
575 :
576 E : PdbInfoHeader70 pdb_header = {};
577 E : ASSERT_TRUE(writer->Write(pdb_header));
578 E : ASSERT_TRUE(writer->Write(static_cast<uint32>(9))); // total string length.
579 E : uint32 offset1 = writer->pos();
580 E : ASSERT_TRUE(writer->Write(3, "/a")); // name 1.
581 E : uint32 offset2 = writer->pos();
582 E : ASSERT_TRUE(writer->Write(3, "/b")); // name 2.
583 E : uint32 offset3 = writer->pos();
584 E : ASSERT_TRUE(writer->Write(3, "/c")); // name 3.
585 E : ASSERT_TRUE(writer->Write(static_cast<uint32>(3))); // number of names.
586 E : ASSERT_TRUE(writer->Write(static_cast<uint32>(3))); // size of bitsets.
587 :
588 E : PdbBitSet present;
589 E : present.Resize(3);
590 E : present.Set(0);
591 E : present.Set(1);
592 E : present.Set(2);
593 E : ASSERT_TRUE(present.Write(writer));
594 :
595 E : ASSERT_TRUE(writer->Write(static_cast<uint32>(0))); // second bitset.
596 :
597 E : ASSERT_TRUE(writer->Write(0));
598 E : ASSERT_TRUE(writer->Write(static_cast<uint32>(42)));
599 E : ASSERT_TRUE(writer->Write(offset2 - offset1));
600 E : ASSERT_TRUE(writer->Write(static_cast<uint32>(7)));
601 E : ASSERT_TRUE(writer->Write(offset3 - offset1));
602 E : ASSERT_TRUE(writer->Write(static_cast<uint32>(95)));
603 :
604 E : NameStreamMap name_stream_map;
605 E : EXPECT_TRUE(ReadHeaderInfoStream(reader, &pdb_header, &name_stream_map));
606 :
607 E : NameStreamMap expected;
608 E : expected["/a"] = 42;
609 E : expected["/b"] = 7;
610 E : expected["/c"] = 95;
611 E : EXPECT_THAT(name_stream_map, testing::ContainerEq(expected));
612 E : }
613 :
614 E : TEST(ReadHeaderInfoStreamTest, ReadFromPdb) {
615 : const base::FilePath pdb_path = testing::GetSrcRelativePath(
616 E : testing::kTestPdbFilePath);
617 E : PdbFile pdb_file;
618 E : PdbReader pdb_reader;
619 E : EXPECT_TRUE(pdb_reader.Read(pdb_path, &pdb_file));
620 :
621 E : PdbInfoHeader70 pdb_header = {};
622 E : NameStreamMap name_stream_map;
623 : EXPECT_TRUE(ReadHeaderInfoStream(pdb_file.GetStream(kPdbHeaderInfoStream),
624 : &pdb_header,
625 E : &name_stream_map));
626 E : }
627 :
628 E : TEST(WriteHeaderInfoStreamTest, WriteToPdbFile) {
629 : const base::FilePath pdb_path = testing::GetSrcRelativePath(
630 E : testing::kTestPdbFilePath);
631 :
632 E : PdbFile pdb_file;
633 E : PdbReader pdb_reader;
634 E : ASSERT_TRUE(pdb_reader.Read(pdb_path, &pdb_file));
635 :
636 E : PdbInfoHeader70 pdb_header = {};
637 E : NameStreamMap name_stream_map;
638 E : ASSERT_TRUE(ReadHeaderInfoStream(pdb_file, &pdb_header, &name_stream_map));
639 :
640 E : pdb_header.pdb_age++;
641 E : name_stream_map["NewStream!"] = 999;
642 :
643 E : EXPECT_TRUE(WriteHeaderInfoStream(pdb_header, name_stream_map, &pdb_file));
644 :
645 E : PdbInfoHeader70 pdb_header2 = {};
646 E : NameStreamMap name_stream_map2;
647 E : ASSERT_TRUE(ReadHeaderInfoStream(pdb_file, &pdb_header2, &name_stream_map2));
648 :
649 E : EXPECT_TRUE(AreEqual(pdb_header, pdb_header2));
650 E : EXPECT_EQ(name_stream_map, name_stream_map2);
651 E : }
652 :
653 E : TEST(WriteHeaderInfoStreamTest, WriteEmpty) {
654 E : scoped_refptr<PdbStream> reader(new PdbByteStream());
655 E : scoped_refptr<WritablePdbStream> writer(reader->GetWritablePdbStream());
656 :
657 E : NameStreamMap name_stream_map;
658 : EXPECT_TRUE(WriteHeaderInfoStream(kSamplePdbHeader,
659 : name_stream_map,
660 E : writer.get()));
661 :
662 E : PdbInfoHeader70 read_pdb_header = {};
663 E : NameStreamMap read_name_stream_map;
664 : EXPECT_TRUE(ReadHeaderInfoStream(reader.get(),
665 : &read_pdb_header,
666 E : &read_name_stream_map));
667 :
668 : EXPECT_EQ(0, ::memcmp(&kSamplePdbHeader,
669 : &read_pdb_header,
670 E : sizeof(kSamplePdbHeader)));
671 E : EXPECT_THAT(name_stream_map, testing::ContainerEq(read_name_stream_map));
672 E : }
673 :
674 E : TEST(WriteHeaderInfoStreamTest, WriteNonEmpty) {
675 E : scoped_refptr<PdbStream> reader(new PdbByteStream());
676 E : scoped_refptr<WritablePdbStream> writer(reader->GetWritablePdbStream());
677 :
678 E : NameStreamMap name_stream_map;
679 E : name_stream_map["/StreamFoo"] = 9;
680 E : name_stream_map["/StreamBar"] = 42;
681 E : name_stream_map["/Stream/With/A/Path"] = 19;
682 : EXPECT_TRUE(WriteHeaderInfoStream(kSamplePdbHeader,
683 : name_stream_map,
684 E : writer.get()));
685 :
686 E : PdbInfoHeader70 read_pdb_header = {};
687 E : NameStreamMap read_name_stream_map;
688 : EXPECT_TRUE(ReadHeaderInfoStream(reader.get(),
689 : &read_pdb_header,
690 E : &read_name_stream_map));
691 :
692 : EXPECT_EQ(0, ::memcmp(&kSamplePdbHeader,
693 : &read_pdb_header,
694 E : sizeof(kSamplePdbHeader)));
695 E : EXPECT_THAT(name_stream_map, testing::ContainerEq(read_name_stream_map));
696 E : }
697 :
698 E : TEST_F(PdbUtilTest, NamedStreamsWorkWithPdbStr) {
699 : // We start by creating a PDB file (a copy of a checked in sample one) and
700 : // adding a new stream to it using our named-stream implementation.
701 : {
702 : base::FilePath orig_pdb_path = testing::GetSrcRelativePath(
703 E : testing::kTestPdbFilePath);
704 :
705 : // Read the sample PDB.
706 E : PdbReader pdb_reader;
707 E : PdbFile pdb_file;
708 E : ASSERT_TRUE(pdb_reader.Read(orig_pdb_path, &pdb_file));
709 :
710 : // Add a new stream to it.
711 E : scoped_refptr<PdbStream> foo_reader(new PdbByteStream());
712 : scoped_refptr<WritablePdbStream> foo_writer(
713 E : foo_reader->GetWritablePdbStream());
714 E : size_t foo_index = pdb_file.AppendStream(foo_reader.get());
715 E : foo_writer->WriteString("foo");
716 :
717 : // Get the PDB header stream.
718 : scoped_refptr<PdbStream> header_stream(pdb_file.GetStream(
719 E : kPdbHeaderInfoStream));
720 E : ASSERT_TRUE(header_stream.get() != NULL);
721 :
722 : // Read the existing name-stream map.
723 E : PdbInfoHeader70 pdb_header = {};
724 E : NameStreamMap name_stream_map;
725 : ASSERT_TRUE(ReadHeaderInfoStream(
726 E : header_stream, &pdb_header, &name_stream_map));
727 :
728 : // Add an entry for the new stream.
729 E : name_stream_map["foo"] = foo_index;
730 :
731 : // Write the new header stream to it.
732 E : scoped_refptr<PdbStream> new_header_reader(new PdbByteStream());
733 : scoped_refptr<WritablePdbStream> new_header_writer(
734 E : new_header_reader->GetWritablePdbStream());
735 : ASSERT_TRUE(pdb::WriteHeaderInfoStream(
736 E : pdb_header, name_stream_map, new_header_writer));
737 E : pdb_file.ReplaceStream(kPdbHeaderInfoStream, new_header_reader);
738 :
739 : // Write the PDB.
740 E : PdbWriter pdb_writer;
741 E : ASSERT_TRUE(pdb_writer.Write(temp_pdb_file_path_, pdb_file));
742 E : }
743 :
744 : // We've now created a new PDB file. We want to make sure that pdbstr.exe
745 : // plays nicely with our named streams by doing a few things:
746 : // (1) If we try to read a non-existing stream, we should get empty output.
747 : // (2) We should be able to read an existing stream and get non-empty output.
748 : // (3) We should be able to add a new stream, and then read it using our
749 : // mechanisms.
750 :
751 : // Get the path to pdbstr.exe, which we redistribute in third_party.
752 : base::FilePath pdbstr_path =
753 E : testing::GetSrcRelativePath(testing::kPdbStrPath);
754 :
755 : // Create the argument specifying the PDB path.
756 E : std::string pdb_arg = ::WideToUTF8(temp_pdb_file_path_.value());
757 E : pdb_arg.insert(0, "-p:");
758 :
759 : // First test: try to read a non-existing stream. Should produce no output.
760 : {
761 E : CommandLine cmd(pdbstr_path);
762 E : cmd.AppendArg(pdb_arg);
763 E : cmd.AppendArg("-r");
764 E : cmd.AppendArg("-s:nonexistent-stream-name");
765 E : std::string output;
766 E : ASSERT_TRUE(base::GetAppOutput(cmd, &output));
767 E : ASSERT_TRUE(output.empty());
768 E : }
769 :
770 : // Second test: read an existing stream (the one we just added). Should
771 : // exit without error and return the expected contents (with a trailing
772 : // newline).
773 : {
774 E : CommandLine cmd(pdbstr_path);
775 E : cmd.AppendArg(pdb_arg);
776 E : cmd.AppendArg("-r");
777 E : cmd.AppendArg("-s:foo");
778 E : std::string output;
779 E : ASSERT_TRUE(base::GetAppOutput(cmd, &output));
780 E : ASSERT_EQ(std::string("foo\r\n"), output);
781 E : }
782 :
783 : // Third test: Add another new stream. This should return without error, and
784 : // we should then be able to read the stream using our mechanisms.
785 : {
786 E : base::FilePath bar_txt = temp_dir_.path().Append(L"bar.txt");
787 : file_util::ScopedFILE bar_file(file_util::OpenFile(
788 E : bar_txt, "wb"));
789 E : fprintf(bar_file.get(), "bar");
790 E : bar_file.reset();
791 :
792 E : std::string bar_arg = WideToUTF8(bar_txt.value());
793 E : bar_arg.insert(0, "-i:");
794 :
795 E : CommandLine cmd(pdbstr_path);
796 E : cmd.AppendArg(pdb_arg);
797 E : cmd.AppendArg("-w");
798 E : cmd.AppendArg("-s:bar");
799 E : cmd.AppendArg(bar_arg);
800 E : std::string output;
801 E : ASSERT_TRUE(base::GetAppOutput(cmd, &output));
802 E : ASSERT_TRUE(output.empty());
803 :
804 E : PdbFile pdb_file;
805 E : PdbReader pdb_reader;
806 E : ASSERT_TRUE(pdb_reader.Read(temp_pdb_file_path_, &pdb_file));
807 :
808 : // Get the PDB header stream.
809 : scoped_refptr<PdbStream> header_stream(pdb_file.GetStream(
810 E : kPdbHeaderInfoStream));
811 E : ASSERT_TRUE(header_stream.get() != NULL);
812 :
813 : // Read the existing name-stream map.
814 E : PdbInfoHeader70 pdb_header = {};
815 E : NameStreamMap name_stream_map;
816 : ASSERT_TRUE(ReadHeaderInfoStream(
817 E : header_stream, &pdb_header, &name_stream_map));
818 :
819 : // There should be a 'bar' stream.
820 E : ASSERT_TRUE(name_stream_map.count("bar"));
821 :
822 : // Get the bar stream.
823 : scoped_refptr<PdbStream> bar_stream(pdb_file.GetStream(
824 E : name_stream_map["bar"]));
825 E : ASSERT_TRUE(bar_stream.get() != NULL);
826 :
827 : // Read all of the data and ensure it is as expected.
828 E : bar_stream->Seek(0);
829 E : std::string bar_data;
830 E : bar_data.resize(bar_stream->length());
831 E : ASSERT_TRUE(bar_stream->Read(&bar_data.at(0), bar_data.size()));
832 E : ASSERT_EQ("bar", bar_data);
833 E : }
834 E : }
835 :
836 E : TEST_F(PdbUtilTest, LoadNamedStreamFromPdbFile) {
837 E : PdbReader reader;
838 E : PdbFile pdb_file;
839 : EXPECT_TRUE(reader.Read(
840 : testing::GetOutputRelativePath(testing::kTestDllPdbName),
841 E : &pdb_file));
842 :
843 E : scoped_refptr<PdbStream> stream;
844 : EXPECT_TRUE(LoadNamedStreamFromPdbFile(
845 E : "StreamThatDoesNotExist", &pdb_file, &stream));
846 E : EXPECT_TRUE(stream.get() == NULL);
847 :
848 : // The MSVC toolchain produces a handful of named streams whose existence we
849 : // can rely on.
850 E : EXPECT_TRUE(LoadNamedStreamFromPdbFile("/LinkInfo", &pdb_file, &stream));
851 E : ASSERT_TRUE(stream.get() != NULL);
852 E : }
853 :
854 : } // namespace pdb
|