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