1 // Copyright 2018 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef COMPONENTS_ZUCCHINI_REFERENCE_BYTES_MIXER_H_ 6 #define COMPONENTS_ZUCCHINI_REFERENCE_BYTES_MIXER_H_ 7 8 #include <stdint.h> 9 10 #include <memory> 11 12 #include "components/zucchini/buffer_view.h" 13 #include "components/zucchini/image_utils.h" 14 #include "components/zucchini/rel32_utils.h" 15 16 namespace zucchini { 17 18 class Disassembler; 19 20 // References encoding may be quite complex in some architectures (e.g., ARM), 21 // requiring bit-level manipulation. In general, bits in a reference body fall 22 // under 2 categories: 23 // - Operation bits: Instruction op code, conditionals, or structural data. 24 // - Payload bits: Actual target data of the reference. These may be absolute, 25 // or be displacements relative to instruction pointer / program counter. 26 // During patch application, 27 // Old reference bytes = {old operation, old payload}, 28 // is transformed to 29 // New reference bytes = {new operation, new payload}. 30 // New image bytes are written by three sources: 31 // (1) Direct copy from old image to new image for matched blocks. 32 // (2) Bytewise diff correction. 33 // (3) Dedicated reference target correction. 34 // 35 // For references whose operation and payload bits are stored in easily 36 // separable bytes (e.g., rel32 reference in X86), (2) can exclude payload bits. 37 // So during patch application, (1) naively copies everything, (2) fixes 38 // operation bytes only, and (3) fixes payload bytes only. 39 // 40 // For architectures with references whose operation and payload bits may mix 41 // within shared bytes (e.g., ARM rel32), a dilemma arises: 42 // - (2) cannot ignores shared bytes, since otherwise new operation bits not 43 // properly transfer. 44 // - Having (2) always overwrite these bytes would reduce the benefits of 45 // reference correction, since references are likely to change. 46 // 47 // Our solution applies a hybrid approach: For each matching old / new reference 48 // pair, define: 49 // Mixed reference bytes = {new operation, old payload}, 50 // 51 // During patch generation, we compute bytewise correction from old reference 52 // bytes to the mixed reference bytes. So during patch application, (2) only 53 // corrects operation bit changes (and skips if they don't change), and (3) 54 // overwrites old payload bits to new payload bits. 55 56 // A base class for (stateful) mixed reference byte generation. This base class 57 // serves as a stub. Architectures whose references store operation bits and 58 // payload bits can share common bytes (e.g., ARM rel32) should override this. 59 class ReferenceBytesMixer { 60 public: 61 ReferenceBytesMixer(); 62 ReferenceBytesMixer(const ReferenceBytesMixer&) = delete; 63 const ReferenceBytesMixer& operator=(const ReferenceBytesMixer&) = delete; 64 virtual ~ReferenceBytesMixer(); 65 66 // Returns a new ReferenceBytesMixer instance that's owned by the caller. 67 static std::unique_ptr<ReferenceBytesMixer> Create( 68 const Disassembler& src_dis, 69 const Disassembler& dst_dis); 70 71 // Returns the number of bytes that need to be mixed for references with given 72 // |type|. Returns 0 if no mixing is required. 73 virtual int NumBytes(uint8_t type) const; 74 75 // Computes mixed reference bytes by combining (a) "payload bits" from an 76 // "old" reference of |type| at |old_view[old_offset]| with (b) "operation 77 // bits" from a "new" reference of |type| at |new_view[new_offset]|. Returns 78 // the result as ConstBufferView, which is valid only until the next call to 79 // Mix(). 80 virtual ConstBufferView Mix(uint8_t type, 81 ConstBufferView old_view, 82 offset_t old_offset, 83 ConstBufferView new_view, 84 offset_t new_offset); 85 }; 86 87 // In AArch32 and AArch64, instructions mix operation bits and payload bits in 88 // complex ways. This is the main use case of ReferenceBytesMixer. 89 class ReferenceBytesMixerElfArm : public ReferenceBytesMixer { 90 public: 91 // |exe_type| must be EXE_TYPE_ELF_ARM or EXE_TYPE_ELF_AARCH64. 92 explicit ReferenceBytesMixerElfArm(ExecutableType exe_type); 93 ReferenceBytesMixerElfArm(const ReferenceBytesMixerElfArm&) = delete; 94 const ReferenceBytesMixerElfArm& operator=(const ReferenceBytesMixerElfArm&) = 95 delete; 96 ~ReferenceBytesMixerElfArm() override; 97 98 // ReferenceBytesMixer: 99 int NumBytes(uint8_t type) const override; 100 ConstBufferView Mix(uint8_t type, 101 ConstBufferView old_view, 102 offset_t old_offset, 103 ConstBufferView new_view, 104 offset_t new_offset) override; 105 106 private: 107 ArmCopyDispFun GetCopier(uint8_t type) const; 108 109 // For simplicity, 32-bit vs. 64-bit distinction is represented by state 110 // |exe_type_|, instead of creating derived classes. 111 const ExecutableType exe_type_; 112 113 std::vector<uint8_t> out_buffer_; 114 }; 115 116 } // namespace zucchini 117 118 #endif // COMPONENTS_ZUCCHINI_REFERENCE_BYTES_MIXER_H_ 119