1 : // Copyright 2012 Google Inc.
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/stringprintf.h"
18 :
19 : namespace block_graph {
20 :
21 : namespace {
22 :
23 : using core::InArchive;
24 : using core::OutArchive;
25 :
26 : // This needs to be incremented any time a any non-backwards compatible change
27 : // is made to the serialization format.
28 : // TODO(chrisha): Enforce this via a unittest. Check in a version of a
29 : // simple block-graph, and ensure it deserializes to the same in-memory
30 : // representation.
31 : static const uint32 kSerializedBlockGraphVersion = 0;
32 :
33 : // Potentially saves a string, depending on whether or not OMIT_STRINGS is
34 : // enabled.
35 : bool MaybeSaveString(const BlockGraphSerializer& bgs,
36 : const std::string& value,
37 E : OutArchive* out_archive) {
38 E : DCHECK(out_archive != NULL);
39 :
40 E : if (bgs.has_attributes(BlockGraphSerializer::OMIT_STRINGS))
41 E : return true;
42 :
43 E : if (!out_archive->Save(value)) {
44 i : LOG(ERROR) << "Unable to save string \"" << value << "\".";
45 i : return false;
46 : }
47 :
48 E : return true;
49 E : }
50 :
51 : // Potentially loads a string, depending on whether or not OMIT_STRINGS is
52 : // enabled.
53 : bool MaybeLoadString(const BlockGraphSerializer& bgs,
54 : std::string* value,
55 E : InArchive* in_archive) {
56 E : DCHECK(value != NULL);
57 E : DCHECK(in_archive != NULL);
58 :
59 E : if (bgs.has_attributes(BlockGraphSerializer::OMIT_STRINGS))
60 E : return true;
61 :
62 E : if (!in_archive->Load(value)) {
63 i : LOG(ERROR) << "Unable to load string.";
64 i : return false;
65 : }
66 :
67 E : return true;
68 E : }
69 :
70 E : bool ValidAttributes(uint32 attributes, uint32 attributes_max) {
71 E : return (attributes & ~(attributes_max - 1)) == 0;
72 E : }
73 :
74 : } // namespace
75 :
76 : bool BlockGraphSerializer::Save(const BlockGraph& block_graph,
77 E : core::OutArchive* out_archive) const {
78 E : CHECK(out_archive != NULL);
79 :
80 : // Save the serialization attributes so we can read this block-graph without
81 : // having to be told how it was saved.
82 : if (!out_archive->Save(kSerializedBlockGraphVersion) ||
83 : !out_archive->Save(static_cast<uint32>(data_mode_)) ||
84 E : !out_archive->Save(attributes_)) {
85 i : LOG(ERROR) << "Unable to save serialized block-graph properties.";
86 i : return false;
87 : }
88 :
89 : // This function takes care of outputting a meaningful log message on
90 : // failure.
91 E : if (!SaveBlockGraphProperties(block_graph, out_archive))
92 i : return false;
93 :
94 : // Save the blocks, except for their references. We do that in a second pass
95 : // so that when loading the referenced blocks will exist.
96 E : if (!SaveBlocks(block_graph, out_archive)) {
97 i : LOG(ERROR) << "Unable to save blocks.";
98 i : return false;
99 : }
100 :
101 : // Save all of the references. The referrers are implicitly saved by this.
102 E : if (!SaveBlockGraphReferences(block_graph, out_archive)) {
103 i : LOG(ERROR) << "Unable to save block graph references.";
104 i : return false;
105 : }
106 :
107 E : return true;
108 E : }
109 :
110 : bool BlockGraphSerializer::Load(BlockGraph* block_graph,
111 E : core::InArchive* in_archive) {
112 E : CHECK(block_graph != NULL);
113 E : CHECK(in_archive != NULL);
114 :
115 E : uint32 version = 0;
116 E : if (!in_archive->Load(&version)) {
117 i : LOG(ERROR) << "Unable to load serialized block graph version.";
118 i : return false;
119 : }
120 :
121 : // Here's is where we could dispatch to different load functions for
122 : // backwards compatibility with previous versions. For now, we simply bail.
123 E : if (version != kSerializedBlockGraphVersion) {
124 E : LOG(ERROR) << "Unable to load block graph with version " << version
125 : << " (expected " << kSerializedBlockGraphVersion << ").";
126 E : return false;
127 : }
128 :
129 : // Read the serialization attributes and mode information so that we know how
130 : // to load the block-graph.
131 E : uint32 data_mode = 0;
132 E : if (!in_archive->Load(&data_mode) || !in_archive->Load(&attributes_)) {
133 i : LOG(ERROR) << "Unable to load serialized block-graph properties.";
134 i : return false;
135 : }
136 E : data_mode_ = static_cast<DataMode>(data_mode);
137 :
138 : // Ensure that the data mode and the attributes are valid.
139 : if (data_mode_ >= DATA_MODE_MAX ||
140 E : !ValidAttributes(attributes_, ATTRIBUTES_MAX)) {
141 i : LOG(ERROR) << "Invalid data mode and/or attributes.";
142 i : return false;
143 : }
144 :
145 : // This function takes care of outputting a meaningful log message on
146 : // failure.
147 E : if (!LoadBlockGraphProperties(block_graph, in_archive))
148 i : return false;
149 :
150 : // Load the blocks, except for their references.
151 E : if (!LoadBlocks(block_graph, in_archive)) {
152 i : LOG(ERROR) << "Unable to load blocks.";
153 i : return false;
154 : }
155 :
156 : // Now load the references and wire them up.
157 E : if (!LoadBlockGraphReferences(block_graph, in_archive)) {
158 i : LOG(ERROR) << "Unable to load block graph references.";
159 i : return false;
160 : }
161 :
162 E : return true;
163 E : }
164 :
165 : bool BlockGraphSerializer::SaveBlockGraphProperties(
166 : const BlockGraph& block_graph,
167 E : OutArchive* out_archive) const {
168 E : DCHECK(out_archive != NULL);
169 :
170 : if (!out_archive->Save(block_graph.next_section_id_) ||
171 : !out_archive->Save(block_graph.sections_) ||
172 E : !out_archive->Save(block_graph.next_block_id_)) {
173 i : LOG(ERROR) << "Unable to save block graph properties.";
174 i : return false;
175 : }
176 :
177 E : return true;
178 E : }
179 :
180 : bool BlockGraphSerializer::LoadBlockGraphProperties(
181 E : BlockGraph* block_graph, InArchive* in_archive) const {
182 E : DCHECK(block_graph != NULL);
183 E : DCHECK(in_archive != NULL);
184 :
185 : // The block graph properties should be empty.
186 E : DCHECK_EQ(0u, block_graph->next_section_id_);
187 E : DCHECK_EQ(0u, block_graph->sections_.size());
188 E : DCHECK_EQ(0u, block_graph->next_block_id_);
189 :
190 : if (!in_archive->Load(&block_graph->next_section_id_) ||
191 : !in_archive->Load(&block_graph->sections_) ||
192 E : !in_archive->Load(&block_graph->next_block_id_)) {
193 i : LOG(ERROR) << "Unable to load block graph properties.";
194 i : return false;
195 : }
196 :
197 E : return true;
198 E : }
199 :
200 : bool BlockGraphSerializer::SaveBlocks(const BlockGraph& block_graph,
201 E : OutArchive* out_archive) const {
202 E : DCHECK(out_archive != NULL);
203 :
204 E : if (!out_archive->Save(block_graph.blocks().size())) {
205 i : LOG(ERROR) << "Unable to save block count.";
206 i : return false;
207 : }
208 :
209 : // Output the basic block properties first.
210 E : BlockGraph::BlockMap::const_iterator it = block_graph.blocks_.begin();
211 E : for (; it != block_graph.blocks_.end(); ++it) {
212 E : BlockGraph::BlockId block_id = it->first;
213 E : const BlockGraph::Block& block = it->second;
214 : if (!out_archive->Save(block_id) ||
215 : !SaveBlockProperties(block, out_archive) ||
216 : !SaveBlockLabels(block, out_archive) ||
217 E : !SaveBlockData(block, out_archive)) {
218 i : LOG(ERROR) << "Unable to save block with id " << block_id << ".";
219 i : return false;
220 : }
221 E : }
222 :
223 E : return true;
224 E : }
225 :
226 : bool BlockGraphSerializer::LoadBlocks(BlockGraph* block_graph,
227 E : InArchive* in_archive) const {
228 E : DCHECK(block_graph != NULL);
229 E : DCHECK(in_archive != NULL);
230 :
231 E : DCHECK_EQ(0u, block_graph->blocks_.size());
232 :
233 E : size_t count = 0;
234 E : if (!in_archive->Load(&count)) {
235 i : LOG(ERROR) << "Unable to load block count.";
236 i : return false;
237 : }
238 :
239 E : for (size_t i = 0; i < count; ++i) {
240 E : BlockGraph::BlockId id = 0;
241 E : if (!in_archive->Load(&id)) {
242 i : LOG(ERROR) << "Unable to load id for block " << i << " of " << count
243 : << ".";
244 i : return false;
245 : }
246 :
247 : std::pair<BlockGraph::BlockMap::iterator, bool> result =
248 E : block_graph->blocks_.insert(std::make_pair(id, BlockGraph::Block()));
249 E : if (!result.second) {
250 i : LOG(ERROR) << "Unable to insert block with id " << id << ".";
251 i : return false;
252 : }
253 E : BlockGraph::Block* block = &result.first->second;
254 E : block->id_ = id;
255 :
256 : if (!LoadBlockProperties(block, in_archive) ||
257 : !LoadBlockLabels(block, in_archive) ||
258 E : !LoadBlockData(block, in_archive)) {
259 i : LOG(ERROR) << "Unable to load block " << i << " of " << count
260 : << " with id " << id << ".";
261 i : return false;
262 : }
263 E : }
264 E : DCHECK_EQ(count, block_graph->blocks_.size());
265 :
266 E : return true;
267 E : }
268 :
269 : bool BlockGraphSerializer::SaveBlockGraphReferences(
270 E : const BlockGraph& block_graph, OutArchive* out_archive) const {
271 E : DCHECK(out_archive != NULL);
272 :
273 E : BlockGraph::BlockMap::const_iterator it = block_graph.blocks().begin();
274 E : for (; it != block_graph.blocks().end(); ++it) {
275 E : if (!SaveBlockReferences(it->second, out_archive)) {
276 i : LOG(ERROR) << "Unable to save references for block with id "
277 : << it->second.id() << ".";
278 i : return false;
279 : }
280 E : }
281 :
282 E : return true;
283 E : }
284 :
285 : bool BlockGraphSerializer::LoadBlockGraphReferences(
286 E : BlockGraph* block_graph, InArchive* in_archive) const {
287 E : DCHECK(block_graph != NULL);
288 E : DCHECK(in_archive != NULL);
289 :
290 E : BlockGraph::BlockMap::iterator it = block_graph->blocks_mutable().begin();
291 E : for (; it != block_graph->blocks_mutable().end(); ++it) {
292 E : if (!LoadBlockReferences(block_graph, &it->second, in_archive)) {
293 i : LOG(ERROR) << "Unable to load references for block with id "
294 : << it->second.id() << ".";
295 i : return false;
296 : }
297 E : }
298 :
299 E : return true;
300 E : }
301 :
302 : bool BlockGraphSerializer::SaveBlockProperties(const BlockGraph::Block& block,
303 E : OutArchive* out_archive) const {
304 E : DCHECK(out_archive != NULL);
305 :
306 : COMPILE_ASSERT(BlockGraph::BLOCK_ATTRIBUTES_MAX <= (1 << 16),
307 : block_attributes_need_more_than_16_bits);
308 :
309 E : uint8 type = static_cast<uint8>(block.type());
310 E : uint16 attributes = static_cast<uint16>(block.attributes());
311 :
312 : // We use a signed integer for saving the section ID, as -1 is used to
313 : // indicate 'no section'.
314 : if (!out_archive->Save(type) ||
315 : !SaveUint30(block.size(), out_archive) ||
316 : !SaveUint30(block.alignment(), out_archive) ||
317 : !out_archive->Save(block.source_ranges()) ||
318 : !out_archive->Save(block.addr()) ||
319 : !SaveInt30(static_cast<uint32>(block.section()), out_archive) ||
320 : !out_archive->Save(attributes) ||
321 E : !MaybeSaveString(*this, block.name(), out_archive)) {
322 i : LOG(ERROR) << "Unable to save properties for block with id "
323 : << block.id() << ".";
324 i : return false;
325 : }
326 :
327 E : return true;
328 E : }
329 :
330 : bool BlockGraphSerializer::LoadBlockProperties(BlockGraph::Block* block,
331 E : InArchive* in_archive) const {
332 E : DCHECK(block != NULL);
333 E : DCHECK(in_archive != NULL);
334 :
335 : // Make sure the block is freshly initialized.
336 E : DCHECK_EQ(BlockGraph::CODE_BLOCK, block->type_);
337 E : DCHECK_EQ(0u, block->size_);
338 E : DCHECK_EQ(1u, block->alignment_);
339 E : DCHECK_EQ(0u, block->source_ranges_.size());
340 E : DCHECK_EQ(kInvalidAddress, block->addr_);
341 E : DCHECK_EQ(BlockGraph::kInvalidSectionId, block->section_);
342 E : DCHECK_EQ(0u, block->attributes_);
343 :
344 E : uint8 type = 0;
345 E : uint32 size = 0;
346 E : uint32 alignment = 0;
347 E : uint32 section = 0;
348 E : uint16 attributes = 0;
349 : if (!in_archive->Load(&type) ||
350 : !LoadUint30(&size, in_archive) ||
351 : !LoadUint30(&alignment, in_archive) ||
352 : !in_archive->Load(&block->source_ranges_) ||
353 : !in_archive->Load(&block->addr_) ||
354 : !LoadInt30(reinterpret_cast<int32*>(§ion), in_archive) ||
355 : !in_archive->Load(&attributes) ||
356 E : !MaybeLoadString(*this, &block->name_, in_archive)) {
357 i : LOG(ERROR) << "Unable to load properties for block with id "
358 : << block->id() << ".";
359 i : return false;
360 : }
361 :
362 : if (type > BlockGraph::BLOCK_TYPE_MAX ||
363 E : !ValidAttributes(attributes, BlockGraph::BLOCK_ATTRIBUTES_MAX)) {
364 i : LOG(ERROR) << "Invalid block type (" << static_cast<uint32>(type)
365 : << ") and/or attributes ("
366 : << base::StringPrintf("%04X", attributes)
367 : << ") for block with id " << block->id() << ".";
368 i : return false;
369 : }
370 :
371 E : block->type_ = static_cast<BlockGraph::BlockType>(type);
372 E : block->size_ = size;
373 E : block->alignment_ = alignment;
374 E : block->section_ = section;
375 E : block->attributes_ = attributes;
376 :
377 E : return true;
378 E : }
379 :
380 : bool BlockGraphSerializer::SaveBlockLabels(const BlockGraph::Block& block,
381 E : OutArchive* out_archive) const {
382 E : DCHECK(out_archive != NULL);
383 :
384 E : if (has_attributes(BlockGraphSerializer::OMIT_LABELS))
385 i : return true;
386 :
387 E : uint32 count = block.labels().size();
388 E : if (!SaveUint30(count, out_archive)) {
389 i : LOG(ERROR) << "Unable to save label count.";
390 i : return false;
391 : }
392 :
393 : BlockGraph::Block::LabelMap::const_iterator label_iter =
394 E : block.labels().begin();
395 E : for (; label_iter != block.labels().end(); label_iter++) {
396 : COMPILE_ASSERT(BlockGraph::LABEL_ATTRIBUTES_MAX <= (1 << 16),
397 : label_attributes_require_more_than_16_bits);
398 :
399 E : int32 offset = label_iter->first;
400 E : const BlockGraph::Label& label = label_iter->second;
401 E : uint16 attributes = static_cast<uint16>(label.attributes());
402 :
403 : if (!SaveInt30(offset, out_archive) || !out_archive->Save(attributes) ||
404 E : !MaybeSaveString(*this, label.name(), out_archive)) {
405 i : LOG(ERROR) << "Unable to save label at offset "
406 : << label_iter->first << " of block with id "
407 : << block.id() << ".";
408 i : return false;
409 : }
410 E : }
411 :
412 E : return true;
413 E : }
414 :
415 : bool BlockGraphSerializer::LoadBlockLabels(BlockGraph::Block* block,
416 E : InArchive* in_archive) const {
417 E : DCHECK(block != NULL);
418 E : DCHECK(in_archive != NULL);
419 :
420 : // The block shouldn't have any labels yet.
421 E : DCHECK_EQ(0u, block->labels().size());
422 :
423 E : if (has_attributes(BlockGraphSerializer::OMIT_LABELS))
424 i : return true;
425 :
426 E : uint32 label_count = 0;
427 E : if (!LoadUint30(&label_count, in_archive)) {
428 i : LOG(ERROR) << "Unable to load label count.";
429 i : return false;
430 : }
431 :
432 E : for (size_t i = 0; i < label_count; ++i) {
433 E : int32 offset = 0;
434 E : uint16 attributes = 0;
435 E : std::string name;
436 :
437 : if (!LoadInt30(&offset, in_archive) || !(in_archive->Load(&attributes)) ||
438 E : !MaybeLoadString(*this, &name, in_archive)) {
439 i : LOG(ERROR) << "Unable to load label " << i << " of " << label_count
440 : << " for block with id " << block->id() << ".";
441 i : return false;
442 : }
443 :
444 : // Ensure the attributes are valid.
445 E : if (!ValidAttributes(attributes, BlockGraph::LABEL_ATTRIBUTES_MAX)) {
446 i : LOG(ERROR) << "Invalid attributes ("
447 : << base::StringPrintf("%04X", attributes) << ") for block "
448 : << "with id " << block->id() << ".";
449 i : return false;
450 : }
451 :
452 E : BlockGraph::Label label(name, attributes);
453 E : CHECK(block->SetLabel(offset, label));
454 E : }
455 E : DCHECK_EQ(label_count, block->labels().size());
456 :
457 E : return true;
458 E : }
459 :
460 : bool BlockGraphSerializer::SaveBlockData(const BlockGraph::Block& block,
461 E : OutArchive* out_archive) const {
462 E : DCHECK(out_archive != NULL);
463 :
464 : // We always output the data size.
465 E : uint32 data_size = block.data_size();
466 E : if (!SaveUint30(data_size, out_archive)) {
467 i : LOG(ERROR) << "Unable to save block data size for block with id "
468 : << block.id() << ".";
469 i : return false;
470 : }
471 :
472 E : bool output_data = false;
473 :
474 E : if (block.data_size() > 0) {
475 E : switch (data_mode_) {
476 : default:
477 i : NOTREACHED();
478 :
479 : case OUTPUT_NO_DATA: {
480 E : output_data = false;
481 E : break;
482 : }
483 :
484 : case OUTPUT_OWNED_DATA: {
485 E : uint8 owns_data = block.owns_data();
486 E : if (!out_archive->Save(owns_data)) {
487 i : LOG(ERROR) << "Unable to save 'owns_data' field of block with id "
488 : << block.id() << ".";
489 i : return false;
490 : }
491 :
492 E : output_data = block.owns_data();
493 E : break;
494 : }
495 :
496 : case OUTPUT_ALL_DATA: {
497 E : output_data = true;
498 : break;
499 : }
500 : }
501 : }
502 :
503 : // Save the data if we need to.
504 E : if (output_data) {
505 E : DCHECK_LT(0u, block.data_size());
506 E : if (!out_archive->out_stream()->Write(block.data_size(), block.data())) {
507 i : LOG(ERROR) << "Unable to save data for block with id "
508 : << block.id() << ".";
509 i : return false;
510 : }
511 : }
512 :
513 : // No callback? Then do nothing!
514 E : if (save_block_data_callback_.get() == NULL)
515 E : return true;
516 :
517 : // Invoke the callback.
518 E : bool data_already_saved = output_data || block.data_size() == 0;
519 : if (!save_block_data_callback_->Run(data_already_saved,
520 E : block, out_archive)) {
521 i : return false;
522 : }
523 :
524 E : return true;
525 E : }
526 :
527 : bool BlockGraphSerializer::LoadBlockData(BlockGraph::Block* block,
528 E : InArchive* in_archive) const {
529 E : DCHECK(block != NULL);
530 E : DCHECK(in_archive != NULL);
531 E : DCHECK_EQ(0u, block->data_size());
532 E : DCHECK(block->data() == NULL);
533 E : DCHECK_EQ(false, block->owns_data());
534 :
535 E : uint32 data_size = 0;
536 E : if (!LoadUint30(&data_size, in_archive)) {
537 i : LOG(ERROR) << "Unable to load data size for block with id "
538 : << block->id() << ".";
539 i : return false;
540 : }
541 :
542 : // This indicates whether or not we need to explicitly load the data directly
543 : // from the serialized stream.
544 E : bool data_in_stream = false;
545 :
546 E : if (data_size > 0) {
547 E : switch (data_mode_) {
548 : default:
549 i : NOTREACHED();
550 :
551 : case OUTPUT_NO_DATA: {
552 E : data_in_stream = false;
553 E : break;
554 : }
555 :
556 : case OUTPUT_OWNED_DATA: {
557 E : uint8 owns_data = 0;
558 E : if (!in_archive->Load(&owns_data)) {
559 i : LOG(ERROR) << "Unable to load 'owns_data' field of block with id "
560 : << block->id() << ".";
561 i : return false;
562 : }
563 :
564 : // If we own the data then it must have been serialized to the stream.
565 E : data_in_stream = owns_data != 0;
566 E : break;
567 : }
568 :
569 : case OUTPUT_ALL_DATA: {
570 E : data_in_stream = true;
571 : break;
572 : }
573 : }
574 : }
575 :
576 E : bool callback_needs_to_set_data = !data_in_stream && data_size > 0;
577 :
578 E : if (data_in_stream) {
579 E : DCHECK_LT(0u, data_size);
580 :
581 : // Read the data from the stream.
582 E : block->AllocateData(data_size);
583 E : DCHECK_EQ(data_size, block->data_size());
584 E : DCHECK(block->data() != NULL);
585 E : if (!in_archive->in_stream()->Read(data_size, block->GetMutableData())) {
586 i : LOG(ERROR) << "Unable to read data for block with id "
587 : << block->id() << ".";
588 i : return false;
589 : }
590 : }
591 :
592 E : if (callback_needs_to_set_data) {
593 : // If we didn't explicitly load the data, then we expect the callback to
594 : // do it. We make sure there is one.
595 E : if (load_block_data_callback_.get() == NULL) {
596 i : LOG(ERROR) << "No load block data callback specified.";
597 i : return false;
598 : }
599 : }
600 :
601 : // If there's a callback, invoke it.
602 E : if (load_block_data_callback_.get()) {
603 : if (!load_block_data_callback_->Run(callback_needs_to_set_data,
604 : data_size,
605 : block,
606 E : in_archive)) {
607 i : LOG(ERROR) << "Block data callback failed.";
608 i : return false;
609 : }
610 : }
611 :
612 E : if (data_size > 0 && block->data() == NULL) {
613 i : LOG(ERROR) << "Load block data callback failed to set block data.";
614 i : return false;
615 : }
616 :
617 E : if (block->data_size() != data_size) {
618 i : LOG(ERROR) << "Load block data callback set incorrect data size.";
619 i : return false;
620 : }
621 :
622 E : return true;
623 E : }
624 :
625 : bool BlockGraphSerializer::SaveBlockReferences(const BlockGraph::Block& block,
626 E : OutArchive* out_archive) const {
627 : // Output the number of references for this block.
628 E : if (!out_archive->Save(block.references().size())) {
629 i : LOG(ERROR) << "Unable to save reference count for block with id "
630 : << block.id() << ".";
631 i : return false;
632 : }
633 :
634 : // Output the references as (offset, reference) pairs.
635 : BlockGraph::Block::ReferenceMap::const_iterator it =
636 E : block.references().begin();
637 E : for (; it != block.references().end(); ++it) {
638 E : int32 offset = it->first;
639 : if (!SaveInt30(offset, out_archive) ||
640 E : !SaveReference(it->second, out_archive)) {
641 i : LOG(ERROR) << "Unable to save (offset, reference) pair at offset "
642 : << offset << " of block with id " << block.id() << ".";
643 i : return false;
644 : }
645 E : }
646 :
647 E : return true;
648 E : }
649 :
650 : bool BlockGraphSerializer::LoadBlockReferences(BlockGraph* block_graph,
651 : BlockGraph::Block* block,
652 E : InArchive* in_archive) const {
653 E : DCHECK(block_graph != NULL);
654 E : DCHECK(block != NULL);
655 E : DCHECK(in_archive != NULL);
656 :
657 : // This block should not have any references yet.
658 E : DCHECK_EQ(0u, block->references().size());
659 :
660 E : size_t count = 0;
661 E : if (!in_archive->Load(&count)) {
662 i : LOG(ERROR) << "Unable to load reference count for block with id "
663 : << block->id() << ".";
664 i : return false;
665 : }
666 :
667 E : for (size_t i = 0; i < count; ++i) {
668 E : int32 offset = 0;
669 E : BlockGraph::Reference ref;
670 : if (!LoadInt30(&offset, in_archive) ||
671 E : !LoadReference(block_graph, &ref, in_archive)) {
672 i : LOG(ERROR) << "Unable to load (offset, reference) pair " << i << " of "
673 : << count << " for block with id " << block->id() << ".";
674 i : return false;
675 : }
676 E : DCHECK(ref.referenced() != NULL);
677 :
678 E : if (!block->SetReference(offset, ref)) {
679 i : LOG(ERROR) << "Unable to create block reference at offset " << offset
680 : << " of block with id " << block->id() << ".";
681 i : return false;
682 : }
683 E : }
684 :
685 E : return true;
686 E : }
687 :
688 : bool BlockGraphSerializer::SaveReference(const BlockGraph::Reference& ref,
689 E : OutArchive* out_archive) const {
690 E : DCHECK(ref.referenced() != NULL);
691 E : DCHECK(out_archive != NULL);
692 :
693 : COMPILE_ASSERT(BlockGraph::REFERENCE_TYPE_MAX < 16,
694 : reference_type_requires_more_than_one_nibble);
695 : COMPILE_ASSERT(BlockGraph::Reference::kMaximumSize < 16,
696 : reference_size_requires_more_than_one_nibble);
697 :
698 : // The type and size are each stored as a nibble of one byte.
699 : uint8 type_size = (static_cast<uint8>(ref.type()) << 4) |
700 E : static_cast<uint8>(ref.size());
701 E : int32 offset = ref.offset();
702 : // Most often the offset and the base are identical, so we actually save
703 : // the base as a difference from the offset to encourage smaller values.
704 E : int32 base_delta = ref.base() - ref.offset();
705 :
706 : if (!out_archive->Save(type_size) ||
707 : !out_archive->Save(ref.referenced()->id()) ||
708 E : !SaveInt30(offset, out_archive) || !SaveInt30(base_delta, out_archive)) {
709 i : LOG(ERROR) << "Unable to write reference properties.";
710 i : return false;
711 : }
712 :
713 E : return true;
714 E : }
715 :
716 : bool BlockGraphSerializer::LoadReference(BlockGraph* block_graph,
717 : BlockGraph::Reference* ref,
718 E : InArchive* in_archive) const {
719 E : DCHECK(block_graph != NULL);
720 E : DCHECK(ref != NULL);
721 E : DCHECK(in_archive != NULL);
722 :
723 E : uint8 type_size = 0;
724 E : BlockGraph::BlockId id = 0;
725 E : int32 offset = 0;
726 E : int32 base_delta = 0;
727 :
728 : if (!in_archive->Load(&type_size) || !in_archive->Load(&id) ||
729 E : !LoadInt30(&offset, in_archive) || !LoadInt30(&base_delta, in_archive)) {
730 i : LOG(ERROR) << "Unable to load reference properties.";
731 i : return false;
732 : }
733 :
734 : // The type and size are each stored as a nibble of one byte.
735 E : uint8 type = (type_size >> 4) & 0xF;
736 E : uint8 size = type_size & 0xF;
737 :
738 : if (type >= BlockGraph::REFERENCE_TYPE_MAX ||
739 E : size > BlockGraph::Reference::kMaximumSize) {
740 i : LOG(ERROR) << "Invalid reference type (" << static_cast<uint32>(type)
741 : << ") and/or size (" << static_cast<uint32>(size) << ").";
742 i : return false;
743 : }
744 :
745 E : BlockGraph::Block* referenced = block_graph->GetBlockById(id);
746 E : if (referenced == NULL) {
747 i : LOG(ERROR) << "Unable to find referenced block with id " << id << ".";
748 i : return false;
749 : }
750 :
751 : *ref = BlockGraph::Reference(static_cast<BlockGraph::ReferenceType>(type),
752 E : size, referenced, offset, offset + base_delta);
753 :
754 E : return true;
755 E : }
756 :
757 : // Saves an unsigned 30 bit value. This uses a variable length encoding where
758 : // the first two bits are reserved to indicate the number of bytes required to
759 : // store the value.
760 : bool BlockGraphSerializer::SaveUint30(uint32 value,
761 E : OutArchive* out_archive) const {
762 E : DCHECK(out_archive != NULL);
763 :
764 : // The maximum value we can represent is 30 bits, as we reserve 2 to indicate
765 : // the byte count.
766 E : CHECK_GT((1u << 30), value);
767 :
768 : // Determine the number of bytes needed in the representation.
769 E : uint32 bytes = 1;
770 E : if (value >= (1 << 22)) {
771 E : bytes = 4;
772 E : } else if (value >= (1 << 14)) {
773 E : bytes = 3;
774 E : } else if (value >= (1 << 6)) {
775 E : bytes = 2;
776 : }
777 :
778 : // Output the value, LSB first. We actually only output 6 bits of the LSB.
779 E : uint8 byte = (value & ((1 << 6) - 1));
780 E : byte |= ((bytes - 1) << 6);
781 E : value >>= 6;
782 E : while (true) {
783 E : if (!out_archive->Save(byte)) {
784 i : LOG(ERROR) << "Unable to write variable-length 30-bit unsigned integer.";
785 i : return false;
786 : }
787 :
788 E : if (--bytes == 0)
789 E : break;
790 :
791 E : byte = value & 0xFF;
792 E : value >>= 8;
793 E : }
794 :
795 E : return true;
796 E : }
797 :
798 : // Loads an unsigned 30-bit value using the encoding discussed in SaveUint30.
799 : bool BlockGraphSerializer::LoadUint30(uint32* value,
800 E : InArchive* in_archive) const {
801 E : DCHECK(value != NULL);
802 E : DCHECK(in_archive != NULL);
803 :
804 E : uint32 temp_value = 0;
805 E : uint32 bytes = 0;
806 E : uint32 position = 0;
807 E : uint8 byte = 0;
808 :
809 E : while (true) {
810 E : if (!in_archive->Load(&byte)) {
811 i : LOG(ERROR) << "Unable to read variable-length 30-bit unsigned integer.";
812 i : return false;
813 : }
814 :
815 : // If we're reading the first byte, we need to read the number of bytes
816 : // remaining from its 2 leading bits.
817 E : if (position == 0) {
818 E : bytes = (byte >> 6) & 0x3;
819 E : temp_value = byte & ((1 << 6) - 1);
820 E : position += 6;
821 E : } else {
822 E : temp_value |= byte << position;
823 E : position += 8;
824 : }
825 :
826 E : if (bytes == 0)
827 E : break;
828 :
829 E : --bytes;
830 E : }
831 :
832 E : *value = temp_value;
833 E : return true;
834 E : }
835 :
836 : // Saves a signed 30-bit value using a variable length encoding. This can
837 : // represent signed values where the magnitude is at most 29-bits. We use a
838 : // simple sign-bit encoding, so there are 2 encodings for 0.
839 : bool BlockGraphSerializer::SaveInt30(int32 value,
840 E : OutArchive* out_archive) const {
841 E : DCHECK(out_archive != NULL);
842 :
843 E : uint32 uvalue = static_cast<uint32>(value < 0 ? -value : value);
844 E : CHECK_GT((1u << 29), uvalue);
845 :
846 : // Add the sign bit as the least significant bit. This allows values near 0
847 : // (positive or negative) to be encoded in as little space as possible.
848 E : uvalue <<= 1;
849 E : if (value < 0)
850 E : uvalue |= 1;
851 :
852 E : if (!SaveUint30(uvalue, out_archive))
853 i : return false;
854 :
855 E : return true;
856 E : }
857 :
858 : bool BlockGraphSerializer::LoadInt30(int32* value,
859 E : InArchive* in_archive) const {
860 E : DCHECK(value != NULL);
861 E : DCHECK(in_archive != NULL);
862 :
863 E : uint32 uvalue = 0;
864 E : if (!LoadUint30(&uvalue, in_archive))
865 i : return false;
866 :
867 E : *value = static_cast<int32>(uvalue >> 1);
868 E : if ((uvalue & 1) != 0)
869 E : *value = -(*value);
870 :
871 E : return true;
872 E : }
873 :
874 : } // namespace block_graph
|