1*a03ca8b9SKrzysztof Kosiński // Copyright 2018 The Chromium Authors. All rights reserved.
2*a03ca8b9SKrzysztof Kosiński // Use of this source code is governed by a BSD-style license that can be
3*a03ca8b9SKrzysztof Kosiński // found in the LICENSE file.
4*a03ca8b9SKrzysztof Kosiński
5*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/reference_bytes_mixer.h"
6*a03ca8b9SKrzysztof Kosiński
7*a03ca8b9SKrzysztof Kosiński #include <algorithm>
8*a03ca8b9SKrzysztof Kosiński
9*a03ca8b9SKrzysztof Kosiński #include "base/check_op.h"
10*a03ca8b9SKrzysztof Kosiński #include "base/logging.h"
11*a03ca8b9SKrzysztof Kosiński #include "base/notreached.h"
12*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/disassembler.h"
13*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/disassembler_elf.h"
14*a03ca8b9SKrzysztof Kosiński
15*a03ca8b9SKrzysztof Kosiński namespace zucchini {
16*a03ca8b9SKrzysztof Kosiński
17*a03ca8b9SKrzysztof Kosiński /******** ReferenceBytesMixer ********/
18*a03ca8b9SKrzysztof Kosiński
19*a03ca8b9SKrzysztof Kosiński // Default implementation is a stub, i.e., for architectures whose references
20*a03ca8b9SKrzysztof Kosiński // have operation bits and payload bits stored in separate bytes. So during
21*a03ca8b9SKrzysztof Kosiński // patch application, payload bits are copied for matched blocks, ignored by
22*a03ca8b9SKrzysztof Kosiński // bytewise corrections, and fixed by reference target corrections.
ReferenceBytesMixer()23*a03ca8b9SKrzysztof Kosiński ReferenceBytesMixer::ReferenceBytesMixer() {}
24*a03ca8b9SKrzysztof Kosiński
25*a03ca8b9SKrzysztof Kosiński ReferenceBytesMixer::~ReferenceBytesMixer() = default;
26*a03ca8b9SKrzysztof Kosiński
27*a03ca8b9SKrzysztof Kosiński // static.
Create(const Disassembler & src_dis,const Disassembler & dst_dis)28*a03ca8b9SKrzysztof Kosiński std::unique_ptr<ReferenceBytesMixer> ReferenceBytesMixer::Create(
29*a03ca8b9SKrzysztof Kosiński const Disassembler& src_dis,
30*a03ca8b9SKrzysztof Kosiński const Disassembler& dst_dis) {
31*a03ca8b9SKrzysztof Kosiński ExecutableType exe_type = src_dis.GetExeType();
32*a03ca8b9SKrzysztof Kosiński DCHECK_EQ(exe_type, dst_dis.GetExeType());
33*a03ca8b9SKrzysztof Kosiński if (exe_type == kExeTypeElfAArch32)
34*a03ca8b9SKrzysztof Kosiński return std::make_unique<ReferenceBytesMixerElfArm>(exe_type);
35*a03ca8b9SKrzysztof Kosiński if (exe_type == kExeTypeElfAArch64)
36*a03ca8b9SKrzysztof Kosiński return std::make_unique<ReferenceBytesMixerElfArm>(exe_type);
37*a03ca8b9SKrzysztof Kosiński return std::make_unique<ReferenceBytesMixer>();
38*a03ca8b9SKrzysztof Kosiński }
39*a03ca8b9SKrzysztof Kosiński
40*a03ca8b9SKrzysztof Kosiński // Stub implementation.
NumBytes(uint8_t type) const41*a03ca8b9SKrzysztof Kosiński int ReferenceBytesMixer::NumBytes(uint8_t type) const {
42*a03ca8b9SKrzysztof Kosiński return 0;
43*a03ca8b9SKrzysztof Kosiński }
44*a03ca8b9SKrzysztof Kosiński
45*a03ca8b9SKrzysztof Kosiński // Base class implementation is a stub that should not be called.
Mix(uint8_t type,ConstBufferView old_view,offset_t old_offset,ConstBufferView new_view,offset_t new_offset)46*a03ca8b9SKrzysztof Kosiński ConstBufferView ReferenceBytesMixer::Mix(uint8_t type,
47*a03ca8b9SKrzysztof Kosiński ConstBufferView old_view,
48*a03ca8b9SKrzysztof Kosiński offset_t old_offset,
49*a03ca8b9SKrzysztof Kosiński ConstBufferView new_view,
50*a03ca8b9SKrzysztof Kosiński offset_t new_offset) {
51*a03ca8b9SKrzysztof Kosiński NOTREACHED() << "Stub.";
52*a03ca8b9SKrzysztof Kosiński return ConstBufferView();
53*a03ca8b9SKrzysztof Kosiński }
54*a03ca8b9SKrzysztof Kosiński
55*a03ca8b9SKrzysztof Kosiński /******** ReferenceBytesMixerElfArm ********/
56*a03ca8b9SKrzysztof Kosiński
ReferenceBytesMixerElfArm(ExecutableType exe_type)57*a03ca8b9SKrzysztof Kosiński ReferenceBytesMixerElfArm::ReferenceBytesMixerElfArm(ExecutableType exe_type)
58*a03ca8b9SKrzysztof Kosiński : exe_type_(exe_type), out_buffer_(4) {} // 4 is a bound on NumBytes().
59*a03ca8b9SKrzysztof Kosiński
60*a03ca8b9SKrzysztof Kosiński ReferenceBytesMixerElfArm::~ReferenceBytesMixerElfArm() = default;
61*a03ca8b9SKrzysztof Kosiński
NumBytes(uint8_t type) const62*a03ca8b9SKrzysztof Kosiński int ReferenceBytesMixerElfArm::NumBytes(uint8_t type) const {
63*a03ca8b9SKrzysztof Kosiński if (exe_type_ == kExeTypeElfAArch32) {
64*a03ca8b9SKrzysztof Kosiński switch (type) {
65*a03ca8b9SKrzysztof Kosiński case AArch32ReferenceType::kRel32_A24: // Falls through.
66*a03ca8b9SKrzysztof Kosiński case AArch32ReferenceType::kRel32_T20:
67*a03ca8b9SKrzysztof Kosiński case AArch32ReferenceType::kRel32_T24:
68*a03ca8b9SKrzysztof Kosiński return 4;
69*a03ca8b9SKrzysztof Kosiński case AArch32ReferenceType::kRel32_T8: // Falls through.
70*a03ca8b9SKrzysztof Kosiński case AArch32ReferenceType::kRel32_T11:
71*a03ca8b9SKrzysztof Kosiński return 2;
72*a03ca8b9SKrzysztof Kosiński }
73*a03ca8b9SKrzysztof Kosiński } else if (exe_type_ == kExeTypeElfAArch64) {
74*a03ca8b9SKrzysztof Kosiński switch (type) {
75*a03ca8b9SKrzysztof Kosiński case AArch64ReferenceType::kRel32_Immd14: // Falls through.
76*a03ca8b9SKrzysztof Kosiński case AArch64ReferenceType::kRel32_Immd19:
77*a03ca8b9SKrzysztof Kosiński case AArch64ReferenceType::kRel32_Immd26:
78*a03ca8b9SKrzysztof Kosiński return 4;
79*a03ca8b9SKrzysztof Kosiński }
80*a03ca8b9SKrzysztof Kosiński }
81*a03ca8b9SKrzysztof Kosiński return 0;
82*a03ca8b9SKrzysztof Kosiński }
83*a03ca8b9SKrzysztof Kosiński
Mix(uint8_t type,ConstBufferView old_view,offset_t old_offset,ConstBufferView new_view,offset_t new_offset)84*a03ca8b9SKrzysztof Kosiński ConstBufferView ReferenceBytesMixerElfArm::Mix(uint8_t type,
85*a03ca8b9SKrzysztof Kosiński ConstBufferView old_view,
86*a03ca8b9SKrzysztof Kosiński offset_t old_offset,
87*a03ca8b9SKrzysztof Kosiński ConstBufferView new_view,
88*a03ca8b9SKrzysztof Kosiński offset_t new_offset) {
89*a03ca8b9SKrzysztof Kosiński int num_bytes = NumBytes(type);
90*a03ca8b9SKrzysztof Kosiński ConstBufferView::const_iterator new_it = new_view.begin() + new_offset;
91*a03ca8b9SKrzysztof Kosiński DCHECK_LE(static_cast<size_t>(num_bytes), out_buffer_.size());
92*a03ca8b9SKrzysztof Kosiński MutableBufferView out_buffer_view(&out_buffer_[0], num_bytes);
93*a03ca8b9SKrzysztof Kosiński std::copy(new_it, new_it + num_bytes, out_buffer_view.begin());
94*a03ca8b9SKrzysztof Kosiński
95*a03ca8b9SKrzysztof Kosiński ArmCopyDispFun copier = GetCopier(type);
96*a03ca8b9SKrzysztof Kosiński DCHECK_NE(copier, nullptr);
97*a03ca8b9SKrzysztof Kosiński
98*a03ca8b9SKrzysztof Kosiński if (!copier(old_view, old_offset, out_buffer_view, 0U)) {
99*a03ca8b9SKrzysztof Kosiński // Failed to mix old payload bits with new operation bits. The main cause of
100*a03ca8b9SKrzysztof Kosiński // of this rare failure is when BL (encoding T1) with payload bits
101*a03ca8b9SKrzysztof Kosiński // representing disp % 4 == 2 transforms into BLX (encoding T2). Error
102*a03ca8b9SKrzysztof Kosiński // arises because BLX requires payload bits to have disp == 0 (mod 4).
103*a03ca8b9SKrzysztof Kosiński // Mixing failures are not fatal to patching; we simply fall back to direct
104*a03ca8b9SKrzysztof Kosiński // copy and forgo benefits from mixing for these cases.
105*a03ca8b9SKrzysztof Kosiński // TODO(huangs, etiennep): Ongoing discussion on whether we should just
106*a03ca8b9SKrzysztof Kosiński // nullify all payload disp so we won't have to deal with this case, but at
107*a03ca8b9SKrzysztof Kosiński // the cost of having Zucchini-apply do more work.
108*a03ca8b9SKrzysztof Kosiński static int output_quota = 10;
109*a03ca8b9SKrzysztof Kosiński if (output_quota > 0) {
110*a03ca8b9SKrzysztof Kosiński LOG(WARNING) << "Reference byte mix failed with type = "
111*a03ca8b9SKrzysztof Kosiński << static_cast<uint32_t>(type) << "." << std::endl;
112*a03ca8b9SKrzysztof Kosiński --output_quota;
113*a03ca8b9SKrzysztof Kosiński if (!output_quota)
114*a03ca8b9SKrzysztof Kosiński LOG(WARNING) << "(Additional output suppressed)";
115*a03ca8b9SKrzysztof Kosiński }
116*a03ca8b9SKrzysztof Kosiński // Fall back to direct copy.
117*a03ca8b9SKrzysztof Kosiński std::copy(new_it, new_it + num_bytes, out_buffer_view.begin());
118*a03ca8b9SKrzysztof Kosiński }
119*a03ca8b9SKrzysztof Kosiński return ConstBufferView(out_buffer_view);
120*a03ca8b9SKrzysztof Kosiński }
121*a03ca8b9SKrzysztof Kosiński
GetCopier(uint8_t type) const122*a03ca8b9SKrzysztof Kosiński ArmCopyDispFun ReferenceBytesMixerElfArm::GetCopier(uint8_t type) const {
123*a03ca8b9SKrzysztof Kosiński if (exe_type_ == kExeTypeElfAArch32) {
124*a03ca8b9SKrzysztof Kosiński switch (type) {
125*a03ca8b9SKrzysztof Kosiński case AArch32ReferenceType::kRel32_A24:
126*a03ca8b9SKrzysztof Kosiński return ArmCopyDisp<AArch32Rel32Translator::AddrTraits_A24>;
127*a03ca8b9SKrzysztof Kosiński case AArch32ReferenceType::kRel32_T8:
128*a03ca8b9SKrzysztof Kosiński return ArmCopyDisp<AArch32Rel32Translator::AddrTraits_T8>;
129*a03ca8b9SKrzysztof Kosiński case AArch32ReferenceType::kRel32_T11:
130*a03ca8b9SKrzysztof Kosiński return ArmCopyDisp<AArch32Rel32Translator::AddrTraits_T11>;
131*a03ca8b9SKrzysztof Kosiński case AArch32ReferenceType::kRel32_T20:
132*a03ca8b9SKrzysztof Kosiński return ArmCopyDisp<AArch32Rel32Translator::AddrTraits_T20>;
133*a03ca8b9SKrzysztof Kosiński case AArch32ReferenceType::kRel32_T24:
134*a03ca8b9SKrzysztof Kosiński return ArmCopyDisp<AArch32Rel32Translator::AddrTraits_T24>;
135*a03ca8b9SKrzysztof Kosiński }
136*a03ca8b9SKrzysztof Kosiński } else if (exe_type_ == kExeTypeElfAArch64) {
137*a03ca8b9SKrzysztof Kosiński switch (type) {
138*a03ca8b9SKrzysztof Kosiński case AArch64ReferenceType::kRel32_Immd14:
139*a03ca8b9SKrzysztof Kosiński return ArmCopyDisp<AArch64Rel32Translator::AddrTraits_Immd14>;
140*a03ca8b9SKrzysztof Kosiński case AArch64ReferenceType::kRel32_Immd19:
141*a03ca8b9SKrzysztof Kosiński return ArmCopyDisp<AArch64Rel32Translator::AddrTraits_Immd19>;
142*a03ca8b9SKrzysztof Kosiński case AArch64ReferenceType::kRel32_Immd26:
143*a03ca8b9SKrzysztof Kosiński return ArmCopyDisp<AArch64Rel32Translator::AddrTraits_Immd26>;
144*a03ca8b9SKrzysztof Kosiński }
145*a03ca8b9SKrzysztof Kosiński }
146*a03ca8b9SKrzysztof Kosiński DLOG(FATAL) << "NOTREACHED";
147*a03ca8b9SKrzysztof Kosiński return nullptr;
148*a03ca8b9SKrzysztof Kosiński }
149*a03ca8b9SKrzysztof Kosiński
150*a03ca8b9SKrzysztof Kosiński } // namespace zucchini
151