Example #1
0
    def _handle_next(self):
        task = self.inqueue.popleft()
        logging.info("{0} unpacking {1}".format(self.name,
                                                task["debuginfo"]["nvra"]))
        task["debuginfo"]["unpacked_path"] = \
                package.unpack_rpm_to_tmp(task["debuginfo"]["rpm_path"],
                                          prefix=task["debuginfo"]["nvra"])
        if task["debuginfo"]["nvra"].startswith("kernel-"):
            logging.info("Generating function offset map for kernel modules")
            task["function_offset_map"] = \
                    get_function_offset_map(task["debuginfo"]["unpacked_path"])

        logging.info("{0} unpacking {1}".format(self.name, task["source"]["nvra"]))
        task["source"]["unpacked_path"] = \
                package.unpack_rpm_to_tmp(task["source"]["rpm_path"],
                                          prefix=task["source"]["nvra"])

        if not task["source"]["nvra"].startswith("kernel-debuginfo-common"):
            specfile = None
            for f in os.listdir(task["source"]["unpacked_path"]):
                if f.endswith(".spec"):
                    specfile = os.path.join(task["source"]["unpacked_path"], f)

            if not specfile:
                logging.info("Unable to find specfile")
            else:
                src_dir = os.path.join(task["source"]["unpacked_path"],
                                       "usr", "src", "debug")
                logging.debug("SPEC file: {0}".format(specfile))
                logging.debug("Running rpmbuild")
                with open("/dev/null", "w") as null:
                    retcode = call(["rpmbuild", "--nodeps", "-bp", "--define",
                                    "_sourcedir {0}".format(task["source"]["unpacked_path"]),
                                    "--define", "_builddir {0}".format(src_dir),
                                    "--define",
                                    "_specdir {0}".format(task["source"]["unpacked_path"]),
                                    specfile], stdout=null, stderr=null)
                    if retcode:
                        logging.warn("rpmbuild exitted with {0}".format(retcode))

        task["source"]["files"] = walk(task["source"]["unpacked_path"])

        for pkg in task["packages"]:
            logging.info("{0} unpacking {1}".format(self.name, pkg["nvra"]))
            if pkg["rpm_path"] == task["debuginfo"]["rpm_path"]:
                logging.debug("Already unpacked")
                pkg["unpacked_path"] = task["debuginfo"]["unpacked_path"]
                continue

            pkg["unpacked_path"] = \
                    package.unpack_rpm_to_tmp(pkg["rpm_path"],
                                              prefix=pkg["nvra"])
        self.outqueue.put(task)
Example #2
0
def retrace_symbols(session):
    '''
    Find all Symbol Sources of Symbols that require retracing.
    Symbol Sources are grouped by build_id to lower the need of
    installing the same RPM multiple times.
    '''

    symbol_sources = (session.query(SymbolSource)
        .filter(SymbolSource.source_path == None)
        .order_by(SymbolSource.build_id, SymbolSource.path)).all()

    total = len(symbol_sources)
    retraced = 0
    logging.info('Retracing {0} symbols'.format(total))

    while symbol_sources:
        retraced += 1
        source = symbol_sources.pop()
        logging.info('[{0}/{1}] Retracing {2} with offset {3}'.format(
            retraced, total, source.path, source.offset))

        if not source.frames:
            logging.debug('No frames assigned with this symbol, skipping')
            continue

        if source.frames[0].backtrace.report.type != 'USERSPACE':
            logging.debug('Skipping non-USERSPACE symbol')
            continue

        # Find debuginfo and then binary package providing the build id.
        # FEDORA/RHEL SPECIFIC
        debuginfo_path = "/usr/lib/debug/.build-id/{0}/{1}.debug".format(
            source.build_id[:2], source.build_id[2:])

        logging.debug('Looking for: {0}'.format(debuginfo_path))

        debuginfo_packages = (session.query(Package)
            .join(PackageDependency)
            .filter(
                (PackageDependency.name == debuginfo_path) &
                (PackageDependency.type == "PROVIDES")
            )).all()

        logging.debug("Found {0} debuginfo packages".format(
            len(debuginfo_packages)))

        packages_found = False

        for debuginfo_package in debuginfo_packages:
            # Check whether there is a binary package corresponding to
            # the debuginfo package that provides the required binary.
            def find_binary_package(path):
                logging.debug('Looking for: {0}'.format(path))
                return (session.query(Package)
                    .join(PackageDependency)
                    .filter(
                        (Package.build_id == debuginfo_package.build_id) &
                        (Package.arch_id == debuginfo_package.arch_id) &
                        (PackageDependency.name == path) &
                        (PackageDependency.type == "PROVIDES")
                    )).first()

            orig_path = source.path
            if ('/../' in source.path) or ('/./' in source.path):
                logging.debug("Source path is not normalized, normalizing")
                source.path = os.path.abspath(source.path)

            binary_package = find_binary_package(source.path)

            if binary_package is None:
                logging.info("Binary package not found, trying /usr fix")

                # Try adding/stripping /usr
                if '/usr' in source.path:
                    logging.debug('Stripping /usr')
                    source.path = source.path.replace('/usr', '')
                    binary_package = find_binary_package(source.path)
                else:
                    logging.debug('Adding /usr')
                    source.path = '/usr' + source.path
                    binary_package = find_binary_package(source.path)

                if binary_package is None:
                    # Revert to original path
                    source.path = orig_path
                    session.expunge(source)
                    logging.warning("Matching binary package not found")
                    continue

            # We found a valid pair of binary and debuginfo packages.
            # Unpack them to temporary directories.
            # Search for possible conflicts with normalized path
            conflict = session.query(SymbolSource) \
                       .filter((SymbolSource.path == source.path) &
                               (SymbolSource.offset == source.offset) &
                               (SymbolSource.build_id == source.build_id)) \
                       .first()

            if conflict and  conflict.id != source.id:
                logging.debug("Merging SymbolSource {0}".format(conflict.id))
                session.expunge(source)

                # replace SymbolSource by the existing one
                for frame in source.frames:
                    frame.symbolsource_id = conflict.id
                session.flush()

                # delete the unnecessary SymbolSource
                session.query(SymbolSource).filter(SymbolSource.id == source.id).delete()
                session.flush()

                source = conflict

            try:
                binary_dir = package.unpack_rpm_to_tmp(
                    binary_package.get_lob_path("package"),
                    prefix="faf-symbol-retrace")
            except Exception, e:
                logging.error("Unable to extract binary package RPM: {0},"
                    " path: {1}, reason: {2}".format(binary_package.nvra(),
                    binary_package.get_lob_path("package"), e))
                continue

            try:
                debuginfo_dir = package.unpack_rpm_to_tmp(
                    debuginfo_package.get_lob_path("package"),
                    prefix="faf-symbol-retrace")
            except:
                logging.error("Unable to extract debuginfo RPM: {0},"
                    " path: {1}, reason: {2}".format(debuginfo_package.nvra(),
                    debuginfo_package.get_lob_path("package"), e))
                continue

            logging.debug("Binary package RPM: {0},"
                " path: {1}".format(binary_package.nvra(),
                binary_package.get_lob_path("package")))
            logging.debug("Debuginfo package RPM: {0},"
                " path: {1}".format(debuginfo_package.nvra(),
                debuginfo_package.get_lob_path("package")))

            # Found matching pair, stop trying.
            packages_found = True
            break

        if not packages_found:
            continue

        retrace_symbol_wrapper(session, source, binary_dir, debuginfo_dir)

        while (symbol_sources and
            symbol_sources[-1].build_id == source.build_id and
            symbol_sources[-1].path == source.path):

            logging.debug("Reusing extracted directories")
            retraced += 1
            source = symbol_sources.pop()
            logging.info('[{0}/{1}] Retracing {2} with offset {3}'.format(
                retraced, total, source.path, source.offset))

            retrace_symbol_wrapper(session, source, binary_dir,
                debuginfo_dir)

        shutil.rmtree(binary_dir)
        shutil.rmtree(debuginfo_dir)