Пример #1
0
def fPrintLogo():
  # We will use the above ASCII and color data to create a list of arguments
  # that can be passed to oConsole.fPrint in order to output the logo in color:
  oConsole.fLock();
  try:
    for uLineIndex in xrange(len(asBugIdLogo)):
      uCurrentColor = NORMAL;
      bUnderlined = False;
      asBugIdLogoPrintArguments = [""];
      sCharsLine = asBugIdLogo[uLineIndex];
      sColorsLine = asBugIdLogoColors[uLineIndex];
      uColorIndex = 0;
      for uColumnIndex in xrange(len(sCharsLine)):
        sColor = sColorsLine[uColorIndex];
        uColorIndex += 1;
        if sColor == "_":
          bUnderlined = not bUnderlined;
          sColor = sColorsLine[uColorIndex];
          uColorIndex += 1;
        uColor = (sColor != " " and (0x0F00 + long(sColor, 16)) or NORMAL) + (bUnderlined and UNDERLINE or 0);
        if uColor != uCurrentColor:
          asBugIdLogoPrintArguments.extend([uColor, ""]);
          uCurrentColor = uColor;
        sChar = sCharsLine[uColumnIndex];
        asBugIdLogoPrintArguments[-1] += sChar;
      oConsole.fPrint(*asBugIdLogoPrintArguments);
  finally:
    oConsole.fUnlock();
Пример #2
0
def fPrintLogo():
    # We will use the above ASCII and color data to create a list of arguments
    # that can be passed to oConsole.fPrint in order to output the logo in color:
    oConsole.fLock()
    try:
        for uLineIndex in xrange(len(asBugIdLogo)):
            iLastColor = -1
            asBugIdLogoPrintArguments = [""]
            sCharsLine = asBugIdLogo[uLineIndex]
            sColorsLine = asBugIdLogoColors[uLineIndex]
            for uColumnIndex in xrange(len(sCharsLine)):
                sColor = sColorsLine[uColumnIndex]
                iColor = sColor == " " and -1 or int("F0" + sColor, 16)
                if iColor != iLastColor:
                    asBugIdLogoPrintArguments.extend([iColor, ""])
                    iColor = iLastColor
                sChar = sCharsLine[uColumnIndex]
                asBugIdLogoPrintArguments[-1] += sChar
            oConsole.fPrint(*asBugIdLogoPrintArguments)
        if dxConfig["bShowLicenseAndDonationInfo"]:
            oConsole.fPrint()
            for asLicenseAndDonationInfoPrintArguments in aasLicenseAndDonationInfoPrintArguments:
                oConsole.fPrint(*asLicenseAndDonationInfoPrintArguments)
            oConsole.fPrint()
    finally:
        oConsole.fUnlock()
Пример #3
0
def fFailedToDebugApplicationCallback(oBugId, sErrorMessage):
  global gbAnErrorOccured;
  gbAnErrorOccured = True;
  oConsole.fLock();
  try:
    oConsole.fPrint(ERROR, u"\u250C\u2500", ERROR_INFO, " Failed to debug the application ", ERROR, sPadding = u"\u2500");
    for sLine in sErrorMessage.split("\n"):
      oConsole.fPrint(ERROR, u"\u2502 ", ERROR_INFO, sLine.rstrip("\r"));
    oConsole.fPrint(ERROR, u"\u2514", sPadding = u"\u2500");
    oConsole.fPrint();
  finally:
    oConsole.fUnlock();
Пример #4
0
def fFailedToDebugApplicationCallback(oBugId, sErrorMessage):
  global gbAnErrorOccured;
  gbAnErrorOccured = True;
  oConsole.fLock();
  try:
    oConsole.fPrint(ERROR, "-" * 80);
    oConsole.fPrint(ERROR, "- Failed to debug the application:");
    for sLine in sErrorMessage.split("\n"):
      oConsole.fPrint(ERROR, "  ", sLine.rstrip("\r"));
    oConsole.fPrint(ERROR, "-" * 80);
    oConsole.fPrint();
  finally:
    oConsole.fUnlock();
Пример #5
0
def fCheckPythonVersion(sApplicationName, asTestedPythonVersions, sBugURL):
  sPythonVersion = platform.python_version();
  uMajorVersion, uMinorVersion, uMicroVersion = [long(s) for s in sPythonVersion.split(".")];
  auTestedMajorVersions = set();
  bRunningInTestedMajorVersion = False;
  bRunningInTestedVersion = False;
  bRunningInOlderVersion = False;
  for sTestedPythonVersion in asTestedPythonVersions:
    uTestedMajorVersion, uTestedMinorVersion, uTestedMicroVersion = [long(s) for s in sTestedPythonVersion.split(".")];
    auTestedMajorVersions.add(uTestedMajorVersion);
    if uMajorVersion == uTestedMajorVersion:
      bRunningInTestedMajorVersion = True;
      if uMinorVersion == uTestedMinorVersion:
        if uMicroVersion == uTestedMicroVersion:
          # We are running in a tested Python version.
          bRunningInTestedVersion = True;
        elif uMicroVersion < uTestedMicroVersion:
          # This application was tested in a later version, so the version we are running in is outdated.
          bRunningInOlderVersion = True;
      elif uMinorVersion < uTestedMinorVersion:
        # This application was tested in a later version, so the version we are running in is outdated.
        bRunningInOlderVersion = True;
  if not bRunningInTestedMajorVersion:
    asTestedMayorVersions = [str(u) for u in auTestedMajorVersions];
    oConsole.fPrint(ERROR, "Error: rs requires ", ERROR_INFO, "Python %s" % faxListOutput(asMayorVersions, "or", ERROR_INFO, ERROR), ".");
    os._exit(3);
  if not bRunningInTestedVersion:
    oConsole.fLock();
    try:
      oConsole.fPrint(WARNING, u"\u250C\u2500", WARNING_INFO, " Warning ", WARNING, sPadding = u"\u2500");
      oConsole.fPrint(WARNING, u"\u2502 You are running ", "an older" if bRunningInOlderVersion else "a newer", " version of Python (", WARNING_INFO, sPythonVersion, WARNING,
          ") in which this version of");
      oConsole.fPrint(WARNING, u"\u2502 ", sApplicationName, " ", "was never tested" if bRunningInOlderVersion else "has not been tested yet", ". The following Python versions have been tested:");
      oConsole.fPrint(WARNING, u"\u2502   ", faxListOutput(asTestedPythonVersions, "and", WARNING_INFO, WARNING), ".");
      if bRunningInOlderVersion:
        oConsole.fPrint(WARNING, u"\u2502 Please update Python to the latest version!");
      else:
        oConsole.fPrint(WARNING, u"\u2502 Please report this so %s can be tested with this version of Python at:" % sApplicationName);
        oConsole.fPrint(WARNING, u"\u2502   ", WARNING_INFO | UNDERLINE, sBugURL);
      oConsole.fPrint(WARNING, u"\u2514", sPadding = u"\u2500");
    finally:
      oConsole.fUnlock();
  elif bRunningInOlderVersion:
    oConsole.fLock();
    try:
      oConsole.fPrint(WARNING, u"\u250C\u2500", WARNING_INFO, " Warning ", WARNING, sPadding = u"\u2500");
      oConsole.fPrint(WARNING, u"\u2502 You are running Python ", WARNING_INFO, sPythonVersion, WARNING, ", which is outdated.");
      oConsole.fPrint(WARNING, u"\u2502 Please update Python to the latest version!");
      oConsole.fPrint(WARNING, u"\u2514", sPadding = u"\u2500");
    finally:
      oConsole.fUnlock();
Пример #6
0
def fLicenseErrorsCallback(oBugId, asErrors):
  # These should have been reported before cBugId was even instantiated, so this is kind of unexpected.
  # But rather than raise AssertionError("NOT REACHED"), we'll report the license error gracefully:
  global gbAnErrorOccured;
  gbAnErrorOccured = True;
  oConsole.fLock();
  try:
    oConsole.fPrint(ERROR, u"\u250C\u2500", ERROR_INFO, " Software license error ", ERROR, sPadding = u"\u2500");
    for sError in asErrors:
      oConsole.fPrint(ERROR, u"\u2502 ", ERROR_INFO, sError);
    oConsole.fPrint(ERROR, u"\u2514", sPadding = u"\u2500");
  finally:
    oConsole.fUnlock();
  os._exit(5);
Пример #7
0
def fBugReportCallback(oBugId, oBugReport):
  global guDetectedBugsCount, \
         guMaximumNumberOfBugs, \
         gduNumberOfRepros_by_sBugIdAndLocation;
  guDetectedBugsCount += 1;
  oConsole.fLock();
  try:
    oConsole.fPrint(u"\u250C\u2500 ", HILITE, "A bug was detected ", NORMAL, sPadding = u"\u2500");
    if oBugReport.sBugLocation:
      oConsole.fPrint(u"\u2502 Id @ Location:    ", INFO, oBugReport.sId, NORMAL, " @ ", INFO, oBugReport.sBugLocation);
      sBugIdAndLocation = "%s @ %s" % (oBugReport.sId, oBugReport.sBugLocation);
    else:
      oConsole.fPrint(u"\u2502 Id:               ", INFO, oBugReport.sId);
      sBugIdAndLocation = oBugReport.sId;
    gduNumberOfRepros_by_sBugIdAndLocation.setdefault(sBugIdAndLocation, 0);
    gduNumberOfRepros_by_sBugIdAndLocation[sBugIdAndLocation] += 1;
    if oBugReport.sBugSourceLocation:
      oConsole.fPrint(u"\u2502 Source:           ", INFO, oBugReport.sBugSourceLocation);
    oConsole.fPrint(u"\u2502 Description:      ", INFO, oBugReport.sBugDescription);
    oConsole.fPrint(u"\u2502 Security impact:  ", INFO, (oBugReport.sSecurityImpact or "None"));
    oConsole.fPrint(u"\u2502 Version:          ", NORMAL, oBugReport.asVersionInformation[0]); # The process' binary.
    for sVersionInformation in oBugReport.asVersionInformation[1:]: # There may be two if the crash was in a
      oConsole.fPrint(u"\u2502                   ", NORMAL, sVersionInformation); # different binary (e.g. a .dll)
    if dxConfig["bGenerateReportHTML"]:
      # Use a report file name base on the BugId.
      sDesiredReportFileName = "%s.html" % sBugIdAndLocation;
      # In collateral mode, we will number the reports so you know in which order bugs were reported.
      if guMaximumNumberOfBugs > 1:
        sDesiredReportFileName = "#%d %s" % (guDetectedBugsCount, sDesiredReportFileName);
      # Translate characters that are not valid in file names.
      sValidReportFileName = mFileSystem2.fsGetValidName(sDesiredReportFileName, bUnicode = \
          dxConfig["bUseUnicodeReportFileNames"]);
      if dxConfig["sReportFolderPath"] is not None:
        sReportFilePath = os.path.join(dxConfig["sReportFolderPath"], sValidReportFileName);
      else:
        sReportFilePath = sValidReportFileName;
      oReportFile = None;
      try:
        oReportFile = mFileSystem2.foGetOrCreateFile(sReportFilePath);
        oReportFile.fWrite(oBugReport.sReportHTML);
      except Exception as oException:
        oConsole.fPrint(u"\u2502 Bug report:       ", ERROR, "Cannot be saved (", ERROR_INFO, str(oException), ERROR, ")");
      else:
        oConsole.fPrint(u"\u2502 Bug report:       ", NORMAL, sValidReportFileName, " (%d bytes)" % len(oBugReport.sReportHTML));
      if oReportFile:
        oReportFile.fClose();
    oConsole.fPrint(u"\u2514", sPadding = u"\u2500");
  finally:
    oConsole.fUnlock();
Пример #8
0
def fBugReportCallback(oBugId, oBugReport):
  global \
      guDetectedBugsCount, \
      guMaximumNumberOfBugs;
  guDetectedBugsCount += 1;
  oConsole.fLock();
  try:
    oConsole.fPrint(u"\u250C\u2500 ", HILITE, "A bug was detect in the application ", NORMAL, sPadding = u"\u2500");
    if oBugReport.sBugLocation:
      oConsole.fPrint(u"\u2502 Id @ Location:    ", INFO, oBugReport.sId, NORMAL, " @ ", INFO, oBugReport.sBugLocation);
      sBugIdAndLocation = "%s @ %s" % (oBugReport.sId, oBugReport.sBugLocation);
    else:
      oConsole.fPrint(u"\u2502 Id:               ", INFO, oBugReport.sId);
      sBugIdAndLocation = oBugReport.sId;
    if oBugReport.sBugSourceLocation:
      oConsole.fPrint(u"\u2502 Source:           ", INFO, oBugReport.sBugSourceLocation);
    oConsole.fPrint(u"\u2502 Description:      ", INFO, oBugReport.sBugDescription);
    oConsole.fPrint(u"\u2502 Security impact:  ", INFO, oBugReport.sSecurityImpact);
    oConsole.fPrint(u"\u2502 Version:          ", NORMAL, oBugReport.asVersionInformation[0]); # The process' binary.
    for sVersionInformation in oBugReport.asVersionInformation[1:]: # There may be two if the crash was in a
      oConsole.fPrint(u"\u2502                   ", NORMAL, sVersionInformation); # different binary (e.g. a .dll)
    if dxConfig["bGenerateReportHTML"]:
      # Use a report file name base on the BugId.
      sDesiredReportFileName = "%s.html" % sBugIdAndLocation;
      # In collateral mode, we will number the reports so you know in which order bugs were reported.
      if guMaximumNumberOfBugs > 1:
        sDesiredReportFileName = "#%d %s" % (guDetectedBugsCount, sDesiredReportFileName);
      # Translate characters that are not valid in file names.
      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(
        oBugReport.sReportHTML,
        sReportFilePath,
        fbRetryOnFailure = lambda: False,
      );
      if eWriteDataToFileResult:
        oConsole.fPrint(u"\u2502 Bug report:       ", ERROR, "Cannot be saved (", \
            ERROR_INFO, repr(eWriteDataToFileResult), ERROR, ")");
      else:
        oConsole.fPrint(u"\u2502 Bug report:       ", NORMAL, sValidReportFileName,  \
            " (%d bytes)" % len(oBugReport.sReportHTML));
    oConsole.fPrint(u"\u2516", sPadding = u"\u2500");
  finally:
    oConsole.fUnlock();
Пример #9
0
def fApplicationDebugOutputCallback(oBugId, oProcess, bIsMainProcess, asMessages):
  uCount = 0;
  sDebug = "debug";
  oConsole.fLock();
  for sMessage in asMessages:
    uCount += 1;
    if uCount == 1:
      sHeader = "*";
      sPrefix = "\u2500" if len(asMessages) == 1 else u"\u252c";       # "---" or "-.-"
    else:
      sHeader = None;
      sPrefix = u"\u2514" if uCount == len(asMessages) else u"\u2502"; # " '-" or " | " 
    fPrintMessageForProcess(sHeader, oProcess, bIsMainProcess,
      INFO, sDebug, NORMAL, sPrefix, HILITE, sMessage,
    );
    sDebug = "     ";
  oConsole.fUnlock();
Пример #10
0
def fCdbISANotIdealCallback(oBugId, oProcess, bIsMainProcess, sCdbISA, bPreventable):
  global \
      gasBinaryNamesThatAreAllowedToRunWithNonIdealCdbISA, \
      gasReportedBinaryNameWithNonIdealCdbISA, \
      gbAnErrorOccured;
  sBinaryName = oProcess.sBinaryName;
  if sBinaryName.lower() in gasBinaryNamesThatAreAllowedToRunWithNonIdealCdbISA:
    return;
  if not bPreventable:
    if not gbQuiet and sBinaryName not in gasReportedBinaryNameWithNonIdealCdbISA:
      gasReportedBinaryNameWithNonIdealCdbISA.append(sBinaryName);
      oConsole.fLock();
      try:
        oConsole.fPrint(
          WARNING, "- You are debugging an ",
          WARNING_INFO, oProcess.sISA, WARNING, " process running ",
          WARNING_INFO, sBinaryName, WARNING, " with a ",
          WARNING_INFO, sCdbISA, WARNING, " cdb.exe."
        );
        oConsole.fPrint("  This appears to be due to the application running both x86 and x64 processes.");
        oConsole.fPrint("  Unfortunately, this means use-after-free bugs in this process may be reported");
        oConsole.fPrint("  as attempts to access reserved memory regions, which is tecnically true but");
        oConsole.fPrint("  not as accurate as you might expect.");
        oConsole.fPrint();
      finally:
        oConsole.fUnlock();
  else:
    gbAnErrorOccured = True;
    oConsole.fLock();
    try:
      oConsole.fPrint(
        ERROR, "- You are debugging an ",
        ERROR_INFO, oProcess.sISA, WARNING, " process running ",
        ERROR_INFO, sBinaryName, WARNING, " with a ",
        ERROR_INFO, sCdbISA, WARNING, " cdb.exe."
      );
      oConsole.fPrint(
        "  You should use the ", INFO, "--isa=", oProcess.sISA, NORMAL, " command line argument to let BugId know",
        "it should be using a ", oProcess.sISA, " cdb.exe.");
      oConsole.fPrint("  Please restart BugId with the aboce command line argument to try again.");
      oConsole.fPrint();
      oConsole.fStatus(INFO, "* BugId is stopping...");
    finally:
      oConsole.fUnlock();
    # There is no reason to run without page heap, so terminated.
    oBugId.fStop();
Пример #11
0
def fPrintExceptionInformation(oException, oTraceback):
    fConsoleOutputExceptionDetails(oException, o0Traceback=oTraceback)
    oConsole.fLock()
    try:
        oConsole.fPrint()
        oConsole.fPrint(
            "Please report the above details at the below web-page so it can be addressed:"
        )
        oConsole.fPrint(INFO,
                        "    https://github.com/SkyLined/BugId/issues/new")
        oConsole.fPrint(
            "If you do not have a github account, or you want to report this issue"
        )
        oConsole.fPrint("privately, you can also send an email to:")
        oConsole.fPrint(INFO, "    [email protected]")
        oConsole.fPrint()
        oConsole.fPrint(
            "In your report, please copy the information about the exception reported"
        )
        oConsole.fPrint(
            "above, as well as the stack trace and BugId version information. This makes"
        )
        oConsole.fPrint(
            "it easier to determine the cause of this issue and makes for faster fixes."
        )
        oConsole.fPrint()
        if not any([
                sVerbose in sys.argv[1:]
                for sVerbose in ["-v", "/v", "-V", "/V", "--verbose=true"]
        ]):
            oConsole.fPrint(
                "If you can reproduce the issue, it would help a lot if you can run BugId in"
            )
            oConsole.fPrint("verbose mode by adding the ", INFO, "--verbose",
                            NORMAL, " command-line argument.")
            oConsole.fPrint("as in: ", HILITE, "BugId -v ",
                            " ".join(sys.argv[1:]))
            oConsole.fPrint()
        fPrintVersionInformation(
            bCheckForUpdates=False,
            bCheckAndShowLicenses=False,
            bShowInstallationFolders=False,
        )
        oConsole.fPrint("Thank you in advance for helping to improve BugId!")
    finally:
        oConsole.fUnlock()
Пример #12
0
def fPrintExceptionInformation(oException, oTraceBack):
  import os, sys, traceback;
  oConsole.fLock();
  try:
    oConsole.fPrint(ERROR, u"\u250C\u2500", ERROR_INFO, " An internal exception has occured ", ERROR, sPadding = u"\u2500");
    oConsole.fPrint(ERROR, u"\u2502 ", ERROR_INFO, repr(oException));
    oConsole.fPrint(ERROR, u"\u2502");
    oConsole.fPrint(ERROR, u"\u2502  Stack:");
    atxStack = traceback.extract_tb(oTraceBack);
    uFrameIndex = 0;
    for (sFileName, uLineNumber, sFunctionName, sCode) in reversed(atxStack):
      asSource = [ERROR_INFO, sFileName, ERROR, "/", str(uLineNumber)];
      if sFunctionName != "<module>":
        asSource = [HILITE, sFunctionName, ERROR, " @ "] + asSource;
      oConsole.fPrint(ERROR, u"\u2502 %3d " % uFrameIndex, *asSource);
      if sCode:
        oConsole.fPrint(ERROR, u"\u2502      > ", NORMAL, sCode.strip(), uConvertTabsToSpaces = 2);
      uFrameIndex += 1;
    oConsole.fPrint(ERROR, u"\u2514", sPadding = u"\u2500");
    oConsole.fPrint();
    oConsole.fPrint("Please report the above details at the below web-page so it can be addressed:");
    oConsole.fPrint(INFO, "    https://github.com/SkyLined/BugId/issues/new");
    oConsole.fPrint("If you do not have a github account, or you want to report this issue");
    oConsole.fPrint("privately, you can also send an email to:");
    oConsole.fPrint(INFO, "    [email protected]");
    oConsole.fPrint();
    oConsole.fPrint("In your report, please copy the information about the exception reported");
    oConsole.fPrint("above, as well as the stack trace and BugId version information. This makes");
    oConsole.fPrint("it easier to determine the cause of this issue and makes for faster fixes.");
    oConsole.fPrint();
    if "-v" not in sys.argv[1:] and "/v" not in sys.argv[1:] and "--verbose=true" not in sys.argv[1:]:
      oConsole.fPrint("If you can reproduce the issue, it would help a lot if you can run BugId in");
      oConsole.fPrint("verbose mode by adding the ", INFO, "--verbose", NORMAL, " command-line argument.");
      oConsole.fPrint("as in: ", HILITE, "BugId -v ", " ".join(sys.argv[1:]));
      oConsole.fPrint();
    fPrintVersionInformation(
      bCheckForUpdates = False,
      bCheckAndShowLicenses = False,
      bShowInstallationFolders = False,
    );
    oConsole.fPrint();
    oConsole.fPrint("Thank you in advance for helping to improve BugId!");
  finally:
    oConsole.fUnlock();
Пример #13
0
def fVersionCheck():
    import os, platform, sys
    oConsole.fLock()
    try:
        oConsole.fPrint("+ ", INFO, "Windows", NORMAL, " version: ", INFO, mWindowsAPI.oWindowsVersion.sProductName, \
          NORMAL, " release ", INFO, mWindowsAPI.oWindowsVersion.sReleaseId, NORMAL, ", build ", INFO, \
          mWindowsAPI.oWindowsVersion.sCurrentBuild, NORMAL, " ", INFO, mWindowsAPI.oWindowsVersion.sISA, NORMAL, ".")
        oConsole.fPrint("+ ", INFO, "Python", NORMAL, " version: ", INFO, str(platform.python_version()), NORMAL, " ", \
          INFO, mWindowsAPI.fsGetPythonISA(), NORMAL, ".")
        axModules = [
            ("BugId", "__main__", oVersionInformation),
            ("cBugId", "cBugId", cBugId.oVersionInformation),
            ("mFileSystem", "mFileSystem", mFileSystem.oVersionInformation),
            ("mWindowsAPI", "mWindowsAPI", mWindowsAPI.oVersionInformation),
            ("oConsole", "oConsole", oConsole.oVersionInformation),
        ]
        uCounter = 0
        for (sModuleName, sSysModuleName,
             oModuleVersionInformation) in axModules:
            assert sModuleName == oModuleVersionInformation.sProjectName, \
                "Module %s reports that it is called %s" % (sModuleName, oModuleVersionInformation.sProjectName)
            sInstallationPath = os.path.dirname(
                sys.modules[sSysModuleName].__file__)
            oConsole.fPrint("+ ", INFO, oModuleVersionInformation.sProjectName, NORMAL, " version: ", INFO, \
                oModuleVersionInformation.sCurrentVersion, NORMAL, ", installed at ", INFO, sInstallationPath, NORMAL, ".")
            oConsole.fProgressBar(uCounter * 1.0 / len(axModules), \
                "* Checking %s for updates..." % oModuleVersionInformation.sProjectName)
            if oModuleVersionInformation.bPreRelease:
                oConsole.fPrint("  You are running a ", HILITE, "pre-release",
                                NORMAL, " version: ",
                                "the latest release version is ", INFO,
                                oModuleVersionInformation.sLatestVersion,
                                NORMAL, ".")
            elif not oModuleVersionInformation.bUpToDate:
                oConsole.fPrint("  Version ", HILITE,
                                oModuleVersionInformation.sLatestVersion,
                                NORMAL, " is available at ", HILITE,
                                oModuleVersionInformation.sUpdateURL, NORMAL,
                                ".")
            uCounter += 1
        oConsole.fPrint()
    finally:
        oConsole.fUnlock()
Пример #14
0
def fuShowApplicationKeyWordHelp(sApplicationKeyword):
  if sApplicationKeyword not in asApplicationKeywords:
    oConsole.fPrint(ERROR, "- Unknown application keyword ", ERROR_INFO, sApplicationKeyword, ERROR, ".");
    return 2;
  oConsole.fPrint("Known application settings for ", sApplicationKeyword);
  if sApplicationKeyword in gdApplication_sBinaryPath_by_sKeyword:
    if gdApplication_sBinaryPath_by_sKeyword[sApplicationKeyword] is None:
      oConsole.fPrint(ERROR, "  The application cannot be found on your system.");
    else:
      oConsole.fPrint("  Binary path: ", INFO, gdApplication_sBinaryPath_by_sKeyword[sApplicationKeyword]);
  elif sApplicationKeyword in gsUWPApplicationPackageName_by_sKeyword:
    oConsole.fLock();
    try:
      oConsole.fPrint("  UWP Application information:");
      oConsole.fPrint("    Package name: ", INFO, gsUWPApplicationPackageName_by_sKeyword[sApplicationKeyword]);
      oConsole.fPrint("    Id: ", INFO, gsUWPApplicationId_by_sKeyword[sApplicationKeyword]);
      if sApplicationKeyword in gasApplicationAttachToProcessesForExecutableNames_by_sKeyword:
        oConsole.fPrint("    Attach to additional processes running any of the following binaries:");
        for sBinaryName in gasApplicationAttachToProcessesForExecutableNames_by_sKeyword[sApplicationKeyword]:
          oConsole.fPrint("      ", INFO, sBinaryName);
    finally:
      oConsole.fUnlock();
  if sApplicationKeyword in gdApplication_fasGetStaticArguments_by_sKeyword:
    fasGetStaticArguments = gdApplication_fasGetStaticArguments_by_sKeyword[sApplicationKeyword];
    oConsole.fPrint("  Default static arguments: ", INFO, " ".join(
      fasGetStaticArguments(bForHelp = True))
    );
  if sApplicationKeyword in gdApplication_asDefaultOptionalArguments_by_sKeyword:
    oConsole.fPrint("  Default optional arguments: ", INFO, " ".join([
      sArgument is DEFAULT_BROWSER_TEST_URL and dxConfig["sDefaultBrowserTestURL"] or sArgument
      for sArgument in gdApplication_asDefaultOptionalArguments_by_sKeyword[sApplicationKeyword]
    ]));
  if sApplicationKeyword in gdApplication_dxSettings_by_sKeyword:
    oConsole.fLock();
    try:
      oConsole.fPrint("  Application specific settings:");
      for sSettingName, xValue in gdApplication_dxSettings_by_sKeyword[sApplicationKeyword].items():
        oConsole.fPrint("    ", HILITE, sSettingName, NORMAL, " = ", INFO, json.dumps(xValue));
    finally:
      oConsole.fUnlock();
  return 0;
Пример #15
0
def fPageHeapNotEnabledCallback(oBugId, uProcessId, sBinaryName, sCommandLine, bIsMainProcess, bPreventable):
  global \
      gasAttachToProcessesForExecutableNames, \
      gasBinaryNamesThatAreAllowedToRunWithoutPageHeap, \
      gasReportedBinaryNameWithoutPageHeap, \
      gbAnErrorOccured;
  if sBinaryName.lower() in gasBinaryNamesThatAreAllowedToRunWithoutPageHeap:
    return;
  if not bPreventable:
    if not gbQuiet and sBinaryName not in gasReportedBinaryNameWithoutPageHeap:
      gasReportedBinaryNameWithoutPageHeap.append(sBinaryName);
      oConsole.fLock();
      try:
        oConsole.fPrint(ERROR,"- Full page heap is not enabled for ", ERROR_INFO, sBinaryName, ERROR,".");
        oConsole.fPrint("  This appears to be due to a bug in page heap that prevents it from");
        oConsole.fPrint("  determining the binary name correctly. Unfortunately, there is no known fix");
        oConsole.fPrint("  or work-around for this. BugId will continue, but detection and analysis of");
        oConsole.fPrint("  any bugs in this process will be sub-optimal.");
        oConsole.fPrint();
      finally:
        oConsole.fUnlock();
  else:
    gbAnErrorOccured = True;
    oConsole.fLock();
    try:
      oConsole.fPrint(ERROR, "- Full page heap is not enabled for all binaries used by the application.");
      oConsole.fPrint(ERROR, "  Specifically it is not enabled for ", ERROR_INFO, sBinaryName, ERROR,".");
      oConsole.fPrint("  You can enabled full page heap for ", sBinaryName, " by running:");
      oConsole.fPrint();
      oConsole.fPrint("      ", INFO, 'PageHeap.cmd "', sBinaryName, '" ON');
      oConsole.fPrint();
      oConsole.fPrint("  Without page heap enabled, detection and anaylsis of any bugs will be sub-");
      oConsole.fPrint("  optimal. Please enable page heap and try again.");
      oConsole.fPrint();
      oConsole.fStatus(INFO, "* BugId is stopping...");
    finally:
      oConsole.fUnlock();
    # There is no reason to run without page heap, so terminated.
    oBugId.fStop();
Пример #16
0
def fPrintApplicationKeyWordHelp(sApplicationKeyword, dxApplicationSettings):
  oConsole.fLock();
  try:
    oConsole.fPrint("Known application settings for ", INFO, sApplicationKeyword);
    if "sBinaryPath" in dxApplicationSettings:
      sBinaryPath = dxApplicationSettings["sBinaryPath"];
      if sBinaryPath is None:
        oConsole.fPrint(ERROR, "  The application cannot be found on your system.");
      else:
        oConsole.fPrint("  Binary path: ", INFO, sBinaryPath);
    elif "dxUWPApplication" in dxApplicationSettings:
      dxUWPApplication = dxApplicationSettings["dxUWPApplication"];
      oConsole.fPrint("  UWP Application information:");
      oConsole.fPrint("    Package name: ", INFO, dxUWPApplication["sPackageName"]);
      oConsole.fPrint("    Id: ", INFO, dxUWPApplication["sId"]);
    if "asApplicationAttachToProcessesForExecutableNames" in dxApplicationSettings:
      asApplicationAttachToProcessesForExecutableNames = dxApplicationSettings["asApplicationAttachToProcessesForExecutableNames"];
      oConsole.fPrint("  Attach to additional processes running any of the following binaries:");
      for sBinaryName in asApplicationAttachToProcessesForExecutableNames:
        oConsole.fPrint("    ", INFO, sBinaryName);
    if "fasGetStaticArguments" in dxApplicationSettings:
      fasGetApplicationStaticArguments = dxApplicationSettings["fasGetStaticArguments"];
      asApplicationStaticArguments = fasGetApplicationStaticArguments(bForHelp = True);
      oConsole.fPrint("  Default static arguments:");
      oConsole.fPrint("    ", INFO, " ".join(asApplicationStaticArguments));
    if "fasGetOptionalArguments" in dxApplicationSettings:
      fasGetOptionalArguments = dxApplicationSettings["fasGetOptionalArguments"];
      asApplicationOptionalArguments = fasGetOptionalArguments(bForHelp = True);
      oConsole.fPrint("  Default optional arguments:");
      oConsole.fPrint("    ", INFO, " ".join(asApplicationOptionalArguments));
    if "dxConfigSettings" in dxApplicationSettings:
      dxApplicationConfigSettings = dxApplicationSettings["dxConfigSettings"];
      if dxApplicationConfigSettings:
        oConsole.fPrint("  Application specific settings:");
        for sSettingName, xValue in dxApplicationConfigSettings.items():
          oConsole.fPrint("    ", INFO, sSettingName, NORMAL, ": ", INFO, json.dumps(xValue));
  finally:
    oConsole.fUnlock();
Пример #17
0
def fPrintUsage(asApplicationKeywords):
    oConsole.fLock()
    try:
        oConsole.fPrint(HILITE, "Usage:")
        oConsole.fPrint()
        oConsole.fPrint(
            INFO,
            "  BugId.py [options] \"path\\to\\binary.exe\" [-- argument [argument [...]]]"
        )
        oConsole.fPrint(
            "    Start the binary in the debugger with the provided arguments."
        )
        oConsole.fPrint()
        oConsole.fPrint(INFO, "  BugId.py [options] --pids=pid[,pid[...]]")
        oConsole.fPrint(
            "    Attach debugger to the process(es) provided in the list. The processes must"
        )
        oConsole.fPrint(
            "    all have been suspended, as they will be resumed by the debugger."
        )
        oConsole.fPrint()
        oConsole.fPrint(
            INFO,
            "  BugId.py [options] --package=[full package name] [-- argument]")
        oConsole.fPrint(
            "    Start and debug the Universal Windows App specified through its package"
        )
        oConsole.fPrint("    name with the provided argument.")
        oConsole.fPrint()
        oConsole.fPrint(
            INFO,
            "  BugId.py [options] application [options] [-- argument [argument [...]]]"
        )
        oConsole.fPrint(
            "    (Where \"application\" is a known application keyword, see below)"
        )
        oConsole.fPrint(
            "    BugId has a list of known applications for which it has specific settings,"
        )
        oConsole.fPrint(
            "    can automatically find the binary on your system, or knows the package name,"
        )
        oConsole.fPrint(
            "    and knows what arguments you will probably want to supply. This makes it a"
        )
        oConsole.fPrint(
            "    lot easier to start an application and apply common settings."
        )
        oConsole.fPrint(
            "    You may be able to overwrite some of these settings by providing different"
        )
        oConsole.fPrint(
            "    values after the keyword. You can also provide a binary path after the"
        )
        oConsole.fPrint(
            "    keyword to use a different binary than BugId detects, or if BugId is unable."
        )
        oConsole.fPrint("    to detect the binary on your system.")
        oConsole.fPrint()
        oConsole.fPrint(HILITE, "Options:")
        oConsole.fPrint(INFO, "  -h, --help")
        oConsole.fPrint("    This cruft.")
        oConsole.fPrint(INFO, "  -q, --quiet")
        oConsole.fPrint("    Output only essential information.")
        oConsole.fPrint(INFO, "  -v, --verbose")
        oConsole.fPrint(
            "    Output all commands send to cdb.exe and everything it outputs in return."
        )
        oConsole.fPrint("    Note that -q and -v are not mutually exclusive.")
        oConsole.fPrint(INFO, "  -f, --fast")
        oConsole.fPrint(
            "    Create no HTML report, do not use symbols. This is an alias for:"
        )
        oConsole.fPrint("        ", HILITE, "--bGenerateReportHTML=false")
        oConsole.fPrint("        ", HILITE, "--cBugId.asSymbolServerURLs=[]")
        oConsole.fPrint("        ", HILITE,
                        "--cBugId.bUse_NT_SYMBOL_PATH=false")
        oConsole.fPrint(INFO, "  -r, --repeat")
        oConsole.fPrint(
            "    Restart the application to run another test as soon as the application is"
        )
        oConsole.fPrint(
            "    terminated. Useful when testing the reliability of a repro, detecting the"
        )
        oConsole.fPrint(
            "    various crashes a non-deterministic repro can cause or while making "
        )
        oConsole.fPrint(
            "    modifications to the repro in order to test how they affect the crash."
        )
        oConsole.fPrint(
            "    A statistics file is created or updated after each run that contains the"
        )
        oConsole.fPrint(
            "    number of occurances of each Bug Id that was detected.")
        oConsole.fPrint(INFO, "  --isa=x86|x64")
        oConsole.fPrint(
            "    Use the x86 or x64 version of cdb to debug the application. The default is"
        )
        oConsole.fPrint(
            "    to use the ISA* of the OS. Applications build to run on x86 systems can be"
        )
        oConsole.fPrint(
            "    debugged using the x64 version of cdb, and you are strongly encouraged to "
        )
        oConsole.fPrint(
            "    do so. But you can use the x86 debugger to debug x86 application if you"
        )
        oConsole.fPrint("    want to. (ISA = Instruction Set Architecture)")
        oConsole.fPrint(INFO, "  --version")
        oConsole.fPrint(
            "    Show cBugId version and that of its sub-modules and check for updates."
        )
        oConsole.fPrint()
        oConsole.fPrint(
            "Options also include any of the settings in dxConfig.py; you can specify them"
        )
        oConsole.fPrint("using ", HILITE, "--[name]=[JSON value]", NORMAL,
                        ". Here are some examples:")
        oConsole.fPrint(INFO, "  --bGenerateReportHTML=false")
        oConsole.fPrint(
            "    Do not save a HTML formatted crash report. This should make BugId run"
        )
        oConsole.fPrint(
            "    faster and use less RAM, as it does not need to gather and process the"
        )
        oConsole.fPrint("    information needed for the HTML report.")
        oConsole.fPrint(
            "    If you only need to confirm a crash can be reproduced, you may want to use"
        )
        oConsole.fPrint(
            "    this: it can make the process of analyzing a crash a lot faster. But if"
        )
        oConsole.fPrint(
            "    no local or cached symbols are available, you'll get less information"
        )
        oConsole.fPrint(INFO, "  \"--sReportFolderPath=\\\"BugId\\\"\"")
        oConsole.fPrint(
            "    Save report to the specified folder, in this case \"BugId\". The quotes"
        )
        oConsole.fPrint(
            "    mess is needed because of the Windows quirck explained below."
        )
        oConsole.fPrint("The remaining dxConfig settings are:")
        for sSettingName in sorted(dxConfig.keys()):
            if sSettingName not in [
                    "bGenerateReportHTML", "sReportFolderPath", "cBugId"
            ]:
                xSettingValue = dxConfig[sSettingName]
                oConsole.fPrint("  ", INFO, "--", sSettingName,
                                NORMAL, " (default value: ", HILITE,
                                str(xSettingValue), NORMAL, ")")
        oConsole.fPrint("See ", HILITE, "dxConfig.py", NORMAL,
                        " for details on each setting.")
        oConsole.fPrint()
        oConsole.fPrint(
            "You can also adjust cBugId specific settings, such as:")
        oConsole.fPrint(INFO, "  --cBugId.bSaveDump=true")
        oConsole.fPrint("    Save a debug dump file when a crash is detected.")
        oConsole.fPrint(
            INFO,
            "  --cBugId.asSymbolServerURLs=[\"http://msdl.microsoft.com/download/symbols\"]"
        )
        oConsole.fPrint(
            "    Use http://msdl.microsoft.com/download/symbols as a symbol server."
        )
        oConsole.fPrint(INFO,
                        "  --cBugId.asSymbolCachePaths=[\"C:\\Symbols\"]")
        oConsole.fPrint("    Use C:\\Symbols to cache symbol files.")
        oConsole.fPrint()
        oConsole.fPrint("See ", HILITE, "cBugId\\dxConfig.py", NORMAL,
                        " for details on all available settings.")
        oConsole.fPrint(
            "All values must be valid JSON of the appropriate type. No checks are made to"
        )
        oConsole.fPrint(
            "ensure this! Providing illegal values may result in exceptions at any time"
        )
        oConsole.fPrint("during execution. You have been warned!")
        oConsole.fPrint()
        oConsole.fPrint(
            "Note that you may need to do a bit of \"quote-juggling\" because Windows likes"
        )
        oConsole.fPrint(
            "to eat quotes for no obvious reason. So, if you want to specify --a=\"b\", you"
        )
        oConsole.fPrint(
            "will need to use \"--a=\\\"b\\\"\", or BugId will see --a=b and `b` is not valid"
        )
        oConsole.fPrint("JSON.")
        oConsole.fPrint()
        oConsole.fPrint("Known application keywords:")
        asLine = ["  "]
        uLineLength = 2
        for sApplicationKeyword in asApplicationKeywords:
            if uLineLength > 2:
                if uLineLength + 2 + len(sApplicationKeyword) + 2 > 80:
                    asLine += [NORMAL, ","]
                    oConsole.fPrint(*asLine)
                    asLine = ["  "]
                    uLineLength = 2
                else:
                    asLine += [NORMAL, ", "]
                    uLineLength += 2
            asLine += [INFO, sApplicationKeyword]
            uLineLength += len(sApplicationKeyword)
        asLine += [NORMAL, "."]
        oConsole.fPrint(*asLine)
        oConsole.fPrint()
        oConsole.fPrint(
            "Run ", HILITE, "BugId.py application?", NORMAL,
            " for an overview of the application specific command")
        oConsole.fPrint("line arguments and settings.")
        oConsole.fPrint()
        oConsole.fPrint(
            "BugId will set it errorlevel/exit code to one of the following values:"
        )
        oConsole.fPrint("  ", INFO, "0", NORMAL,
                        " = BugId successfully ran the application ", HILITE,
                        "without detecting a bug", NORMAL, ".")
        oConsole.fPrint("  ", INFO, "1", NORMAL,
                        " = BugId successfully ran the application and ",
                        HILITE, "detected a bug", NORMAL, ".")
        oConsole.fPrint(
            "  ", INFO, "2", NORMAL,
            " = BugId was unable to parse the command-line arguments provided."
        )
        oConsole.fPrint(
            "  ", INFO, "3", NORMAL,
            " = BugId ran into an internal error: pleace report the details!")
        oConsole.fPrint(
            "  ", INFO, "4", NORMAL,
            " = BugId was unable to start or attach to the application.")
    finally:
        oConsole.fUnlock()
Пример #18
0
def fPrintUsageInformation(asApplicationKeywords):
    oConsole.fLock()
    try:
        oConsole.fPrint(HILITE, "Usage:")
        oConsole.fPrint()
        oConsole.fPrint(
            INFO,
            "  BugId.py [options] <target> [options] [-- argument [argument [...]]]"
        )
        oConsole.fPrint()
        oConsole.fPrint(HILITE, "Targets:")
        oConsole.fPrint(INFO, "  \"path\\to\\binary.exe\"")
        oConsole.fPrint(
            "    Start the given binary in the debugger with the given arguments."
        )
        oConsole.fPrint(INFO, "  --pids=pid[,pid[...]]")
        oConsole.fPrint(
            "    Attach debugger to the process(es) provided in the list. The processes ",
            HILITE, "must")
        oConsole.fPrint(
            "    all have been suspended, as they will be resumed by the debugger."
        )
        oConsole.fPrint(
            "    Arguments cannot be provided for obvious reasons.")
        oConsole.fPrint(INFO, "  --uwp-app=<package name>[!<application id>]")
        oConsole.fPrint(
            "    Start and debug a Universal Windows Platform App identified by the given"
        )
        oConsole.fPrint(
            "    package name and application id. If no application id is provided and the"
        )
        oConsole.fPrint(
            "    package exposes only one if, it will default to that id. Note that only"
        )
        oConsole.fPrint(
            "    a single argument can be passed to a UWP App; additional arguments will be"
        )
        oConsole.fPrint("    silently ignored.")
        oConsole.fPrint(INFO, "  <known application keyword>")
        oConsole.fPrint(
            "    BugId has a list of known targets that are identified by a keyword. You can"
        )
        oConsole.fPrint(
            "    use such a keyword to have BugId try to automatically find the binary or"
        )
        oConsole.fPrint(
            "    determine the package name and id for that application, optionally apply"
        )
        oConsole.fPrint(
            "    application specific settings and provide default arguments. This makes it"
        )
        oConsole.fPrint(
            "    easier to run these applications without having to manually provide these."
        )
        oConsole.fPrint(
            "    You can optioanlly override any default settings by providing them *after*"
        )
        oConsole.fPrint(
            "    the keyword. You can also provide the path to the application binary after"
        )
        oConsole.fPrint(
            "    the keyword to use a different binary than the one BugId automatically"
        )
        oConsole.fPrint(
            "    detects, or if BugId is unable to detect the binary on your system."
        )
        oConsole.fPrint()
        oConsole.fPrint(HILITE, "Options:")

        oConsole.fPrint(INFO, "  -c, --collateral[=number of bugs]")
        oConsole.fPrint(
            "    When the specified number of bugs is larger than 1 (default 5), BugId will"
        )
        oConsole.fPrint(
            "    go into \"collateral bug handling\" mode. This means that after certain"
        )
        oConsole.fPrint(
            "    access violation bugs are reported, it will attempt to \"fake\" that the"
        )
        oConsole.fPrint(
            "    instruction that caused the exception succeeded without triggering an"
        )
        oConsole.fPrint(
            "    exception. For read operations, it will set the destination register to a"
        )
        oConsole.fPrint(
            "    tainted value (0x41414141...). For write operations, it will simply step"
        )
        oConsole.fPrint(
            "    over the instruction. It will do this for up to the specified number of"
        )
        oConsole.fPrint("    bugs.")
        oConsole.fPrint(
            "    The upshot of this is that you can get an idea of what would happen if"
        )
        oConsole.fPrint(
            "    you were able to control the bad read/write operation. This can be usedful"
        )
        oConsole.fPrint(
            "    when determining if a particular vulnerability is theoretically exploitable"
        )
        oConsole.fPrint(
            "    or not. E.g. it might show that nothing else happens, that the application"
        )
        oConsole.fPrint(
            "    crashes unavoidably and immediately, both of which indicate that the issue"
        )
        oConsole.fPrint(
            "    is not exploitable. It might also show that reading from or writing to"
        )
        oConsole.fPrint(
            "    otherwise inaccessible parts of memory or controlling execution flow is"
        )
        oConsole.fPrint(
            "    potentially possible, indicating it is exploitable.")

        oConsole.fPrint(INFO, "  -d, --dump")
        oConsole.fPrint("    Save a mini crash dump when a crash is detected.")

        oConsole.fPrint(INFO, "  --full-dump")
        oConsole.fPrint("    Save a full crash dump when a crash is detected.")

        oConsole.fPrint(INFO, "  -f, --fast")
        oConsole.fPrint(
            "    Create no HTML report, do not use symbols. This is an alias for:"
        )
        oConsole.fPrint("        ", INFO, "--bGenerateReportHTML=false")
        oConsole.fPrint("        ", INFO, "--cBugId.asSymbolServerURLs=[]")
        oConsole.fPrint("        ", INFO, "--cBugId.bUse_NT_SYMBOL_PATH=false")

        oConsole.fPrint(INFO, "  -h, --help")
        oConsole.fPrint("    This cruft.")

        oConsole.fPrint(INFO, "  -I [arguments]")
        oConsole.fPrint(
            "    Install as the default JIT debugger on the system. This allows BugId to"
        )
        oConsole.fPrint(
            "    generate a report whenever an application crashes.")
        oConsole.fPrint(
            "    All arguments after -I will be passed to BugId whenever it is started as"
        )
        oConsole.fPrint(
            "    the JIT debugger. It might be useful to add arguments such as \"--pause\""
        )
        oConsole.fPrint(
            "    to leave the BugId window open after it generated a report, \"--full-dump\""
        )
        oConsole.fPrint(
            "    to generate a full memory dump and \"--reports=<path>\" to have the reports"
        )
        oConsole.fPrint(
            "    stored in a specific folder. Otherwise, the location where reports and"
        )
        oConsole.fPrint("    other output are stored is not known.")

        oConsole.fPrint(INFO, "  --isa=x86|x64")
        oConsole.fPrint(
            "    Use the x86 or x64 version of cdb to debug the application. The default is"
        )
        oConsole.fPrint(
            "    to use the ISA* of the OS. Applications build to run on x86 systems can be"
        )
        oConsole.fPrint(
            "    debugged using the x64 version of cdb, and you are strongly encouraged to "
        )
        oConsole.fPrint(
            "    do so. But you can use the x86 debugger to debug x86 application if you"
        )
        oConsole.fPrint("    want to. (ISA = Instruction Set Architecture)")

        oConsole.fPrint(INFO, "  -p, --pause")
        oConsole.fPrint(
            "    Always wait for the user to press ENTER before terminating at the end."
        )

        oConsole.fPrint(INFO, "  -q, --quiet")
        oConsole.fPrint("    Output only essential information.")

        oConsole.fPrint(INFO, "  -r, --repeat[=number of loops]")
        oConsole.fPrint(
            "    Restart the application to run another test as soon as the application is"
        )
        oConsole.fPrint(
            "    terminated. Useful when testing the reliability of a repro, detecting the"
        )
        oConsole.fPrint(
            "    various crashes a non-deterministic repro can cause or while making "
        )
        oConsole.fPrint(
            "    modifications to the repro in order to test how they affect the crash."
        )
        oConsole.fPrint(
            "    A statistics file is created or updated after each run that contains the"
        )
        oConsole.fPrint(
            "    number of occurances of each Bug Id that was detected. If a number is"
        )
        oConsole.fPrint(
            "    provided, the application will be run that many times. Otherwise the"
        )
        oConsole.fPrint("    application will be run indefinitely.")

        oConsole.fPrint(INFO, "  --symbols=path\\to\\symbols\\folder")
        oConsole.fPrint(
            "    Use the given path as a local symbol folder in addition to the symbol paths"
        )
        oConsole.fPrint(
            "    specified in dxConfig. You can provide this option multiple times to add"
        )
        oConsole.fPrint("    as many additional local symbol paths as needed.")

        oConsole.fPrint(INFO, "  --reports=path\\to\\reports\\folder")
        oConsole.fPrint(
            "    Store reports in the given path. Optional cdb output and crash dumps are"
        )
        oConsole.fPrint("    stored in the same location.")

        oConsole.fPrint(INFO, "  -v, --verbose")
        oConsole.fPrint(
            "    Output all commands send to cdb.exe and everything it outputs in return."
        )
        oConsole.fPrint("    Note that -q and -v are not mutually exclusive.")

        oConsole.fPrint(INFO, "  --version")
        oConsole.fPrint("    Show version information and check for updates.")

        oConsole.fPrint()
        oConsole.fPrint(
            "  Options also include any of the settings in dxConfig.py; you can specify them"
        )
        oConsole.fPrint("  using ", INFO, "--[name]=[JSON value]", NORMAL,
                        ". Here are some examples:")
        oConsole.fPrint(INFO, "  --bGenerateReportHTML=false")
        oConsole.fPrint(
            "    Do not save a HTML formatted crash report. This should make BugId run"
        )
        oConsole.fPrint(
            "    faster and use less RAM, as it does not need to gather and process the"
        )
        oConsole.fPrint("    information needed for the HTML report.")
        oConsole.fPrint(
            "    If you only need to confirm a crash can be reproduced, you may want to use"
        )
        oConsole.fPrint(
            "    this: it can make the process of analyzing a crash a lot faster. But if"
        )
        oConsole.fPrint(
            "    no local or cached symbols are available, you'll get less information"
        )
        oConsole.fPrint(INFO, "  \"--sReportFolderPath=\\\"BugId\\\"\"")
        oConsole.fPrint(
            "    Save report to the specified folder, in this case \"BugId\". The quotes"
        )
        oConsole.fPrint(
            "    mess is needed because of the Windows quirck explained below."
        )
        oConsole.fPrint("  The remaining dxConfig settings are:")
        for sSettingName in sorted(dxConfig.keys()):
            if sSettingName not in [
                    "bGenerateReportHTML", "sReportFolderPath", "cBugId"
            ]:
                xSettingValue = dxConfig[sSettingName]
                oConsole.fPrint("  ", INFO, "--", sSettingName,
                                NORMAL, " (default value: ", INFO,
                                str(xSettingValue), NORMAL, ")")
        oConsole.fPrint("  See ", INFO, "dxConfig.py", NORMAL,
                        " for details on each setting.")
        oConsole.fPrint()
        oConsole.fPrint(
            "  You can also adjust cBugId specific settings, such as:")
        oConsole.fPrint(
            INFO,
            "  --cBugId.asSymbolServerURLs=[\"http://msdl.microsoft.com/download/symbols\"]"
        )
        oConsole.fPrint(
            "    Use http://msdl.microsoft.com/download/symbols as a symbol server."
        )
        oConsole.fPrint(INFO,
                        "  --cBugId.asSymbolCachePaths=[\"C:\\Symbols\"]")
        oConsole.fPrint("    Use C:\\Symbols to cache symbol files.")
        oConsole.fPrint("  See ", INFO, "cBugId\\dxConfig.py", NORMAL,
                        " for details on all available settings.")
        oConsole.fPrint(
            "  All values must be valid JSON of the appropriate type. No checks are made to"
        )
        oConsole.fPrint(
            "  ensure this! Providing illegal values may result in exceptions at any time"
        )
        oConsole.fPrint("  during execution. You have been warned!")
        oConsole.fPrint()
        oConsole.fPrint(
            "  Note that you may need to do a bit of \"quote-juggling\" because Windows likes"
        )
        oConsole.fPrint(
            "  to eat quotes for no obvious reason. So, if you want to specify --a=\"b\", you"
        )
        oConsole.fPrint(
            "  will need to use \"--a=\\\"b\\\"\", or BugId will see --a=b and `b` is not valid"
        )
        oConsole.fPrint("  JSON.")
        oConsole.fPrint()
        oConsole.fPrint(HILITE, "Known application keywords:")
        asLine = ["  "]
        uLineLength = 2
        for sApplicationKeyword in asApplicationKeywords:
            if uLineLength > 2:
                if uLineLength + 2 + len(sApplicationKeyword) + 2 > 80:
                    asLine += [NORMAL, ","]
                    oConsole.fPrint(*asLine)
                    asLine = ["  "]
                    uLineLength = 2
                else:
                    asLine += [NORMAL, ", "]
                    uLineLength += 2
            asLine += [INFO, sApplicationKeyword]
            uLineLength += len(sApplicationKeyword)
        asLine += [NORMAL, "."]
        oConsole.fPrint(*asLine)
        oConsole.fPrint()
        oConsole.fPrint(
            "  Run ", INFO, "BugId.py application?", NORMAL,
            " for an overview of the application specific command")
        oConsole.fPrint("  line arguments and settings.")
        oConsole.fPrint()
        oConsole.fPrint(HILITE, "Exit codes:")
        oConsole.fPrint("  ", INFO, "0", NORMAL,
                        " = BugId successfully ran the application ",
                        UNDERLINE, "without detecting a bug", NORMAL, ".")
        oConsole.fPrint("  ", INFO, "1", NORMAL,
                        " = BugId successfully ran the application and ",
                        UNDERLINE, "detected a bug", NORMAL, ".")
        oConsole.fPrint(
            "  ", ERROR_INFO, "2", NORMAL,
            " = BugId was unable to parse the command-line arguments provided."
        )
        oConsole.fPrint(
            "  ", ERROR_INFO, "3", NORMAL,
            " = BugId ran into an internal error: please report the details!")
        oConsole.fPrint(
            "  ", ERROR_INFO, "4", NORMAL,
            " = BugId was unable to start or attach to the application.")
        oConsole.fPrint("  ", ERROR_INFO, "5", NORMAL,
                        " = You do not have a valid license.")
    finally:
        oConsole.fUnlock()
Пример #19
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();
Пример #20
0
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
Пример #21
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();
Пример #22
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!");
Пример #23
0
def fDumpExceptionAndExit(oException, oTraceBack):
    import os, sys, traceback
    oConsole.fLock()
    try:
        oConsole.fPrint(ERROR, "-" * 80)
        oConsole.fPrint(ERROR, "- An internal exception has occured:")
        oConsole.fPrint(ERROR, "  ", repr(oException))
        oConsole.fPrint(ERROR, "  Stack:")
        atxStack = traceback.extract_tb(oTraceBack)
        uFrameIndex = len(atxStack) - 1
        for (sFileName, uLineNumber, sFunctionName,
             sCode) in reversed(atxStack):
            sSource = "%s/%d" % (sFileName, uLineNumber)
            if sFunctionName != "<module>":
                sSource = "%s (%s)" % (sFunctionName, sSource)
            oConsole.fPrint(ERROR, "  %3d " % uFrameIndex, sSource)
            if sCode:
                oConsole.fPrint(ERROR, "      > ", sCode.strip())
            uFrameIndex -= 1
        oConsole.fPrint()
        oConsole.fPrint(ERROR, "  Windows version: ",
                        str(mWindowsAPI.oWindowsVersion))
        oConsole.fPrint(ERROR, "  BugId version: ",
                        oVersionInformation.sCurrentVersion)
        for (sModule, xModule) in [
            ("cBugId", cBugId),
            ("mFileSystem", mFileSystem),
            ("mWindowsAPI", mWindowsAPI),
            ("oConsole", oConsole),
        ]:
            oConsole.fPrint(ERROR, "  ", sModule, " version: ",
                            xModule.oVersionInformation.sCurrentVersion)
        oConsole.fPrint(ERROR, "-" * 80)
        oConsole.fPrint()
        oConsole.fPrint(
            "Please report the above details at the below web-page so it can be addressed:"
        )
        oConsole.fPrint(INFO,
                        "    https://github.com/SkyLined/BugId/issues/new")
        oConsole.fPrint(
            "If you do not have a github account, or you want to report this issue"
        )
        oConsole.fPrint("privately, you can also send an email to:")
        oConsole.fPrint(INFO, "    [email protected]")
        oConsole.fPrint()
        oConsole.fPrint(
            "In your report, please copy the information about the exception reported"
        )
        oConsole.fPrint(
            "above, as well as the stack trace and BugId version information. This makes"
        )
        oConsole.fPrint(
            "it easier to determine the cause of this issue and makes for faster fixes."
        )
        oConsole.fPrint()
        if "-v" not in sys.argv[1:] and "/v" not in sys.argv[
                1:] and "--verbose=true" not in sys.argv[1:]:
            oConsole.fPrint(
                "If you can reproduce the issue, it would help a lot if you can run BugId in"
            )
            oConsole.fPrint("verbose mode by adding the ", INFO, "--verbose",
                            NORMAL, " command-line argument.")
            oConsole.fPrint("as in:", HILITE, "BugId -v ",
                            " ".join(sys.argv[1:]))
            oConsole.fPrint()
        oConsole.fPrint("Thank you in advance for helping to improve BugId!")
    finally:
        oConsole.fUnlock()
        os._exit(3)
Пример #24
0
def fPrintUsageInformation():
    oConsole.fLock()
    try:
        oConsole.fOutput(HILITE, "Usage:")
        oConsole.fOutput("  ", INFO, "FileSystemBrowser", NORMAL, " [", INFO,
                         "\"path to browse\"", NORMAL, "] [", INFO, "OPTIONS",
                         NORMAL, "]")
        oConsole.fOutput()
        oConsole.fOutput(HILITE, "Arguments:")
        oConsole.fOutput("  ", INFO, "\"path to browser\"")
        oConsole.fOutput(
            "      Path to use as the root node (default = current working directory)"
        )
        oConsole.fOutput()
        oConsole.fOutput(HILITE, "Options:")
        oConsole.fOutput("  ", INFO, "--help")
        oConsole.fOutput("    This cruft.")
        oConsole.fOutput("  ", INFO, "--arguments=\"path\"")
        oConsole.fOutput(
            "    Read and process additional arguments from a file.")
        oConsole.fOutput("  ", INFO, "--offline=\"path\"")
        oConsole.fOutput(
            "    Do not start a webserver to allow browsing but instead create files for"
        )
        oConsole.fOutput("    offline browsing or uploading to server.")
        oConsole.fOutput("  ", INFO, "--apply-sharepoint-hacks")
        oConsole.fOutput(
            "    Modify offline files for use on SharePoint server where .json files are not"
        )
        oConsole.fOutput("    allowed.")
        oConsole.fOutput("  ", INFO, "--http-direct")
        oConsole.fOutput(
            "    Make direct requests to look up favicons for website links.")
        oConsole.fOutput("  ", INFO, "--http-proxy=hostname:port")
        oConsole.fOutput(
            "    Use the specified hostname and port as a HTTP proxy to make requests to"
        )
        oConsole.fOutput("    look up favicons for website links.")
        oConsole.fOutput("  ", INFO, "--http-timeout=<seconds>")
        oConsole.fOutput(
            "    Wait for a HTTP response from a server or proxy for at most the given number"
        )
        oConsole.fOutput("    of seconds before failing the request.")
        oConsole.fOutput("  ", INFO, "--debug")
        oConsole.fOutput("    Show debug output")
        oConsole.fOutput("")
        oConsole.fOutput(HILITE, "Notes:")
        oConsole.fOutput("  You can provide the ", INFO, "--http-direct",
                         NORMAL, " and/or ", INFO, "--http-proxy", NORMAL,
                         " arguments to allow")
        oConsole.fOutput(
            "  FileSystemBrowser to request any webpages that are linked to in order to"
        )
        oConsole.fOutput(
            "  determine their 'favicon' icon and use that for the link. Note that this can"
        )
        oConsole.fOutput("  slow down the creation of the tree significantly.")
        oConsole.fOutput("  You can combine the ", INFO, "--http-direct",
                         NORMAL, " and ", INFO, "--http-proxy", NORMAL,
                         " arguments to try both")
        oConsole.fOutput(
            "  direct requests and requests through a proxy when on an intranet. You can"
        )
        oConsole.fOutput("  also specify multiple ", INFO, "--http-proxy",
                         NORMAL, " arguments to have this")
        oConsole.fOutput(
            "  script to try multiple proxies for each webpage untill the webpage can"
        )
        oConsole.fOutput("  successfully be downloaded.")
        oConsole.fOutput("  If you provide the ", INFO, "--http-timeout",
                         NORMAL, " argument, it will affect only")
        oConsole.fOutput("  connections made by the client based on ", INFO,
                         "--http-direct", NORMAL, " and/or ", INFO,
                         "--http-proxy")
        oConsole.fOutput(
            "  arguments that come after it. This allows you to set different timeouts for"
        )
        oConsole.fOutput("  these arguments.")
        oConsole.fOutput("  The order in which you provide the ", INFO,
                         "--http-direct", NORMAL, " and ", INFO,
                         "--http-proxy", NORMAL, " arguments")
        oConsole.fOutput(
            "  determines the order in which request for webpages are attempted directly or"
        )
        oConsole.fOutput("  through proxies.")
    finally:
        oConsole.fUnlock()
Пример #25
0
        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();

if __name__ == "__main__":
  try:
    uExitCode = fuMain(sys.argv[1:]);
    
    if not gbQuiet and dxConfig["bShowLicenseAndDonationInfo"]:
      oConsole.fLock();
      try:
        oConsole.fPrint();
        oConsole.fPrint("This version of BugId is provided free of charge for non-commercial use only.");
        oConsole.fPrint("If you find it useful and would like to make a donation, you can send bitcoin");
        oConsole.fPrint("to ",INFO,"183yyxa9s1s1f7JBpPHPmzQ346y91Rx5DX",NORMAL,".");
        oConsole.fPrint("If you wish to use BugId commercially, please contact the author to request a");
        oConsole.fPrint("quote. Contact and licensing information can be found at:");
        oConsole.fPrint("    ",INFO,"https://github.com/SkyLined/BugId#license",NORMAL,".");
      finally:
        oConsole.fUnlock();
    os._exit(uExitCode);
  except Exception as oException:
    cException, oException, oTraceBack = sys.exc_info();
    fDumpExceptionAndExit(oException, oTraceBack);