Index: /trunk/src/VBox/ValidationKit/testdriver/reporter.py
===================================================================
--- /trunk/src/VBox/ValidationKit/testdriver/reporter.py	(revision 61322)
+++ /trunk/src/VBox/ValidationKit/testdriver/reporter.py	(revision 61323)
@@ -168,4 +168,12 @@
         """
         _ = oSrcFile; _ = sSrcFilename; _ = sAltName; _ = sDescription; _ = sKind; _ = sCaller; _ = sTsPrf;
+        return True;
+
+    def addLogString(self, sLog, sLogName, sAltName, sDescription, sKind, sCaller, sTsPrf):
+        """
+        Adds the file to the report.
+        Returns True on success, False on failure.
+        """
+        _ = sLog; _ = sLogName; _ = sAltName; _ = sDescription; _ = sKind; _ = sCaller; _ = sTsPrf;
         return True;
 
@@ -465,4 +473,34 @@
         return fRc;
 
+    def addLogString(self, sLog, sLogName, sAltName, sDescription, sKind, sCaller, sTsPrf):
+        # Figure the destination filename.
+        iOtherFile = self.iOtherFile;
+        self.iOtherFile += 1;
+        sDstFilename = os.path.join(self.sLogDir, 'other-%d-%s.log' \
+                                    % (iOtherFile, os.path.splitext(os.path.basename(sLogName))[0]));
+        self.log(0, '** Other log file: %s - %s (%s)' % (sDstFilename, sDescription, sLogName), sCaller, sTsPrf);
+
+        # Open the destination file and copy over the data.
+        fRc = True;
+        try:
+            oDstFile = utils.openNoInherit(sDstFilename, 'w');
+        except Exception, oXcpt:
+            self.log(0, 'error opening %s: %s' % (sDstFilename, oXcpt), sCaller, sTsPrf);
+        else:
+            try:
+                oDstFile.write(sLog);
+            except Exception, oXcpt:
+                fRc = False;
+                self.log(0, 'error writing %s: %s' % (sDstFilename, oXcpt), sCaller, sTsPrf);
+
+            oDstFile.close();
+
+            # Leave a mark in the XML log.
+            self._xmlWrite(['<LogFile timestamp="%s" filename="%s" source="%s" kind="%s" ok="%s">%s</LogFile>\n'
+                % (utils.getIsoTimestamp(), self._xmlEscAttr(os.path.basename(sDstFilename)), self._xmlEscAttr(sLogName), \
+                   self._xmlEscAttr(sKind), fRc, self._xmlEscAttr(sDescription))] );
+        _ = sAltName;
+        return fRc;
+
     def subXmlStart(self, oFileWrapper):
         # Open a new file and just include it from the main XML.
@@ -682,4 +720,43 @@
         return False;
 
+    def _doUploadString(self, sSrc, sSrcName, sDescription, sKind, sMime):
+        """ Uploads the given string as a separate file to the test manager. """
+
+        # Prepare header and url.
+        dHeader = dict(self._dHttpHeader);
+        dHeader['Content-Type'] = 'application/octet-stream';
+        self._writeOutput('%s: _doUploadString: sHeader=%s' % (utils.getTimePrefix(), dHeader,));
+        self._writeOutput('%s: _doUploadString: size=%d' % (utils.getTimePrefix(), sys.getsizeof(sSrc),));
+
+        from common import constants;
+        sUrl = self._sTmServerPath + '&' \
+             + self._fnUrlEncode({ constants.tbreq.UPLOAD_PARAM_NAME: os.path.basename(sSrcName),
+                                   constants.tbreq.UPLOAD_PARAM_DESC: sDescription,
+                                   constants.tbreq.UPLOAD_PARAM_KIND: sKind,
+                                   constants.tbreq.UPLOAD_PARAM_MIME: sMime,
+                                   constants.tbreq.ALL_PARAM_ACTION:  constants.tbreq.UPLOAD,
+                                });
+
+        # Retry loop.
+        secStart = utils.timestampSecond();
+        while True:
+            try:
+                oConn = self._fnTmConnect();
+                oConn.request('POST', sUrl, sSrc, dHeader);
+                fRc = self._processTmStatusResponse(oConn, '_doUploadString', fClose = True);
+                oConn.close();
+                if fRc is not None:
+                    return fRc;
+            except:
+                logXcpt('warning: exception during UPLOAD request');
+
+            if utils.timestampSecond() - secStart >= self.kcSecTestManagerRetryTimeout:
+                self._writeOutput('%s: _doUploadString: Timed out.' % (utils.getTimePrefix(),));
+                break;
+            self._writeOutput('%s: _doUploadString: Retrying...' % (utils.getTimePrefix(), ));
+            time.sleep(2);
+
+        return False;
+
     def _xmlDoFlush(self, asXml, fRetry = False, fDtor = False):
         """
@@ -757,4 +834,18 @@
             self.log(0, '*** UNKNOWN FILE "%s" - KIND "%s" - DESC "%s" ***'
                      % (sSrcFilename, sKind, sDescription),  sCaller, sTsPrf);
+        return fRc;
+
+    def addLogString(self, sLog, sLogName, sAltName, sDescription, sKind, sCaller, sTsPrf):
+        fRc = True;
+        if sKind in [ 'text', 'log', ]  or  sKind.startswith('log/'):
+            self.log(0, '*** Uploading "%s" - KIND: "%s" - DESC: "%s" ***'
+                        % (sLogName, sKind, sDescription),  sCaller, sTsPrf);
+            self.xmlFlush();
+            g_oLock.release();
+            self._doUploadString(sLog, sAltName, sDescription, sKind, 'text/plain');
+            g_oLock.acquire();
+        else:
+            self.log(0, '*** UNKNOWN FILE "%s" - KIND "%s" - DESC "%s" ***'
+                     % (sLogName, sKind, sDescription),  sCaller, sTsPrf);
         return fRc;
 
@@ -1223,4 +1314,26 @@
     return fRc;
 
+def addLogString(sLog, sLogName, sKind, sDescription = ''):
+    """
+    Adds the specified log string to the report.
+
+    The sLog parameter sets the name of the log file.
+
+    The sDescription is a free form description of the log file.
+
+    The sKind parameter is for adding some machine parsable hint what kind of
+    log file this really is.
+
+    Returns True on success, False on failure (no ENOENT errors are logged).
+    """
+    sTsPrf  = utils.getTimePrefix();
+    sCaller = utils.getCallerName();
+    fRc     = False;
+
+    g_oLock.acquire();
+    fRc = g_oReporter.addLogString(sLog, sLogName, None, sDescription, sKind, sCaller, sTsPrf);
+    g_oLock.release();
+    return fRc;
+
 def isLocal():
     """Is this a local reporter?"""
Index: /trunk/src/VBox/ValidationKit/testdriver/vbox.py
===================================================================
--- /trunk/src/VBox/ValidationKit/testdriver/vbox.py	(revision 61322)
+++ /trunk/src/VBox/ValidationKit/testdriver/vbox.py	(revision 61323)
@@ -801,4 +801,5 @@
         self.fAlwaysUploadLogs  = False;
         self.fAlwaysUploadScreenshots = False;
+        self.fEnableDebugger          = True;
 
         # Quietly detect build and validation kit.
@@ -1523,4 +1524,7 @@
         reporter.log('  --vbox-always-upload-screenshots');
         reporter.log('      Whether to always upload final screen shots, or only do so on failure.');
+        reporter.log('  --debugger, --no-debugger');
+        reporter.log('      Enables the VBox debugger, port at 5000');
+        reporter.log('      Default: --debugger');
         if self.oTestVmSet is not None:
             self.oTestVmSet.showUsage();
@@ -1624,4 +1628,8 @@
         elif asArgs[iArg] == '--vbox-always-upload-screenshots':
             self.fAlwaysUploadScreenshots = True;
+        elif asArgs[iArg] == '--debugger':
+            self.fEnableDebugger = True;
+        elif asArgs[iArg] == '--no-debugger':
+            self.fEnableDebugger = False;
         else:
             # Relevant for selecting VMs to test?
@@ -2124,4 +2132,6 @@
             elif sFirmwareType == 'efi':
                 fRc = oSession.setFirmwareType(vboxcon.FirmwareType_EFI);
+            if fRc and self.fEnableDebugger:
+                fRc = oSession.setExtraData('VBoxInternal/DBGC/Enabled', '1');
 
             if fRc: fRc = oSession.saveSettings();
@@ -2527,10 +2537,17 @@
         # Take Screenshot and upload it (see below) to Test Manager if appropriate/requested.
         #
-        sLastScreenshotPath = None
+        sLastScreenshotPath = None;
         if fTakeScreenshot is True  or  self.fAlwaysUploadScreenshots  or  reporter.testErrorCount() > 0:
-            sLastScreenshotPath = os.path.join(self.sScratchPath, "LastScreenshot-%s.png" % oSession.sName)
-            fRc = oSession.takeScreenshot(sLastScreenshotPath)
+            sLastScreenshotPath = os.path.join(self.sScratchPath, "LastScreenshot-%s.png" % oSession.sName);
+            fRc = oSession.takeScreenshot(sLastScreenshotPath);
             if fRc is not True:
-                sLastScreenshotPath = None
+                sLastScreenshotPath = None;
+
+        #
+        # Query the OS kernel log from the debugger if appropriate/requested.
+        #
+        sOsKernelLog = None;
+        if self.fAlwaysUploadLogs or reporter.testErrorCount() > 0:
+            sOsKernelLog = oSession.queryOsKernelLog();
 
         #
@@ -2603,4 +2620,11 @@
             else:
                 reporter.addLogFile(sLastScreenshotPath, 'screenshot/success', 'Last VM screenshot');
+
+        # Add the guest OS log if it has been requested and taken successfully.
+        if sOsKernelLog is not None:
+            if reporter.testErrorCount() > 0:
+                reporter.addLogString(sOsKernelLog, 'kern.log', 'log/guest/kernel/failure', 'Guest OS kernel log');
+            else:
+                reporter.addLogString(sOsKernelLog, 'kern.log', 'log/guest/kernel/success', 'Guest OS kernel log');
 
         return fRc;
Index: /trunk/src/VBox/ValidationKit/testdriver/vboxwrappers.py
===================================================================
--- /trunk/src/VBox/ValidationKit/testdriver/vboxwrappers.py	(revision 61322)
+++ /trunk/src/VBox/ValidationKit/testdriver/vboxwrappers.py	(revision 61323)
@@ -2373,4 +2373,30 @@
 
     #
+    # IMachineDebugger wrappers.
+    #
+
+    def queryOsKernelLog(self):
+        """
+        Tries to get the OS kernel log using the VM debugger interface.
+
+        Returns string containing the kernel log on success.
+        Returns None on failure.
+        """
+        try:
+            sPluginsLoaded = self.o.console.debugger.loadPlugIn('all');
+            if sPluginsLoaded == 'all':
+                sOsDetected = self.o.console.debugger.detectOS();
+                if sOsDetected is not None:
+                    sOsKernelLog = self.o.console.debugger.queryOSKernelLog(0);
+            else:
+                reporter.log('Unable to load debugger plugins');
+                return None;
+        except:
+            reporter.logXcpt('Unable to query the OS kernel log');
+            return None;
+
+        return sOsKernelLog;
+
+    #
     # Other methods.
     #
