1 : // Copyright 2015 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/instrument/instrumenters/flummox_instrumenter.h"
16 :
17 : #include <algorithm>
18 : #include <sstream>
19 :
20 : #include "base/values.h"
21 : #include "base/files/file_util.h"
22 : #include "base/json/json_reader.h"
23 : #include "base/strings/string_util.h"
24 : #include "syzygy/application/application.h"
25 :
26 : namespace instrument {
27 : namespace instrumenters {
28 :
29 : namespace {
30 :
31 : using base::DictionaryValue;
32 : using base::ListValue;
33 : using base::Value;
34 :
35 : } // namespace
36 :
37 E : bool FlummoxInstrumenter::FlummoxConfig::ReadFromJSON(const std::string& json) {
38 E : bool input_add_copy = false;
39 E : scoped_ptr<Value> value(base::JSONReader::Read(json));
40 E : if (value.get() == nullptr) {
41 i : LOG(ERROR) << "Invalid or empty configuration JSON.";
42 i : return false;
43 : }
44 E : if (value->GetType() != Value::TYPE_DICTIONARY) {
45 i : LOG(ERROR) << "Invalid allocation filter transform file.";
46 i : return false;
47 : }
48 :
49 : const DictionaryValue* outer_dict =
50 E : reinterpret_cast<const DictionaryValue*>(value.get());
51 :
52 E : std::string targets_key("targets");
53 E : const DictionaryValue* targets_dict = nullptr;
54 :
55 E : if (!outer_dict->GetDictionary(targets_key, &targets_dict)) {
56 i : LOG(ERROR) << "Outer dictionary must contain key 'targets'.";
57 i : return false;
58 : }
59 :
60 E : std::set<std::string> temp_target_set;
61 E : DictionaryValue::Iterator it(*targets_dict);
62 E : for (; !it.IsAtEnd(); it.Advance()) {
63 E : std::string function_name = it.key();
64 E : const ListValue* strategy_list = nullptr;
65 E : if (!it.value().GetAsList(&strategy_list)) {
66 i : LOG(ERROR) << "Strategy list expected.";
67 i : return false;
68 : }
69 : // TODO(huangs): Load strategies.
70 : // for (const Value* strategy : *strategy_list) { }
71 E : temp_target_set.insert(function_name);
72 E : }
73 :
74 E : std::string add_copy_key("add_copy");
75 : if (outer_dict->HasKey(add_copy_key) &&
76 E : !outer_dict->GetBoolean(add_copy_key, &input_add_copy)) {
77 i : LOG(ERROR) << add_copy_key << " must be a boolean.";
78 i : return false;
79 : }
80 :
81 : // Success!
82 E : target_set_.swap(temp_target_set);
83 E : add_copy_ = input_add_copy;
84 E : return true;
85 E : }
86 :
87 : bool FlummoxInstrumenter::FlummoxConfig::ReadFromJSONPath(
88 E : const base::FilePath& path) {
89 E : std::string file_string;
90 E : if (!base::ReadFileToString(path, &file_string)) {
91 i : LOG(ERROR) << "Unable to read file to string.";
92 i : return false;
93 : }
94 E : if (!ReadFromJSON(file_string)) {
95 i : LOG(ERROR) << "Unable to parse JSON string.";
96 i : return false;
97 : }
98 E : return true;
99 E : }
100 :
101 E : bool FlummoxInstrumenter::InstrumentPrepare() {
102 E : return config_.ReadFromJSONPath(flummox_config_path_);
103 E : }
104 :
105 E : bool FlummoxInstrumenter::InstrumentImpl() {
106 : flummox_transform_.reset(
107 : new instrument::transforms::FillerTransform(
108 E : config_.target_set(), config_.add_copy()));
109 E : flummox_transform_->set_debug_friendly(debug_friendly_);
110 :
111 E : if (!relinker_->AppendTransform(flummox_transform_.get())) {
112 i : LOG(ERROR) << "Failed to apply transform.";
113 i : return false;
114 : }
115 :
116 E : return true;
117 E : }
118 :
119 : bool FlummoxInstrumenter::DoCommandLineParse(
120 E : const base::CommandLine* command_line) {
121 E : DCHECK(command_line != nullptr);
122 :
123 E : if (!Super::DoCommandLineParse(command_line))
124 i : return false;
125 :
126 : // Parse the target list filename.
127 : flummox_config_path_ = application::AppImplBase::AbsolutePath(
128 E : command_line->GetSwitchValuePath("flummox-config-path"));
129 E : if (flummox_config_path_.empty()) {
130 i : LOG(ERROR) << "You must specify --flummox-config-path.";
131 i : return false;
132 : }
133 :
134 E : return true;
135 E : }
136 :
137 : } // namespace instrumenters
138 : } // namespace instrument
|