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)
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)
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)
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)
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
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)
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)
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