blob: 95cf5e17a777e2b45aa9bd62b4e9d3c377c46933 [file] [log] [blame]
// 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/instrument/instrumenters/flummox_instrumenter.h"
#include <algorithm>
#include <sstream>
#include "base/values.h"
#include "base/files/file_util.h"
#include "base/json/json_reader.h"
#include "base/strings/string_util.h"
#include "syzygy/application/application.h"
namespace instrument {
namespace instrumenters {
namespace {
using base::DictionaryValue;
using base::ListValue;
using base::Value;
} // namespace
bool FlummoxInstrumenter::FlummoxConfig::ReadFromJSON(const std::string& json) {
bool input_add_copy = false;
std::unique_ptr<Value> value(base::JSONReader::Read(json).release());
if (value.get() == nullptr) {
LOG(ERROR) << "Invalid or empty configuration JSON.";
return false;
}
if (value->GetType() != Value::TYPE_DICTIONARY) {
LOG(ERROR) << "Invalid allocation filter transform file.";
return false;
}
const DictionaryValue* outer_dict =
reinterpret_cast<const DictionaryValue*>(value.get());
std::string targets_key("targets");
const DictionaryValue* targets_dict = nullptr;
if (!outer_dict->GetDictionary(targets_key, &targets_dict)) {
LOG(ERROR) << "Outer dictionary must contain key 'targets'.";
return false;
}
std::set<std::string> temp_target_set;
DictionaryValue::Iterator it(*targets_dict);
for (; !it.IsAtEnd(); it.Advance()) {
std::string function_name = it.key();
const ListValue* strategy_list = nullptr;
if (!it.value().GetAsList(&strategy_list)) {
LOG(ERROR) << "Strategy list expected.";
return false;
}
// TODO(huangs): Load strategies.
// for (const Value* strategy : *strategy_list) { }
temp_target_set.insert(function_name);
}
std::string add_copy_key("add_copy");
if (outer_dict->HasKey(add_copy_key) &&
!outer_dict->GetBoolean(add_copy_key, &input_add_copy)) {
LOG(ERROR) << add_copy_key << " must be a boolean.";
return false;
}
// Success!
target_set_.swap(temp_target_set);
add_copy_ = input_add_copy;
return true;
}
bool FlummoxInstrumenter::FlummoxConfig::ReadFromJSONPath(
const base::FilePath& path) {
std::string file_string;
if (!base::ReadFileToString(path, &file_string)) {
LOG(ERROR) << "Unable to read file to string.";
return false;
}
if (!ReadFromJSON(file_string)) {
LOG(ERROR) << "Unable to parse JSON string.";
return false;
}
return true;
}
bool FlummoxInstrumenter::InstrumentPrepare() {
return config_.ReadFromJSONPath(flummox_config_path_);
}
bool FlummoxInstrumenter::InstrumentImpl() {
flummox_transform_.reset(
new instrument::transforms::FillerTransform(
config_.target_set(), config_.add_copy()));
flummox_transform_->set_debug_friendly(debug_friendly_);
if (!relinker_->AppendTransform(flummox_transform_.get())) {
LOG(ERROR) << "Failed to apply transform.";
return false;
}
return true;
}
bool FlummoxInstrumenter::DoCommandLineParse(
const base::CommandLine* command_line) {
DCHECK(command_line != nullptr);
if (!Super::DoCommandLineParse(command_line))
return false;
// Parse the target list filename.
flummox_config_path_ = application::AppImplBase::AbsolutePath(
command_line->GetSwitchValuePath("flummox-config-path"));
if (flummox_config_path_.empty()) {
LOG(ERROR) << "You must specify --flummox-config-path.";
return false;
}
return true;
}
} // namespace instrumenters
} // namespace instrument