diff options
author | Samuel Huang <huangs@chromium.org> | 2018-03-13 18:19:34 +0000 |
---|---|---|
committer | Edward Lesmes <ehmaldonado@google.com> | 2021-07-23 21:50:59 +0000 |
commit | 06f1ae9aaca969ee95ef840f22b6b461c304542d (patch) | |
tree | f1e5c6624e70628e81fbf38d6cd14b974abe5d93 /abs32_utils.cc | |
download | zucchini-06f1ae9aaca969ee95ef840f22b6b461c304542d.tar.gz |
[Zucchini] Move Zucchini from /chrome/installer/ to /components/.
(Use "git log --follow" to see older revisions of files).
/components/ is the most logical place to put Zucchini, which only
depends on /base and /testing/gtest. This move also enables Zucchini to
be used by the Component Updater. Details:
- Move all files; run the following to change deps and guards:
sed 's/chrome\/installer/components/' *.cc *.h -i
sed 's/CHROME_INSTALLER/COMPONENTS/' *.cc *.h -i
- Sorting works out pretty well!
- Change all 'chrome/installer/zucchini' to 'components/zucchini'
throughout other parts of the repo; sort if necessary.
- Fix 6 'git cl lint' errors.
- Change 1 Bind() usage to BindRepeated().
- Update OWNER.
Bug: 729154
Change-Id: I50c5a7d411ea85f707b5994ab319dfb2a1acccf7
Reviewed-on: https://chromium-review.googlesource.com/954923
Reviewed-by: Greg Thompson <grt@chromium.org>
Reviewed-by: Jochen Eisinger <jochen@chromium.org>
Reviewed-by: Samuel Huang <huangs@chromium.org>
Commit-Queue: Samuel Huang <huangs@chromium.org>
Cr-Commit-Position: refs/heads/master@{#542857}
NOKEYCHECK=True
GitOrigin-RevId: 577ef6c435e8d43be6e3e60ccbcbd1881780f4ec
Diffstat (limited to 'abs32_utils.cc')
-rw-r--r-- | abs32_utils.cc | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/abs32_utils.cc b/abs32_utils.cc new file mode 100644 index 0000000..b45da7e --- /dev/null +++ b/abs32_utils.cc @@ -0,0 +1,201 @@ +// 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/logging.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::vector<offset_t>& abs32_locations, + offset_t lo, + offset_t hi) + : image_(image), addr_(std::move(addr)) { + CHECK_LE(lo, hi); + auto find_and_check = [&addr](const std::vector<offset_t>& locations, + offset_t offset) { + auto it = std::lower_bound(locations.begin(), locations.end(), offset); + // Ensure |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; + +base::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 base::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; + +base::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 target = target_rva_to_offset_.Convert(unit->target_rva); + if (target == kInvalidOffset) + continue; + // In rare cases, the most significant bit of |target| is set. This + // interferes with label marking. A quick fix is to reject these. + if (IsMarked(target)) { + LOG(WARNING) << "Warning: Skipping mark-aliased PE abs32 target: " + << AsHex<8>(location) << " -> " << AsHex<8>(target) << "."; + continue; + } + return Reference{location, target}; + } + return base::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 RemoveOverlappingAbs32Locations(Bitness bitness, + std::vector<offset_t>* locations) { + if (locations->size() <= 1) + return 0; + + uint32_t width = WidthOf(bitness); + 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 |