[fuzz] Improve fuzz job tree walking

This CL reworks Fuzzer::Check and its related methods to look for
component manifests when run on a Fuchisa package.  It also reformats
the output to make the salient details easier to spot.

SEC-103

Tests: Reran unit tests, manually tested with other packages
Change-Id: I5060d013e068ae24a6aaaa9c4c5e63a4635fe10b
diff --git a/system/ulib/fuzz-utils/fuzzer.cpp b/system/ulib/fuzz-utils/fuzzer.cpp
index 66424d2..8ba845c 100644
--- a/system/ulib/fuzz-utils/fuzzer.cpp
+++ b/system/ulib/fuzz-utils/fuzzer.cpp
@@ -92,7 +92,7 @@
 void Fuzzer::Reset() {
     cmd_ = kNone;
     name_.clear();
-    executable_.clear();
+    target_.clear();
     root_.clear();
     resource_path_.Reset();
     data_path_.Reset();
@@ -326,10 +326,10 @@
 
 void Fuzzer::GetArgs(StringList* out) {
     out->clear();
-    if (strstr(executable_.c_str(), "fuchsia-pkg://fuchsia.com/") == executable_.c_str()) {
+    if (strstr(target_.c_str(), "fuchsia-pkg://fuchsia.com/") == target_.c_str()) {
         out->push_back("/system/bin/run");
     }
-    out->push_back(executable_.c_str());
+    out->push_back(target_.c_str());
     const char* key;
     const char* val;
     options_.begin();
@@ -409,20 +409,27 @@
 bool Fuzzer::CheckProcess(zx_handle_t process) const {
     char name[ZX_MAX_NAME_LEN];
     zx_info_process_t info;
-    if (zx_object_get_property(process, ZX_PROP_NAME, name, sizeof(name)) != ZX_OK ||
-        strcmp(name, executable_.c_str()) != 0 ||
-        zx_object_get_info(process, ZX_INFO_PROCESS, &info, sizeof(info), nullptr, nullptr) !=
-            ZX_OK) {
+
+    if (zx_object_get_property(process, ZX_PROP_NAME, name, sizeof(name)) != ZX_OK) {
+        return false;
+    }
+
+    const char* target = target_.c_str();
+    const char* meta = strstr(target, "#meta/");
+    if (meta) {
+        target = meta + strlen("#meta/");
+    }
+    if (strcmp(name, target) != 0 || zx_object_get_info(process, ZX_INFO_PROCESS, &info,
+                                                        sizeof(info), nullptr, nullptr) != ZX_OK) {
         return false;
     }
 
     if (!info.started) {
-        fprintf(out_, "Fuzzer '%s' has not started.\n", name_.c_str());
+        fprintf(out_, "%s: NOT STARTED\n", name_.c_str());
     } else if (!info.exited) {
-        fprintf(out_, "Fuzzer '%s' is running.\n", name_.c_str());
+        fprintf(out_, "%s: RUNNING\n", name_.c_str());
     } else {
-        fprintf(out_, "Fuzzer '%s' exited with return code %" PRId64 ".\n", name_.c_str(),
-                info.return_code);
+        fprintf(out_, "%s: EXITED (return code = %" PRId64 ")\n", name_.c_str(), info.return_code);
     }
 
     return true;
@@ -494,7 +501,7 @@
     fuzzers.begin();
     fuzzers.next(&name, &executable);
     name_.Set(name);
-    executable_.Set(executable);
+    target_.Set(executable);
 
     fbl::String package, target;
     if ((rc = ParseName(name_.c_str(), &package, &target)) != ZX_OK) {
@@ -649,16 +656,16 @@
     // Report fuzzer execution status
     Walker walker(this);
     if (walker.WalkRootJobTree() != ZX_ERR_STOP) {
-        fprintf(out_, "Fuzzer '%s' is not running.\n", name_.c_str());
+        fprintf(out_, "%s: STOPPED\n", name_.c_str());
     }
 
     // Fuzzer details
-    fprintf(out_, "The fuzzer binary is located at: %s\n", executable_.c_str());
-    fprintf(out_, "The fuzzing data is located at: %s\n", data_path_.c_str());
+    fprintf(out_, "    Target info:  %s\n", target_.c_str());
+    fprintf(out_, "    Output path:  %s\n", data_path_.c_str());
 
     // Report corpus details, if present
     if ((rc = data_path_.Push("corpus")) != ZX_OK) {
-        fprintf(out_, "No fuzzing corpus was found\n");
+        fprintf(out_, "    Corpus size:  0 inputs / 0 bytes\n");
     } else {
         auto corpus = data_path_.List();
         size_t corpus_size = 0;
@@ -669,8 +676,7 @@
             }
             corpus_size += input_size;
         }
-        fprintf(out_, "The fuzzing corpus has %zu inputs totaling %zu bytes.\n", corpus->length(),
-                corpus_size);
+        fprintf(out_, "    Corpus size:  %zu inputs / %zu bytes\n", corpus->length(), corpus_size);
         data_path_.Pop();
     }
 
@@ -681,11 +687,12 @@
     artifacts->keep_if_any(&prefixes);
     size_t num_artifacts = artifacts->length();
     if (num_artifacts == 0) {
-        fprintf(out_, "The fuzzer has not produced any artifacts.\n");
+        fprintf(out_, "    Artifacts:    None\n");
     } else {
-        fprintf(out_, "The fuzzer has produced %zu artifacts:\n", num_artifacts);
-        for (const char* artifact = artifacts->first(); artifact; artifact = artifacts->next()) {
-            fprintf(out_, "  %s\n", artifact);
+        const char* artifact = artifacts->first();
+        fprintf(out_, "    Artifacts:    %s\n", artifact);
+        while ((artifact = artifacts->next())) {
+            fprintf(out_, "                  %s\n", artifact);
         }
     }
 
diff --git a/system/ulib/fuzz-utils/include/fuzz-utils/fuzzer.h b/system/ulib/fuzz-utils/include/fuzz-utils/fuzzer.h
index 4fd21b5..cfed862 100644
--- a/system/ulib/fuzz-utils/include/fuzz-utils/fuzzer.h
+++ b/system/ulib/fuzz-utils/include/fuzz-utils/fuzzer.h
@@ -46,7 +46,7 @@
     void set_root(const char* root) { root_.Set(root); }
     void set_out(FILE* out) { out_ = out; }
     void set_err(FILE* err) { err_ = err; }
-    void set_executable(const char* executable) { executable_.Set(executable); }
+    void set_target(const char* target) { target_.Set(target); }
 
     // Interpret the given |args| and execute the appropriate subcommand.
     zx_status_t Run(StringList* args);
@@ -120,7 +120,7 @@
     // Fuzzer name; may be a user-supplied pattern until resolved into a package/target.
     fbl::String name_;
     // Path on target to the fuzzer binary
-    fbl::String executable_;
+    fbl::String target_;
     // Path that the resource and data paths are relative to; primarily used for testing.
     fbl::String root_;
     // Path on target to where immutable fuzzing resources are stored
diff --git a/system/utest/fuzz-utils/fuzzer.cpp b/system/utest/fuzz-utils/fuzzer.cpp
index 4773f03..399c43a 100644
--- a/system/utest/fuzz-utils/fuzzer.cpp
+++ b/system/utest/fuzz-utils/fuzzer.cpp
@@ -666,46 +666,46 @@
 
     ASSERT_TRUE(test.Eval("check zircon/target1"));
     EXPECT_EQ(ZX_OK, test.Run());
-    EXPECT_TRUE(test.InStdOut("not running"));
+    EXPECT_TRUE(test.InStdOut("stopped"));
     EXPECT_TRUE(test.InStdOut(test.executable()));
     EXPECT_TRUE(test.InStdOut(test.data_path()));
-    EXPECT_TRUE(test.InStdOut("no fuzzing corpus"));
-    EXPECT_TRUE(test.InStdOut("has not produced any artifacts."));
+    EXPECT_TRUE(test.InStdOut("0 inputs"));
+    EXPECT_TRUE(test.InStdOut("none"));
 
     ASSERT_TRUE(test.Eval("check zircon/target2"));
     EXPECT_EQ(ZX_OK, test.Run());
-    EXPECT_TRUE(test.InStdOut("not running"));
+    EXPECT_TRUE(test.InStdOut("stopped"));
     EXPECT_TRUE(test.InStdOut(test.executable()));
     EXPECT_TRUE(test.InStdOut(test.data_path()));
-    EXPECT_TRUE(test.InStdOut("fuzzing corpus has"));
-    EXPECT_TRUE(test.InStdOut("has produced"));
+    EXPECT_TRUE(test.InStdOut("0 inputs"));
+    EXPECT_TRUE(test.InStdOut("crash"));
 
     // Fuchsia tests
     ASSERT_TRUE(test.InitFuchsia());
 
     ASSERT_TRUE(test.Eval("check zircon/target2"));
     EXPECT_EQ(ZX_OK, test.Run());
-    EXPECT_TRUE(test.InStdOut("not running"));
+    EXPECT_TRUE(test.InStdOut("stopped"));
     EXPECT_TRUE(test.InStdOut(test.executable()));
     EXPECT_TRUE(test.InStdOut(test.data_path()));
-    EXPECT_TRUE(test.InStdOut("fuzzing corpus has"));
-    EXPECT_TRUE(test.InStdOut("has produced"));
+    EXPECT_TRUE(test.InStdOut("0 inputs"));
+    EXPECT_TRUE(test.InStdOut("crash"));
 
     ASSERT_TRUE(test.Eval("check fuchsia/target1"));
     EXPECT_EQ(ZX_OK, test.Run());
-    EXPECT_TRUE(test.InStdOut("not running"));
+    EXPECT_TRUE(test.InStdOut("stopped"));
     EXPECT_TRUE(test.InStdOut(test.executable()));
     EXPECT_TRUE(test.InStdOut(test.data_path()));
-    EXPECT_TRUE(test.InStdOut("no fuzzing corpus"));
-    EXPECT_TRUE(test.InStdOut("has not produced any artifacts."));
+    EXPECT_TRUE(test.InStdOut("0 inputs"));
+    EXPECT_TRUE(test.InStdOut("none"));
 
     ASSERT_TRUE(test.Eval("check fuchsia/target4"));
     EXPECT_EQ(ZX_OK, test.Run());
-    EXPECT_TRUE(test.InStdOut("not running"));
+    EXPECT_TRUE(test.InStdOut("stopped"));
     EXPECT_TRUE(test.InStdOut(test.executable()));
     EXPECT_TRUE(test.InStdOut(test.data_path()));
-    EXPECT_TRUE(test.InStdOut("fuzzing corpus has"));
-    EXPECT_TRUE(test.InStdOut("has produced"));
+    EXPECT_TRUE(test.InStdOut("0 inputs"));
+    EXPECT_TRUE(test.InStdOut("crash"));
 
     END_TEST;
 }
diff --git a/system/utest/fuzz-utils/test-fuzzer.cpp b/system/utest/fuzz-utils/test-fuzzer.cpp
index 4db45b1..0561cc0 100644
--- a/system/utest/fuzz-utils/test-fuzzer.cpp
+++ b/system/utest/fuzz-utils/test-fuzzer.cpp
@@ -121,9 +121,9 @@
     return -1;
 }
 
-bool TestFuzzer::CheckProcess(zx_handle_t process, const char* executable) {
-    if (executable) {
-        set_executable(executable);
+bool TestFuzzer::CheckProcess(zx_handle_t process, const char* target) {
+    if (target) {
+        set_target(target);
     }
     return Fuzzer::CheckProcess(process);
 }