示例#1
0
    def _tar_xz(self,
                archive_name,
                archive_dir,
                filepaths,
                unlink=True) -> None:
        archive_path = os.path.join(archive_dir, archive_name)
        archive_path_tmp = os.path.join(archive_dir,
                                        "{0}.tmp".format(archive_name))
        tmpdir = get_temp_dir()
        tmpsubdir = os.path.join(tmpdir, "archive")
        unlink_paths = list(filepaths)

        try:
            os.makedirs(tmpsubdir)
        except OSError as ex:
            if ex.errno == errno.EEXIST:
                raise FafError("The directory '{0}' already exists".format(
                    tmpsubdir)) from ex
            raise

        untar = None
        if os.path.isfile(archive_path):
            self.log_info("An existing archive found, will merge the contents")
            untar = self._untar_xz(archive_path)
            with os.scandir(untar) as iterator:
                for entry in iterator:
                    if entry.is_dir() and entry.name.endswith("archive"):
                        filepaths = [
                            os.path.join(entry.path, f)
                            for f in os.listdir(entry.path)
                        ] + filepaths
                        break

        self.log_info("Creating symlinks")
        for filepath in filepaths:
            linkpath = os.path.join(tmpsubdir, os.path.basename(filepath))
            # merge - do not overwrite already archived data
            try:
                self.log_debug("%s ~> %s", filepath, linkpath)
                os.symlink(filepath, linkpath)
            except OSError as ex:
                if ex.errno != errno.EEXIST:
                    raise

                self.log_debug("Already exists")

        self.log_info("Running tar")
        safe_popen("tar", "chJf", archive_path_tmp, "-C", tmpdir, "archive")
        os.rename(archive_path_tmp, archive_path)

        self.log_info("Cleaning up")

        if untar is not None:
            shutil.rmtree(untar, ignore_errors=True)

        if unlink:
            for path in unlink_paths:
                os.unlink(path)

        shutil.rmtree(tmpsubdir)
示例#2
0
    def _tar_xz(self, archive_name, archive_dir, filepaths, unlink=True):
        archive_path = os.path.join(archive_dir, archive_name)
        archive_path_tmp = os.path.join(archive_dir,
                                        "{0}.tmp".format(archive_name))
        tmpdir = get_temp_dir()
        tmpsubdir = os.path.join(tmpdir, "archive")
        unlink_paths = list(filepaths)

        try:
            os.makedirs(tmpsubdir)
        except OSError as ex:
            if ex.errno == errno.EEXIST:
                raise FafError("The directory '{0}' already exists"
                               .format(tmpsubdir))
            raise

        untar = None
        if os.path.isfile(archive_path):
            self.log_info("An existing archive found, will merge the contents")
            untar = self._untar_xz(archive_path)
            for filename in [os.path.join(untar, f) for f in os.listdir(untar)]:
                if os.path.isdir(filename) and filename.endswith("archive"):
                    filepaths = [os.path.join(filename, f)
                                 for f in os.listdir(filename)] + filepaths
                    break

        self.log_info("Creating symlinks")
        for filepath in filepaths:
            linkpath = os.path.join(tmpsubdir, os.path.basename(filepath))
            # merge - do not overwrite already archived data
            try:
                self.log_debug("{0} ~> {1}".format(filepath, linkpath))
                os.symlink(filepath, linkpath)
            except OSError as ex:
                if ex.errno != errno.EEXIST:
                    raise

                self.log_debug("Already exists")

        self.log_info("Running tar")
        safe_popen("tar", "chJf", archive_path_tmp, "-C", tmpdir, "archive")
        os.rename(archive_path_tmp, archive_path)

        self.log_info("Cleaning up")

        if untar is not None:
            shutil.rmtree(untar, ignore_errors=True)

        if unlink:
            for path in unlink_paths:
                os.unlink(path)

        shutil.rmtree(tmpsubdir)
示例#3
0
文件: retrace.py 项目: abrt/faf
def get_function_offset_map(files):
    result = {}

    for filename in files:
        modulename = filename.rsplit("/", 1)[1].replace("-", "_")
        if modulename.endswith(".ko.debug"):
            modulename = str(modulename[:-9])

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

        child = safe_popen("eu-readelf", "-s", filename, encoding="utf-8")
        if child is None:
            continue

        for line in child.stdout.splitlines():
            if not "FUNC" in line and not "NOTYPE" in line:
                continue

            spl = line.split()
            try:
                result[modulename][spl[7].lstrip("_")] = int(spl[1], 16)
            except IndexError:
                continue

    return result
示例#4
0
文件: retrace.py 项目: marusak/faf
def get_function_offset_map(files):
    result = {}

    for filename in files:
        modulename = filename.rsplit("/", 1)[1].replace("-", "_")
        if modulename.endswith(".ko.debug"):
            modulename = str(modulename[:-9])

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

        child = safe_popen("eu-readelf", "-s", filename)
        if child is None:
            continue

        for line in child.stdout.splitlines():
            if not "FUNC" in line and not "NOTYPE" in line:
                continue

            spl = line.split()
            try:
                result[modulename][spl[7].lstrip("_")] = int(spl[1], 16)
            except IndexError:
                continue

    return result
示例#5
0
文件: c2p.py 项目: mkutlak/faf
    def _unstrip(
        self, cmdline
    ) -> Union[int, Tuple[List[Tuple[str, Optional[str]]], List[str]]]:
        build_ids = []
        missing = []

        self.log_info("Executing eu-unstrip")
        child = safe_popen("eu-unstrip",
                           "-n",
                           "--core",
                           cmdline.COREDUMP,
                           encoding="utf-8")
        if child is None:
            self.log_error("Failed to execute eu-unstrip")
            return 1

        for line in child.stdout.splitlines():
            if not all(c in string.printable for c in line):
                self.log_warn("Skipping line with non-printable characters")
                self.log_debug(line)
                continue
            match = Coredump2Packages.UNSTRIP_LINE_PARSER.match(line)
            if not match:
                self.log_warn("Unable to parse line: {0}".format(line))
                continue

            # Build ID
            if match.group(2):
                # File
                if match.group(3).startswith("/"):
                    build_ids.append((match.group(2), match.group(3)))
                # Name
                elif match.group(5) != "-":
                    # vDSO
                    if match.group(7):
                        self.log_debug("Skipping vDSO %s", match.group(8))
                        continue
                    # Deleted
                    if match.group(9):
                        self.log_warn("{} was reported as deleted, "
                                      "which means that the file comes from "
                                      "a different package version than "
                                      "the one installed".format(
                                          match.group(5)))
                        continue

                    build_ids.append((match.group(2), match.group(5)))
                else:
                    build_ids.append((match.group(2), None))
            else:
                missing.append(match.group(3))

        return build_ids, missing
示例#6
0
def demangle(mangled):
    """
    Demangle C++ symbol name.
    """

    child = safe_popen("c++filt", mangled, encoding="utf-8")
    if child is None:
        return None

    result = child.stdout.strip()
    if result != mangled:
        log.debug("Demangled: '%s' ~> '%s'", mangled, result)

    return result
示例#7
0
文件: retrace.py 项目: marusak/faf
def demangle(mangled):
    """
    Demangle C++ symbol name.
    """

    child = safe_popen("c++filt", mangled)
    if child is None:
        return None

    result = child.stdout.strip()
    if result != mangled:
        log.debug("Demangled: '{0}' ~> '{1}'".format(mangled, result))

    return result
示例#8
0
文件: retrace.py 项目: abrt/faf
def demangle(mangled):
    """
    Demangle C++ symbol name.
    """

    child = safe_popen("c++filt", mangled, encoding="utf-8")
    if child is None:
        return None

    result = child.stdout.strip()
    if result != mangled:
        log.debug("Demangled: '{0}' ~> '{1}'".format(mangled, result))

    return result
示例#9
0
文件: retrace.py 项目: marusak/faf
def get_base_address(binary_path):
    """
    Runs eu-unstrip on a binary to get the address used
    as base for calculating relative offsets.
    """

    child = safe_popen("eu-unstrip", "-n", "-e", binary_path)

    if child is None:
        raise FafError("eu-unstrip failed")

    match = RE_UNSTRIP_BASE_OFFSET.match(child.stdout)
    if match is None:
        raise FafError("Unexpected output from eu-unstrip: '{0}'".format(
            child.stdout))

    return int(match.group(1), 16)
示例#10
0
文件: retrace.py 项目: abrt/faf
def get_base_address(binary_path):
    """
    Runs eu-unstrip on a binary to get the address used
    as base for calculating relative offsets.
    """

    child = safe_popen("eu-unstrip", "-n", "-e", binary_path, encoding="utf-8")

    if child is None:
        raise FafError("eu-unstrip failed")

    match = RE_UNSTRIP_BASE_OFFSET.match(child.stdout)
    if match is None:
        raise FafError("Unexpected output from eu-unstrip: '{0}'"
                       .format(child.stdout))

    return int(match.group(1), 16)
示例#11
0
文件: c2p.py 项目: abrt/faf
    def _unstrip(self, cmdline):
        build_ids = []
        missing = []

        self.log_info("Executing eu-unstrip")
        child = safe_popen("eu-unstrip", "-n", "--core", cmdline.COREDUMP, encoding="utf-8")
        if child is None:
            self.log_error("Failed to execute eu-unstrip")
            return 1

        for line in child.stdout.splitlines():
            if not all(c in string.printable for c in line):
                self.log_warn("Skipping line with non-printable characters")
                self.log_debug(line)
                continue
            match = Coredump2Packages.UNSTRIP_LINE_PARSER.match(line)
            if not match:
                self.log_warn("Unable to parse line: {0}".format(line))
                continue

            # Build ID
            if match.group(2):
                # File
                if match.group(3).startswith("/"):
                    build_ids.append((match.group(2), match.group(3)))
                # Name
                elif match.group(5) != "-":
                    # vDSO
                    if match.group(7):
                        self.log_debug("Skipping vDSO {}".format(match.group(8)))
                        continue
                    # Deleted
                    elif match.group(9):
                        self.log_warn("{} was reported as deleted, "
                                      "which means that the file comes from "
                                      "a different package version than "
                                      "the one installed".format(match.group(5)))
                        continue

                    build_ids.append((match.group(2), match.group(5)))
                else:
                    build_ids.append((match.group(2), None))
            else:
                missing.append(match.group(3))

        return build_ids, missing
示例#12
0
文件: retrace.py 项目: jfilak/faf
def addr2line(binary_path, address, debuginfo_dir):
    """
    Calls eu-addr2line on a binary, address and directory with debuginfo.
    Returns an ordered list of triplets (function name, source file, line no).
    The last element is always the symbol given to retrace. The elements
    before are inlined symbols that should be placed above the given symbol
    (assuming that entry point is on the bottom of the stacktrace).
    """

    result = []
    child = safe_popen("eu-addr2line",
                       "--executable", binary_path,
                       "--debuginfo-path", debuginfo_dir,
                       "--functions", str(address))

    if child is None:
        raise FafError("eu-add2line failed")

    line1, line2 = child.stdout.splitlines()
    line2_parts = line2.split(":", 1)
    line2_srcfile = line2_parts[0]
    line2_srcline = int(line2_parts[1])

    match = RE_ADDR2LINE_LINE1.match(line1)
    if match is None:
        raise FafError("Unexpected output from eu-addr2line: '{0}'"
                       .format(line1))

    if match.group(3) is None:
        funcname = match.group(1)
        srcfile = line2_srcfile
        srcline = line2_srcline
    else:
        funcname = match.group(6)
        srcfile = match.group(4)
        srcline = int(match.group(5))

        result.append((match.group(1), line2_srcfile, line2_srcline))

    result.append((funcname, srcfile, srcline))

    return result
示例#13
0
文件: retrace.py 项目: pypingou/faf
def addr2line(binary_path, address, debuginfo_dir):
    """
    Calls eu-addr2line on a binary, address and directory with debuginfo.
    Returns an ordered list of triplets (function name, source file, line no).
    The last element is always the symbol given to retrace. The elements
    before are inlined symbols that should be placed above the given symbol
    (assuming that entry point is on the bottom of the stacktrace).
    """

    result = []
    child = safe_popen("eu-addr2line", "--executable", binary_path,
                       "--debuginfo-path", debuginfo_dir, "--functions",
                       str(address))

    if child is None:
        raise FafError("eu-add2line failed")

    line1, line2 = child.stdout.splitlines()
    line2_parts = line2.split(":", 1)
    line2_srcfile = line2_parts[0]
    line2_srcline = int(line2_parts[1])

    match = RE_ADDR2LINE_LINE1.match(line1)
    if match is None:
        raise FafError(
            "Unexpected output from eu-addr2line: '{0}'".format(line1))

    if match.group(3) is None:
        funcname = match.group(1)
        srcfile = line2_srcfile
        srcline = line2_srcline
    else:
        funcname = match.group(6)
        srcfile = match.group(4)
        srcline = int(match.group(5))

        result.append((match.group(1), line2_srcfile, line2_srcline))

    result.append((funcname, srcfile, srcline))

    return result
示例#14
0
文件: retrace.py 项目: marusak/faf
def addr2line(binary_path, address, debuginfo_dir):
    """
    Calls eu-addr2line on a binary, address and directory with debuginfo.
    Returns an ordered list of triplets (function name, source file, line no).
    The last element is always the symbol given to retrace. The elements
    before are inlined symbols that should be placed above the given symbol
    (assuming that entry point is on the bottom of the stacktrace).
    """

    result = []
    funcname = None
    srcfile = "??"
    srcline = 0

    # eu-addr2line often finds the symbol if we decrement the address by one.
    # we try several addresses that maps to no file or to the same source file
    # and source line as the original address.
    for addr_enh in range(0, 15):
        if addr_enh > address:
            break

        addr = "0x{0:x}".format(address - addr_enh)
        child = safe_popen("eu-addr2line", "--executable", binary_path,
                           "--debuginfo-path", debuginfo_dir, "--functions",
                           addr)

        if child is None:
            raise FafError("eu-add2line failed")

        line1, line2 = child.stdout.splitlines()
        if sys.version_info.major == 3:
            # Python 3
            line1 = line1.decode("utf-8")
            line2 = line2.decode("utf-8")
        line2_parts = line2.split(":", 1)
        line2_srcfile = line2_parts[0]
        line2_srcline = int(line2_parts[1])

        match = RE_ADDR2LINE_LINE1.match(line1)
        if match is None:
            raise FafError(
                "Unexpected output from eu-addr2line: '{0}'".format(line1))

        if srcfile != line2_srcfile or srcline != line2_srcline:
            if srcfile != "??" or srcline != 0:
                break

        if match.group(1) == "??":
            srcfile = line2_srcfile
            srcline = line2_srcline
            continue
        elif match.group(3) is None:
            funcname = match.group(1)
            srcfile = line2_srcfile
            srcline = line2_srcline
        else:
            funcname = match.group(6)
            srcfile = match.group(4)
            srcline = int(match.group(5))

            result.append((match.group(1), line2_srcfile, line2_srcline))

        break

    if funcname is None:
        raise FafError("eu-addr2line cannot find function name")

    result.append((funcname, srcfile, srcline))

    return result
示例#15
0
文件: c2p.py 项目: trams/faf
    def run(self, cmdline, db):
        build_ids = []
        missing = []

        self.log_info("Executing eu-unstrip")
        child = safe_popen("eu-unstrip", "-n", "--core", cmdline.COREDUMP)
        if child is None:
            self.log_error("Failed to execute eu-unstrip")
            return 1

        for line in child.stdout.splitlines():
            match = Coredump2Packages.UNSTRIP_LINE_PARSER.match(line)
            if not match:
                self.log_warn("Unable to parse line: {0}".format(line))
                continue

            if match.group(2):
                if match.group(3).startswith("/"):
                    build_ids.append((match.group(2), match.group(3)))
                elif (match.group(5) != "-" and
                      not match.group(5).startswith("[")):
                    build_ids.append((match.group(2), match.group(5)))
                else:
                    build_ids.append((match.group(2), None))
            else:
                missing.append(match.group(3))

        self.log_info("Mapping build-ids into debuginfo packages")
        build_id_maps = {}
        debuginfos = {}
        for build_id, soname in build_ids:
            debug_file = self._build_id_to_debug_file(build_id)
            db_packages = get_packages_by_file(db, debug_file)
            db_packages = [p for p in db_packages if p.has_lob("package")]
            if len(db_packages) < 1:
                self.log_warn("No debuginfo found for '{0}' ({1})"
                              .format(build_id, soname))
                continue
            else:
                self.log_debug("Found {0} debuginfo packages for '{1}' ({2}): "
                               "{3}".format(len(db_packages), build_id, soname,
                                            [p.nvra() for p in db_packages]))

            if build_id not in build_id_maps:
                build_id_maps[build_id] = set()

            for db_package in db_packages:
                pkgname = db_package.name
                pkgnvra = db_package.nvra()

                build_id_maps[build_id].add(pkgname)

                if pkgname not in debuginfos:
                    debuginfos[pkgname] = {}

                if pkgnvra not in debuginfos[pkgname]:
                    debuginfos[pkgname][pkgnvra] = { "count": 0,
                                                     "package": db_package }

                debuginfos[pkgname][pkgnvra]["count"] += 1

        for build_id, debug_pkgs in build_id_maps.items():
            if len(debug_pkgs) > 1:
                self.log_warn("Debuginfo conflict: '{0}' is provided by {1}"
                              .format(build_id, debug_pkgs))

            build_id_maps[build_id] = debug_pkgs.pop()

        result = set()
        debuginfo_maps = {}
        debuginfo_packages = []
        for pkgname in sorted(debuginfos):
            best = { "count": -1, "package": None }
            for pkgnvra in debuginfos[pkgname]:
                if debuginfos[pkgname][pkgnvra]["count"] > best["count"]:
                    best = debuginfos[pkgname][pkgnvra]

            if best["package"]:
                basename = best["package"].build.base_package_name
                if basename in Coredump2Packages.SKIP_PACKAGES:
                    self.log_debug("Skipping '{0}'".format(basename))
                    continue

                self.log_debug("Picking '{0}' for '{1}' with {2} build_id "
                               "matches".format(best["package"].nvra(),
                                                best["package"].name,
                                                best["count"]))

                debuginfo_packages.append(best["package"])
                debuginfo_maps[best["package"].name] = best["package"]
                result.add(best["package"])
            else:
                #paranoia - never happens
                self.log_warn("Unable to determine best version of '{0}'"
                              .format(pkgname))

        self.log_info("Getting binary packages from debuginfos")
        archs = {}
        db_build_ids = [dp.build.id for dp in debuginfo_packages]
        postprocess = set()
        for build_id, soname in build_ids:
            if build_id not in build_id_maps:
                continue

            if soname is None:
                if (build_id in build_id_maps and
                    isinstance(build_id_maps[build_id], basestring) and
                    build_id_maps[build_id] in debuginfo_maps):
                    nvra = debuginfo_maps[build_id_maps[build_id]].nvra()
                    self.log_info("No shared object name for '{0}' ({1})"
                                  .format(build_id, nvra))
                    db_build = debuginfo_maps[build_id_maps[build_id]].build
                    postprocess.add(db_build)
            else:
                debuginfo_name = build_id_maps[build_id]
                if debuginfo_name in Coredump2Packages.SKIP_PACKAGES:
                    self.log_debug("Skipping {0}".format(debuginfo_name))
                    continue

                db_arch = debuginfo_maps[debuginfo_name].arch
                abspath = soname.startswith("/")
                db_packages = get_packages_by_file_builds_arch(db,
                                                               soname,
                                                               db_build_ids,
                                                               db_arch,
                                                               abspath=abspath)

                if abspath and len(db_packages) < 1:
                    new_soname = usrmove(soname)
                    db_packages = get_packages_by_file_builds_arch(db,
                                                                   new_soname,
                                                                   db_build_ids,
                                                                   db_arch)

                if len(db_packages) < 1:
                    self.log_warn("Unable to find binary package for '{0}' "
                                  "({1})".format(build_id, soname))
                    continue

                for db_package in db_packages:
                    result.add(db_package)
                    arch = db_arch.name
                    if arch not in archs:
                        archs[arch] = 0

                    archs[arch] += 1

        if len(postprocess) > 0 and len(archs) > 0:
            self.log_info("Post-processing records without shared object name")
            arch = None
            archmax = 0
            for archname, archcount in archs.items():
                if archcount > archmax:
                    archmax = archcount
                    arch = archname

            self.log_info("Determined architecture: {0}".format(arch))

            for db_build in postprocess:
                basename = db_build.base_package_name
                if basename in Coredump2Packages.SKIP_PACKAGES:
                    self.log_info("Skipping {0}".format(basename))
                    continue

                for db_package in db_build.packages:
                    if db_package.arch.name == arch:
                        self.log_debug("Picking {0} for {1}"
                                       .format(db_package.nvra(), basename))
                        result.add(db_package)

        link = None
        tmpdir = None
        if cmdline.symlink_dir:
            tmpdir = tempfile.mkdtemp(dir=cmdline.symlink_dir)
            link = os.symlink
        elif cmdline.hardlink_dir:
            tmpdir = tempfile.mkdtemp(dir=cmdline.hardlink_dir)
            link = os.link

        for db_package in result:
            if link is None:
                print(db_package.nvra())
                continue

            path_from = db_package.get_lob_path("package")
            path_to = os.path.join(tmpdir, "{0}.rpm".format(db_package.nvra()))
            try:
                link(path_from, path_to)
            except OSError:
                if cmdline.no_copy:
                    continue

                shutil.copy2(path_from, path_to)

        if tmpdir is not None:
            print tmpdir
示例#16
0
    def run(self, cmdline, db):
        build_ids = []
        missing = []

        self.log_info("Executing eu-unstrip")
        child = safe_popen("eu-unstrip", "-n", "--core", cmdline.COREDUMP)
        if child is None:
            self.log_error("Failed to execute eu-unstrip")
            return 1

        for line in child.stdout.splitlines():
            match = Coredump2Packages.UNSTRIP_LINE_PARSER.match(line)
            if not match:
                self.log_warn("Unable to parse line: {0}".format(line))
                continue

            if not all(c in string.printable for c in line):
                self.log_warn("Skipping line with non-printable characters")
                self.log_debug(line)
                continue

            if match.group(2):
                if match.group(3).startswith("/"):
                    build_ids.append((match.group(2), match.group(3)))
                elif (match.group(5) != "-"
                      and not match.group(5).startswith("[")):
                    build_ids.append((match.group(2), match.group(5)))
                else:
                    build_ids.append((match.group(2), None))
            else:
                missing.append(match.group(3))

        self.log_info("Mapping build-ids into debuginfo packages")
        build_id_maps = {}
        debuginfos = {}
        for build_id, soname in build_ids:
            debug_file = self._build_id_to_debug_file(build_id)
            db_packages = get_packages_by_file(db, debug_file)
            db_packages = [p for p in db_packages if p.has_lob("package")]
            if len(db_packages) < 1:
                self.log_warn("No debuginfo found for '{0}' ({1})".format(
                    build_id, soname))
                continue
            else:
                self.log_debug("Found {0} debuginfo packages for '{1}' ({2}): "
                               "{3}".format(len(db_packages), build_id, soname,
                                            [p.nvra() for p in db_packages]))

            if build_id not in build_id_maps:
                build_id_maps[build_id] = set()

            for db_package in db_packages:
                pkgname = db_package.name
                pkgnvra = db_package.nvra()

                build_id_maps[build_id].add(pkgname)

                if pkgname not in debuginfos:
                    debuginfos[pkgname] = {}

                if pkgnvra not in debuginfos[pkgname]:
                    debuginfos[pkgname][pkgnvra] = {
                        "count": 0,
                        "package": db_package
                    }

                debuginfos[pkgname][pkgnvra]["count"] += 1

        for build_id, debug_pkgs in build_id_maps.items():
            if len(debug_pkgs) > 1:
                self.log_warn(
                    "Debuginfo conflict: '{0}' is provided by {1}".format(
                        build_id, debug_pkgs))

            build_id_maps[build_id] = debug_pkgs.pop()

        result = set()
        debuginfo_maps = {}
        debuginfo_packages = []
        for pkgname in sorted(debuginfos):
            best = {"count": -1, "package": None}
            for pkgnvra in debuginfos[pkgname]:
                if debuginfos[pkgname][pkgnvra]["count"] > best["count"]:
                    best = debuginfos[pkgname][pkgnvra]

            if best["package"]:
                basename = best["package"].build.base_package_name
                if basename in Coredump2Packages.SKIP_PACKAGES:
                    self.log_debug("Skipping '{0}'".format(basename))
                    continue

                self.log_debug("Picking '{0}' for '{1}' with {2} build_id "
                               "matches".format(best["package"].nvra(),
                                                best["package"].name,
                                                best["count"]))

                debuginfo_packages.append(best["package"])
                debuginfo_maps[best["package"].name] = best["package"]
                result.add(best["package"])
            else:
                #paranoia - never happens
                self.log_warn(
                    "Unable to determine best version of '{0}'".format(
                        pkgname))

        self.log_info("Getting binary packages from debuginfos")
        archs = {}
        db_build_ids = [dp.build.id for dp in debuginfo_packages]
        postprocess = set()
        for build_id, soname in build_ids:
            if build_id not in build_id_maps:
                continue

            if soname is None:
                if (build_id in build_id_maps and isinstance(
                        build_id_maps[build_id], six.string_types)
                        and build_id_maps[build_id] in debuginfo_maps):
                    nvra = debuginfo_maps[build_id_maps[build_id]].nvra()
                    self.log_info(
                        "No shared object name for '{0}' ({1})".format(
                            build_id, nvra))
                    db_build = debuginfo_maps[build_id_maps[build_id]].build
                    postprocess.add(db_build)
            else:
                debuginfo_name = build_id_maps[build_id]
                if debuginfo_name in Coredump2Packages.SKIP_PACKAGES:
                    self.log_debug("Skipping {0}".format(debuginfo_name))
                    continue

                db_arch = debuginfo_maps[debuginfo_name].arch
                abspath = soname.startswith("/")
                db_packages = get_packages_by_file_builds_arch(db,
                                                               soname,
                                                               db_build_ids,
                                                               db_arch,
                                                               abspath=abspath)

                if abspath and len(db_packages) < 1:
                    new_soname = usrmove(soname)
                    db_packages = get_packages_by_file_builds_arch(
                        db, new_soname, db_build_ids, db_arch)

                if len(db_packages) < 1:
                    self.log_warn("Unable to find binary package for '{0}' "
                                  "({1})".format(build_id, soname))
                    continue

                for db_package in db_packages:
                    result.add(db_package)
                    arch = db_arch.name
                    if arch not in archs:
                        archs[arch] = 0

                    archs[arch] += 1

        if len(postprocess) > 0 and len(archs) > 0:
            self.log_info("Post-processing records without shared object name")
            arch = None
            archmax = 0
            for archname, archcount in archs.items():
                if archcount > archmax:
                    archmax = archcount
                    arch = archname

            self.log_info("Determined architecture: {0}".format(arch))

            for db_build in postprocess:
                basename = db_build.base_package_name
                if basename in Coredump2Packages.SKIP_PACKAGES:
                    self.log_info("Skipping {0}".format(basename))
                    continue

                for db_package in db_build.packages:
                    if db_package.arch.name == arch:
                        self.log_debug("Picking {0} for {1}".format(
                            db_package.nvra(), basename))
                        result.add(db_package)

        link = None
        tmpdir = None
        if cmdline.symlink_dir:
            tmpdir = tempfile.mkdtemp(dir=cmdline.symlink_dir)
            link = os.symlink
        elif cmdline.hardlink_dir:
            tmpdir = tempfile.mkdtemp(dir=cmdline.hardlink_dir)
            link = os.link

        for db_package in result:
            if link is None:
                print(db_package.nvra())
                continue

            path_from = db_package.get_lob_path("package")
            path_to = os.path.join(tmpdir, "{0}.rpm".format(db_package.nvra()))
            try:
                link(path_from, path_to)
            except OSError:
                if cmdline.no_copy:
                    continue

                shutil.copy2(path_from, path_to)

        if tmpdir is not None:
            print(tmpdir)
示例#17
0
 def _untar_xz(self, archive):
     tmpdir = tempfile.mkdtemp(dir=get_temp_dir(),
                               prefix=os.path.basename(archive))
     safe_popen("tar", "xJf", archive, "-C", tmpdir)
     return tmpdir
示例#18
0
 def _untar_xz(self, archive):
     tmpdir = tempfile.mkdtemp(dir=get_temp_dir(),
                               prefix=os.path.basename(archive))
     safe_popen("tar", "xJf", archive, "-C", tmpdir)
     return tmpdir
示例#19
0
文件: retrace.py 项目: abrt/faf
def addr2line(binary_path, address, debuginfo_dir):
    """
    Calls eu-addr2line on a binary, address and directory with debuginfo.
    Returns an ordered list of triplets (function name, source file, line no).
    The last element is always the symbol given to retrace. The elements
    before are inlined symbols that should be placed above the given symbol
    (assuming that entry point is on the bottom of the stacktrace).
    """

    result = []
    funcname = None
    srcfile = "??"
    srcline = 0

    # eu-addr2line often finds the symbol if we decrement the address by one.
    # we try several addresses that maps to no file or to the same source file
    # and source line as the original address.
    for addr_enh in range(0, 15):
        if addr_enh > address:
            break

        addr = "0x{0:x}".format(address - addr_enh)
        child = safe_popen("eu-addr2line",
                           "--executable", binary_path,
                           "--debuginfo-path", debuginfo_dir,
                           "--functions", addr,
                           encoding="utf-8")

        if child is None:
            raise FafError("eu-add2line failed")

        line1, line2 = child.stdout.splitlines()
        # format of the line2 is filename:lineno[:columnno]
        line2_parts = line2.split(":")
        line2_srcfile = line2_parts[0]
        line2_srcline = int(line2_parts[1])

        match = RE_ADDR2LINE_LINE1.match(line1)
        if match is None:
            raise FafError("Unexpected output from eu-addr2line: '{0}'"
                           .format(line1))

        if srcfile != line2_srcfile or srcline != line2_srcline:
            if srcfile != "??" or srcline != 0:
                break

        if match.group(1) == "??":
            srcfile = line2_srcfile
            srcline = line2_srcline
            continue
        elif match.group(3) is None:
            funcname = match.group(1)
            srcfile = line2_srcfile
            srcline = line2_srcline
        else:
            funcname = match.group(6)
            srcfile = match.group(4)
            srcline = int(match.group(5))

            result.append((match.group(1), line2_srcfile, line2_srcline))

        break

    if funcname is None:
        raise FafError("eu-addr2line cannot find function name")

    result.append((funcname, srcfile, srcline))

    return result