예제 #1
0
 def fRun(oTest):
   global bFailed, oOutputLock;
   oConcurrentTestsSemaphore.acquire();
   sBinary = dsBinaries_by_sISA[oTest.sISA];
   asApplicationCommandLine = [sBinary] + oTest.asCommandLineArguments;
   if bDebugStartFinish:
     oOutputLock and oOutputLock.acquire();
     oTest.bHasOutputLock = True;
     print "@ Started %s" % oTest;
     oOutputLock and oOutputLock.release();
     oTest.bHasOutputLock = False;
   try:
     oTest.oBugId = cBugId(
       asApplicationCommandLine = asApplicationCommandLine,
       asSymbolServerURLs = ["http://msdl.microsoft.com/download/symbols"],
       bGetDetailsHTML = dxConfig["bSaveTestReports"],
       fFinishedCallback = oTest.fFinishedHandler,
       fInternalExceptionCallback = oTest.fInternalExceptionHandler,
     );
     oTest.oBugId.fSetCheckForExcessiveCPUUsageTimeout(1);
   except Exception, oException:
     if not bFailed:
       bFailed = True;
       oOutputLock and oOutputLock.acquire();
       oTest.bHasOutputLock = True;
       print "- Failed test: %s" " ".join([dsBinaries_by_sISA[oTest.sISA]] + oTest.asCommandLineArguments);
       print "  Expected:    %s" % oTest.sExpectedBugTypeId;
       print "  Exception:   %s" % oException;
       oOutputLock and oOutputLock.release();
       oTest.bHasOutputLock = False;
예제 #2
0
파일: Tests.py 프로젝트: noobdoesre/cBugId
 def fRun(oTest):
   global bFailed, oOutputLock;
   oConcurrentTestsSemaphore.acquire();
   sBinary = dsBinaries_by_sISA[oTest.sISA];
   asApplicationCommandLine = [sBinary] + oTest.asCommandLineArguments;
   if bDebugStartFinish:
     oOutputLock and oOutputLock.acquire();
     oTest.bHasOutputLock = True;
     print "* Started %s" % oTest;
     oOutputLock and oOutputLock.release();
     oTest.bHasOutputLock = False;
   try:
     oTest.oBugId = cBugId(
       sCdbISA = oTest.sISA,
       asApplicationCommandLine = asApplicationCommandLine,
       asSymbolServerURLs = ["http://msdl.microsoft.com/download/symbols"],
       bGetDetailsHTML = True,
       fFinishedCallback = oTest.fFinishedHandler,
       fInternalExceptionCallback = oTest.fInternalExceptionHandler,
     );
     oTest.oBugId.fSetCheckForExcessiveCPUUsageTimeout(1);
   except Exception, oException:
     if not bFailed:
       bFailed = True;
       oOutputLock and oOutputLock.acquire();
       oTest.bHasOutputLock = True;
       print "- Failed test: %s" % " ".join([dsBinaries_by_sISA[oTest.sISA]] + oTest.asCommandLineArguments);
       print "  Expected:    %s" % oTest.sExpectedBugTypeId;
       print "  Exception:   %s" % oException;
       oOutputLock and oOutputLock.release();
       oTest.bHasOutputLock = False;
예제 #3
0
파일: Tests.py 프로젝트: bnagy/BugId
 def fRun(oTest):
   oConcurrentTestsSemaphore.acquire();
   sBinary = dsBinaries_by_sISA[oTest.sISA];
   asApplicationCommandLine = [sBinary] + oTest.asCommandLineArguments;
   oBugId = cBugId(
     asApplicationCommandLine = asApplicationCommandLine,
     fFinishedCallback = oTest.fFinishedHandler,
     fInternalExceptionCallback = oTest.fInternalExceptionHandler,
   );
예제 #4
0
파일: Tests.py 프로젝트: snowendless/cBugId
 def fRun(oTest, fErrorCallback):
     global bFailed, oOutputLock
     oTest.fErrorCallback = fErrorCallback
     oOutputLock and oOutputLock.acquire()
     oTest.bHasOutputLock = True
     print "* %s\r" % oTest,
     oOutputLock and oOutputLock.release()
     oTest.bHasOutputLock = False
     sApplicationBinaryPath = oTest.sBinary
     asApplicationArguments = oTest.asCommandLineArguments
     if oTest.bRunInShell:
         asApplicationArguments = ["/C", sApplicationBinaryPath
                                   ] + asApplicationArguments
         sApplicationBinaryPath = os.environ.get("ComSpec")
     if bDebugStartFinish:
         oOutputLock and oOutputLock.acquire()
         oTest.bHasOutputLock = True
         print "* Started %s" % oTest
         oOutputLock and oOutputLock.release()
         oTest.bHasOutputLock = False
     try:
         oTest.oBugId = cBugId(
             sCdbISA=oTest.sISA,
             sApplicationBinaryPath=sApplicationBinaryPath,
             asApplicationArguments=asApplicationArguments,
             asSymbolServerURLs=[
                 "http://msdl.microsoft.com/download/symbols"
             ],  # Will be ignore if symbols are disabled.
             bGenerateReportHTML=oTest.bGenerateReportHTML,
             fFinishedCallback=oTest.fFinishedHandler,
             fInternalExceptionCallback=oTest.fInternalExceptionHandler,
             fFailedToDebugApplicationCallback=oTest.
             fFailedToDebugApplicationHandler,
             fPageHeapNotEnabledCallback=oTest.fPageHeapNotEnabledHandler,
             fStdInInputCallback=gbDebugIO and oTest.fOutputStdIn,
             fStdOutOutputCallback=gbDebugIO and oTest.fOutputStdOut,
             fStdErrOutputCallback=gbDebugIO and oTest.fOutputStdErr,
         )
         oTest.oBugId.fStart()
         oTest.oBugId.fSetCheckForExcessiveCPUUsageTimeout(1)
         oTest.oBugId.fWait()
     except Exception, oException:
         if not bFailed:
             bFailed = True
             oOutputLock and oOutputLock.acquire()
             oTest.bHasOutputLock = True
             print "- Failed test: %s" % " ".join(
                 [dsBinaries_by_sISA[oTest.sISA]] +
                 oTest.asCommandLineArguments)
             print "  Expected:    %s" % repr(oTest.sExpectedBugId)
             print "  Exception:   %s" % repr(oException)
             oOutputLock and oOutputLock.release()
             oTest.bHasOutputLock = False
             fErrorCallback()
             raise
예제 #5
0
파일: Tests.py 프로젝트: ik2ploit/BugId
 def fRun(oTest):
   global bFailed, oOutputLock;
   oConcurrentTestsSemaphore.acquire();
   sBinary = dsBinaries_by_sISA[oTest.sISA];
   asApplicationCommandLine = [sBinary] + oTest.asCommandLineArguments;
   try:
     oBugId = cBugId(
       asApplicationCommandLine = asApplicationCommandLine,
       fFinishedCallback = oTest.fFinishedHandler,
       fInternalExceptionCallback = oTest.fInternalExceptionHandler,
     );
   except Exception, oException:
     if not bFailed:
       bFailed = True;
       oOutputLock.acquire();
       print "- %s" % oTest;
       print "    => Exception: %s" % oException;
       oOutputLock.release();
       os._exit(1);
예제 #6
0
 def fRun(oTest):
     global bFailed, oOutputLock
     oConcurrentTestsSemaphore.acquire()
     if oTest.sExpectedFailedToDebugApplicationErrorMessage:
         sBinary = "this:cannot:be:run"
     else:
         sBinary = dsBinaries_by_sISA[oTest.sISA]
     asApplicationCommandLine = [sBinary] + oTest.asCommandLineArguments
     if bDebugStartFinish:
         oOutputLock and oOutputLock.acquire()
         oTest.bHasOutputLock = True
         print "* Started %s" % oTest
         oOutputLock and oOutputLock.release()
         oTest.bHasOutputLock = False
     try:
         oTest.oBugId = cBugId(
             sCdbISA=oTest.sISA,
             asApplicationCommandLine=asApplicationCommandLine,
             asSymbolServerURLs=[
                 "http://msdl.microsoft.com/download/symbols"
             ],  # Will be ignore if symbols are disabled.
             bGenerateReportHTML=oTest.bGenerateReportHTML,
             fFinishedCallback=oTest.fFinishedHandler,
             fInternalExceptionCallback=oTest.fInternalExceptionHandler,
         )
         oTest.oBugId.fStart()
         oTest.oBugId.fSetCheckForExcessiveCPUUsageTimeout(1)
     except Exception, oException:
         if not bFailed:
             bFailed = True
             oOutputLock and oOutputLock.acquire()
             oTest.bHasOutputLock = True
             print "- Failed test: %s" % " ".join(
                 [dsBinaries_by_sISA[oTest.sISA]] +
                 oTest.asCommandLineArguments)
             print "  Expected:    %s" % repr(oTest.sExpectedBugTypeId)
             print "  Exception:   %s" % repr(oException)
             oOutputLock and oOutputLock.release()
             oTest.bHasOutputLock = False
             raise
예제 #7
0
 def fRun(oTest):
     global bFailed, oOutputLock
     oConcurrentTestsSemaphore.acquire()
     sBinary = dsBinaries_by_sISA[oTest.sISA]
     asApplicationCommandLine = [sBinary] + oTest.asCommandLineArguments
     if bDebugStartFinish:
         oOutputLock.acquire()
         print "@ Started %s" % oTest
         oOutputLock.release()
     try:
         oTest.oBugId = cBugId(
             asApplicationCommandLine=asApplicationCommandLine,
             fFinishedCallback=oTest.fFinishedHandler,
             fInternalExceptionCallback=oTest.fInternalExceptionHandler,
         )
     except Exception, oException:
         if not bFailed:
             bFailed = True
             oOutputLock.acquire()
             print "- %s" % oTest
             print "    => Exception: %s" % oException
             oOutputLock.release()
예제 #8
0
파일: Tests.py 프로젝트: carlosgprado/BugId
 def fRun(oTest):
   global bFailed, oOutputLock;
   oConcurrentTestsSemaphore.acquire();
   sBinary = dsBinaries_by_sISA[oTest.sISA];
   asApplicationCommandLine = [sBinary] + oTest.asCommandLineArguments;
   if bDebugStartFinish:
     oOutputLock.acquire();
     print "@ Started %s" % oTest;
     oOutputLock.release();
   try:
     oTest.oBugId = cBugId(
       asApplicationCommandLine = asApplicationCommandLine,
       asSymbolServerURLs = ["http://msdl.microsoft.com/download/symbols"],
       fFinishedCallback = oTest.fFinishedHandler,
       fInternalExceptionCallback = oTest.fInternalExceptionHandler,
     );
   except Exception, oException:
     if not bFailed:
       bFailed = True;
       oOutputLock.acquire();
       print "- %s" % oTest;
       print "    => Exception: %s" % oException;
       oOutputLock.release();
예제 #9
0
파일: BugId.py 프로젝트: bnagy/BugId
   else:
     # Running after being resumed.
     print "* The application was resumed successfully and is running...";
 
 def fExceptionDetectedHandler(uCode, sDescription):
   print "* Exception code 0x%X (%s) was detected and is being analyzed..." % (uCode, sDescription);
 
 if asApplicationCommandLine:
   print "* The debugger is starting the application...";
   print "  Command line: %s" % " ".join(asApplicationCommandLine);
 else:
   print "* The debugger is attaching to the application...";
 oBugId = cBugId(
   asApplicationCommandLine = asApplicationCommandLine,
   auApplicationProcessIds = auApplicationProcessIds,
   asSymbolServerURLs = [],
   fApplicationRunningCallback = fApplicationRunningHandler,
   fExceptionDetectedCallback = fExceptionDetectedHandler,
 );
 oBugId.fWait();
 if oBugId.oErrorReport:
   print "* A bug was detected in the application.";
   print;
   print "Id:               %s" % oBugId.oErrorReport.sId;
   print "Description:      %s" % oBugId.oErrorReport.sErrorDescription;
   print "Process binary:   %s" % oBugId.oErrorReport.sProcessBinaryName;
   print "Code:             %s" % oBugId.oErrorReport.sCodeDescription;
   print "Security impact:  %s" % oBugId.oErrorReport.sSecurityImpact;
   if dxBugIdConfig["bSaveReport"]:
     dsMap = {'"': "''", "<": "[", ">": "]", "\\": "#", "/": "#", "?": "#", "*": "#", ":": ".", "|": "#"};
     sFileNameBase = "".join([dsMap.get(sChar, sChar) for sChar in oBugId.oErrorReport.sId]);
예제 #10
0
파일: BugId.py 프로젝트: pcb0ts/BugId
def fMain(asArguments):
  global \
      gasAttachToProcessesForExecutableNames, \
      gasBinaryNamesThatAreAllowedToRunWithoutPageHeap, \
      gbQuiet, \
      gbVerbose, \
      guDetectedBugsCount, \
      guMaximumNumberOfBugs;
  if len(asArguments) == 0:
    fPrintLogo();
    fPrintUsage(ddxApplicationSettings_by_sKeyword.keys());
    os._exit(0);
  # Parse all arguments until we encounter "--".
  sApplicationKeyword = None;
  sApplicationBinaryPath = None;
  auApplicationProcessIds = [];
  sUWPApplicationPackageName = None;
  sUWPApplicationId = None;
  asApplicationOptionalArguments = None;
  sApplicationISA = None;
  bRepeat = False;
  bCheckForUpdates = False;
  dxUserProvidedConfigSettings = {};
  bFast = False;
  while asArguments:
    sArgument = asArguments.pop(0);
    if sArgument == "--":
      if len(auApplicationProcessIds) > 0:
      # The rest of the arguments are to be passed to the application
        oConsole.fPrint(ERROR, "- You cannot provide process ids and application arguments.");
        os._exit(2);
      asApplicationOptionalArguments = asArguments;
      break;
    elif sArgument in ["-q", "/q"]:
      gbQuiet = True;
    elif sArgument in ["-v", "/v"]:
      gbVerbose = True;
    elif sArgument in ["-f", "/f"]:
      bFast = True;
    elif sArgument in ["-r", "/r"]:
      bRepeat = True;
    elif sArgument in ["-c", "/c"]:
      guMaximumNumberOfBugs = guDefaultCollateralMaximumNumberOfBugs;
    elif sArgument in ["-?", "/?", "-h", "/h"]:
      fPrintLogo();
      fPrintUsage(ddxApplicationSettings_by_sKeyword.keys());
      os._exit(0);
    elif sArgument.startswith("--"):
      if "=" in sArgument:
        sSettingName, sValue = sArgument[2:].split("=", 1);
      else:
        # "--bFlag" is an alias for "--bFlag=true"
        sSettingName = sArgument[2:];
        sValue = None;
      
      if sSettingName in ["pid", "pids"]:
        if not sValue:
          oConsole.fPrint(ERROR, "- You must provide at least one process id.");
          os._exit(2);
        if sApplicationBinaryPath is not None:
          oConsole.fPrint(ERROR, "- You cannot provide an application binary and process ids.");
          os._exit(2);
        if sUWPApplicationPackageName is not None:
          oConsole.fPrint(ERROR, "- You cannot provide an UWP application package name and process ids.");
          os._exit(2);
        auApplicationProcessIds += [long(x) for x in sValue.split(",")];
      elif sSettingName in ["uwp", "uwp-app"]:
        if not sValue:
          oConsole.fPrint(ERROR, "- You must provide an UWP application package name.");
          os._exit(2);
        if sUWPApplicationPackageName is not None:
          oConsole.fPrint(ERROR, "- You cannot provide multiple UWP application package names.");
          os._exit(2);
        if sApplicationBinaryPath is not None:
          oConsole.fPrint(ERROR, "- You cannot provide an application binary and UWP package name.");
          os._exit(2);
        if len(auApplicationProcessIds) > 0:
          oConsole.fPrint(ERROR, "- You cannot provide process ids and an UWP application package name.");
          os._exit(2);
        if "!" not in sValue:
          oConsole.fPrint(ERROR, "- Please provide a string of the form ", ERROR_INFO, sSettingName, \
              "=<package name>!<application id>.");
          os._exit(2);
        sUWPApplicationPackageName, sUWPApplicationId = sValue.split("!", 1);
      elif sSettingName in ["help"]:
        fPrintLogo();
        fPrintUsage(ddxApplicationSettings_by_sKeyword.keys());
        os._exit(0);
      elif sSettingName in ["version", "check-for-updates"]:
        fVersionCheck();
        os._exit(0);
      elif sSettingName in ["isa", "cpu"]:
        if not sValue:
          oConsole.fPrint(ERROR, "- You must provide an Instruction Set Architecture.");
          os._exit(2);
        if sValue not in ["x86", "x64"]:
          oConsole.fPrint(ERROR, "- Unknown Instruction Set Architecture ", repr(sValue));
          os._exit(2);
        sApplicationISA = sValue;
      elif sSettingName in ["quiet", "silent"]:
        if sValue is None or sValue.lower() == "true":
          gbQuiet = True;
        elif sValue.lower() == "false":
          gbQuiet = False;
        else:
          oConsole.fPrint(ERROR, "- The value for ", ERROR_INFO, "--", sSettingName, ERROR, \
              " must be \"true\" or \"false\".");
      elif sSettingName in ["verbose", "debug"]:
        if sValue is None or sValue.lower() == "true":
          gbVerbose = True;
        elif sValue.lower() == "false":
          gbVerbose = False;
        else:
          oConsole.fPrint(ERROR, "- The value for ", ERROR_INFO, "--", sSettingName, ERROR, \
              " must be \"true\" or \"false\".");
      elif sSettingName in ["fast", "quick"]:
        if sValue is None or sValue.lower() == "true":
          bFast = True;
        elif sValue.lower() == "false":
          bFast = False;
        else:
          oConsole.fPrint(ERROR, "- The value for ", ERROR_INFO, "--", sSettingName, ERROR, \
              " must be \"true\" or \"false\".");
      elif sSettingName in ["repeat", "forever"]:
        if sValue is None or sValue.lower() == "true":
          bRepeat = True;
        elif sValue.lower() == "false":
          bRepeat = False;
        else:
          oConsole.fPrint(ERROR, "- The value for ", ERROR_INFO, "--", sSettingName, ERROR, \
              " must be \"true\" or \"false\".");
      elif sSettingName in ["collateral"]:
        if sValue is None:
          guMaximumNumberOfBugs = guDefaultCollateralMaximumNumberOfBugs;
        else:
          guMaximumNumberOfBugs = long(sValue);
      elif sSettingName in ["test-internal-error", "internal-error-test"]:
        raise Exception("Testing internal error");
      else:
        if not sValue:
          oConsole.fPrint(ERROR, "- You cannot provide an argument (", ERROR_INFO, "--", sSettingName, ERROR, \
              ") without a value.");
          os._exit(2);
        try:
          xValue = json.loads(sValue);
        except ValueError as oError:
          oConsole.fPrint(ERROR, "- Cannot decode argument JSON value ", ERROR_INFO, "--", sSettingName, "=", sValue, \
              ERROR, ": ", ERROR_INFO, " ".join(oError.args), ERROR, ".");
          os._exit(2);
        # User provided config settings must be applied after any keyword specific config settings:
        dxUserProvidedConfigSettings[sSettingName] = xValue;
    elif sArgument in ddxApplicationSettings_by_sKeyword:
      if sApplicationKeyword is not None:
        oConsole.fPrint(ERROR, "- You cannot provide multiple application keywords.");
        os._exit(2);
      sApplicationKeyword = sArgument;
    elif sArgument[-1] == "?":
      sApplicationKeyword = sArgument[:-1];
      dxApplicationSettings = ddxApplicationSettings_by_sKeyword.get(sApplicationKeyword);
      if not dxApplicationSettings:
        oConsole.fPrint(ERROR, "- Unknown application keyword ", ERROR_INFO, sApplicationKeyword, ERROR, ".");
        os._exit(2);
      fPrintApplicationKeyWordHelp(sApplicationKeyword, dxApplicationSettings);
      os._exit(0);
    else:
      if sApplicationBinaryPath is not None:
        oConsole.fLock();
        try:
          oConsole.fPrint(ERROR, "- You cannot provide multiple application binaries.");
          oConsole.fPrint(ERROR, "  (Did you perhaps forget to put ", ERROR_INFO, "--", ERROR, \
              " before the start of the application arguments?)");
        finally:
          oConsole.fUnlock();
        os._exit(2);
      if len(auApplicationProcessIds) > 0:
        oConsole.fPrint(ERROR, "- You cannot provide process ids and an application binary.");
        os._exit(2);
      if sUWPApplicationPackageName is not None:
        oConsole.fPrint(ERROR, "- You cannot provide an application UWP package name and a binary.");
        os._exit(2);
      sApplicationBinaryPath = sArgument;
  
  if bFast:
    gbQuiet = True;
    dxUserProvidedConfigSettings["bGenerateReportHTML"] = False;
    dxUserProvidedConfigSettings["asSymbolServerURLs"] = [];
    dxUserProvidedConfigSettings["cBugId.bUse_NT_SYMBOL_PATH"] = False;
  
  dsApplicationURLTemplate_by_srSourceFilePath = {};
  
  fCleanup = None;
  if sApplicationKeyword:
    dxApplicationSettings = ddxApplicationSettings_by_sKeyword.get(sApplicationKeyword);
    if not dxApplicationSettings:
      oConsole.fPrint(ERROR, "- Unknown application keyword ", ERROR_INFO, sApplicationKeyword, ERROR, ".");
      os._exit(2);
    fCheckApplication = dxApplicationSettings.get("fCheckApplication");
    if fCheckApplication:
      fCheckApplication(); # This should terminate BugId with the relevant exit code if needed.
    fCleanup = dxApplicationSettings.get("fCleanup");
    # Get application binary/UWP package name/process ids as needed:
    if "sBinaryPath" in dxApplicationSettings:
      # This application is started from the command-line.
      if auApplicationProcessIds:
        oConsole.fPrint(ERROR, "- You cannot provide process ids for application keyword ", ERROR_INFO, \
            sApplicationKeyword, ERROR, ".");
        os._exit(2);
      if sUWPApplicationPackageName:
        oConsole.fPrint(ERROR, "- You cannot provide an application UWP package name for application keyword ", \
            ERROR_INFO, sApplicationKeyword, ERROR, ".");
        os._exit(2);
      if sApplicationBinaryPath is None:
        sApplicationBinaryPath = dxApplicationSettings["sBinaryPath"];
        if sApplicationBinaryPath is None:
          oConsole.fPrint(ERROR, "- The main application binary for ", ERROR_INFO, sApplicationKeyword, \
              ERROR, " could not be detected on your system.");
          oConsole.fPrint(ERROR, "  Please provide the path to this binary in the arguments.");
          os._exit(4);
    elif "dxUWPApplication" in dxApplicationSettings:
      dxUWPApplication = dxApplicationSettings["dxUWPApplication"];
      # This application is started as a Universal Windows Platform application.
      if sApplicationBinaryPath:
        oConsole.fPrint(ERROR, "- You cannot provide an application binary for application keyword ", \
            ERROR_INFO, sApplicationKeyword, ERROR, ".");
        os._exit(2);
      if auApplicationProcessIds:
        oConsole.fPrint(ERROR, "- You cannot provide process ids for application keyword ", ERROR_INFO, \
            sApplicationKeyword, ERROR, ".");
        os._exit(2);
      sUWPApplicationPackageName = dxUWPApplication["sPackageName"];
      sUWPApplicationId = dxUWPApplication["sId"];
    elif not auApplicationProcessIds:
      # This application is attached to.
      oConsole.fPrint(ERROR, "- You must provide process ids for application keyword ", \
          ERROR_INFO, sApplicationKeyword, ERROR, ".");
      os._exit(2);
    elif asApplicationOptionalArguments:
      # Cannot provide arguments if we're attaching to processes
      oConsole.fPrint(ERROR, "- You cannot provide arguments for application keyword ", \
          ERROR_INFO, sApplicationKeyword, ERROR, ".");
      os._exit(2);
    if "asApplicationAttachToProcessesForExecutableNames" in dxApplicationSettings:
      gasAttachToProcessesForExecutableNames = dxApplicationSettings["asApplicationAttachToProcessesForExecutableNames"];
    # Get application arguments;
    if "fasGetStaticArguments" in dxApplicationSettings:
      fasGetApplicationStaticArguments = dxApplicationSettings["fasGetStaticArguments"];
      asApplicationStaticArguments = fasGetApplicationStaticArguments(bForHelp = False);
    else:
      asApplicationStaticArguments = [];
    if asApplicationOptionalArguments is None and "fasGetOptionalArguments" in dxApplicationSettings:
      fasGetApplicationOptionalArguments = dxApplicationSettings["fasGetOptionalArguments"];
      asApplicationOptionalArguments = fasGetApplicationOptionalArguments(bForHelp = False);
    asApplicationArguments = asApplicationStaticArguments + asApplicationOptionalArguments;
    # Apply application specific settings
    if dxApplicationSettings.get("dxConfigSettings"):
      dxApplicationConfigSettings = dxApplicationSettings["dxConfigSettings"];
      if gbVerbose:
        oConsole.fPrint("* Applying application specific configuration for %s:" % sApplicationKeyword);
      for (sSettingName, xValue) in dxApplicationConfigSettings.items():
        if sSettingName not in dxUserProvidedConfigSettings:
          fApplyConfigSetting(sSettingName, xValue, [None, "  "][gbVerbose]); # Apply and show result indented.
      if gbVerbose:
        oConsole.fPrint();
    # Apply application specific source settings
    if "dsURLTemplate_by_srSourceFilePath" in dxApplicationSettings:
      dsApplicationURLTemplate_by_srSourceFilePath = dxApplicationSettings["dsURLTemplate_by_srSourceFilePath"];
    # If not ISA is specified, apply the application specific ISA (if any).
    if not sApplicationISA and "sISA" in dxApplicationSettings:
      sApplicationISA = dxApplicationSettings["sISA"];
    if "asBinaryNamesThatAreAllowedToRunWithoutPageHeap" in dxApplicationSettings:
      gasBinaryNamesThatAreAllowedToRunWithoutPageHeap = [
        sBinaryName.lower() for sBinaryName in dxApplicationSettings["asBinaryNamesThatAreAllowedToRunWithoutPageHeap"]
      ];
  elif (auApplicationProcessIds or sUWPApplicationPackageName or sApplicationBinaryPath):
    # There are no static arguments if there is no application keyword, only the user-supplied optional arguments
    # are used if they are supplied:
    asApplicationArguments = asApplicationOptionalArguments or [];
  else:
    oConsole.fLock();
    try:
      oConsole.fPrint(ERROR, "- You must provide something to debug. This can be either one or more process");
      oConsole.fPrint(ERROR, "  ids, an application command-line or an UWP application package name.");
      oConsole.fPrint("Run \"", INFO, "BugId -h", NORMAL, "\" for help on command-line arguments.");
    finally:
      oConsole.fUnlock();
    os._exit(2);
  
  # Apply user provided settings:
  for (sSettingName, xValue) in dxUserProvidedConfigSettings.items():
    fApplyConfigSetting(sSettingName, xValue, [None, ""][gbVerbose]); # Apply and show result
  
  if bRepeat:
    duNumberOfRepros_by_sBugIdAndLocation = {};
    sValidStatisticsFileName = mFileSystem.fsValidName("Reproduction statistics.txt");
  uRunCounter = 0;
  while 1: # Will only loop if bRepeat is True
    nStartTime = time.clock();
    if fCleanup and dxConfig["bCleanup"]:
      oConsole.fStatus("* Cleaning up application state...");
      fCleanup();
    uRunCounter += 1;
    oConsole.fLock();
    try:
      if sApplicationBinaryPath:
        if not gbQuiet:
          asCommandLine = [sApplicationBinaryPath] + asApplicationArguments;
          oConsole.fPrint("* Command line: ", INFO, " ".join(asCommandLine));
        oConsole.fStatus("* The debugger is starting the application...");
      else:
        if auApplicationProcessIds:
          asProcessIdsOutput = [];
          for uApplicationProcessId in auApplicationProcessIds:
            if asProcessIdsOutput: asProcessIdsOutput.append(", ");
            asProcessIdsOutput.extend([INFO, str(uApplicationProcessId), NORMAL]);
          oConsole.fPrint("* Running process ids: ", INFO, *asProcessIdsOutput);
        if sUWPApplicationPackageName:
          if not gbQuiet:
            if asApplicationArguments:
              oConsole.fPrint("* UWP application id: ", INFO, sUWPApplicationId, NORMAL, ", package name: ", INFO, \
                  sUWPApplicationPackageName, NORMAL, ", Arguments: ", INFO, " ".join(asApplicationArguments));
            else:
              oConsole.fPrint("* UWP application id: ", INFO, sUWPApplicationId, NORMAL, ", package name: ", INFO, \
                  sUWPApplicationPackageName);
        if not sUWPApplicationPackageName:
          oConsole.fStatus("* The debugger is attaching to running processes of the application...");
        elif auApplicationProcessIds:
          oConsole.fStatus("* The debugger is attaching to running processes and starting the application...");
        else:
          oConsole.fStatus("* The debugger is starting the application...");
    finally:
      oConsole.fUnlock();
    oBugId = cBugId(
      sCdbISA = sApplicationISA or cBugId.sOSISA,
      sApplicationBinaryPath = sApplicationBinaryPath or None,
      auApplicationProcessIds = auApplicationProcessIds or None,
      sUWPApplicationPackageName = sUWPApplicationPackageName or None,
      sUWPApplicationId = sUWPApplicationId or None,
      asApplicationArguments = asApplicationArguments,
      asLocalSymbolPaths = dxConfig["asLocalSymbolPaths"],
      asSymbolCachePaths = dxConfig["asSymbolCachePaths"], 
      asSymbolServerURLs = dxConfig["asSymbolServerURLs"],
      dsURLTemplate_by_srSourceFilePath = dsApplicationURLTemplate_by_srSourceFilePath,
      bGenerateReportHTML = dxConfig["bGenerateReportHTML"],
      uProcessMaxMemoryUse = dxConfig["uProcessMaxMemoryUse"],
      uTotalMaxMemoryUse = dxConfig["uTotalMaxMemoryUse"],
      uMaximumNumberOfBugs = guMaximumNumberOfBugs,
    );
    oBugId.fAddEventCallback("Failed to debug application", fFailedToDebugApplicationCallback);
    oBugId.fAddEventCallback("Failed to apply application memory limits", fFailedToApplyApplicationMemoryLimitsCallback);
    oBugId.fAddEventCallback("Failed to apply process memory limits", fFailedToApplyProcessMemoryLimitsCallback);
    oBugId.fAddEventCallback("Application running", fApplicationRunningCallback);
    oBugId.fAddEventCallback("Application suspended", fApplicationSuspendedCallback);
    oBugId.fAddEventCallback("Application resumed", fApplicationResumedCallback);
    oBugId.fAddEventCallback("Process terminated", fProcessTerminatedCallback);
    oBugId.fAddEventCallback("Internal exception", fInternalExceptionCallback);
    oBugId.fAddEventCallback("Page heap not enabled", fPageHeapNotEnabledCallback);
    if gbVerbose:
      oBugId.fAddEventCallback("Cdb stdin input", fCdbStdInInputCallback);
      oBugId.fAddEventCallback("Cdb stdout output", fCdbStdOutOutputCallback);
    oBugId.fAddEventCallback("Cdb stderr output", fCdbStdErrOutputCallback);
    oBugId.fAddEventCallback("Started process", fStartedProcessCallback);
    oBugId.fAddEventCallback("Attached to process", fAttachedToProcessCallback);
    oBugId.fAddEventCallback("Application stdout output", fApplicationStdOutOutputCallback);
    oBugId.fAddEventCallback("Application stderr output", fApplicationStdOutOutputCallback);
    oBugId.fAddEventCallback("Bug report", fBugReportCallback);

    if dxConfig["nApplicationMaxRunTime"] is not None:
      oBugId.foSetTimeout("Maximum application runtime", dxConfig["nApplicationMaxRunTime"], \
          fApplicationMaxRunTimeCallback);
    if dxConfig["bExcessiveCPUUsageCheckEnabled"] and dxConfig["nExcessiveCPUUsageCheckInitialTimeout"]:
      oBugId.fSetCheckForExcessiveCPUUsageTimeout(dxConfig["nExcessiveCPUUsageCheckInitialTimeout"]);
    guDetectedBugsCount = 0;
    oBugId.fStart();
    oBugId.fWait();
    if gbAnErrorOccured:
      os._exit(3);
    if guDetectedBugsCount == 0:
      oConsole.fPrint(u"\u2500\u2500 The application terminated without a bug being detected ", sPadding = u"\u2500");
      sBugIdAndLocation = "No crash";
    if gbVerbose:
      oConsole.fPrint("  Application time: %s seconds" % (long(oBugId.fnApplicationRunTime() * 1000) / 1000.0));
      nOverheadTime = time.clock() - nStartTime - oBugId.fnApplicationRunTime();
      oConsole.fPrint("  BugId overhead:   %s seconds" % (long(nOverheadTime * 1000) / 1000.0));
    if not bRepeat:
      os._exit(guDetectedBugsCount > 0 and 1 or 0);
    duNumberOfRepros_by_sBugIdAndLocation.setdefault(sBugIdAndLocation, 0)
    duNumberOfRepros_by_sBugIdAndLocation[sBugIdAndLocation] += 1;
    sStatistics = "";
    auOrderedNumberOfRepros = sorted(list(set(duNumberOfRepros_by_sBugIdAndLocation.values())));
    auOrderedNumberOfRepros.reverse();
    for uNumberOfRepros in auOrderedNumberOfRepros:
      for sBugIdAndLocation in duNumberOfRepros_by_sBugIdAndLocation.keys():
        if duNumberOfRepros_by_sBugIdAndLocation[sBugIdAndLocation] == uNumberOfRepros:
          sStatistics += "%d \xD7 %s (%d%%)\r\n" % (uNumberOfRepros, str(sBugIdAndLocation), \
              round(100.0 * uNumberOfRepros / uRunCounter));
    if dxConfig["sReportFolderPath"] is not None:
      sStatisticsFilePath = mFileSystem.fsPath(dxConfig["sReportFolderPath"], sValidStatisticsFileName);
    else:
      sStatisticsFilePath = mFileSystem.fsPath(sValidStatisticsFileName);
    eWriteDataToFileResult = mFileSystem.feWriteDataToFile(
      sStatistics,
      sStatisticsFilePath,
      fbRetryOnFailure = lambda: False,
    );
    if eWriteDataToFileResult:
      oConsole.fPrint("  Statistics:       ", ERROR, "Cannot be saved (", ERROR_INFO, repr(eWriteDataToFileResult), \
          ERROR, ")");
    else:
      oConsole.fPrint("  Statistics:       ", INFO, sStatisticsFilePath, NORMAL, " (%d bytes)" % len(sStatistics));
    oConsole.fPrint(); # and loop
예제 #11
0
파일: BugId.py 프로젝트: 453483289/BugId
def fuMain(asArguments):
    global gbQuiet, \
           gasAttachToProcessesForBinaryNames
    if len(asArguments) == 0:
        fPrintLogo()
        fPrintUsage(asApplicationKeywords)
        return 0
    # returns an exit code, values are:
    # 0 = executed successfully, no bugs found.
    # 1 = executed successfully, bug detected.
    # 2 = bad arguments
    # 3 = internal error
    # 4 = failed to start process or attach to process(es).
    # Parse all "--" arguments until we encounter a non-"--" argument.
    sApplicationKeyword = None
    sApplicationBinaryPath = None
    auApplicationProcessIds = []
    sApplicationPackageName = None
    sApplicationId = None
    asApplicationOptionalArguments = None
    sApplicationISA = None
    bRepeat = False
    bCheckForUpdates = False
    dxUserProvidedConfigSettings = {}
    bFast = False
    while asArguments:
        sArgument = asArguments.pop(0)
        if sArgument == "--":
            if len(auApplicationProcessIds) > 0:
                # The rest of the arguments are to be passed to the application
                oConsole.fPrint(
                    ERROR,
                    "- You cannot supply process ids and application arguments."
                )
                return 2
            asApplicationOptionalArguments = asArguments
            break
        elif sArgument in ["-q", "/q"]:
            gbQuiet = True
        elif sArgument in ["-f", "/f"]:
            bFast = True
        elif sArgument in ["-r", "/r"]:
            bRepeat = True
        elif sArgument in ["-?", "/?", "-h", "/h"]:
            fPrintLogo()
            fPrintUsage(asApplicationKeywords)
            return 0
        elif sArgument.startswith("--"):
            if "=" in sArgument:
                sSettingName, sValue = sArgument[2:].split("=", 1)
            else:
                # "--bFlag" is an alias for "--bFlag=true"
                sSettingName = sArgument[2:]
                sValue = "true"

            if sSettingName in ["pid", "pids"]:
                if sApplicationBinaryPath is not None:
                    oConsole.fPrint(
                        ERROR,
                        "- You cannot supply an application binary and process ids."
                    )
                    return 2
                if sApplicationPackageName is not None:
                    oConsole.fPrint(
                        ERROR,
                        "- You cannot supply an application package name and process ids."
                    )
                    return 2
                auApplicationProcessIds += [
                    long(x) for x in sValue.split(",")
                ]
            elif sSettingName in ["uwp", "uwp-app"]:
                if sApplicationPackageName is not None:
                    oConsole.fPrint(
                        ERROR,
                        "- You cannot supply two or more application package names."
                    )
                    return 2
                if sApplicationBinaryPath is not None:
                    oConsole.fPrint(
                        ERROR,
                        "- You cannot supply an application binary and package name."
                    )
                    return 2
                if len(auApplicationProcessIds) > 0:
                    oConsole.fPrint(
                        ERROR,
                        "- You cannot supply process ids and an application package name."
                    )
                    return 2
                if "!" not in sValue:
                    oConsole.fPrint(
                        ERROR,
                        "- Please provide a string of the form %s=<package name>!<application id>.",
                        sSettingName)
                    return 2
                sApplicationPackageName, sApplicationId = sValue.split("!", 1)
            elif sSettingName in ["version", "check-for-updates"]:
                return fuVersionCheck()
            elif sSettingName in ["isa", "cpu"]:
                if sValue not in ["x86", "x64"]:
                    oConsole.fPrint(ERROR, "- Unknown ISA %s" % repr(sValue))
                    return 2
                sApplicationISA = sValue
            elif sSettingName in ["quiet", "silent"]:
                gbQuiet = sValue.lower() == "true"
            elif sSettingName in ["fast", "quick"]:
                bFast = True
            elif sSettingName in ["repeat", "forever"]:
                bRepeat = True
            else:
                try:
                    xValue = json.loads(sValue)
                except ValueError:
                    oConsole.fPrint(
                        ERROR,
                        "- Cannot decode argument JSON value %s." % sValue)
                    return 2
                # User provided config settings must be applied after any keyword specific config settings:
                dxUserProvidedConfigSettings[sSettingName] = xValue
        elif sArgument in asApplicationKeywords:
            if sApplicationKeyword is not None:
                oConsole.fPrint(
                    ERROR,
                    "- You cannot supply two or more application keywords.")
                return 2
            sApplicationKeyword = sArgument
        elif sArgument[-1] == "?" and sArgument[:-1] in asApplicationKeywords:
            return fuShowApplicationKeyWordHelp(sArgument[:-1])
        else:
            if sApplicationBinaryPath is not None:
                oConsole.fPrint(
                    ERROR,
                    "- You cannot supply two or more application binaries.")
                return 2
            if len(auApplicationProcessIds) > 0:
                oConsole.fPrint(
                    ERROR,
                    "- You cannot supply process ids and an application binary."
                )
                return 2
            if sApplicationPackageName is not None:
                oConsole.fPrint(
                    ERROR,
                    "- You cannot supply an application package name and a binary."
                )
                return 2
            sApplicationBinaryPath = sArgument

    if bFast:
        gbQuiet = True
        dxUserProvidedConfigSettings["bGenerateReportHTML"] = False
        dxUserProvidedConfigSettings["asSymbolServerURLs"] = []
        dxUserProvidedConfigSettings["cBugId.bUse_NT_SYMBOL_PATH"] = False

    dsURLTemplate_by_srSourceFilePath = {}
    rImportantStdOutLines = None
    rImportantStdErrLines = None

    if sApplicationKeyword:
        # Get application binary/package name/process ids as needed:
        if sApplicationKeyword in gdApplication_sBinaryPath_by_sKeyword:
            # This application is started from the command-line.
            if auApplicationProcessIds:
                oConsole.fPrint(
                    ERROR,
                    "- You cannot specify process ids for application keyword ",
                    INFO, sApplicationKeyword, NORMAL, ".")
                return 2
            if sApplicationPackageName:
                oConsole.fPrint(
                    ERROR,
                    "- You cannot specify an application package name for application keyword ",
                    INFO, sApplicationKeyword, NORMAL, ".")
                return 2
            if sApplicationBinaryPath is None:
                sApplicationBinaryPath = gdApplication_sBinaryPath_by_sKeyword[
                    sApplicationKeyword]
        elif sApplicationKeyword in gsApplicationPackageName_by_sKeyword:
            # This application is started as an application package.
            if sApplicationBinaryPath:
                oConsole.fPrint(
                    ERROR,
                    "- You cannot specify an application binary for application keyword ",
                    INFO, sApplicationKeyword, NORMAL, ".")
                return 2
            sApplicationPackageName = gsApplicationPackageName_by_sKeyword[
                sApplicationKeyword]
            sApplicationId = gsApplicationId_by_sKeyword[sApplicationKeyword]
        elif not auApplicationProcessIds:
            # This application is attached to.
            oConsole.fPrint(
                ERROR,
                "- You must specify process ids for application keyword ",
                INFO, sApplicationKeyword, NORMAL, ".")
            return 2
        elif asApplicationOptionalArguments:
            # Cannot supply arguments if we're attaching to processes
            oConsole.fPrint(
                ERROR,
                "- You cannot specify arguments for application keyword ",
                INFO, sApplicationKeyword, NORMAL, ".")
            return 2
        if sApplicationKeyword in gasApplicationAttachToProcessesForBinaryNames_by_sKeyword:
            gasAttachToProcessesForBinaryNames = gasApplicationAttachToProcessesForBinaryNames_by_sKeyword[
                sApplicationKeyword]
        # Get application arguments;
        asApplicationStaticArguments = gdApplication_asStaticArguments_by_sKeyword.get(
            sApplicationKeyword, [])
        if asApplicationOptionalArguments is None:
            asApplicationOptionalArguments = [
                sArgument is DEFAULT_BROWSER_TEST_URL
                and dxConfig["sDefaultBrowserTestURL"] or sArgument
                for sArgument in
                gdApplication_asDefaultOptionalArguments_by_sKeyword.get(
                    sApplicationKeyword, [])
            ]
        asApplicationArguments = asApplicationStaticArguments + asApplicationOptionalArguments
        # Apply application specific settings
        if sApplicationKeyword in gdApplication_dxSettings_by_sKeyword:
            if not gbQuiet:
                oConsole.fPrint(
                    "* Applying application specific configuration for %s:" %
                    sApplicationKeyword)
            for (sSettingName, xValue) in gdApplication_dxSettings_by_sKeyword[
                    sApplicationKeyword].items():
                if sSettingName not in dxUserProvidedConfigSettings:
                    fApplyConfigSetting(sSettingName, xValue, "  ")
                    # Apply and show result indented.
            if not gbQuiet:
                oConsole.fPrint()
        # Apply application specific source settings
        if sApplicationKeyword in gdApplication_sURLTemplate_by_srSourceFilePath_by_sKeyword:
            dsURLTemplate_by_srSourceFilePath = gdApplication_sURLTemplate_by_srSourceFilePath_by_sKeyword[
                sApplicationKeyword]
        # Apply application specific stdio settings:
        if sApplicationKeyword in gdApplication_rImportantStdOutLines_by_sKeyword:
            rImportantStdOutLines = gdApplication_rImportantStdOutLines_by_sKeyword[
                sApplicationKeyword]
        if sApplicationKeyword in gdApplication_rImportantStdErrLines_by_sKeyword:
            rImportantStdErrLines = gdApplication_rImportantStdErrLines_by_sKeyword[
                sApplicationKeyword]
        if not sApplicationISA and sApplicationKeyword in gdApplication_sISA_by_sKeyword:
            # Apply application specific ISA
            sApplicationISA = gdApplication_sISA_by_sKeyword[
                sApplicationKeyword]
    else:
        # There are no static arguments if there is no application keyword, only the user-supplied optional arguments
        # are used if they are supplied:
        asApplicationArguments = asApplicationOptionalArguments or []

    # Apply user provided settings:
    for (sSettingName, xValue) in dxUserProvidedConfigSettings.items():
        fApplyConfigSetting(sSettingName, xValue, "")
        # Apply and show result

    if bRepeat:
        duNumberOfRepros_by_sBugIdAndLocation = {}
        sValidStatisticsFileName = FileSystem.fsValidName(
            "Reproduction statistics.txt")
    uRunCounter = 0
    while 1:  # Will only loop if bRepeat is True
        nStartTime = time.clock()
        uRunCounter += 1
        if sApplicationBinaryPath:
            if not gbQuiet:
                asCommandLine = [sApplicationBinaryPath
                                 ] + asApplicationArguments
                oConsole.fPrint("* Command line: ", INFO,
                                " ".join(asCommandLine))
                oConsole.fPrint()
            oConsole.fStatus("* The debugger is starting the application...")
        else:
            if auApplicationProcessIds:
                asProcessIdsOutput = []
                for uApplicationProcessId in auApplicationProcessIds:
                    if asProcessIdsOutput: asProcessIdsOutput.append(", ")
                    asProcessIdsOutput.extend(
                        [INFO, str(uApplicationProcessId), NORMAL])
                oConsole.fPrint("* Running process ids: ", INFO,
                                *asProcessIdsOutput)
            if sApplicationPackageName:
                if not gbQuiet:
                    if asApplicationArguments:
                        oConsole.fPrint("* Package name: ", INFO,
                                        sApplicationPackageName, NORMAL,
                                        ", Arguments: ", INFO,
                                        " ".join(asApplicationArguments))
                    else:
                        oConsole.fPrint("* Package name: ", INFO,
                                        sApplicationPackageName)
                    oConsole.fPrint()
            if not sApplicationPackageName:
                oConsole.fStatus(
                    "* The debugger is attaching to running processes of the application..."
                )
            elif auApplicationProcessIds:
                oConsole.fStatus(
                    "* The debugger is attaching to running processes and starting the application..."
                )
            else:
                oConsole.fStatus(
                    "* The debugger is starting the application...")
        oBugId = cBugId(
            sCdbISA=sApplicationISA or cBugId.sOSISA,
            sApplicationBinaryPath=sApplicationBinaryPath or None,
            auApplicationProcessIds=auApplicationProcessIds or None,
            sApplicationPackageName=sApplicationPackageName or None,
            sApplicationId=sApplicationId or None,
            asApplicationArguments=asApplicationArguments,
            asLocalSymbolPaths=dxConfig["asLocalSymbolPaths"],
            asSymbolCachePaths=dxConfig["asSymbolCachePaths"],
            asSymbolServerURLs=dxConfig["asSymbolServerURLs"],
            dsURLTemplate_by_srSourceFilePath=dsURLTemplate_by_srSourceFilePath,
            rImportantStdOutLines=rImportantStdOutLines,
            rImportantStdErrLines=rImportantStdErrLines,
            bGenerateReportHTML=dxConfig["bGenerateReportHTML"],
            fFailedToDebugApplicationCallback=fFailedToDebugApplicationHandler,
            fApplicationRunningCallback=fApplicationRunningHandler,
            fApplicationSuspendedCallback=fApplicationSuspendedHandler,
            fApplicationResumedCallback=fApplicationResumedHandler,
            fMainProcessTerminatedCallback=fMainProcessTerminatedHandler,
            fInternalExceptionCallback=fInternalExceptionHandler,
            fFinishedCallback=None,
            fPageHeapNotEnabledCallback=fPageHeapNotEnabledHandler,
            fStdErrOutputCallback=fStdErrOutputHandler,
            fNewProcessCallback=fNewProcessHandler,
        )
        if dxConfig["nApplicationMaxRunTime"] is not None:
            oBugId.fxSetTimeout(dxConfig["nApplicationMaxRunTime"],
                                fApplicationRunTimeoutHandler, oBugId)
        if dxConfig["bExcessiveCPUUsageCheckEnabled"] and dxConfig[
                "nExcessiveCPUUsageCheckInitialTimeout"]:
            oBugId.fSetCheckForExcessiveCPUUsageTimeout(
                dxConfig["nExcessiveCPUUsageCheckInitialTimeout"])
        oBugId.fStart()
        oBugId.fWait()
        if gbAnErrorOccured:
            return 3
        if oBugId.oBugReport is not None:
            oConsole.fPrint(HILITE, "A bug was detect in the application:")
            oConsole.fPrint("  Id @ Location:    ", INFO,
                            oBugId.oBugReport.sId, NORMAL, " @ ", INFO,
                            oBugId.oBugReport.sBugLocation)
            if oBugId.oBugReport.sBugSourceLocation:
                oConsole.fPrint("  Source:           ", INFO,
                                oBugId.oBugReport.sBugSourceLocation)
            oConsole.fPrint("  Description:      ", INFO,
                            oBugId.oBugReport.sBugDescription)
            oConsole.fPrint("  Security impact:  ", INFO,
                            oBugId.oBugReport.sSecurityImpact)
            oConsole.fPrint("  Version:          ", HILITE,
                            oBugId.oBugReport.asVersionInformation[0])
            # There is always the process' binary.
            for sVersionInformation in oBugId.oBugReport.asVersionInformation[
                    1:]:  # There may be two if the crash was in a
                oConsole.fPrint("                    ", sVersionInformation)
                # different binary (e.g. a .dll)
            sBugIdAndLocation = "%s @ %s" % (oBugId.oBugReport.sId,
                                             oBugId.oBugReport.sBugLocation)
            if dxConfig["bGenerateReportHTML"]:
                # We'd like a report file name base on the BugId, but the later may contain characters that are not valid in a file name
                sDesiredReportFileName = "%s.html" % sBugIdAndLocation
                # Thus, we need to translate these characters to create a valid filename that looks very similar to the BugId
                sValidReportFileName = FileSystem.fsValidName(
                    sDesiredReportFileName,
                    bUnicode=dxConfig["bUseUnicodeReportFileNames"])
                if dxConfig["sReportFolderPath"] is not None:
                    sReportFilePath = FileSystem.fsPath(
                        dxConfig["sReportFolderPath"], sValidReportFileName)
                else:
                    sReportFilePath = FileSystem.fsPath(sValidReportFileName)
                eWriteDataToFileResult = FileSystem.feWriteDataToFile(
                    oBugId.oBugReport.sReportHTML,
                    sReportFilePath,
                    fbRetryOnFailure=lambda: False,
                )
                if eWriteDataToFileResult:
                    oConsole.fPrint(
                        "  Bug report:       ", ERROR,
                        "Cannot be saved (%s)" % repr(eWriteDataToFileResult))
                else:
                    oConsole.fPrint(
                        "  Bug report:       ", HILITE, sValidReportFileName,
                        NORMAL,
                        " (%d bytes)" % len(oBugId.oBugReport.sReportHTML))
        else:
            oConsole.fPrint(
                10, "The application terminated without a bug being detected.")
            sBugIdAndLocation = "No crash"
        oConsole.fPrint("  Application time: %s seconds" %
                        (long(oBugId.fnApplicationRunTime() * 1000) / 1000.0))
        nOverheadTime = time.clock(
        ) - nStartTime - oBugId.fnApplicationRunTime()
        oConsole.fPrint("  BugId overhead:   %s seconds" %
                        (long(nOverheadTime * 1000) / 1000.0))
        if not bRepeat: return oBugId.oBugReport is not None and 1 or 0
        duNumberOfRepros_by_sBugIdAndLocation.setdefault(sBugIdAndLocation, 0)
        duNumberOfRepros_by_sBugIdAndLocation[sBugIdAndLocation] += 1
        sStatistics = ""
        auOrderedNumberOfRepros = sorted(
            list(set(duNumberOfRepros_by_sBugIdAndLocation.values())))
        auOrderedNumberOfRepros.reverse()
        for uNumberOfRepros in auOrderedNumberOfRepros:
            for sBugIdAndLocation in duNumberOfRepros_by_sBugIdAndLocation.keys(
            ):
                if duNumberOfRepros_by_sBugIdAndLocation[
                        sBugIdAndLocation] == uNumberOfRepros:
                    sStatistics += "%d \xD7 %s (%d%%)\r\n" % (
                        uNumberOfRepros, sBugIdAndLocation,
                        round(100.0 * uNumberOfRepros / uRunCounter))
        if dxConfig["sReportFolderPath"] is not None:
            sStatisticsFilePath = FileSystem.fsPath(
                dxConfig["sReportFolderPath"], sValidStatisticsFileName)
        else:
            sStatisticsFilePath = FileSystem.fsPath(sValidStatisticsFileName)
        eWriteDataToFileResult = FileSystem.feWriteDataToFile(
            sStatistics,
            sStatisticsFilePath,
            fbRetryOnFailure=lambda: False,
        )
        if eWriteDataToFileResult:
            oConsole.fPrint(
                "  Statistics:       ", ERROR,
                "Cannot be saved (%s)" % repr(eWriteDataToFileResult))
        else:
            oConsole.fPrint("  Statistics:       ", INFO, sStatisticsFilePath,
                            NORMAL, " (%d bytes)" % len(sStatistics))
        oConsole.fPrint()
예제 #12
0
def fTest(
    sISA,
    axCommandLineArguments,
    asExpectedBugIdAndLocations,
    sExpectedFailedToDebugApplicationErrorMessage=None,
    bRunInShell=False,
    sApplicationBinaryPath=None,
    uMaximumNumberOfBugs=2,
):
    global gbTestFailed
    if gbTestFailed:
        return
    asApplicationArguments = axCommandLineArguments and [
        isinstance(x, str) and x or x < 10 and ("%d" % x) or ("0x%X" % x)
        for x in axCommandLineArguments
    ] or []
    if sApplicationBinaryPath is None:
        sApplicationBinaryPath = dsBinaries_by_sISA[sISA]
    asCommandLine = [sApplicationBinaryPath] + asApplicationArguments
    sFailedToDebugApplicationErrorMessage = None
    if sExpectedFailedToDebugApplicationErrorMessage:
        sTestDescription = "%s => %s" % (
            "Running %s" % sApplicationBinaryPath,
            repr(sExpectedFailedToDebugApplicationErrorMessage))
    else:
        sTestDescription = "%s %s%s => %s" % (
          sISA,
          " ".join(asApplicationArguments), \
          bRunInShell and " (in child process)" or "",
          " => ".join(asExpectedBugIdAndLocations) or "no bugs")

    sTestBinaryName = os.path.basename(sApplicationBinaryPath).lower()

    if bRunInShell:
        asApplicationArguments = ["/C", sApplicationBinaryPath
                                  ] + asApplicationArguments
        sApplicationBinaryPath = dsComSpec_by_sISA[sISA]

    fSetTitle(sTestDescription)
    if bDebugStartFinish:
        fOutput("* Started %s" % sTestDescription)
    else:
        fOutput("* %s" % sTestDescription, bCRLF=False)

    asLog = []

    def fStdInInputHandler(oBugId, sInput):
        if gbDebugIO: fOutput("stdin<%s" % sInput)
        asLog.append("stdin<%s" % sInput)

    def fStdOutOutputHandler(oBugId, sOutput):
        if gbDebugIO: fOutput("stdout>%s" % sOutput)
        asLog.append("stdout>%s" % sOutput)

    def fStdErrOutputHandler(oBugId, sOutput):
        if gbDebugIO: fOutput("stderr>%s" % sOutput)
        asLog.append("stderr>%s" % sOutput)

    def fLogMessageHandler(oBugId, sMessageClass, sMessage):
        if gbDebugIO: fOutput("log>%s: %s" % (sMessageClass, sMessage))
        asLog.append("log>%s: %s" % (sMessageClass, sMessage))

    def fApplicationStdOutOutputHandler(oBugId, uProcessId, sBinaryName,
                                        sCommandLine, sMessage):
        if gbDebugIO:
            fOutput("process %d/0x%X (%s): stdout> %s" %
                    (uProcessId, uProcessId, sBinaryName, sMessage))
        asLog.append("process %d/0x%X (%s): stdout> %s" %
                     (uProcessId, uProcessId, sBinaryName, sMessage))

    def fApplicationStdErrOutputHandler(oBugId, uProcessId, sBinaryName,
                                        sCommandLine, sMessage):
        if gbDebugIO:
            fOutput("process %d/0x%X (%s): stderr> %s" %
                    (uProcessId, uProcessId, sBinaryName, sMessage))
        asLog.append("process %d/0x%X (%s): stderr> %s" %
                     (uProcessId, uProcessId, sBinaryName, sMessage))

    def fFailedToDebugApplicationHandler(oBugId, sErrorMessage):
        global gbTestFailed
        if sExpectedFailedToDebugApplicationErrorMessage == sErrorMessage:
            return
        gbTestFailed = True
        if not gbDebugIO:
            for sLine in asLog:
                fOutput(sLine)
        fOutput("- Failed test: %s" % sTestDescription)
        if sExpectedFailedToDebugApplicationErrorMessage:
            fOutput("  Expected:    %s" %
                    repr(sExpectedFailedToDebugApplicationErrorMessage))
        else:
            fOutput("  BugId unexpectedly failed to debug the application")
        fOutput("  Error:       %s" % repr(sErrorMessage))
        oBugId.fStop()

    def fInternalExceptionHandler(oBugId, oException, oTraceBack):
        global gbTestFailed
        gbTestFailed = True
        if not gbDebugIO:
            for sLine in asLog:
                fOutput(sLine)
        fOutput("@" * 80)
        fOutput("- An internal exception has occured in test: %s" %
                sTestDescription)
        fOutput("  %s" % repr(oException))
        fOutput("  Stack:")
        txStack = traceback.extract_tb(oTraceBack)
        uFrameIndex = len(txStack) - 1
        for (sFileName, uLineNumber, sFunctionName,
             sCode) in reversed(txStack):
            sSource = "%s/%d" % (sFileName, uLineNumber)
            if sFunctionName != "<module>":
                sSource = "%s (%s)" % (sFunctionName, sSource)
            fOutput("  %3d %s" % (uFrameIndex, sSource))
            if sCode:
                fOutput("      > %s" % sCode.strip())
            uFrameIndex -= 1
        fOutput("@" * 80)
        oBugId.fStop()

    def fPageHeapNotEnabledHandler(oBugId, uProcessId, sBinaryName,
                                   sCommandLine, bIsMainProcess, bPreventable):
        assert sBinaryName == "cmd.exe", \
            "It appears you have not enabled page heap for %s, which is required to run tests." % sBinaryName

    def fFailedToApplyMemoryLimitsHandler(oBugId, uProcessId, sBinaryName,
                                          sCommandLine):
        global gbTestFailed
        gbTestFailed = True
        if not gbDebugIO:
            for sLine in asLog:
                fOutput(sLine)
        fOutput("- Failed to apply memory limits to process %d/0x%X (%s: %s) for test: %s" % \
            (uProcessId, uProcessId, sBinaryName, sCommandLine, sTestDescription))
        oBugId.fStop()

    aoBugReports = []

    def fBugReportHandler(oBugId, oBugReport):
        aoBugReports.append(oBugReport)

    try:
        oBugId = cBugId(
            sCdbISA=sISA,
            sApplicationBinaryPath=sApplicationBinaryPath,
            asApplicationArguments=asApplicationArguments,
            asSymbolServerURLs=["http://msdl.microsoft.com/download/symbols"
                                ],  # Will be ignore if symbols are disabled.
            bGenerateReportHTML=gbGenerateReportHTML,
            uTotalMaxMemoryUse=guTotalMaxMemoryUse,
            uMaximumNumberOfBugs=uMaximumNumberOfBugs,
        )
        oBugId.fAddEventCallback("Internal exception",
                                 fInternalExceptionHandler)
        oBugId.fAddEventCallback("Failed to debug application",
                                 fFailedToDebugApplicationHandler)
        oBugId.fAddEventCallback("Failed to apply application memory limits",
                                 fFailedToApplyMemoryLimitsHandler)
        oBugId.fAddEventCallback("Failed to apply process memory limits",
                                 fFailedToApplyMemoryLimitsHandler)
        oBugId.fAddEventCallback("Page heap not enabled",
                                 fPageHeapNotEnabledHandler)
        oBugId.fAddEventCallback("Cdb stdin input", fStdInInputHandler)
        oBugId.fAddEventCallback("Cdb stdout output", fStdOutOutputHandler)
        oBugId.fAddEventCallback("Cdb stderr output", fStdErrOutputHandler)
        oBugId.fAddEventCallback("Bug report", fBugReportHandler)
        oBugId.fAddEventCallback("Log message", fLogMessageHandler)
        oBugId.fAddEventCallback("Application stdout output",
                                 fApplicationStdOutOutputHandler)
        oBugId.fAddEventCallback("Application stderr output",
                                 fApplicationStdErrOutputHandler)
        oBugId.fStart()
        oBugId.fSetCheckForExcessiveCPUUsageTimeout(1)
        oBugId.fWait()
        if gbTestFailed:
            return
        if sExpectedFailedToDebugApplicationErrorMessage:
            pass
        elif len(aoBugReports) != len(asExpectedBugIdAndLocations):
            gbTestFailed = True
            if not gbDebugIO:
                for sLine in asLog:
                    fOutput(sLine)
            fOutput("- Failed test: %s" % sTestDescription)
            fOutput(
                "  Test reported %d instead of %d bugs in the application." %
                (len(aoBugReports), len(asExpectedBugIdAndLocations)))
            uCounter = 1
            for sExpectedBugIdAndLocation in asExpectedBugIdAndLocations:
                uCounter += 1
                fOutput("           #%d: %s" %
                        (uCounter, sExpectedBugIdAndLocation))

            uCounter = 0
            for oBugReport in aoBugReports:
                uCounter += 1
                fOutput("  Bug #%d:      %s @ %s" %
                        (uCounter, oBugReport.sId, oBugReport.sBugLocation))
                fOutput("               %s" % (oBugReport.sBugDescription))
        elif asExpectedBugIdAndLocations:
            uCounter = 0
            for oBugReport in aoBugReports:
                sExpectedBugIdAndLocation = asExpectedBugIdAndLocations[
                    uCounter]
                uCounter += 1
                sBugIdAndLocation = "%s @ %s" % (oBugReport.sId,
                                                 oBugReport.sBugLocation)
                if sExpectedBugIdAndLocation[
                        0] == "*":  # string contains a regular expression
                    # Remove "*" and insert (escaped) test binary name in location
                    sExpectedBugIdAndLocation = "^(%s)$" % sExpectedBugIdAndLocation[
                        1:].replace("<test-binary>",
                                    re.escape(sTestBinaryName))
                    bSuccess = re.match(sExpectedBugIdAndLocation,
                                        sBugIdAndLocation)
                else:
                    sExpectedBugIdAndLocation = sExpectedBugIdAndLocation.replace(
                        "<test-binary>", sTestBinaryName)
                    bSuccess = sBugIdAndLocation == sExpectedBugIdAndLocation
                if not bSuccess:
                    gbTestFailed = True
                    if not gbDebugIO:
                        for sLine in asLog:
                            fOutput(sLine)
                    fOutput("- Failed test: %s" % sTestDescription)
                    fOutput("  Test bug #%d does not match %s." %
                            (uCounter, sExpectedBugIdAndLocation))
                    uCounter = 1
                    fOutput("  Expected #%d: %s" %
                            (uCounter, asExpectedBugIdAndLocations[0]))
                    for sExpectedBugIdAndLocation in asExpectedBugIdAndLocations[
                            1:]:
                        uCounter += 1
                        fOutput("           #%d: %s" %
                                (uCounter, sExpectedBugIdAndLocation))

                    uCounter = 0
                    for oBugReport in aoBugReports:
                        uCounter += 1
                        fOutput("  Bug #%d:      %s @ %s" %
                                (uCounter, oBugReport.sId,
                                 oBugReport.sBugLocation))
                        fOutput("               %s" %
                                (oBugReport.sBugDescription))
                    break
        if gbGenerateReportHTML:
            for oBugReport in aoBugReports:
                # We'd like a report file name base on the BugId, but the later may contain characters that are not valid in a file name
                sDesiredReportFileName = "%s %s @ %s.html" % (
                    sPythonISA, oBugReport.sId, oBugReport.sBugLocation)
                # Thus, we need to translate these characters to create a valid filename that looks very similar to the BugId
                sValidReportFileName = mFileSystem.fsValidName(
                    sDesiredReportFileName, bUnicode=False)
                mFileSystem.fWriteDataToFile(
                    oBugReport.sReportHTML,
                    sReportsFolderName,
                    sValidReportFileName,
                    fbRetryOnFailure=lambda: False,
                )
                fOutput("  Wrote report: %s" % sDesiredReportFileName)
        if gbDebugIO:
            fOutput()
            fOutput("=" * 80)
            fOutput()
    except Exception, oException:
        fOutput("- Failed test: %s" % sTestDescription)
        fOutput("  Exception:   %s" % repr(oException))
        raise
예제 #13
0
파일: BugId.py 프로젝트: SkyLined/BugId
def fuMain(asArguments):
  nStartTime = time.clock();
  # returns an exit code, values are:
  # 0 = executed successfully, no bugs found.
  # 1 = executed successfully, bug detected.
  # 2 = bad arguments
  # 3 = internal error
  # 4 = failed to start process or attach to process(es).
  # Parse all "--" arguments until we encounter a non-"--" argument.
  auApplicationProcessIds = [];
  sApplicationISA = None;
  bForever = False;
  dxUserProvidedConfigSettings = {};
  while asArguments and asArguments[0].startswith("--"):
    sArgument = asArguments.pop(0);
    if "=" in sArgument:
      sSettingName, sValue = sArgument[2:].split("=", 1);
    else:
      # "--bFlag" is an alias for "--bFlag=true"
      sSettingName = sArgument[2:];
      sValue = True;
    if sSettingName in ["pid", "pids"]:
      auApplicationProcessIds += [long(x) for x in sValue.split(",")];
    elif sSettingName == "isa":
      if sValue not in ["x86", "x64"]:
        print "- Unknown ISA %s" % repr(sValue);
        return 2;
      sApplicationISA = sValue;
    elif sSettingName == "fast":
      # Alias for these three settings:
      dxUserProvidedConfigSettings["bGenerateReportHTML"] = False;
      dxUserProvidedConfigSettings["asSymbolServerURLs"] = [];
      dxUserProvidedConfigSettings["cBugId.bUse_NT_SYMBOL_PATH"] = False;
    elif sSettingName == "forever":
      bForever = True;
    else:
      try:
        xValue = json.loads(sValue);
      except ValueError:
        print "- Cannot decode argument JSON value %s" % sValue;
        return 2;
      # User provided config settings must be applied after any keyword specific config settings:
      dxUserProvidedConfigSettings[sSettingName] = xValue;
  dsURLTemplate_by_srSourceFilePath = {};
  rImportantStdOutLines = None;
  rImportantStdErrLines = None;
  # If there are any additional arguments, it must be an application keyword followed by additional arguments
  # or an application command-line:
  if not asArguments:
    # No keyword or command line: process ids to attach to must be provided
    asApplicationCommandLine = None;
    if not auApplicationProcessIds:
      print "You must specify an application command-line, keyword or process ids";
      return 2;
  else:
    # First argument may be an application keyword
    sApplicationKeyword = None;
    sApplicationBinary = None;
    if "=" in asArguments[0]:
      # user provided an application keyword and binary
      sApplicationKeyword, sApplicationBinary = asArguments.pop(0).split("=", 1);
    elif asArguments[0] in asApplicationKeywords or asArguments[0][-1] == "?":
      # user provided an application keyword, or requested information on something that may be one:
      sApplicationKeyword = asArguments.pop(0);
    asApplicationCommandLine = None;
    if sApplicationKeyword:
      if sApplicationKeyword[-1] == "?":
        # User requested information about a possible keyword application
        return fuShowApplicationKeyWordHelp(sApplicationKeyword[:-1]);
      # Get application command line for keyword, if available:
      if sApplicationKeyword in gdApplication_asCommandLine_by_sKeyword:
        if auApplicationProcessIds:
          print "You cannot specify process ids for application %s" % sApplicationKeyword;
          return 2;
        asApplicationCommandLine = gdApplication_asCommandLine_by_sKeyword[sApplicationKeyword];
        if sApplicationBinary:
          # Replace binary with user provided value
          asApplicationCommandLine = [sApplicationBinary] + asApplicationCommandLine[1:];
        else:
          if asApplicationCommandLine[0] is None:
            print "Application %s does not appear to be installed";
            return 2;
        if asArguments:
          # Add user provided additional application arguments:
          asApplicationCommandLine += asArguments;
        elif sApplicationKeyword in gdApplication_asDefaultAdditionalArguments_by_sKeyword:
          # Add default additional application arguments:
          asApplicationCommandLine += [
            sArgument is DEFAULT_BROWSER_TEST_URL and dxConfig["sDefaultBrowserTestURL"] or sArgument
            for sArgument in gdApplication_asDefaultAdditionalArguments_by_sKeyword[sApplicationKeyword]
          ];
      
      elif asArguments:
        print "You cannot specify arguments for application keyword %s" % sApplicationKeyword;
        return 2;
      elif not auApplicationProcessIds:
        print "You must specify process ids for application keyword %s" % sApplicationKeyword;
        return 2;
      # Apply application specific settings
      if sApplicationKeyword in gdApplication_dxSettings_by_sKeyword:
        print "* Applying application specific settings:";
        for (sSettingName, xValue) in gdApplication_dxSettings_by_sKeyword[sApplicationKeyword].items():
          if sSettingName not in dxUserProvidedConfigSettings:
            fApplyConfigSetting(sSettingName, xValue, "  "); # Apply and show result indented.
      # Apply application specific source settings
      if sApplicationKeyword in gdApplication_sURLTemplate_by_srSourceFilePath_by_sKeyword:
        dsURLTemplate_by_srSourceFilePath = gdApplication_sURLTemplate_by_srSourceFilePath_by_sKeyword[sApplicationKeyword];
      # Apply application specific stdio settings:
      if sApplicationKeyword in gdApplication_rImportantStdOutLines_by_sKeyword:
        rImportantStdOutLines = gdApplication_rImportantStdOutLines_by_sKeyword[sApplicationKeyword];
      if sApplicationKeyword in gdApplication_rImportantStdErrLines_by_sKeyword:
        rImportantStdErrLines = gdApplication_rImportantStdErrLines_by_sKeyword[sApplicationKeyword];
      if not sApplicationISA and sApplicationKeyword in gdApplication_sISA_by_sKeyword:
        # Apply application specific ISA
        sApplicationISA = gdApplication_sISA_by_sKeyword[sApplicationKeyword];
    elif auApplicationProcessIds:
      # user provided an application command-line and process ids
      print "You cannot specify both an application command-line and process ids";
      return 2;
    else:
      # user provided an application command-line
      asApplicationCommandLine = asArguments;
  
  # Apply user provided settings:
  for (sSettingName, xValue) in dxUserProvidedConfigSettings.items():
    fApplyConfigSetting(sSettingName, xValue); # Apply and show result
  
  while 1: # Will only loop if bForever is True
    if asApplicationCommandLine:
      print "+ The debugger is starting the application...";
      print "  Command line: %s" % " ".join(asApplicationCommandLine);
    else:
      print "+ The debugger is attaching to the application...";
    oBugId = cBugId(
      sCdbISA = sApplicationISA or cBugId.sOSISA,
      asApplicationCommandLine = asApplicationCommandLine or None,
      auApplicationProcessIds = auApplicationProcessIds or None,
      asLocalSymbolPaths = dxConfig["asLocalSymbolPaths"],
      asSymbolCachePaths = dxConfig["asSymbolCachePaths"], 
      asSymbolServerURLs = dxConfig["asSymbolServerURLs"],
      dsURLTemplate_by_srSourceFilePath = dsURLTemplate_by_srSourceFilePath,
      rImportantStdOutLines = rImportantStdOutLines,
      rImportantStdErrLines = rImportantStdErrLines,
      bGenerateReportHTML = dxConfig["bGenerateReportHTML"],
      fApplicationRunningCallback = fApplicationRunningHandler,
      fApplicationSuspendedCallback = fApplicationSuspendedHandler,
      fApplicationResumedCallback = fApplicationResumedHandler,
      fMainProcessTerminatedCallback = fMainProcessTerminatedHandler,
    );
    if dxConfig["nApplicationMaxRunTime"] is not None:
      oBugId.fxSetTimeout(dxConfig["nApplicationMaxRunTime"], fApplicationRunTimeoutHandler, oBugId);
    if dxConfig["nExcessiveCPUUsageCheckInitialTimeout"]:
      oBugId.fSetCheckForExcessiveCPUUsageTimeout(dxConfig["nExcessiveCPUUsageCheckInitialTimeout"]);
    oBugId.fStart();
    oBugId.fWait();
    if oBugId.oInternalException:
      print "-" * 80;
      print "- An error has occured in cBugId, which cannot be handled:";
      print "  %s" % repr(oBugId.oInternalException);
      print "  BugId version %s, cBugId version %s" % (sVersion, cBugId.sVersion);
      print "-" * 80;
      print;
      print "  Please report this issue at the below web-page so it can be addressed:";
      print "      https://github.com/SkyLined/BugId/issues/new";
      print "  If you do not have a github account, or you want to report this issue";
      print "  privately, you can also send an email to:";
      print "      [email protected]";
      print;
      print "  In your report, please copy all the information about the error reported";
      print "  above, as well as the version information. This makes it easier to determine";
      print "  the cause of this issue. I will try to address the issues as soon as";
      print "  possible. Thank you in advance for helping to improve BugId!";
      return 3;
    if oBugId.sFailedToDebugApplicationErrorMessage is not None:
      print "-" * 80;
      print "- Failed to debug the application:"
      for sLine in oBugId.sFailedToDebugApplicationErrorMessage.split("\n"):
        print "  %s" % sLine.rstrip("\r");
      print "-" * 80;
      return 4;
    if oBugId.oBugReport is not None:
      print;
      print "  === BugId report (https://github.com/SkyLined/BugId) ".ljust(80, "=");
      print "  Id:               %s" % oBugId.oBugReport.sId;
      print "  Location:         %s" % oBugId.oBugReport.sBugLocation;
      print "  Description:      %s" % oBugId.oBugReport.sBugDescription;
      print "  Version:          %s" % oBugId.oBugReport.asVersionInformation[0]; # There is always the process' binary.
      for sVersionInformation in oBugId.oBugReport.asVersionInformation[1:]: # There may be two if the crash was in a
        print "                    %s" % sVersionInformation;                # different binary (e.g. a .dll)
      if oBugId.oBugReport.sBugSourceLocation:
        print "  Source:           %s" % oBugId.oBugReport.sBugSourceLocation;
      print "  Security impact:  %s" % oBugId.oBugReport.sSecurityImpact;
      print "  Application time: %s seconds" % (long(oBugId.fnApplicationRunTime() * 1000) / 1000.0);
      nOverheadTime = time.clock() - nStartTime - oBugId.fnApplicationRunTime();
      print "  BugId overhead:   %s seconds" % (long(nOverheadTime * 1000) / 1000.0);
      if dxConfig["bGenerateReportHTML"]:
        # We'd like a report file name base on the BugId, but the later may contain characters that are not valid in a file name
        sDesiredReportFileName = "%s @ %s.html" % (oBugId.oBugReport.sId, oBugId.oBugReport.sBugLocation);
        # Thus, we need to translate these characters to create a valid filename that looks very similar to the BugId
        sValidReportFileName = FileSystem.fsValidName(sDesiredReportFileName, bUnicode = dxConfig["bUseUnicodeReportFileNames"]);
        if dxConfig["sReportFolderPath"] is not None:
          sReportFilePath = FileSystem.fsPath(dxConfig["sReportFolderPath"], sValidReportFileName);
        else:
          sReportFilePath = FileSystem.fsPath(sValidReportFileName);
        eWriteDataToFileResult = FileSystem.feWriteDataToFile(
          oBugId.oBugReport.sReportHTML,
          sReportFilePath,
          fbRetryOnFailure = lambda: False,
        );
        if eWriteDataToFileResult:
          print "  Bug report:       Cannot be saved (%s)" % repr(eWriteDataToFileResult);
        else:
          print "  Bug report:       %s (%d bytes)" % (sValidReportFileName, len(oBugId.oBugReport.sReportHTML));
      if not bForever: return 1;
    else:
      print;
      print "  === BugId report (https://github.com/SkyLined/BugId) ".ljust(80, "=");
      print "  Id:               None";
      print "  Description:      The application terminated before a bug was detected.";
      print "  Application time: %s seconds" % (long(oBugId.fnApplicationRunTime() * 1000) / 1000.0);
      nOverheadTime = time.clock() - nStartTime - oBugId.fnApplicationRunTime();
      print "  BugId overhead:   %s seconds" % (long(nOverheadTime * 1000) / 1000.0);
      if not bForever: return 0;
    print; # and loop
예제 #14
0
파일: BugId.py 프로젝트: zhuyue1314/BugId
            # Running after being resumed.
            print "* The application was resumed successfully and is running..."

    def fExceptionDetectedHandler(uCode, sDescription):
        print "* Exception code 0x%X (%s) was detected and is being analyzed..." % (
            uCode, sDescription)

    if asApplicationCommandLine:
        print "* The debugger is starting the application..."
        print "  Command line: %s" % " ".join(asApplicationCommandLine)
    else:
        print "* The debugger is attaching to the application..."
    oBugId = cBugId(
        asApplicationCommandLine=asApplicationCommandLine,
        auApplicationProcessIds=auApplicationProcessIds,
        asSymbolServerURLs=[],
        fApplicationRunningCallback=fApplicationRunningHandler,
        fExceptionDetectedCallback=fExceptionDetectedHandler,
    )
    oBugId.fWait()
    if oBugId.oErrorReport:
        print "* A bug was detected in the application."
        print
        print "  Id:               %s" % oBugId.oErrorReport.sId
        print "  Description:      %s" % oBugId.oErrorReport.sErrorDescription
        print "  Process binary:   %s" % oBugId.oErrorReport.sProcessBinaryName
        print "  Code:             %s" % oBugId.oErrorReport.sCodeDescription
        print "  Security impact:  %s" % oBugId.oErrorReport.sSecurityImpact
        if dxConfig["bSaveReport"]:
            sFileNameBase = fsCreateFileName(oBugId.oErrorReport.sId)
            # File name may be too long, keep trying to
예제 #15
0
def fMain(asArguments):
  global \
      gasAttachForProcessExecutableNames, \
      gasBinaryNamesThatAreAllowedToRunWithoutPageHeap, \
      gbQuiet, \
      gbVerbose, \
      guDetectedBugsCount, \
      guMaximumNumberOfBugs;
  
  # Make sure Windows and the Python binary are up to date; we don't want our users to unknowingly run outdated
  # software as this is likely to cause unexpected issues.
  fCheckPythonVersion("BugId", asTestedPythonVersions, "https://github.com/SkyLined/BugId/issues/new")
  if mWindowsAPI.oSystemInfo.sOSVersion != "10.0":
    oConsole.fPrint(ERROR, "Error: unfortunately BugId only runs on Windows 10 at this time.");
    os._exit(3);
  if mWindowsAPI.oSystemInfo.sOSISA == "x64" and mWindowsAPI.fsGetPythonISA() == "x86":
    oConsole.fLock();
    try:
      oConsole.fPrint(WARNING, u"\u250C\u2500", WARNING_INFO, " Warning ", WARNING, sPadding = u"\u2500");
      oConsole.fPrint(WARNING, u"\u2502 You are running a ", WARNING_INFO, "32-bit", WARNING, " version of Python on a ",
          WARNING_INFO, "64-bit", WARNING, " version of Windows.");
      oConsole.fPrint(WARNING, u"\u2502 BugId will not be able to debug 64-bit applications unless you run it in a 64-bit " +
          "version of Python.");
      oConsole.fPrint(WARNING, u"\u2502 If you experience any issues, use a 64-bit version of Python and try again.");
      oConsole.fPrint(WARNING, u"\u2514", sPadding = u"\u2500");
    finally:
      oConsole.fUnlock();
  
  # Show usage information if no arguments are provided:
  if len(asArguments) == 0:
    fPrintLogo();
    fPrintUsageInformation(ddxApplicationSettings_by_sKeyword.keys());
    oConsole.fCleanup();
    os._exit(0);
  
  # Parse all arguments until we encounter "--".
  sApplicationKeyword = None;
  sApplicationBinaryPath = None;
  auApplicationProcessIds = [];
  sUWPApplicationPackageName = None;
  sUWPApplicationId = None;
  asApplicationOptionalArguments = None;
  sApplicationISA = None;
  bRepeat = False;
  uNumberOfRepeats = None;
  bCheckForUpdates = False;
  dxUserProvidedConfigSettings = {};
  asAdditionalLocalSymbolPaths = [];
  bFast = False;
  while asArguments:
    sArgument = asArguments.pop(0);
    if sArgument == "--":
      if len(auApplicationProcessIds) > 0:
      # The rest of the arguments are to be passed to the application
        oConsole.fPrint(ERROR, "- You cannot provide process ids and application arguments.");
        oConsole.fCleanup();
        os._exit(2);
      asApplicationOptionalArguments = asArguments;
      break;
    elif sArgument in ["-q", "/q"]:
      gbQuiet = True;
    elif sArgument in ["-v", "/v"]:
      gbVerbose = True;
    elif sArgument in ["-f", "/f"]:
      bFast = True;
    elif sArgument in ["-r", "/r"]:
      bRepeat = True;
    elif sArgument in ["-c", "/c"]:
      guMaximumNumberOfBugs = guDefaultCollateralMaximumNumberOfBugs;
    elif sArgument in ["-?", "/?", "-h", "/h"]:
      fPrintLogo();
      fPrintUsageInformation(ddxApplicationSettings_by_sKeyword.keys());
      oConsole.fCleanup();
      os._exit(0);
    elif sArgument.startswith("--"):
      if "=" in sArgument:
        sSettingName, sValue = sArgument[2:].split("=", 1);
      else:
        # "--bFlag" is an alias for "--bFlag=true"
        sSettingName = sArgument[2:];
        sValue = None;
      
      if sSettingName in ["pid", "pids"]:
        if not sValue:
          oConsole.fPrint(ERROR, "- You must provide at least one process id.");
          oConsole.fCleanup();
          os._exit(2);
        if sApplicationBinaryPath is not None:
          oConsole.fPrint(ERROR, "- You cannot provide an application binary and process ids.");
          oConsole.fCleanup();
          os._exit(2);
        if sUWPApplicationPackageName is not None:
          oConsole.fPrint(ERROR, "- You cannot provide an UWP application package name and process ids.");
          oConsole.fCleanup();
          os._exit(2);
        auApplicationProcessIds += [long(x) for x in sValue.split(",")];
      elif sSettingName in ["uwp", "uwp-app"]:
        if not sValue:
          oConsole.fPrint(ERROR, "- You must provide UWP application details.");
          oConsole.fCleanup();
          os._exit(2);
        if sUWPApplicationPackageName is not None:
          oConsole.fPrint(ERROR, "- You cannot provide UWP application details more than once.");
          oConsole.fCleanup();
          os._exit(2);
        if sApplicationBinaryPath is not None:
          oConsole.fPrint(ERROR, "- You cannot provide an application binary and UWP application details.");
          oConsole.fCleanup();
          os._exit(2);
        if len(auApplicationProcessIds) > 0:
          oConsole.fPrint(ERROR, "- You cannot provide process ids and UWP application details.");
          oConsole.fCleanup();
          os._exit(2);
        if "!" not in sValue:
          oConsole.fPrint(ERROR, "- Please provide UWP application details in the form ", ERROR_INFO, sSettingName, \
              "=<package name>!<application id>", ERROR, ".");
          oConsole.fCleanup();
          os._exit(2);
        sUWPApplicationPackageName, sUWPApplicationId = sValue.split("!", 1);
      elif sSettingName in ["help"]:
        fPrintLogo();
        fPrintUsageInformation(ddxApplicationSettings_by_sKeyword.keys());
        oConsole.fCleanup();
        os._exit(0);
      elif sSettingName in ["version", "check-for-updates"]:
        fPrintVersionInformation(
          bCheckForUpdates = True,
          bCheckAndShowLicenses = True,
          bShowInstallationFolders = True,
        );
        oConsole.fCleanup();
        os._exit(0);
      elif sSettingName in ["isa", "cpu"]:
        if not sValue:
          oConsole.fPrint(ERROR, "- You must provide an Instruction Set Architecture.");
          oConsole.fCleanup();
          os._exit(2);
        if sValue not in ["x86", "x64"]:
          oConsole.fPrint(ERROR, "- Unknown Instruction Set Architecture ", repr(sValue));
          oConsole.fCleanup();
          os._exit(2);
        sApplicationISA = sValue;
      elif sSettingName in ["quiet", "silent"]:
        if sValue is None or sValue.lower() == "true":
          gbQuiet = True;
        elif sValue.lower() == "false":
          gbQuiet = False;
        else:
          oConsole.fPrint(ERROR, "- The value for ", ERROR_INFO, "--", sSettingName, ERROR, \
              " must be \"true\" or \"false\".");
      elif sSettingName in ["verbose", "debug"]:
        if sValue is None or sValue.lower() == "true":
          gbVerbose = True;
        elif sValue.lower() == "false":
          gbVerbose = False;
        else:
          oConsole.fPrint(ERROR, "- The value for ", ERROR_INFO, "--", sSettingName, ERROR, \
              " must be \"true\" or \"false\".");
      elif sSettingName in ["fast", "quick"]:
        if sValue is None or sValue.lower() == "true":
          bFast = True;
        elif sValue.lower() == "false":
          bFast = False;
        else:
          oConsole.fPrint(ERROR, "- The value for ", ERROR_INFO, "--", sSettingName, ERROR, \
              " must be \"true\" or \"false\".");
      elif sSettingName in ["forever"]:
        if sValue is None or sValue.lower() == "true":
          bRepeat = True;
        elif sValue.lower() == "false":
          bRepeat = False;
        else:
          oConsole.fPrint(ERROR, "- The value for ", ERROR_INFO, "--", sSettingName, ERROR, \
              " must be \"true\" or \"false\".");
      elif sSettingName in ["repeat"]:
        bRepeat = sValue is None or sValue.lower() != "false";
        if bRepeat and sValue is not None:
          try:
            uNumberOfRepeats = long(sValue);
            if uNumberOfRepeats < 2:
              uNumberOfRepeats = None;
            elif str(uNumberOfRepeats) != sValue:
              uNumberOfRepeats = None;
          except:
            pass;
          if uNumberOfRepeats is None:
            oConsole.fPrint(ERROR, "- The value for ", ERROR_INFO, "--", sSettingName, ERROR, \
                " must be an integer larger than 1 or \"false\".");
      elif sSettingName in ["collateral"]:
        if sValue is None:
          guMaximumNumberOfBugs = guDefaultCollateralMaximumNumberOfBugs;
        else:
          # -- collateral=1 means one collateral bug in addition to the first bug.
          guMaximumNumberOfBugs = long(sValue) + 1;
      elif sSettingName in ["symbols"]:
        if sValue is None or not mFileSystem2.foGetFolder(sValue):
          oConsole.fPrint(ERROR, "- The value for ", ERROR_INFO, "--", sSettingName, ERROR, \
              " must be a valid path.");
        asAdditionalLocalSymbolPaths.append(sValue);
      elif sSettingName in ["test-internal-error", "internal-error-test"]:
        raise Exception("Testing internal error");
      else:
        if not sValue:
          oConsole.fPrint(ERROR, "- You cannot provide an argument (", ERROR_INFO, "--", sSettingName, ERROR, \
              ") without a value.");
          oConsole.fCleanup();
          os._exit(2);
        try:
          xValue = json.loads(sValue);
        except ValueError as oError:
          oConsole.fPrint(ERROR, "- Cannot decode argument JSON value --", ERROR_INFO, sSettingName, ERROR, "=", \
              ERROR_INFO, sValue, ERROR, ": ", ERROR_INFO, " ".join(oError.args), ERROR, ".");
          oConsole.fCleanup();
          os._exit(2);
        # User provided config settings must be applied after any keyword specific config settings:
        dxUserProvidedConfigSettings[sSettingName] = xValue;
    elif sArgument in ddxApplicationSettings_by_sKeyword:
      if sApplicationKeyword is not None:
        oConsole.fPrint(ERROR, "- You cannot provide multiple application keywords.");
        oConsole.fCleanup();
        os._exit(2);
      sApplicationKeyword = sArgument;
    elif sArgument[-1] == "?":
      sApplicationKeyword = sArgument[:-1];
      dxApplicationSettings = ddxApplicationSettings_by_sKeyword.get(sApplicationKeyword);
      if not dxApplicationSettings:
        oConsole.fPrint(ERROR, "- Unknown application keyword ", ERROR_INFO, sApplicationKeyword, ERROR, ".");
        oConsole.fCleanup();
        os._exit(2);
      fPrintApplicationKeyWordHelp(sApplicationKeyword, dxApplicationSettings);
      oConsole.fCleanup();
      os._exit(0);
    else:
      if sApplicationBinaryPath is not None:
        oConsole.fLock();
        try:
          oConsole.fPrint(ERROR, "- You cannot provide multiple application binaries.");
          oConsole.fPrint(ERROR, "  (Did you perhaps forget to put ", ERROR_INFO, "--", ERROR, \
              " before the start of the application arguments?)");
        finally:
          oConsole.fUnlock();
        oConsole.fCleanup();
        os._exit(2);
      if len(auApplicationProcessIds) > 0:
        oConsole.fPrint(ERROR, "- You cannot provide process ids and an application binary.");
        oConsole.fCleanup();
        os._exit(2);
      if sUWPApplicationPackageName is not None:
        oConsole.fPrint(ERROR, "- You cannot provide an application UWP package name and a binary.");
        oConsole.fCleanup();
        os._exit(2);
      sApplicationBinaryPath = sArgument;
  
  if bFast:
    gbQuiet = True;
    dxUserProvidedConfigSettings["bGenerateReportHTML"] = False;
    dxUserProvidedConfigSettings["asSymbolServerURLs"] = [];
    dxUserProvidedConfigSettings["cBugId.bUse_NT_SYMBOL_PATH"] = False;
  
  dsApplicationURLTemplate_by_srSourceFilePath = {};
  
  fSetup = None; # Function specific to a keyword application, used to setup stuff before running.
  fCleanup = None; # Function specific to a keyword application, used to cleanup stuff before & after running.
  if sApplicationKeyword:
    dxApplicationSettings = ddxApplicationSettings_by_sKeyword.get(sApplicationKeyword);
    if not dxApplicationSettings:
      oConsole.fPrint(ERROR, "- Unknown application keyword ", ERROR_INFO, sApplicationKeyword, ERROR, ".");
      oConsole.fCleanup();
      os._exit(2);
    fSetup = dxApplicationSettings.get("fSetup");
    fCleanup = dxConfig["bCleanup"] and dxApplicationSettings.get("fCleanup");
    # Get application binary/UWP package name/process ids as needed:
    if "sBinaryPath" in dxApplicationSettings:
      # This application is started from the command-line.
      if auApplicationProcessIds:
        oConsole.fPrint(ERROR, "- You cannot provide process ids for application keyword ", ERROR_INFO, \
            sApplicationKeyword, ERROR, ".");
        oConsole.fCleanup();
        os._exit(2);
      if sUWPApplicationPackageName:
        oConsole.fPrint(ERROR, "- You cannot provide an application UWP package name for application keyword ", \
            ERROR_INFO, sApplicationKeyword, ERROR, ".");
        oConsole.fCleanup();
        os._exit(2);
      if sApplicationBinaryPath is None:
        sApplicationBinaryPath = dxApplicationSettings["sBinaryPath"];
        if sApplicationBinaryPath is None:
          oConsole.fPrint(ERROR, "- The main application binary for ", ERROR_INFO, sApplicationKeyword, \
              ERROR, " could not be detected on your system.");
          oConsole.fPrint(ERROR, "  Please provide the path to this binary in the arguments.");
          oConsole.fCleanup();
          os._exit(4);
    elif "dxUWPApplication" in dxApplicationSettings:
      dxUWPApplication = dxApplicationSettings["dxUWPApplication"];
      # This application is started as a Universal Windows Platform application.
      if sApplicationBinaryPath:
        oConsole.fPrint(ERROR, "- You cannot provide an application binary for application keyword ", \
            ERROR_INFO, sApplicationKeyword, ERROR, ".");
        oConsole.fCleanup();
        os._exit(2);
      if auApplicationProcessIds:
        oConsole.fPrint(ERROR, "- You cannot provide process ids for application keyword ", ERROR_INFO, \
            sApplicationKeyword, ERROR, ".");
        oConsole.fCleanup();
        os._exit(2);
      sUWPApplicationPackageName = dxUWPApplication["sPackageName"];
      sUWPApplicationId = dxUWPApplication["sId"];
    elif not auApplicationProcessIds:
      # This application is attached to.
      oConsole.fPrint(ERROR, "- You must provide process ids for application keyword ", \
          ERROR_INFO, sApplicationKeyword, ERROR, ".");
      oConsole.fCleanup();
      os._exit(2);
    elif asApplicationOptionalArguments:
      # Cannot provide arguments if we're attaching to processes
      oConsole.fPrint(ERROR, "- You cannot provide arguments for application keyword ", \
          ERROR_INFO, sApplicationKeyword, ERROR, ".");
      oConsole.fCleanup();
      os._exit(2);
    if "asApplicationAttachForProcessExecutableNames" in dxApplicationSettings:
      gasAttachForProcessExecutableNames = dxApplicationSettings["asApplicationAttachForProcessExecutableNames"];
    # Get application arguments;
    if "fasGetStaticArguments" in dxApplicationSettings:
      fasGetApplicationStaticArguments = dxApplicationSettings["fasGetStaticArguments"];
      asApplicationStaticArguments = fasGetApplicationStaticArguments(bForHelp = False);
    else:
      asApplicationStaticArguments = [];
    if asApplicationOptionalArguments is None and "fasGetOptionalArguments" in dxApplicationSettings:
      fasGetApplicationOptionalArguments = dxApplicationSettings["fasGetOptionalArguments"];
      asApplicationOptionalArguments = fasGetApplicationOptionalArguments(bForHelp = False);
    asApplicationArguments = asApplicationStaticArguments + asApplicationOptionalArguments;
    # Apply application specific settings
    if dxApplicationSettings.get("dxConfigSettings"):
      dxApplicationConfigSettings = dxApplicationSettings["dxConfigSettings"];
      if gbVerbose:
        oConsole.fPrint("* Applying application specific configuration for %s:" % sApplicationKeyword);
      for (sSettingName, xValue) in dxApplicationConfigSettings.items():
        if sSettingName not in dxUserProvidedConfigSettings:
          # Apply and show result indented or errors.
          if not fbApplyConfigSetting(sSettingName, xValue, [None, "  "][gbVerbose]):
            os._exit(2);
      if gbVerbose:
        oConsole.fPrint();
    # Apply application specific source settings
    if "dsURLTemplate_by_srSourceFilePath" in dxApplicationSettings:
      dsApplicationURLTemplate_by_srSourceFilePath = dxApplicationSettings["dsURLTemplate_by_srSourceFilePath"];
    # If not ISA is specified, apply the application specific ISA (if any).
    if not sApplicationISA and "sISA" in dxApplicationSettings:
      sApplicationISA = dxApplicationSettings["sISA"];
    if "asBinaryNamesThatAreAllowedToRunWithoutPageHeap" in dxApplicationSettings:
      gasBinaryNamesThatAreAllowedToRunWithoutPageHeap += [
        sBinaryName.lower() for sBinaryName in dxApplicationSettings["asBinaryNamesThatAreAllowedToRunWithoutPageHeap"]
      ];
  elif (auApplicationProcessIds or sUWPApplicationPackageName or sApplicationBinaryPath):
    # There are no static arguments if there is no application keyword, only the user-supplied optional arguments
    # are used if they are supplied:
    asApplicationArguments = asApplicationOptionalArguments or [];
  else:
    oConsole.fLock();
    try:
      oConsole.fPrint(ERROR, "- You must provide something to debug. This can be either one or more process");
      oConsole.fPrint(ERROR, "  ids, an application command-line or an UWP application package name.");
      oConsole.fPrint("Run \"", INFO, "BugId -h", NORMAL, "\" for help on command-line arguments.");
    finally:
      oConsole.fUnlock();
    oConsole.fCleanup();
    os._exit(2);
  
  # Apply user provided settings:
  for (sSettingName, xValue) in dxUserProvidedConfigSettings.items():
    # Apply and show result or errors:
    if not fbApplyConfigSetting(sSettingName, xValue, [None, ""][gbVerbose]):
      os._exit(2);
  
  # Check if cdb.exe is found:
  sCdbISA = sApplicationISA or cBugId.sOSISA;
  if not cBugId.fbCdbFound(sCdbISA):
    oConsole.fLock();
    try:
      oConsole.fPrint(ERROR, "- BugId depends on ", ERROR_INFO, "Debugging Tools for Windows", ERROR, " which was not found.");
      oConsole.fPrint();
      oConsole.fPrint("To install, download the Windows 10 SDK installer at:");
      oConsole.fPrint();
      oConsole.fPrint("  ", INFO, "https://developer.microsoft.com/en-US/windows/downloads/windows-10-sdk");
      oConsole.fPrint();
      oConsole.fPrint("After downloading, run the installer. You can deselect all other features");
      oConsole.fPrint("of the SDK before installation; only ", INFO, "Debugging Tools for Windows", NORMAL, " is required.");
      oConsole.fPrint();
      oConsole.fPrint("Once you have completed these steps, please try again.");
    finally:
      oConsole.fUnlock();
    oConsole.fCleanup();
    os._exit(2);
  
  # Check license
  (asLicenseErrors, asLicenseWarnings) = mProductDetails.ftasGetLicenseErrorsAndWarnings();
  if asLicenseErrors:
    oConsole.fLock();
    try:
      oConsole.fPrint(ERROR, u"\u250C\u2500", ERROR_INFO, " Software license error ", ERROR, sPadding = u"\u2500");
      for sLicenseError in asLicenseErrors:
        oConsole.fPrint(ERROR, u"\u2502 ", ERROR_INFO, sLicenseError);
      oConsole.fPrint(ERROR, u"\u2514", sPadding = u"\u2500");
    finally:
      oConsole.fUnlock();
    os._exit(5);
  if asLicenseWarnings:
    oConsole.fLock();
    try:
      oConsole.fPrint(WARNING, u"\u250C\u2500", WARNING_INFO, " Software license warning ", WARNING, sPadding = u"\u2500");
      for sLicenseWarning in asLicenseWarnings:
        oConsole.fPrint(WARNING, u"\u2502 ", WARNING_INFO, sLicenseWarning);
      oConsole.fPrint(WARNING, u"\u2514", sPadding = u"\u2500");
    finally:
      oConsole.fUnlock();
  
  if bRepeat:
    sValidStatisticsFileName = mFileSystem2.fsGetValidName("Reproduction statistics.txt");
  uRunCounter = 0;
  while 1: # Will only loop if bRepeat is True
    nStartTimeInSeconds = time.clock();
    if fSetup:
      # Call setup before the application is started. Argument is boolean value indicating if this is the first time
      # the function is being called.
      oConsole.fStatus("* Applying special application configuration settings...");
      fSetup(bFirstRun = uRunCounter == 0);
    uRunCounter += 1;
    oConsole.fLock();
    try:
      if sApplicationBinaryPath:
        # make the binary path absolute because relative paths don't work.
        sApplicationBinaryPath = os.path.abspath(sApplicationBinaryPath);
        if not gbQuiet:
          asCommandLine = [sApplicationBinaryPath] + asApplicationArguments;
          oConsole.fPrint("* Command line: ", INFO, " ".join(asCommandLine));
        oConsole.fStatus("* The debugger is starting the application...");
      else:
        if auApplicationProcessIds:
          asProcessIdsOutput = [];
          for uApplicationProcessId in auApplicationProcessIds:
            if asProcessIdsOutput: asProcessIdsOutput.append(", ");
            asProcessIdsOutput.extend([INFO, str(uApplicationProcessId), NORMAL]);
          oConsole.fPrint("* Running process ids: ", INFO, *asProcessIdsOutput);
        if sUWPApplicationPackageName:
          if not gbQuiet:
            if asApplicationArguments:
              oConsole.fPrint("* UWP application id: ", INFO, sUWPApplicationId, NORMAL, ", package name: ", INFO, \
                  sUWPApplicationPackageName, NORMAL, ", Arguments: ", INFO, " ".join(asApplicationArguments));
            else:
              oConsole.fPrint("* UWP application id: ", INFO, sUWPApplicationId, NORMAL, ", package name: ", INFO, \
                  sUWPApplicationPackageName);
        if not sUWPApplicationPackageName:
          oConsole.fStatus("* The debugger is attaching to running processes of the application...");
        elif auApplicationProcessIds:
          oConsole.fStatus("* The debugger is attaching to running processes and starting the application...");
        else:
          oConsole.fStatus("* The debugger is starting the application...");
    finally:
      oConsole.fUnlock();
    asLocalSymbolPaths = dxConfig["asLocalSymbolPaths"] or [];
    if asAdditionalLocalSymbolPaths:
      asLocalSymbolPaths += asAdditionalLocalSymbolPaths;
    oBugId = cBugId(
      sCdbISA = sCdbISA,
      sApplicationBinaryPath = sApplicationBinaryPath or None,
      auApplicationProcessIds = auApplicationProcessIds or None,
      sUWPApplicationPackageName = sUWPApplicationPackageName or None,
      sUWPApplicationId = sUWPApplicationId or None,
      asApplicationArguments = asApplicationArguments,
      asLocalSymbolPaths = asLocalSymbolPaths or None,
      asSymbolCachePaths = dxConfig["asSymbolCachePaths"], 
      asSymbolServerURLs = dxConfig["asSymbolServerURLs"],
      dsURLTemplate_by_srSourceFilePath = dsApplicationURLTemplate_by_srSourceFilePath,
      bGenerateReportHTML = dxConfig["bGenerateReportHTML"],
      uProcessMaxMemoryUse = dxConfig["uProcessMaxMemoryUse"],
      uTotalMaxMemoryUse = dxConfig["uTotalMaxMemoryUse"],
      uMaximumNumberOfBugs = guMaximumNumberOfBugs,
    );
    oBugId.fAddEventCallback("Application resumed", fApplicationResumedCallback);
    oBugId.fAddEventCallback("Application running", fApplicationRunningCallback);
    oBugId.fAddEventCallback("Application suspended", fApplicationSuspendedCallback);
    oBugId.fAddEventCallback("Application debug output", fApplicationDebugOutputCallback);
    oBugId.fAddEventCallback("Application stderr output", fApplicationStdErrOutputCallback);
    oBugId.fAddEventCallback("Application stdout output", fApplicationStdOutOutputCallback);
    oBugId.fAddEventCallback("Bug report", fBugReportCallback);
    oBugId.fAddEventCallback("Cdb stderr output", fCdbStdErrOutputCallback);
    if gbVerbose:
      oBugId.fAddEventCallback("Cdb stdin input", fCdbStdInInputCallback);
      oBugId.fAddEventCallback("Cdb stdout output", fCdbStdOutOutputCallback);
      oBugId.fAddEventCallback("Log message", fLogMessageCallback);
    oBugId.fAddEventCallback("Failed to apply application memory limits", fFailedToApplyApplicationMemoryLimitsCallback);
    oBugId.fAddEventCallback("Failed to apply process memory limits", fFailedToApplyProcessMemoryLimitsCallback);
    oBugId.fAddEventCallback("Failed to debug application", fFailedToDebugApplicationCallback);
    oBugId.fAddEventCallback("Internal exception", fInternalExceptionCallback);
    oBugId.fAddEventCallback("License warnings", fLicenseWarningsCallback);
    oBugId.fAddEventCallback("License errors", fLicenseErrorsCallback);
    oBugId.fAddEventCallback("Page heap not enabled", fPageHeapNotEnabledCallback);
    oBugId.fAddEventCallback("Cdb ISA not ideal", fCdbISANotIdealCallback);
    oBugId.fAddEventCallback("Process attached", fProcessAttachedCallback);
    oBugId.fAddEventCallback("Process started", fProcessStartedCallback);
    oBugId.fAddEventCallback("Process terminated", fProcessTerminatedCallback);

    if dxConfig["nApplicationMaxRunTimeInSeconds"] is not None:
      oBugId.foSetTimeout("Maximum application runtime", dxConfig["nApplicationMaxRunTimeInSeconds"], \
          fApplicationMaxRunTimeCallback);
    if dxConfig["bExcessiveCPUUsageCheckEnabled"] and dxConfig["nExcessiveCPUUsageCheckInitialTimeoutInSeconds"]:
      oBugId.fSetCheckForExcessiveCPUUsageTimeout(dxConfig["nExcessiveCPUUsageCheckInitialTimeoutInSeconds"]);
    guDetectedBugsCount = 0;
    oBugId.fStart();
    oBugId.fWait();
    if gbAnErrorOccured:
      if fCleanup:
        # Call cleanup after runnning the application, before exiting BugId
        oConsole.fStatus("* Cleaning up application state...");
        fCleanup();
      oConsole.fCleanup();
      os._exit(3);
    if guDetectedBugsCount == 0:
      oConsole.fPrint(u"\u2500\u2500 The application terminated without a bug being detected ", sPadding = u"\u2500");
      gduNumberOfRepros_by_sBugIdAndLocation.setdefault("No crash", 0);
      gduNumberOfRepros_by_sBugIdAndLocation["No crash"] += 1;
    if gbVerbose:
      oConsole.fPrint("  Application time: %s seconds" % (long(oBugId.fnApplicationRunTimeInSeconds() * 1000) / 1000.0));
      nOverheadTimeInSeconds = time.clock() - nStartTimeInSeconds - oBugId.fnApplicationRunTimeInSeconds();
      oConsole.fPrint("  BugId overhead:   %s seconds" % (long(nOverheadTimeInSeconds * 1000) / 1000.0));
    if uNumberOfRepeats is not None:
      uNumberOfRepeats -= 1;
      if uNumberOfRepeats == 0:
        bRepeat = False;
    if not bRepeat:
      if fCleanup:
        # Call cleanup after runnning the application, before exiting BugId
        oConsole.fStatus("* Cleaning up application state...");
        fCleanup();
      oConsole.fCleanup();
      os._exit(guDetectedBugsCount > 0 and 1 or 0);
    sStatistics = "";
    auOrderedNumberOfRepros = sorted(list(set(gduNumberOfRepros_by_sBugIdAndLocation.values())));
    auOrderedNumberOfRepros.reverse();
    for uNumberOfRepros in auOrderedNumberOfRepros:
      for sBugIdAndLocation in gduNumberOfRepros_by_sBugIdAndLocation.keys():
        if gduNumberOfRepros_by_sBugIdAndLocation[sBugIdAndLocation] == uNumberOfRepros:
          sStatistics += "%d \xD7 %s (%d%%)\r\n" % (uNumberOfRepros, str(sBugIdAndLocation), \
              round(100.0 * uNumberOfRepros / uRunCounter));
    if dxConfig["sReportFolderPath"] is not None:
      sStatisticsFilePath = os.path.join(dxConfig["sReportFolderPath"], sValidStatisticsFileName);
    else:
      sStatisticsFilePath = sValidStatisticsFileName;
    oStatisticsFile = None;
    try:
      oStatisticsFile = mFileSystem2.foGetOrCreateFile(sStatisticsFilePath);
      oStatisticsFile.fWrite(sStatistics);
    except Exception as oException:
      oConsole.fPrint("  Statistics:       ", ERROR, "Cannot be saved (", ERROR_INFO, str(oException), ERROR, ")");
    else:
      oConsole.fPrint("  Statistics:       ", INFO, sStatisticsFilePath, NORMAL, " (%d bytes)" % len(sStatistics));
    if oStatisticsFile:
      oStatisticsFile.fClose();
    oConsole.fPrint(); # and loop
  raise AssertionError("Not reached!");
예제 #16
0
def fuMain(asArguments):
    nStartTime = time.clock()
    # returns an exit code, values are:
    # 0 = executed successfully, no bugs found.
    # 1 = executed successfully, bug detected.
    # 2 = bad arguments
    # 3 = internal error
    # 4 = failed to start process or attach to process(es).
    # Parse all "--" arguments until we encounter a non-"--" argument.
    auApplicationProcessIds = []
    sApplicationISA = None
    bForever = False
    dxUserProvidedConfigSettings = {}
    while asArguments and asArguments[0].startswith("--"):
        sArgument = asArguments.pop(0)
        if "=" in sArgument:
            sSettingName, sValue = sArgument[2:].split("=", 1)
        else:
            # "--bFlag" is an alias for "--bFlag=true"
            sSettingName = sArgument[2:]
            sValue = True
        if sSettingName in ["pid", "pids"]:
            auApplicationProcessIds += [long(x) for x in sValue.split(",")]
        elif sSettingName == "isa":
            if sValue not in ["x86", "x64"]:
                print "- Unknown ISA %s" % repr(sValue)
                return 2
            sApplicationISA = sValue
        elif sSettingName == "fast":
            # Alias for these three settings:
            dxUserProvidedConfigSettings["bGenerateReportHTML"] = False
            dxUserProvidedConfigSettings["asSymbolServerURLs"] = []
            dxUserProvidedConfigSettings["cBugId.bUse_NT_SYMBOL_PATH"] = False
        elif sSettingName == "forever":
            bForever = True
        else:
            try:
                xValue = json.loads(sValue)
            except ValueError:
                print "- Cannot decode argument JSON value %s" % sValue
                return 2
            # User provided config settings must be applied after any keyword specific config settings:
            dxUserProvidedConfigSettings[sSettingName] = xValue
    dsURLTemplate_by_srSourceFilePath = {}
    rImportantStdOutLines = None
    rImportantStdErrLines = None
    # If there are any additional arguments, it must be an application keyword followed by additional arguments
    # or an application command-line:
    if not asArguments:
        # No keyword or command line: process ids to attach to must be provided
        asApplicationCommandLine = None
        if not auApplicationProcessIds:
            print "You must specify an application command-line, keyword or process ids"
            return 2
    else:
        # First argument may be an application keyword
        sApplicationKeyword = None
        sApplicationBinary = None
        if "=" in asArguments[0]:
            # user provided an application keyword and binary
            sApplicationKeyword, sApplicationBinary = asArguments.pop(0).split(
                "=", 1)
        elif asArguments[0] in asApplicationKeywords or asArguments[0][
                -1] == "?":
            # user provided an application keyword, or requested information on something that may be one:
            sApplicationKeyword = asArguments.pop(0)
        asApplicationCommandLine = None
        if sApplicationKeyword:
            if sApplicationKeyword[-1] == "?":
                # User requested information about a possible keyword application
                return fuShowApplicationKeyWordHelp(sApplicationKeyword[:-1])
            # Get application command line for keyword, if available:
            if sApplicationKeyword in gdApplication_asCommandLine_by_sKeyword:
                if auApplicationProcessIds:
                    print "You cannot specify process ids for application %s" % sApplicationKeyword
                    return 2
                asApplicationCommandLine = gdApplication_asCommandLine_by_sKeyword[
                    sApplicationKeyword]
                if sApplicationBinary:
                    # Replace binary with user provided value
                    asApplicationCommandLine = [
                        sApplicationBinary
                    ] + asApplicationCommandLine[1:]
                else:
                    if asApplicationCommandLine[0] is None:
                        print "Application %s does not appear to be installed"
                        return 2
                if asArguments:
                    # Add user provided additional application arguments:
                    asApplicationCommandLine += asArguments
                elif sApplicationKeyword in gdApplication_asDefaultAdditionalArguments_by_sKeyword:
                    # Add default additional application arguments:
                    asApplicationCommandLine += [
                        sArgument is DEFAULT_BROWSER_TEST_URL
                        and dxConfig["sDefaultBrowserTestURL"] or sArgument
                        for sArgument in
                        gdApplication_asDefaultAdditionalArguments_by_sKeyword[
                            sApplicationKeyword]
                    ]

            elif asArguments:
                print "You cannot specify arguments for application keyword %s" % sApplicationKeyword
                return 2
            elif not auApplicationProcessIds:
                print "You must specify process ids for application keyword %s" % sApplicationKeyword
                return 2
            # Apply application specific settings
            if sApplicationKeyword in gdApplication_dxSettings_by_sKeyword:
                print "* Applying application specific settings:"
                for (sSettingName,
                     xValue) in gdApplication_dxSettings_by_sKeyword[
                         sApplicationKeyword].items():
                    if sSettingName not in dxUserProvidedConfigSettings:
                        fApplyConfigSetting(sSettingName, xValue, "  ")
                        # Apply and show result indented.
            # Apply application specific source settings
            if sApplicationKeyword in gdApplication_sURLTemplate_by_srSourceFilePath_by_sKeyword:
                dsURLTemplate_by_srSourceFilePath = gdApplication_sURLTemplate_by_srSourceFilePath_by_sKeyword[
                    sApplicationKeyword]
            # Apply application specific stdio settings:
            if sApplicationKeyword in gdApplication_rImportantStdOutLines_by_sKeyword:
                rImportantStdOutLines = gdApplication_rImportantStdOutLines_by_sKeyword[
                    sApplicationKeyword]
            if sApplicationKeyword in gdApplication_rImportantStdErrLines_by_sKeyword:
                rImportantStdErrLines = gdApplication_rImportantStdErrLines_by_sKeyword[
                    sApplicationKeyword]
            if not sApplicationISA and sApplicationKeyword in gdApplication_sISA_by_sKeyword:
                # Apply application specific ISA
                sApplicationISA = gdApplication_sISA_by_sKeyword[
                    sApplicationKeyword]
        elif auApplicationProcessIds:
            # user provided an application command-line and process ids
            print "You cannot specify both an application command-line and process ids"
            return 2
        else:
            # user provided an application command-line
            asApplicationCommandLine = asArguments

    # Apply user provided settings:
    for (sSettingName, xValue) in dxUserProvidedConfigSettings.items():
        fApplyConfigSetting(sSettingName, xValue)
        # Apply and show result

    while 1:  # Will only loop if bForever is True
        if asApplicationCommandLine:
            print "+ The debugger is starting the application..."
            print "  Command line: %s" % " ".join(asApplicationCommandLine)
        else:
            print "+ The debugger is attaching to the application..."
        oBugId = cBugId(
            sCdbISA=sApplicationISA or cBugId.sOSISA,
            asApplicationCommandLine=asApplicationCommandLine or None,
            auApplicationProcessIds=auApplicationProcessIds or None,
            asLocalSymbolPaths=dxConfig["asLocalSymbolPaths"],
            asSymbolCachePaths=dxConfig["asSymbolCachePaths"],
            asSymbolServerURLs=dxConfig["asSymbolServerURLs"],
            dsURLTemplate_by_srSourceFilePath=dsURLTemplate_by_srSourceFilePath,
            rImportantStdOutLines=rImportantStdOutLines,
            rImportantStdErrLines=rImportantStdErrLines,
            bGenerateReportHTML=dxConfig["bGenerateReportHTML"],
            fApplicationRunningCallback=fApplicationRunningHandler,
            fApplicationSuspendedCallback=fApplicationSuspendedHandler,
            fApplicationResumedCallback=fApplicationResumedHandler,
            fMainProcessTerminatedCallback=fMainProcessTerminatedHandler,
        )
        if dxConfig["nApplicationMaxRunTime"] is not None:
            oBugId.fxSetTimeout(dxConfig["nApplicationMaxRunTime"],
                                fApplicationRunTimeoutHandler, oBugId)
        if dxConfig["nExcessiveCPUUsageCheckInitialTimeout"]:
            oBugId.fSetCheckForExcessiveCPUUsageTimeout(
                dxConfig["nExcessiveCPUUsageCheckInitialTimeout"])
        oBugId.fStart()
        oBugId.fWait()
        if oBugId.oInternalException:
            print "-" * 80
            print "- An error has occured in cBugId, which cannot be handled:"
            print "  %s" % repr(oBugId.oInternalException)
            print "  BugId version %s, cBugId version %s" % (sVersion,
                                                             cBugId.sVersion)
            print "-" * 80
            print
            print "  Please report this issue at the below web-page so it can be addressed:"
            print "      https://github.com/SkyLined/BugId/issues/new"
            print "  If you do not have a github account, or you want to report this issue"
            print "  privately, you can also send an email to:"
            print "      [email protected]"
            print
            print "  In your report, please copy all the information about the error reported"
            print "  above, as well as the version information. This makes it easier to determine"
            print "  the cause of this issue. I will try to address the issues as soon as"
            print "  possible. Thank you in advance for helping to improve BugId!"
            return 3
        if oBugId.sFailedToDebugApplicationErrorMessage is not None:
            print "-" * 80
            print "- Failed to debug the application:"
            for sLine in oBugId.sFailedToDebugApplicationErrorMessage.split(
                    "\n"):
                print "  %s" % sLine.rstrip("\r")
            print "-" * 80
            return 4
        if oBugId.oBugReport is not None:
            print
            print "  === BugId report (https://github.com/SkyLined/BugId) ".ljust(
                80, "=")
            print "  Id:               %s" % oBugId.oBugReport.sId
            print "  Location:         %s" % oBugId.oBugReport.sBugLocation
            print "  Description:      %s" % oBugId.oBugReport.sBugDescription
            print "  Version:          %s" % oBugId.oBugReport.asVersionInformation[
                0]
            # There is always the process' binary.
            for sVersionInformation in oBugId.oBugReport.asVersionInformation[
                    1:]:  # There may be two if the crash was in a
                print "                    %s" % sVersionInformation
                # different binary (e.g. a .dll)
            if oBugId.oBugReport.sBugSourceLocation:
                print "  Source:           %s" % oBugId.oBugReport.sBugSourceLocation
            print "  Security impact:  %s" % oBugId.oBugReport.sSecurityImpact
            print "  Application time: %s seconds" % (
                long(oBugId.fnApplicationRunTime() * 1000) / 1000.0)
            nOverheadTime = time.clock(
            ) - nStartTime - oBugId.fnApplicationRunTime()
            print "  BugId overhead:   %s seconds" % (
                long(nOverheadTime * 1000) / 1000.0)
            if dxConfig["bGenerateReportHTML"]:
                # We'd like a report file name base on the BugId, but the later may contain characters that are not valid in a file name
                sDesiredReportFileName = "%s @ %s.html" % (
                    oBugId.oBugReport.sId, oBugId.oBugReport.sBugLocation)
                # Thus, we need to translate these characters to create a valid filename that looks very similar to the BugId
                sValidReportFileName = FileSystem.fsValidName(
                    sDesiredReportFileName,
                    bUnicode=dxConfig["bUseUnicodeReportFileNames"])
                if dxConfig["sReportFolderPath"] is not None:
                    sReportFilePath = FileSystem.fsPath(
                        dxConfig["sReportFolderPath"], sValidReportFileName)
                else:
                    sReportFilePath = FileSystem.fsPath(sValidReportFileName)
                eWriteDataToFileResult = FileSystem.feWriteDataToFile(
                    oBugId.oBugReport.sReportHTML,
                    sReportFilePath,
                    fbRetryOnFailure=lambda: False,
                )
                if eWriteDataToFileResult:
                    print "  Bug report:       Cannot be saved (%s)" % repr(
                        eWriteDataToFileResult)
                else:
                    print "  Bug report:       %s (%d bytes)" % (
                        sValidReportFileName, len(
                            oBugId.oBugReport.sReportHTML))
            if not bForever: return 1
        else:
            print
            print "  === BugId report (https://github.com/SkyLined/BugId) ".ljust(
                80, "=")
            print "  Id:               None"
            print "  Description:      The application terminated before a bug was detected."
            print "  Application time: %s seconds" % (
                long(oBugId.fnApplicationRunTime() * 1000) / 1000.0)
            nOverheadTime = time.clock(
            ) - nStartTime - oBugId.fnApplicationRunTime()
            print "  BugId overhead:   %s seconds" % (
                long(nOverheadTime * 1000) / 1000.0)
            if not bForever: return 0
        print
예제 #17
0
def fuMain(asArguments):
  global gbVerbose, gbQuiet, gasAttachToProcessesForExecutableNames;
  if len(asArguments) == 0:
    fPrintLogo();
    fPrintUsage(asApplicationKeywords);
    return 0;
  # Parse all arguments until we encounter "--".
  sApplicationKeyword = None;
  sApplicationBinaryPath = None;
  auApplicationProcessIds = [];
  sUWPApplicationPackageName = None;
  sUWPApplicationId = None;
  asApplicationOptionalArguments = None;
  sApplicationISA = None;
  bRepeat = False;
  bCheckForUpdates = False;
  dxUserProvidedConfigSettings = {};
  bFast = False;
  while asArguments:
    sArgument = asArguments.pop(0);
    if sArgument == "--":
      if len(auApplicationProcessIds) > 0:
      # The rest of the arguments are to be passed to the application
        oConsole.fPrint(ERROR, "- You cannot provide process ids and application arguments.");
        return 2;
      asApplicationOptionalArguments = asArguments;
      break;
    elif sArgument in ["-q", "/q"]:
      gbQuiet = True;
    elif sArgument in ["-v", "/v"]:
      gbVerbose = True;
    elif sArgument in ["-f", "/f"]:
      bFast = True;
    elif sArgument in ["-r", "/r"]:
      bRepeat = True;
    elif sArgument in ["-?", "/?", "-h", "/h"]:
      fPrintLogo();
      fPrintUsage(asApplicationKeywords);
      return 0;
    elif sArgument.startswith("--"):
      if "=" in sArgument:
        sSettingName, sValue = sArgument[2:].split("=", 1);
      else:
        # "--bFlag" is an alias for "--bFlag=true"
        sSettingName = sArgument[2:];
        sValue = None;
      
      if sSettingName in ["pid", "pids"]:
        if not sValue:
          oConsole.fPrint(ERROR, "- You must provide at least one process id.");
          return 2;
        if sApplicationBinaryPath is not None:
          oConsole.fPrint(ERROR, "- You cannot provide an application binary and process ids.");
          return 2;
        if sUWPApplicationPackageName is not None:
          oConsole.fPrint(ERROR, "- You cannot provide an UWP application package name and process ids.");
          return 2;
        auApplicationProcessIds += [long(x) for x in sValue.split(",")];
      elif sSettingName in ["uwp", "uwp-app"]:
        if not sValue:
          oConsole.fPrint(ERROR, "- You must provide an UWP application package name.");
          return 2;
        if sUWPApplicationPackageName is not None:
          oConsole.fPrint(ERROR, "- You cannot provide multiple UWP application package names.");
          return 2;
        if sApplicationBinaryPath is not None:
          oConsole.fPrint(ERROR, "- You cannot provide an application binary and UWP package name.");
          return 2;
        if len(auApplicationProcessIds) > 0:
          oConsole.fPrint(ERROR, "- You cannot provide process ids and an UWP application package name.");
          return 2;
        if "!" not in sValue:
          oConsole.fPrint(ERROR, "- Please provide a string of the form ", ERROR_INFO, sSettingName, "=<package name>!<application id>.");
          return 2;
        sUWPApplicationPackageName, sUWPApplicationId = sValue.split("!", 1);
      elif sSettingName in ["version", "check-for-updates"]:
        fVersionCheck();
        return 0;
      elif sSettingName in ["isa", "cpu"]:
        if not sValue:
          oConsole.fPrint(ERROR, "- You must provide an Instruction Set Architecture.");
          return 2;
        if sValue not in ["x86", "x64"]:
          oConsole.fPrint(ERROR, "- Unknown Instruction Set Architecture ", repr(sValue));
          return 2;
        sApplicationISA = sValue;
      elif sSettingName in ["quiet", "silent"]:
        if sValue is None or sValue.lower() == "true":
          gbQuiet = True;
        elif sValue.lower() == "false":
          gbQuiet = False;
        else:
          oConsole.fPrint(ERROR, "- The value for ", ERROR_INFO, "--", sSettingName, ERROR, " must be \"true\" or \"false\".");
      elif sSettingName in ["verbose", "debug"]:
        if sValue is None or sValue.lower() == "true":
          gbVerbose = True;
        elif sValue.lower() == "false":
          gbVerbose = False;
        else:
          oConsole.fPrint(ERROR, "- The value for ", ERROR_INFO, "--", sSettingName, ERROR, " must be \"true\" or \"false\".");
      elif sSettingName in ["fast", "quick"]:
        if sValue is None or sValue.lower() == "true":
          bFast = True;
        elif sValue.lower() == "false":
          bFast = False;
        else:
          oConsole.fPrint(ERROR, "- The value for ", ERROR_INFO, "--", sSettingName, ERROR, " must be \"true\" or \"false\".");
      elif sSettingName in ["repeat", "forever"]:
        if sValue is None or sValue.lower() == "true":
          bRepeat = True;
        elif sValue.lower() == "false":
          bRepeat = False;
        else:
          oConsole.fPrint(ERROR, "- The value for ", ERROR_INFO, "--", sSettingName, ERROR, " must be \"true\" or \"false\".");
      elif sSettingName in ["test-internal-error", "internal-error-test"]:
        raise Exception("Testing internal error");
      else:
        try:
          xValue = json.loads(sValue);
        except ValueError as oError:
          oConsole.fPrint(ERROR, "- Cannot decode argument JSON value ", ERROR_INFO, sValue, ERROR, ": ", \
              ERROR_INFO, " ".join(oError.args), ERROR, ".");
          return 2;
        # User provided config settings must be applied after any keyword specific config settings:
        dxUserProvidedConfigSettings[sSettingName] = xValue;
    elif sArgument in asApplicationKeywords:
      if sApplicationKeyword is not None:
        oConsole.fPrint(ERROR, "- You cannot provide multiple application keywords.");
        return 2;
      sApplicationKeyword = sArgument;
    elif sArgument[-1] == "?" and sArgument[:-1] in asApplicationKeywords:
      return fuShowApplicationKeyWordHelp(sArgument[:-1]);
    else:
      if sApplicationBinaryPath is not None:
        oConsole.fLock();
        try:
          oConsole.fPrint(ERROR, "- You cannot provide multiple application binaries.");
          oConsole.fPrint(ERROR, "  (Did you perhaps forget to put ", ERROR_INFO, "--", ERROR, " before the start of the application arguments?)");
        finally:
          oConsole.fUnlock();
        return 2;
      if len(auApplicationProcessIds) > 0:
        oConsole.fPrint(ERROR, "- You cannot provide process ids and an application binary.");
        return 2;
      if sUWPApplicationPackageName is not None:
        oConsole.fPrint(ERROR, "- You cannot provide an application UWP package name and a binary.");
        return 2;
      sApplicationBinaryPath = sArgument;
  
  if bFast:
    gbQuiet = True;
    dxUserProvidedConfigSettings["bGenerateReportHTML"] = False;
    dxUserProvidedConfigSettings["asSymbolServerURLs"] = [];
    dxUserProvidedConfigSettings["cBugId.bUse_NT_SYMBOL_PATH"] = False;
  
  dsURLTemplate_by_srSourceFilePath = {};
  rImportantStdOutLines = None;
  rImportantStdErrLines = None;
  
  if sApplicationKeyword:
    fCleanup = dxConfig["bCleanup"] and gdfCleanup_by_sKeyword.get(sApplicationKeyword) or None;
    # Get application binary/UWP package name/process ids as needed:
    if sApplicationKeyword in gdApplication_sBinaryPath_by_sKeyword:
      # This application is started from the command-line.
      if auApplicationProcessIds:
        oConsole.fPrint(ERROR, "- You cannot provide process ids for application keyword ", ERROR_INFO, \
            sApplicationKeyword, ERROR, ".");
        return 2;
      if sUWPApplicationPackageName:
        oConsole.fPrint(ERROR, "- You cannot provide an application UWP package name for application keyword ", \
            ERROR_INFO, sApplicationKeyword, ERROR, ".");
        return 2;
      if sApplicationBinaryPath is None:
        sApplicationBinaryPath = gdApplication_sBinaryPath_by_sKeyword[sApplicationKeyword];
        if sApplicationBinaryPath is None:
          oConsole.fPrint(ERROR, "- The main application binary for ", ERROR_INFO, sApplicationKeyword, \
              ERROR, " could not be detected on your system.");
          oConsole.fPrint(ERROR, "  Please provide the path to this binary in the arguments.");
          return 4;
    elif sApplicationKeyword in gsUWPApplicationPackageName_by_sKeyword:
      # This application is started as an application package.
      if sApplicationBinaryPath:
        oConsole.fPrint(ERROR, "- You cannot provide an application binary for application keyword ", \
            ERROR_INFO, sApplicationKeyword, ERROR, ".");
        return 2;
      sUWPApplicationPackageName = gsUWPApplicationPackageName_by_sKeyword[sApplicationKeyword];
      sUWPApplicationId = gsUWPApplicationId_by_sKeyword[sApplicationKeyword];
    elif not auApplicationProcessIds:
      # This application is attached to.
      oConsole.fPrint(ERROR, "- You must provide process ids for application keyword ", \
          ERROR_INFO, sApplicationKeyword, ERROR, ".");
      return 2;
    elif asApplicationOptionalArguments:
      # Cannot provide arguments if we're attaching to processes
      oConsole.fPrint(ERROR, "- You cannot provide arguments for application keyword ", \
          ERROR_INFO, sApplicationKeyword, ERROR, ".");
      return 2;
    if sApplicationKeyword in gasApplicationAttachToProcessesForExecutableNames_by_sKeyword:
      gasAttachToProcessesForExecutableNames = gasApplicationAttachToProcessesForExecutableNames_by_sKeyword[sApplicationKeyword];
    # Get application arguments;
    fasGetApplicationStaticArguments = gdApplication_fasGetStaticArguments_by_sKeyword.get(sApplicationKeyword, None);
    asApplicationStaticArguments = fasGetApplicationStaticArguments and fasGetApplicationStaticArguments(bForHelp = False) or [];
    if asApplicationOptionalArguments is None:
      asApplicationOptionalArguments = [
        sArgument is DEFAULT_BROWSER_TEST_URL and dxConfig["sDefaultBrowserTestURL"] or sArgument
        for sArgument in gdApplication_asDefaultOptionalArguments_by_sKeyword.get(sApplicationKeyword, [])
      ];
    asApplicationArguments = asApplicationStaticArguments + asApplicationOptionalArguments;
    # Apply application specific settings
    if sApplicationKeyword in gdApplication_dxSettings_by_sKeyword:
      if gbVerbose:
        oConsole.fPrint("* Applying application specific configuration for %s:" % sApplicationKeyword);
      for (sSettingName, xValue) in gdApplication_dxSettings_by_sKeyword[sApplicationKeyword].items():
        if sSettingName not in dxUserProvidedConfigSettings:
          fApplyConfigSetting(sSettingName, xValue, "  "); # Apply and show result indented.
      if gbVerbose:
        oConsole.fPrint();
    # Apply application specific source settings
    if sApplicationKeyword in gdApplication_sURLTemplate_by_srSourceFilePath_by_sKeyword:
      dsURLTemplate_by_srSourceFilePath = gdApplication_sURLTemplate_by_srSourceFilePath_by_sKeyword[sApplicationKeyword];
    # Apply application specific stdio settings:
    if sApplicationKeyword in gdApplication_rImportantStdOutLines_by_sKeyword:
      rImportantStdOutLines = gdApplication_rImportantStdOutLines_by_sKeyword[sApplicationKeyword];
    if sApplicationKeyword in gdApplication_rImportantStdErrLines_by_sKeyword:
      rImportantStdErrLines = gdApplication_rImportantStdErrLines_by_sKeyword[sApplicationKeyword];
    if not sApplicationISA and sApplicationKeyword in gdApplication_sISA_by_sKeyword:
      # Apply application specific ISA
      sApplicationISA = gdApplication_sISA_by_sKeyword[sApplicationKeyword];
  elif (auApplicationProcessIds or sUWPApplicationPackageName or sApplicationBinaryPath):
    fCleanup = None;
    # There are no static arguments if there is no application keyword, only the user-supplied optional arguments
    # are used if they are supplied:
    asApplicationArguments = asApplicationOptionalArguments or [];
  else:
    oConsole.fLock();
    try:
      oConsole.fPrint(ERROR, "- You must provide something to debug. This can be either one or more process");
      oConsole.fPrint(ERROR, "  ids, an application command-line or an UWP application package name.");
      oConsole.fPrint("Run \"", INFO, "BugId -h", NORMAL, "\" for help on command-line arguments.");
    finally:
      oConsole.fUnlock();
    return 2;
  
  # Apply user provided settings:
  for (sSettingName, xValue) in dxUserProvidedConfigSettings.items():
    fApplyConfigSetting(sSettingName, xValue, ""); # Apply and show result
  
  if bRepeat:
    duNumberOfRepros_by_sBugIdAndLocation = {};
    sValidStatisticsFileName = mFileSystem.fsValidName("Reproduction statistics.txt");
  uRunCounter = 0;
  while 1: # Will only loop if bRepeat is True
    nStartTime = time.clock();
    if fCleanup is not None:
      oConsole.fStatus("* Cleaning up application state...");
      fCleanup();
    uRunCounter += 1;
    oConsole.fLock();
    try:
      if sApplicationBinaryPath:
        if not gbQuiet:
          asCommandLine = [sApplicationBinaryPath] + asApplicationArguments;
          oConsole.fPrint("* Command line: ", INFO, " ".join(asCommandLine));
        oConsole.fStatus("* The debugger is starting the application...");
      else:
        if auApplicationProcessIds:
          asProcessIdsOutput = [];
          for uApplicationProcessId in auApplicationProcessIds:
            if asProcessIdsOutput: asProcessIdsOutput.append(", ");
            asProcessIdsOutput.extend([INFO, str(uApplicationProcessId), NORMAL]);
          oConsole.fPrint("* Running process ids: ", INFO, *asProcessIdsOutput);
        if sUWPApplicationPackageName:
          if not gbQuiet:
            if asApplicationArguments:
              oConsole.fPrint("* UWP application id: ", INFO, sUWPApplicationId, NORMAL, ", package name: ", INFO, \
                  sUWPApplicationPackageName, NORMAL, ", Arguments: ", INFO, " ".join(asApplicationArguments));
            else:
              oConsole.fPrint("* UWP application id: ", INFO, sUWPApplicationId, NORMAL, ", package name: ", INFO, \
                  sUWPApplicationPackageName);
        if not sUWPApplicationPackageName:
          oConsole.fStatus("* The debugger is attaching to running processes of the application...");
        elif auApplicationProcessIds:
          oConsole.fStatus("* The debugger is attaching to running processes and starting the application...");
        else:
          oConsole.fStatus("* The debugger is starting the application...");
    finally:
      oConsole.fUnlock();
    oBugId = cBugId(
      sCdbISA = sApplicationISA or cBugId.sOSISA,
      sApplicationBinaryPath = sApplicationBinaryPath or None,
      auApplicationProcessIds = auApplicationProcessIds or None,
      sUWPApplicationPackageName = sUWPApplicationPackageName or None,
      sUWPApplicationId = sUWPApplicationId or None,
      asApplicationArguments = asApplicationArguments,
      asLocalSymbolPaths = dxConfig["asLocalSymbolPaths"],
      asSymbolCachePaths = dxConfig["asSymbolCachePaths"], 
      asSymbolServerURLs = dxConfig["asSymbolServerURLs"],
      dsURLTemplate_by_srSourceFilePath = dsURLTemplate_by_srSourceFilePath,
      rImportantStdOutLines = rImportantStdOutLines,
      rImportantStdErrLines = rImportantStdErrLines,
      bGenerateReportHTML = dxConfig["bGenerateReportHTML"],
      uProcessMaxMemoryUse = dxConfig["uProcessMaxMemoryUse"],
      uTotalMaxMemoryUse = dxConfig["uTotalMaxMemoryUse"],
      fFailedToDebugApplicationCallback = fFailedToDebugApplicationHandler,
      fFailedToApplyMemoryLimitsCallback = fFailedToApplyMemoryLimitsHandler,
      fApplicationRunningCallback = fApplicationRunningHandler,
      fApplicationSuspendedCallback = fApplicationSuspendedHandler,
      fApplicationResumedCallback = fApplicationResumedHandler,
      fMainProcessTerminatedCallback = fMainProcessTerminatedHandler,
      fInternalExceptionCallback = fInternalExceptionHandler,
      fFinishedCallback = None,
      fPageHeapNotEnabledCallback = fPageHeapNotEnabledHandler,
      fStdInInputCallback = gbVerbose and fStdInInputHandler or None,
      fStdOutOutputCallback = gbVerbose and fStdOutOutputHandler or None,
      fStdErrOutputCallback = fStdErrOutputHandler,
      fNewProcessCallback = fNewProcessHandler,
      fApplicationStdOutOrErrOutputCallback = fApplicationStdOutOrErrOutputHandler,
    );
    if dxConfig["nApplicationMaxRunTime"] is not None:
      oBugId.foSetTimeout("Maximum application runtime", dxConfig["nApplicationMaxRunTime"], fApplicationRunTimeHandler);
    if dxConfig["bExcessiveCPUUsageCheckEnabled"] and dxConfig["nExcessiveCPUUsageCheckInitialTimeout"]:
      oBugId.fSetCheckForExcessiveCPUUsageTimeout(dxConfig["nExcessiveCPUUsageCheckInitialTimeout"]);
    oBugId.fStart();
    oBugId.fWait();
    if gbAnErrorOccured:
      return 3;
    oConsole.fLock();
    try:
      if oBugId.oBugReport is not None:
        oConsole.fPrint(HILITE, "+ A bug was detect in the application:");
        if oBugId.oBugReport.sBugLocation:
          oConsole.fPrint("  Id @ Location:    ", INFO, oBugId.oBugReport.sId, NORMAL, " @ ", INFO, oBugId.oBugReport.sBugLocation);
          sBugIdAndLocation = "%s @ %s" % (oBugId.oBugReport.sId, oBugId.oBugReport.sBugLocation);
        else:
          oConsole.fPrint("  Id:               ", INFO, oBugId.oBugReport.sId);
          sBugIdAndLocation = oBugId.oBugReport.sId;
        if oBugId.oBugReport.sBugSourceLocation:
          oConsole.fPrint("  Source:           ", INFO, oBugId.oBugReport.sBugSourceLocation);
        oConsole.fPrint("  Description:      ", INFO, oBugId.oBugReport.sBugDescription);
        oConsole.fPrint("  Security impact:  ", INFO, oBugId.oBugReport.sSecurityImpact);
        oConsole.fPrint("  Version:          ", HILITE, oBugId.oBugReport.asVersionInformation[0]); # There is always the process' binary.
        for sVersionInformation in oBugId.oBugReport.asVersionInformation[1:]: # There may be two if the crash was in a
          oConsole.fPrint("                    ", HILITE, sVersionInformation); # different binary (e.g. a .dll)
        if dxConfig["bGenerateReportHTML"]:
          # We'd like a report file name base on the BugId, but the later may contain characters that are not valid in a file name
          sDesiredReportFileName = "%s.html" % sBugIdAndLocation;
          # Thus, we need to translate these characters to create a valid filename that looks very similar to the BugId
          sValidReportFileName = mFileSystem.fsValidName(sDesiredReportFileName, bUnicode = dxConfig["bUseUnicodeReportFileNames"]);
          if dxConfig["sReportFolderPath"] is not None:
            sReportFilePath = mFileSystem.fsPath(dxConfig["sReportFolderPath"], sValidReportFileName);
          else:
            sReportFilePath = mFileSystem.fsPath(sValidReportFileName);
          eWriteDataToFileResult = mFileSystem.feWriteDataToFile(
            oBugId.oBugReport.sReportHTML,
            sReportFilePath,
            fbRetryOnFailure = lambda: False,
          );
          if eWriteDataToFileResult:
            oConsole.fPrint("  Bug report:       ", ERROR, "Cannot be saved (", \
                ERROR_INFO, repr(eWriteDataToFileResult), ERROR, ")");
          else:
            oConsole.fPrint("  Bug report:       ", HILITE, sValidReportFileName, NORMAL, " (%d bytes)" % len(oBugId.oBugReport.sReportHTML));
      else:
        oConsole.fPrint("+ The application terminated without a bug being detected.");
        sBugIdAndLocation = "No crash";
      if gbVerbose:
        oConsole.fPrint("  Application time: %s seconds" % (long(oBugId.fnApplicationRunTime() * 1000) / 1000.0));
        nOverheadTime = time.clock() - nStartTime - oBugId.fnApplicationRunTime();
        oConsole.fPrint("  BugId overhead:   %s seconds" % (long(nOverheadTime * 1000) / 1000.0));
      if not bRepeat: return oBugId.oBugReport is not None and 1 or 0;
      duNumberOfRepros_by_sBugIdAndLocation.setdefault(sBugIdAndLocation, 0)
      duNumberOfRepros_by_sBugIdAndLocation[sBugIdAndLocation] += 1;
      sStatistics = "";
      auOrderedNumberOfRepros = sorted(list(set(duNumberOfRepros_by_sBugIdAndLocation.values())));
      auOrderedNumberOfRepros.reverse();
      for uNumberOfRepros in auOrderedNumberOfRepros:
        for sBugIdAndLocation in duNumberOfRepros_by_sBugIdAndLocation.keys():
          if duNumberOfRepros_by_sBugIdAndLocation[sBugIdAndLocation] == uNumberOfRepros:
            sStatistics += "%d \xD7 %s (%d%%)\r\n" % (uNumberOfRepros, str(sBugIdAndLocation), round(100.0 * uNumberOfRepros / uRunCounter));
      if dxConfig["sReportFolderPath"] is not None:
        sStatisticsFilePath = mFileSystem.fsPath(dxConfig["sReportFolderPath"], sValidStatisticsFileName);
      else:
        sStatisticsFilePath = mFileSystem.fsPath(sValidStatisticsFileName);
      eWriteDataToFileResult = mFileSystem.feWriteDataToFile(
        sStatistics,
        sStatisticsFilePath,
        fbRetryOnFailure = lambda: False,
      );
      if eWriteDataToFileResult:
        oConsole.fPrint("  Statistics:       ", ERROR, "Cannot be saved (", ERROR_INFO, repr(eWriteDataToFileResult), ERROR, ")");
      else:
        oConsole.fPrint("  Statistics:       ", INFO, sStatisticsFilePath, NORMAL, " (%d bytes)" % len(sStatistics));
      oConsole.fPrint(); # and loop
    finally:
      oConsole.fUnlock();
예제 #18
0
파일: BugId.py 프로젝트: codecrack3/BugId
 
 def fApplicationExitHandler():
   print "  * T+%.1f The application has exited..." % oBugId.fnApplicationRunTime();
   oBugId.fStop();
 
 if asApplicationCommandLine:
   print "+ The debugger is starting the application...";
   print "  Command line: %s" % " ".join(asApplicationCommandLine);
 else:
   print "+ The debugger is attaching to the application...";
 oBugId = cBugId(
   asApplicationCommandLine = asApplicationCommandLine,
   auApplicationProcessIds = auApplicationProcessIds,
   asSymbolServerURLs = dxConfig["asSymbolServerURLs"],
   dsURLTemplate_by_srSourceFilePath = dsURLTemplate_by_srSourceFilePath,
   rImportantStdOutLines = rImportantStdOutLines,
   rImportantStdErrLines = rImportantStdErrLines,
   bGetDetailsHTML = dxConfig["bSaveReport"],
   fApplicationRunningCallback = fApplicationRunningHandler,
   fExceptionDetectedCallback = fExceptionDetectedHandler,
   fApplicationExitCallback = fApplicationExitHandler,
 );
 oBugId.fWait();
 if oBugId.oBugReport:
   print "+ A bug was detected in the application.";
   print;
   print "  Id:               %s" % oBugId.oBugReport.sId;
   print "  Description:      %s" % oBugId.oBugReport.sBugDescription;
   print "  Location:         %s" % oBugId.oBugReport.sBugLocation;
   if oBugId.oBugReport.sBugSourceLocation:
     print "  Source:           %s" % oBugId.oBugReport.sBugSourceLocation;
   print "  Security impact:  %s" % oBugId.oBugReport.sSecurityImpact;
예제 #19
0
파일: BugId.py 프로젝트: chubbymaggie/BugId
def fuMain(asArguments):
  # returns an exit code, values are:
  # 0 = executed successfully, no bugs found.
  # 1 = executed successfully, bug detected.
  # 2 = bad arguments
  # 3 = internal error
  global oBugId, bApplicationIsStarted, bCheckForExcessiveCPUUsageTimeoutSet;
  # Parse all "--" arguments until we encounter a non-"--" argument.
  auApplicationProcessIds = [];
  sApplicationISA = None;
  dxUserProvidedConfigSettings = {};
  while asArguments and asArguments[0].startswith("--"):
    sArgument = asArguments.pop(0);
    sSettingName, sValue = sArgument[2:].split("=", 1);
    if sSettingName in ["pid", "pids"]:
      auApplicationProcessIds += [long(x) for x in sValue.split(",")];
    elif sSettingName == "isa":
      if sValue not in ["x86", "x64"]:
        print "- Unknown ISA %s" % repr(sValue);
        return 2;
      sApplicationISA = sValue;
    else:
      try:
        xValue = json.loads(sValue);
      except ValueError:
        print "- Cannot decode argument JSON value %s" % sValue;
        return 2;
      # User provided config settings must be applied after any keyword specific config settings:
      dxUserProvidedConfigSettings[sSettingName] = xValue;
  dsURLTemplate_by_srSourceFilePath = {};
  rImportantStdOutLines = None;
  rImportantStdErrLines = None;
  # If there are any additional arguments, it must be an application keyword followed by additional arguments
  # or an application command-line:
  if not asArguments:
    # No keyword or command line: process ids to attach to must be provided
    asApplicationCommandLine = None;
    if not auApplicationProcessIds:
      print "You must specify an application command-line, keyword or process ids";
      return 2;
  else:
    # First argument may be an application keyword
    sApplicationKeyword = None;
    sApplicationBinary = None;
    if "=" in asArguments[0]:
      # user provided an application keyword and binary
      sApplicationKeyword, sApplicationBinary = asArguments.pop(0).split("=", 1);
    elif asArguments[0] in asApplicationKeywords or asArguments[0][-1] == "?":
      # user provided an application keyword, or requested information on something that may be one:
      sApplicationKeyword = asArguments.pop(0);
    asApplicationCommandLine = None;
    if sApplicationKeyword:
      if sApplicationKeyword[-1] == "?":
        # User requested information about a possible keyword application
        return fuShowApplicationKeyWordHelp(sApplicationKeyword[:-1]);
      # Get application command line for keyword, if available:
      if sApplicationKeyword in gdApplication_asCommandLine_by_sKeyword:
        if auApplicationProcessIds:
          print "You cannot specify process ids for application %s" % sApplicationKeyword;
          return 2;
        asApplicationCommandLine = gdApplication_asCommandLine_by_sKeyword[sApplicationKeyword];
        if sApplicationBinary:
          # Replace binary with user provided value
          asApplicationCommandLine = [sApplicationBinary] + asApplicationCommandLine[1:];
        else:
          if asApplicationCommandLine[0] is None:
            print "Application %s does not appear to be installed";
            return 2;
        if asArguments:
          # Add user provided additional application arguments:
          asApplicationCommandLine += asArguments;
        elif sApplicationKeyword in gdApplication_asDefaultAdditionalArguments_by_sKeyword:
          # Add default additional application arguments:
          asApplicationCommandLine += [
            sArgument is DEFAULT_BROWSER_TEST_URL and dxConfig["sDefaultBrowserTestURL"] or sArgument
            for sArgument in gdApplication_asDefaultAdditionalArguments_by_sKeyword[sApplicationKeyword]
          ];
      
      elif asArguments:
        print "You cannot specify arguments for application keyword %s" % sApplicationKeyword;
        return 2;
      elif not auApplicationProcessIds:
        print "You must specify process ids for application keyword %s" % sApplicationKeyword;
        return 2;
      # Apply application specific settings
      if sApplicationKeyword in gdApplication_dxSettings_by_sKeyword:
        print "* Applying application specific settings:";
        for (sSettingName, xValue) in gdApplication_dxSettings_by_sKeyword[sApplicationKeyword].items():
          if sSettingName not in dxUserProvidedConfigSettings:
            fApplyConfigSetting(sSettingName, xValue, "  "); # Apply and show result indented.
      # Apply application specific source settings
      if sApplicationKeyword in gdApplication_sURLTemplate_by_srSourceFilePath_by_sKeyword:
        dsURLTemplate_by_srSourceFilePath = gdApplication_sURLTemplate_by_srSourceFilePath_by_sKeyword[sApplicationKeyword];
      # Apply application specific stdio settings:
      if sApplicationKeyword in gdApplication_rImportantStdOutLines_by_sKeyword:
        rImportantStdOutLines = gdApplication_rImportantStdOutLines_by_sKeyword[sApplicationKeyword];
      if sApplicationKeyword in gdApplication_rImportantStdErrLines_by_sKeyword:
        rImportantStdErrLines = gdApplication_rImportantStdErrLines_by_sKeyword[sApplicationKeyword];
      if not sApplicationISA and sApplicationKeyword in gdApplication_sISA_by_sKeyword:
        # Apply application specific ISA
        sApplicationISA = gdApplication_sISA_by_sKeyword[sApplicationKeyword];
    elif auApplicationProcessIds:
      # user provided an application command-line and process ids
      print "You cannot specify both an application command-line and process ids";
      return 2;
    else:
      # user provided an application command-line
      asApplicationCommandLine = asArguments;
  
  # Apply user provided settings:
  for (sSettingName, xValue) in dxUserProvidedConfigSettings.items():
    fApplyConfigSetting(sSettingName, xValue); # Apply and show result
  
  bApplicationIsStarted = asApplicationCommandLine is None; # if we're attaching the application is already started.
  if asApplicationCommandLine:
    print "+ The debugger is starting the application...";
    print "  Command line: %s" % " ".join(asApplicationCommandLine);
  else:
    print "+ The debugger is attaching to the application...";
  oBugId = cBugId(
    sCdbISA = sApplicationISA or sOSISA,
    asApplicationCommandLine = asApplicationCommandLine or None,
    auApplicationProcessIds = auApplicationProcessIds or None,
    asSymbolServerURLs = dxConfig["asSymbolServerURLs"],
    dsURLTemplate_by_srSourceFilePath = dsURLTemplate_by_srSourceFilePath,
    rImportantStdOutLines = rImportantStdOutLines,
    rImportantStdErrLines = rImportantStdErrLines,
    bGetDetailsHTML = dxConfig["bSaveReport"],
    fApplicationRunningCallback = fApplicationRunningHandler,
    fExceptionDetectedCallback = fExceptionDetectedHandler,
    fApplicationExitCallback = fApplicationExitHandler,
    fInternalExceptionCallback = fInternalExceptionCallback,
  );
  oBugId.fWait();
  if not bApplicationIsStarted:
    print "- BugId was unable to debug the application.";
    return 3;
  elif oInternalException is not None:
    print "+ BugId run into an internal error:";
    print "  %s" % repr(oInternalException);
    print;
    print "  Please report this issue at the below web-page so it can be addressed:";
    print "  https://github.com/SkyLined/BugId/issues/new";
    return 3;
  elif oBugId.oBugReport is not None:
    print "+ A bug was detected in the application.";
    print;
    print "  === BugId report (https://github.com/SkyLined/BugId) ".ljust(80, "=");
    print "  Id:               %s" % oBugId.oBugReport.sId;
    print "  Location:         %s" % oBugId.oBugReport.sBugLocation;
    print "  Description:      %s" % oBugId.oBugReport.sBugDescription;
    print "  Version:          %s" % oBugId.oBugReport.asVersionInformation[0]; # There is always the process' binary.
    for sVersionInformation in oBugId.oBugReport.asVersionInformation[1:]: # There may be two if the crash was in a
      print "                    %s" % sVersionInformation;                # different binary (e.g. a .dll)
    if oBugId.oBugReport.sBugSourceLocation:
      print "  Source:           %s" % oBugId.oBugReport.sBugSourceLocation;
    print "  Security impact:  %s" % oBugId.oBugReport.sSecurityImpact;
    print "  Run time:         %s seconds" % (long(oBugId.fnApplicationRunTime() * 1000) / 1000.0);
    if dxConfig["bSaveReport"]:
      # We'd like a report file name base on the BugId, but the later may contain characters that are not valid in a file name
      sDesiredReportFileName = "%s @ %s.html" % (oBugId.oBugReport.sId, oBugId.oBugReport.sBugLocation);
      # Thus, we need to translate these characters to create a valid filename that looks very similar to the BugId
      sValidReportFileName = FileSystem.fsValidName(sDesiredReportFileName, bUnicode = dxConfig["bUseUnicodeReportFileNames"]);
      if dxConfig["sReportFolderPath"] is not None:
        sReportFilePath = FileSystem.fsPath(dxConfig["sReportFolderPath"], sValidReportFileName);
      else:
        sReportFilePath = FileSystem.fsPath(sValidReportFileName);
      eWriteDataToFileResult = FileSystem.feWriteDataToFile(
        oBugId.oBugReport.sDetailsHTML,
        sReportFilePath,
        fbRetryOnFailure = lambda: False,
      );
      if eWriteDataToFileResult:
        print "  Bug report:       Cannot be saved (%s)" % repr(eWriteDataToFileResult);
      else:
        print "  Bug report:       %s (%d bytes)" % (sValidReportFileName, len(oBugId.oBugReport.sDetailsHTML));
    return 1;
  else:
    print "- The application has terminated without crashing.";
    print "  Run time:         %s seconds" % (long(oBugId.fnApplicationRunTime() * 1000) / 1000.0);
    return 0;