123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- // 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.
- #include "components/zucchini/abs32_utils.h"
- #include <algorithm>
- #include <type_traits>
- #include <utility>
- #include "base/check_op.h"
- #include "components/zucchini/io_utils.h"
- namespace zucchini {
- namespace {
- // Templated helper for AbsoluteAddress::Read().
- template <typename T>
- bool ReadAbs(ConstBufferView image, offset_t offset, uint64_t* value) {
- static_assert(std::is_unsigned<T>::value, "Value type must be unsigned.");
- if (!image.can_access<T>(offset))
- return false;
- *value = static_cast<uint64_t>(image.read<T>(offset));
- return true;
- }
- // Templated helper for AbsoluteAddress::Write().
- template <typename T>
- bool WriteAbs(offset_t offset, T value, MutableBufferView* image) {
- static_assert(std::is_unsigned<T>::value, "Value type must be unsigned.");
- if (!image->can_access<T>(offset))
- return false;
- image->write<T>(offset, value);
- return true;
- }
- } // namespace
- /******** AbsoluteAddress ********/
- AbsoluteAddress::AbsoluteAddress(Bitness bitness, uint64_t image_base)
- : bitness_(bitness), image_base_(image_base), value_(image_base) {
- CHECK(bitness_ == kBit64 || image_base_ < 0x100000000ULL);
- }
- AbsoluteAddress::AbsoluteAddress(AbsoluteAddress&&) = default;
- AbsoluteAddress::~AbsoluteAddress() = default;
- bool AbsoluteAddress::FromRva(rva_t rva) {
- if (rva >= kRvaBound)
- return false;
- uint64_t value = image_base_ + rva;
- // Check overflow, which manifests as |value| "wrapping around", resulting in
- // |value| less than |image_base_| (preprocessing needed for 32-bit).
- if (((bitness_ == kBit32) ? (value & 0xFFFFFFFFU) : value) < image_base_)
- return false;
- value_ = value;
- return true;
- }
- rva_t AbsoluteAddress::ToRva() const {
- if (value_ < image_base_)
- return kInvalidRva;
- uint64_t raw_rva = value_ - image_base_;
- if (raw_rva >= kRvaBound)
- return kInvalidRva;
- return static_cast<rva_t>(raw_rva);
- }
- bool AbsoluteAddress::Read(offset_t offset, const ConstBufferView& image) {
- // Read raw data; |value_| is not guaranteed to represent a valid RVA.
- if (bitness_ == kBit32)
- return ReadAbs<uint32_t>(image, offset, &value_);
- DCHECK_EQ(kBit64, bitness_);
- return ReadAbs<uint64_t>(image, offset, &value_);
- }
- bool AbsoluteAddress::Write(offset_t offset, MutableBufferView* image) {
- if (bitness_ == kBit32)
- return WriteAbs<uint32_t>(offset, static_cast<uint32_t>(value_), image);
- DCHECK_EQ(kBit64, bitness_);
- return WriteAbs<uint64_t>(offset, value_, image);
- }
- /******** Abs32RvaExtractorWin32 ********/
- Abs32RvaExtractorWin32::Abs32RvaExtractorWin32(
- ConstBufferView image,
- AbsoluteAddress&& addr,
- const std::deque<offset_t>& abs32_locations,
- offset_t lo,
- offset_t hi)
- : image_(image), addr_(std::move(addr)) {
- CHECK_LE(lo, hi);
- auto find_and_check = [this](const std::deque<offset_t>& locations,
- offset_t offset) {
- auto it = std::lower_bound(locations.begin(), locations.end(), offset);
- // Ensure that |offset| does not straddle a reference body.
- CHECK(it == locations.begin() || offset - *(it - 1) >= addr_.width());
- return it;
- };
- cur_abs32_ = find_and_check(abs32_locations, lo);
- end_abs32_ = find_and_check(abs32_locations, hi);
- }
- Abs32RvaExtractorWin32::Abs32RvaExtractorWin32(Abs32RvaExtractorWin32&&) =
- default;
- Abs32RvaExtractorWin32::~Abs32RvaExtractorWin32() = default;
- absl::optional<Abs32RvaExtractorWin32::Unit> Abs32RvaExtractorWin32::GetNext() {
- while (cur_abs32_ < end_abs32_) {
- offset_t location = *(cur_abs32_++);
- if (!addr_.Read(location, image_))
- continue;
- rva_t target_rva = addr_.ToRva();
- if (target_rva == kInvalidRva)
- continue;
- return Unit{location, target_rva};
- }
- return absl::nullopt;
- }
- /******** Abs32ReaderWin32 ********/
- Abs32ReaderWin32::Abs32ReaderWin32(Abs32RvaExtractorWin32&& abs32_rva_extractor,
- const AddressTranslator& translator)
- : abs32_rva_extractor_(std::move(abs32_rva_extractor)),
- target_rva_to_offset_(translator) {}
- Abs32ReaderWin32::~Abs32ReaderWin32() = default;
- absl::optional<Reference> Abs32ReaderWin32::GetNext() {
- for (auto unit = abs32_rva_extractor_.GetNext(); unit.has_value();
- unit = abs32_rva_extractor_.GetNext()) {
- offset_t location = unit->location;
- offset_t unsafe_target = target_rva_to_offset_.Convert(unit->target_rva);
- if (unsafe_target != kInvalidOffset)
- return Reference{location, unsafe_target};
- }
- return absl::nullopt;
- }
- /******** Abs32WriterWin32 ********/
- Abs32WriterWin32::Abs32WriterWin32(MutableBufferView image,
- AbsoluteAddress&& addr,
- const AddressTranslator& translator)
- : image_(image),
- addr_(std::move(addr)),
- target_offset_to_rva_(translator) {}
- Abs32WriterWin32::~Abs32WriterWin32() = default;
- void Abs32WriterWin32::PutNext(Reference ref) {
- rva_t target_rva = target_offset_to_rva_.Convert(ref.target);
- if (target_rva != kInvalidRva) {
- addr_.FromRva(target_rva);
- addr_.Write(ref.location, &image_);
- }
- }
- /******** Exported Functions ********/
- size_t RemoveUntranslatableAbs32(ConstBufferView image,
- AbsoluteAddress&& addr,
- const AddressTranslator& translator,
- std::deque<offset_t>* locations) {
- AddressTranslator::RvaToOffsetCache target_rva_checker(translator);
- Abs32RvaExtractorWin32 extractor(image, std::move(addr), *locations, 0,
- image.size());
- Abs32ReaderWin32 reader(std::move(extractor), translator);
- std::deque<offset_t>::iterator write_it = locations->begin();
- // |reader| reads |locations| while |write_it| modifies it. However, there's
- // no conflict since read occurs before write, and can skip ahead.
- for (auto ref = reader.GetNext(); ref.has_value(); ref = reader.GetNext())
- *(write_it++) = ref->location;
- DCHECK(write_it <= locations->end());
- size_t num_removed = locations->end() - write_it;
- locations->erase(write_it, locations->end());
- return num_removed;
- }
- size_t RemoveOverlappingAbs32Locations(uint32_t width,
- std::deque<offset_t>* locations) {
- if (locations->size() <= 1)
- return 0;
- auto slow = locations->begin();
- auto fast = locations->begin() + 1;
- for (;;) {
- // Find next good location.
- while (fast != locations->end() && *fast - *slow < width)
- ++fast;
- // Advance |slow|. For the last iteration this becomes the new sentinel.
- ++slow;
- if (fast == locations->end())
- break;
- // Compactify good locations (potentially overwrite bad locations).
- if (slow != fast)
- *slow = *fast;
- ++fast;
- }
- size_t num_removed = locations->end() - slow;
- locations->erase(slow, locations->end());
- return num_removed;
- }
- } // namespace zucchini
|