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