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 |