123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212 |
- // Copyright 2017 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_REL32_UTILS_H_
- #define COMPONENTS_ZUCCHINI_REL32_UTILS_H_
- #include <algorithm>
- #include <array>
- #include <deque>
- #include <memory>
- #include "base/logging.h"
- #include "components/zucchini/address_translator.h"
- #include "components/zucchini/arm_utils.h"
- #include "components/zucchini/buffer_view.h"
- #include "components/zucchini/image_utils.h"
- #include "components/zucchini/io_utils.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- namespace zucchini {
- // Reader that emits x86 / x64 References (locations and target) from a list of
- // valid locations, constrained by a portion of an image.
- class Rel32ReaderX86 : public ReferenceReader {
- public:
- // |image| is an image containing x86 / x64 code in [|lo|, |hi|).
- // |locations| is a sorted list of offsets of rel32 reference locations.
- // |translator| (for |image|) is embedded into |target_rva_to_offset_| and
- // |location_offset_to_rva_| for address translation, and therefore must
- // outlive |*this|.
- Rel32ReaderX86(ConstBufferView image,
- offset_t lo,
- offset_t hi,
- const std::deque<offset_t>* locations,
- const AddressTranslator& translator);
- Rel32ReaderX86(const Rel32ReaderX86&) = delete;
- const Rel32ReaderX86& operator=(const Rel32ReaderX86&) = delete;
- ~Rel32ReaderX86() override;
- // Returns the next reference, or absl::nullopt if exhausted.
- absl::optional<Reference> GetNext() override;
- private:
- ConstBufferView image_;
- AddressTranslator::RvaToOffsetCache target_rva_to_offset_;
- AddressTranslator::OffsetToRvaCache location_offset_to_rva_;
- const offset_t hi_;
- const std::deque<offset_t>::const_iterator last_;
- std::deque<offset_t>::const_iterator current_;
- };
- // Writer for x86 / x64 rel32 References.
- class Rel32WriterX86 : public ReferenceWriter {
- public:
- // |image| wraps the raw bytes of a binary in which rel32 references will be
- // written. |translator| (for |image|) is embedded into
- // |target_offset_to_rva_| and |location_offset_to_rva_| for address
- // translation, and therefore must outlive |*this|.
- Rel32WriterX86(MutableBufferView image, const AddressTranslator& translator);
- Rel32WriterX86(const Rel32WriterX86&) = delete;
- const Rel32WriterX86& operator=(const Rel32WriterX86&) = delete;
- ~Rel32WriterX86() override;
- void PutNext(Reference ref) override;
- private:
- MutableBufferView image_;
- AddressTranslator::OffsetToRvaCache target_offset_to_rva_;
- AddressTranslator::OffsetToRvaCache location_offset_to_rva_;
- };
- // Reader that emits x86 / x64 References (locations and target) of a spcific
- // type from a list of valid locations, constrained by a portion of an image.
- template <class ADDR_TRAITS>
- class Rel32ReaderArm : public ReferenceReader {
- public:
- using CODE_T = typename ADDR_TRAITS::code_t;
- Rel32ReaderArm(const AddressTranslator& translator,
- ConstBufferView view,
- const std::deque<offset_t>& rel32_locations,
- offset_t lo,
- offset_t hi)
- : view_(view),
- offset_to_rva_(translator),
- rva_to_offset_(translator),
- hi_(hi) {
- cur_it_ =
- std::lower_bound(rel32_locations.begin(), rel32_locations.end(), lo);
- rel32_end_ = rel32_locations.end();
- }
- Rel32ReaderArm(const Rel32ReaderArm&) = delete;
- const Rel32ReaderArm& operator=(const Rel32ReaderArm&) = delete;
- absl::optional<Reference> GetNext() override {
- while (cur_it_ < rel32_end_ && *cur_it_ < hi_) {
- offset_t location = *(cur_it_++);
- CODE_T code = ADDR_TRAITS::Fetch(view_, location);
- rva_t instr_rva = offset_to_rva_.Convert(location);
- rva_t target_rva = kInvalidRva;
- if (ADDR_TRAITS::Read(instr_rva, code, &target_rva)) {
- offset_t target = rva_to_offset_.Convert(target_rva);
- if (target != kInvalidOffset)
- return Reference{location, target};
- }
- }
- return absl::nullopt;
- }
- private:
- ConstBufferView view_;
- AddressTranslator::OffsetToRvaCache offset_to_rva_;
- AddressTranslator::RvaToOffsetCache rva_to_offset_;
- std::deque<offset_t>::const_iterator cur_it_;
- std::deque<offset_t>::const_iterator rel32_end_;
- offset_t hi_;
- };
- // Writer for ARM rel32 References of a specific type.
- template <class ADDR_TRAITS>
- class Rel32WriterArm : public ReferenceWriter {
- public:
- using CODE_T = typename ADDR_TRAITS::code_t;
- Rel32WriterArm(const AddressTranslator& translator,
- MutableBufferView mutable_view)
- : mutable_view_(mutable_view), offset_to_rva_(translator) {}
- Rel32WriterArm(const Rel32WriterArm&) = delete;
- const Rel32WriterArm& operator=(const Rel32WriterArm&) = delete;
- void PutNext(Reference ref) override {
- CODE_T code = ADDR_TRAITS::Fetch(mutable_view_, ref.location);
- rva_t instr_rva = offset_to_rva_.Convert(ref.location);
- rva_t target_rva = offset_to_rva_.Convert(ref.target);
- if (ADDR_TRAITS::Write(instr_rva, target_rva, &code)) {
- ADDR_TRAITS::Store(mutable_view_, ref.location, code);
- } else {
- LOG(ERROR) << "Write error: " << AsHex<8>(ref.location) << ": "
- << AsHex<static_cast<int>(sizeof(CODE_T)) * 2>(code)
- << " <= " << AsHex<8>(target_rva) << ".";
- }
- }
- private:
- MutableBufferView mutable_view_;
- AddressTranslator::OffsetToRvaCache offset_to_rva_;
- };
- // Copier that makes |*dst_it| similar to |*src_it| (both assumed to point to
- // rel32 instructions of type ADDR_TRAITS) by copying the displacement (i.e.,
- // payload bits) from |src_it| to |dst_it|. If successful, updates |*dst_it|,
- // and returns true. Otherwise returns false. Note that alignment is not an
- // issue since the displacement is not translated to target RVA!
- template <class ADDR_TRAITS>
- bool ArmCopyDisp(ConstBufferView src_view,
- offset_t src_idx,
- MutableBufferView dst_view,
- offset_t dst_idx) {
- using CODE_T = typename ADDR_TRAITS::code_t;
- CODE_T src_code = ADDR_TRAITS::Fetch(src_view, src_idx);
- arm_disp_t disp = 0;
- if (ADDR_TRAITS::Decode(src_code, &disp)) {
- CODE_T dst_code = ADDR_TRAITS::Fetch(dst_view, dst_idx);
- if (ADDR_TRAITS::Encode(disp, &dst_code)) {
- ADDR_TRAITS::Store(dst_view, dst_idx, dst_code);
- return true;
- }
- }
- return false;
- }
- // Outputs error message (throttled) on ArmCopyDisp failure.
- void OutputArmCopyDispFailure(uint32_t addr_type);
- // Mixer for ARM rel32 References of a specific type.
- template <class ADDR_TRAITS>
- class Rel32MixerArm : public ReferenceMixer {
- using code_t = typename ADDR_TRAITS::code_t;
- static constexpr size_t kCodeWidth = sizeof(code_t);
- public:
- Rel32MixerArm(ConstBufferView src_image, ConstBufferView dst_image)
- : src_image_(src_image), dst_image_(dst_image) {}
- ~Rel32MixerArm() override = default;
- ConstBufferView Mix(offset_t src_offset, offset_t dst_offset) override {
- ConstBufferView::const_iterator new_it = dst_image_.begin() + dst_offset;
- MutableBufferView out_buffer_view(out_buffer_.data(), kCodeWidth);
- std::copy(new_it, new_it + kCodeWidth, out_buffer_view.begin());
- if (!ArmCopyDisp<ADDR_TRAITS>(src_image_, src_offset, out_buffer_view,
- 0U)) {
- OutputArmCopyDispFailure(static_cast<uint32_t>(ADDR_TRAITS::addr_type));
- // Fall back to direct copy.
- std::copy(new_it, new_it + kCodeWidth, out_buffer_.begin());
- }
- return ConstBufferView(out_buffer_.data(), kCodeWidth);
- }
- private:
- ConstBufferView src_image_;
- ConstBufferView dst_image_;
- std::array<uint8_t, sizeof(code_t)> out_buffer_;
- };
- } // namespace zucchini
- #endif // COMPONENTS_ZUCCHINI_REL32_UTILS_H_
|