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/block_graph/block_graph_serializer.h"
16 :
17 : #include "base/bind.h"
18 : #include "gtest/gtest.h"
19 : #include "syzygy/block_graph/unittest_util.h"
20 : #include "syzygy/core/serialization.h"
21 :
22 : namespace block_graph {
23 :
24 : namespace {
25 :
26 : class TestBlockGraphSerializer : public BlockGraphSerializer {
27 : public:
28 : using BlockGraphSerializer::SaveUint32;
29 : using BlockGraphSerializer::LoadUint32;
30 : using BlockGraphSerializer::SaveInt32;
31 : using BlockGraphSerializer::LoadInt32;
32 : };
33 :
34 : class BlockGraphSerializerTest : public ::testing::Test {
35 : public:
36 E : BlockGraphSerializerTest() : block_data_loaded_by_callback_(0) { }
37 :
38 E : virtual void SetUp() override {}
39 :
40 E : void InitOutArchive() {
41 E : v_.clear();
42 E : os_.reset(core::CreateByteOutStream(std::back_inserter(v_)));
43 : oa_.reset(new core::NativeBinaryOutArchive(
44 E : os_.get()));
45 E : }
46 :
47 E : void InitInArchive() {
48 E : is_.reset(core::CreateByteInStream(v_.begin(), v_.end()));
49 : ia_.reset(new core::NativeBinaryInArchive(
50 E : is_.get()));
51 E : }
52 :
53 E : void InitBlockGraph() {
54 E : BlockGraph::Section* text = bg_.AddSection(".text", 1 | 4);
55 E : BlockGraph::Section* data = bg_.AddSection(".data", 2);
56 E : BlockGraph::Section* rdata = bg_.AddSection(".rdata", 2 | 4);
57 :
58 E : BlockGraph::Block* c1 = bg_.AddBlock(BlockGraph::CODE_BLOCK, 20, "code1");
59 E : BlockGraph::Block* c2 = bg_.AddBlock(BlockGraph::CODE_BLOCK, 16, "code2");
60 E : BlockGraph::Block* d1 = bg_.AddBlock(BlockGraph::DATA_BLOCK, 20, "data1");
61 E : BlockGraph::Block* rd1 = bg_.AddBlock(BlockGraph::DATA_BLOCK, 16, "rdata1");
62 E : BlockGraph::Block* rd2 = bg_.AddBlock(BlockGraph::DATA_BLOCK, 16, "rdata2");
63 :
64 E : c1->set_section(text->id());
65 E : c2->set_section(text->id());
66 E : d1->set_section(data->id());
67 E : rd1->set_section(rdata->id());
68 E : rd2->set_section(rdata->id());
69 :
70 : // Set compiland name.
71 E : c1->set_compiland_name("c.o");
72 E : c2->set_compiland_name("c.o");
73 E : d1->set_compiland_name("d.o");
74 E : rd1->set_compiland_name("d.o");
75 E : rd2->set_compiland_name("d.o");
76 :
77 : // Set up alignments and paddings.
78 E : c2->set_alignment(16);
79 E : c2->set_alignment_offset(-4);
80 E : c2->set_padding_before(1);
81 E : d1->set_alignment(16);
82 E : rd1->set_alignment(16);
83 E : rd1->set_alignment(16);
84 :
85 : // Some of the blocks own their own data, some don't. One has no data at
86 : // all.
87 E : c1->SetData(kCode1Data, sizeof(kCode1Data));
88 E : c2->CopyData(sizeof(kCode2Data), kCode2Data);
89 E : d1->SetData(kData1Data, sizeof(kData1Data));
90 E : rd1->CopyData(sizeof(kRdata1Data), kRdata1Data);
91 :
92 : // Given them all source ranges.
93 : c1->source_ranges().Push(BlockGraph::Block::DataRange(0, 20),
94 E : BlockGraph::Block::SourceRange(core::RelativeAddress(0), 20));
95 : c2->source_ranges().Push(BlockGraph::Block::DataRange(0, 16),
96 E : BlockGraph::Block::SourceRange(core::RelativeAddress(36), 48));
97 : d1->source_ranges().Push(BlockGraph::Block::DataRange(0, 20),
98 E : BlockGraph::Block::SourceRange(core::RelativeAddress(512), 532));
99 : rd1->source_ranges().Push(BlockGraph::Block::DataRange(0, 16),
100 E : BlockGraph::Block::SourceRange(core::RelativeAddress(1024), 1040));
101 : rd2->source_ranges().Push(BlockGraph::Block::DataRange(0, 16),
102 E : BlockGraph::Block::SourceRange(core::RelativeAddress(1040), 1056));
103 :
104 : // Set up labels.
105 : c1->SetLabel(0, BlockGraph::Label("code1",
106 E : BlockGraph::CODE_LABEL | BlockGraph::DEBUG_START_LABEL));
107 E : c1->SetLabel(8, BlockGraph::Label("label", BlockGraph::CODE_LABEL));
108 E : c1->SetLabel(11, BlockGraph::Label("debug", BlockGraph::DEBUG_END_LABEL));
109 : c1->SetLabel(12, BlockGraph::Label("jump",
110 E : BlockGraph::DATA_LABEL | BlockGraph::JUMP_TABLE_LABEL));
111 E : c2->SetLabel(0, BlockGraph::Label("code1", BlockGraph::CODE_LABEL));
112 : c2->SetLabel(8, BlockGraph::Label("jump",
113 E : BlockGraph::DATA_LABEL | BlockGraph::JUMP_TABLE_LABEL));
114 : c2->SetLabel(12, BlockGraph::Label("case",
115 E : BlockGraph::DATA_LABEL | BlockGraph::CASE_TABLE_LABEL));
116 E : d1->SetLabel(0, BlockGraph::Label("data", BlockGraph::DATA_LABEL));
117 :
118 : // Set up some references.
119 : c1->SetReference(4, BlockGraph::Reference(
120 E : BlockGraph::ABSOLUTE_REF, 4, d1, 0, 0));
121 : c1->SetReference(12, BlockGraph::Reference(
122 E : BlockGraph::ABSOLUTE_REF, 4, c2, 0, 0));
123 : c2->SetReference(8, BlockGraph::Reference(
124 E : BlockGraph::ABSOLUTE_REF, 4, c1, 0, 0));
125 : d1->SetReference(0, BlockGraph::Reference(
126 E : BlockGraph::ABSOLUTE_REF, 4, rd1, 0, 0));
127 : rd1->SetReference(0, BlockGraph::Reference(
128 E : BlockGraph::ABSOLUTE_REF, 4, rd2, 0, 0));
129 E : }
130 :
131 E : void InitBlockDataCallbacks1() {
132 : s_.set_load_block_data_callback(
133 : base::Bind(&BlockGraphSerializerTest::LoadBlockDataCallback1,
134 E : base::Unretained(this)));
135 E : }
136 :
137 E : void InitBlockDataCallbacks2() {
138 : s_.set_save_block_data_callback(
139 : base::Bind(&BlockGraphSerializerTest::SaveBlockDataCallback2,
140 E : base::Unretained(this)));
141 : s_.set_load_block_data_callback(
142 : base::Bind(&BlockGraphSerializerTest::LoadBlockDataCallback2,
143 E : base::Unretained(this)));
144 E : }
145 :
146 : bool LoadBlockDataCallback1(bool need_to_set_data,
147 : size_t size,
148 : BlockGraph::Block* block,
149 E : core::InArchive* in_archive) {
150 E : DCHECK(block != NULL);
151 E : DCHECK(in_archive != NULL);
152 :
153 : // We only have work to do if the data is not explicitly saved.
154 E : if (!need_to_set_data)
155 E : return true;
156 :
157 E : block_data_loaded_by_callback_++;
158 :
159 E : EXPECT_LT(0u, size);
160 E : if (size == 0)
161 i : return false;
162 :
163 E : EXPECT_EQ(1u, block->source_ranges().size());
164 E : if (block->source_ranges().size() != 1)
165 i : return false;
166 :
167 : // We use the source range to determine which block gets which data, as the
168 : // name is not always present.
169 E : size_t data_size = 0;
170 E : const uint8* data = NULL;
171 E : switch (block->source_ranges().range_pairs()[0].second.start().value()) {
172 : case 0:
173 E : data = kCode1Data;
174 E : data_size = sizeof(kCode1Data);
175 E : break;
176 :
177 : case 36:
178 E : data = kCode2Data;
179 E : data_size = sizeof(kCode2Data);
180 E : break;
181 :
182 : case 512:
183 E : data = kData1Data;
184 E : data_size = sizeof(kData1Data);
185 E : break;
186 :
187 : case 1024:
188 E : data = kRdata1Data;
189 E : data_size = sizeof(kRdata1Data);
190 : break;
191 :
192 : default:
193 : break;
194 : }
195 :
196 E : EXPECT_TRUE(data != NULL);
197 E : EXPECT_EQ(data_size, size);
198 E : if (data == NULL || data_size != size)
199 i : return false;
200 :
201 E : block->SetData(data, data_size);
202 E : return true;
203 E : }
204 :
205 : bool SaveBlockDataCallback2(bool data_already_saved,
206 : const BlockGraph::Block& block,
207 E : core::OutArchive* out_archive) {
208 E : DCHECK(out_archive != NULL);
209 :
210 : // If the data is already saved, do nothing.
211 E : if (data_already_saved)
212 E : return true;
213 :
214 E : EXPECT_LT(0u, block.data_size());
215 E : if (block.data_size() == 0)
216 i : return false;
217 :
218 : // Determine which data buffer the block holds, and save an index value
219 : // representing it.
220 E : char data_index = -1;
221 E : if (memcmp(kCode1Data, block.data(), block.data_size()) == 0)
222 E : data_index = 0;
223 E : else if (memcmp(kCode2Data, block.data(), block.data_size()) == 0)
224 E : data_index = 1;
225 E : else if (memcmp(kData1Data, block.data(), block.data_size()) == 0)
226 E : data_index = 2;
227 E : else if (memcmp(kRdata1Data, block.data(), block.data_size()) == 0)
228 E : data_index = 3;
229 :
230 E : EXPECT_NE(-1, data_index);
231 E : if (data_index == -1)
232 i : return false;
233 :
234 E : if (!out_archive->Save(data_index))
235 i : return false;
236 :
237 E : return true;
238 E : }
239 :
240 : bool LoadBlockDataCallback2(bool need_to_set_data,
241 : size_t size,
242 : BlockGraph::Block* block,
243 E : core::InArchive* in_archive) {
244 E : DCHECK(block != NULL);
245 E : DCHECK(in_archive != NULL);
246 :
247 : // We only have work to do if the data is not explicitly saved.
248 E : if (!need_to_set_data)
249 E : return true;
250 :
251 E : block_data_loaded_by_callback_++;
252 :
253 E : EXPECT_LT(0u, size);
254 E : if (size == 0)
255 i : return false;
256 :
257 E : char data_index = -1;
258 E : if (!in_archive->Load(&data_index))
259 i : return false;
260 :
261 E : EXPECT_LE(0, data_index);
262 E : EXPECT_GT(4, data_index);
263 :
264 : static const uint8* kData[] = {
265 : kCode1Data, kCode2Data, kData1Data, kRdata1Data };
266 E : block->SetData(kData[data_index], size);
267 :
268 E : return true;
269 E : }
270 :
271 : enum InitCallbacksType {
272 : eNoBlockDataCallbacks,
273 : eInitBlockDataCallbacks1,
274 : eInitBlockDataCallbacks2
275 : };
276 :
277 : void TestRoundTrip(BlockGraphSerializer::DataMode data_mode,
278 : BlockGraphSerializer::Attributes attributes,
279 : InitCallbacksType init_callback,
280 E : size_t expected_block_data_loaded_by_callback) {
281 E : InitBlockGraph();
282 E : InitOutArchive();
283 :
284 E : s_.set_data_mode(data_mode);
285 E : s_.set_attributes(attributes);
286 :
287 : // Initialize the callbacks.
288 E : switch (init_callback) {
289 : case eInitBlockDataCallbacks1: {
290 E : InitBlockDataCallbacks1();
291 E : break;
292 : }
293 :
294 : case eInitBlockDataCallbacks2: {
295 E : InitBlockDataCallbacks2();
296 : break;
297 : }
298 :
299 : case eNoBlockDataCallbacks:
300 : default:
301 : // Do nothing.
302 : break;
303 : }
304 :
305 E : ASSERT_TRUE(s_.Save(bg_, oa_.get()));
306 E : ASSERT_LT(0u, v_.size());
307 :
308 E : InitInArchive();
309 :
310 E : BlockGraph bg;
311 E : ASSERT_TRUE(s_.Load(&bg, ia_.get()));
312 E : ASSERT_EQ(data_mode, s_.data_mode());
313 E : ASSERT_EQ(attributes, s_.attributes());
314 E : ASSERT_EQ(expected_block_data_loaded_by_callback,
315 : block_data_loaded_by_callback_);
316 :
317 E : ASSERT_TRUE(testing::BlockGraphsEqual(bg_, bg, s_));
318 E : }
319 :
320 : TestBlockGraphSerializer s_;
321 :
322 : // A block-graph.
323 : BlockGraph bg_;
324 :
325 : // Streams and archives.
326 : std::vector<uint8> v_;
327 : scoped_ptr<core::OutStream> os_;
328 : scoped_ptr<core::InStream> is_;
329 : scoped_ptr<core::OutArchive> oa_;
330 : scoped_ptr<core::InArchive> ia_;
331 :
332 : static const uint8 kCode1Data[16];
333 : static const uint8 kCode2Data[16];
334 : static const uint8 kData1Data[16];
335 : static const uint8 kRdata1Data[16];
336 :
337 : size_t block_data_loaded_by_callback_;
338 : };
339 :
340 : const uint8 BlockGraphSerializerTest::kCode1Data[16] = {
341 : 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
342 : const uint8 BlockGraphSerializerTest::kCode2Data[16] = {
343 : 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5 };
344 : const uint8 BlockGraphSerializerTest::kData1Data[16] = {
345 : 10, 30, 45, 63, 20, 23, 67, 20, 32, 40, 50, 10, 15, 10, 18, 19 };
346 : const uint8 BlockGraphSerializerTest::kRdata1Data[16] = {
347 : 28, 28, 29, 30, 56, 28, 23, 78, 19, 99, 10, 10, 23, 54, 54, 12 };
348 :
349 : } // namespace
350 :
351 E : TEST_F(BlockGraphSerializerTest, Construction) {
352 E : ASSERT_EQ(BlockGraphSerializer::DEFAULT_DATA_MODE, s_.data_mode());
353 E : ASSERT_EQ(BlockGraphSerializer::DEFAULT_ATTRIBUTES, s_.data_mode());
354 E : }
355 :
356 E : TEST_F(BlockGraphSerializerTest, SetDataMode) {
357 E : ASSERT_EQ(BlockGraphSerializer::DEFAULT_DATA_MODE, s_.data_mode());
358 :
359 E : s_.set_data_mode(BlockGraphSerializer::OUTPUT_NO_DATA);
360 E : ASSERT_EQ(BlockGraphSerializer::OUTPUT_NO_DATA, s_.data_mode());
361 :
362 E : s_.set_data_mode(BlockGraphSerializer::OUTPUT_ALL_DATA);
363 E : ASSERT_EQ(BlockGraphSerializer::OUTPUT_ALL_DATA, s_.data_mode());
364 E : }
365 :
366 E : TEST_F(BlockGraphSerializerTest, AddAttributes) {
367 E : ASSERT_EQ(0u, s_.attributes());
368 :
369 E : s_.add_attributes(1);
370 E : ASSERT_EQ(1u, s_.attributes());
371 :
372 E : s_.add_attributes(2 | 4);
373 E : ASSERT_EQ(1u | 2u | 4u, s_.attributes());
374 E : }
375 :
376 E : TEST_F(BlockGraphSerializerTest, ClearAttributes) {
377 E : ASSERT_EQ(0u, s_.attributes());
378 :
379 E : s_.add_attributes(1 | 2);
380 E : ASSERT_EQ(1u | 2u, s_.attributes());
381 :
382 E : s_.clear_attributes(2);
383 E : ASSERT_EQ(1u, s_.attributes());
384 E : }
385 :
386 E : TEST_F(BlockGraphSerializerTest, SetAttributes) {
387 E : ASSERT_EQ(0u, s_.attributes());
388 :
389 E : s_.set_attributes(1 | 2);
390 E : ASSERT_EQ(1u | 2u, s_.attributes());
391 :
392 E : s_.set_attributes(4 | 8);
393 E : ASSERT_EQ(4u | 8u, s_.attributes());
394 E : }
395 :
396 E : TEST_F(BlockGraphSerializerTest, HasAttributes) {
397 E : ASSERT_EQ(0u, s_.attributes());
398 :
399 E : s_.set_attributes(1 | 2);
400 E : ASSERT_EQ(1u | 2u, s_.attributes());
401 :
402 E : ASSERT_TRUE(s_.has_attributes(1));
403 E : ASSERT_TRUE(s_.has_attributes(2));
404 E : ASSERT_TRUE(s_.has_attributes(1 | 2));
405 E : ASSERT_FALSE(s_.has_attributes(1 | 2 | 4));
406 E : }
407 :
408 E : TEST_F(BlockGraphSerializerTest, HasAnyAttributes) {
409 E : ASSERT_EQ(0u, s_.attributes());
410 :
411 E : s_.set_attributes(1 | 2);
412 E : ASSERT_EQ(1u | 2u, s_.attributes());
413 :
414 E : ASSERT_TRUE(s_.has_any_attributes(1));
415 E : ASSERT_TRUE(s_.has_any_attributes(2));
416 E : ASSERT_TRUE(s_.has_any_attributes(1 | 2 | 4));
417 E : ASSERT_FALSE(s_.has_any_attributes(4 | 8));
418 E : }
419 :
420 E : TEST_F(BlockGraphSerializerTest, VariableLengthUint32Encoding) {
421 : const uint32 kTestValues[] = {
422 : // 5-bit values (< 32) that map to 1 byte.
423 : 1, 27, 31,
424 : // 13-bit values (< 8,192) that map to 2 bytes.
425 : 32, 1034, 8191,
426 : // 21-bit values (< 2,097,152) that map to 3 bytes.
427 : 8192, 1023847, 2097151,
428 : // 29-bit values (< 536,870,912) that map to 4 bytes.
429 : 2097152, 38274285, 536870911,
430 : // 32-bit values (< 4,294,967,296) that map to 5 bytes.
431 E : 536870912, 1610612736, 4294967295 };
432 :
433 E : for (size_t i = 0; i < arraysize(kTestValues); ++i) {
434 E : InitOutArchive();
435 E : ASSERT_TRUE(s_.SaveUint32(kTestValues[i], oa_.get()));
436 E : ASSERT_EQ((i / 3) + 1, v_.size());
437 :
438 E : InitInArchive();
439 E : uint32 value = 0;
440 E : ASSERT_TRUE(s_.LoadUint32(&value, ia_.get()));
441 :
442 E : ASSERT_EQ(kTestValues[i], value);
443 E : }
444 E : }
445 :
446 E : TEST_F(BlockGraphSerializerTest, VariableLengthInt32Encoding) {
447 : const int32 kTestValues[] = {
448 : // 4-bit values (< 16) that map to 1 byte.
449 : 1, 9, 15,
450 : // 12-bit values (< 4,096) that map to 2 bytes.
451 : 16, 1034, 4095,
452 : // 20-bit values (< 1,048,576) that map to 3 bytes.
453 : 4096, 815632, 1048575,
454 : // 28-bit values (< 268,435,456) that map to 4 bytes.
455 : 1048576, 38274285, 268435455,
456 : // 31-bit values (< 2,147,483,648) that map to 5 bytes.
457 E : 268435456, 805306368, 2147483647 };
458 :
459 E : for (size_t i = 0; i < arraysize(kTestValues); ++i) {
460 : // We try the value in a negative and positive format.
461 E : for (int32 j = -1; j <= 1; j += 2) {
462 E : int32 expected_value = kTestValues[i] * j;
463 :
464 E : InitOutArchive();
465 E : ASSERT_TRUE(s_.SaveInt32(expected_value, oa_.get()));
466 E : ASSERT_EQ((i / 3) + 1, v_.size());
467 :
468 E : InitInArchive();
469 E : int32 value = 0;
470 E : ASSERT_TRUE(s_.LoadInt32(&value, ia_.get()));
471 :
472 E : ASSERT_EQ(expected_value, value);
473 E : }
474 E : }
475 E : }
476 :
477 E : TEST_F(BlockGraphSerializerTest, FailsToLoadWrongVersion) {
478 : // Serialize an empty block-graph.
479 E : InitOutArchive();
480 E : ASSERT_TRUE(s_.Save(bg_, oa_.get()));
481 :
482 : // The first 4 bytes of the stream are the version. We change it so it is
483 : // invalid.
484 E : v_[0] += 1;
485 :
486 : // Deserialization should fail.
487 E : InitInArchive();
488 E : ASSERT_FALSE(s_.Load(&bg_, ia_.get()));
489 E : }
490 :
491 E : TEST_F(BlockGraphSerializerTest, RoundTripNoData) {
492 : ASSERT_NO_FATAL_FAILURE(TestRoundTrip(
493 : BlockGraphSerializer::OUTPUT_NO_DATA,
494 : BlockGraphSerializer::DEFAULT_ATTRIBUTES,
495 E : eInitBlockDataCallbacks1, 4));
496 E : }
497 :
498 E : TEST_F(BlockGraphSerializerTest, RoundTripNoDataCustomRepresentation) {
499 : ASSERT_NO_FATAL_FAILURE(TestRoundTrip(
500 : BlockGraphSerializer::OUTPUT_NO_DATA,
501 : BlockGraphSerializer::DEFAULT_ATTRIBUTES,
502 E : eInitBlockDataCallbacks2, 4));
503 E : }
504 :
505 E : TEST_F(BlockGraphSerializerTest, RoundTripOwnedData) {
506 : ASSERT_NO_FATAL_FAILURE(TestRoundTrip(
507 : BlockGraphSerializer::OUTPUT_OWNED_DATA,
508 : BlockGraphSerializer::DEFAULT_ATTRIBUTES,
509 E : eInitBlockDataCallbacks1, 2));
510 E : }
511 :
512 E : TEST_F(BlockGraphSerializerTest, RoundTripOwnedDataCustomRepresentation) {
513 : ASSERT_NO_FATAL_FAILURE(TestRoundTrip(
514 : BlockGraphSerializer::OUTPUT_OWNED_DATA,
515 : BlockGraphSerializer::DEFAULT_ATTRIBUTES,
516 E : eInitBlockDataCallbacks2, 2));
517 E : }
518 :
519 E : TEST_F(BlockGraphSerializerTest, RoundTripAllData) {
520 : ASSERT_NO_FATAL_FAILURE(TestRoundTrip(
521 : BlockGraphSerializer::OUTPUT_ALL_DATA,
522 : BlockGraphSerializer::DEFAULT_ATTRIBUTES,
523 E : eNoBlockDataCallbacks, 0));
524 E : }
525 :
526 : // TODO(chrisha): Do a heck of a lot more testing of protected member functions.
527 :
528 : } // namespace block_graph
|