예제 #1
0
파일: retrace.py 프로젝트: rtnpro/faf
def prepare_tasks(db, debuginfo_map):
    """
    Creates tasks from debuginfo map
    """
    result = []
    for debuginfo in debuginfo_map:
        packages = []
        for package in debuginfo_map[debuginfo]:
            pkg_entry = { "package": package,
                          "nvra": package.nvra(),
                          "rpm_path": package.get_lob_path("package"),
                          "symbols": debuginfo_map[debuginfo][package] }
            packages.append(pkg_entry)

        if debuginfo.name.startswith("kernel"):
            common = "kernel-debuginfo-common-{0}".format(debuginfo.arch.name)
            source = db.session.query(Package) \
                               .join(Arch) \
                               .join(Build) \
                               .filter((Build.id == debuginfo.build_id) &
                                       (Package.arch == debuginfo.arch) &
                                       (Package.name == common)) \
                               .one()
        else:
            try:
                source = db.session.query(Package) \
                                   .join(Arch) \
                                   .join(Build) \
                                   .filter((Build.id == debuginfo.build_id) &
                                           (Arch.name == "src")) \
                                   .one()
            except Exception as ex:
                logging.error("Unable to find source RPM: {0}".format(str(ex)))
                continue

        task = { "debuginfo": { "package": debuginfo,
                                "nvra": debuginfo.nvra(),
                                "rpm_path": debuginfo.get_lob_path("package") },
                 "source":    { "package": source,
                                "nvra": source.nvra(),
                                "rpm_path": source.get_lob_path("package") },
                 "packages":  packages }

        result.append(task)

    return result
예제 #2
0
파일: retrace.py 프로젝트: rtnpro/faf
def prepare_debuginfo_map(db):
    """
    Prepares the mapping debuginfo ~> packages ~> symbols
    """
    result = {}
    symbolsources = db.session.query(SymbolSource) \
                              .filter(SymbolSource.source_path == None).all()
    todelete = set()
    total = len(symbolsources)
    i = 0
    for symbolsource in symbolsources:
        i += 1
        try:
            if not symbolsource.symbol:
                logging.info("Empty symbol for symbolsource #{0} @ '{1}'" \
                              .format(symbolsource.id, symbolsource.path))
                continue
        except:
            continue

        logging.info("[{0}/{1}] Processing {2} @ '{3}'" \
                     .format(i, total, symbolsource.symbol.name, symbolsource.path))
        if not symbolsource.frames:
            logging.info("No frames found")
            continue

        if symbolsource.frames[0].backtrace.report.type.lower() == "kerneloops":
            try:
                version, release, arch, flavour = parse_kernel_build_id(symbolsource.build_id)
            except Exception as ex:
                logging.error(str(ex))
                continue

            logging.debug("Version = {0}; Release = {1}; Arch = {2}; Flavour = {3}" \
                          .format(version, release, arch, flavour))
            pkgname = "kernel"
            if not flavour is None:
                pkgname = "kernel-{0}".format(flavour)

            debugpkgname = "{0}-debuginfo".format(pkgname)
            debuginfo = db.session.query(Package) \
                                  .join(Build) \
                                  .join(Arch) \
                                  .filter((Package.name == debugpkgname) &
                                          (Build.version == version) &
                                          (Build.release == release) &
                                          (Arch.name == arch)) \
                                  .first()
            if not debuginfo:
                logging.debug("Matching kernel debuginfo not found")
                continue

            if not os.path.isfile(debuginfo.get_lob_path("package")):
                logging.debug("Package metadata found, but the actual package "
                              "is not available in storage.")
                continue

            if not debuginfo in result:
                result[debuginfo] = {}

            # ugly, but whatever - there is no binary package required
            if not debuginfo in result[debuginfo]:
                result[debuginfo][debuginfo] = set()

            result[debuginfo][debuginfo].add(symbolsource)

            continue

        if symbolsource.frames[0].backtrace.report.type.lower() != "userspace":
            logging.info("Skipping non-userspace symbol")
            continue

        if symbolsource.build_id is None:
            logging.info("No build-id available")
            continue

        debug_file = get_debug_file(symbolsource.build_id)
        debuginfos = db.session.query(Package) \
                               .join(PackageDependency) \
                               .filter((PackageDependency.name == debug_file) &
                                       (PackageDependency.type == "PROVIDES")) \
                               .all()
        logging.debug("Found {0} debuginfo packages".format(len(debuginfos)))
        for debuginfo in debuginfos:
            package = db.session.query(Package) \
                                .join(PackageDependency) \
                                .filter((PackageDependency.name == symbolsource.path) &
                                        (Package.arch == debuginfo.arch) &
                                        (Package.build_id == debuginfo.build_id)) \
                                .first()
            if not package:
                logging.debug("Trying AbsPath fix")
                abspath = os.path.abspath(symbolsource.path)
                if symbolsource.path != abspath:
                    logging.info("Applying AbsPath fix")
                    conflict = db.session.query(SymbolSource) \
                                         .filter((SymbolSource.path == abspath) &
                                                 (SymbolSource.offset == symbolsource.offset) &
                                                 (SymbolSource.build_id == symbolsource.build_id)) \
                                         .first()
                    if conflict:
                        db.session.execute("UPDATE {0} SET symbolsource_id = :newid " \
                                           "WHERE symbolsource_id = :oldid" \
                                           .format(ReportBtFrame.__tablename__),
                                           {"oldid": symbolsource.id, "newid": conflict.id })
                        todelete.add(symbolsource.id)
                        db.session.expunge(symbolsource)
                        symbolsource = conflict
                    else:
                        symbolsource.path = abspath

                    package = db.session.query(Package) \
                                        .join(PackageDependency) \
                                        .filter((PackageDependency.name == symbolsource.path) &
                                                (Package.arch == debuginfo.arch) &
                                                (Package.build_id == debuginfo.build_id)) \
                                        .first()

            if not package:
                logging.debug("Trying UsrMove fix")
                if symbolsource.path.startswith("/usr"):
                    newpath = symbolsource.path[4:]
                else:
                    newpath = "/usr{0}".format(symbolsource.path)

                package = db.session.query(Package) \
                                    .join(PackageDependency) \
                                    .filter((PackageDependency.name == newpath) &
                                            (Package.arch == debuginfo.arch) &
                                            (Package.build_id == debuginfo.build_id)) \
                                    .first()
                if package:
                    logging.info("Applying UsrMove fix")
                    conflict = db.session.query(SymbolSource) \
                                         .filter((SymbolSource.path == newpath) &
                                                 (SymbolSource.offset == symbolsource.offset) &
                                                 (SymbolSource.build_id == symbolsource.build_id)) \
                                         .first()
                    if conflict:
                        db.session.execute("UPDATE {0} SET symbolsource_id = :newid " \
                                           "WHERE symbolsource_id = :oldid" \
                                           .format(ReportBtFrame.__tablename__),
                                           {"oldid": symbolsource.id, "newid": conflict.id })
                        todelete.add(symbolsource.id)
                        db.session.expunge(symbolsource)
                        symbolsource = conflict
                    else:
                        symbolsource.path = newpath

            db.session.flush()

            if not package:
                logging.debug("Matching binary package not found")
                continue

            if not os.path.isfile(package.get_lob_path("package")) or \
               not os.path.isfile(debuginfo.get_lob_path("package")):
                logging.debug("Package metadata found, but the actual package "
                              "is not available in storage.")
                continue

            if not debuginfo in result:
                result[debuginfo] = {}

            if not package in result[debuginfo]:
                result[debuginfo][package] = set()

            result[debuginfo][package].add(symbolsource)
            break
        else:
            logging.warn("Unable to find a suitable package combination")

    db.session.flush()
    if todelete:
        # cond1 | cond2 | cond3 | ... | cond_n-1 | cond_n
        # delete by slices of 100 members - reduce is recursive
        todelete = list(todelete)
        for i in xrange((len(todelete) + 99) / 100):
            part = todelete[(100 * i):(100 * (i + 1))]
            cond = reduce(lambda x, y: x | y, [SymbolSource.id == id for id in part])
            try:
                db.session.query(SymbolSource).filter(cond).delete()
            except Exception as ex:
                logging.error("Unable to delete: {0}".format(str(ex)))
                continue

    return result