blob: f46c275ce7a0f7c50e3f163fbf1b605340e4a2a3 [file] [log] [blame]
// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Declares TypedBlock and ConstTypedBlock. These are thin wrappers to
// BlockGraph::Block objects which allow the data within a block to be
// interpreted as an object of a given type.
//
// Example use is as follows:
//
// BlockGraph::Block* dos_header_block = ...;
// TypedBlock<IMAGE_DOS_HEADER> dos_header;
// DCHECK(dos_header.Init(0, dos_header_block));
//
// // Reference the fields of the object as if we had a pointer to the object.
// if (dos_header->e_magic == ...) ...
//
// // Dereference pointers in the object using 'Dereference'. This takes care
// // of finding, validating and following references within the block graph.
// TypedBlock<IMAGE_NT_HEADERS> nt_headers;
// DCHECK(dos_header.Dereference(dos_header->e_lfanew, &nt_headers));
//
// For full details of the API, refer to internal::TypedBlockImpl, defined in
// syzygy/block_graph/typed_block_internal.h
#ifndef SYZYGY_BLOCK_GRAPH_TYPED_BLOCK_H_
#define SYZYGY_BLOCK_GRAPH_TYPED_BLOCK_H_
#include "syzygy/block_graph/block_graph.h"
namespace block_graph {
namespace internal {
typedef BlockGraph::Block* BlockPtr;
typedef const BlockGraph::Block* ConstBlockPtr;
// Forward declare.
template <typename T, typename BlockPtr, typename ChildType>
class TypedBlockImpl;
} // namespace internal
// Used for interpreting a non-const BlockGraph::Block's data as a mutable
// object of type T. Augments TypedBlockImpl with routine's for modifying
// references.
template <typename T> class TypedBlock
: public internal::TypedBlockImpl<T,
internal::BlockPtr,
TypedBlock<T>> {
public:
typedef BlockGraph::Block Block;
typedef BlockGraph::Offset Offset;
typedef BlockGraph::Reference Reference;
typedef BlockGraph::ReferenceType ReferenceType;
typedef BlockGraph::Size Size;
typedef T ObjectType;
template <typename T2> struct Rebind {
typedef TypedBlock<typename T2> Type;
};
TypedBlock() : TypedBlockImpl() { }
// Accesses the block encapsulated by this typed block.
//
// @returns a non-const pointer to the encapsulated block.
internal::BlockPtr block() { return block_; }
// Accesses the block encapsulated by this typed block.
//
// @returns a const pointer to the encapsulated block.
internal::ConstBlockPtr block() const { return block_; }
// Removes the reference at the given offset. Will clear a reference of any
// size and type.
//
// @param offset the offset of the reference to clear.
void RemoveReferenceAt(Offset offset) {
RemoveReferenceImpl(offset, 0);
}
// Removes the reference at the given offset, but only if it has the given
// size. Returns false if there exists a reference at the offset but with a
// different size, true otherwise.
//
// @param offset the offset of the reference to clear.
// @param size the size of the reference to clear.
// @returns true on success, false otherwise.
bool RemoveReferenceAt(Offset offset, size_t size) {
return RemoveReferenceImpl(offset, size);
}
// Removes the reference corresponding to the given value. Succeeds if there
// is no reference at the offset, or if the existing reference has the same
// size as the value.
//
// @tparam TIn the type of @p value.
// @param value the value in this block encapsulating the reference to erase.
template <typename TIn>
bool RemoveReference(const TIn& value) {
return RemoveReferenceImpl(OffsetOf(value), sizeof(TIn));
}
// Builds a reference with the given type, offset and size to the given
// block and offset.
//
// @param reference_type the type of reference to create.
// @param reference_offset the offset of the reference to construct.
// @param reference_size the size of the reference to construct.
// @param referenced_block the block to be referenced.
// @param referenced_offset the offset into the block to be directly
// referenced.
// @param referenced_base the offset into the block of the item that is
// actually being referenced.
// @returns true iff this inserts a new reference.
bool SetReference(ReferenceType reference_type,
Offset reference_offset,
size_t reference_size,
Block* referenced_block,
Offset referenced_offset,
Offset referenced_base);
// Sets a reference from one value to a given block/offset. The size of the
// reference will be sizeof(TFrom).
//
// @tparam TFrom the type of @p value_from.
// @param reference_type the type of reference to create.
// @param value_from the value which will hold the created reference.
// @param block_to the block to be referenced.
// @param offset_to the offset of @p block_to to be referenced directly.
// @param base_to the offset of @p block_to to be actually referenced.
template <typename TFrom>
bool SetReference(ReferenceType reference_type,
const TFrom& value_from,
Block* block_to,
Offset offset_to,
Offset base_to) {
DCHECK(block_to != NULL);
return SetReference(reference_type, OffsetOf(value_from), sizeof(TFrom),
block_to, offset_to, base_to);
}
// Sets a direct reference (where base = offset) from one value to another
// typed block. The size of the reference will be sizeof(TFrom).
//
// @tparam TFrom the type of @p value_from.
// @tparam T2 the type encapsulated by @p typed_block_to.
// @param reference_type the type of reference to create.
// @param value_from the value which will hold the created reference.
// @param typed_block_to the typed block that will be referenced. The
// reference will be constructed to the beginning of the object
// encapsulated by the typed block.
// @returns true iff this inserts a new reference.
template <typename TFrom, typename T2>
bool SetReference(ReferenceType reference_type,
const TFrom& value_from,
const TypedBlock<T2>& typed_block_to) {
return SetReference(reference_type, OffsetOf(value_from), sizeof(TFrom),
const_cast<Block*>(typed_block_to.block()), typed_block_to.offset(),
typed_block_to.offset());
}
// Sets a direct reference (where base = offset) from one value to another.
// The size of the reference will be sizeof(TFrom). The offset and base are
// inferred from the position of @p value_to in @p typed_block_to.
//
// @tparam TFrom the type of @p value_from.
// @tparam T2 the type encapsulated by @p typed_block_to.
// @tparam TTo the type of value_to.
// @param reference_type the type of reference to create.
// @param value_from the value which will hold the created reference.
// @param typed_block_to the typed block that will be referenced.
// @param value_to the value within @p typed_block_to that will be referenced.
// @returns true iff this inserts a new reference.
template <typename TFrom, typename T2, typename TTo>
bool SetReference(ReferenceType reference_type,
const TFrom& value_from,
const TypedBlock<T2>& typed_block_to,
const TTo& value_to) {
Offset offset_to = typed_block_to.OffsetOf(value_to);
return SetReference(reference_type, OffsetOf(value_from), sizeof(TFrom),
const_cast<Block*>(typed_block_to.block()), offset_to, offset_to);
}
private:
// Clears the reference at the given @p offset, but only if it has the given
// @p size. If @p size = 0, then a reference of any size will be cleared.
// Returns true on success, false otherwise.
//
// @param offset the offset of the reference to erase.
// @param size the size of the reference to erase, 0 if it doesn't matter.
bool RemoveReferenceImpl(Offset offset, size_t size);
DISALLOW_COPY_AND_ASSIGN(TypedBlock);
};
// Used for interpreting a const BlockGraph::Block's data as a constant object
// of type T.
template <typename T> class ConstTypedBlock
: public internal::TypedBlockImpl<const T,
internal::ConstBlockPtr,
ConstTypedBlock<T>> {
public:
typedef T ObjectType;
template <typename T2> struct Rebind {
typedef ConstTypedBlock<T2> Type;
};
ConstTypedBlock() : TypedBlockImpl() { }
// Accesses the block encapsulated by this typed block.
//
// @returns a const pointer to the encapsulated block.
internal::ConstBlockPtr block() const { return block_; }
private:
DISALLOW_COPY_AND_ASSIGN(ConstTypedBlock);
};
template <typename T>
bool TypedBlock<T>::SetReference(ReferenceType reference_type,
Offset reference_offset,
Size reference_size,
Block* referenced_block,
Offset referenced_offset,
Offset referenced_base) {
DCHECK(referenced_block != NULL);
BlockGraph::Reference reference(reference_type, reference_size,
referenced_block, referenced_offset,
referenced_base);
return block_->SetReference(reference_offset, reference);
}
template <typename T>
bool TypedBlock<T>::RemoveReferenceImpl(Offset offset, size_t size) {
if (size != 0) {
Reference reference;
if (block_->GetReference(offset, &reference)) {
if (reference.size() != size)
return false;
}
}
block_->RemoveReference(offset);
return true;
}
} // namespace block_graph
// This brings in the implementation.
#include "syzygy/block_graph/typed_block_internal.h"
#endif // SYZYGY_BLOCK_GRAPH_TYPED_BLOCK_H_