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 
LogFileListener(String logFile)51   public LogFileListener(String logFile) {
52     this.logFile = logFile;
53   }
54 
55   @Override
setup()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
shutdown()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 
write(String msg)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
handleSuccessfulHostVerification()87   public void handleSuccessfulHostVerification() {
88     write("Host verification: SUCCESS");
89     successfulVerification++;
90   }
91 
92   @Override
handleFailedHostVerification(ExecutionResult verificationResult)93   public void handleFailedHostVerification(ExecutionResult verificationResult) {
94     write("Host verification: FAILED");
95     failedVerification++;
96   }
97 
98   @Override
handleFailedTargetVerification()99   public void handleFailedTargetVerification() {
100     write("Target verification: FAILED");
101     failedVerification++;
102   }
103 
104   @Override
handleIterationStarted(int iteration)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
handleTimeouts(List<Executor> timedOut, List<Executor> didNotTimeOut)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
handleDivergences(Map<String, List<Executor>> outputMap)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
handleFuzzingFile(String inputFile)151   public void handleFuzzingFile(String inputFile) {
152     write("Fuzzing file '" + inputFile + "'");
153   }
154 
155   @Override
handleSeed(long seed)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
handleHostVerificationSigabort(ExecutionResult verificationResult)168   public void handleHostVerificationSigabort(ExecutionResult verificationResult) {
169     write("Host verification: SIGABORTED");
170   }
171 
172   @Override
handleSuccess(Map<String, List<Executor>> outputMap)173   public void handleSuccess(Map<String, List<Executor>> outputMap) {
174     write("All executors agreed on result.");
175     success++;
176   }
177 
178   @Override
handleDumpOutput(String outputLine, Executor executor)179   public void handleDumpOutput(String outputLine, Executor executor) {
180     write(executor.getName() + " OUTPUT:");
181     write(outputLine);
182   }
183 
184   @Override
handleDumpVerify(String verifyLine)185   public void handleDumpVerify(String verifyLine) {
186     write("VERIFY: " + verifyLine);
187   }
188 
189   @Override
handleMutationStats(String statsString)190   public void handleMutationStats(String statsString) {
191     write("Mutation Stats: " + statsString);
192   }
193 
194   @Override
handleTiming(String name, float elapsedTime)195   public void handleTiming(String name, float elapsedTime) {
196     write(String.format("'%s': %.3fs", name, elapsedTime));
197   }
198 
199   @Override
handleMutationFail()200   public void handleMutationFail() {
201     write("Mutation process: FAILED");
202     failedMutation++;
203   }
204 
205   @Override
handleSummary()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
handleIterationFinished(int iteration)244   public void handleIterationFinished(int iteration) {
245     write("");
246   }
247 
248   @Override
handleSuccessfullyFuzzedFile(String programName)249   public void handleSuccessfullyFuzzedFile(String programName) {
250     write("Successfully fuzzed file '" + programName + "'");
251   }
252 
253   @Override
handleSelfDivergence()254   public void handleSelfDivergence() {
255     write("Golden Executor was self-divergent!");
256     selfDivergent++;
257   }
258 
259   @Override
handleArchitectureSplit()260   public void handleArchitectureSplit() {
261     write("Divergent outputs align with difference in architectures.");
262     architectureSplit++;
263   }
264 
265   @Override
handleMessage(String msg)266   public void handleMessage(String msg) {
267     write(msg);
268   }
269 
270   @Override
handleMutations(List<Mutation> mutations)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