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