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();
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()
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();
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();
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();
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);
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();
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();
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();
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();
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()
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();
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()
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;
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();
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();
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()
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()
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();
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
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();
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!");
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)
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()
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);