Example #1
0
    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.")
Example #2
0
    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.")
Example #3
0
 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)
Example #4
0
    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
Example #5
0
    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)
Example #6
0
    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)
Example #7
0
    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
Example #8
0
    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)