示例#1
0
    def symbolize(self,
                  dsym_path,
                  image_vmaddr,
                  image_addr,
                  instruction_addr,
                  cpu_name,
                  symbolize_inlined=False):
        """Symbolizes a single frame based on the information provided.  If
        the symbolication fails a `SymbolicationError` is raised.

        `dsym_path` is the path to the dsym file on the file system.
        `image_vmaddr` is the slide of the image.  For most situations this
        can just be set to `0`.  If it's zero or unset we will attempt to
        find the slide from the dsym file.  `image_addr` is the canonical
        image address as loaded.  `instruction_addr` is the address where the
        error happened.

        `cpu_name` is the CPU name.  It follows general apple conventions and
        is used to special case certain behavior and look up the right
        symbols.  Common names are `armv7` and `arm64`.

        Additionally if `symbolize_inlined` is set to `True` then a list of
        frames is returned instead which might contain inlined frames.  In
        that case the return value might be an empty list instead.
        """
        if self._closed:
            raise RuntimeError('Symbolizer is closed')
        dsym_path = normalize_dsym_path(dsym_path)

        image_vmaddr = parse_addr(image_vmaddr)
        if not image_vmaddr:
            di = self._symbolizer.get_debug_info(dsym_path)
            if di is not None:
                variant = di.get_variant(cpu_name)
                if variant is not None:
                    image_vmaddr = variant.vmaddr

        image_addr = parse_addr(image_addr)
        instruction_addr = parse_addr(instruction_addr)
        if not is_valid_cpu_name(cpu_name):
            raise SymbolicationError('"%s" is not a valid cpu name' % cpu_name)

        addr = image_vmaddr + instruction_addr - image_addr

        with self._lock:
            with timedsection('symbolize'):
                if symbolize_inlined:
                    return self._symbolizer.symbolize_inlined(
                        dsym_path, addr, cpu_name)
                return self._symbolizer.symbolize(dsym_path, addr, cpu_name)
示例#2
0
    def symbolize(self,
                  dsym_path,
                  image_vmaddr,
                  image_addr,
                  instruction_addr,
                  cpu_name,
                  uuid=None,
                  silent=True,
                  demangle=True):
        if self._closed:
            raise RuntimeError('Symbolizer is closed')
        if not is_valid_cpu_name(cpu_name):
            raise ValueError('"%s" is not a valid cpu name' % cpu_name)
        dsym_path = normalize_dsym_path(dsym_path)

        image_vmaddr = parse_addr(image_vmaddr)
        if not image_vmaddr:
            image_vmaddr = get_macho_vmaddr(dsym_path, cpu_name) or 0

        image_addr = parse_addr(image_addr)
        instruction_addr = parse_addr(instruction_addr)

        addr = image_vmaddr + instruction_addr - image_addr

        try:
            with self._lock:
                with timedsection('symbolize'):
                    sym = self.symbolizer.symbolize(dsym_path, addr, cpu_name)
            if sym[0] is None:
                raise SymbolicationError('Symbolizer could not find symbol')
        except SymbolicationError:
            if not silent:
                raise
            sym = (None, None, 0, 0)

        symbol_name = sym[0]
        if demangle:
            symbol_name = demangle_symbol(symbol_name)

        return {
            'symbol_name': symbol_name,
            'filename': sym[1],
            'line': sym[2],
            'column': sym[3],
            'uuid': uuid,
        }
示例#3
0
    def symbolize(self,
                  dsym_path,
                  image_vmaddr,
                  image_addr,
                  instruction_addr,
                  cpu_name,
                  uuid=None,
                  silent=True):
        if self._closed:
            raise RuntimeError('Symbolizer is closed')
        if not is_valid_cpu_name(cpu_name):
            raise ValueError('"%s" is not a valid cpu name' % cpu_name)
        dsym_path = normalize_dsym_path(dsym_path)

        image_vmaddr = parse_addr(image_vmaddr)
        if not image_vmaddr:
            image_vmaddr = get_macho_vmaddr(dsym_path, cpu_name) or 0

        image_addr = parse_addr(image_addr)
        instruction_addr = parse_addr(instruction_addr)

        addr = image_vmaddr + instruction_addr - image_addr

        try:
            with self._lock:
                with timedsection('symbolize'):
                    sym = self.symbolizer.symbolize(dsym_path, addr, cpu_name)
            if sym[0] is None:
                raise SymbolicationError('Symbolizer could not find symbol')
        except SymbolicationError:
            if not silent:
                raise
            sym = (None, None, 0, 0)

        return {
            'symbol_name': demangle_symbol(sym[0]),
            'filename': sym[1],
            'line': sym[2],
            'column': sym[3],
            'uuid': uuid,
        }
示例#4
0
 def __init__(self, driver, dsym_paths, binary_images):
     if isinstance(dsym_paths, string_types):
         dsym_paths = [dsym_paths]
     self.driver = driver
     with timedsection('findimages'):
         self.images = find_debug_images(dsym_paths, binary_images)
示例#5
0
def find_debug_images(dsym_paths, binary_images):
    images_to_load = set()

    with timedsection('iterimages0'):
        for image in binary_images:
            cpu_name = get_cpu_name(image['cpu_type'], image['cpu_subtype'])
            if cpu_name is not None:
                images_to_load.add(image['uuid'].lower())

    images = {}

    # Step one: load images that are named by their UUID
    with timedsection('loadimages-fast'):
        for uuid in list(images_to_load):
            for dsym_path in dsym_paths:
                fn = os.path.join(dsym_path, uuid)
                if os.path.isfile(fn):
                    images[uuid] = fn
                    images_to_load.discard(uuid)
                    break

    # Otherwise fall back to loading images from the dsym bundle.  Because
    # this loading strategy is pretty slow we do't actually want to use it
    # unless we have a path that looks like a bundle.  As a result we
    # find all the paths which are bundles and then only process those.
    if images_to_load:
        slow_paths = []
        for dsym_path in dsym_paths:
            if os.path.isdir(os.path.join(dsym_path, 'Contents')):
                slow_paths.append(dsym_path)

        with timedsection('loadimages-slow'):
            for dsym_path in slow_paths:
                dwarf_base = os.path.join(dsym_path, 'Contents', 'Resources',
                                          'DWARF')
                if os.path.isdir(dwarf_base):
                    for fn in os.listdir(dwarf_base):
                        # Looks like a UUID we loaded, skip it
                        if fn in images:
                            continue
                        full_fn = os.path.join(dwarf_base, fn)
                        uuids = get_macho_uuids(full_fn)
                        for _, uuid in uuids:
                            if uuid in images_to_load:
                                images[uuid] = full_fn
                                images_to_load.discard(uuid)

    rv = {}

    # Now resolve all the images.
    with timedsection('resolveimages'):
        for image in binary_images:
            cpu_name = get_cpu_name(image['cpu_type'], image['cpu_subtype'])
            if cpu_name is None:
                continue
            uid = image['uuid'].lower()
            if uid not in images:
                continue
            rv[image['image_addr']] = {
                'uuid': uid,
                'image_addr': image['image_addr'],
                'dsym_path': images[uid],
                'image_vmaddr': image['image_vmaddr'],
                'cpu_name': cpu_name,
            }

    return rv
示例#6
0
文件: images.py 项目: robopsi/symsynd
def find_debug_images(dsym_paths, binary_images):
    """Given a list of paths and a list of binary images this returns a
    dictionary of image addresses to the locations on the file system for
    all found images.
    """
    images_to_load = set()

    with timedsection('iterimages0'):
        for image in binary_images:
            if get_image_cpu_name(image) is not None:
                images_to_load.add(image['uuid'].lower())

    images = {}

    # Step one: load images that are named by their UUID
    with timedsection('loadimages-fast'):
        for uuid in list(images_to_load):
            for dsym_path in dsym_paths:
                fn = os.path.join(dsym_path, uuid)
                if os.path.isfile(fn):
                    images[uuid] = fn
                    images_to_load.discard(uuid)
                    break

    # Otherwise fall back to loading images from the dsym bundle.  Because
    # this loading strategy is pretty slow we do't actually want to use it
    # unless we have a path that looks like a bundle.  As a result we
    # find all the paths which are bundles and then only process those.
    if images_to_load:
        slow_paths = []
        for dsym_path in dsym_paths:
            if os.path.isdir(os.path.join(dsym_path, 'Contents')):
                slow_paths.append(dsym_path)

        with timedsection('loadimages-slow'):
            for dsym_path in slow_paths:
                dwarf_base = os.path.join(dsym_path, 'Contents', 'Resources',
                                          'DWARF')
                if os.path.isdir(dwarf_base):
                    for fn in os.listdir(dwarf_base):
                        # Looks like a UUID we loaded, skip it
                        if fn in images:
                            continue
                        full_fn = os.path.join(dwarf_base, fn)
                        try:
                            di = DebugInfo.open_path(full_fn)
                        except DebugInfoError:
                            continue
                        for variant in di.get_variants():
                            uuid = str(variant.uuid)
                            if uuid in images_to_load:
                                images[uuid] = full_fn
                                images_to_load.discard(uuid)

    rv = {}

    # Now resolve all the images.
    with timedsection('resolveimages'):
        for image in binary_images:
            cpu_name = get_image_cpu_name(image)
            if cpu_name is None:
                continue
            uid = image['uuid'].lower()
            if uid not in images:
                continue
            rv[parse_addr(image['image_addr'])] = images[uid]

    return rv
示例#7
0
 def __init__(self, driver, dsym_paths, binary_images):
     if isinstance(dsym_paths, string_types):
         dsym_paths = [dsym_paths]
     self.driver = driver
     with timedsection('findimages'):
         self.images = find_debug_images(dsym_paths, binary_images)
示例#8
0
def find_debug_images(dsym_paths, binary_images):
    images_to_load = set()

    with timedsection('iterimages0'):
        for image in binary_images:
            cpu_name = get_cpu_name(image['cpu_type'],
                                    image['cpu_subtype'])
            if cpu_name is not None:
                images_to_load.add(image['uuid'].lower())

    images = {}

    # Step one: load images that are named by their UUID
    with timedsection('loadimages-fast'):
        for uuid in list(images_to_load):
            for dsym_path in dsym_paths:
                fn = os.path.join(dsym_path, uuid)
                if os.path.isfile(fn):
                    images[uuid] = fn
                    images_to_load.discard(uuid)
                    break

    # Otherwise fall back to loading images from the dsym bundle.  Because
    # this loading strategy is pretty slow we do't actually want to use it
    # unless we have a path that looks like a bundle.  As a result we
    # find all the paths which are bundles and then only process those.
    if images_to_load:
        slow_paths = []
        for dsym_path in dsym_paths:
            if os.path.isdir(os.path.join(dsym_path, 'Contents')):
                slow_paths.append(dsym_path)

        with timedsection('loadimages-slow'):
            for dsym_path in slow_paths:
                dwarf_base = os.path.join(dsym_path, 'Contents',
                                          'Resources', 'DWARF')
                if os.path.isdir(dwarf_base):
                    for fn in os.listdir(dwarf_base):
                        # Looks like a UUID we loaded, skip it
                        if fn in images:
                            continue
                        full_fn = os.path.join(dwarf_base, fn)
                        uuids = get_macho_uuids(full_fn)
                        for _, uuid in uuids:
                            if uuid in images_to_load:
                                images[uuid] = full_fn
                                images_to_load.discard(uuid)

    rv = {}

    # Now resolve all the images.
    with timedsection('resolveimages'):
        for image in binary_images:
            cpu_name = get_cpu_name(image['cpu_type'],
                                    image['cpu_subtype'])
            if cpu_name is None:
                continue
            uid = image['uuid'].lower()
            if uid not in images:
                continue
            rv[image['image_addr']] = {
                'uuid': uid,
                'image_addr': image['image_addr'],
                'dsym_path': images[uid],
                'image_vmaddr': image['image_vmaddr'],
                'cpu_name': cpu_name,
            }

    return rv