courgette_tool.cc 18 KB

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