def foCreateForException(cBugReport, oCdbWrapper, uExceptionCode, sExceptionDescription): uStackFramesCount = dxBugIdConfig["uMaxStackFramesCount"]; if uExceptionCode == STATUS_STACK_OVERFLOW: # In order to detect a recursion loop, we need more stack frames: uStackFramesCount += (dxBugIdConfig["uMinStackRecursionLoops"] + 1) * dxBugIdConfig["uMaxStackRecursionLoopSize"] oProcess = cProcess.foCreate(oCdbWrapper); if not oCdbWrapper.bCdbRunning: return None; oStack = cStack.foCreate(oCdbWrapper, uStackFramesCount); if not oCdbWrapper.bCdbRunning: return None; oException = cException.foCreate(oCdbWrapper, uExceptionCode, sExceptionDescription, oStack); if not oCdbWrapper.bCdbRunning: return None; # If this exception was not caused by the application, but by cdb itself, None is return. This is not a bug. if oException is None: return None; # Create a preliminary error report. oBugReport = cBugReport( oCdbWrapper = oCdbWrapper, sBugTypeId = oException.sTypeId, sBugDescription = oException.sDescription, sSecurityImpact = oException.sSecurityImpact, oProcess = oProcess, oStack = oStack, ); # Perform exception specific analysis: foAnalyzeException = dfoAnalyzeException_by_uExceptionCode.get(oException.uCode); if foAnalyzeException: oBugReport = foAnalyzeException(oBugReport, oCdbWrapper, oException); if not oCdbWrapper.bCdbRunning: return None; if not oBugReport: # This exception is not a bug, continue the application. return None; return oBugReport;
def foCreateForException(cBugReport, oCdbWrapper, uExceptionCode, sExceptionDescription): uStackFramesCount = dxBugIdConfig["uMaxStackFramesCount"]; if uExceptionCode == STATUS_STACK_OVERFLOW: # In order to detect a recursion loop, we need more stack frames: uStackFramesCount += dxBugIdConfig["uMinStackRecursionLoops"] * dxBugIdConfig["uMaxStackRecursionLoopSize"] oStack = cStack.foCreate(oCdbWrapper, uStackFramesCount); if not oCdbWrapper.bCdbRunning: return None; oException = cException.foCreate(oCdbWrapper, uExceptionCode, sExceptionDescription, oStack); if not oCdbWrapper.bCdbRunning: return None; # If this exception was not caused by the application, but by cdb itself, None is return. This is not a bug. if oException is None: return None; # Hide some functions at the top of the stack that are merely helper functions and not relevant to the error: oStack.fHideTopFrames(asHiddenTopFrames); # Create a preliminary error report. oBugReport = cBugReport( oCdbWrapper = oCdbWrapper, sBugTypeId = oException.sTypeId, sBugDescription = oException.sDescription, sSecurityImpact = oException.sSecurityImpact, oStack = oStack, ); # Perform exception specific analysis: foAnalyzeException = dfoAnalyzeException_by_uExceptionCode.get(oException.uCode); if foAnalyzeException: oBugReport = foAnalyzeException(oBugReport, oCdbWrapper, oException); if not oCdbWrapper.bCdbRunning: return None; if not oBugReport: # This exception is not a bug, continue the application. return None; return oBugReport.foPostProcess(oCdbWrapper);
def foCreate(cBugReport, oCdbWrapper, sBugTypeId, sBugDescription, sSecurityImpact): uStackFramesCount = dxBugIdConfig["uMaxStackFramesCount"]; oStack = cStack.foCreate(oCdbWrapper, uStackFramesCount); if not oCdbWrapper.bCdbRunning: return None; # Hide some functions at the top of the stack that are merely helper functions and not relevant to the error: oStack.fHideTopFrames(asHiddenTopFrames); # Create a preliminary error report. oBugReport = cBugReport( oCdbWrapper = oCdbWrapper, sBugTypeId = sBugTypeId, sBugDescription = sBugDescription, sSecurityImpact = sSecurityImpact, oStack = oStack, ); return oBugReport.foPostProcess(oCdbWrapper);
def foCreate(cBugReport, oCdbWrapper, sBugTypeId, sBugDescription, sSecurityImpact): uStackFramesCount = dxBugIdConfig["uMaxStackFramesCount"] oStack = cStack.foCreate(oCdbWrapper, uStackFramesCount) if not oCdbWrapper.bCdbRunning: return None # Hide some functions at the top of the stack that are merely helper functions and not relevant to the error: oStack.fHideTopFrames(asHiddenTopFrames) # Create a preliminary error report. oBugReport = cBugReport( oCdbWrapper=oCdbWrapper, sBugTypeId=sBugTypeId, sBugDescription=sBugDescription, sSecurityImpact=sSecurityImpact, oStack=oStack, ) return oBugReport
def foCreate(cBugReport, oCdbWrapper, sBugTypeId, sBugDescription, sSecurityImpact): uStackFramesCount = dxBugIdConfig["uMaxStackFramesCount"]; oProcess = cProcess.foCreate(oCdbWrapper); if not oCdbWrapper.bCdbRunning: return None; oStack = cStack.foCreate(oCdbWrapper, uStackFramesCount); if not oCdbWrapper.bCdbRunning: return None; # Create a preliminary error report. oBugReport = cBugReport( oCdbWrapper = oCdbWrapper, sBugTypeId = sBugTypeId, sBugDescription = sBugDescription, sSecurityImpact = sSecurityImpact, oProcess = oProcess, oStack = oStack, ); return oBugReport;
def foGetStack(oException, oCdbWrapper): # This is not going to chance, so we can cache it: if not hasattr(oException, "oStack"): oException.oStack = cStack.foCreate(oCdbWrapper); # If the exception record was retreived earlier, it may have been done before all symbols were loaded. if oException.asExceptionRecord is not None: # Getting the stack loads all symbols, so get the exception record again to extract the "ExceptionAddress" symbol. oException.asExceptionRecord = oCdbWrapper.fasSendCommandAndReadOutput(".exr -1"); if not oCdbWrapper.bCdbRunning: return None; for sLine in oException.asExceptionRecord: # "ExceptionAddress:" whitespace address whitespace "(" (symbol) ")" } oExceptionAddressSymbolMatch = re.match(r"ExceptionAddress\:\s+[0-9A-F`]+\s+\((.+)\)", sLine, re.I); if oExceptionAddressSymbolMatch: oException.sAddressSymbol = oExceptionAddressSymbolMatch.group(1); break; # verify the exception and the first stack frame have the same information where applicable. oException.fCheckWithFirstStackFrame(oCdbWrapper); return oException.oStack;
def foCreateForException(cBugReport, oCdbWrapper, uExceptionCode, sExceptionDescription): uStackFramesCount = dxBugIdConfig["uMaxStackFramesCount"] if uExceptionCode == STATUS_STACK_OVERFLOW: # In order to detect a recursion loop, we need more stack frames: uStackFramesCount += dxBugIdConfig[ "uMinStackRecursionLoops"] * dxBugIdConfig[ "uMaxStackRecursionLoopSize"] oStack = cStack.foCreate(oCdbWrapper, uStackFramesCount) if not oCdbWrapper.bCdbRunning: return None oException = cException.foCreate(oCdbWrapper, uExceptionCode, sExceptionDescription, oStack) if not oCdbWrapper.bCdbRunning: return None # If this exception was not caused by the application, but by cdb itself, None is return. This is not a bug. if oException is None: return None # Hide some functions at the top of the stack that are merely helper functions and not relevant to the error: oStack.fHideTopFrames(asHiddenTopFrames) # Create a preliminary error report. oBugReport = cBugReport( oCdbWrapper=oCdbWrapper, sBugTypeId=oException.sTypeId, sBugDescription=oException.sDescription, sSecurityImpact=oException.sSecurityImpact, oStack=oStack, ) # Perform exception specific analysis: foAnalyzeException = dfoAnalyzeException_by_uExceptionCode.get( oException.uCode) if foAnalyzeException: oBugReport = foAnalyzeException(oBugReport, oCdbWrapper, oException) if not oCdbWrapper.bCdbRunning: return None if not oBugReport: # This exception is not a bug, continue the application. return None return oBugReport
def foCreate(cSelf, oCrashInfo, uCode, sCodeDescription): oProcess = cProcess.foCreate(oCrashInfo); oSelf = cSelf(oProcess, uCode, sCodeDescription); # We do this twice to make sure symbols are loaded the first time, which may create additional symbal warnings and # errors that makes the output harder to parse. The second time, there will be no such output, so we can parse it # a lot easier. asExceptionRecord = oCrashInfo._fasSendCommandAndReadOutput(".exr -1"); if asExceptionRecord is None: return None; asExceptionRecord = oCrashInfo._fasSendCommandAndReadOutput(".exr -1"); if asExceptionRecord is None: return None; uParameterCount = None; uParameterIndex = None; for sLine in asExceptionRecord: oNameValueMatch = re.match(r"^\s*%s\s*$" % ( r"(\w+)(?:\[(\d+)\])?\:\s+" # (name) optional{ "[" (index) "]" } ":" whitespace r"([0-9A-F`]+)" # (value) r"(?:\s+\((.*)\))?" # optional{ whitespace "(" (symbol || description) ")" } ), sLine, re.I); if oNameValueMatch: sName, sIndex, sValue, sDetails = oNameValueMatch.groups(); uValue = int(sValue.replace("`", ""), 16); if sName == "ExceptionAddress": oSelf.uAddress = uValue; oSelf.sAddressSymbol = sDetails; elif sName == "ExceptionCode": assert uValue == uCode, \ "Exception record has an unexpected ExceptionCode value (0x%08X vs 0x%08X)" % (uValue, uCode); assert sDetails is None or sDetails == sCodeDescription, \ "Exception record has an unexpected ExceptionCode description (%s vs %s)" % \ (repr(sDetails), repr(sCodeDescription)); elif sName == "ExceptionFlags": oSelf.uFlags = uValue; elif sName == "NumberParameters": uParameterCount = uValue; uParameterIndex = 0; oSelf.auParameters = []; elif sName == "Parameter": assert int(sIndex, 16) == uParameterIndex, \ "Unexpected parameter #0x%s vs 0x%X" % (sIndex, uParameterIndex); oSelf.auParameters.append(uValue); uParameterIndex += 1; else: raise AssertionError("Unknown exception record value %s" % sLine); elif oSelf.sDetails is None: oSelf.sDetails = sLine; else: raise AssertionError("Superfluous exception record line %s" % sLine); assert oSelf.uAddress is not None, \ "Exception record is missing an ExceptionAddress value"; assert oSelf.uFlags is not None, \ "Exception record is missing an ExceptionFlags value"; assert uParameterCount is not None, \ "Exception record is missing an NumberParameters value"; assert uParameterCount == len(oSelf.auParameters), \ "Unexpected number of parameters (%d vs %d)" % (len(oSelf.auParameters), uParameterCount); # Now handle the information in the exception record and perform additional tasks as needed. Create an exception # id that uniquely identifies the exception and a description of the exception. if uCode == 0xC000027B: # Parameter[0] = paStowedExceptionInformationArray; # Parameter[1] = uStowedExceptionInformationArrayLength; assert len(oSelf.auParameters) == 2, \ "Unexpected number of WinRT language exception parameters (%d vs 2)" % len(oSelf.auParameters); pStowedExceptionsAddress = oSelf.auParameters[0]; uStowedExceptionsCount = oSelf.auParameters[1]; assert uStowedExceptionsCount == 1, \ "Unexpected number of WinRT language exception stowed exceptions (%d vs 1)" % uStowedExceptionsCount; # The stowed exception replaces this exception: return cStowedException.foCreate(oCrashInfo, oProcess, pStowedExceptionsAddress); elif uCode == STATUS_ACCESS_VIOLATION: # Parameter[0] = access type (0 = read, 1 = write, 8 = execute) # Parameter[1] = address assert len(oSelf.auParameters) == 2, \ "Unexpected number of access violation exception parameters (%d vs 2)" % len(oSelf.auParameters); # Access violation: add the type of operation and the location to the exception id. sViolationTypeId = "AV" + {0:"R", 1:"W", 8:"E"}.get(oSelf.auParameters[0], "?"); sViolationTypeDescription = {0:"reading", 1:"writing", 8:"executing"}.get(oSelf.auParameters[0], "0x%X-ing" % oSelf.auParameters[0]); uAddress = oSelf.auParameters[1]; sAddressId, sAddressDescription = ftsGetAddressIdAndDescription(uAddress); if sAddressId != "NULL": asPageHeapInformation = oCrashInfo._fasSendCommandAndReadOutput("!heap -p -a 0x%X" % uAddress); asPageHeapInformation = oCrashInfo._fasSendCommandAndReadOutput("!heap -p -a 0x%X" % uAddress); asPageHeapInformation = oCrashInfo._fasSendCommandAndReadOutput("!heap -p -a 0x%X" % (uAddress - 0x4)); if asPageHeapInformation is None: return None; #if uAddress & 0xFFF < 0x8: # # Assuming page heap is This may be a buffer overrun oSelf.sTypeId = "%s@%s" % (sViolationTypeId, sAddressId); oSelf.sDescription = "%s while %s memory at 0x%X (%s)" % \ (sCodeDescription, sViolationTypeDescription, uAddress, sAddressDescription); uNULLMinusOffsetMinAddress = {"x64": 0xFFFFFFFFFFFF0000, "x86": 0xFFFF0000}[oProcess.sISA]; oSelf.sSecurityImpact = ((uAddress > uNULLMinusOffsetMinAddress or uAddress < 0x10000) and "Not a security issue" or "Probably a security issue" ); elif uCode == STATUS_STACK_BUFFER_OVERRUN: # Parameter[0] = fail fast code assert len(oSelf.auParameters) == 1, \ "Unexpected number of fail fast exception parameters (%d vs 1)" % len(oSelf.auParameters); sCodeId, sCodeDescription, sSecurityImpact = \ ftsGetFailFastErrorCodeIdDescriptionAndSecurityImpact(oSelf.auParameters[0]); oSelf.sTypeId = "FF@%s" % sCodeId; oSelf.sDescription = "A critical issue was detected (code %d: %s)" % (oSelf.auParameters[0], sCodeDescription); oSelf.sSecurityImpact = sSecurityImpact; else: oSelf.sTypeId = fsGetExceptionTypeId(uCode); oSelf.sDescription = "%s (code 0x%08X)" % (sCodeDescription, uCode); oSelf.sSecurityImpact = fsGetSecurityImpact(uCode); # Get the stack oSelf.oStack = cStack.foCreate(oCrashInfo, oSelf.oProcess); if oSelf.oStack is None: return None; return oSelf;
def foGetStack(oException, oCdbWrapper): # This is not going to chance, so we can cache it: if not hasattr(oException, "oStack"): oException.oStack = cStack.foCreate(oCdbWrapper); return oException.oStack;
def oStack(oBugReport): if oBugReport.__oStack is None: oBugReport.__oStack = cStack.foCreate(oBugReport.__oProcess, oBugReport.uStackFramesCount) return oBugReport.__oStack
def foGetStack(oException, oCdbWrapper): # This is not going to chance, so we can cache it: if not hasattr(oException, "oStack"): oException.oStack = cStack.foCreate(oCdbWrapper) return oException.oStack
def foGetStack(oSelf, oCrashInfo): # This is not going to chance, so we can cache it: if not hasattr(oSelf, "oStack"): oSelf.oStack = cStack.foCreate(oCrashInfo, oSelf.oProcess); return oSelf.oStack;
def foCreate(cSelf, oCrashInfo, uCode, sCodeDescription): oProcess = cProcess.foCreate(oCrashInfo) oSelf = cSelf(oProcess, uCode, sCodeDescription) # We do this twice to make sure symbols are loaded the first time, which may create additional symbal warnings and # errors that makes the output harder to parse. The second time, there will be no such output, so we can parse it # a lot easier. asExceptionRecord = oCrashInfo._fasSendCommandAndReadOutput(".exr -1") if asExceptionRecord is None: return None asExceptionRecord = oCrashInfo._fasSendCommandAndReadOutput(".exr -1") if asExceptionRecord is None: return None uParameterCount = None uParameterIndex = None for sLine in asExceptionRecord: oNameValueMatch = re.match( r"^\s*%s\s*$" % ( r"(\w+)(?:\[(\d+)\])?\:\s+" # (name) optional{ "[" (index) "]" } ":" whitespace r"([0-9A-F`]+)" # (value) r"(?:\s+\((.*)\))?" # optional{ whitespace "(" (symbol || description) ")" } ), sLine, re.I) if oNameValueMatch: sName, sIndex, sValue, sDetails = oNameValueMatch.groups() uValue = int(sValue.replace("`", ""), 16) if sName == "ExceptionAddress": oSelf.uAddress = uValue oSelf.sAddressSymbol = sDetails elif sName == "ExceptionCode": assert uValue == uCode, \ "Exception record has an unexpected ExceptionCode value (0x%08X vs 0x%08X)" % (uValue, uCode) assert sDetails is None or sDetails == sCodeDescription, \ "Exception record has an unexpected ExceptionCode description (%s vs %s)" % \ (repr(sDetails), repr(sCodeDescription)) elif sName == "ExceptionFlags": oSelf.uFlags = uValue elif sName == "NumberParameters": uParameterCount = uValue uParameterIndex = 0 oSelf.auParameters = [] elif sName == "Parameter": assert int(sIndex, 16) == uParameterIndex, \ "Unexpected parameter #0x%s vs 0x%X" % (sIndex, uParameterIndex) oSelf.auParameters.append(uValue) uParameterIndex += 1 else: raise AssertionError("Unknown exception record value %s" % sLine) elif oSelf.sDetails is None: oSelf.sDetails = sLine else: raise AssertionError("Superfluous exception record line %s" % sLine) assert oSelf.uAddress is not None, \ "Exception record is missing an ExceptionAddress value" assert oSelf.uFlags is not None, \ "Exception record is missing an ExceptionFlags value" assert uParameterCount is not None, \ "Exception record is missing an NumberParameters value" assert uParameterCount == len(oSelf.auParameters), \ "Unexpected number of parameters (%d vs %d)" % (len(oSelf.auParameters), uParameterCount) # Now handle the information in the exception record and perform additional tasks as needed. Create an exception # id that uniquely identifies the exception and a description of the exception. if uCode == 0xC000027B: # Parameter[0] = paStowedExceptionInformationArray; # Parameter[1] = uStowedExceptionInformationArrayLength; assert len(oSelf.auParameters) == 2, \ "Unexpected number of WinRT language exception parameters (%d vs 2)" % len(oSelf.auParameters) pStowedExceptionsAddress = oSelf.auParameters[0] uStowedExceptionsCount = oSelf.auParameters[1] assert uStowedExceptionsCount == 1, \ "Unexpected number of WinRT language exception stowed exceptions (%d vs 1)" % uStowedExceptionsCount # The stowed exception replaces this exception: return cStowedException.foCreate(oCrashInfo, oProcess, pStowedExceptionsAddress) elif uCode == STATUS_ACCESS_VIOLATION: # Access violation: add the type of operation and the location to the exception id. sViolationTypeId = "AV" + { 0: "R", 1: "W", 8: "E" }.get(oSelf.auParameters[0], "?") sViolationTypeDescription = { 0: "reading", 1: "writing", 8: "executing" }.get(oSelf.auParameters[0], "?") uAddress = oSelf.auParameters[1] sAddressId = fsGetAddressId(uAddress) oSelf.sTypeId = "%s@%s" % (sViolationTypeId, sAddressId) oSelf.sDescription = "%s while %s memory at 0x%08X (%s)" % ( sCodeDescription, sViolationTypeDescription, uAddress, sAddressId) oSelf.sSecurityImpact = ( (uAddress > 0xFFFF0000 or uAddress < 0x10000) and "Not a security issue" or "Probably a security issue") else: oSelf.sTypeId = fsGetExceptionTypeId(uCode) oSelf.sDescription = "%s (code 0x%08X)" % (sCodeDescription, uCode) oSelf.sSecurityImpact = fsGetSecurityImpact(uCode) # Get the stack oSelf.oStack = cStack.foCreate(oCrashInfo, oSelf.oProcess) if oSelf.oStack is None: return None return oSelf