aboutsummaryrefslogtreecommitdiff
path: root/abs32_utils.cc
diff options
context:
space:
mode:
authorSamuel Huang <huangs@chromium.org>2018-03-13 18:19:34 +0000
committerEdward Lesmes <ehmaldonado@google.com>2021-07-23 21:50:59 +0000
commit06f1ae9aaca969ee95ef840f22b6b461c304542d (patch)
treef1e5c6624e70628e81fbf38d6cd14b974abe5d93 /abs32_utils.cc
downloadzucchini-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.cc201
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