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/pe/new_decomposer.h"
16 :
17 : #include "base/string_split.h"
18 : #include "gtest/gtest.h"
19 : #include "syzygy/block_graph/block_graph_serializer.h"
20 : #include "syzygy/block_graph/typed_block.h"
21 : #include "syzygy/block_graph/unittest_util.h"
22 : #include "syzygy/core/unittest_util.h"
23 : #include "syzygy/pdb/pdb_byte_stream.h"
24 : #include "syzygy/pdb/pdb_file.h"
25 : #include "syzygy/pdb/pdb_reader.h"
26 : #include "syzygy/pdb/pdb_util.h"
27 : #include "syzygy/pe/pe_relinker.h"
28 : #include "syzygy/pe/pe_utils.h"
29 : #include "syzygy/pe/unittest_util.h"
30 :
31 : namespace pe {
32 :
33 : namespace {
34 :
35 : using block_graph::BlockGraph;
36 : using block_graph::ConstTypedBlock;
37 : using core::RelativeAddress;
38 :
39 : const size_t kPointerSize = BlockGraph::Reference::kMaximumSize;
40 :
41 : // Exposes the protected methods for testing.
42 : class TestNewDecomposer : public NewDecomposer {
43 : public:
44 : explicit TestNewDecomposer(const PEFile& image_file)
45 : : NewDecomposer(image_file) {
46 : }
47 :
48 : // Expose as public for testing.
49 : using NewDecomposer::LoadBlockGraphFromPdbStream;
50 : using NewDecomposer::LoadBlockGraphFromPdb;
51 : };
52 :
53 : class NewDecomposerTest : public testing::PELibUnitTest {
54 : typedef testing::PELibUnitTest Super;
55 :
56 : public:
57 E : void SetUp() {
58 E : Super::SetUp();
59 :
60 E : ASSERT_NO_FATAL_FAILURE(CreateTemporaryDir(&temp_dir_));
61 E : }
62 :
63 : FilePath temp_dir_;
64 : };
65 :
66 : } // namespace
67 :
68 E : TEST_F(NewDecomposerTest, MutatorsAndAccessors) {
69 E : FilePath image_path(testing::GetExeRelativePath(testing::kTestDllName));
70 E : FilePath pdb_path(testing::GetExeRelativePath(testing::kTestDllPdbName));
71 :
72 E : PEFile image_file;
73 E : ASSERT_TRUE(image_file.Init(image_path));
74 :
75 E : NewDecomposer decomposer(image_file);
76 E : EXPECT_TRUE(decomposer.pdb_path().empty());
77 E : EXPECT_TRUE(decomposer.parse_debug_info());
78 :
79 E : decomposer.set_pdb_path(pdb_path);
80 E : EXPECT_EQ(pdb_path, decomposer.pdb_path());
81 :
82 E : decomposer.set_parse_debug_info(false);
83 E : EXPECT_FALSE(decomposer.parse_debug_info());
84 E : }
85 :
86 E : TEST_F(NewDecomposerTest, Decompose) {
87 E : FilePath image_path(testing::GetExeRelativePath(testing::kTestDllName));
88 E : PEFile image_file;
89 :
90 E : ASSERT_TRUE(image_file.Init(image_path));
91 :
92 : // Decompose the test image.
93 E : NewDecomposer decomposer(image_file);
94 E : EXPECT_TRUE(decomposer.pdb_path().empty());
95 :
96 E : BlockGraph block_graph;
97 E : ImageLayout image_layout(&block_graph);
98 E : EXPECT_TRUE(decomposer.Decompose(&image_layout));
99 E : EXPECT_FALSE(decomposer.pdb_path().empty());
100 :
101 : // Retrieve and validate the DOS header.
102 : BlockGraph::Block* dos_header_block =
103 E : image_layout.blocks.GetBlockByAddress(RelativeAddress(0));
104 E : ASSERT_TRUE(dos_header_block != NULL);
105 E : ASSERT_TRUE(IsValidDosHeaderBlock(dos_header_block));
106 :
107 : // Retrieve and validate the NT header.
108 : BlockGraph::Block* nt_headers_block =
109 E : GetNtHeadersBlockFromDosHeaderBlock(dos_header_block);
110 E : ASSERT_TRUE(nt_headers_block != NULL);
111 E : ASSERT_TRUE(IsValidNtHeadersBlock(nt_headers_block));
112 :
113 : // There should be some blocks in the graph and in the layout, and the same
114 : // number in the block-graph and image layout.
115 E : EXPECT_LT(0u, block_graph.blocks().size());
116 E : EXPECT_LT(0u, image_layout.blocks.size());
117 E : EXPECT_EQ(block_graph.blocks().size(), image_layout.blocks.size());
118 :
119 E : EXPECT_EQ(6u, block_graph.sections().size());
120 E : EXPECT_EQ(6u, image_layout.sections.size());
121 :
122 E : EXPECT_EQ(".text", image_layout.sections[0].name);
123 E : EXPECT_NE(0U, image_layout.sections[0].addr.value());
124 E : EXPECT_NE(0U, image_layout.sections[0].size);
125 E : EXPECT_NE(0U, image_layout.sections[0].data_size);
126 : EXPECT_EQ(IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ,
127 E : image_layout.sections[0].characteristics);
128 :
129 E : EXPECT_EQ(".rdata", image_layout.sections[1].name);
130 E : EXPECT_NE(0U, image_layout.sections[1].addr.value());
131 E : EXPECT_NE(0U, image_layout.sections[1].size);
132 E : EXPECT_NE(0U, image_layout.sections[1].data_size);
133 : EXPECT_EQ(IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ,
134 E : image_layout.sections[1].characteristics);
135 :
136 E : EXPECT_EQ(".data", image_layout.sections[2].name);
137 E : EXPECT_NE(0U, image_layout.sections[2].addr.value());
138 E : EXPECT_NE(0U, image_layout.sections[2].size);
139 E : EXPECT_NE(0U, image_layout.sections[2].data_size);
140 : EXPECT_EQ(
141 : IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE,
142 E : image_layout.sections[2].characteristics);
143 :
144 E : EXPECT_EQ(".tls", image_layout.sections[3].name);
145 E : EXPECT_NE(0U, image_layout.sections[3].addr.value());
146 E : EXPECT_NE(0U, image_layout.sections[3].size);
147 E : EXPECT_NE(0U, image_layout.sections[3].data_size);
148 : EXPECT_EQ(
149 : IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE,
150 E : image_layout.sections[3].characteristics);
151 :
152 E : EXPECT_EQ(".rsrc", image_layout.sections[4].name);
153 E : EXPECT_NE(0U, image_layout.sections[4].addr.value());
154 E : EXPECT_NE(0U, image_layout.sections[4].size);
155 E : EXPECT_NE(0U, image_layout.sections[4].data_size);
156 : EXPECT_EQ(IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ,
157 E : image_layout.sections[4].characteristics);
158 :
159 E : EXPECT_EQ(".reloc", image_layout.sections[5].name);
160 E : EXPECT_NE(0U, image_layout.sections[5].addr.value());
161 E : EXPECT_NE(0U, image_layout.sections[5].size);
162 E : EXPECT_NE(0U, image_layout.sections[5].data_size);
163 : EXPECT_EQ(IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE |
164 E : IMAGE_SCN_MEM_READ, image_layout.sections[5].characteristics);
165 :
166 : // We expect the ImageLayout sections to agree with the BlockGraph sections
167 : // in number, id, name and characteristics.
168 E : EXPECT_EQ(block_graph.sections().size(), image_layout.sections.size());
169 E : for (size_t i = 0; i < image_layout.sections.size(); ++i) {
170 : const BlockGraph::Section* section =
171 E : block_graph.GetSectionById(i);
172 E : ASSERT_TRUE(section != NULL);
173 E : EXPECT_EQ(section->id(), i);
174 E : EXPECT_EQ(section->name(), image_layout.sections[i].name);
175 : EXPECT_EQ(section->characteristics(),
176 E : image_layout.sections[i].characteristics);
177 E : }
178 :
179 : // We expect every block to be associated with a section, and only two blocks
180 : // should not be assigned to a section--the two header blocks.
181 E : size_t non_section_blocks = 0;
182 : BlockGraph::BlockMap::const_iterator it =
183 E : block_graph.blocks().begin();
184 E : for (; it != block_graph.blocks().end(); ++it) {
185 E : const BlockGraph::Block& block = it->second;
186 E : if (block.section() == BlockGraph::kInvalidSectionId) {
187 E : ++non_section_blocks;
188 E : } else {
189 : // If this is not a header block, it should refer to a valid section id.
190 E : EXPECT_LE(0u, block.section());
191 E : EXPECT_LT(block.section(), block_graph.sections().size());
192 : }
193 E : }
194 E : EXPECT_EQ(2u, non_section_blocks);
195 :
196 : // Every byte of each section must be accounted for by all of the non-header
197 : // blocks.
198 E : size_t section_blocks = 0;
199 E : for (size_t i = 0; i < image_layout.sections.size(); ++i) {
200 : BlockGraph::AddressSpace::RangeMapConstIterPair it_pair =
201 : image_layout.blocks.GetIntersectingBlocks(
202 : image_layout.sections[i].addr,
203 E : image_layout.sections[i].size);
204 :
205 : // Make sure the first iterator is dereferenceable.
206 E : ASSERT_TRUE(it_pair.first != image_layout.blocks.end());
207 :
208 : // The first and last iterators should not be the same.
209 E : EXPECT_TRUE(it_pair.first != it_pair.second);
210 :
211 : // The first iterator should start at the beginning of the section.
212 E : EXPECT_EQ(image_layout.sections[i].addr, it_pair.first->first.start());
213 :
214 : // Ensure the blocks are contiguous, and count the number of blocks as we
215 : // go.
216 E : BlockGraph::AddressSpace::RangeMapConstIter it_old = it_pair.first;
217 E : BlockGraph::AddressSpace::RangeMapConstIter it_cur = it_pair.first;
218 E : ++it_cur;
219 E : ++section_blocks;
220 E : while (it_cur != it_pair.second) {
221 E : EXPECT_EQ(it_old->first.end(), it_cur->first.start());
222 E : it_old = it_cur;
223 E : ++it_cur;
224 E : ++section_blocks;
225 E : }
226 :
227 : // Make sure the last block perfectly covers the section.
228 : EXPECT_EQ(image_layout.sections[i].addr + image_layout.sections[i].size,
229 E : it_old->first.end());
230 E : }
231 :
232 : // All of the blocks should have been covered, save the 2 header blocks.
233 E : EXPECT_EQ(section_blocks + 2, image_layout.blocks.size());
234 :
235 : // Make sure that all bracketed COFF groups have been parsed. There are 8
236 : // of them that we currently know of:
237 : // .CRT$XCA -> .CRT$XCZ: C initializers
238 : // .CRT$XIA -> .CRT$XLZ: C++ initializers
239 : // .CRT$XLA -> .CRT$XLZ: TLS callbacks
240 : // .CRT$XPA -> .CRT$XPZ: CRT pre-termination functions.
241 : // .CRT$XTA -> .CRT$XTZ: CRT termination functions.
242 : // .rtc$IAA -> .rtc$IZZ: Run-time checking initializers.
243 : // .rtc$TAA -> .rtc$TZZ: Run-time checking termination functions.
244 : // .tls -> .tls$ZZZ: TLS data.
245 E : size_t coff_group_blocks = 0;
246 E : it = block_graph.blocks().begin();
247 E : for (; it != block_graph.blocks().end(); ++it) {
248 E : const BlockGraph::Block& block = it->second;
249 E : if (block.attributes() & BlockGraph::COFF_GROUP)
250 E : ++coff_group_blocks;
251 E : }
252 E : EXPECT_EQ(8u, coff_group_blocks);
253 E : }
254 :
255 E : TEST_F(NewDecomposerTest, DecomposeFailsWithNonexistentPdb) {
256 E : FilePath image_path(testing::GetExeRelativePath(testing::kTestDllName));
257 E : PEFile image_file;
258 :
259 E : ASSERT_TRUE(image_file.Init(image_path));
260 :
261 E : NewDecomposer decomposer(image_file);
262 E : decomposer.set_pdb_path(testing::GetExeRelativePath(L"nonexistent.pdb"));
263 :
264 E : BlockGraph block_graph;
265 E : ImageLayout image_layout(&block_graph);
266 E : EXPECT_FALSE(decomposer.Decompose(&image_layout));
267 E : }
268 :
269 E : TEST_F(NewDecomposerTest, LabelsAndAttributes) {
270 E : FilePath image_path(testing::GetExeRelativePath(testing::kTestDllName));
271 E : PEFile image_file;
272 :
273 E : ASSERT_TRUE(image_file.Init(image_path));
274 :
275 : // Decompose the test image and look at the result.
276 E : NewDecomposer decomposer(image_file);
277 E : BlockGraph block_graph;
278 E : ImageLayout image_layout(&block_graph);
279 E : ASSERT_TRUE(decomposer.Decompose(&image_layout));
280 :
281 : // Locate various specific function blocks in the block-graph.
282 E : const BlockGraph::Block* dll_main_block = NULL;
283 E : const BlockGraph::Block* func_with_inl_asm_block = NULL;
284 E : const BlockGraph::Block* strchr_block = NULL;
285 E : const BlockGraph::Block* imp_load_block = NULL;
286 : {
287 : BlockGraph::BlockMap::const_iterator it =
288 E : block_graph.blocks().begin();
289 E : for (; it != block_graph.blocks().end(); ++it) {
290 E : const BlockGraph::Block* block = &(it->second);
291 :
292 E : BlockGraph::Label label;
293 E : if (!block->GetLabel(0, &label))
294 E : continue;
295 E : std::vector<std::string> names;
296 : base::SplitStringUsingSubstr(label.name(), NewDecomposer::kLabelNameSep,
297 E : &names);
298 :
299 E : base::StringPiece block_name(block->name());
300 :
301 : if (std::find(names.begin(), names.end(), "DllMain") != names.end() &&
302 E : block_name.ends_with("\\test_dll.obj")) {
303 E : ASSERT_TRUE(dll_main_block == NULL);
304 E : dll_main_block = &it->second;
305 E : } else if (std::find(names.begin(), names.end(),
306 : "FunctionWithInlineAssembly") != names.end() &&
307 E : block_name.ends_with("\\test_dll.obj")) {
308 E : ASSERT_TRUE(func_with_inl_asm_block == NULL);
309 E : func_with_inl_asm_block = &it->second;
310 E : } else if (std::find(names.begin(), names.end(),
311 : "found_bx") != names.end() &&
312 E : block_name.ends_with("\\strchr.obj")) {
313 E : ASSERT_TRUE(strchr_block == NULL);
314 E : strchr_block = &it->second;
315 E : } else if (std::find(names.begin(), names.end(),
316 E : "__imp_load_CoInitialize") != names.end()) {
317 E : ASSERT_TRUE(imp_load_block == NULL);
318 E : imp_load_block = &it->second;
319 : }
320 E : }
321 : }
322 E : ASSERT_TRUE(dll_main_block != NULL);
323 E : ASSERT_TRUE(func_with_inl_asm_block != NULL);
324 E : ASSERT_TRUE(strchr_block != NULL);
325 E : ASSERT_TRUE(imp_load_block != NULL);
326 :
327 E : ASSERT_NE(0UL, imp_load_block->attributes() & BlockGraph::THUNK);
328 :
329 : // TODO(chrisha): When alignment calculations are complete, re-enable this
330 : // test.
331 : // DllMain has a jump table so it should have pointer alignment.
332 : //ASSERT_EQ(kPointerSize, dll_main_block->alignment());
333 :
334 : // Validate that the FunctionWithInlineAssembly block has the appropriate
335 : // attributes.
336 : ASSERT_TRUE(func_with_inl_asm_block->attributes() &
337 E : BlockGraph::HAS_INLINE_ASSEMBLY);
338 :
339 : // Validate that the strchr block has the appropriate attributes.
340 : ASSERT_TRUE(strchr_block->attributes() &
341 E : BlockGraph::BUILT_BY_UNSUPPORTED_COMPILER);
342 :
343 : // Validate that the DllMain block has the expected population of labels.
344 E : EXPECT_EQ(32, dll_main_block->labels().size());
345 :
346 E : std::map<BlockGraph::LabelAttributes, size_t> label_attr_counts;
347 : {
348 : BlockGraph::Block::LabelMap::const_iterator it =
349 E : dll_main_block->labels().begin();
350 E : for (; it != dll_main_block->labels().end(); ++it) {
351 E : BlockGraph::LabelAttributes attr_mask = 1;
352 E : for (; attr_mask != BlockGraph::LABEL_ATTRIBUTES_MAX; attr_mask <<= 1) {
353 E : if (it->second.has_attributes(attr_mask))
354 E : label_attr_counts[attr_mask]++;
355 E : }
356 E : }
357 : }
358 :
359 E : EXPECT_EQ(19, label_attr_counts[BlockGraph::CODE_LABEL]);
360 E : EXPECT_EQ(10, label_attr_counts[BlockGraph::CALL_SITE_LABEL]);
361 E : EXPECT_EQ(5, label_attr_counts[BlockGraph::DATA_LABEL]);
362 E : EXPECT_EQ(3, label_attr_counts[BlockGraph::JUMP_TABLE_LABEL]);
363 E : EXPECT_EQ(2, label_attr_counts[BlockGraph::CASE_TABLE_LABEL]);
364 E : EXPECT_EQ(1, label_attr_counts[BlockGraph::DEBUG_START_LABEL]);
365 E : EXPECT_EQ(1, label_attr_counts[BlockGraph::DEBUG_END_LABEL]);
366 E : }
367 :
368 : namespace {
369 :
370 : void GetNtHeadersBlock(const BlockGraph::Block* dos_header_block,
371 E : BlockGraph::Block** out_nt_headers_block) {
372 E : DCHECK(out_nt_headers_block != NULL);
373 :
374 E : ConstTypedBlock<IMAGE_DOS_HEADER> dos_header;
375 E : ASSERT_TRUE(dos_header.Init(0, dos_header_block));
376 E : ConstTypedBlock<IMAGE_NT_HEADERS> nt_headers;
377 E : ASSERT_TRUE(dos_header.Dereference(dos_header->e_lfanew, &nt_headers));
378 E : ASSERT_TRUE(nt_headers.block() != NULL);
379 E : *out_nt_headers_block = const_cast<BlockGraph::Block*>(nt_headers.block());
380 E : }
381 :
382 : // This test fixture class contains all the tests that need files generated by
383 : // the relinker (the new image and its corresponding PDB).
384 : class NewDecomposerAfterRelinkTest : public NewDecomposerTest {
385 : typedef NewDecomposerTest Super;
386 :
387 : public:
388 E : virtual void SetUp() OVERRIDE {
389 E : Super::SetUp();
390 E : }
391 :
392 E : void Relink(bool compress_pdb) {
393 : // Initialize a relinker and generate a pdb that contains a block-graph
394 : // stream.
395 E : relinked_dll_ = temp_dir_.Append(testing::kTestDllName);
396 E : relinked_pdb_ = temp_dir_.Append(testing::kTestDllPdbName);
397 :
398 : relinker_.set_input_path(testing::GetExeRelativePath(
399 E : testing::kTestDllName));
400 : relinker_.set_input_pdb_path(testing::GetExeRelativePath(
401 E : testing::kTestDllPdbName));
402 E : relinker_.set_allow_overwrite(true);
403 E : relinker_.set_augment_pdb(true);
404 E : relinker_.set_compress_pdb(compress_pdb);
405 E : relinker_.set_output_path(relinked_dll_);
406 E : relinker_.set_output_pdb_path(relinked_pdb_);
407 E : ASSERT_TRUE(relinker_.Init());
408 E : ASSERT_TRUE(relinker_.Relink());
409 E : }
410 :
411 : // Given a decomposed image this checks its NT headers against those
412 : // contained in the transformed image stored in the relinker.
413 E : void ReconcileNtHeaders(ImageLayout* image_layout) {
414 E : DCHECK(image_layout != NULL);
415 :
416 : // Get the NT headers block associated with the in-memory representation of
417 : // the relinked image.
418 E : BlockGraph::Block* nt1 = NULL;
419 E : ASSERT_NO_FATAL_FAILURE(GetNtHeadersBlock(relinker_.dos_header_block(),
420 : &nt1));
421 E : ASSERT_TRUE(nt1 != NULL);
422 :
423 : // Get the NT headers block associated with the decomposition just performed
424 : // on the relinked image.
425 : BlockGraph::Block* dos_header_block =
426 E : image_layout->blocks.GetBlockByAddress(core::RelativeAddress(0));
427 E : ASSERT_TRUE(dos_header_block != NULL);
428 E : BlockGraph::Block* nt2 = NULL;
429 E : ASSERT_NO_FATAL_FAILURE(GetNtHeadersBlock(dos_header_block, &nt2));
430 E : ASSERT_TRUE(nt2 != NULL);
431 :
432 : // The NT headers don't compare equal because things like the timestamp and
433 : // checksum are filled out post-transform. We copy the old NT headers into
434 : // the new image so that we can do a simple comparison afterwards.
435 E : ASSERT_EQ(nt1->data_size(), nt2->data_size());
436 E : nt1->SetData(nt2->data(), nt2->data_size());
437 E : }
438 :
439 : // Used to ensure that round-trip decomposition works (where the image is not
440 : // decomposed, but rather deserialized from the PDB).
441 E : void LoadRedecompositionData(bool compressed) {
442 E : ASSERT_NO_FATAL_FAILURE(Relink(compressed));
443 :
444 E : PEFile image_file;
445 E : ASSERT_TRUE(image_file.Init(relinked_dll_));
446 :
447 : // Decompose the test image and look at the result.
448 E : NewDecomposer decomposer(image_file);
449 E : BlockGraph block_graph;
450 E : ImageLayout image_layout(&block_graph);
451 :
452 E : ASSERT_TRUE(decomposer.Decompose(&image_layout));
453 :
454 : // Certain data is written to the NT headers post-transform (checksum), so
455 : // it's not reflected in the relinker's block-graph. We reconcile the
456 : // headers prior to doing the comparison.
457 E : ASSERT_NO_FATAL_FAILURE(ReconcileNtHeaders(&image_layout));
458 :
459 : // Ensure that the post-relink block-graph and the deserialized one from the
460 : // PDB are the same.
461 E : block_graph::BlockGraphSerializer bgs;
462 E : ASSERT_TRUE(::testing::BlockGraphsEqual(relinker_.block_graph(),
463 : block_graph,
464 : bgs));
465 E : }
466 :
467 : PERelinker relinker_;
468 : FilePath relinked_dll_;
469 : FilePath relinked_pdb_;
470 : };
471 :
472 : } // namespace
473 :
474 E : TEST_F(NewDecomposerAfterRelinkTest, LoadRedecompositionDataUncompressed) {
475 E : ASSERT_NO_FATAL_FAILURE(LoadRedecompositionData(false));
476 E : }
477 :
478 E : TEST_F(NewDecomposerAfterRelinkTest, LoadRedecompositionDataCompressed) {
479 E : ASSERT_NO_FATAL_FAILURE(LoadRedecompositionData(true));
480 E : }
481 :
482 E : TEST_F(NewDecomposerAfterRelinkTest, FailToLoadBlockGraphWithInvalidVersion) {
483 E : ASSERT_NO_FATAL_FAILURE(Relink(true));
484 :
485 : // Get the block-graph stream from the PDB and change the version of it.
486 :
487 : // Get the stream.
488 E : pdb::PdbFile pdb_file;
489 E : pdb::PdbReader pdb_reader;
490 E : pdb_reader.Read(relinked_pdb_, &pdb_file);
491 E : scoped_refptr<pdb::PdbStream> block_graph_stream;
492 : EXPECT_TRUE(pdb::LoadNamedStreamFromPdbFile(pdb::kSyzygyBlockGraphStreamName,
493 : &pdb_file,
494 E : &block_graph_stream));
495 :
496 : // Create a copy of the stream. We need to do this to have a stream that we
497 : // can modify.
498 E : scoped_refptr<pdb::PdbByteStream> new_stream = new pdb::PdbByteStream();
499 E : ASSERT_TRUE(new_stream->Init(block_graph_stream.get()));
500 E : block_graph_stream = new_stream.get();
501 : scoped_refptr<pdb::WritablePdbStream> block_graph_writer =
502 E : block_graph_stream->GetWritablePdbStream();
503 E : ASSERT_TRUE(block_graph_writer.get() != NULL);
504 :
505 : // Change the version of the stream.
506 E : block_graph_writer->set_pos(0);
507 E : block_graph_writer->Write(pdb::kSyzygyBlockGraphStreamVersion + 1);
508 :
509 E : BlockGraph block_graph;
510 E : ImageLayout image_layout(&block_graph);
511 :
512 : // We've invalided the version previously so this test should fail.
513 E : PEFile image_file;
514 E : ASSERT_TRUE(image_file.Init(relinked_dll_));
515 : ASSERT_FALSE(TestNewDecomposer::LoadBlockGraphFromPdbStream(
516 E : image_file, block_graph_stream.get(), &image_layout));
517 E : }
518 :
519 : } // namespace pe
|