Index: trunk/src/VBox/ValidationKit/testmanager/batch/virtual_test_sheriff.py
===================================================================
--- trunk/src/VBox/ValidationKit/testmanager/batch/virtual_test_sheriff.py	(revision 80128)
+++ trunk/src/VBox/ValidationKit/testmanager/batch/virtual_test_sheriff.py	(revision 80140)
@@ -248,7 +248,7 @@
         """
         if not self.sSvcLog:
-            asSvcLogFiles = self.oTree.getListOfLogFilesByKind(TestResultFileData.ksKind_LogReleaseSvc);
-            if asSvcLogFiles:
-                self.sSvcLog = self.getLogFile(asSvcLogFiles[0]);
+            aoSvcLogFiles = self.oTree.getListOfLogFilesByKind(TestResultFileData.ksKind_LogReleaseSvc);
+            if aoSvcLogFiles:
+                self.sSvcLog = self.getLogFile(aoSvcLogFiles[0]);
         return self.sSvcLog;
 
@@ -588,4 +588,7 @@
     ## @name Failure reasons we know.
     ## @{
+    ktReason_Add_CopyToGuest_Timeout                   = ( 'Additions',         'CopyToGuest Timeout' );
+    ktReason_Add_FlushViewOfFile                       = ( 'Additions',         'FlushViewOfFile' );
+    ktReason_Add_Mmap_Coherency                        = ( 'Additions',         'mmap coherency' );
     ktReason_BSOD_Recovery                             = ( 'BSOD',              'Recovery' );
     ktReason_BSOD_Automatic_Repair                     = ( 'BSOD',              'Automatic Repair' );
@@ -1004,5 +1007,7 @@
 
     ## Things we search a main or VM log for to figure out why something went bust.
-    katSimpleMainAndVmLogReasons = [
+    ## @note DO NOT ADD MORE STUFF HERE!
+    ##       Please use katSimpleMainLogReasons and katSimpleVmLogReasons instead!
+    katSimpleMainAndVmLogReasonsDeprecated = [
         # ( Whether to stop on hit, reason tuple, needle text. )
         ( False, ktReason_Guru_Generic,                             'GuruMeditation' ),
@@ -1038,4 +1043,14 @@
     ];
 
+    ## This we search a main log for to figure out why something went bust.
+    katSimpleMainLogReasons = [
+        # ( Whether to stop on hit, reason tuple, needle text. )
+    ];
+
+    ## This we search a VM log  for to figure out why something went bust.
+    katSimpleVmLogReasons = [
+        # ( Whether to stop on hit, reason tuple, needle text. )
+    ];
+
     ## Things we search a VBoxHardening.log file for to figure out why something went bust.
     katSimpleVBoxHardeningLogReasons = [
@@ -1139,4 +1154,36 @@
 
 
+    def investigateGATest(self, oCaseFile, oFailedResult, sResultLog):
+        """
+        Investigates a failed VM run.
+        """
+        enmReason = None;
+        if oFailedResult.sName == 'mmap':
+            if sResultLog.find('FsPerf: Flush issue at offset ') >= 0:
+                enmReason = self.ktReason_Add_Mmap_Coherency;
+            elif sResultLog.find('FlushViewOfFile') >= 0:
+                enmReason = self.ktReason_Add_FlushViewOfFile;
+        elif oFailedResult.sName == 'Copy to guest':
+            if sResultLog.find('*** abort action ***') >= 0:
+                enmReason = self.ktReason_Add_CopyToGuest_Timeout;
+
+        if enmReason is not None:
+            return oCaseFile.noteReasonForId(enmReason, oFailedResult.idTestResult);
+
+        self.vprint(u'TODO: Cannot place GA failure idTestResult=%u - %s' % (oFailedResult.idTestResult, oFailedResult.sName,));
+        self.dprint(u'%s + %s <<\n%s\n<<' % (oFailedResult.tsCreated, oFailedResult.tsElapsed, sResultLog,));
+        return False;
+
+    def isResultFromGATest(self, oFailedResult):
+        """
+        Checks if this result and corresponding log snippet looks like a GA test run.
+        """
+        while oFailedResult is not None:
+            if oFailedResult.sName in [ 'Guest Control', 'Shared Folders', 'FsPerf', ]:
+                return True;
+            oFailedResult = oFailedResult.oParent;
+        return False;
+
+
     def investigateVMResult(self, oCaseFile, oFailedResult, sResultLog):
         """
@@ -1198,5 +1245,20 @@
             # Loop thru the simple stuff.
             #
-            fRet = self.scanLog([sResultLog, sVMLog], self.katSimpleMainAndVmLogReasons, oCaseFile, oFailedResult.idTestResult);
+
+            # Main log.
+            fRet = self.scanLog([sResultLog,], self.katSimpleMainLogReasons, oCaseFile, oFailedResult.idTestResult);
+            if fRet is True:
+                return fRet;
+            fFoundSomething |= fRet is None;
+
+            # VM log.
+            fRet = self.scanLog([sVMLog,], self.katSimpleVmLogReasons, oCaseFile, oFailedResult.idTestResult);
+            if fRet is True:
+                return fRet;
+            fFoundSomething |= fRet is None;
+
+            # Old main + vm log.
+            fRet = self.scanLog([sResultLog, sVMLog], self.katSimpleMainAndVmLogReasonsDeprecated,
+                                oCaseFile, oFailedResult.idTestResult);
             if fRet is True:
                 return fRet;
@@ -1307,4 +1369,18 @@
         return None;
 
+    def isResultFromVMRun(self, oFailedResult, sResultLog):
+        """
+        Checks if this result and corresponding log snippet looks like a VM run.
+        """
+
+        # Look for startVmEx/ startVmAndConnectToTxsViaTcp and similar output in the log.
+        if sResultLog.find(' startVm') > 0:
+            return True;
+
+        # Any other indicators? No?
+        _ = oFailedResult;
+        return False;
+
+
     ## Things we search a VBoxSVC log for to figure out why something went bust.
     katSimpleSvcLogReasons = [
@@ -1324,17 +1400,16 @@
         return False;
 
-
-    def isResultFromVMRun(self, oFailedResult, sResultLog):
-        """
-        Checks if this result and corresponding log snippet looks like a VM run.
-        """
-
-        # Look for startVmEx/ startVmAndConnectToTxsViaTcp and similar output in the log.
-        if sResultLog.find(' startVm') > 0:
-            return True;
-
-        # Any other indicators? No?
-        _ = oFailedResult;
+    def investigateNtHardLogForVMRun(self, oCaseFile):
+        """
+        Check if the hardening log for a single VM run contains VM crash indications.
+        """
+        aoLogFiles = oCaseFile.oTree.getListOfLogFilesByKind(TestResultFileData.ksKind_LogReleaseVm);
+        for oLogFile in aoLogFiles:
+            if oLogFile.sFile.find('VBoxHardening.log') >= 0:
+                sLog = oCaseFile.getLogFile(oLogFile);
+                if sLog.find('Quitting: ExitCode=0xc0000005') >= 0:
+                    return oCaseFile.noteReasonForId(self.ktReason_Unknown_VM_Crash, oCaseFile.oTree.idTestResult);
         return False;
+
 
     def investigateVBoxVMTest(self, oCaseFile, fSingleVM):
@@ -1415,4 +1490,7 @@
                 self.investigateVMResult(oCaseFile, oFailedResult, sResultLog);
 
+            elif self.isResultFromGATest(oFailedResult):
+                self.investigateGATest(oCaseFile, oFailedResult, sResultLog);
+
             elif sResultLog.find('most likely not unique') > 0:
                 oCaseFile.noteReasonForId(self.ktReason_Host_NetworkMisconfiguration, oFailedResult.idTestResult)
@@ -1433,5 +1511,5 @@
 
         #
-        # Check VBoxSVC.log for VM crashes if inconclusive on single VM runs.
+        # Check VBoxSVC.log and VBoxHardening.log for VM crashes if inconclusive on single VM runs.
         #
         if fSingleVM and len(oCaseFile.dReasonForResultId) < len(aoFailedResults):
@@ -1439,4 +1517,6 @@
                         % (len(oCaseFile.dReasonForResultId), len(aoFailedResults)));
             if self.investigateSvcLogForVMRun(oCaseFile, oCaseFile.getSvcLog()):
+                return self.caseClosed(oCaseFile);
+            if self.investigateNtHardLogForVMRun(oCaseFile):
                 return self.caseClosed(oCaseFile);
 
