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