Пример #1
0
def _handle_image_status(status, image, sdk_info, data):
    if status in ("found", "unused"):
        return
    elif status == "missing":
        package = image.get("code_file")
        # TODO(mitsuhiko): This check seems wrong?  This call seems to
        # mirror the one in the ios symbol server support.  If we change
        # one we need to change the other.
        if not package or is_known_third_party(package, sdk_info=sdk_info):
            return

        if is_optional_package(package, sdk_info=sdk_info):
            error = SymbolicationFailed(
                type=EventError.NATIVE_MISSING_OPTIONALLY_BUNDLED_DSYM)
        else:
            error = SymbolicationFailed(type=EventError.NATIVE_MISSING_DSYM)
    elif status == "malformed":
        error = SymbolicationFailed(type=EventError.NATIVE_BAD_DSYM)
    elif status == "too_large":
        error = SymbolicationFailed(type=EventError.FETCH_TOO_LARGE)
    elif status == "fetching_failed":
        error = SymbolicationFailed(type=EventError.FETCH_GENERIC_ERROR)
    elif status == "other":
        error = SymbolicationFailed(type=EventError.UNKNOWN_ERROR)
    else:
        logger.error("Unknown status: %s", status)
        return

    error.image_arch = image.get("arch")
    error.image_path = image.get("code_file")
    error.image_name = image_name(image.get("code_file"))
    error.image_uuid = image.get("debug_id")

    write_error(error, data)
Пример #2
0
def _merge_minidump_response(data, response):
    data["platform"] = "native"
    if response.get("crashed") is not None:
        data["level"] = "fatal" if response["crashed"] else "info"

    validate_and_set_timestamp(data, response.get("timestamp"))

    if response.get("system_info"):
        _merge_system_info(data, response["system_info"])

    sdk_info = get_sdk_from_event(data)

    images = []
    set_path(data, "debug_meta", "images", value=images)

    for complete_image in response["modules"]:
        image = {}
        _merge_image(image, complete_image, sdk_info,
                     lambda e: write_error(e, data))
        images.append(image)

    # Extract the crash reason and infos
    data_exception = get_path(data, "exception", "values", 0)
    exc_value = ("Assertion Error: %s" % response.get("assertion")
                 if response.get("assertion") else "Fatal Error: %s" %
                 response.get("crash_reason"))
    data_exception["value"] = exc_value
    data_exception["type"] = response.get("crash_reason")

    data_threads = []
    if response["stacktraces"]:
        data["threads"] = {"values": data_threads}
    else:
        error = SymbolicationFailed(message="minidump has no thread list",
                                    type=EventError.NATIVE_SYMBOLICATOR_FAILED)
        write_error(error, data)

    for complete_stacktrace in response["stacktraces"]:
        is_requesting = complete_stacktrace.get("is_requesting")
        thread_id = complete_stacktrace.get("thread_id")

        data_thread = {"id": thread_id, "crashed": is_requesting}
        data_threads.append(data_thread)

        if is_requesting:
            data_exception["thread_id"] = thread_id
            data_stacktrace = data_exception.setdefault("stacktrace", {})
            data_stacktrace["frames"] = []
        else:
            data_thread["stacktrace"] = data_stacktrace = {"frames": []}

        if complete_stacktrace.get("registers"):
            data_stacktrace["registers"] = complete_stacktrace["registers"]

        for complete_frame in reversed(complete_stacktrace["frames"]):
            new_frame = {}
            _merge_frame(new_frame, complete_frame)
            data_stacktrace["frames"].append(new_frame)
Пример #3
0
def _handle_response_status(event_data, response_json):
    if not response_json:
        error = SymbolicationFailed(type=EventError.NATIVE_INTERNAL_FAILURE)
    elif response_json['status'] == 'completed':
        return True
    elif response_json['status'] == 'failed':
        error = SymbolicationFailed(message=response_json.get('message') or None,
                                    type=EventError.NATIVE_SYMBOLICATOR_FAILED)
    else:
        logger.error('Unexpected symbolicator status: %s', response_json['status'])
        error = SymbolicationFailed(type=EventError.NATIVE_INTERNAL_FAILURE)

    write_error(error, event_data)
Пример #4
0
def _merge_full_response(data, response):
    data["platform"] = "native"
    if response.get("crashed") is not None:
        data["level"] = "fatal" if response["crashed"] else "info"

    if response.get("system_info"):
        _merge_system_info(data, response["system_info"])

    sdk_info = get_sdk_from_event(data)

    images = []
    set_path(data, "debug_meta", "images", value=images)

    for complete_image in response["modules"]:
        image = {}
        _merge_image(image, complete_image, sdk_info, data)
        images.append(image)

    # Extract the crash reason and infos
    data_exception = get_path(data, "exception", "values", 0)
    if response.get("assertion"):
        data_exception["value"] = "Assertion Error: {}".format(
            response["assertion"])
    elif response.get("crash_details"):
        data_exception["value"] = response["crash_details"]
    elif response.get("crash_reason"):
        data_exception["value"] = "Fatal Error: {}".format(
            response["crash_reason"])
    else:
        # We're merging a full response, so there was no initial payload
        # submitted. Assuming that this still contains the placeholder, remove
        # it rather than showing a default value.
        data_exception.pop("value", None)

    if response.get("crash_reason"):
        data_exception["type"] = response["crash_reason"]

    data_threads = []
    if response["stacktraces"]:
        data["threads"] = {"values": data_threads}
    else:
        error = SymbolicationFailed(message="minidump has no thread list",
                                    type=EventError.NATIVE_SYMBOLICATOR_FAILED)
        write_error(error, data)

    for complete_stacktrace in response["stacktraces"]:
        is_requesting = complete_stacktrace.get("is_requesting")
        thread_id = complete_stacktrace.get("thread_id")

        data_thread = {"id": thread_id, "crashed": is_requesting}
        data_threads.append(data_thread)

        if is_requesting:
            data_exception["thread_id"] = thread_id
            data_stacktrace = data_exception.setdefault("stacktrace", {})
            data_stacktrace["frames"] = []
        else:
            data_thread["stacktrace"] = data_stacktrace = {"frames": []}

        if complete_stacktrace.get("registers"):
            data_stacktrace["registers"] = complete_stacktrace["registers"]

        for complete_frame in reversed(complete_stacktrace["frames"]):
            new_frame = {}
            _merge_frame(new_frame, complete_frame)
            data_stacktrace["frames"].append(new_frame)
Пример #5
0
def process_payload(data):
    project = Project.objects.get_from_cache(id=data["project"])

    symbolicator = Symbolicator(project=project, event_id=data["event_id"])

    stacktrace_infos = [
        stacktrace for stacktrace in find_stacktraces_in_data(data) if any(
            is_native_platform(x) for x in stacktrace.platforms)
    ]

    stacktraces = [{
        "registers":
        sinfo.stacktrace.get("registers") or {},
        "frames": [
            f for f in reversed(sinfo.stacktrace.get("frames") or ())
            if _handles_frame(data, f)
        ],
    } for sinfo in stacktrace_infos]

    if not any(stacktrace["frames"] for stacktrace in stacktraces):
        return

    modules = native_images_from_data(data)
    signal = signal_from_data(data)

    response = symbolicator.process_payload(stacktraces=stacktraces,
                                            modules=modules,
                                            signal=signal)

    if not _handle_response_status(data, response):
        return data

    assert len(modules) == len(response["modules"]), (modules, response)

    sdk_info = get_sdk_from_event(data)

    for raw_image, complete_image in zip(modules, response["modules"]):
        _merge_image(raw_image, complete_image, sdk_info,
                     lambda e: write_error(e, data))

    assert len(stacktraces) == len(response["stacktraces"]), (stacktraces,
                                                              response)

    for sinfo, complete_stacktrace in zip(stacktrace_infos,
                                          response["stacktraces"]):
        complete_frames_by_idx = {}
        for complete_frame in complete_stacktrace.get("frames") or ():
            complete_frames_by_idx.setdefault(complete_frame["original_index"],
                                              []).append(complete_frame)

        new_frames = []
        native_frames_idx = 0

        for raw_frame in reversed(sinfo.stacktrace["frames"]):
            if not _handles_frame(data, raw_frame):
                new_frames.append(raw_frame)
                continue

            for complete_frame in complete_frames_by_idx.get(
                    native_frames_idx) or ():
                merged_frame = dict(raw_frame)
                _merge_frame(merged_frame, complete_frame)
                if merged_frame.get("package"):
                    raw_frame["package"] = merged_frame["package"]
                new_frames.append(merged_frame)

            native_frames_idx += 1

        if sinfo.container is not None and native_frames_idx > 0:
            sinfo.container["raw_stacktrace"] = {
                "frames": list(sinfo.stacktrace["frames"]),
                "registers": sinfo.stacktrace.get("registers"),
            }

        new_frames.reverse()
        sinfo.stacktrace["frames"] = new_frames

    return data
Пример #6
0
def _merge_minidump_response(data, response):
    data['platform'] = 'native'
    if response.get('crashed') is not None:
        data['level'] = 'fatal' if response['crashed'] else 'info'

    validate_and_set_timestamp(data, response.get('timestamp'))

    if response.get('system_info'):
        _merge_system_info(data, response['system_info'])

    sdk_info = get_sdk_from_event(data)

    images = []
    set_path(data, 'debug_meta', 'images', value=images)

    for complete_image in response['modules']:
        image = {}
        _merge_image(image, complete_image, sdk_info,
                     lambda e: write_error(e, data))
        images.append(image)

    # Extract the crash reason and infos
    data_exception = get_path(data, 'exception', 'values', 0)
    exc_value = ('Assertion Error: %s' % response.get('assertion')
                 if response.get('assertion') else 'Fatal Error: %s' %
                 response.get('crash_reason'))
    data_exception['value'] = exc_value
    data_exception['type'] = response.get('crash_reason')

    data_threads = []
    if response['stacktraces']:
        data['threads'] = {'values': data_threads}
    else:
        error = SymbolicationFailed(message='minidump has no thread list',
                                    type=EventError.NATIVE_SYMBOLICATOR_FAILED)
        write_error(error, data)

    for complete_stacktrace in response['stacktraces']:
        is_requesting = complete_stacktrace.get('is_requesting')
        thread_id = complete_stacktrace.get('thread_id')

        data_thread = {
            'id': thread_id,
            'crashed': is_requesting,
        }
        data_threads.append(data_thread)

        if is_requesting:
            data_exception['thread_id'] = thread_id
            data_stacktrace = data_exception.setdefault('stacktrace', {})
            data_stacktrace['frames'] = []
        else:
            data_thread['stacktrace'] = data_stacktrace = {'frames': []}

        if complete_stacktrace.get('registers'):
            data_stacktrace['registers'] = complete_stacktrace['registers']

        for complete_frame in reversed(complete_stacktrace['frames']):
            new_frame = {}
            _merge_frame(new_frame, complete_frame)
            data_stacktrace['frames'].append(new_frame)
Пример #7
0
    def run_symbolicator(self, processing_task):
        # TODO(markus): Make this work with minidumps. An unprocessed minidump
        # event will not contain unsymbolicated frames, because the minidump
        # upload already happened in store.
        # It will also presumably not contain images, so `self.available` will
        # already be `False`.

        if not self.available:
            return

        request_id_cache_key = request_id_cache_key_for_event(self.data)

        stacktraces = []
        processable_stacktraces = []
        has_frames = False

        for stacktrace_info, pf_list in processing_task.iter_processable_stacktraces():
            registers = stacktrace_info.stacktrace.get('registers') or {}

            # The filtering condition of this list comprehension is copied
            # from `iter_processable_frames`.
            #
            # We cannot reuse `iter_processable_frames` because the
            # symbolicator currently expects a list of stacktraces, not
            # flat frames.
            #
            # Right now we can't even filter out frames (e.g. using a frame
            # cache locally). The stacktraces have to be as complete as
            # possible because the symbolicator assumes the first frame of
            # a stacktrace to be the crashing frame. This assumption is
            # already violated because the SDK might chop off frames though
            # (which is less likely to be the case though).
            pf_list = [
                pf for pf in reversed(pf_list)
                if pf.processor == self
            ]

            frames = []

            for pf in pf_list:
                frame = {'instruction_addr': pf['instruction_addr']}
                if pf.get('trust') is not None:
                    frame['trust'] = pf['trust']
                frames.append(frame)
                has_frames = True

            stacktraces.append({
                'registers': registers,
                'frames': frames
            })

            processable_stacktraces.append(pf_list)

        if not has_frames:
            return

        rv = run_symbolicator(
            project=self.project,
            request_id_cache_key=request_id_cache_key,
            stacktraces=stacktraces, modules=self.images,
            signal=self.signal
        )

        if not handle_symbolicator_response_status(self.data, rv):
            return

        # TODO(markus): Set signal and os context from symbolicator response,
        # for minidumps

        assert len(self.images) == len(rv['modules']), (self.images, rv)

        for image, complete_image in zip(self.images, rv['modules']):
            merge_symbolicator_image(
                image, complete_image, self.sdk_info,
                lambda e: write_error(e, self.data)
            )

        assert len(stacktraces) == len(rv['stacktraces'])

        for pf_list, symbolicated_stacktrace in zip(
            processable_stacktraces,
            rv['stacktraces']
        ):
            for symbolicated_frame in symbolicated_stacktrace.get('frames') or ():
                pf = pf_list[symbolicated_frame['original_index']]
                pf.data['symbolicator_match'].append(symbolicated_frame)
Пример #8
0
def process_payload(data):
    project = Project.objects.get_from_cache(id=data['project'])
    task_id_cache_key = task_id_cache_key_for_event(data)

    symbolicator = Symbolicator(
        project=project,
        task_id_cache_key=task_id_cache_key
    )

    stacktrace_infos = [
        stacktrace
        for stacktrace in find_stacktraces_in_data(data)
        if any(is_native_platform(x) for x in stacktrace.platforms)
    ]

    stacktraces = [
        {
            'registers': sinfo.stacktrace.get('registers') or {},
            'frames': [
                f for f in reversed(sinfo.stacktrace.get('frames') or ())
                if _handles_frame(data, f)
            ]
        }
        for sinfo in stacktrace_infos
    ]

    if not any(stacktrace['frames'] for stacktrace in stacktraces):
        return

    modules = native_images_from_data(data)
    signal = signal_from_data(data)

    response = symbolicator.process_payload(
        stacktraces=stacktraces,
        modules=modules,
        signal=signal,
    )

    if not _handle_response_status(data, response):
        return data

    assert len(modules) == len(response['modules']), (modules, response)

    sdk_info = get_sdk_from_event(data)

    for raw_image, complete_image in zip(modules, response['modules']):
        _merge_image(
            raw_image,
            complete_image,
            sdk_info,
            lambda e: write_error(
                e,
                data))

    assert len(stacktraces) == len(response['stacktraces']), (stacktraces, response)

    for sinfo, complete_stacktrace in zip(stacktrace_infos, response['stacktraces']):
        complete_frames_by_idx = {}
        for complete_frame in complete_stacktrace.get('frames') or ():
            complete_frames_by_idx \
                .setdefault(complete_frame['original_index'], []) \
                .append(complete_frame)

        new_frames = []
        native_frames_idx = 0

        for raw_frame in reversed(sinfo.stacktrace['frames']):
            if not _handles_frame(data, raw_frame):
                new_frames.append(raw_frame)
                continue

            for complete_frame in complete_frames_by_idx.get(native_frames_idx) or ():
                merged_frame = dict(raw_frame)
                _merge_frame(merged_frame, complete_frame)
                if merged_frame.get('package'):
                    raw_frame['package'] = merged_frame['package']
                new_frames.append(merged_frame)

            native_frames_idx += 1

        if sinfo.container is not None and native_frames_idx > 0:
            sinfo.container['raw_stacktrace'] = {
                'frames': list(sinfo.stacktrace['frames']),
                'registers': sinfo.stacktrace.get('registers')
            }

        new_frames.reverse()
        sinfo.stacktrace['frames'] = new_frames

    return data