| Index: syzygy/refinery/analyzers/type_propagator_analyzer.cc
|
| diff --git a/syzygy/refinery/analyzers/type_propagator_analyzer.cc b/syzygy/refinery/analyzers/type_propagator_analyzer.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..04e63bf0ee3b89dc4761412dcd534e3b2d782241
|
| --- /dev/null
|
| +++ b/syzygy/refinery/analyzers/type_propagator_analyzer.cc
|
| @@ -0,0 +1,171 @@
|
| +// Copyright 2015 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.
|
| +
|
| +#include "syzygy/refinery/analyzers/type_propagator_analyzer.h"
|
| +
|
| +#include <queue>
|
| +
|
| +#include "syzygy/refinery/process_state/process_state_util.h"
|
| +#include "syzygy/refinery/process_state/refinery.pb.h"
|
| +#include "syzygy/refinery/types/type.h"
|
| +
|
| +namespace refinery {
|
| +
|
| +// static
|
| +const char TypePropagatorAnalyzer::kTypePropagatorAnalyzerName[] =
|
| + "TypePropagatorAnalyzer";
|
| +
|
| +TypePropagatorAnalyzer::TypePropagatorAnalyzer(
|
| + scoped_refptr<SymbolProvider> symbol_provider)
|
| + : symbol_provider_(symbol_provider) {
|
| + DCHECK(symbol_provider.get() != nullptr);
|
| +}
|
| +
|
| +Analyzer::AnalysisResult TypePropagatorAnalyzer::Analyze(
|
| + const minidump::Minidump& minidump,
|
| + ProcessState* process_state) {
|
| + DCHECK(process_state != nullptr);
|
| +
|
| + // Analyzers that build content for the bytes and typed block layer must have
|
| + // already run. We use the existence of a bytes layer and a typed block layer
|
| + // as a proxy for this. Longer term, a proper notion of analyzer dependencies
|
| + // should be introduced.
|
| + BytesLayerPtr bytes_layer;
|
| + if (!process_state->FindLayer(&bytes_layer)) {
|
| + LOG(ERROR) << "Missing bytes layer.";
|
| + return ANALYSIS_ERROR;
|
| + }
|
| + TypedBlockLayerPtr typed_layer;
|
| + if (!process_state->FindLayer(&typed_layer)) {
|
| + LOG(ERROR) << "Missing typed block layer.";
|
| + return ANALYSIS_ERROR;
|
| + }
|
| +
|
| + ModuleLayerAccessor accessor(process_state);
|
| +
|
| + std::queue<TypedData> process_queue;
|
| +
|
| + // Recover typed data from the typed block layer.
|
| + for (TypedBlockRecordPtr rec : *typed_layer) {
|
| + const TypedBlock& typedblock = rec->data();
|
| +
|
| + // Recover the type.
|
| + pe::PEFile::Signature signature;
|
| + if (!accessor.GetModuleSignature(typedblock.module_id(), &signature))
|
| + return ANALYSIS_ERROR;
|
| +
|
| + scoped_refptr<TypeRepository> type_repository;
|
| + if (!symbol_provider_->FindOrCreateTypeRepository(signature,
|
| + &type_repository)) {
|
| + return ANALYSIS_ERROR;
|
| + }
|
| +
|
| + TypePtr type = type_repository->GetType(typedblock.type_id());
|
| + if (type == nullptr)
|
| + return ANALYSIS_ERROR;
|
| +
|
| + // Queue typed data for processing.
|
| + process_queue.push(TypedData(process_state, type, rec->range().start()));
|
| + }
|
| +
|
| + // Process typed data looking for pointers or contained pointers.
|
| + while (!process_queue.empty()) {
|
| + if (!AnalyzeTypedData(process_queue.front(), process_state))
|
| + return ANALYSIS_ERROR;
|
| + process_queue.pop();
|
| + }
|
| +
|
| + return ANALYSIS_COMPLETE;
|
| +}
|
| +
|
| +bool TypePropagatorAnalyzer::AnalyzeTypedData(const TypedData& typed_data,
|
| + ProcessState* process_state) {
|
| + DCHECK(process_state != nullptr);
|
| +
|
| + TypePtr type = typed_data.type();
|
| + DCHECK(type.get());
|
| +
|
| + switch (type->kind()) {
|
| + case Type::USER_DEFINED_TYPE_KIND:
|
| + return AnalyzeTypedDataUDT(typed_data, process_state);
|
| + case Type::POINTER_TYPE_KIND:
|
| + return AnalyzeTypedDataPointer(typed_data, process_state);
|
| + case Type::ARRAY_TYPE_KIND:
|
| + return AnalyzeTypedDataArray(typed_data, process_state);
|
| + case Type::BASIC_TYPE_KIND:
|
| + case Type::FUNCTION_TYPE_KIND:
|
| + case Type::GLOBAL_TYPE_KIND:
|
| + case Type::WILDCARD_TYPE_KIND:
|
| + // Nothing to do with these.
|
| + return true;
|
| + default:
|
| + DCHECK(false);
|
| + return false;
|
| + }
|
| +}
|
| +
|
| +bool TypePropagatorAnalyzer::AnalyzeTypedDataUDT(const TypedData& typed_data,
|
| + ProcessState* process_state) {
|
| + DCHECK_EQ(Type::USER_DEFINED_TYPE_KIND, typed_data.type()->kind());
|
| + DCHECK(process_state != nullptr);
|
| +
|
| + // TODO(manzagop): implement.
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool TypePropagatorAnalyzer::AnalyzeTypedDataPointer(
|
| + const TypedData& typed_data,
|
| + ProcessState* process_state) {
|
| + DCHECK_EQ(Type::POINTER_TYPE_KIND, typed_data.type()->kind());
|
| + DCHECK(process_state != nullptr);
|
| +
|
| + TypedData content_data;
|
| + if (!typed_data.Dereference(&content_data)) {
|
| + // Unable to dereference. This may be because the pointer's contents (the
|
| + // address of the pointee) are not available.
|
| + // TODO(manzagop): have a better way to distinguish a failure (can't cast
|
| + // pointer) from an acceptable negative result (missing the required bytes)
|
| + // and have counters for these kinds of events.
|
| + return true;
|
| + }
|
| +
|
| + return AddTypedBlock(content_data, process_state);
|
| +}
|
| +
|
| +bool TypePropagatorAnalyzer::AnalyzeTypedDataArray(
|
| + const TypedData& typed_data,
|
| + ProcessState* process_state) {
|
| + DCHECK_EQ(Type::ARRAY_TYPE_KIND, typed_data.type()->kind());
|
| + DCHECK(process_state != nullptr);
|
| +
|
| + // TODO(manzagop): implement.
|
| + return true;
|
| +}
|
| +
|
| +bool TypePropagatorAnalyzer::AddTypedBlock(const TypedData& typed_data,
|
| + ProcessState* process_state) {
|
| + ModuleLayerAccessor accessor(process_state);
|
| + pe::PEFile::Signature signature;
|
| + if (!typed_data.type()->repository()->GetModuleSignature(&signature))
|
| + return false;
|
| + ModuleId module_id = accessor.GetModuleId(signature);
|
| + if (module_id == kNoModuleId)
|
| + return false;
|
| +
|
| + return AddTypedBlockRecord(typed_data.GetRange(), L"", module_id,
|
| + typed_data.type()->type_id(), process_state);
|
| +}
|
| +
|
| +} // namespace refinery
|
|
|