diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
index d9b6136..8b3fb53 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
@@ -50,7 +50,8 @@ public:
   typedef std::vector<std::pair<BlockEdge, const ExplodedNode*> >
             BlocksExhausted;
   
-  typedef std::vector<std::pair<const CFGBlock*, const ExplodedNode*> >
+  typedef std::pair<const ExplodedNode*, const Stmt*> AbortedStmtPair;
+  typedef std::vector<std::pair<const CFGBlock*, AbortedStmtPair> >
             BlocksAborted;
 
 private:
@@ -141,10 +142,11 @@ public:
                                          WList->hasWork() || 
                                          wasBlockAborted(); }
 
-  /// Inform the CoreEngine that a basic block was aborted because
-  /// it could not be completely analyzed.
-  void addAbortedBlock(const ExplodedNode *node, const CFGBlock *block) {
-    blocksAborted.push_back(std::make_pair(block, node));
+  /// Inform the CoreEngine that a basic block was aborted because of an
+  /// unsupported statement.
+  void addAbortedBlock(const CFGBlock *block, const ExplodedNode *node,
+                       const Stmt *stmt) {
+    blocksAborted.push_back(std::make_pair(block, std::make_pair(node, stmt)));
   }
   
   WorkList *getWorkList() const { return WList; }
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index b7c4958..821fc6e 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -241,6 +241,7 @@ public:
 
   // Functions for external checking of whether we have unfinished work
   bool wasBlocksExhausted() const { return Engine.wasBlocksExhausted(); }
+  bool wereBlocksAborted() const { return Engine.wasBlockAborted(); }
   bool hasEmptyWorkList() const { return !Engine.getWorkList()->hasWork(); }
   bool hasWorkRemaining() const { return Engine.hasWorkRemaining(); }
 
@@ -403,6 +404,8 @@ public:
   std::pair<const ProgramPointTag *, const ProgramPointTag*>
     getEagerlyAssumeTags();
 
+  const ProgramPointTag* getBlocksExceededTag() const;
+
   SVal evalMinus(SVal X) {
     return X.isValid() ? svalBuilder.evalMinus(cast<NonLoc>(X)) : X;
   }
diff --git a/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp b/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
index abc76b1..d2c026b 100644
--- a/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
@@ -27,18 +27,47 @@ using namespace ento;
 namespace {
 class AnalyzerStatsChecker : public Checker<check::EndAnalysis> {
 public:
-  void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const;
+  void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,
+                        ExprEngine &Eng) const;
+private:
+  // Emit visitation statistics about Decls
+  void emitDeclStats(ExplodedGraph &G, ExprEngine &Eng, BugReporter &B,
+                     const SourceManager &SM) const;
+
+  // Emit information about exhausted blocks (including sinks)
+  void emitExhaustedStats(ExprEngine &Eng, BugReporter &B,
+                          const SourceManager &SM) const;
+
+  // Emit information about aborted blocks due to incomplete implementation
+  void emitAbortedStats(ExprEngine &Eng, BugReporter &B,
+                        const SourceManager &SM) const;
+
+  // Emit information about incomplete analysis due to block limits
+  void emitBlockExhaustionStats(ExprEngine &Eng, BugReporter &B,
+                                const SourceManager &SM) const;
+
+  // Get an approximate statement located near a ProgramPoint. Returns NULL if
+  // one cannot be found.
+  const Stmt *getApproxStmt(const ProgramPoint &PP) const;
 };
 }
 
 void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
                                             BugReporter &B,
                                             ExprEngine &Eng) const {
-  const CFG *C  = 0;
-  const Decl *D = 0;
-  const LocationContext *LC = 0;
   const SourceManager &SM = B.getSourceManager();
+  emitDeclStats(G, Eng, B, SM);
+  emitExhaustedStats(Eng, B, SM);
+  emitAbortedStats(Eng, B, SM);
+  emitBlockExhaustionStats(Eng, B, SM);
+}
+
+void AnalyzerStatsChecker::emitDeclStats(ExplodedGraph &G,
+                                         ExprEngine& Eng,
+                                         BugReporter &B,
+                                         const SourceManager &SM) const {
   llvm::SmallPtrSet<const CFGBlock*, 256> reachable;
+  const LocationContext *LC = 0; // TODO: don't assume only one LC
 
   // Iterate over explodedgraph
   for (ExplodedGraph::node_iterator I = G.nodes_begin();
@@ -55,8 +84,7 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
   }
 
   // Get the CFG and the Decl of this block
-  C = LC->getCFG();
-  D = LC->getAnalysisDeclContext()->getDecl();
+  const CFG *C = LC->getCFG();
 
   unsigned total = 0, unreachable = 0;
 
@@ -76,6 +104,7 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
   // Generate the warning string
   SmallString<128> buf;
   llvm::raw_svector_ostream output(buf);
+  const Decl *D = LC->getAnalysisDeclContext()->getDecl();
   PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
   if (Loc.isValid()) {
     output << Loc.getFilename() << " : ";
@@ -90,29 +119,118 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
   }
   
   output << " -> Total CFGBlocks: " << total << " | Unreachable CFGBlocks: "
-      << unreachable << " | Exhausted Block: "
+      << unreachable << " | Exhausted Blocks: "
       << (Eng.wasBlocksExhausted() ? "yes" : "no")
+      << " | Aborted Blocks: "
+      << (Eng.wereBlocksAborted() ? "yes" : "no")
       << " | Empty WorkList: "
       << (Eng.hasEmptyWorkList() ? "yes" : "no");
 
   B.EmitBasicReport("Analyzer Statistics", "Internal Statistics", output.str(),
       PathDiagnosticLocation(D, SM));
+}
 
-  // Emit warning for each block we bailed out on
+void AnalyzerStatsChecker::emitExhaustedStats(ExprEngine &Eng,
+                                              BugReporter &B,
+                                              const SourceManager &SM) const {
   typedef CoreEngine::BlocksExhausted::const_iterator ExhaustedIterator;
   const CoreEngine &CE = Eng.getCoreEngine();
+
   for (ExhaustedIterator I = CE.blocks_exhausted_begin(),
       E = CE.blocks_exhausted_end(); I != E; ++I) {
-    const BlockEdge &BE =  I->first;
+    const BlockEdge &BE  = I->first;
+    const ExplodedNode *EN = I->second;
+    const LocationContext *LC = EN->getLocationContext();
+
     const CFGBlock *Exit = BE.getDst();
     const CFGElement &CE = Exit->front();
-    if (const CFGStmt *CS = dyn_cast<CFGStmt>(&CE))
-      B.EmitBasicReport("Bailout Point", "Internal Statistics", "The analyzer "
-          "stopped analyzing at this point",
+    if (const CFGStmt *CS = dyn_cast<CFGStmt>(&CE)) {
+      // Check if the sink was generated from visitation limits
+      if (EN->getLocation().getTag() == Eng.getBlocksExceededTag()) {
+        B.EmitBasicReport("Exhaustion Point", "Internal Statistics", "The "
+          "analyzer stopped because this block was visited too many times",
+          PathDiagnosticLocation::createBegin(CS->getStmt(), SM, LC));
+      } else {
+      B.EmitBasicReport("Sink Point", "Internal Statistics", "The analyzer "
+          "could not continue past this point",
           PathDiagnosticLocation::createBegin(CS->getStmt(), SM, LC));
+      }
+    }
   }
 }
 
+void AnalyzerStatsChecker::emitAbortedStats(ExprEngine &Eng,
+                                            BugReporter &B,
+                                            const SourceManager &SM) const {
+  typedef CoreEngine::BlocksAborted::const_iterator AbortedIterator;
+  const CoreEngine &CE = Eng.getCoreEngine();
+
+  for (AbortedIterator I = CE.blocks_aborted_begin(),
+      E = CE.blocks_aborted_end(); I != E; ++I) {
+    const CoreEngine::AbortedStmtPair aborted = I->second;
+    const LocationContext *LC = aborted.first->getLocationContext();
+    const Stmt *S = aborted.second;
+
+    SmallString<128> buf("The analyzer stopped at this point due to an "
+        "unsupported statement of type ");
+    buf += S->getStmtClassName();
+    B.EmitBasicReport("Abort Point", "Internal Statistics", buf.str(),
+        PathDiagnosticLocation::createBegin(S, SM, LC));
+  }
+}
+
+void AnalyzerStatsChecker::emitBlockExhaustionStats(ExprEngine &Eng,
+                                                    BugReporter &B,
+                                                    const SourceManager &SM)
+                                                    const {
+  // Check to see if we exceeded our block limit
+  WorkList *WL = Eng.getCoreEngine().getWorkList();
+  if (!WL->hasWork())
+    return;
+
+  WorkListUnit nextWorkItem = WL->dequeue();
+  const ExplodedNode *nextEN = nextWorkItem.getNode();
+  const Stmt *S = getApproxStmt(nextEN->getLocation());
+
+  if (S == NULL)
+    return;
+
+  const LocationContext *LC = nextEN->getLocationContext();
+  B.EmitBasicReport("Abort Point", "Internal Statistics", "The analyzer stopped"
+      "at this point due to visitation limits",
+      PathDiagnosticLocation::createBegin(S, SM, LC));
+}
+
+const Stmt *AnalyzerStatsChecker::getApproxStmt(const ProgramPoint &PP) const {
+  // Try to get a real Stmt first
+  if (const StmtPoint *location = dyn_cast<StmtPoint>(&PP)) {
+    return location->getStmt();
+  }
+
+  // Next we will try for an approximation if we can get a CFGBlock
+  const CFGBlock *B =  NULL;
+  switch (PP.getKind()) {
+  case ProgramPoint::BlockEdgeKind:
+    B = cast<BlockEdge>(&PP)->getDst();
+    break;
+  case ProgramPoint::BlockEntranceKind:
+    B = cast<BlockEntrance>(&PP)->getBlock();
+    break;
+  case ProgramPoint::BlockExitKind:
+    B = cast<BlockExit>(&PP)->getBlock();
+    break;
+  default:
+    return NULL;
+  }
+
+  const CFGElement &CE = B->front();
+  if (const CFGStmt *CS = dyn_cast<CFGStmt>(&CE)) {
+    return CS->getStmt();
+  }
+
+  return NULL;
+}
+
 void ento::registerAnalyzerStatsChecker(CheckerManager &mgr) {
   mgr.registerChecker<AnalyzerStatsChecker>();
 }
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 34ad23a..2eaff2b 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -490,7 +490,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
     case Stmt::LambdaExprClass:
     case Stmt::SEHFinallyStmtClass: {
       const ExplodedNode *node = Bldr.generateNode(S, Pred, Pred->getState());
-      Engine.addAbortedBlock(node, currentBuilderContext->getBlock());
+      Engine.addAbortedBlock(currentBuilderContext->getBlock(), node, S);
       break;
     }
     
@@ -926,13 +926,13 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
 
 /// Block entrance.  (Update counters).
 void ExprEngine::processCFGBlockEntrance(NodeBuilderWithSinks &nodeBuilder) {
-  
+
   // FIXME: Refactor this into a checker.
   ExplodedNode *pred = nodeBuilder.getContext().getPred();
-  
+
   if (nodeBuilder.getContext().getCurrentBlockCount() >= AMgr.getMaxVisit()) {
-    static SimpleProgramPointTag tag("ExprEngine : Block count exceeded");
-    nodeBuilder.generateNode(pred->getState(), pred, &tag, true);
+    nodeBuilder.generateNode(pred->getState(), pred, getBlocksExceededTag(),
+                             true);
   }
 }
 
@@ -1952,3 +1952,8 @@ void ExprEngine::ViewGraph(ExplodedNode** Beg, ExplodedNode** End) {
   GraphPrintSourceManager = NULL;
 #endif
 }
+
+const ProgramPointTag* ExprEngine::getBlocksExceededTag() const {
+  static SimpleProgramPointTag tag("ExprEngine : Block count exceeded");
+  return &tag;
+}
