[M108 Migration][HBBTV] Implement ewk_context_register_jsplugin_mime_types API
[platform/framework/web/chromium-efl.git] / courgette / courgette_tool.cc
1 // Copyright 2011 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <stdarg.h>
6 #include <stddef.h>
7 #include <stdint.h>
8
9 #include <initializer_list>
10 #include <memory>
11 #include <string>
12 #include <tuple>
13 #include <vector>
14
15 #include "base/at_exit.h"
16 #include "base/command_line.h"
17 #include "base/files/file_path.h"
18 #include "base/files/file_util.h"
19 #include "base/files/memory_mapped_file.h"
20 #include "base/logging.h"
21 #include "base/strings/string_number_conversions.h"
22 #include "base/strings/string_util.h"
23 #include "base/strings/utf_string_conversions.h"
24 #include "courgette/assembly_program.h"
25 #include "courgette/courgette.h"
26 #include "courgette/courgette_flow.h"
27 #include "courgette/encoded_program.h"
28 #include "courgette/program_detector.h"
29 #include "courgette/streams.h"
30 #include "courgette/third_party/bsdiff/bsdiff.h"
31
32 namespace {
33
34 using courgette::CourgetteFlow;
35
36 const char kUsageGen[] = "-gen <old_in> <new_in> <patch_out>";
37 const char kUsageApply[] = "-apply <old_in> <patch_in> <new_out>";
38 const char kUsageGenbsdiff[] = "-genbsdiff <old_in> <new_in> <patch_out>";
39 const char kUsageApplybsdiff[] = "-applybsdiff <old_in> <patch_in> <new_out>";
40 const char kUsageSupported[] = "-supported <exec_file_in>";
41 const char kUsageDis[] = "-dis <exec_file_in> <assembly_file_out>";
42 const char kUsageAsm[] = "-asm <assembly_file_in> <exec_file_out>";
43 const char kUsageDisadj[] = "-disadj <old_in> <new_in> <new_assembly_file_out>";
44 const char kUsageGen1[] = "-gen1[au] <old_in> <new_in> <patch_base_out>";
45
46 /******** Utilities to print help and exit ********/
47
48 void PrintHelp() {
49   fprintf(stderr, "Main Usage:\n");
50   for (auto usage :
51        {kUsageGen, kUsageApply, kUsageGenbsdiff, kUsageApplybsdiff}) {
52     fprintf(stderr, "  courgette %s\n", usage);
53   }
54   fprintf(stderr, "Diagnosis Usage:\n");
55   for (auto usage :
56        {kUsageSupported, kUsageDis, kUsageAsm, kUsageDisadj, kUsageGen1}) {
57     fprintf(stderr, "  courgette %s\n", usage);
58   }
59 }
60
61 void UsageProblem(const char* message) {
62   fprintf(stderr, "%s", message);
63   fprintf(stderr, "\n");
64   PrintHelp();
65   exit(1);
66 }
67
68 void Problem(const char* format, ...) {
69   va_list args;
70   va_start(args, format);
71   vfprintf(stderr, format, args);
72   fprintf(stderr, "\n");
73   va_end(args);
74   exit(1);
75 }
76
77 /******** BufferedFileReader ********/
78
79 // A file reader that calls Problem() on failure.
80 class BufferedFileReader : public courgette::BasicBuffer {
81  public:
82   BufferedFileReader(const base::FilePath& file_name, const char* kind) {
83     if (!buffer_.Initialize(file_name))
84       Problem("Can't read %s file.", kind);
85   }
86
87   BufferedFileReader(const BufferedFileReader&) = delete;
88   BufferedFileReader& operator=(const BufferedFileReader&) = delete;
89
90   ~BufferedFileReader() override = default;
91
92   // courgette::BasicBuffer:
93   const uint8_t* data() const override { return buffer_.data(); }
94   size_t length() const override { return buffer_.length(); }
95
96  private:
97   base::MemoryMappedFile buffer_;
98 };
99
100 /******** Various helpers ********/
101
102 void WriteSinkToFile(const courgette::SinkStream* sink,
103                      const base::FilePath& output_file) {
104   int count = base::WriteFile(output_file,
105                               reinterpret_cast<const char*>(sink->Buffer()),
106                               static_cast<int>(sink->Length()));
107   if (count == -1)
108     Problem("Can't write output.");
109   if (static_cast<size_t>(count) != sink->Length())
110     Problem("Incomplete write.");
111 }
112
113 bool Supported(const base::FilePath& input_file) {
114   bool result = false;
115
116   BufferedFileReader buffer(input_file, "input");
117
118   courgette::ExecutableType type;
119   size_t detected_length;
120
121   DetectExecutableType(buffer.data(), buffer.length(), &type, &detected_length);
122
123   // If the detection fails, we just fall back on UNKNOWN
124   std::string format = "Unsupported";
125
126   switch (type) {
127     case courgette::EXE_UNKNOWN:
128       break;
129
130     case courgette::EXE_WIN_32_X86:
131       format = "Windows 32 PE";
132       result = true;
133       break;
134
135     case courgette::EXE_ELF_32_X86:
136       format = "ELF 32 X86";
137       result = true;
138       break;
139
140     case courgette::EXE_WIN_32_X64:
141       format = "Windows 64 PE";
142       result = true;
143       break;
144   }
145
146   printf("%s Executable\n", format.c_str());
147   return result;
148 }
149
150 void Disassemble(const base::FilePath& input_file,
151                  const base::FilePath& output_file) {
152   CourgetteFlow flow;
153   BufferedFileReader input_buffer(input_file, flow.name(flow.ONLY));
154   flow.ReadDisassemblerFromBuffer(flow.ONLY, input_buffer);
155   flow.CreateAssemblyProgramFromDisassembler(flow.ONLY, false);
156   flow.CreateEncodedProgramFromDisassemblerAndAssemblyProgram(flow.ONLY);
157   flow.DestroyDisassembler(flow.ONLY);
158   flow.DestroyAssemblyProgram(flow.ONLY);
159   flow.WriteSinkStreamSetFromEncodedProgram(flow.ONLY);
160   flow.DestroyEncodedProgram(flow.ONLY);
161   courgette::SinkStream sink;
162   flow.WriteSinkStreamFromSinkStreamSet(flow.ONLY, &sink);
163   if (flow.failed())
164     Problem(flow.message().c_str());
165
166   WriteSinkToFile(&sink, output_file);
167 }
168
169 void DisassembleAndAdjust(const base::FilePath& old_file,
170                           const base::FilePath& new_file,
171                           const base::FilePath& output_file) {
172   // Flow graph and process sequence (DA = Disassembler, AP = AssemblyProgram,
173   // EP = EncodedProgram, Adj = Adjusted):
174   //   [1 Old DA] --> [2 Old AP]    [4 New AP] <-- [3 New DA]
175   //                      |             |              |
176   //                      |             v (move)       v
177   //                      +---> [5 Adj New AP] --> [6 New EP]
178   //                                               (7 Write)
179   CourgetteFlow flow;
180   BufferedFileReader old_buffer(old_file, flow.name(flow.OLD));
181   BufferedFileReader new_buffer(new_file, flow.name(flow.NEW));
182   flow.ReadDisassemblerFromBuffer(flow.OLD, old_buffer);       // 1
183   flow.CreateAssemblyProgramFromDisassembler(flow.OLD, true);  // 2
184   flow.DestroyDisassembler(flow.OLD);
185   flow.ReadDisassemblerFromBuffer(flow.NEW, new_buffer);       // 3
186   flow.CreateAssemblyProgramFromDisassembler(flow.NEW, true);  // 4
187   flow.AdjustNewAssemblyProgramToMatchOld();                   // 5
188   flow.DestroyAssemblyProgram(flow.OLD);
189   flow.CreateEncodedProgramFromDisassemblerAndAssemblyProgram(flow.NEW);  // 6
190   flow.DestroyAssemblyProgram(flow.NEW);
191   flow.DestroyDisassembler(flow.NEW);
192   flow.WriteSinkStreamSetFromEncodedProgram(flow.NEW);  // 7
193   flow.DestroyEncodedProgram(flow.NEW);
194   courgette::SinkStream sink;
195   flow.WriteSinkStreamFromSinkStreamSet(flow.NEW, &sink);
196   if (flow.failed())
197     Problem(flow.message().c_str());
198
199   WriteSinkToFile(&sink, output_file);
200 }
201
202 // Diffs two executable files, write a set of files for the diff, one file per
203 // stream of the EncodedProgram format.  Each file is the bsdiff between the
204 // original file's stream and the new file's stream.  This is completely
205 // uninteresting to users, but it is handy for seeing how much each which
206 // streams are contributing to the final file size.  Adjustment is optional.
207 void DisassembleAdjustDiff(const base::FilePath& old_file,
208                            const base::FilePath& new_file,
209                            const base::FilePath& output_file_root,
210                            bool adjust) {
211   // Same as PatchGeneratorX86_32::Transform(), except Adjust is optional, and
212   // |flow|'s internal SinkStreamSet get used.
213   // Flow graph and process sequence (DA = Disassembler, AP = AssemblyProgram,
214   // EP = EncodedProgram, Adj = Adjusted):
215   //   [1 Old DA] --> [2 Old AP]   [6 New AP] <-- [5 New DA]
216   //       |            |   |          |              |
217   //       v            |   |          v (move)       v
218   //   [3 Old EP] <-----+   +->[7 Adj New AP] --> [8 New EP]
219   //   (4 Write)                                  (9 Write)
220   CourgetteFlow flow;
221   BufferedFileReader old_buffer(old_file, flow.name(flow.OLD));
222   BufferedFileReader new_buffer(new_file, flow.name(flow.NEW));
223   flow.ReadDisassemblerFromBuffer(flow.OLD, old_buffer);                  // 1
224   flow.CreateAssemblyProgramFromDisassembler(flow.OLD, adjust);           // 2
225   flow.CreateEncodedProgramFromDisassemblerAndAssemblyProgram(flow.OLD);  // 3
226   flow.DestroyDisassembler(flow.OLD);
227   flow.WriteSinkStreamSetFromEncodedProgram(flow.OLD);  // 4
228   flow.DestroyEncodedProgram(flow.OLD);
229   flow.ReadDisassemblerFromBuffer(flow.NEW, new_buffer);         // 5
230   flow.CreateAssemblyProgramFromDisassembler(flow.NEW, adjust);  // 6
231   if (adjust)
232     flow.AdjustNewAssemblyProgramToMatchOld();  // 7, optional
233   flow.DestroyAssemblyProgram(flow.OLD);
234   flow.CreateEncodedProgramFromDisassemblerAndAssemblyProgram(flow.NEW);  // 8
235   flow.DestroyAssemblyProgram(flow.NEW);
236   flow.DestroyDisassembler(flow.NEW);
237   flow.WriteSinkStreamSetFromEncodedProgram(flow.NEW);  // 9
238   flow.DestroyEncodedProgram(flow.NEW);
239   if (flow.failed())
240     Problem(flow.message().c_str());
241
242   courgette::SinkStream empty_sink;
243   for (int i = 0;; ++i) {
244     courgette::SinkStream* old_stream = flow.data(flow.OLD)->sinks.stream(i);
245     courgette::SinkStream* new_stream = flow.data(flow.NEW)->sinks.stream(i);
246     if (old_stream == nullptr && new_stream == nullptr)
247       break;
248
249     courgette::SourceStream old_source;
250     courgette::SourceStream new_source;
251     old_source.Init(old_stream ? *old_stream : empty_sink);
252     new_source.Init(new_stream ? *new_stream : empty_sink);
253     courgette::SinkStream patch_stream;
254     bsdiff::BSDiffStatus status =
255         bsdiff::CreateBinaryPatch(&old_source, &new_source, &patch_stream);
256     if (status != bsdiff::OK)
257       Problem("-xxx failed.");
258
259     std::string append = std::string("-") + base::NumberToString(i);
260
261     WriteSinkToFile(&patch_stream,
262                     output_file_root.InsertBeforeExtensionASCII(append));
263   }
264 }
265
266 void Assemble(const base::FilePath& input_file,
267               const base::FilePath& output_file) {
268   CourgetteFlow flow;
269   BufferedFileReader input_buffer(input_file, flow.name(flow.ONLY));
270   flow.ReadSourceStreamSetFromBuffer(flow.ONLY, input_buffer);
271   flow.ReadEncodedProgramFromSourceStreamSet(flow.ONLY);
272   courgette::SinkStream sink;
273   flow.WriteExecutableFromEncodedProgram(flow.ONLY, &sink);
274   if (flow.failed())
275     Problem(flow.message().c_str());
276
277   WriteSinkToFile(&sink, output_file);
278 }
279
280 void GenerateEnsemblePatch(const base::FilePath& old_file,
281                            const base::FilePath& new_file,
282                            const base::FilePath& patch_file) {
283   BufferedFileReader old_buffer(old_file, "'old' input");
284   BufferedFileReader new_buffer(new_file, "'new' input");
285
286   courgette::SourceStream old_stream;
287   courgette::SourceStream new_stream;
288   old_stream.Init(old_buffer.data(), old_buffer.length());
289   new_stream.Init(new_buffer.data(), new_buffer.length());
290
291   courgette::SinkStream patch_stream;
292   courgette::Status status =
293       courgette::GenerateEnsemblePatch(&old_stream, &new_stream, &patch_stream);
294
295   if (status != courgette::C_OK)
296     Problem("-gen failed.");
297
298   WriteSinkToFile(&patch_stream, patch_file);
299 }
300
301 void ApplyEnsemblePatch(const base::FilePath& old_file,
302                         const base::FilePath& patch_file,
303                         const base::FilePath& new_file) {
304   // We do things a little differently here in order to call the same Courgette
305   // entry point as the installer.  That entry point point takes file names and
306   // returns an status code but does not output any diagnostics.
307
308   courgette::Status status = courgette::ApplyEnsemblePatch(
309       old_file.value().c_str(), patch_file.value().c_str(),
310       new_file.value().c_str());
311
312   if (status == courgette::C_OK)
313     return;
314
315   // Diagnose the error.
316   switch (status) {
317     case courgette::C_BAD_ENSEMBLE_MAGIC:
318       Problem("Not a courgette patch");
319       break;
320
321     case courgette::C_BAD_ENSEMBLE_VERSION:
322       Problem("Wrong version patch");
323       break;
324
325     case courgette::C_BAD_ENSEMBLE_HEADER:
326       Problem("Corrupt patch");
327       break;
328
329     case courgette::C_DISASSEMBLY_FAILED:
330       Problem("Disassembly failed (could be because of memory issues)");
331       break;
332
333     case courgette::C_STREAM_ERROR:
334       Problem("Stream error (likely out of memory or disk space)");
335       break;
336
337     default:
338       break;
339   }
340
341   // If we failed due to a missing input file, this will print the message.
342   { BufferedFileReader old_buffer(old_file, "'old' input"); }
343   { BufferedFileReader patch_buffer(patch_file, "'patch' input"); }
344
345   // Non-input related errors:
346   if (status == courgette::C_WRITE_OPEN_ERROR)
347     Problem("Can't open output");
348   if (status == courgette::C_WRITE_ERROR)
349     Problem("Can't write output");
350
351   Problem("-apply failed.");
352 }
353
354 void GenerateBSDiffPatch(const base::FilePath& old_file,
355                          const base::FilePath& new_file,
356                          const base::FilePath& patch_file) {
357   BufferedFileReader old_buffer(old_file, "'old' input");
358   BufferedFileReader new_buffer(new_file, "'new' input");
359
360   courgette::SourceStream old_stream;
361   courgette::SourceStream new_stream;
362   old_stream.Init(old_buffer.data(), old_buffer.length());
363   new_stream.Init(new_buffer.data(), new_buffer.length());
364
365   courgette::SinkStream patch_stream;
366   bsdiff::BSDiffStatus status =
367       bsdiff::CreateBinaryPatch(&old_stream, &new_stream, &patch_stream);
368
369   if (status != bsdiff::OK)
370     Problem("-genbsdiff failed.");
371
372   WriteSinkToFile(&patch_stream, patch_file);
373 }
374
375 void ApplyBSDiffPatch(const base::FilePath& old_file,
376                       const base::FilePath& patch_file,
377                       const base::FilePath& new_file) {
378   BufferedFileReader old_buffer(old_file, "'old' input");
379   BufferedFileReader patch_buffer(patch_file, "'patch' input");
380
381   courgette::SourceStream old_stream;
382   courgette::SourceStream patch_stream;
383   old_stream.Init(old_buffer.data(), old_buffer.length());
384   patch_stream.Init(patch_buffer.data(), patch_buffer.length());
385
386   courgette::SinkStream new_stream;
387   bsdiff::BSDiffStatus status =
388       bsdiff::ApplyBinaryPatch(&old_stream, &patch_stream, &new_stream);
389
390   if (status != bsdiff::OK)
391     Problem("-applybsdiff failed.");
392
393   WriteSinkToFile(&new_stream, new_file);
394 }
395
396 }  // namespace
397
398 int main(int argc, const char* argv[]) {
399   base::AtExitManager at_exit_manager;
400   base::CommandLine::Init(argc, argv);
401   const base::CommandLine& command_line =
402       *base::CommandLine::ForCurrentProcess();
403
404   logging::LoggingSettings settings;
405   if (command_line.HasSwitch("nologfile")) {
406     settings.logging_dest =
407         logging::LOG_TO_SYSTEM_DEBUG_LOG | logging::LOG_TO_STDERR;
408   } else {
409     settings.logging_dest = logging::LOG_TO_ALL;
410     settings.log_file_path = FILE_PATH_LITERAL("courgette.log");
411   }
412   std::ignore = logging::InitLogging(settings);
413   logging::SetMinLogLevel(logging::LOG_VERBOSE);
414
415   bool cmd_sup = command_line.HasSwitch("supported");
416   bool cmd_dis = command_line.HasSwitch("dis");
417   bool cmd_asm = command_line.HasSwitch("asm");
418   bool cmd_disadj = command_line.HasSwitch("disadj");
419   bool cmd_make_patch = command_line.HasSwitch("gen");
420   bool cmd_apply_patch = command_line.HasSwitch("apply");
421   bool cmd_make_bsdiff_patch = command_line.HasSwitch("genbsdiff");
422   bool cmd_apply_bsdiff_patch = command_line.HasSwitch("applybsdiff");
423   bool cmd_spread_1_adjusted = command_line.HasSwitch("gen1a");
424   bool cmd_spread_1_unadjusted = command_line.HasSwitch("gen1u");
425
426   std::vector<base::FilePath> values;
427   const base::CommandLine::StringVector& args = command_line.GetArgs();
428   for (size_t i = 0; i < args.size(); ++i) {
429     values.push_back(base::FilePath(args[i]));
430   }
431
432   // '-repeat=N' is for debugging.  Running many iterations can reveal leaks and
433   // bugs in cleanup.
434   int repeat_count = 1;
435   std::string repeat_switch = command_line.GetSwitchValueASCII("repeat");
436   if (!repeat_switch.empty())
437     if (!base::StringToInt(repeat_switch, &repeat_count))
438       repeat_count = 1;
439
440   if (cmd_sup + cmd_dis + cmd_asm + cmd_disadj + cmd_make_patch +
441           cmd_apply_patch + cmd_make_bsdiff_patch + cmd_apply_bsdiff_patch +
442           cmd_spread_1_adjusted + cmd_spread_1_unadjusted !=
443       1) {
444     UsageProblem(
445         "First argument must be one of:\n"
446         "  -supported, -asm, -dis, -disadj, -gen, -apply, -genbsdiff,"
447         " -applybsdiff, or -gen1[au].");
448   }
449
450   while (repeat_count-- > 0) {
451     if (cmd_sup) {
452       if (values.size() != 1)
453         UsageProblem(kUsageSupported);
454       return !Supported(values[0]);
455     } else if (cmd_dis) {
456       if (values.size() != 2)
457         UsageProblem(kUsageDis);
458       Disassemble(values[0], values[1]);
459     } else if (cmd_asm) {
460       if (values.size() != 2)
461         UsageProblem(kUsageAsm);
462       Assemble(values[0], values[1]);
463     } else if (cmd_disadj) {
464       if (values.size() != 3)
465         UsageProblem(kUsageDisadj);
466       DisassembleAndAdjust(values[0], values[1], values[2]);
467     } else if (cmd_make_patch) {
468       if (values.size() != 3)
469         UsageProblem(kUsageGen);
470       GenerateEnsemblePatch(values[0], values[1], values[2]);
471     } else if (cmd_apply_patch) {
472       if (values.size() != 3)
473         UsageProblem(kUsageApply);
474       ApplyEnsemblePatch(values[0], values[1], values[2]);
475     } else if (cmd_make_bsdiff_patch) {
476       if (values.size() != 3)
477         UsageProblem(kUsageGenbsdiff);
478       GenerateBSDiffPatch(values[0], values[1], values[2]);
479     } else if (cmd_apply_bsdiff_patch) {
480       if (values.size() != 3)
481         UsageProblem(kUsageApplybsdiff);
482       ApplyBSDiffPatch(values[0], values[1], values[2]);
483     } else if (cmd_spread_1_adjusted || cmd_spread_1_unadjusted) {
484       if (values.size() != 3)
485         UsageProblem(kUsageGen1);
486       DisassembleAdjustDiff(values[0], values[1], values[2],
487                             cmd_spread_1_adjusted);
488     } else {
489       UsageProblem("No operation specified");
490     }
491   }
492
493   return 0;
494 }