コード例 #1
0
class NativeStacktraceProcessor(StacktraceProcessor):
    def __init__(self, *args, **kwargs):
        StacktraceProcessor.__init__(self, *args, **kwargs)
        debug_meta = self.data.get('debug_meta')
        self.sym = None
        if debug_meta:
            self.available = True
            self.debug_meta = debug_meta
            self.sdk_info = get_sdk_from_event(self.data)
        else:
            self.available = False

    def close(self):
        StacktraceProcessor.close(self)
        if self.sym is not None:
            self.sym.close()
            self.sym = None

    def preprocess_related_data(self):
        if not self.available:
            return False

        is_debug_build = self.debug_meta.get('is_debug_build')
        referenced_images = find_stacktrace_referenced_images(
            self.debug_meta['images'],
            [x.stacktrace for x in self.stacktrace_infos])
        self.sym = Symbolizer(self.project,
                              self.debug_meta['images'],
                              referenced_images=referenced_images,
                              is_debug_build=is_debug_build)

        # The symbolizer gets a reference to the debug meta's images so
        # when it resolves the missing vmaddrs it changes them in the data
        # dict.
        return self.sym.resolve_missing_vmaddrs()

    def find_best_instruction(self, frame, stacktrace_info, idx):
        """Given a frame, stacktrace info and frame index this returns the
        interpolated instruction address we then use for symbolication later.
        """
        meta = None

        # We only need to provide meta information for frame zero
        if idx == 0:
            # The signal is useful information for symsynd in some situations
            # to disambiugate the first frame.  If we can get this information
            # from the mechanism we want to pass it onwards.
            signal = None
            exc = self.data.get('sentry.interfaces.Exception')
            if exc is not None:
                mechanism = exc['values'][0].get('mechanism')
                if mechanism and 'posix_signal' in mechanism and \
                   'signal' in mechanism['posix_signal']:
                    signal = mechanism['posix_signal']['signal']
            meta = {
                'frame_number': 0,
                'registers': stacktrace_info.stacktrace.get('registers'),
                'signal': signal,
            }

        return self.sym.find_best_instruction(frame, meta=meta)

    def process_frame(self, frame, stacktrace_info, idx):
        # XXX: warn on missing availability?

        # Only process frames here that are of supported platforms and
        # have the mandatory requirements for
        if not self.available or \
           self.get_effective_platform(frame) != 'cocoa' or \
           'instruction_addr' not in frame:
            return None

        errors = []

        # Construct a raw frame that is used by the symbolizer
        # backend.  We only assemble the bare minimum we need here.
        sym_input_frame = {
            'object_name':
            frame.get('package'),
            'instruction_addr':
            self.find_best_instruction(frame, stacktrace_info, idx),
            'symbol_name':
            frame.get('function'),
            'symbol_addr':
            frame.get('symbol_addr'),
        }
        in_app = self.sym.is_in_app(sym_input_frame)

        new_frames = []
        raw_frame = dict(frame)
        raw_frame['in_app'] = in_app

        try:
            symbolicated_frames = self.sym.symbolize_frame(
                sym_input_frame, self.sdk_info, symbolize_inlined=True)
            if not symbolicated_frames:
                return None, [raw_frame], []
        except SymbolicationFailed as e:
            errors = []
            if e.is_user_fixable or e.is_sdk_failure:
                errors.append({
                    'type': e.type,
                    'image_uuid': e.image_uuid,
                    'image_path': e.image_path,
                    'image_arch': e.image_arch,
                    'message': e.message,
                })
            else:
                logger.debug('Failed to symbolicate with native backend',
                             exc_info=True)
            return None, [raw_frame], errors

        for sfrm in symbolicated_frames:
            symbol = sfrm.get('symbol_name') or \
                frame.get('function') or '<unknown>'
            function = demangle_symbol(symbol, simplified=True)

            new_frame = dict(frame)
            new_frame['function'] = function

            # If we demangled something, store the original in the
            # symbol portion of the frame
            if function != symbol:
                new_frame['symbol'] = symbol

            new_frame['abs_path'] = sfrm.get('filename') or None
            if new_frame['abs_path']:
                new_frame['filename'] = posixpath.basename(
                    new_frame['abs_path'])
            if sfrm.get('line') is not None:
                new_frame['lineno'] = sfrm['line']
            if sfrm.get('column') is not None:
                new_frame['colno'] = sfrm['column']
            new_frame['package'] = sfrm['object_name'] \
                or new_frame.get('package')

            new_frame['in_app'] = in_app
            new_frames.append(new_frame)

        return new_frames, [raw_frame], []