Home | History | Annotate | Download | only in listeners
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package dexfuzz.listeners;
     18 
     19 import dexfuzz.ExecutionResult;
     20 import dexfuzz.Log;
     21 import dexfuzz.executors.Executor;
     22 import dexfuzz.program.Mutation;
     23 import dexfuzz.program.MutationSerializer;
     24 
     25 import java.io.BufferedWriter;
     26 import java.io.FileWriter;
     27 import java.io.IOException;
     28 import java.util.Date;
     29 import java.util.List;
     30 import java.util.Map;
     31 
     32 /**
     33  * Logs events to a file.
     34  */
     35 public class LogFileListener extends BaseListener {
     36   private BufferedWriter writer;
     37   boolean ready = false;
     38 
     39   long successfulVerification;
     40   long failedVerification;
     41   long failedMutation;
     42   long success;
     43   long timedOut;
     44   long divergence;
     45   long selfDivergent;
     46   long architectureSplit;
     47   long iterations;
     48 
     49   private String logFile;
     50 
     51   public LogFileListener(String logFile) {
     52     this.logFile = logFile;
     53   }
     54 
     55   @Override
     56   public void setup() {
     57     try {
     58       writer = new BufferedWriter(new FileWriter(logFile));
     59       ready = true;
     60     } catch (IOException e) {
     61       e.printStackTrace();
     62     }
     63   }
     64 
     65   @Override
     66   public void shutdown() {
     67     try {
     68       writer.close();
     69     } catch (IOException e) {
     70       e.printStackTrace();
     71     }
     72     Log.always("Full log in " + logFile);
     73   }
     74 
     75   private void write(String msg) {
     76     if (!ready) {
     77       return;
     78     }
     79     try {
     80       writer.write(msg + "\n");
     81     } catch (IOException e) {
     82       e.printStackTrace();
     83     }
     84   }
     85 
     86   @Override
     87   public void handleSuccessfulHostVerification() {
     88     write("Host verification: SUCCESS");
     89     successfulVerification++;
     90   }
     91 
     92   @Override
     93   public void handleFailedHostVerification(ExecutionResult verificationResult) {
     94     write("Host verification: FAILED");
     95     failedVerification++;
     96   }
     97 
     98   @Override
     99   public void handleFailedTargetVerification() {
    100     write("Target verification: FAILED");
    101     failedVerification++;
    102   }
    103 
    104   @Override
    105   public void handleIterationStarted(int iteration) {
    106     write("--> FUZZ " + (iteration + 1));
    107     Date now = new Date(System.currentTimeMillis());
    108     write("Time started: " + now.toString());
    109     iterations++;
    110   }
    111 
    112   @Override
    113   public void handleTimeouts(List<Executor> timedOut, List<Executor> didNotTimeOut) {
    114     write("Some executors timed out.");
    115     write("Timed out:");
    116     for (Executor executor : timedOut) {
    117       write("  " + executor.getName());
    118     }
    119     if (!didNotTimeOut.isEmpty()) {
    120       write("Did not time out:");
    121       for (Executor executor : didNotTimeOut) {
    122         write("  " + executor.getName());
    123       }
    124     }
    125     this.timedOut++;
    126   }
    127 
    128   @Override
    129   public void handleDivergences(Map<String, List<Executor>> outputMap) {
    130     write("DIVERGENCE between some executors!");
    131     int outputCount = 1;
    132     for (List<Executor> executors : outputMap.values()) {
    133       write("Output " + outputCount + ":");
    134       for (Executor executor : executors) {
    135         write("  " + executor.getName());
    136       }
    137       outputCount++;
    138     }
    139     divergence++;
    140 
    141     // You are probably interested in reading about these divergences while fuzzing
    142     // is taking place, so flush the writer now.
    143     try {
    144       writer.flush();
    145     } catch (IOException e) {
    146       e.printStackTrace();
    147     }
    148   }
    149 
    150   @Override
    151   public void handleFuzzingFile(String inputFile) {
    152     write("Fuzzing file '" + inputFile + "'");
    153   }
    154 
    155   @Override
    156   public void handleSeed(long seed) {
    157     write("Using " + seed + " for seed.");
    158     // Flush the seed as well, so if anything goes wrong we can see what seed lead
    159     // to the issue.
    160     try {
    161       writer.flush();
    162     } catch (IOException e) {
    163       e.printStackTrace();
    164     }
    165   }
    166 
    167   @Override
    168   public void handleHostVerificationSigabort(ExecutionResult verificationResult) {
    169     write("Host verification: SIGABORTED");
    170   }
    171 
    172   @Override
    173   public void handleSuccess(Map<String, List<Executor>> outputMap) {
    174     write("All executors agreed on result.");
    175     success++;
    176   }
    177 
    178   @Override
    179   public void handleDumpOutput(String outputLine, Executor executor) {
    180     write(executor.getName() + " OUTPUT:");
    181     write(outputLine);
    182   }
    183 
    184   @Override
    185   public void handleDumpVerify(String verifyLine) {
    186     write("VERIFY: " + verifyLine);
    187   }
    188 
    189   @Override
    190   public void handleMutationStats(String statsString) {
    191     write("Mutation Stats: " + statsString);
    192   }
    193 
    194   @Override
    195   public void handleTiming(String name, float elapsedTime) {
    196     write(String.format("'%s': %.3fs", name, elapsedTime));
    197   }
    198 
    199   @Override
    200   public void handleMutationFail() {
    201     write("Mutation process: FAILED");
    202     failedMutation++;
    203   }
    204 
    205   @Override
    206   public void handleSummary() {
    207     write("");
    208     write("---+++--- SUMMARY ---+++---");
    209     write("Fuzzing attempts: " + iterations);
    210     write("  Failed verification: " + failedVerification);
    211     write("  Failed mutation: " + failedMutation);
    212     write("  Timed out: " + timedOut);
    213     write("Successful: " + success);
    214     write("  Self divergent: " + selfDivergent);
    215     write("  Architecture split: " + architectureSplit);
    216     write("Produced divergence: " + divergence);
    217 
    218     long truelyDivergent = divergence - (selfDivergent + architectureSplit);
    219     long verified = success + timedOut + truelyDivergent;
    220 
    221     write("");
    222 
    223     float verifiedTotalRatio =
    224         (((float) (verified)) / iterations) * 100.0f;
    225     write(String.format("Percentage Verified/Total: %.3f%%", verifiedTotalRatio));
    226 
    227     float timedOutVerifiedRatio =
    228         (((float) timedOut) / (verified)) * 100.0f;
    229     write(String.format("Percentage Timed Out/Verified: %.3f%%", timedOutVerifiedRatio));
    230 
    231     float successfulVerifiedRatio =
    232         (((float) success) / (verified)) * 100.0f;
    233     write(String.format("Percentage Successful/Verified: %.3f%%", successfulVerifiedRatio));
    234 
    235     float divergentVerifiedRatio =
    236         (((float) truelyDivergent) / (verified)) * 100.0f;
    237     write(String.format("Percentage Divergent/Verified: %.3f%%", divergentVerifiedRatio));
    238 
    239     write("---+++--- SUMMARY ---+++---");
    240     write("");
    241   }
    242 
    243   @Override
    244   public void handleIterationFinished(int iteration) {
    245     write("");
    246   }
    247 
    248   @Override
    249   public void handleSuccessfullyFuzzedFile(String programName) {
    250     write("Successfully fuzzed file '" + programName + "'");
    251   }
    252 
    253   @Override
    254   public void handleSelfDivergence() {
    255     write("Golden Executor was self-divergent!");
    256     selfDivergent++;
    257   }
    258 
    259   @Override
    260   public void handleArchitectureSplit() {
    261     write("Divergent outputs align with difference in architectures.");
    262     architectureSplit++;
    263   }
    264 
    265   @Override
    266   public void handleMessage(String msg) {
    267     write(msg);
    268   }
    269 
    270   @Override
    271   public void handleMutations(List<Mutation> mutations) {
    272     write("Mutations Report");
    273     for (Mutation mutation : mutations) {
    274       write(MutationSerializer.getMutationString(mutation));
    275     }
    276   }
    277 }
    278