1 : // Copyright 2012 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/grinder/basic_block_entry_count_serializer.h"
16 :
17 : #include <string>
18 : #include <utility>
19 :
20 : #include "base/stringprintf.h"
21 : #include "base/files/file_path.h"
22 : #include "base/json/json_reader.h"
23 : #include "syzygy/common/indexed_frequency_data.h"
24 : #include "syzygy/core/json_file_writer.h"
25 : #include "syzygy/pdb/pdb_reader.h"
26 : #include "syzygy/pdb/pdb_util.h"
27 : #include "syzygy/pe/find.h"
28 : #include "syzygy/pe/metadata.h"
29 : #include "syzygy/pe/pe_file.h"
30 :
31 : namespace grinder {
32 :
33 : namespace {
34 :
35 : using core::JSONFileWriter;
36 : using basic_block_util::EntryCountType;
37 : using basic_block_util::EntryCountMap;
38 : using basic_block_util::ModuleEntryCountMap;
39 : using basic_block_util::ModuleInformation;
40 :
41 : const char kMetadata[] = "metadata";
42 : const char kEntryCounts[] = "entry_counts";
43 :
44 : bool OutputEntryCount(
45 : JSONFileWriter* writer,
46 : const ModuleInformation& module_information,
47 E : const EntryCountMap& entry_counts) {
48 E : DCHECK(writer != NULL);
49 :
50 : // Start a new dictionary.
51 E : if (!writer->OpenDict())
52 i : return false;
53 :
54 : // Pour the module information into a PE Metadata object, for convenient
55 : // JSON serialization.
56 E : pe::Metadata metadata;
57 E : if (!metadata.Init(pe::PEFile::Signature(module_information)))
58 i : return false;
59 :
60 : // Output the module metadata.
61 : if (!writer->OutputKey(kMetadata) ||
62 E : !metadata.SaveToJSON(writer)) {
63 i : return false;
64 : }
65 :
66 : // Output the entry count array.
67 : if (!writer->OutputComment(base::StringPrintf(
68 : "%d basic-block counter values.", entry_counts.size()).c_str()) ||
69 : !writer->OutputKey(kEntryCounts) ||
70 E : !writer->OpenList()) {
71 i : return false;
72 : }
73 :
74 E : EntryCountMap::const_iterator it = entry_counts.begin();
75 E : for (; it != entry_counts.end(); ++it) {
76 : if (!writer->OpenList() ||
77 : !writer->OutputInteger(it->first) ||
78 : !writer->OutputInteger(it->second) ||
79 E : !writer->CloseList())
80 i : return false;
81 E : }
82 :
83 E : if (!writer->CloseList())
84 i : return false;
85 :
86 : // Close the dictionary.
87 E : if (!writer->CloseDict())
88 i : return false;
89 :
90 : // And we're done.
91 E : return true;
92 E : }
93 :
94 : bool ReadEntryCount(const base::DictionaryValue* dict_value,
95 E : ModuleEntryCountMap* module_entry_count_map) {
96 E : DCHECK(dict_value != NULL);
97 E : DCHECK(module_entry_count_map != NULL);
98 :
99 : // Load the metadata about the image.
100 E : const base::DictionaryValue* metadata_dict = NULL;
101 E : if (!dict_value->GetDictionary(kMetadata, &metadata_dict)) {
102 E : LOG(ERROR) << "Missing or invalid " << kMetadata << " entry.";
103 E : return false;
104 : }
105 :
106 E : pe::Metadata metadata;
107 E : if (!metadata.LoadFromJSON(*metadata_dict)) {
108 : // The loader will log any errors.
109 i : return false;
110 : }
111 :
112 : // Extract the entry count list.
113 E : const base::ListValue* entry_count_list = NULL;
114 E : if (!dict_value->GetList(kEntryCounts, &entry_count_list)) {
115 E : LOG(ERROR) << "Missing or invalid " << kEntryCounts << " entry.";
116 E : return false;
117 : }
118 :
119 : // Convert the signature into a ModuleInformation struct.
120 E : const pe::PEFile::Signature& signature = metadata.module_signature();
121 E : ModuleInformation module_information;
122 E : module_information.base_address = signature.base_address.value();
123 E : module_information.image_checksum = signature.module_checksum;
124 E : module_information.image_file_name = signature.path;
125 E : module_information.module_size = signature.module_size;
126 E : module_information.time_date_stamp = signature.module_time_date_stamp;
127 :
128 : // Insert a new entry count record for this module.
129 : std::pair<ModuleEntryCountMap::iterator, bool> result =
130 : module_entry_count_map->insert(std::make_pair(
131 E : module_information, EntryCountMap()));
132 :
133 : // Validate that we really did insert a new module into the map.
134 E : if (!result.second) {
135 i : LOG(ERROR) << "Found duplicate entries for " << signature.path << ".";
136 i : return false;
137 : }
138 :
139 : // Populate the entry count vector with the values in the list.
140 E : EntryCountMap& values = result.first->second;
141 E : size_t num_entries = entry_count_list->GetSize();
142 E : for (size_t i = 0; i < num_entries; ++i) {
143 E : basic_block_util::BasicBlockOffset offset = 0;
144 E : basic_block_util::EntryCountType entry_count = 0;
145 E : const base::ListValue* entry = NULL;
146 : if (!entry_count_list->GetList(i, &entry) ||
147 : entry->GetSize() != 2 ||
148 : !entry->GetInteger(0, &offset) ||
149 : !entry->GetInteger(1, &entry_count) ||
150 E : offset < 0 || entry_count < 0) {
151 E : LOG(ERROR) << "Invalid value in entry count list.";
152 E : return false;
153 : }
154 :
155 E : if (!values.insert(std::make_pair(offset, entry_count)).second) {
156 i : LOG(ERROR) << "Duplicate basic block offset in entry count list.";
157 i : return false;
158 : }
159 E : }
160 :
161 : // And we're done.
162 E : return true;
163 E : }
164 :
165 : } // namespace
166 :
167 : BasicBlockEntryCountSerializer::BasicBlockEntryCountSerializer()
168 E : : pretty_print_(false) {
169 E : }
170 :
171 : bool BasicBlockEntryCountSerializer::SaveAsJson(
172 E : const ModuleEntryCountMap& entry_count_map, FILE* file) {
173 E : DCHECK(file != NULL);
174 E : core::JSONFileWriter writer(file, pretty_print_);
175 :
176 : // Open the list;
177 E : if (!writer.OpenList())
178 i : return false;
179 :
180 : // Output each entry;
181 E : ModuleEntryCountMap::const_iterator it = entry_count_map.begin();
182 E : for (; it != entry_count_map.end(); ++it) {
183 E : if (!OutputEntryCount(&writer, it->first, it->second))
184 i : return false;
185 E : }
186 :
187 : // Close the list.
188 E : if (!writer.CloseList())
189 i : return false;
190 :
191 E : return true;
192 E : }
193 :
194 : bool BasicBlockEntryCountSerializer::SaveAsJson(
195 E : const ModuleEntryCountMap& entry_count_map, const base::FilePath& path) {
196 E : DCHECK(!path.empty());
197 E : file_util::ScopedFILE file(file_util::OpenFile(path, "wb"));
198 E : if (file.get() == NULL) {
199 i : LOG(ERROR) << "Failed to open " << path.value() << " for reading.";
200 i : return false;
201 : }
202 :
203 E : if (!SaveAsJson(entry_count_map, file.get())) {
204 i : LOG(ERROR) << "Failed to write JSON data to " << path.value() << ".";
205 i : return false;
206 : }
207 :
208 E : return true;
209 E : }
210 :
211 : bool BasicBlockEntryCountSerializer::LoadFromJson(
212 E : const base::FilePath& path, ModuleEntryCountMap* module_entry_count_map) {
213 E : DCHECK(module_entry_count_map != NULL);
214 E : DCHECK(!path.empty());
215 :
216 E : std::string json_string;
217 E : if (!file_util::ReadFileToString(path, &json_string)) {
218 E : LOG(ERROR) << "Failed to read '" << path.value() << "'.";
219 E : return false;
220 : }
221 :
222 E : base::JSONReader json_reader;
223 E : std::string error_msg;
224 : scoped_ptr<base::Value> json_value(
225 : json_reader.ReadAndReturnError(
226 E : json_string, base::JSON_ALLOW_TRAILING_COMMAS, NULL, &error_msg));
227 E : if (json_value.get() == NULL) {
228 E : LOG(ERROR) << "Failed to parse '" << path.value() << "' as JSON ("
229 : << error_msg << ").";
230 E : return false;
231 : }
232 :
233 E : if (!PopulateFromJsonValue(json_value.get(), module_entry_count_map))
234 i : return false;
235 :
236 E : return true;
237 E : }
238 :
239 : bool BasicBlockEntryCountSerializer::PopulateFromJsonValue(
240 : const base::Value* json_value,
241 E : ModuleEntryCountMap* module_entry_count_map) {
242 E : DCHECK(json_value != NULL);
243 E : DCHECK(module_entry_count_map != NULL);
244 :
245 E : module_entry_count_map->clear();
246 :
247 : // Extract the top level list of module.
248 E : const base::ListValue* module_list = NULL;
249 E : if (!json_value->GetAsList(&module_list)) {
250 E : LOG(ERROR) << "Expected a list as the top level JSON construct.";
251 E : return false;
252 : }
253 :
254 : // Extract each module.
255 E : size_t num_modules = module_list->GetSize();
256 E : for (size_t i = 0; i < num_modules; ++i) {
257 E : const base::DictionaryValue* dict_value = NULL;
258 E : if (!module_list->GetDictionary(i, &dict_value)) {
259 E : LOG(ERROR) << "Invalid type for entry " << i << ".";
260 E : return false;
261 : }
262 E : if (!ReadEntryCount(dict_value, module_entry_count_map)) {
263 : // ReadEntryCount() has already logged the error.
264 E : return false;
265 : }
266 E : }
267 :
268 E : return true;
269 E : }
270 :
271 : } // namespace grinder
|