[Zucchini] Add -start-scan-at=# switch to Zucchini-{gen,detect,match}.
Chrome Update infra is changing to use self-extracting archives. A
problem is that Zucchini would only identify the outer binary, and skip
the non-compressed payload binaries. This causes these binaries to be
treated as unstructured raw data, and Zucchini loses its advantage re.
pointer management.
This CL has two parts:
1. Implement a simple solution to the above problem: Add -start-scan-at
switch to specify the offset to begin element detection. This
allows us to skip the outermost binary by passing a small value.
This flag is available for Zucchini-{gen,detect,match}, and is
ignored if either -impose or -raw switch is used.
* This does not affect patch format and Zucchini-apply.
2. Add struct GenerateOptions to collect Zucchini-{gen,detect,match}
switches {-start-scan-at, -impose, -raw}, then add GenerateBuffer()
overload to use it, and deprecate GenerateBuffer{,Imposed,Raw}(),
which uses the new interface internally.
Details:
* ElementFinder: Add `init_pos` CTOR param as initial value to `pos_`,
to implement (1)'s main behavior.
* zucchini_command.cc: Add ReadGenerateOptions() to read switches into
GenerateOptions.
* Zucchini-gen: Add plumbing for -start-scan-at:
MainGen() [reads `options`]
-> Generate() [param `options`]
-> GenerateCommon()
(API start)
-> GenerateBuffer() [extract `start_scan_at` from `options`]
-> HeuristicEnsembleMatcher CTOR
-> FindEmbeddedElements()
-> ElementFinder CTOR [param changed to `init_pos`]
* Zucchini-{detect,match}: Add plumbing:
Main{Detect,Match}() [reads `options`]
-> {Detect,Match}All()
-> ElementFinder CTOR or HeuristicEnsembleMatcher CTOR.
Also update ElementDetectionTest with cursory case to pass `init_pos`.
Bug: 413402398
Change-Id: I50744e759379404ff7dcb73c2d3586ac7fca599a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6550735
Reviewed-by: Joshua Pawlicki <[email protected]>
Commit-Queue: Samuel Huang <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1460685}
diff --git a/components/zucchini/zucchini_commands.cc b/components/zucchini/zucchini_commands.cc
index 4dedee7..7959d28 100644
--- a/components/zucchini/zucchini_commands.cc
+++ b/components/zucchini/zucchini_commands.cc
@@ -43,6 +43,7 @@
constexpr char kSwitchImpose[] = "impose";
constexpr char kSwitchKeep[] = "keep";
constexpr char kSwitchRaw[] = "raw";
+constexpr char kSwitchStartScanAt[] = "start-scan-at";
class WrappedMappedFileReader : public zucchini::MappedFileReader {
public:
@@ -61,15 +62,30 @@
zucchini::status::Code status = kStatusSuccess;
};
+zucchini::GenerateOptions ReadGenerateOptions(const MainParams& params) {
+ zucchini::GenerateOptions options{
+ .imposed_matches =
+ params.command_line->GetSwitchValueASCII(kSwitchImpose),
+ .is_raw = params.command_line->HasSwitch(kSwitchRaw),
+ };
+ if (params.command_line->HasSwitch(kSwitchStartScanAt)) {
+ const std::string s =
+ params.command_line->GetSwitchValueASCII(kSwitchStartScanAt);
+ std::istringstream(s) >> options.start_scan_at;
+ }
+ return options;
+}
+
} // namespace
+/******** Various Main*() functions ********/
+
zucchini::status::Code MainGen(MainParams params) {
+ zucchini::GenerateOptions options = ReadGenerateOptions(params);
CHECK_EQ(3U, params.file_paths->size());
- return zucchini::Generate(
- (*params.file_paths)[0], (*params.file_paths)[1], (*params.file_paths)[2],
- params.command_line->HasSwitch(kSwitchKeep),
- params.command_line->HasSwitch(kSwitchRaw),
- params.command_line->GetSwitchValueASCII(kSwitchImpose));
+ return zucchini::Generate((*params.file_paths)[0], (*params.file_paths)[1],
+ (*params.file_paths)[2], options,
+ params.command_line->HasSwitch(kSwitchKeep));
}
zucchini::status::Code MainApply(MainParams params) {
@@ -99,6 +115,7 @@
}
zucchini::status::Code MainDetect(MainParams params) {
+ zucchini::GenerateOptions options = ReadGenerateOptions(params);
CHECK_EQ(1U, params.file_paths->size());
WrappedMappedFileReader input((*params.file_paths)[0]);
if (input.status != kStatusSuccess)
@@ -106,13 +123,14 @@
std::vector<zucchini::ConstBufferView> sub_image_list;
zucchini::status::Code result = zucchini::DetectAll(
- {input.data(), input.length()}, *params.out, &sub_image_list);
+ {input.data(), input.length()}, options, *params.out, &sub_image_list);
if (result != kStatusSuccess)
*params.err << "Fatal error found when detecting executables." << std::endl;
return result;
}
zucchini::status::Code MainMatch(MainParams params) {
+ zucchini::GenerateOptions options = ReadGenerateOptions(params);
CHECK_EQ(2U, params.file_paths->size());
WrappedMappedFileReader old_image((*params.file_paths)[0]);
if (old_image.status != kStatusSuccess)
@@ -121,12 +139,9 @@
if (new_image.status != kStatusSuccess)
return new_image.status;
- std::string imposed_matches =
- params.command_line->GetSwitchValueASCII(kSwitchImpose);
- zucchini::status::Code status =
- zucchini::MatchAll({old_image.data(), old_image.length()},
- {new_image.data(), new_image.length()},
- std::move(imposed_matches), *params.out);
+ zucchini::status::Code status = zucchini::MatchAll(
+ {old_image.data(), old_image.length()},
+ {new_image.data(), new_image.length()}, options, *params.out);
if (status != kStatusSuccess)
*params.err << "Fatal error found when matching executables." << std::endl;
return status;