1 : // Copyright 2012 Google Inc.
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 : // Parses a module and ETW trace files, generating an ordering of the
16 : // blocks in the decomposed image.
17 :
18 : #include <objbase.h>
19 : #include <iostream>
20 :
21 : #include "base/at_exit.h"
22 : #include "base/command_line.h"
23 : #include "base/file_path.h"
24 : #include "base/string_number_conversions.h"
25 : #include "base/string_split.h"
26 : #include "base/stringprintf.h"
27 : #include "syzygy/reorder/dead_code_finder.h"
28 : #include "syzygy/reorder/linear_order_generator.h"
29 : #include "syzygy/reorder/random_order_generator.h"
30 :
31 m : using reorder::DeadCodeFinder;
32 m : using reorder::LinearOrderGenerator;
33 m : using reorder::RandomOrderGenerator;
34 m : using reorder::Reorderer;
35 :
36 m : static const char kUsage[] =
37 m : "Usage: reorder [options] [ETW log files ...]\n"
38 m : " Required Options:\n"
39 m : " --instrumented-dll=<path> the path to the instrumented DLL.\n"
40 m : " --output-file=<path> the output file.\n"
41 m : " Optional Options:\n"
42 m : " --input-dll=<path> the input DLL to reorder. If this is not\n"
43 m : " specified it will be inferred from the instrumented DLL\n"
44 m : " metadata.\n"
45 m : " --seed=INT generates a random ordering; don't specify ETW log files.\n"
46 m : " --list-dead-code instead of an ordering, output the set of functions\n"
47 m : " not visited during the trace.\n"
48 m : " --pretty-print enables pretty printing of the JSON output file.\n"
49 m : " --reorderer-flags=<comma separated reorderer flags>\n"
50 m : " Reorderer Flags:\n"
51 m : " no-code: Do not reorder code sections.\n"
52 m : " no-data: Do not reorder data sections.\n";
53 :
54 m : const char kFlags[] = "reorderer-flags";
55 :
56 m : static int Usage(const char* message) {
57 m : std::cerr << message << std::endl << kUsage;
58 :
59 m : return 1;
60 m : }
61 :
62 : // Parses reorderer flags. Returns true on success, false otherwise. On
63 : // failure, also outputs Usage with an error message.
64 m : static bool ParseReordererFlags(CommandLine* cmd_line,
65 m : Reorderer::Flags* flags) {
66 m : DCHECK(cmd_line != NULL);
67 m : DCHECK(flags != NULL);
68 :
69 m : Reorderer::Flags out_flags = (Reorderer::kFlagReorderData |
70 m : Reorderer::kFlagReorderCode);
71 :
72 m : if (cmd_line->HasSwitch(kFlags)) {
73 m : typedef std::vector<std::string> TextFlags;
74 m : TextFlags text_flags;
75 m : base::SplitString(cmd_line->GetSwitchValueASCII(kFlags), ',', &text_flags);
76 m : TextFlags::const_iterator flag_iter = text_flags.begin();
77 m : for (; flag_iter != text_flags.end(); ++flag_iter) {
78 m : if (*flag_iter == "no-data") {
79 m : out_flags &= ~Reorderer::kFlagReorderData;
80 m : } else if (*flag_iter == "no-code") {
81 m : out_flags &= ~Reorderer::kFlagReorderCode;
82 m : } else if (!flag_iter->empty()) {
83 m : std::string message = base::StringPrintf("Unknown reorderer flag: %s.",
84 m : flag_iter->c_str());
85 m : Usage(message.c_str());
86 m : return false;
87 m : }
88 m : }
89 m : }
90 m : *flags = out_flags;
91 :
92 m : return true;
93 m : }
94 :
95 m : int main(int argc, char** argv) {
96 m : base::AtExitManager at_exit_manager;
97 m : CommandLine::Init(argc, argv);
98 :
99 m : if (!logging::InitLogging(L"", logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG,
100 m : logging::DONT_LOCK_LOG_FILE, logging::APPEND_TO_OLD_LOG_FILE,
101 m : logging::ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS)) {
102 m : return 1;
103 m : }
104 :
105 m : CommandLine* cmd_line = CommandLine::ForCurrentProcess();
106 m : DCHECK(cmd_line != NULL);
107 :
108 : // Parse the command line.
109 m : typedef CommandLine::StringType StringType;
110 m : FilePath instrumented_dll_path =
111 m : cmd_line->GetSwitchValuePath("instrumented-dll");
112 m : FilePath input_dll_path = cmd_line->GetSwitchValuePath("input-dll");
113 m : FilePath output_file = cmd_line->GetSwitchValuePath("output-file");
114 :
115 m : int seed = 0;
116 m : StringType seed_str(cmd_line->GetSwitchValueNative("seed"));
117 m : if (!seed_str.empty() && !base::StringToInt(seed_str, &seed)) {
118 m : return Usage("Invalid seed value.");
119 m : }
120 :
121 m : std::vector<FilePath> trace_paths;
122 m : for (size_t i = 0; i < cmd_line->GetArgs().size(); ++i)
123 m : trace_paths.push_back(FilePath(cmd_line->GetArgs()[i]));
124 m : bool pretty_print = cmd_line->HasSwitch("pretty-print");
125 m : bool list_dead_code = cmd_line->HasSwitch("list-dead-code");
126 :
127 m : if (instrumented_dll_path.empty() || output_file.empty()) {
128 m : return Usage(
129 m : "You must specify instrumented-dll and output-file.");
130 m : }
131 :
132 m : if (seed_str.empty()) {
133 m : if (trace_paths.size() < 1) {
134 m : return Usage("You must specify at least one trace file "
135 m : "if you are not generating a random ordering.");
136 m : }
137 m : } else {
138 m : if (list_dead_code || trace_paths.size()) {
139 m : return Usage("Do not specify list-dead-code or ETW trace files when "
140 m : "generating a random ordering.");
141 m : }
142 m : }
143 :
144 m : Reorderer::Flags reorderer_flags = 0;
145 m : if (!ParseReordererFlags(cmd_line, &reorderer_flags)) {
146 m : return 1;
147 m : }
148 :
149 : // Initialize COM, as it is used by Decomposer, ComdatOrder and Reorderer.
150 m : if (FAILED(CoInitialize(NULL))) {
151 m : LOG(ERROR) << "Failed to initialize COM.";
152 m : return 1;
153 m : }
154 :
155 m : scoped_ptr<Reorderer::OrderGenerator> order_generator;
156 m : if (!seed_str.empty()) {
157 m : order_generator.reset(new RandomOrderGenerator(seed));
158 m : } else if (list_dead_code) {
159 m : order_generator.reset(new DeadCodeFinder());
160 m : } else {
161 m : order_generator.reset(new LinearOrderGenerator());
162 m : }
163 :
164 m : pe::PEFile input_dll;
165 m : block_graph::BlockGraph block_graph;
166 m : pe::ImageLayout image_layout(&block_graph);
167 m : reorder::Reorderer::Order order;
168 m : Reorderer reorderer(input_dll_path,
169 m : instrumented_dll_path,
170 m : trace_paths,
171 m : reorderer_flags);
172 m : if (!reorderer.Reorder(order_generator.get(),
173 m : &order,
174 m : &input_dll,
175 m : &image_layout)) {
176 m : LOG(ERROR) << "Reorder failed.";
177 m : return 1;
178 m : }
179 :
180 m : if (!order.SerializeToJSON(input_dll, output_file, pretty_print)) {
181 m : LOG(ERROR) << "Unable to output order.";
182 m : return 1;
183 m : }
184 :
185 m : CoUninitialize();
186 :
187 m : return 0;
188 m : }
|