zcov: / lib/Core/ExecutionState.cpp


Files: 1 Branches Taken: 51.2% 88 / 172
Generated: 2009-05-17 22:47 Branches Executed: 61.6% 106 / 172
Line Coverage: 53.3% 122 / 229


Programs: 1 Runs 371


       1                 : /* -*- mode: c++; c-basic-offset: 2; -*- */
       2                 : 
       3                 : #include "klee/ExecutionState.h"
       4                 : 
       5                 : #include "klee/Internal/Module/Cell.h"
       6                 : #include "klee/Internal/Module/InstructionInfoTable.h"
       7                 : #include "klee/Internal/Module/KInstruction.h"
       8                 : #include "klee/Internal/Module/KModule.h"
       9                 : 
      10                 : #include "klee/Expr.h"
      11                 : #include "klee/Memory.h"
      12                 : 
      13                 : #include "llvm/Function.h"
      14                 : #include "llvm/Support/CommandLine.h"
      15                 : 
      16                 : #include <iostream>
      17                 : #include <cassert>
      18                 : #include <map>
      19                 : #include <set>
      20                 : #include <stdarg.h>
      21                 : 
      22                 : #include "klee/Internal/FIXME/sugar.h"
      23                 : 
      24                 : using namespace llvm;
      25                 : using namespace klee;
      26                 : 
      27                 : namespace { 
      28                 :   cl::opt<bool>
      29              103:   DebugLogStateMerge("debug-log-state-merge");
      30                 : }
      31                 : 
      32                 : /***/
      33                 : 
      34                 : // FIXME: Ugh. See comment in Searcher.cpp
      35                 : extern
      36                 : std::map< std::pair< std::pair<unsigned, bool>, 
      37                 :                      std::pair<unsigned, bool> >, 
      38                 :           int > termStatesBranchPairTally;
      39                 : 
      40                 : // only used if klee::userSearcherRequiresBranchSequences()
      41                 : // contains two-branch adjacent sequences that have been seen thus
      42                 : // during ANY state that has TERMINATED
      43                 : // (implemented as a multiset so can count the number of terminated
      44                 : // states that has seen a particular branch pair)
      45                 : extern
      46                 : std::multiset< std::pair< std::pair<unsigned, bool>, 
      47                 :                           std::pair<unsigned, bool> > > seenBranchPairs;
      48                 : 
      49                 : /***/
      50                 : 
      51             1056: StackFrame::StackFrame(KInstIterator _caller, KFunction *_kf)
      52                 :   : caller(_caller), kf(_kf), callPathNode(0), 
      53             3168:     minDistToUncoveredOnReturn(0), varargs(0) {
                  1742440: branch 1 taken
                     1056: branch 2 taken
                        0: branch 4 not taken
                        0: branch 5 not taken
      54          1743496:   locals = new Cell[kf->numRegisters];
      55             1056: }
      56                 : 
      57             3619: StackFrame::StackFrame(const StackFrame &s) 
      58                 :   : caller(s.caller),
      59                 :     kf(s.kf),
      60                 :     callPathNode(s.callPathNode),
      61                 :     allocas(s.allocas),
      62                 :     minDistToUncoveredOnReturn(s.minDistToUncoveredOnReturn),
      63             7238:     varargs(s.varargs) {
                  5461222: branch 1 taken
                     3619: branch 2 taken
                        0: branch 4 not taken
                        0: branch 5 not taken
      64          5464841:   locals = new Cell[s.kf->numRegisters];
                  5461222: branch 0 taken
                     3619: branch 1 taken
                     3619: branch 2 taken
                     3619: branch 3 taken
      65          5464841:   for (unsigned i=0; i<s.kf->numRegisters; i++)
      66          5461222:     locals[i] = s.locals[i];
      67             3619: }
      68                 : 
      69             4675: StackFrame::~StackFrame() { 
                     4675: branch 0 taken
                        0: branch 1 not taken
                  7203662: branch 2 taken
                     4675: branch 3 taken
                     4675: branch 5 taken
                     4675: branch 6 taken
                     4675: branch 7 taken
                     4675: branch 8 taken
      70             9350:   delete[] locals; 
      71             4675: }
      72                 : 
      73                 : /***/
      74                 : 
      75              103: ExecutionState::ExecutionState(KFunction *kf) 
      76                 :   : fakeState(false),
      77                 :     underConstrained(false),
      78                 :     depth(0),
      79                 :     pc(kf->instructions),
      80                 :     prevPC(pc),
      81                 :     queryCost(0.), 
      82                 :     weight(1),
      83                 :     instsSinceCovNew(0),
      84                 :     coveredNew(false),
      85                 :     forkDisabled(false),
      86             1339:     ptreeNode(0) {
      87              103:   pushFrame(0, kf);
      88              103: }
      89                 : 
      90                0: ExecutionState::ExecutionState(const std::vector<ref<Expr> > &assumptions) 
      91                 :   : fakeState(true),
      92                 :     underConstrained(false),
      93                 :     constraints(assumptions),
      94                 :     queryCost(0.),
      95                0:     ptreeNode(0) {
      96                0: }
      97                 : 
      98             1453: ExecutionState::~ExecutionState() {
                     1551: branch 1 taken
                     1453: branch 2 taken
                        0: branch 4 not taken
                        0: branch 5 not taken
      99             4457:   while (!stack.empty()) popFrame();
     100            13077: }
     101                 : 
     102              687: ExecutionState *ExecutionState::branch() {
     103              687:   depth++;
     104                 : 
     105             1374:   ExecutionState *falseState = new ExecutionState(*this);
     106              687:   falseState->coveredNew = false;
     107              687:   falseState->coveredLines.clear();
     108                 : 
     109              687:   weight *= .5;
     110              687:   falseState->weight -= weight;
     111                 : 
     112              687:   return falseState;
     113                 : }
     114                 : 
     115             1056: void ExecutionState::pushFrame(KInstIterator caller, KFunction *kf) {
     116             2112:   stack.push_back(StackFrame(caller,kf));
     117             1056: }
     118                 : 
     119             3063: void ExecutionState::popFrame() {
     120             6126:   StackFrame &sf = stack.back();
                   601283: branch 0 taken
                     3063: branch 1 taken
     121           610472:   foreach(it, sf.allocas.begin(), sf.allocas.end())
     122           601283:     addressSpace.unbindObject(*it);
     123             3063:   stack.pop_back();
     124             3063: }
     125                 : 
     126                0: bool ExecutionState::isLastBranchPairSeen() {
     127                0:   unsigned s = branchDecisionsSequence.size();
                        0: branch 0 not taken
                        0: branch 1 not taken
     128                0:   if (s > 1) {
     129                 :     std::pair< std::pair<unsigned, bool>, std::pair<unsigned, bool> > lastPair =
     130                0:       std::make_pair(branchDecisionsSequence[s-2], branchDecisionsSequence[s-1]);
     131                0:     return (seenBranchPairs.count(lastPair) > 0);
     132                 :   }
     133                 :   else {
     134                0:     return false;
     135                 :   }
     136                 : }
     137                 : 
     138                 : // Pre: branchDecisionsSequence.size() > 1
     139                0: std::pair< std::pair<unsigned, bool>, std::pair<unsigned, bool> > ExecutionState::getLastBranchPair() {
     140                0:   unsigned s = branchDecisionsSequence.size();
                        0: branch 0 not taken
                        0: branch 1 not taken
     141                0:   assert(s > 1);
     142                 :   std::pair< std::pair<unsigned, bool>, std::pair<unsigned, bool> > lastPair =
     143                0:     std::make_pair(branchDecisionsSequence[s-2], branchDecisionsSequence[s-1]);
     144                 :   return lastPair;
     145                 : }
     146                 : 
     147                 : // return total tally on all branch pairs seen thus far
     148                 : // in this state (no dups) by referring to
     149                 : // termStatesBranchPairTally:
     150                0: int ExecutionState::getBranchPairsTally() {
     151                0:   int total = 0;
                        0: branch 0 not taken
                        0: branch 1 not taken
     152                0:   foreach(it, mySeenBranchPairs.begin(), mySeenBranchPairs.end()) {
     153                0:     total += termStatesBranchPairTally[*it];
     154                 :   }
     155                0:   return total;
     156                 : }
     157                 : 
     158                0: void ExecutionState::branchSeqHandleStateBranch(unsigned branchID, bool trueTaken, bool isTwoWay) {
     159                0:   std::pair<unsigned, bool> curBranchDecision = std::make_pair(branchID, trueTaken);
     160                 : 
     161                 :   // add the most recent branch pair to state.mySeenBranchPairs:
                        0: branch 0 not taken
                        0: branch 1 not taken
     162                0:   if (branchDecisionsSequence.size() > 0) {
     163                0:     std::pair<unsigned, bool> lastBranchDecision = branchDecisionsSequence.back();
     164                 : 
     165                0:     mySeenBranchPairs.insert(std::make_pair(lastBranchDecision, curBranchDecision));
     166                 : 
     167                 :     /*
     168                 :     klee_message("  branchSeqHandleStateBranch: <%u, %u>, <%u, %u>",
     169                 :                  lastBranchDecision.first,
     170                 :                  lastBranchDecision.second,
     171                 :                  curBranchDecision.first,
     172                 :                  curBranchDecision.second);
     173                 :     */
     174                 :   }
     175                 : 
     176                0:   branchDecisionsSequence.push_back(curBranchDecision);
     177                 : 
     178                 :   BranchInfo b;
     179                0:   b.isTwoWay = isTwoWay;
     180                0:   b.alreadyCoveredNew = coveredNew;
     181                0:   branchInfoSequence.push_back(b);
     182                 : 
     183                 :   //klee_message("branchSeqHandleStateBranch() - %u", branchDecisionsSequence.size());
     184                0: }
     185                 : 
     186                 : ///
     187                 : 
     188          3010735: std::string ExecutionState::getFnAlias(std::string fn) {
     189          3010735:   std::map < std::string, std::string >::iterator it = fnAliases.find(fn);
                        4: branch 0 taken
                  3010731: branch 1 taken
     190          6021470:   if (it != fnAliases.end())
     191                8:     return it->second;
     192          6021462:   else return "";
     193                 : }
     194                 : 
     195                2: void ExecutionState::addFnAlias(std::string old_fn, std::string new_fn) {
     196                2:   fnAliases[old_fn] = new_fn;
     197                2: }
     198                 : 
     199                5: void ExecutionState::removeFnAlias(std::string fn) {
     200                5:   fnAliases.erase(fn);
     201                5: }
     202                 : 
     203                 : /**/
     204                 : 
     205               28: std::ostream &klee::operator<<(std::ostream &os, const MemoryMap &mm) {
     206               28:   os << "{";
     207                 :   let(it, mm.begin());
     208                 :   let(ie, mm.end());
                       28: branch 0 taken
                        0: branch 1 not taken
     209               28:   if (it!=ie) {
     210               84:     os << "MO" << it->first->id << ":" << it->second;
                     2268: branch 2 taken
                       28: branch 3 taken
     211             4592:     for (++it; it!=ie; ++it)
     212             6804:       os << ", MO" << it->first->id << ":" << it->second;
     213                 :   }
     214               28:   os << "}";
     215               28:   return os;
     216                 : }
     217                 : 
     218               70: bool ExecutionState::merge(const ExecutionState &b) {
                       14: branch 0 taken
                       56: branch 1 taken
     219               70:   if (DebugLogStateMerge)
     220               14:     llvm::cerr << "-- attempting merge of A:" << this << " with B:" << &b << "--\n";
                        0: branch 0 not taken
                       70: branch 1 taken
     221              140:   if (pc != b.pc)
     222                0:     return false;
     223                 : 
     224                 : #ifdef KLEE_TRACK_REFERENTS
     225                 :   // DRE: haven't thought about merging base object information.
     226                 :   return false;
     227                 : #endif
     228                 : 
     229                 :   // XXX is it even possible for these to differ? does it matter? probably
     230                 :   // implies difference in object states?
                        0: branch 0 not taken
                       70: branch 1 taken
     231              140:   if (symbolics!=b.symbolics)
     232                0:     return false;
     233                 : 
     234                 :   {
     235               70:     let(itA, stack.begin());
     236               70:     let(itB, b.stack.begin());
                      140: branch 0 taken
                       70: branch 1 taken
                      140: branch 2 taken
                        0: branch 3 not taken
                      140: branch 4 taken
                       70: branch 5 taken
     237              560:     while (itA!=stack.end() && itB!=b.stack.end()) {
     238                 :       // XXX vaargs?
                      140: branch 0 taken
                        0: branch 1 not taken
                        0: branch 2 not taken
                      140: branch 3 taken
                        0: branch 4 not taken
                      140: branch 5 taken
     239              700:       if (itA->caller!=itB->caller || itA->kf!=itB->kf)
     240                0:         return false;
     241                 :       ++itA;
     242                 :       ++itB;
     243                 :     }
                       70: branch 0 taken
                        0: branch 1 not taken
                        0: branch 2 not taken
                       70: branch 3 taken
                        0: branch 4 not taken
                       70: branch 5 taken
     244              210:     if (itA!=stack.end() || itB!=b.stack.end())
     245                0:       return false;
     246                 :   }
     247                 : 
     248                 :   std::set< ref<Expr> > aConstraints, bConstraints, commonConstraints, aSuffix, bSuffix;
                       70: branch 0 taken
                       70: branch 1 taken
     249              350:   foreach(it, constraints.begin(), constraints.end())
     250                 :     aConstraints.insert(*it);
                      595: branch 0 taken
                       70: branch 1 taken
     251              805:   foreach(it, b.constraints.begin(), b.constraints.end())
     252                 :     bConstraints.insert(*it);
     253                 :   std::set_intersection(aConstraints.begin(), aConstraints.end(),
     254                 :                         bConstraints.begin(), bConstraints.end(),
     255              140:                         std::inserter(commonConstraints, commonConstraints.begin()));
     256                 :   std::set_difference(aConstraints.begin(), aConstraints.end(),
     257                 :                       commonConstraints.begin(), commonConstraints.end(),
     258              140:                       std::inserter(aSuffix, aSuffix.end()));
     259                 :   std::set_difference(bConstraints.begin(), bConstraints.end(),
     260                 :                       commonConstraints.begin(), commonConstraints.end(),
     261              140:                       std::inserter(bSuffix, bSuffix.end()));
                       14: branch 0 taken
                       56: branch 1 taken
     262               70:   if (DebugLogStateMerge) {
     263                 :     llvm::cerr << "\tconstraint prefix: [";
                        0: branch 1 not taken
                       14: branch 2 taken
     264               28:     foreach(it, commonConstraints.begin(), commonConstraints.end())
     265                0:       llvm::cerr << *it << ", ";
     266                 :     llvm::cerr << "]\n";
     267                 :     llvm::cerr << "\tA suffix: [";
                       14: branch 1 taken
                       14: branch 2 taken
     268               56:     foreach(it, aSuffix.begin(), aSuffix.end())
     269               14:       llvm::cerr << *it << ", ";
     270                 :     llvm::cerr << "]\n";
     271                 :     llvm::cerr << "\tB suffix: [";
                      119: branch 1 taken
                       14: branch 2 taken
     272              266:     foreach(it, bSuffix.begin(), bSuffix.end())
     273              119:       llvm::cerr << *it << ", ";
     274                 :     llvm::cerr << "]\n";
     275                 :   }
     276                 : 
     277                 :   // We cannot merge if addresses would resolve differently in the
     278                 :   // states. This means:
     279                 :   // 
     280                 :   // 1. Any objects created since the branch in either object must
     281                 :   // have been free'd.
     282                 :   //
     283                 :   // 2. We cannot have free'd any pre-existing object in one state
     284                 :   // and not the other
     285                 : 
                       14: branch 0 taken
                       56: branch 1 taken
     286               70:   if (DebugLogStateMerge) {
     287                 :     llvm::cerr << "\tchecking object states\n";
     288               14:     llvm::cerr << "A: " << addressSpace.objects << "\n";
     289               14:     llvm::cerr << "B: " << b.addressSpace.objects << "\n";
     290                 :   }
     291                 :     
     292                 :   std::set<const MemoryObject*> mutated;
     293               70:   let(ai, addressSpace.objects.begin());
     294               70:   let(bi, b.addressSpace.objects.begin());
     295               70:   let(ae, addressSpace.objects.end());
     296               70:   let(be, b.addressSpace.objects.end());
                     5740: branch 2 taken
                       70: branch 3 taken
                     5740: branch 4 taken
                        0: branch 5 not taken
                     5740: branch 6 taken
                       70: branch 7 taken
     297            17360:   for (; ai!=ae && bi!=be; ++ai, ++bi) {
                        0: branch 0 not taken
                     5740: branch 1 taken
     298            11480:     if (ai->first != bi->first) {
                        0: branch 0 not taken
                        0: branch 1 not taken
     299                0:       if (DebugLogStateMerge) {
                        0: branch 0 not taken
                        0: branch 1 not taken
     300                0:         if (ai->first < bi->first) {
     301                0:           llvm::cerr << "\t\tB misses binding for: " << ai->first->id << "\n";
     302                 :         } else {
     303                0:           llvm::cerr << "\t\tA misses binding for: " << bi->first->id << "\n";
     304                 :         }
     305                 :       }
     306                0:       return false;
     307                 :     }
                       70: branch 0 taken
                     5670: branch 1 taken
     308            17220:     if (ai->second != bi->second) {
                       14: branch 0 taken
                       56: branch 1 taken
     309               70:       if (DebugLogStateMerge)
     310               14:         llvm::cerr << "\t\tmutated: " << ai->first->id << "\n";
     311               70:       mutated.insert(ai->first);
     312                 :     }
     313                 :   }
                       70: branch 0 taken
                        0: branch 1 not taken
                        0: branch 2 not taken
                       70: branch 3 taken
                        0: branch 4 not taken
                       70: branch 5 taken
     314              140:   if (ai!=ae || bi!=be) {
                        0: branch 0 not taken
                        0: branch 1 not taken
     315                0:     if (DebugLogStateMerge)
     316                 :       llvm::cerr << "\t\tmappings differ\n";
     317                0:     return false;
     318                 :   }
     319                 :   
     320                 :   // merge stack
     321                 : 
     322                 :   ref<Expr> inA(1, Expr::Bool), inB(1, Expr::Bool);
                       70: branch 1 taken
                       70: branch 2 taken
     323              280:   foreach(it, aSuffix.begin(), aSuffix.end())
     324               70:     inA = AndExpr::create(inA, *it);
                      595: branch 1 taken
                       70: branch 2 taken
     325             1330:   foreach(it, bSuffix.begin(), bSuffix.end())
     326              595:     inB = AndExpr::create(inB, *it);
     327                 : 
     328                 :   // XXX should we have a preference as to which predicate to use?
     329                 :   // it seems like it can make a difference, even though logically
     330                 :   // they must contradict each other and so inA => !inB
     331                 : 
     332               70:   let(itA, stack.begin());
     333               70:   let(itB, b.stack.begin());
                      140: branch 0 taken
                       70: branch 1 taken
     334              420:   for (; itA!=stack.end(); ++itA, ++itB) {
     335              140:     StackFrame &af = *itA;
     336              140:     const StackFrame &bf = *itB;
                     5040: branch 0 taken
                      140: branch 1 taken
     337             5180:     for (unsigned i=0; i<af.kf->numRegisters; i++) {
     338             5040:       ref<Expr> &av = af.locals[i].value;
     339             5040:       const ref<Expr> &bv = bf.locals[i].value;
                     2240: branch 0 taken
                     2800: branch 1 taken
                        0: branch 2 not taken
                     2240: branch 3 taken
                     2240: branch 4 taken
                     2800: branch 5 taken
     340             7280:       if (av.isNull() || bv.isNull()) {
     341                 :         // if one is null then by implication (we are at same pc)
     342                 :         // we cannot reuse this local, so just ignore
     343                 :       } else {
     344             2240:         av = SelectExpr::create(inA, av, bv);
     345                 :       }
     346                 :     }
     347                 :   }
     348                 : 
                       70: branch 0 taken
                       70: branch 1 taken
     349              210:   foreach(it, mutated.begin(), mutated.end()) {
     350               70:     const MemoryObject *mo = *it;
     351               70:     const ObjectState *os = addressSpace.findObject(mo);
     352               70:     const ObjectState *otherOS = b.addressSpace.findObject(mo);
                       70: branch 0 taken
                        0: branch 1 not taken
                        0: branch 2 not taken
                       70: branch 3 taken
     353               70:     assert(os && !os->readOnly && "objects mutated but not writable in merging state");
                        0: branch 0 not taken
                       70: branch 1 taken
     354               70:     assert(otherOS);
     355                 : 
     356               70:     ObjectState *wos = addressSpace.getWriteable(mo, os);
                      280: branch 2 taken
                       70: branch 3 taken
     357              350:     for (unsigned i=0; i<mo->size; i++) {
     358              280:       ref<Expr> av = wos->read8(i);
     359              280:       ref<Expr> bv = otherOS->read8(i);
     360              280:       wos->write(i, SelectExpr::create(inA, av, bv));
     361                 :     }
     362                 :   }
     363                 : 
     364              140:   constraints = ConstraintManager();
                        0: branch 1 not taken
                       70: branch 2 taken
     365              140:   foreach(it, commonConstraints.begin(), commonConstraints.end()) {
     366                0:     constraints.addConstraint(*it);
     367                 :   }
     368               70:   constraints.addConstraint(OrExpr::create(inA, inB));
     369                 : 
     370               70:   return true;
     371                 : }
     372                 : 
     373                 : /**/
     374                 : 
     375                 : /*
     376                 :    Used for tainting: create a clone of os that we can revirt to with
     377                 :    the behavior that all constraints are preserved, but writes are 
     378                 :    discarded.  When we revirt it will be at the same address.
     379                 :  */
     380                 : ObjectState *ExecutionState::cloneObject(ObjectState *os, 
     381                0:                                          MemoryObject *mo) {
     382                0:   MemoryMap::iterator it = shadowObjects.find(mo);
                        0: branch 1 not taken
                        0: branch 2 not taken
     383                0:   if (it != shadowObjects.end())
     384                0:     assert(0 && "Cannot exist already!");
     385                 : 
     386                 :   llvm::cerr << "DRE: Inserting a cloned object: " << mo << "\n";
     387                0:   shadowObjects = shadowObjects.replace(std::make_pair(mo, os));
     388                0:   os = new ObjectState(*os);
     389                0:   addressSpace.bindObject(mo, os);
     390                0:   return os;
     391                 : }
     392                 : 
     393                 : void ExecutionState::revirtClonedObject(const MemoryObject *mo, 
     394                0:                                         ObjectState *os) {
     395                 :   // XXX DWD this may be busted if os has already been bound.
     396                 :   // probably fixed by just making a copy of the os, but I'm
     397                 :   // not sure what is going on here so skipping. bug me if
     398                 :   // you have problems DRE.
     399                0:   addressSpace.bindObject(mo, os);
     400                 :   llvm::cerr << "Revirting object: " << mo << "\n";
     401                0: }
     402                 : 
     403                 : // Or should this be a one at a time thing?
     404                0: void ExecutionState::revirtClonedObjects(void) {
     405                 :   llvm::cerr << "Revirting objects\n";
     406                0:   unsigned n = 0;
     407                 : 
                        0: branch 1 not taken
                        0: branch 2 not taken
     408                0:   foreach(it_orig, shadowObjects.begin(), shadowObjects.end()) {
     409                0:      revirtClonedObject(it_orig->first, it_orig->second);
     410                0:      n++;
     411                0:   }
     412                 :   llvm::cerr << "Revirted: " << n << " objects\n";
     413                0: }
     414                 : 
     415                 : /***/
     416                 : 
     417                 : 
     418                 : ExecutionTraceEvent::ExecutionTraceEvent(ExecutionState& state, 
     419                0:                                          KInstruction* ki)
     420                0:   : consecutiveCount(1) 
     421                 : {
     422                0:   file = ki->info->file;
     423                0:   line = ki->info->line;
     424                0:   funcName = state.stack.back().kf->function->getName();
     425                0:   stackDepth = state.stack.size();
     426                0: }
     427                 : 
     428                0: bool ExecutionTraceEvent::ignoreMe() const {
     429                 :   // ignore all events occurring in certain pesky uclibc files:
                        0: branch 1 not taken
                        0: branch 2 not taken
     430                0:   if (file.find("libc/stdio/") != std::string::npos) {
     431                0:     return true;
     432                 :   }
     433                 : 
     434                0:   return false;
     435                 : }
     436                 : 
     437                0: void ExecutionTraceEvent::print(std::ostream &os) const {
     438                0:   os.width(stackDepth);
     439                0:   os << ' ';
     440                0:   printDetails(os);
     441                0:   os << ' ' << file << ':' << line << ':' << funcName;
                        0: branch 0 not taken
                        0: branch 1 not taken
     442                0:   if (consecutiveCount > 1)
     443                0:     os << " (" << consecutiveCount << "x)\n";
     444                 :   else
     445                0:     os << '\n';
     446                0: }
     447                 : 
     448                 : 
     449                0: bool ExecutionTraceEventEquals(ExecutionTraceEvent* e1, ExecutionTraceEvent* e2) {
     450                 :   // first see if their base class members are identical:
                        0: branch 0 not taken
                        0: branch 1 not taken
                        0: branch 2 not taken
                        0: branch 3 not taken
                        0: branch 4 not taken
                        0: branch 5 not taken
                        0: branch 6 not taken
                        0: branch 7 not taken
     451                0:   if (!((e1->file == e2->file) &&
     452                 :         (e1->line == e2->line) &&
     453                 :         (e1->funcName == e2->funcName)))
     454                0:     return false;
     455                 : 
     456                 :   // fairly ugly, but i'm no OOP master, so this is the way i'm
     457                 :   // doing it for now ... lemme know if there's a cleaner way:
                        0: branch 0 not taken
                        0: branch 1 not taken
     458                0:   BranchTraceEvent* be1 = dynamic_cast<BranchTraceEvent*>(e1);
                        0: branch 0 not taken
                        0: branch 1 not taken
     459                0:   BranchTraceEvent* be2 = dynamic_cast<BranchTraceEvent*>(e2);
                        0: branch 0 not taken
                        0: branch 1 not taken
     460                0:   if (be1 && be2) {
     461                 :     return ((be1->trueTaken == be2->trueTaken) &&
     462                0:             (be1->canForkGoBothWays == be2->canForkGoBothWays));
     463                 :   }
     464                 : 
     465                 :   // don't tolerate duplicates in anything else:
     466                0:   return false;
     467                 : }
     468                 : 
     469                 : 
     470                0: void BranchTraceEvent::printDetails(std::ostream &os) const {
     471                 :   os << "BRANCH " << (trueTaken ? "T" : "F") << ' ' <<
                        0: branch 0 not taken
                        0: branch 1 not taken
                        0: branch 2 not taken
                        0: branch 3 not taken
     472                0:         (canForkGoBothWays ? "2-way" : "1-way");
     473                0: }
     474                 : 
     475                0: void ExecutionTraceManager::addEvent(ExecutionTraceEvent* evt) {
     476                 :   // don't trace anything before __user_main, except for global events
                        0: branch 0 not taken
                        0: branch 1 not taken
     477                0:   if (!hasSeenUserMain) {
                        0: branch 0 not taken
                        0: branch 1 not taken
     478                0:     if (evt->funcName == "__user_main") {
     479                0:       hasSeenUserMain = true;
     480                 :     }
                        0: branch 0 not taken
                        0: branch 1 not taken
     481                0:     else if (evt->funcName != "global_def") {
     482                0:       return;
     483                 :     }
     484                 :   }
     485                 : 
     486                 :   // custom ignore events:
                        0: branch 1 not taken
                        0: branch 2 not taken
     487                0:   if (evt->ignoreMe())
     488                0:     return;
     489                 : 
                        0: branch 0 not taken
                        0: branch 1 not taken
     490                0:   if (events.size() > 0) {
     491                 :     // compress consecutive duplicates:
     492                0:     ExecutionTraceEvent* last = events.back();
                        0: branch 1 not taken
                        0: branch 2 not taken
     493                0:     if (ExecutionTraceEventEquals(last, evt)) {
     494                0:       last->consecutiveCount++;
     495                0:       return;
     496                 :     }
     497                 :   }
     498                 : 
     499                0:   events.push_back(evt);
     500                 : }
     501                 : 
     502                0: void ExecutionTraceManager::printAllEvents(std::ostream &os) const {
                        0: branch 0 not taken
                        0: branch 1 not taken
     503                0:   foreach(it, events.begin(), events.end()) {
     504                0:     (*it)->print(os);
     505                 :   }
                      103: branch 0 taken
                        0: branch 1 not taken
                      103: branch 2 taken
                        0: branch 3 not taken
     506              309: }
     507                 : 
     508                 : /***/

Generated: 2009-05-17 22:47 by zcov