def calculateComplexDerefOpAddress(complexDerefOp, registerMap): match = re.match("((?:\\-?0x[0-9a-f]+)?)\\(%([a-z0-9]+),%([a-z0-9]+),([0-9]+)\\)", complexDerefOp) if match != None: offset = 0L if len(match.group(1)) > 0: offset = long(match.group(1), 16) regA = RegisterHelper.getRegisterValue(match.group(2), registerMap) regB = RegisterHelper.getRegisterValue(match.group(3), registerMap) mult = long(match.group(4), 16) # If we're missing any of the two register values, return None if regA == None or regB == None: if regA == None: return (None, "Missing value for register %s" % match.group(2)) else: return (None, "Missing value for register %s" % match.group(3)) if RegisterHelper.getBitWidth(registerMap) == 32: val = int32(uint32(regA)) + int32(uint32(offset)) + (int32(uint32(regB)) * int32(uint32(mult))) else: # Assume 64 bit width val = int64(uint64(regA)) + int64(uint64(offset)) + (int64(uint64(regB)) * int64(uint64(mult))) return (long(val), None) return (None, "Unknown failure.")
def calculateComplexDerefOpAddress(complexDerefOp, registerMap): match = re.match( "((?:\\-?0x[0-9a-f]+)?)\\(%([a-z0-9]+),%([a-z0-9]+),([0-9]+)\\)", complexDerefOp) if match != None: offset = 0L if len(match.group(1)) > 0: offset = long(match.group(1), 16) regA = RegisterHelper.getRegisterValue(match.group(2), registerMap) regB = RegisterHelper.getRegisterValue(match.group(3), registerMap) mult = long(match.group(4), 16) # If we're missing any of the two register values, return None if regA == None or regB == None: if regA == None: return (None, "Missing value for register %s" % match.group(2)) else: return (None, "Missing value for register %s" % match.group(3)) if RegisterHelper.getBitWidth(registerMap) == 32: val = int32(uint32(regA)) + int32(uint32(offset)) + ( int32(uint32(regB)) * int32(uint32(mult))) else: # Assume 64 bit width val = int64(uint64(regA)) + int64(uint64(offset)) + ( int64(uint64(regB)) * int64(uint64(mult))) return (long(val), None) return (None, "Unknown failure.")
def runTest(self): registerMap = { "rax" : 0xfffffffffffffe00L, "rbx" : 0x7ffff79a7640L } self.assertEqual(RegisterHelper.getRegisterValue("rax", registerMap), 0xfffffffffffffe00L) self.assertEqual(RegisterHelper.getRegisterValue("eax", registerMap), 0xfffffe00L) self.assertEqual(RegisterHelper.getRegisterValue("ax", registerMap), 0xfe00L) self.assertEqual(RegisterHelper.getRegisterValue("ah", registerMap), 0xfeL) self.assertEqual(RegisterHelper.getRegisterValue("al", registerMap), 0x0L) self.assertEqual(RegisterHelper.getRegisterValue("rbx", registerMap), 0x7ffff79a7640L) self.assertEqual(RegisterHelper.getRegisterValue("ebx", registerMap), 0xf79a7640L) self.assertEqual(RegisterHelper.getRegisterValue("bx", registerMap), 0x7640L) self.assertEqual(RegisterHelper.getRegisterValue("bh", registerMap), 0x76L) self.assertEqual(RegisterHelper.getRegisterValue("bl", registerMap), 0x40L)
def calculateCrashAddress(crashInstruction, registerMap): ''' Calculate the crash address given the crash instruction and register contents @type crashInstruction: string @param crashInstruction: Crash instruction string as provided by GDB @type registerMap: Map from string to long @param registerMap: Map of register names to values @rtype: long @return The calculated crash address On error, a string containing the failure message is returned instead. ''' if (len(crashInstruction) == 0): # GDB shows us no instruction, so the memory at the instruction # pointer address must be inaccessible and we should assume # that this caused our crash. return RegisterHelper.getInstructionPointer(registerMap) parts = crashInstruction.split(None, 1) if len(parts) == 1: # Single instruction without any operands? # Only accept those that we explicitly know so far. instruction = parts[0] if instruction == "ret": # If ret is crashing, it's most likely due to the stack pointer # pointing somewhere where it shouldn't point, so use that as # the crash address. return RegisterHelper.getStackPointer(registerMap) elif instruction == "ud2": # ud2 - Raise invalid opcode exception # We treat this like invalid instruction return RegisterHelper.getInstructionPointer(registerMap) else: raise RuntimeError("Unsupported non-operand instruction: %s" % instruction) if len(parts) != 2: raise RuntimeError("Failed to split instruction and operands apart: %s" % crashInstruction) instruction = parts[0] operands = parts[1] if not re.match("[a-z\\.]+", instruction): raise RuntimeError("Invalid instruction: %s" % instruction) parts = operands.split(",") # We now have four possibilities: # 1. Length of parts is 1, that means we have one operand # 2. Length of parts is 2, that means we have two simple operands # 3. Length of parts is 4 and # a) First part contains '(' but not ')', meaning the first operand is complex # b) First part contains no '(' or ')', meaning the last operand is complex # e.g. mov %ecx,0x500094(%r15,%rdx,4) # # 4. Length of parts is 3, just one complex operand. # e.g. shrb -0x69(%rdx,%rbx,8) # When we fail, try storing a reason here failureReason = "Unknown failure." if RegisterHelper.isX86Compatible(registerMap): if len(parts) == 1: if instruction == "callq" or instruction == "call" or instruction == "push" or instruction == "pop": return RegisterHelper.getStackPointer(registerMap) else: failureReason = "Unsupported single-operand instruction." elif len(parts) == 2: failureReason = "Unknown failure with two-operand instruction." derefOp = None if "(" in parts[0] and ")" in parts[0]: derefOp = parts[0] if "(" in parts[1] and ")" in parts[1]: if derefOp != None: if ":(" in parts[1]: # This can be an instruction using multiple segments, like: # # movsq %ds:(%rsi),%es:(%rdi) # # (gdb) p $_siginfo._sifields._sigfault.si_addr # $1 = (void *) 0x7ff846e64d28 # (gdb) x /i $pc # => 0x876b40 <js::ArgumentsObject::create<CopyFrameArgs>(JSContext*, JS::HandleScript, JS::HandleFunction, unsigned int, CopyFrameArgs&)+528>: movsq %ds:(%rsi),%es:(%rdi) # (gdb) info reg $ds # ds 0x0 0 # (gdb) info reg $es # es 0x0 0 # (gdb) info reg $rsi # rsi 0x7ff846e64d28 140704318115112 # (gdb) info reg $rdi # rdi 0x7fff27fac030 140733864132656 # # # We don't support this right now, so return None. # return None raise RuntimeError("Instruction operands have multiple loads? %s" % crashInstruction) derefOp = parts[1] if derefOp != None: match = re.match("((?:\\-?0x[0-9a-f]+)?)\\(%([a-z0-9]+)\\)", derefOp) if match != None: offset = 0L if len(match.group(1)): offset = long(match.group(1), 16) val = RegisterHelper.getRegisterValue(match.group(2), registerMap) # If we don't have the value, return None if val == None: failureReason = "Missing value for register %s " % match.group(2) else: if RegisterHelper.getBitWidth(registerMap) == 32: return long(int32(uint32(offset)) + int32(uint32(val))) else: # Assume 64 bit width return long(int64(uint64(offset)) + int64(uint64(val))) else: failureReason = "Failed to decode two-operand instruction: No dereference operation or hardcoded address detected." # We might still be reading from/writing to a hardcoded address. # Note that it's not possible to have two hardcoded addresses # in one instruction, one operand must be a register or immediate # constant (denoted by leading $). In some cases, like a movabs # instruction, the immediate constant however is dereferenced # and is the first operator. So we first check parts[1] then # parts[0] in case it's a dereferencing operation. for x in (parts[1], parts[0]): result = re.match("\\$?(\\-?0x[0-9a-f]+)", x) if result != None: return long(result.group(1), 16) elif len(parts) == 3: # Example instruction: shrb -0x69(%rdx,%rbx,8) if "(" in parts[0] and ")" in parts[2]: complexDerefOp = parts[0] + "," + parts[1] + "," + parts[2] (result, reason) = GDBCrashInfo.calculateComplexDerefOpAddress(complexDerefOp, registerMap) if result == None: failureReason = reason else: return result else: raise RuntimeError("Unexpected instruction pattern: %s" % crashInstruction) elif len(parts) == 4: if "(" in parts[0] and not ")" in parts[0]: complexDerefOp = parts[0] + "," + parts[1] + "," + parts[2] elif not "(" in parts[0] and not ")" in parts[0]: complexDerefOp = parts[1] + "," + parts[2] + "," + parts[3] (result, reason) = GDBCrashInfo.calculateComplexDerefOpAddress(complexDerefOp, registerMap) if result == None: failureReason = reason else: return result else: raise RuntimeError("Unexpected length after splitting operands of this instruction: %s" % crashInstruction) else: failureReason = "Architecture is not supported." print("Unable to calculate crash address from instruction: %s " % crashInstruction, file=sys.stderr) print("Reason: %s" % failureReason, file=sys.stderr) return failureReason
def __init__(self, stdout, stderr, configuration, crashData=None): ''' Private constructor, called by L{CrashInfo.fromRawCrashData}. Do not use directly. ''' CrashInfo.__init__(self) if stdout != None: self.rawStdout.extend(stdout) if stderr != None: self.rawStderr.extend(stderr) if crashData != None: self.rawCrashData.extend(crashData) self.configuration = configuration # If crashData is given, use that to find the GDB trace, otherwise use stderr if crashData: gdbOutput = crashData else: gdbOutput = stderr gdbFramePatterns = [ "\\s*#(\\d+)\\s+(0x[0-9a-f]+) in (.+?) \\(.*?\\)( at .+)?", "\\s*#(\\d+)\\s+()(.+?) \\(.*?\\)( at .+)?" ] gdbRegisterPattern = RegisterHelper.getRegisterPattern() + "\\s+0x([0-9a-f]+)" gdbCrashAddressPattern = "Crash Address:\\s+0x([0-9a-f]+)" gdbCrashInstructionPattern = "=> 0x[0-9a-f]+(?: <.+>)?:\\s+(.*)" lastLineBuf = "" pastFrames = False for traceLine in gdbOutput: # Do a very simple check for a frame number in combination with pending # buffer content. If we detect this constellation, then it's highly likely # that we have a valid trace line but no pattern that fits it. We need # to make sure that we report this. if not pastFrames and re.match("\\s*#\\d+.+", lastLineBuf) != None and re.match("\\s*#\\d+.+", traceLine) != None: print("Fatal error parsing this GDB trace line:", file=sys.stderr) print(lastLineBuf, file=sys.stderr) raise RuntimeError("Fatal error parsing GDB trace") if not len(lastLineBuf): match = re.search(gdbRegisterPattern, traceLine) if match != None: pastFrames = True register = match.group(1) value = long(match.group(2), 16) self.registers[register] = value else: match = re.search(gdbCrashAddressPattern, traceLine) if match != None: self.crashAddress = long(match.group(1), 16) else: match = re.search(gdbCrashInstructionPattern, traceLine) if match != None: self.crashInstruction = match.group(1) if not pastFrames: if not len(lastLineBuf) and re.match("\\s*#\\d+.+", traceLine) == None: # Skip additional lines continue lastLineBuf += traceLine functionName = None frameIndex = None for gdbPattern in gdbFramePatterns: match = re.search(gdbPattern, lastLineBuf) if match != None: frameIndex = int(match.group(1)) functionName = match.group(3) break if frameIndex == None: # Line might not be complete yet, try adding the next continue else: # Successfully parsed line, reset last line buffer lastLineBuf = "" # Allow #0 to appear twice in the beginning, GDB does this for core dumps ... if len(self.backtrace) != frameIndex and frameIndex == 0: self.backtrace.pop(0) elif len(self.backtrace) != frameIndex: print("Fatal error parsing this GDB trace (Index mismatch, wanted %s got %s ): " % (len(self.backtrace), frameIndex), file=sys.stderr) print(os.linesep.join(gdbOutput), file=sys.stderr) raise RuntimeError("Fatal error parsing GDB trace") # This is a workaround for GDB throwing an error while resolving function arguments # in the trace and aborting. We try to remove the error message to at least recover # the function name properly. gdbErrorIdx = functionName.find(" (/build/buildd/gdb") if gdbErrorIdx > 0: functionName = functionName[:gdbErrorIdx] self.backtrace.append(functionName) # If we have no crash address but the instruction, try to calculate the crash address if self.crashAddress == None and self.crashInstruction != None: crashAddress = GDBCrashInfo.calculateCrashAddress(self.crashInstruction, self.registers) if isinstance(crashAddress, basestring): self.failureReason = crashAddress return self.crashAddress = crashAddress if self.crashAddress != None and self.crashAddress < 0: if RegisterHelper.getBitWidth(self.registers) == 32: self.crashAddress = uint32(self.crashAddress) else: # Assume 64 bit width self.crashAddress = uint64(self.crashAddress)
def __init__(self, stdout, stderr, configuration, crashData=None): ''' Private constructor, called by L{CrashInfo.fromRawCrashData}. Do not use directly. ''' CrashInfo.__init__(self) if stdout != None: self.rawStdout.extend(stdout) if stderr != None: self.rawStderr.extend(stderr) if crashData != None: self.rawCrashData.extend(crashData) self.configuration = configuration cdbRegisterPattern = RegisterHelper.getRegisterPattern() + "=([0-9a-f]+)" inCrashingThread = False inEcxrData = False ecxrData = [] for line in crashData: # Start of .ecxr data if re.match(r'0:000> \.ecxr', line): inEcxrData = True continue if inEcxrData: # Example: # 0:000> .ecxr # rax=0000000000000000 rbx=0000000000008000 rcx=00000000000005af # rdx=0000000000000000 rsi=0000000008c52000 rdi=0000000000008000 # rip=000007fef86c13e4 rsp=000000000033bb10 rbp=0000000000000008 # r8=0000000077440000 r9=00000000000003a6 r10=00000000c000012d # r11=0000000000000246 r12=0000000000000008 r13=0000000000500040 # r14=0000000008c007e0 r15=0000000000000000 # iopl=0 nv up ei pl nz na pe nc # cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000200 if line.startswith("cs="): inEcxrData = False continue # First extract the line, example: # rax=0000000000000000 rbx=0000000000008000 rcx=00000000000005af matchLine = re.search(RegisterHelper.getRegisterPattern(), line) if matchLine != None: ecxrData.extend(line.split()) # Next, put the rax, rbx, rcx, etc. entries into a list of their own, then iterate match = re.search(cdbRegisterPattern, line) for instr in ecxrData: match = re.search(cdbRegisterPattern, instr) if match != None: register = match.group(1) value = long(match.group(2), 16) self.registers[register] = value # Crash address if line.startswith("Exception Faulting Address:"): # Example: # Exception Faulting Address: 0x7fef86c13e4 address = line.split(": ")[1] self.crashAddress = long(address, 16) # Crash instruction if line.startswith("Faulting Instruction:"): # Example: # Faulting Instruction:01206fbd int 3 cInstruction = line.split(":")[1].split(None, 1)[1] self.crashInstruction = cInstruction # Start of stack for crashing thread if re.match(r'^\s*Hash Usage : Stack Trace:', line): inCrashingThread = True continue if inCrashingThread: # Example: # Major+Minor : mozglue!moz_abort+0x4 # Minor : mozglue!je_realloc+0x3d # Minor : js_64_prof_windows_a523d4c7efe2!mozilla::VectorBase<unsigned char,256,js::SystemAllocPolicy,mozilla::Vector<unsigned char,256,j+0x53 # Minor : js_64_prof_windows_a523d4c7efe2!js::jit::X86Encoding::BaseAssembler::X86InstructionFormatter::oneByteOp64+0x35 # Minor : Unknown components = line.split(None, 4) stackEntry = components[2] # See http://msecdbg.codeplex.com/SourceControl/latest#MSECDbgExts/Source/exploitable.cpp # "Instruction Address: ..." will appear after: LogStackInformation( objDebugger, objState ); if "Instruction" in components[0]: inCrashingThread = False continue stackEntry = CDBCrashInfo.removeFilenameAndOffset(stackEntry) stackEntry = CrashInfo.sanitizeStackFrame(stackEntry) self.backtrace.append(stackEntry)
def calculateCrashAddress(crashInstruction, registerMap): ''' Calculate the crash address given the crash instruction and register contents @type crashInstruction: string @param crashInstruction: Crash instruction string as provided by GDB @type registerMap: Map from string to long @param registerMap: Map of register names to values @rtype: long @return The calculated crash address On error, a string containing the failure message is returned instead. ''' if (len(crashInstruction) == 0): # GDB shows us no instruction, so the memory at the instruction # pointer address must be inaccessible and we should assume # that this caused our crash. return RegisterHelper.getInstructionPointer(registerMap) parts = crashInstruction.split(None, 1) if len(parts) != 2: raise RuntimeError( "Failed to split instruction and operands apart: %s" % crashInstruction) instruction = parts[0] operands = parts[1] if not re.match("[a-z\\.]+", instruction): raise RuntimeError("Invalid instruction: %s" % instruction) parts = operands.split(",") # We now have four possibilities: # 1. Length of parts is 1, that means we have one operand # 2. Length of parts is 2, that means we have two simple operands # 3. Length of parts is 4 and # a) First part contains '(' but not ')', meaning the first operand is complex # b) First part contains no '(' or ')', meaning the last operand is complex # e.g. mov %ecx,0x500094(%r15,%rdx,4) # # 4. Length of parts is 3, just one complex operand. # e.g. shrb -0x69(%rdx,%rbx,8) # When we fail, try storing a reason here failureReason = "Unknown failure." if RegisterHelper.isX86Compatible(registerMap): if len(parts) == 1: if instruction == "callq" or instruction == "push" or instruction == "pop": return RegisterHelper.getStackPointer(registerMap) else: failureReason = "Unsupported single-operand instruction." elif len(parts) == 2: failureReason = "Unknown failure with two-operand instruction." derefOp = None if "(" in parts[0] and ")" in parts[0]: derefOp = parts[0] if "(" in parts[1] and ")" in parts[1]: if derefOp != None: if ":(" in parts[1]: # This can be an instruction using multiple segments, like: # # movsq %ds:(%rsi),%es:(%rdi) # # (gdb) p $_siginfo._sifields._sigfault.si_addr # $1 = (void *) 0x7ff846e64d28 # (gdb) x /i $pc # => 0x876b40 <js::ArgumentsObject::create<CopyFrameArgs>(JSContext*, JS::HandleScript, JS::HandleFunction, unsigned int, CopyFrameArgs&)+528>: movsq %ds:(%rsi),%es:(%rdi) # (gdb) info reg $ds # ds 0x0 0 # (gdb) info reg $es # es 0x0 0 # (gdb) info reg $rsi # rsi 0x7ff846e64d28 140704318115112 # (gdb) info reg $rdi # rdi 0x7fff27fac030 140733864132656 # # # We don't support this right now, so return None. # return None raise RuntimeError( "Instruction operands have multiple loads? %s" % crashInstruction) derefOp = parts[1] if derefOp != None: match = re.match( "((?:\\-?0x[0-9a-f]+)?)\\(%([a-z0-9]+)\\)", derefOp) if match != None: offset = 0L if len(match.group(1)): offset = long(match.group(1), 16) val = RegisterHelper.getRegisterValue( match.group(2), registerMap) # If we don't have the value, return None if val == None: failureReason = "Missing value for register %s " % match.group( 2) else: if RegisterHelper.getBitWidth(registerMap) == 32: return long( int32(uint32(offset)) + int32(uint32(val))) else: # Assume 64 bit width return long( int64(uint64(offset)) + int64(uint64(val))) else: failureReason = "Failed to decode two-operand instruction: No dereference operation or hardcoded address detected." # We might still be reading from/writing to a hardcoded address. # Note that it's not possible to have two hardcoded addresses # in one instruction, one operand must be a register or immediate # constant (denoted by leading $). In some cases, like a movabs # instruction, the immediate constant however is dereferenced # and is the first operator. So we first check parts[1] then # parts[0] in case it's a dereferencing operation. for x in (parts[1], parts[0]): result = re.match("\\$?(\\-?0x[0-9a-f]+)", x) if result != None: return long(result.group(1), 16) elif len(parts) == 3: # Example instruction: shrb -0x69(%rdx,%rbx,8) if "(" in parts[0] and ")" in parts[2]: complexDerefOp = parts[0] + "," + parts[1] + "," + parts[2] (result, reason) = GDBCrashInfo.calculateComplexDerefOpAddress( complexDerefOp, registerMap) if result == None: failureReason = reason else: return result else: raise RuntimeError("Unexpected instruction pattern: %s" % crashInstruction) elif len(parts) == 4: if "(" in parts[0] and not ")" in parts[0]: complexDerefOp = parts[0] + "," + parts[1] + "," + parts[2] elif not "(" in parts[0] and not ")" in parts[0]: complexDerefOp = parts[1] + "," + parts[2] + "," + parts[3] (result, reason) = GDBCrashInfo.calculateComplexDerefOpAddress( complexDerefOp, registerMap) if result == None: failureReason = reason else: return result else: raise RuntimeError( "Unexpected length after splitting operands of this instruction: %s" % crashInstruction) else: failureReason = "Architecture is not supported." print("Unable to calculate crash address from instruction: %s " % crashInstruction, file=sys.stderr) print("Reason: %s" % failureReason, file=sys.stderr) return failureReason
def __init__(self, stdout, stderr, configuration, crashData=None): ''' Private constructor, called by L{CrashInfo.fromRawCrashData}. Do not use directly. ''' CrashInfo.__init__(self) if stdout != None: self.rawStdout.extend(stdout) if stderr != None: self.rawStderr.extend(stderr) if crashData != None: self.rawCrashData.extend(crashData) self.configuration = configuration # If crashData is given, use that to find the GDB trace, otherwise use stderr if crashData: gdbOutput = crashData else: gdbOutput = stderr gdbFramePatterns = [ "\\s*#(\\d+)\\s+(0x[0-9a-f]+) in (.+?) \\(.*?\\)( at .+)?", "\\s*#(\\d+)\\s+()(.+?) \\(.*?\\)( at .+)?" ] gdbRegisterPattern = RegisterHelper.getRegisterPattern( ) + "\\s+0x([0-9a-f]+)" gdbCrashAddressPattern = "Crash Address:\\s+0x([0-9a-f]+)" gdbCrashInstructionPattern = "=> 0x[0-9a-f]+(?: <.+>)?:\\s+(.*)" lastLineBuf = "" pastFrames = False for traceLine in gdbOutput: # Do a very simple check for a frame number in combination with pending # buffer content. If we detect this constellation, then it's highly likely # that we have a valid trace line but no pattern that fits it. We need # to make sure that we report this. if not pastFrames and re.match( "\\s*#\\d+.+", lastLineBuf) != None and re.match( "\\s*#\\d+.+", traceLine) != None: print("Fatal error parsing this GDB trace line:", file=sys.stderr) print(lastLineBuf, file=sys.stderr) raise RuntimeError("Fatal error parsing GDB trace") if not len(lastLineBuf): match = re.search(gdbRegisterPattern, traceLine) if match != None: pastFrames = True register = match.group(1) value = long(match.group(2), 16) self.registers[register] = value else: match = re.search(gdbCrashAddressPattern, traceLine) if match != None: self.crashAddress = long(match.group(1), 16) else: match = re.search(gdbCrashInstructionPattern, traceLine) if match != None: self.crashInstruction = match.group(1) if not pastFrames: if not len(lastLineBuf) and re.match("\\s*#\\d+.+", traceLine) == None: # Skip additional lines continue lastLineBuf += traceLine functionName = None frameIndex = None for gdbPattern in gdbFramePatterns: match = re.search(gdbPattern, lastLineBuf) if match != None: frameIndex = int(match.group(1)) functionName = match.group(3) break if frameIndex == None: # Line might not be complete yet, try adding the next continue else: # Successfully parsed line, reset last line buffer lastLineBuf = "" # Allow #0 to appear twice in the beginning, GDB does this for core dumps ... if len(self.backtrace) != frameIndex and frameIndex == 0: self.backtrace.pop(0) elif len(self.backtrace) != frameIndex: print( "Fatal error parsing this GDB trace (Index mismatch, wanted %s got %s ): " % (len(self.backtrace), frameIndex), file=sys.stderr) print(os.linesep.join(gdbOutput), file=sys.stderr) raise RuntimeError("Fatal error parsing GDB trace") # This is a workaround for GDB throwing an error while resolving function arguments # in the trace and aborting. We try to remove the error message to at least recover # the function name properly. gdbErrorIdx = functionName.find(" (/build/buildd/gdb") if gdbErrorIdx > 0: functionName = functionName[:gdbErrorIdx] self.backtrace.append(functionName) # If we have no crash address but the instruction, try to calculate the crash address if self.crashAddress == None and self.crashInstruction != None: crashAddress = GDBCrashInfo.calculateCrashAddress( self.crashInstruction, self.registers) if isinstance(crashAddress, basestring): self.failureReason = crashAddress return self.crashAddress = crashAddress if self.crashAddress != None and self.crashAddress < 0: if RegisterHelper.getBitWidth(self.registers) == 32: self.crashAddress = uint32(self.crashAddress) else: # Assume 64 bit width self.crashAddress = uint64(self.crashAddress)