コード例 #1
0
def fPrintVersionInformation(bCheckForUpdates, bCheckAndShowLicenses, bShowInstallationFolders):
  # Read product details for rs and all modules it uses.
  aoProductDetails = mProductDetails.faoGetProductDetailsForAllLoadedModules();
  oMainProductDetails = mProductDetails.foGetProductDetailsForMainModule();
  if bCheckForUpdates:
    uCheckedProductCounter = 0;
    for oProductDetails in aoProductDetails:
      oConsole.fProgressBar(
        uCheckedProductCounter * 1.0 / len(aoProductDetails),
        "Checking %s for updates..." % oProductDetails.sProductName,
      );
      try:
        oProductDetails.oLatestProductDetailsFromRepository;
      except Exception as oException:
        oConsole.fPrint(
          ERROR, u"- Version check for ", ERROR_INFO, oProductDetails.sProductName,
          ERROR, " failed: ", ERROR_INFO, str(oException),
        );
      uCheckedProductCounter += 1;
  oConsole.fLock();
  try:
    if bCheckAndShowLicenses:
      aoLicenses = [];
      asLicensedProductNames = [];
      asProductNamesInTrial = [];
      asUnlicensedProductNames = [];
      for oProductDetails in aoProductDetails:
        if oProductDetails.oLicense:
          if oProductDetails.oLicense not in aoLicenses:
            aoLicenses.append(oProductDetails.oLicense);
          asLicensedProductNames.append(oProductDetails.sProductName);
        elif oProductDetails.bHasTrialPeriod and oProductDetails.bInTrialPeriod:
          asProductNamesInTrial.append(oProductDetails.sProductName);
        else:
          asUnlicensedProductNames.append(oProductDetails.sProductName);

      oLicenseCheckServer = mProductDetails.cLicenseCheckServer(oMainProductDetails.sLicenseServerURL);
      uCheckedLicenseCounter = 0;
      for oLicense in aoLicenses:
        oConsole.fProgressBar(
          uCheckedLicenseCounter * 1.0 / len(aoLicenses),
          "Checking license %s with server..." % oLicense.sLicenseId,
        );
        sLicenseCheckServerError = oLicense.fsCheckWithServerAndGetError(oLicenseCheckServer, bForceCheck = True);
        if sLicenseCheckServerError:
          oConsole.fPrint(
            ERROR, u"- License check for ", ERROR_INFO, oLicense.sLicenseId,
            ERROR, " on server ", ERROR_INFO, oMainProductDetails.sLicenseServerURL,
            ERROR, " failed: ", ERROR_INFO, sLicenseCheckServerError,
          );
        uCheckedLicenseCounter += 1;
    
    oConsole.fPrint(
      u"\u250C\u2500 ", INFO, "Version information", NORMAL, " ", sPadding = u"\u2500"
    );
    # Output the BugId product information first, then its dependencies:
    fPrintProductDetails(oMainProductDetails, bIsMainProduct = True, bShowInstallationFolders = bShowInstallationFolders);
    for oProductDetails in aoProductDetails:
      if oProductDetails != oMainProductDetails:
        fPrintProductDetails(oProductDetails, bIsMainProduct = False, bShowInstallationFolders = bShowInstallationFolders);
    
    oConsole.fPrint(
      u"\u2502 \u2219 ", INFO, "Windows",
      NORMAL, " version: ", INFO, oSystemInfo.sOSName,
      NORMAL, " release ", INFO, oSystemInfo.sOSReleaseId,
      NORMAL, ", build ", INFO, oSystemInfo.sOSBuild,
      NORMAL, " ", INFO, oSystemInfo.sOSISA,
      NORMAL, ".",
    );
    oConsole.fPrint(
      u"\u2502 \u2219 ", INFO, "Python",
      NORMAL, " version: ", INFO, str(platform.python_version()),
      NORMAL, " ", INFO, fsGetPythonISA(),
      NORMAL, ".",
    );
    
    if bCheckAndShowLicenses:
      oConsole.fPrint(
        u"\u251C\u2500 ", INFO, "License information", NORMAL, " ", sPadding = u"\u2500",
      );
      if aoLicenses:
        oConsole.fPrint(
          NORMAL, u"\u2502 \u2219 This system is registered with id ", INFO, mProductDetails.fsGetSystemId(), NORMAL, " on the license server",
        );
      for oLicense in aoLicenses:
        oConsole.fPrint(
          u"\u2502 \u2219 License ", INFO, oLicense.sLicenseId,
          NORMAL, " for ", INFO, oLicense.asProductNames[0], 
          NORMAL, " covers ", INFO, oLicense.sUsageTypeDescription, 
          NORMAL, " by ", INFO, oLicense.sLicenseeName,
          NORMAL, " of the following products:",
        );
        oConsole.fPrint(u"\u2502     ", faxListOutput(oLicense.asProductNames, "and", INFO, NORMAL));
      if asProductNamesInTrial:
        oConsole.fPrint(*(
          [
            u"\u2502 \u2219 "
          ] + faxListOutput(asProductNamesInTrial, "and", WARNING_INFO, WARNING)  + [
            WARNING, " ", len(asProductNamesInTrial) == 1 and "is" or "are", " not covered by a valid, active license but ",
            len(asProductNamesInTrial) == 1 and "it is in its" or "they are in their", " trial period.",
          ]
        ));
      if asUnlicensedProductNames:
        oConsole.fPrint(*(
          [
            u"\u2502 \u2219 "
          ] + faxListOutput(asUnlicensedProductNames, "and", ERROR_INFO, ERROR)  + [
            ERROR, " ", len(asProductNamesInTrial) == 1 and "is" or "are", " not covered by a valid, active license and ",
            len(asProductNamesInTrial) == 1 and "has exceeded its" or "have exceeded their", " trial period.",
          ]
        ));
    oConsole.fPrint(
      u"\u2514", sPadding = u"\u2500",
    );
    oConsole.fPrint();
  finally:
    oConsole.fUnlock();

  (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();
  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();
コード例 #2
0
def fOutputLicenseInformation(bUpdateIfNeeded=False):
    # Read product details for rs and all modules it uses.
    aoProductDetails = mProductDetails.faoGetProductDetailsForAllLoadedModules(
    )
    o0MainProductDetails = mProductDetails.fo0GetProductDetailsForMainModule()
    oConsole.fLock()
    try:
        aoLicenses = []
        asProductNamesWithoutLicenseRequirement = []
        asLicensedProductNames = []
        asProductNamesInTrial = []
        asUnlicensedProductNames = []
        for oProductDetails in aoProductDetails:
            if not oProductDetails.bRequiresLicense:
                asProductNamesWithoutLicenseRequirement.append(
                    oProductDetails.sProductName)
            elif oProductDetails.o0License:
                if oProductDetails.o0License not in aoLicenses:
                    aoLicenses.append(oProductDetails.o0License)
                asLicensedProductNames.append(oProductDetails.sProductName)
            elif oProductDetails.bHasTrialPeriod and oProductDetails.bInTrialPeriod:
                asProductNamesInTrial.append(oProductDetails.sProductName)
            else:
                asUnlicensedProductNames.append(oProductDetails.sProductName)

        if o0MainProductDetails and o0MainProductDetails.sb0LicenseServerURL is not None:
            oLicenseServer = mProductDetails.cLicenseServer(
                o0MainProductDetails.sb0LicenseServerURL)
            uCheckedLicenseCounter = 0
            aoUpdatedLicenses = []
            for oLicense in aoLicenses:
                oConsole.fProgressBar(
                    uCheckedLicenseCounter * 1.0 / len(aoLicenses),
                    "Checking license %s with server..." % oLicense.sLicenseId,
                )
                sLicenseServerError = oLicense.fsCheckWithServerAndGetError(
                    oLicenseServer, bForceCheck=True)
                sServerURL = str(o0MainProductDetails.sb0LicenseServerURL,
                                 "ascii", "strict")
                if sLicenseServerError:
                    oConsole.fOutput(
                        COLOR_ERROR,
                        CHAR_ERROR,
                        COLOR_NORMAL,
                        " License check for ",
                        COLOR_INFO,
                        oLicense.sLicenseId,
                        COLOR_NORMAL,
                        " on server ",
                        COLOR_INFO,
                        sServerURL,
                        COLOR_NORMAL,
                        " failed:",
                    )
                    oConsole.fOutput(
                        "  ",
                        COLOR_INFO,
                        sLicenseServerError,
                    )
                uCheckedLicenseCounter += 1
                if oLicense.bMayNeedToBeUpdated and bUpdateIfNeeded:
                    oConsole.fProgressBar(
                        uCheckedLicenseCounter * 1.0 / len(aoLicenses),
                        "Downloading updated license %s from server..." %
                        oLicense.sLicenseId,
                    )
                    oUpdatedLicense = oLicenseServer.foDownloadUpdatedLicense(
                        oLicense)
                    oConsole.fOutput(
                        COLOR_OK,
                        CHAR_OK,
                        COLOR_NORMAL,
                        " Downloaded updated license ",
                        COLOR_INFO,
                        oLicense.sLicenseId,
                        COLOR_NORMAL,
                        " from server ",
                        COLOR_INFO,
                        str(oLicenseServer.sbServerURL, "ascii", "strict"),
                        COLOR_NORMAL,
                        ".",
                    )
                    aoUpdatedLicenses.append(oUpdatedLicense)
            if len(aoUpdatedLicenses) > 0:
                for oProductDetails in aoProductDetails:
                    if oProductDetails.sb0LicenseServerURL is None:
                        continue
                        # No need for a license == do not store license
                    aoUpdatedLicensesForThisProduct = [
                        oUpdatedLicense
                        for oUpdatedLicense in aoUpdatedLicenses
                        if oProductDetails.sProductName in
                        oUpdatedLicense.asProductNames
                    ]
                    mProductDetails.fWriteLicensesToProductFolder(
                        aoUpdatedLicensesForThisProduct, oProductDetails)
                    oConsole.fOutput(
                        COLOR_OK,
                        CHAR_OK,
                        COLOR_NORMAL,
                        " Saved ",
                        COLOR_INFO,
                        str(len(aoUpdatedLicensesForThisProduct)),
                        COLOR_NORMAL,
                        " updated license",
                        ""
                        if len(aoUpdatedLicensesForThisProduct) == 1 else "s",
                        " for product ",
                        COLOR_INFO,
                        oProductDetails.sProductName,
                        COLOR_NORMAL,
                        " in folder ",
                        COLOR_INFO,
                        oProductDetails.sInstallationFolderPath,
                        COLOR_NORMAL,
                        ".",
                    )

        if f0OutputLogo:
            f0OutputLogo()

        oConsole.fOutput(
            "┌───[",
            COLOR_HILITE,
            " License information ",
            COLOR_NORMAL,
            "]",
            sPadding="─",
        )
        if aoLicenses:
            oConsole.fOutput(
                "│ ",
                COLOR_OK,
                CHAR_OK,
                COLOR_NORMAL,
                " This system uses system id ",
                COLOR_INFO,
                mProductDetails.fsGetSystemId(),
                COLOR_NORMAL,
                " with the license server.",
            )
            oConsole.fOutput(
                "├",
                sPadding="─",
            )
        for oLicense in aoLicenses:
            oConsole.fOutput(
                "│ ",
                COLOR_OK,
                CHAR_OK,
                COLOR_NORMAL,
                " License ",
                COLOR_INFO,
                oLicense.sLicenseId,
                COLOR_NORMAL,
                " covers ",
                COLOR_INFO,
                oLicense.sUsageTypeDescription,
                COLOR_NORMAL,
                " by ",
                COLOR_INFO,
                oLicense.sLicenseeName,
                COLOR_NORMAL,
                " of ",
                COLOR_INFO,
                oLicense.asProductNames[0],
                COLOR_NORMAL,
                " on ",
                COLOR_INFO,
                str(oLicense.uLicensedInstances),
                COLOR_NORMAL,
                " machine",
                "s" if oLicense.uLicensedInstances != 1 else "",
                ".",
            )
            oConsole.fOutput(
                "│   Covered products: ",
                faxListOutput(oLicense.asProductNames, "and",
                              oLicense.asProductNames, COLOR_INFO,
                              COLOR_NORMAL, COLOR_NORMAL),
                COLOR_NORMAL,
                ".",
            )
            oConsole.fOutput(
                "│   License source: ",
                COLOR_INFO,
                oLicense.sLicenseSource,
                COLOR_NORMAL,
                ".",
            )
        if asProductNamesInTrial:
            oConsole.fOutput(
                "│ ",
                COLOR_WARNING,
                CHAR_WARNING,
                COLOR_NORMAL,
                " A ",
                COLOR_INFO,
                "trial period",
                COLOR_NORMAL,
                " is active for the following product",
                "s" if len(asProductNamesInTrial) > 1 else "",
                ":",
            )
            oConsole.fOutput(
                "│   ",
                faxListOutput(asProductNamesInTrial, "and",
                              asProductNamesInTrial, COLOR_INFO, COLOR_NORMAL,
                              COLOR_NORMAL),
                COLOR_NORMAL,
                ".",
            )
        if asProductNamesWithoutLicenseRequirement:
            oConsole.fOutput(
                "│ ",
                COLOR_OK,
                CHAR_OK,
                " ",
                COLOR_INFO,
                "No license",
                COLOR_NORMAL,
                " is required to use the following product",
                "s"
                if len(asProductNamesWithoutLicenseRequirement) > 1 else "",
                ":",
            )
            oConsole.fOutput(
                "│   ",
                faxListOutput(asProductNamesWithoutLicenseRequirement, "and",
                              [], COLOR_INFO, COLOR_NORMAL, COLOR_NORMAL),
                COLOR_NORMAL,
                ".",
            )
        if asUnlicensedProductNames:
            oConsole.fOutput(
                "│ ",
                COLOR_ERROR,
                CHAR_ERROR,
                COLOR_NORMAL,
                " ",
                COLOR_INFO,
                "No valid license",
                COLOR_NORMAL,
                " was found and ",
                COLOR_INFO,
                "the trial period has been exceeded",
                COLOR_NORMAL,
                " for the following product",
                "s" if len(asUnlicensedProductNames) > 1 else "",
                ":",
            )
            oConsole.fOutput(
                "│   ",
                faxListOutput(asUnlicensedProductNames, "and",
                              asUnlicensedProductNames, COLOR_INFO,
                              COLOR_NORMAL, COLOR_NORMAL),
                COLOR_NORMAL,
                ".",
            )

        (asLicenseErrors, asLicenseWarnings
         ) = mProductDetails.ftasGetLicenseErrorsAndWarnings()
        if asLicenseErrors:
            oConsole.fOutput("├───[",
                             COLOR_ERROR,
                             " Software license error ",
                             COLOR_NORMAL,
                             "]",
                             sPadding="─")
            for sLicenseError in asLicenseErrors:
                oConsole.fOutput("│ ", COLOR_ERROR, CHAR_ERROR, COLOR_INFO,
                                 " ", sLicenseError)
        if asLicenseWarnings:
            oConsole.fOutput("├───[",
                             COLOR_WARNING,
                             " Software license warning ",
                             COLOR_NORMAL,
                             "]",
                             sPadding="─")
            for sLicenseWarning in asLicenseWarnings:
                oConsole.fOutput("│ ", COLOR_WARNING, CHAR_WARNING, COLOR_INFO,
                                 " ", sLicenseWarning)
        oConsole.fOutput("└", sPadding="─")
    finally:
        oConsole.fUnlock()
コード例 #3
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!");
コード例 #4
0
ファイル: BugId.py プロジェクト: andigena/BugId
def fMain(asArguments):
    global \
        gasAttachToProcessesForExecutableNames, \
        gasBinaryNamesThatAreAllowedToRunWithoutPageHeap, \
        gbQuiet, \
        gbVerbose, \
        guDetectedBugsCount, \
        guMaximumNumberOfBugs
    # 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
    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 an UWP application package name.")
                    oConsole.fCleanup()
                    os._exit(2)
                if sUWPApplicationPackageName is not None:
                    oConsole.fPrint(
                        ERROR,
                        "- You cannot provide multiple UWP application package names."
                    )
                    oConsole.fCleanup()
                    os._exit(2)
                if sApplicationBinaryPath is not None:
                    oConsole.fPrint(
                        ERROR,
                        "- You cannot provide an application binary and UWP package name."
                    )
                    oConsole.fCleanup()
                    os._exit(2)
                if len(auApplicationProcessIds) > 0:
                    oConsole.fPrint(
                        ERROR,
                        "- You cannot provide process ids and an UWP application package name."
                    )
                    oConsole.fCleanup()
                    os._exit(2)
                if "!" not in sValue:
                    oConsole.fPrint(ERROR, "- Please provide a string of the form ", ERROR_INFO, sSettingName, \
                        "=<package name>!<application id>.")
                    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 ["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:
                    # -- 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 mFileSystem.fbIsFolder(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, "=", 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 "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()
        oConsole.fCleanup()
        os._exit(2)

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

    # 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:
        duNumberOfRepros_by_sBugIdAndLocation = {}
        sValidStatisticsFileName = mFileSystem.fsValidName(
            "Reproduction statistics.txt")
    uRunCounter = 0
    while 1:  # Will only loop if bRepeat is True
        nStartTime = 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=sApplicationISA or cBugId.sOSISA,
            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("Process attached", fProcessAttachedCallback)
        oBugId.fAddEventCallback("Process started", fProcessStartedCallback)
        oBugId.fAddEventCallback("Process terminated",
                                 fProcessTerminatedCallback)

        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:
            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")
            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:
            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)
        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
    raise AssertionError("Not reached!")