// // Copyright (C) 2007 United States Government as represented by the // Administrator of the National Aeronautics and Space Administration // (NASA). All Rights Reserved. // // This software is distributed under the NASA Open Source Agreement // (NOSA), version 1.3. The NOSA has been approved by the Open Source // Initiative. See the file NOSA-1.3-JPF at the top of the distribution // directory tree for the complete NOSA document. // // THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY // KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT // LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO // SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR // A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT // THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT // DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. // package gov.nasa.jpf.listener; import gov.nasa.jpf.Config; import gov.nasa.jpf.JPF; import gov.nasa.jpf.ListenerAdapter; import gov.nasa.jpf.jvm.bytecode.InvokeInstruction; import gov.nasa.jpf.search.Search; import gov.nasa.jpf.util.StringSetMatcher; import gov.nasa.jpf.vm.Instruction; import gov.nasa.jpf.vm.ThreadInfo; import gov.nasa.jpf.vm.VM; /** * tool to save traces upon various conditions like * - property violation * - call of a certain method * - reaching a certain search depth * - creating a certain thread */ public class TraceStorer extends ListenerAdapter { int nTrace = 1; String traceFileName; // do we store to the same file? (i.e. overwrite previously stored traces) // if set to 'true', store all traces (in <traceFileName>.n) boolean storeMultiple; // do we want to terminate after first store, even if it's triggered by a // property violation? boolean terminateOnStore; boolean storeOnConstraintHit; // search depth at what we store the tace int storeDepth; // calls that should trigger a store StringSetMatcher storeCalls; // thread starts that should trigger a store StringSetMatcher storeThreads; // do we want verbose output boolean verbose; Search search; VM vm; public TraceStorer (Config config, JPF jpf){ traceFileName = config.getString("trace.file", "trace"); storeMultiple = config.getBoolean("trace.multiple", false); storeDepth = config.getInt("trace.depth", Integer.MAX_VALUE); verbose = config.getBoolean("trace.verbose", false); terminateOnStore = config.getBoolean("trace.terminate", false); storeOnConstraintHit = config.getBoolean("trace.store_constraint", false); storeCalls = StringSetMatcher.getNonEmpty(config.getStringArray("trace.store_calls")); storeThreads = StringSetMatcher.getNonEmpty(config.getStringArray("trace.store_threads")); vm = jpf.getVM(); search = jpf.getSearch(); } void storeTrace(String reason) { String fname = traceFileName; if (storeMultiple){ fname = fname + '.' + nTrace++; } vm.storeTrace(fname, reason, verbose); // <2do> maybe some comment would be in order } @Override public void propertyViolated (Search search){ // Ok, this is unconditional storeTrace("violated property: " + search.getLastError().getDetails()); // no need to terminate (and we don't want to interfere with search.multiple_errors) } @Override public void stateAdvanced (Search search){ if (search.getDepth() == storeDepth){ storeTrace("search depth reached: " + storeDepth); checkSearchTermination(); } } @Override public void searchConstraintHit (Search search){ if (storeOnConstraintHit){ storeTrace("search constraint hit: " + search.getLastSearchConstraint()); } } @Override public void instructionExecuted (VM vm, ThreadInfo ti, Instruction nextInsn, Instruction executedInsn){ if (storeCalls != null){ if (executedInsn instanceof InvokeInstruction) { InvokeInstruction iinsn = (InvokeInstruction)executedInsn; String clsName = iinsn.getInvokedMethodClassName(); String mthName = iinsn.getInvokedMethodName(); String mn = clsName + '.' + mthName; if (storeCalls.matchesAny(mn)){ storeTrace("call: " + mn); checkVMTermination(ti); } } } } @Override public void threadStarted(VM vm, ThreadInfo ti) { if (storeThreads != null){ String tname = ti.getName(); if (storeThreads.matchesAny( tname)){ storeTrace("thread started: " + tname); checkVMTermination(ti); } } } boolean checkVMTermination(ThreadInfo ti) { if (terminateOnStore){ ti.breakTransition("storeTraceTermination"); search.terminate(); return true; } return false; } boolean checkSearchTermination() { if (terminateOnStore){ search.terminate(); return true; } return false; } }