// Copyright 2018 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef COMPONENTS_ZUCCHINI_REFERENCE_BYTES_MIXER_H_ #define COMPONENTS_ZUCCHINI_REFERENCE_BYTES_MIXER_H_ #include #include #include #include "base/macros.h" #include "components/zucchini/buffer_view.h" #include "components/zucchini/image_utils.h" namespace zucchini { class Disassembler; // References encoding may be quite complex in some architectures (e.g., ARM), // requiring bit-level manipulation. In general, bits in a reference body fall // under 2 categories: // - Operation bits: Instruction op code, conditionals, or structural data. // - Payload bits: Actual target data of the reference. These may be absolute, // or be displacements relative to instruction pointer / program counter. // During patch application, // Old reference bytes = {old operation, old payload}, // is transformed to // New reference bytes = {new operation, new payload}. // New image bytes are written by three sources: // (1) Direct copy from old image to new image for matched blocks. // (2) Bytewise diff correction. // (3) Dedicated reference target correction. // // For references whose operation and payload bits are stored in easily // separable bytes (e.g., rel32 reference in X86), (2) can exclude payload bits. // So during patch application, (1) naively copies everything, (2) fixes // operation bytes only, and (3) fixes payload bytes only. // // For architectures with references whose operation and payload bits may mix // within shared bytes (e.g., ARM rel32), a dilemma arises: // - (2) cannot ignores shared bytes, since otherwise new operation bits not // properly transfer. // - Having (2) always overwrite these bytes would reduce the benefits of // reference correction, since references are likely to change. // // Our solution applies a hybrid approach: For each matching old / new reference // pair, define: // Mixed reference bytes = {new operation, old payload}, // // During patch generation, we compute bytewise correction from old reference // bytes to the mixed reference bytes. So during patch application, (2) only // corrects operation bit changes (and skips if they don't change), and (3) // overwrites old payload bits to new payload bits. // A base class for (stateful) mixed reference byte generation. This base class // serves as a stub. Architectures whose references store operation bits and // payload bits can share common bytes (e.g., ARM rel32) should override this. class ReferenceBytesMixer { public: ReferenceBytesMixer(); virtual ~ReferenceBytesMixer(); // Returns a new ReferenceBytesMixer instance that's owned by the caller. static std::unique_ptr Create( const Disassembler& src_dis, const Disassembler& dst_dis); // Returns the number of bytes that need to be mixed for references with given // |type|. Returns 0 if no mixing is required. virtual int NumBytes(uint8_t type) const; // Computes mixed reference bytes by combining (a) "payload bits" from an // "old" reference of |type| at |old_base[old_offset]| with (b) "operation // bits" from a "new" reference of |type| at |new_base[new_offset]|. Returns // the result as ConstBufferView, which is valid only until the next call to // Mix(). virtual ConstBufferView Mix(uint8_t type, ConstBufferView::const_iterator old_base, offset_t old_offset, ConstBufferView::const_iterator new_base, offset_t new_offset); private: DISALLOW_COPY_AND_ASSIGN(ReferenceBytesMixer); }; } // namespace zucchini #endif // COMPONENTS_ZUCCHINI_REFERENCE_BYTES_MIXER_H_