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