blob: a4691fd8938c4657f06c1d92567f31198e30d45b [file] [log] [blame]
// 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 <stddef.h>
#include <vector>
#include "base/logging.h"
#include "base/macros.h"
#include "base/optional.h"
#include "components/zucchini/buffer_view.h"
#include "components/zucchini/image_utils.h"
namespace zucchini {
// See for definitions on abs32 and rel32 references. The following
// are assumed:
// * Abs32 reference bodies have fixed widths.
// * Rel32 locations can be identified by heuristically disassembling machine
// code, and errors are tolerated.
// * The collection all abs32 and rel32 reference bodies do not overlap.
// A class to visit non-empty contiguous gaps in |region| that lie outside of
// |abs32_locations| elements, each with a body that spans |abs32_width_| bytes.
// For example, given:
// region = [base_ + 4, base_ + 26),
// abs32_locations = {2, 6, 15, 20, 27},
// abs32_width_ = 4,
// the following is obtained:
// 111111111122222222223 -> offsets
// 0123456789012345678901234567890
// ....**********************..... -> region = *
// ^ ^ ^ ^ ^ -> abs32 locations
// aaaaaaaa aaaa aaaa aaaa -> abs32 bodies
// ....------*****----*----**..... -> regions excluding abs32 -> 3 gaps
// The resulting gaps (non-empty, so [6, 6) is excluded) are:
// [10, 15), [19, 20), [24, 26).
// These gaps can then be passed to Rel32Finder (below) to find rel32 references
// with bodies that are guaranteed to not overlap with any abs32 bodies.
class Abs32GapFinder {
// |abs32_locations| is a sorted list of non-overlapping abs32 locations in
// |image|, each spanning |abs32_width| bytes. Gaps are searched in |region|,
// which must be part of |image|.
Abs32GapFinder(ConstBufferView image,
ConstBufferView region,
const std::vector<offset_t>& abs32_locations,
size_t abs32_width);
// Returns the next available gap, or nullopt if exhausted.
base::Optional<ConstBufferView> GetNext();
const ConstBufferView::const_iterator base_;
const ConstBufferView::const_iterator region_end_;
ConstBufferView::const_iterator current_lo_;
std::vector<offset_t>::const_iterator abs32_current_;
std::vector<offset_t>::const_iterator abs32_end_;
size_t abs32_width_;
// A class to scan regions within an image to find successive rel32 references.
// Architecture-specific parsing and result extraction are delegated to
// inherited classes. This is typically used along with Abs32GapFinder to find
// search regions.
class Rel32Finder {
virtual ~Rel32Finder();
// Assigns the scan |region| for rel32 references to enable FindNext() use.
void SetRegion(ConstBufferView region);
// When a rel32 reference is found, the caller needs to decide whether to keep
// the result (perhaps following more validation). If it decides to keep the
// result, then it must call Accept(), so the next call to FindNext() can skip
// the accepted rel32 reference.
void Accept();
// Accessors for unittest.
ConstBufferView::const_iterator accept_it() const { return accept_it_; }
ConstBufferView region() const { return region_; }
// Alternatives for where to continue the next scan when a rel32 reference is
// found. nulls indicate that no rel32 references remain.
struct NextIterators {
// The next iterator if the caller does not call Accept().
ConstBufferView::const_iterator reject;
// The next iterator if the caller calls Accept().
ConstBufferView::const_iterator accept;
// Scans for the next rel32 reference, and returns whether any is found, so a
// "while" loop can be used for iterative rel32 extraction. The results are
// cached in Rel32Finder_Impl and obtained by Rel32Finder_Impl::GetRel32().
bool FindNext();
// Detects and extracts architecture-specific rel32 reference. For each one
// found, the implementation should cache the necessary data to be retrieved
// via accessors. Returns a NextIterators that stores alternatives for where
// to continue the scan. If no rel32 reference is found then the returned
// NextIterators are nulls.
virtual NextIterators Scan(ConstBufferView region) = 0;
ConstBufferView region_;
ConstBufferView::const_iterator accept_it_ = nullptr;
// Parsing for X86 or X64: we perform naive scan for opcodes that have rel32 as
// an argument, and disregard instruction alignment.
class Rel32FinderIntel : public Rel32Finder {
// Struct to store GetNext() results.
struct Result {
ConstBufferView::const_iterator location;
// Some references must have their target in the same section as location,
// which we use this to heuristically reject rel32 reference candidates.
// When true, this constraint is relaxed.
bool can_point_outside_section;
using Rel32Finder::Rel32Finder;
// Returns the next available Result, or nullopt if exhausted.
base::Optional<Result> GetNext() {
if (FindNext())
return rel32_;
return base::nullopt;
// Helper for Scan() that also assigns |rel32_|.
Rel32Finder::NextIterators SetResult(ConstBufferView::const_iterator cursor,
uint32_t code_size,
bool can_point_outside_section);
// Cached results.
Result rel32_;
// Rel32Finder:
NextIterators Scan(ConstBufferView region) override = 0;
// X86 instructions.
class Rel32FinderX86 : public Rel32FinderIntel {
using Rel32FinderIntel::Rel32FinderIntel;
// Rel32Finder:
NextIterators Scan(ConstBufferView region) override;
// X64 instructions.
class Rel32FinderX64 : public Rel32FinderIntel {
using Rel32FinderIntel::Rel32FinderIntel;
// Rel32Finder:
NextIterators Scan(ConstBufferView region) override;
} // namespace zucchini